Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
All notable changes to `codesema` (the npm package in `packages/cli`) are documented here.
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [SemVer](https://semver.org).

## [0.18.1] - 2026-08-27

### Fixed

- **`--env-file` is now `--secrets-file`.** Node consumes an `--env-file` argument itself, even placed after the script (its native dotenv flag), so `runner await-secrets --env-file` and `runner install-service --env-file` never reached the CLI at all under a real node install; bun does not do this, which is why every test and the local e2e stayed green. First caught on a real server install. `install.sh` passes the new flag.

## [0.18.0] - 2026-08-27

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codesema-tools",
"version": "0.18.0",
"version": "0.18.1",
"private": true,
"type": "module",
"workspaces": [
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/assets/deploy/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ else
log "$env_file already holds both runtime secrets, skipping await-secrets"
else
log "waiting for secrets: on your workstation, run 'codesema runner autoconfig' and compare its fingerprint against the one printed above"
REPO_URL="$(codesema runner await-secrets --env-file "$env_file")"
REPO_URL="$(codesema runner await-secrets --secrets-file "$env_file")"
fi

if [ -z "${REPO_URL:-}" ]; then
Expand Down Expand Up @@ -277,7 +277,7 @@ else
git clone "$REPO_URL" "$repo_dir"
fi

( cd "$repo_dir" && codesema runner install-service --env-file "$env_file" )
( cd "$repo_dir" && codesema runner install-service --secrets-file "$env_file" )

log "done at $(date -u +%FT%TZ)"
log "check it with: systemctl --user status codesema-runner.service"
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codesema",
"version": "0.18.0",
"version": "0.18.1",
"description": "Local merge request review, step by step. Your AI agent reviews, codesema displays.",
"license": "MIT",
"author": "Hasan TASKIN",
Expand Down
16 changes: 8 additions & 8 deletions packages/cli/src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ Usage:
Pick a registered runner, collect a GH token and/or a Claude Code
token for it, seal them to that runner's key and deposit them on
the hub for it to pick up
codesema runner await-secrets [--env-file <path>] [--timeout <s>]
codesema runner await-secrets [--secrets-file <path>] [--timeout <s>]
Run on the runner machine: wait for the secret \`autoconfig\` sealed
for it, decrypt it into --env-file and print the repo URL it carried
for it, decrypt it into --secrets-file and print the repo URL it carried
codesema runner serve [--detach] Alias for \`codesema workspace --runner\`; --detach backgrounds the
daemon (prints its pid and log path) instead of running it in the
foreground
codesema runner stop Stop a runner daemon started with --detach (or under systemd) for
this repo
codesema runner disconnect Forget the connected hub (clears local credentials only —
also revoke this arm in the dashboard's Settings)
codesema runner install-service [--env-file <path>]
codesema runner install-service [--secrets-file <path>]
Install a systemd --user unit that runs \`codesema runner serve\`
for this repo, enabled and started now
codesema runner uninstall-service Stop and remove that systemd --user unit
Expand Down Expand Up @@ -89,7 +89,7 @@ Options:
--gh-token-from-gh \`runner autoconfig\`: capture GH_TOKEN from this machine's \`gh auth token\` without asking
--claude-token <t> \`runner autoconfig\`: Claude Code OAuth token to send instead of prompting for one
--repo-url <url> \`runner autoconfig\`: repo URL to send instead of the detected git remote
--env-file <path> \`runner install-service\`'s EnvironmentFile=, or \`runner await-secrets\`'s
--secrets-file <path> \`runner install-service\`'s EnvironmentFile=, or \`runner await-secrets\`'s
destination env file (default: the runner's own env file)
-h, --help Show this help
-v, --version Show version
Expand Down Expand Up @@ -661,15 +661,15 @@ Usage :
Choisit un runner enregistré, récupère un jeton gh et/ou un jeton
Claude Code pour lui, les scelle avec sa clé et les dépose sur le
hub pour qu'il les récupère
codesema runner await-secrets [--env-file <chemin>] [--timeout <s>]
codesema runner await-secrets [--secrets-file <chemin>] [--timeout <s>]
À lancer sur la machine runner : attend le secret scellé par
\`autoconfig\`, le déchiffre dans --env-file et affiche l'URL du
\`autoconfig\`, le déchiffre dans --secrets-file et affiche l'URL du
dépôt reçue
codesema runner serve Alias de \`codesema workspace --runner\`
codesema runner disconnect Oublie le hub connecté (efface seulement les identifiants
locaux, pensez aussi à révoquer ce bras dans les Settings du
dashboard)
codesema runner install-service [--env-file <chemin>]
codesema runner install-service [--secrets-file <chemin>]
Installe une unité systemd --user qui lance
\`codesema runner serve\` pour ce dépôt, activée et démarrée
codesema runner uninstall-service Arrête et supprime cette unité systemd --user
Expand Down Expand Up @@ -701,7 +701,7 @@ Options :
--gh-token-from-gh \`runner autoconfig\` : capture GH_TOKEN via \`gh auth token\` sans confirmation
--claude-token <j> \`runner autoconfig\` : jeton OAuth Claude Code à envoyer plutôt que de le demander
--repo-url <url> \`runner autoconfig\` : URL de dépôt à envoyer plutôt que le remote détecté
--env-file <chemin> \`runner install-service\` : EnvironmentFile= de l'unité systemd générée, ou
--secrets-file <chemin> \`runner install-service\` : EnvironmentFile= de l'unité systemd générée, ou
fichier de destination de \`runner await-secrets\` (défaut : le fichier env du runner)
-h, --help Afficher cette aide
-v, --version Afficher la version
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
title?: string | undefined
prompt?: string | undefined
detach?: boolean | undefined
'env-file'?: string | undefined
'secrets-file'?: string | undefined
fingerprint?: string | undefined
'gh-token-from-gh'?: boolean | undefined
'claude-token'?: string | undefined
Expand Down Expand Up @@ -148,93 +148,93 @@
return { kind: 'command', name: command, arg: positionals[1] }
}

async function runCommand(
name: CommandName,
arg: string | undefined,
values: ParsedValues,
repoRoot: string | null,
): Promise<void> {
switch (name) {
case 'review':
await review({
branch: values.branch,
target: values.target,
agent: values.agent,
port: parseIntFlag('port', values.port, 1, 65535),
timeout: parseIntFlag('timeout', values.timeout, 1, 86400),
full: values.full,
dual: values.dual,
failOn: parseFailOn(values['fail-on']),
open: !values['no-open'],
cwd: process.cwd(),
})
break
case 'prep':
await prep({
branch: values.branch,
target: values.target ?? loadConfig(repoRoot).target,
cwd: process.cwd(),
})
break
case 'workspace':
if (values.runner) {
// workspace() (workspace.ts) has a fixed options type with no room
// for a runner flag; the signal crosses into startServer (serve.ts)
// the same way CODESEMA_SYNC_URL/CODESEMA_DEV_VITE already do in
// this codebase, read at the one place that needs it.
process.env.CODESEMA_RUNNER_MODE = '1'
}
await workspace({
port: parseIntFlag('port', values.port, 1, 65535),
open: !values['no-open'],
cwd: process.cwd(),
agent: values.agent,
timeout: parseIntFlag('timeout', values.timeout, 1, 86400),
})
break
case 'menu':
await runMenu({ cwd: process.cwd() })
break
case 'show':
await show({
review: values.review,
port: parseIntFlag('port', values.port, 1, 65535) ?? loadConfig(repoRoot).port,
open: !values['no-open'],
cwd: process.cwd(),
})
break
case 'config':
await configCommand(repoRoot)
break
case 'export':
exportCommand({ review: values.review, out: values.out, cwd: process.cwd() })
break
case 'sync':
await syncCommand({ action: arg, cwd: process.cwd(), force: values.force })
break
case 'link':
await linkCommand({ code: arg })
break
case 'runner':
await runnerCommand({
action: arg,
cwd: process.cwd(),
url: values.url,
token: values.token,
issue: values.issue,
title: values.title,
prompt: values.prompt,
detach: values.detach,
envFile: values['env-file'],
envFile: values['secrets-file'],
fingerprint: values.fingerprint,
ghTokenFromGh: values['gh-token-from-gh'],
claudeToken: values['claude-token'],
repoUrl: values['repo-url'],
timeoutSeconds: parseIntFlag('timeout', values.timeout, 1, 86400),
})
break
}
}

Check warning on line 237 in packages/cli/src/index.ts

View workflow job for this annotation

GitHub Actions / quality

eslint(max-lines-per-function)

The async function `runCommand` has too many lines (83). Maximum allowed is 60.

Check warning on line 237 in packages/cli/src/index.ts

View workflow job for this annotation

GitHub Actions / quality

eslint(complexity)

async function `runCommand` has a complexity of 14. Maximum allowed is 10.

async function main(): Promise<void> {
const { values, positionals } = parseArgs({
Expand All @@ -261,7 +261,7 @@
title: { type: 'string' },
prompt: { type: 'string' },
detach: { type: 'boolean' },
'env-file': { type: 'string' },
'secrets-file': { type: 'string' },
fingerprint: { type: 'string' },
'gh-token-from-gh': { type: 'boolean' },
'claude-token': { type: 'string' },
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/runner-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe('installRunnerService / uninstallRunnerService', () => {
])
})

test('resolves a relative --env-file against the given cwd, not process.cwd()', () => {
test('resolves a relative --secrets-file against the given cwd, not process.cwd()', () => {
writeFileSync(join(cwd, 'runner.env'), 'GH_TOKEN=x\n')
const result = installRunnerService({
workingDirectory: '/repo',
Expand All @@ -129,7 +129,7 @@ describe('installRunnerService / uninstallRunnerService', () => {
expect(written).toContain(`EnvironmentFile=${join(cwd, 'runner.env')}`)
})

test('an absolute --env-file is used as-is', () => {
test('an absolute --secrets-file is used as-is', () => {
const envFile = join(xdgConfigHome, 'runner.env')
writeFileSync(envFile, 'GH_TOKEN=x\n')
const result = installRunnerService({
Expand All @@ -141,7 +141,7 @@ describe('installRunnerService / uninstallRunnerService', () => {
expect(result.environmentFile).toBe(envFile)
})

test('a missing --env-file throws and writes nothing', () => {
test('a missing --secrets-file throws and writes nothing', () => {
expect(() =>
installRunnerService({
workingDirectory: '/repo',
Expand Down
Loading