@gluecharm-lab/easyspecs-cli 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,10 +5,10 @@ Headless **EasySpecs** command-line tool: same orchestration ideas as the **Easy
5
5
  ## The three factory-level commands
6
6
 
7
7
  1. **`easyspecs-cli analysis` — create new context**
8
- Runs the full **Generate Context** factory end to end (synthesis until stable, coverage, remediation, reporting, link mapping, index assembly). Use this when you need a fresh or full rebuild of **`.gluecharm/context`** from the repo. Optional **`--upload`** pushes resulting context to EasySpecs after **`auth login`** and **`config set-project-id`**. **`--synthesis-only`** stops after synthesis; **`--force-new-context-analysis`** overrides skip-when-already-analyzed behavior when the factory would otherwise exit early. If **`git worktree add`** fails because a temp analysis checkout folder was removed but Git still lists it, the CLI runs **`git worktree prune`** in your repository and retries **`git worktree add`** once (same behaviour wherever the CLI creates that temp worktree).
8
+ Runs the full **Generate Context** factory end to end (synthesis until stable, coverage, remediation, reporting, link mapping, index assembly). Use this when you need a fresh or full rebuild of **`.gluecharm/context`** from the repo. **`--force-new-context-analysis`** overrides skip-when-already-analyzed behavior when **`easyspecs.factory.cloudContextAnalyzed`** would otherwise short-circuit the run. After **`analysis`**, run **`easyspecs-cli upload context`** or **`upload republish`** when you want context on EasySpecs (**`auth login`** + **`config set-project-id`**). If **`git worktree add`** fails because a temp analysis checkout folder was removed but Git still lists it, the CLI runs **`git worktree prune`** in your repository and retries **`git worktree add`** once (same behaviour wherever the CLI creates that temp worktree).
9
9
 
10
10
  2. **`easyspecs-cli update context` — update context from code churn**
11
- Incremental refresh from a **git delta** since the stored baseline (**`easyspecs.factory.updateContext.lastRunAt`**) or, when that is absent, inferred from workspace context mtimes: materialises **`changes-since-date.md`**, runs **scoped** remediation when commits and touched paths warrant it, then optional promotion and **`--upload`**. Use this day to day after **`analysis`** when the codebase moved but specs did not restart from zero.
11
+ Incremental refresh from a **git delta** since the stored baseline (**`easyspecs.factory.updateContext.lastRunAt`**) or, when that is absent, inferred from workspace context mtimes: materialises **`changes-since-date.md`**, runs **scoped** remediation when commits and touched paths warrant it, then optional promotion. Use **`upload context`** afterward when you need cloud sync. Use this day to day after **`analysis`** when the codebase moved but specs did not restart from zero.
12
12
 
13
13
  3. **`easyspecs-cli context drift <referencePath>` — analyze drift against specs**
14
14
  **`referencePath`** is a **file or directory** of truth documents (requirements, specs, PRD, architecture notes — whatever your team treats as ground truth relative to repo root). The CLI compares **repository / analysis worktree** context against that reference (OpenCode-assisted), writes **`drift-<label>-<date>.md`** under **`.gluecharm/context/drift/`**, and can update the reference index markdown. **`--label <slug>`** names the report file; **`--index <path>`** overrides which root markdown anchors the comparison; **`--dry-run`** validates references only (**no worktree, agent, or writes**).
@@ -56,7 +56,7 @@ easyspecs-cli config init
56
56
  easyspecs-cli analysis
57
57
  ```
58
58
 
59
- **`config init`** creates **`.easyspecs/config.json`** with defaults (add **`--overwrite`** to replace an existing file). After the first **`analysis`**, typical follow-ups are **`update context`** (incremental sync with git) and **`context drift`** when you hold truth in specs files/folders elsewhere in the repo. Use **`download context`** (**`auth login`** + **`config set-project-id`**) to pull stored context from EasySpecs into **`.gluecharm/context`**. Append **`analysis --upload`** or **`update context --upload`** to sync edits back after login + project id. Use **`--ci`** in automation for non-interactive behaviour and stricter defaults (e.g. Factory outer-iteration cap).
59
+ **`config init`** creates **`.easyspecs/config.json`** with defaults (add **`--overwrite`** to replace an existing file). After the first **`analysis`**, typical follow-ups are **`update context`** (incremental sync with git) and **`context drift`** when you hold truth in specs files/folders elsewhere in the repo. Use **`download context`** (**`auth login`** + **`config set-project-id`**) to pull stored context from EasySpecs into **`.gluecharm/context`**. Run **`upload context`** or **`upload republish`** after **`analysis`** / **`update context`** when you want edits on EasySpecs. Use **`--ci`** in automation for non-interactive behaviour and stricter defaults (e.g. Factory outer-iteration cap).
60
60
 
61
61
  Set **`easyspecs.defaultGitRemoteUrl`** with **`config set-git-remote <url>`** when you want that recorded in config. Tunables belong in **`<repo>/.easyspecs/config.json`** — do not rely on **`EASYSPECS_*`** environment variables for product settings.
62
62
 
@@ -258,8 +258,8 @@ Every command the CLI accepts, with command-specific tokens. Global flags above
258
258
  | `run synthesis` | — | Context artefact pipeline pass; **`requireOpenCode`** applies. **`--promote` / `--no-promote`** affect promotion after success. |
259
259
  | `run synthesis resume-missing` | **`--worktree <path>`** (optional) | Parallel missing-artefact remediation pool on an existing checkout (from **`--worktree`** or last snapshot). **`requireOpenCode`**. |
260
260
  | `run synthesis resume-synthesis` | **`--worktree <path>`** (optional) | Same implementation as **`resume-missing`** (alias command path). |
261
- | `analysis` | **`--synthesis-only`**, **`--upload`**, **`--skip-upload`**, **`--force-new-context-analysis`** (any order among argv tokens after **`analysis`**) | Full **Generate Context** factory unless **`--synthesis-only`** — **create new context** trajectory. **`--upload`** runs backend sync after the factory (needs **`auth login`** + **`easyspecs.easyspecsProjectId`**). Without **`--upload`**, backend sync is skipped. **`--skip-upload`** appears in **`easyspecs-cli help`**; omit **`--upload`** to skip upload. If **`easyspecs.factory.cloudContextAnalyzed`** is **`true`** (legacy **`easyspecs.analysis.cloudContextAnalyzed`**) and neither **`--synthesis-only`** nor **`--force-new-context-analysis`** is set, exits **0** early with **`analysisSkipped`** (machine JSON fields). Stale temp-worktree registration (*missing but already registered worktree*): **`git worktree prune`** in the repo root, then one retry of **`git worktree add`**. |
262
- | `update context` | **`--upload`** (optional; any order in tail) | **Update context** trajectory: git window after baseline → worktree → **`changes-since-date.md`** → optional remediation → **`--promote` / `--no-promote`** → optional **`--upload`** (mtime-scoped files) → **`easyspecs.factory.updateContext.lastRunAt`**. Seed context should exist on **HEAD** in the checkout (the factory may copy from workspace when the worktree lacks context). |
261
+ | `analysis` | **`--force-new-context-analysis`** (optional; tail only). **`--upload`** / **`--skip-upload`** → usage exit; **`--synthesis-only`** ignored + stderr deprecation (**SRS-60**). | Full **Generate Context** factory — **create new context** trajectory. CLI **does not** run backend upload inside **`analysis`**; use **`upload context`** / **`upload republish`** afterward. If **`easyspecs.factory.cloudContextAnalyzed`** is **`true`** and **`--force-new-context-analysis`** is absent, exits **0** early with **`analysisSkipped`**. Stale temp-worktree registration: **`git worktree prune`** then one retry of **`git worktree add`**. |
262
+ | `update context` | | **Update context** trajectory: git window after baseline → worktree → **`changes-since-date.md`** → optional remediation → **`--promote` / `--no-promote`** → **`easyspecs.factory.updateContext.lastRunAt`**. Run **`upload context`** separately for cloud sync. Seed context should exist on **HEAD** in the checkout (the factory may copy from workspace when the worktree lacks context). |
263
263
  | `diagnose reference-coverage` | **`--root workspace`** \| **`--root worktree`**, optional **`--worktree <path>`** | Reference coverage gate; optional percent limit via **`easyspecs.diagnose.zeroReference.maxPercentNonReferenced`**. |
264
264
  | `diagnose coordination-duplicates` | same | Duplicate/orphan reporting; **`easyspecs.diagnose.coordinationDuplicates.strict`**. |
265
265
  | `diagnose coverage-report` | same | Writes coverage execution report path. |
@@ -276,7 +276,7 @@ Every command the CLI accepts, with command-specific tokens. Global flags above
276
276
 
277
277
  **OpenCode:** commands that spawn agents require **`opencode`** (or configured executable) on **`PATH`** and credentials unless **`skipCredentialsCheck`** or provider keys in **`config.json`** apply (**`requireOpenCode`**).
278
278
 
279
- **EasySpecs API session:** **`download context`**, **`upload context`**, **`upload republish`**, **`analysis --upload`**, and **`update context --upload`** need a prior **`auth login`** (or **`--ci`** with **`easyspecs.auth.ciLogin`** in **`config.json`** when argv omits email/password on login), plus **`easyspecs.easyspecsProjectId`** for the upload/download commands.
279
+ **EasySpecs API session:** **`download context`**, **`upload context`**, and **`upload republish`** need a prior **`auth login`** (or **`--ci`** with **`easyspecs.auth.ciLogin`** in **`config.json`** when argv omits email/password on login), plus **`easyspecs.easyspecsProjectId`** for those commands.
280
280
 
281
281
  **Unknown command:** prints help and exits with a usage error.
282
282
 
package/commands.md CHANGED
@@ -1,20 +1,22 @@
1
1
  # EasySpecs CLI — commands, flags, and configuration
2
2
 
3
- **Error codes:** OS exit codes, structured **`failureExitId`** values, and JSON field semantics are catalogued in **[`error-code.md`](./error-code.md)** (maintained with CLI changes).
3
+ **Error codes:** OS exit codes, structured `**failureExitId`** values, and JSON field semantics are catalogued in `**[error-code.md](./error-code.md)**` (maintained with CLI changes).
4
4
 
5
- Published package: **`@gluecharm-lab/easyspecs-cli`** (`easyspecs-cli`). Source of truth for routing and option registration: [`src/cli/cliProgram.ts`](../../src/cli/cliProgram.ts), command dispatch and business flow wiring: [`src/cli/main.ts`](../../src/cli/main.ts), merged settings: [`mergeEasyspecsCliSettings`](../../src/cli/cliSettings.ts), per-repo config: [`src/config/easyspecsConfigFile.ts`](../../src/config/easyspecsConfigFile.ts), CLI API URL resolution: [`src/easyspecsApiBaseUrlCli.ts`](../../src/easyspecsApiBaseUrlCli.ts). The VS Code extension resolves API URLs via [`src/apiBaseUrlResolve.ts`](../../src/apiBaseUrlResolve.ts); **`easyspecs-cli` does not use that chain** for System Manager origin (**SRS-43 R30 / R34**).
5
+ Published package: `**@gluecharm-lab/easyspecs-cli**` (`easyspecs-cli`). Source of truth for routing and option registration: `[src/cli/cliProgram.ts](../../src/cli/cliProgram.ts)`, command dispatch and business flow wiring: `[src/cli/main.ts](../../src/cli/main.ts)`, merged settings: `[mergeEasyspecsCliSettings](../../src/cli/cliSettings.ts)`, per-repo config: `[src/config/easyspecsConfigFile.ts](../../src/config/easyspecsConfigFile.ts)`, CLI API URL resolution: `[src/easyspecsApiBaseUrlCli.ts](../../src/easyspecsApiBaseUrlCli.ts)`. The VS Code extension resolves API URLs via `[src/apiBaseUrlResolve.ts](../../src/apiBaseUrlResolve.ts)`; `**easyspecs-cli` does not use that chain** for System Manager origin (**SRS-43 R30 / R34**).
6
6
 
7
7
  ### Vocabulary (SRS-53)
8
8
 
9
- End-to-end behaviour and file layout: see the repo root companion **`run-analysis-flow.md`** (no URL; same repository).
9
+ End-to-end behaviour and file layout: see the repo root companion `**run-analysis-flow.md`** (no URL; same repository).
10
10
 
11
- | Term | One-line meaning |
12
- |------|------------------|
13
- | **Factory** | The ordered **Generate Context** run (CLI: **`analysis`**; VS Code: Diagnosis **Run factory** / **Stop factory**). |
14
- | **Pipeline** | A named stage the Factory composes: Synthesis, Coverage, Remediation, Link Mapping, Upload, or Download. |
11
+
12
+ | Term | One-line meaning |
13
+ | --------------- | -------------------------------------------------------------------------------------------------------------------- |
14
+ | **Factory** | The ordered **Generate Context** run (CLI: `**analysis`**; VS Code: Diagnosis **Run factory** / **Stop factory**). |
15
+ | **Pipeline** | A named stage the Factory composes: Synthesis, Coverage, Remediation, Link Mapping, Upload, or Download. |
15
16
  | **Workstation** | One atomic unit inside a Pipeline (OpenCode agent + deterministic validators / repair loop, or a programmatic step). |
16
17
 
17
- **Stderr tags (human TTY mode):** phase changes may insert a blank line when the family changes. Tags include **`[factory]`**, **`[pipeline:synthesis]`** (and `coverage`, `remediation`, `link-mapping`, `upload`, `download`), **`[workstation:<id>]`** for OpenCode subprocess lines, **`[pool]`** / **`[queue]`** for work queues, **`[deprecated-setting]`** when a legacy **`config.json`** key was consumed (canonical keys: **`easyspecs.factory.*`**, **`easyspecs.workstations.*`**, **`easyspecs.pipelines.upload.*`** — see SRS-53 alias table). **`[ace]`** and **`[open questions]`** unchanged.
18
+
19
+ **Stderr tags (human TTY mode):** phase changes may insert a blank line when the family changes. Tags include `**[factory]`**, `**[pipeline:synthesis]**` (and `coverage`, `remediation`, `link-mapping`, `upload`, `download`), `**[workstation:<id>]**` for OpenCode subprocess lines, `**[pool]**` / `**[queue]**` for work queues, `**[deprecated-setting]**` when a legacy `**config.json**` key was consumed (canonical keys: `**easyspecs.factory.***`, `**easyspecs.workstations.***`, `**easyspecs.pipelines.upload.***` — see SRS-53 alias table). `**[ace]**` and `**[open questions]**` unchanged.
18
20
 
19
21
  Quick usage:
20
22
 
@@ -24,41 +26,45 @@ easyspecs-cli help
24
26
 
25
27
  ### Factory validation reporting (**SRS-57**)
26
28
 
27
- When **`easyspecs-cli analysis`** exits with **validation** (**`5`**), human stderr prints a short banner and **one bullet per failed factory phase** (readable label, **`validationExitId`** **`5.1`–`5.9`**, normative **`title`**, optional **`detail`**). **`--json`** adds:
29
+ When `**easyspecs-cli analysis`** exits with **validation** (`**5`**), human stderr prints a short banner and **one bullet per failed factory phase** (readable label, `**validationExitId`** `**5.1`–`5.9**`, normative `**title**`, optional `**detail**`). `**--json**` adds:
30
+
28
31
 
29
- | JSON key | Meaning |
30
- | -------- | ------- |
31
- | **`factoryFailures`** | Array of **`{ factory, phase, exitCode, failureExitId, title, validationExitId? (when exit 5), detail?, validationSubcode? }`** — **`failureExitId`** is the canonical **`major.minor`** id (SRS-58); see [`error-code.md`](./error-code.md). |
32
- | **`failurePhase`** | Last failed phase in macro order (alias for scripts). |
33
- | **`validationExitId`** | Matching **`5.x`** for **`failurePhase`**. |
34
- | **`exitMeaning`** | First failure **`title`**, or that title plus “and *N* other pipeline phases failed”. |
35
- | **`error`** | Orchestrator message; if several phases failed, a short appendix lists extra **`validationExitId`**s (see [`factoryValidationFailures.ts`](../../src/factory/factoryValidationFailures.ts)). |
32
+ | JSON key | Meaning |
33
+ | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34
+ | `**factoryFailures**` | Array of `**{ factory, phase, exitCode, failureExitId, title, validationExitId? (when exit 5), detail?, validationSubcode? }**``**failureExitId**` is the canonical `**major.minor**` id (SRS-58); see `[error-code.md](./error-code.md)`. |
35
+ | `**failurePhase**` | Last failed phase in macro order (alias for scripts). |
36
+ | `**validationExitId**` | Matching `**5.x**` for `**failurePhase**`. |
37
+ | `**exitMeaning**` | First failure `**title**`, or that title plus “and *N* other pipeline phases failed”. |
38
+ | `**error**` | Orchestrator message; if several phases failed, a short appendix lists extra `**validationExitId`**s (see `[factoryValidationFailures.ts](../../src/factory/factoryValidationFailures.ts)`). |
36
39
 
37
- **`validationExitId` → `phase` map:** **`5.1`** `create_analysis_worktree`, **`5.2`** `materialize_opencode_agents`, **`5.3`** `synthesis_convergence`, **`5.4`** `reference_coverage`, **`5.5`** `zero_reference_remediation_convergence`, **`5.6`** `reference_coverage_execution_report`, **`5.7`** `link_mapping_pipeline`, **`5.8`** `assemble_application_context_index`, **`5.9`** `backend_context_sync`, **`5.0`** unknown / unattributed. Normative **`title`** strings and readable labels: [`.gluecharm/docs/srs/srs-57.md`](../../.gluecharm/docs/srs/srs-57.md).
38
40
 
39
- **Optional `validationSubcode` (v1):** **`R5_MACRO_PING_PONG`** when synthesis **`detail`** notes **R5** unstable convergence; **`COVERAGE_PERCENT_THRESHOLD`** when reference-coverage **`detail`** matches the strict percent gate pattern.
41
+ `**validationExitId` `phase` map:** `**5.1`** `create_analysis_worktree`, `**5.2**` `materialize_opencode_agents`, `**5.3**` `synthesis_convergence`, `**5.4**` `reference_coverage`, `**5.5**` `zero_reference_remediation_convergence`, `**5.6**` `reference_coverage_execution_report`, `**5.7**` `link_mapping_pipeline`, `**5.8**` `assemble_application_context_index`, `**5.9**` `backend_context_sync`, `**5.0**` unknown / unattributed. Normative `**title**` strings and readable labels: `[.gluecharm/docs/srs/srs-57.md](../../.gluecharm/docs/srs/srs-57.md)`.
42
+
43
+ **Optional `validationSubcode` (v1):** `**R5_MACRO_PING_PONG`** when synthesis `**detail**` notes **R5** unstable convergence; `**COVERAGE_PERCENT_THRESHOLD`** when reference-coverage `**detail**` matches the strict percent gate pattern.
40
44
 
41
45
  ---
42
46
 
43
47
  ## Global options
44
48
 
45
- These flags may appear **before** the subcommand. Parsing and command registration are implemented with Commander in [`src/cli/cliProgram.ts`](../../src/cli/cliProgram.ts), with command execution in [`src/cli/main.ts`](../../src/cli/main.ts).
49
+ These flags may appear **before** the subcommand. Parsing and command registration are implemented with Commander in `[src/cli/cliProgram.ts](../../src/cli/cliProgram.ts)`, with command execution in `[src/cli/main.ts](../../src/cli/main.ts)`.
50
+
51
+
52
+ | Flag | Effect |
53
+ | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54
+ | `--cwd <dir>` | Repository root for git resolution and file paths (default: current working directory). |
55
+ | `--ci` | Non-interactive mode; feeds into merged settings (e.g. Factory outer-iteration default when unlimited). `**EASYSPECS_CI` is not read** — use this flag in CI. |
56
+ | `--json` | On supported exits, prints one JSON summary line on stdout; suppresses some human-oriented stderr unless `--verbose`. On `**analysis`** validation (**exit code 5**), the JSON line includes `**factoryFailures`** (**SRS-57** — one object per `**failed`** factory phase) plus `**failurePhase**`, `**validationExitId**`, composed `**error**`, and `**exitMeaning**` tailored to the first failure. |
57
+ | `--verbose` | Extra stderr logging where implemented. |
58
+ | `--api-base-url <url>` | System Manager API origin for this process (overrides `easyspecs.apiBaseUrl` in config). |
59
+ | `--environment production` | `--environment staging` | Alias: `**--env**`. Overrides `easyspecs.deploymentEnvironment` for built-in URL selection when no explicit URL is set. |
60
+ | `--promote` | After a successful `run synthesis`, copy generated `.gluecharm/context` from the analysis worktree into the workspace repo (when promotion is applicable). |
61
+ | `--no-promote` | Disable that promotion step for this run. |
62
+ | `--help`, `-h` | Show built-in help (also `help` as first positional). Does **not** create `.easyspecs/config.json`. |
63
+ | `--version`, `-V` | Print CLI package version (also `version` as first positional). Does **not** create config. |
64
+ | `--config <path>` | Parsed but **unused** by `main.ts` today; configuration is read from `<repoRoot>/.easyspecs/config.json`. |
46
65
 
47
- | Flag | Effect |
48
- |------|--------|
49
- | `--cwd <dir>` | Repository root for git resolution and file paths (default: current working directory). |
50
- | `--ci` | Non-interactive mode; feeds into merged settings (e.g. Factory outer-iteration default when unlimited). **`EASYSPECS_CI` is not read** — use this flag in CI. |
51
- | `--json` | On supported exits, prints one JSON summary line on stdout; suppresses some human-oriented stderr unless `--verbose`. On **`analysis`** validation (**exit code 5**), the JSON line includes **`factoryFailures`** (**SRS-57** — one object per **`failed`** factory phase) plus **`failurePhase`**, **`validationExitId`**, composed **`error`**, and **`exitMeaning`** tailored to the first failure. |
52
- | `--verbose` | Extra stderr logging where implemented. |
53
- | `--api-base-url <url>` | System Manager API origin for this process (overrides `easyspecs.apiBaseUrl` in config). |
54
- | `--environment production` \| `--environment staging` | Alias: **`--env`**. Overrides `easyspecs.deploymentEnvironment` for built-in URL selection when no explicit URL is set. |
55
- | `--promote` | After a successful `run synthesis`, copy generated `.gluecharm/context` from the analysis worktree into the workspace repo (when promotion is applicable). |
56
- | `--no-promote` | Disable that promotion step for this run. |
57
- | `--help`, `-h` | Show built-in help (also `help` as first positional). Does **not** create `.easyspecs/config.json`. |
58
- | `--version`, `-V` | Print CLI package version (also `version` as first positional). Does **not** create config. |
59
- | `--config <path>` | Parsed but **unused** by `main.ts` today; configuration is read from `<repoRoot>/.easyspecs/config.json`. |
60
66
 
61
- Environment (stderr styling): **`NO_COLOR`** (any non-empty value) disables ANSI colors. **`FORCE_COLOR`** (any non-empty value) allows colors even when stderr is not a TTY. With **`--json`**, human stderr is normally suppressed; **`--json --verbose`** prints plain stderr **without** ANSI. In human mode, a **blank line** may be printed when the diagnostic **phase** changes (e.g. **`[factory]`** → **`[pool]`** / **`[workstation:listFeatures]`**). See **README** (Terminal diagnostics).
67
+ Environment (stderr styling): `**NO_COLOR`** (any non-empty value) disables ANSI colors. `**FORCE_COLOR**` (any non-empty value) allows colors even when stderr is not a TTY. With `**--json**`, human stderr is normally suppressed; `**--json --verbose**` prints plain stderr **without** ANSI. In human mode, a **blank line** may be printed when the diagnostic **phase** changes (e.g. `**[factory]`** → `**[pool]**` / `**[workstation:listFeatures]**`). See **README** (Terminal diagnostics).
62
68
 
63
69
  ---
64
70
 
@@ -66,57 +72,61 @@ Environment (stderr styling): **`NO_COLOR`** (any non-empty value) disables ANSI
66
72
 
67
73
  ### File: `<repoRoot>/.easyspecs/config.json`
68
74
 
69
- Canonical JSON created on first need (except **`help`**, **`version`**, and **`doctor`** — no auto-create). Invalid JSON fails with a clear path (**R6**). Merged documents are also validated against **SRS-46** JSON Schema ([`srs-46-config.schema.json`](../../.gluecharm/docs/srs/srs-46-config.schema.json)) — see [`USER-MANUAL-SRS-46.md`](../../.gluecharm/docs/srs/USER-MANUAL-SRS-46.md). If **`config.json`** is missing and **`.easyspecs/cli.json`** exists, settings are imported once (**§6 M2**) into the new file.
70
-
71
- Merge uses **this file + global CLI flags only** — no `EASYSPECS_*` / `VITE_*` product overrides on **`easyspecs-cli`** (**R34**).
72
-
73
- **Workspace layout (SRS-48):** For **`analysis`**, **`update context`**, **`diagnose`**, **`upload`**, **`download context`**, and **`context link-graph`**, the CLI creates the minimal **`.gluecharm/`** directories (**`docs/srs`**, **`content`**, **`logs`**, **`context`**) under the relevant filesystem root when they are missing. You do not need to copy a Gluecharm template tree before first use.
74
-
75
- | Path | Purpose |
76
- |------|---------|
77
- | `schemaVersion` | Integer (e.g. `2`) for future migrations. |
78
- | `easyspecs.deploymentEnvironment` | `production` or `staging` (default `production`). Used with built-in System Manager URLs when `apiBaseUrl` is empty. |
79
- | `easyspecs.apiBaseUrl` | Explicit System Manager origin; wins after `--api-base-url`. Generated defaults use **`https://api.easyspecs.ai`** (production). Use **`""`** only if you want the built-in URL from **`deploymentEnvironment`** / **`--environment`** instead. |
80
- | `easyspecs.easyspecsProjectId` | Optional EasySpecs **project** id (Content application UUID). **Only** store for uploads / Sync — set via **`Send context`**, **`Changes Sync`**, **`config set-project-id`**, or **`easyspecs-cli`**. **`upload`** / **`analysis --upload`** read **only** this field (merged **`easyspecs.applicationId`** legacy key maps here). |
81
- | `easyspecs.defaultGitRemoteUrl` | Optional primary **`git remote`** URL (HTTPS or SSH) for documentation / tooling; analysis still uses the live repo. Related: **`index-application-context.json`** `repository`, **`.easyspecs/analysis-worktree.json`** `repositoryRoot`. |
82
- | `easyspecs.cliSessionPath` | Repo-relative or absolute path to **`cli-session.json`** written by **`auth login`**. Empty **`""`** → **`~/.easyspecs/cli-session.json`**. Effective path: global **`--session-path`** (if passed) **`cliSessionPath`** default home path ([`cliSession.ts`](../../src/cli/cliSession.ts)). |
83
- | `easyspecs.openCode` | `executable`, `skipCredentialsCheck` (legacy shortcut; see also `openCodeRuntime`). |
84
- | `easyspecs.analysis.*` | Remaining analysis flags (e.g. **`promoteContextToWorkspace`**, ACE toggles). **SRS-46 cache** now lives under **`easyspecs.factory.cloudContextAnalyzed`** / **`…At`** (canonical); legacy **`easyspecs.analysis.cloudContext*`** still read for one cycle. |
85
- | `easyspecs.factory.*` | Factory: **`debug`** (stderr phase transitions; legacy **`easyspecs.macro.debug`**), backoff (`initialDelayMs`, `multiplier`, `maxDelayMs`), `maxOuterIterationsPerPipeline`, `maxPingPongCycles`, `synthesisRemediationShareBackoff`, cloud-context-analyzed cache. Legacy **`easyspecs.orchestration.*`** aliases per SRS-53. |
86
- | `easyspecs.workstations.*` | OpenCode argv template, timeouts, repair attempts, pool width, coordination lock timeout. Legacy **`easyspecs.analysis.openCodeTest*`** / **`listJsonSchemaRepairAttempts`** / **`markdown*`** / **`maxConcurrentOpenCodeAgents`** / **`coordinationListLockTimeoutMs`** aliases. |
87
- | `easyspecs.pipelines.upload.useBatch` | Upload batching preference. Legacy **`easyspecs.analysis.uploadUseBatch`**. |
88
- | `easyspecs.orchestration.*` | **Deprecated** use **`easyspecs.factory.*`** (SRS-53); still merged when present. |
89
- | `easyspecs.openCodeRuntime` | Annex-aligned block: `providers` (per-provider `apiKey`, `defaultModel`), `run`, `coordinationRepairs`, `pool`, `projectConfigOverlay` — see [`srs-43-opencode.schema.json`](../../.gluecharm/docs/srs/srs-43-opencode.schema.json). |
90
- | `easyspecs.diagnose.zeroReference.maxPercentNonReferenced` | `number` \| **`null`**. When **`null`**, `diagnose reference-coverage` does not fail on percent alone (**SRS-44**). |
91
- | `easyspecs.diagnose.coordinationDuplicates.strict` | Boolean (default **`true`**). When **`true`**, duplicate/orphan rows fail `diagnose coordination-duplicates`. |
92
- | `easyspecs.upload.contextDirectory` | Repo-relative or absolute override for **`upload republish`** context dir; empty **`""`** automatic (analysis snapshot). |
93
- | `easyspecs.upload.fetchContextAnalyzedInCloud` | Boolean, default **`true`**. When **`true`**, after a fully successful **`upload context`** / **`upload republish`**, the CLI performs **`GET /api/content/application/:id`** and emits **`contextAnalyzedInCloud`** / **`contextAnalyzedInCloudAt`** on **`--json`**; updates **`easyspecs.factory.cloudContext*`** cache (legacy **`easyspecs.analysis.cloudContext*`**). When **`false`**, skips that GET and omits those JSON keys. |
94
- | `easyspecs.upload.contextAnalyzedStatusTimeoutMs` | Optional positive integer (ms). GET timeout; default **15000** if omitted. |
95
- | `easyspecs.cli.bundledResourcesRoot` | Optional path to bundled **`resources/`** (folder containing **`opencode-agents/`**). Empty infer next to the CLI package. |
96
- | `easyspecs.auth.ciLogin.email` / `password` | Used only with **`--ci`** when **`--email` / `--password`** are omitted (**SRS-44**). Prefer CI-generated **`config.json`**; do not commit secrets. |
75
+ Canonical JSON created on first need (except `**help`**, `**version**`, and `**doctor**` — no auto-create). Invalid JSON fails with a clear path (**R6**). Merged documents are also validated against **SRS-46** JSON Schema (`[srs-46-config.schema.json](../../.gluecharm/docs/srs/srs-46-config.schema.json)`) — see `[USER-MANUAL-SRS-46.md](../../.gluecharm/docs/srs/USER-MANUAL-SRS-46.md)`. If `**config.json`** is missing and `**.easyspecs/cli.json**` exists, settings are imported once (**§6 M2**) into the new file.
76
+
77
+ Merge uses **this file + global CLI flags only** — no `EASYSPECS_*` / `VITE_*` product overrides on `**easyspecs-cli`** (**R34**).
78
+
79
+ **Workspace layout (SRS-48):** For `**analysis`**, `**update context**`, `**diagnose**`, `**upload**`, `**download context**`, and `**context link-graph**`, the CLI creates the minimal `**.gluecharm/**` directories (`**docs/srs**`, `**content**`, `**logs**`, `**context**`) under the relevant filesystem root when they are missing. You do not need to copy a Gluecharm template tree before first use.
80
+
81
+
82
+ | Path | Purpose |
83
+ | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
84
+ | `schemaVersion` | Integer (e.g. `2`) for future migrations. |
85
+ | `easyspecs.deploymentEnvironment` | `production` or `staging` (default `production`). Used with built-in System Manager URLs when `apiBaseUrl` is empty. |
86
+ | `easyspecs.apiBaseUrl` | Explicit System Manager origin; wins after `--api-base-url`. Generated defaults use `**https://api.easyspecs.ai**` (production). Use `**""**` only if you want the built-in URL from `**deploymentEnvironment**` / `**--environment**` instead. |
87
+ | `easyspecs.easyspecsProjectId` | Optional EasySpecs **project** id (Content application UUID). **Only** store for uploads / Sync set via `**Send context`**, `**Changes Sync**`, `**config set-project-id**`, or `**easyspecs-cli**`. **`upload context`** / **`upload republish`** read **only** this field (merged `**easyspecs.applicationId`** legacy key maps here). |
88
+ | `easyspecs.defaultGitRemoteUrl` | Optional primary `**git remote**` URL (HTTPS or SSH) for documentation / tooling; analysis still uses the live repo. Related: `**index-application-context.json**` `repository`, `**.easyspecs/analysis-worktree.json**` `repositoryRoot`. |
89
+ | `easyspecs.cliSessionPath` | Repo-relative or absolute path to `**cli-session.json**` written by `**auth login**`. Empty `**""**` → `**~/.easyspecs/cli-session.json**`. Effective path: global `**--session-path**` (if passed) `**cliSessionPath**` → default home path (`[cliSession.ts](../../src/cli/cliSession.ts)`). |
90
+ | `easyspecs.openCode` | `executable`, `skipCredentialsCheck` (legacy shortcut; see also `openCodeRuntime`). |
91
+ | `easyspecs.analysis.*` | Remaining analysis flags (e.g. `**promoteContextToWorkspace**`, ACE toggles). **SRS-46 cache** now lives under `**easyspecs.factory.cloudContextAnalyzed`** / `**…At**` (canonical); legacy `**easyspecs.analysis.cloudContext***` still read for one cycle. |
92
+ | `easyspecs.factory.*` | Factory: `**debug**` (stderr phase transitions; legacy `**easyspecs.macro.debug**`), backoff (`initialDelayMs`, `multiplier`, `maxDelayMs`), `maxOuterIterationsPerPipeline`, `maxPingPongCycles`, `synthesisRemediationShareBackoff`, cloud-context-analyzed cache. Legacy `**easyspecs.orchestration.***` aliases per SRS-53. |
93
+ | `easyspecs.workstations.*` | OpenCode argv template, timeouts, repair attempts, pool width, coordination lock timeout. Legacy `**easyspecs.analysis.openCodeTest***` / `**listJsonSchemaRepairAttempts**` / `**markdown***` / `**maxConcurrentOpenCodeAgents**` / `**coordinationListLockTimeoutMs**` aliases. |
94
+ | `easyspecs.pipelines.upload.useBatch` | Upload batching preference. Legacy `**easyspecs.analysis.uploadUseBatch**`. |
95
+ | `easyspecs.orchestration.*` | **Deprecated** use `**easyspecs.factory.*`** (SRS-53); still merged when present. |
96
+ | `easyspecs.openCodeRuntime` | Annex-aligned block: `providers` (per-provider `apiKey`, `defaultModel`), `run`, `coordinationRepairs`, `pool`, `projectConfigOverlay` see `[srs-43-opencode.schema.json](../../.gluecharm/docs/srs/srs-43-opencode.schema.json)`. |
97
+ | `easyspecs.diagnose.zeroReference.maxPercentNonReferenced` | `number` | `**null**`. When `**null**`, `diagnose reference-coverage` does not fail on percent alone (**SRS-44**). |
98
+ | `easyspecs.diagnose.coordinationDuplicates.strict` | Boolean (default `**true`**). When `**true**`, duplicate/orphan rows fail `diagnose coordination-duplicates`. |
99
+ | `easyspecs.upload.contextDirectory` | Repo-relative or absolute override for `**upload republish**` context dir; empty `**""**` automatic (analysis snapshot). |
100
+ | `easyspecs.upload.fetchContextAnalyzedInCloud` | Boolean, default `**true**`. When `**true**`, after a fully successful `**upload context**` / `**upload republish**`, the CLI performs `**GET /api/content/application/:id**` and emits `**contextAnalyzedInCloud**` / `**contextAnalyzedInCloudAt**` on `**--json**`; updates `**easyspecs.factory.cloudContext***` cache (legacy `**easyspecs.analysis.cloudContext***`). When `**false**`, skips that GET and omits those JSON keys. |
101
+ | `easyspecs.upload.contextAnalyzedStatusTimeoutMs` | Optional positive integer (ms). GET timeout; default **15000** if omitted. |
102
+ | `easyspecs.cli.bundledResourcesRoot` | Optional path to bundled `**resources/`** (folder containing `**opencode-agents/**`). Empty infer next to the CLI package. |
103
+ | `easyspecs.auth.ciLogin.email` / `password` | Used only with `**--ci**` when `**--email` / `--password**` are omitted (**SRS-44**). Prefer CI-generated `**config.json`**; do not commit secrets. |
104
+
97
105
 
98
106
  ### Resolved System Manager URL (`easyspecs-cli`)
99
107
 
100
- **Order:** `--api-base-url` → non-empty `easyspecs.apiBaseUrl` → built-in URL from effective environment (**`--environment`** \|\| **`easyspecs.deploymentEnvironment`** \|\| **`production`**). No `.env` / `process.env` product keys (**R30**).
108
+ **Order:** `--api-base-url` → non-empty `easyspecs.apiBaseUrl` → built-in URL from effective environment (`**--environment`** `**easyspecs.deploymentEnvironment**` `**production**`). No `.env` / `process.env` product keys (**R30**).
101
109
 
102
- Built-in defaults ship in [`src/easyspecsBuiltInApiUrls.ts`](../../src/easyspecsBuiltInApiUrls.ts).
110
+ Built-in defaults ship in `[src/easyspecsBuiltInApiUrls.ts](../../src/easyspecsBuiltInApiUrls.ts)`.
103
111
 
104
112
  ### No EasySpecs `EASYSPECS_*` configuration env (**SRS-44**)
105
113
 
106
- **`easyspecs-cli`** does **not** read **`EASYSPECS_*`**, **`VITE_*`**, or **`.env`** for product settings — use **`.easyspecs/config.json`** (+ global CLI flags) only. OS-level variables such as **`PATH`** still apply for finding **`node`**, **`opencode`**, **`git`**.
114
+ `**easyspecs-cli`** does **not** read `**EASYSPECS_*`**, `**VITE_***`, or `**.env**` for product settings — use `**.easyspecs/config.json**` (+ global CLI flags) only. OS-level variables such as `**PATH**` still apply for finding `**node**`, `**opencode**`, `**git**`.
107
115
 
108
- Provider API keys for OpenCode runs should live under **`easyspecs.openCodeRuntime.providers`** in **`config.json`**; they are injected into the **child** OpenCode process (**R13**) and redacted in **`doctor --inspect-config`** (**R17**).
116
+ Provider API keys for OpenCode runs should live under `**easyspecs.openCodeRuntime.providers**` in `**config.json**`; they are injected into the **child** OpenCode process (**R13**) and redacted in `**doctor --inspect-config`** (**R17**).
109
117
 
110
118
  ---
111
119
 
112
120
  ## Diagnose / context flags
113
121
 
114
- Used after `diagnose <subcommand>` or **`context link-graph`**:
122
+ Used after `diagnose <subcommand>` or `**context link-graph`**:
123
+
124
+
125
+ | Flag | Values | Meaning |
126
+ | ------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
127
+ | `--root` | `workspace` or `worktree` | Whether paths resolve against the workspace repo root or an analysis checkout (`[parseTailFlags](../../src/cli/parseTailFlags.ts)`). |
128
+ | `--worktree` | path | Analysis git checkout (required for `--root worktree` when no path embedded in `--root` flow; combined with explicit `--worktree` — see `main.ts`). |
115
129
 
116
- | Flag | Values | Meaning |
117
- |------|--------|---------|
118
- | `--root` | `workspace` or `worktree` | Whether paths resolve against the workspace repo root or an analysis checkout ([`parseTailFlags`](../../src/cli/parseTailFlags.ts)). |
119
- | `--worktree` | path | Analysis git checkout (required for `--root worktree` when no path embedded in `--root` flow; combined with explicit `--worktree` — see `main.ts`). |
120
130
 
121
131
  ---
122
132
 
@@ -124,45 +134,48 @@ Used after `diagnose <subcommand>` or **`context link-graph`**:
124
134
 
125
135
  Each row lists **command-specific CLI tokens**, then **what configuration applies**.
126
136
 
127
- | Command | Command-specific flags / tokens | Configuration & notes |
128
- |---------|--------------------------------|----------------------|
129
- | `help`, `--help` | | Global options only; prints usage. |
130
- | `version` | — | Prints [`PKG_VERSION`](../../src/cli/main.ts) from the bundle. |
131
- | `doctor` | Optional **`--readiness`**, **`--inspect-config`** | **Does not** create `config.json`. Default (no flags) = **`--readiness`**: repo root, resolved API URL, OpenCode installed/credentials, agents dir. **`--inspect-config`** alone: redacted **`merged`** + **`easyspecsConfig`**. **`--readiness --inspect-config`**: both. Global flags apply (**`--cwd`**, **`--ci`**, **`--api-base-url`**, **`--session-path`**, **`--environment`**, **`--promote`** / **`--no-promote`**). |
132
- | `config init` | Optional **`--overwrite`** | Creates **`<repo>/.easyspecs/config.json`** with full defaults if missing; imports legacy **`cli.json`** / **`settings.json`** (ACE) when present, same as first-time bootstrap. If the file already exists, does nothing unless **`--overwrite`** (replaces with that bootstrap content). Does not run other commands. |
133
- | `config set-project-id <id>` | | Writes **`easyspecs.easyspecsProjectId`** to **`config.json`**, replacing any previous value. Creates **`config.json`** (defaults + legacy import) if missing. |
134
- | `config set-git-remote <url>` | — | Writes **`easyspecs.defaultGitRemoteUrl`** to **`config.json`**, replacing any previous value. Same bootstrap-if-missing behaviour as **`set-project-id`**. |
135
- | `auth login` | **`--email <email> --password <password>`**, optional **`--session-path <path>`** (tail; updates **`config.json`**) | Calls **`POST /api/authentication/login`**. On success prints **`OK`** (stdout), exit **0**, and writes tokens + **`apiBaseUrl`** to the session file. Tail **`--session-path`** updates **`easyspecs.cliSessionPath`** in **`config.json`** (normalized repo-relative when under the repo) and writes the session there for this run; omit it to use the existing **`easyspecs.cliSessionPath`** / default **`~/.easyspecs/cli-session.json`**. Global **`--session-path`** (before the command) overrides the effective session file for any command without changing **`config.json`**. On failure prints **`KO: …`** (stderr), exit **`auth`**. **`easyspecs-cli --ci auth login`** without argv credentials uses **`easyspecs.auth.ciLogin`** in **`config.json`**. **`--password`** on argv is visible to **`ps`**. |
136
- | `auth logout` | | Deletes the effective session file (same path rules as **`auth login`**). |
137
- | `auth status` | — | Reads session file. |
138
- | `run synthesis` | — | Single SRS-9 context pass (same as extension **Run Analysis**). **`requireOpenCode`** → executable + credentials unless skip flag. Uses **`merged.pipelineOpenCode`** from **`config.json`**. **`--promote` / `--no-promote`** controls promotion after success. |
139
- | `run synthesis resume-missing`, `run synthesis resume-synthesis` | Optional **`--worktree <path>`** | Same implementation: resolves checkout via `--worktree` or stored snapshot ([`resolveAdHocCheckoutRoot`](../../src/cli/main.ts)). OpenCode + **`merged.pipelineOpenCode`**. |
140
- | `analysis` | Optional tokens anywhere in argv: **`--synthesis-only`**, **`--upload`**, **`--force-new-context-analysis`** | **SRS-32** full **Factory** loop: synthesis convergence (until no missing artefacts), coverage, zero-ref, report, **link mapping**, index assembly, optional backend sync. Factory timing from **`merged.factory`** (internal merge shape in [`cliSettings.ts`](../../src/cli/cliSettings.ts)) + **`--ci`** defaults. **`--upload`** requires prior **`auth login`** session. Debug: **`easyspecs.factory.debug`** (legacy **`easyspecs.macro.debug`**). OpenCode options from **`merged.pipelineOpenCode`**. **SRS-46:** if **`easyspecs.factory.cloudContextAnalyzed`** is **`true`** (legacy **`easyspecs.analysis.cloudContextAnalyzed`**) and neither **`--synthesis-only`** nor **`--force-new-context-analysis`** is set, exits **0** without running the Factory or **`--upload`** (machine fields: **`analysisSkipped`**, **`skipReason`**, **`cloudContextAnalyzedAt`**). **SRS-59:** if **`git worktree add`** fails with Git’s *missing but already registered worktree* (temp checkout folder gone but still registered), the CLI runs **`git worktree prune`** in the repo root and retries **`worktree add`** once — see **§ Analysis git checkout** below. |
141
- | `update context` | Optional **`--upload`** (anywhere in tail, same pattern as **`analysis --upload`**) | **SRS-55:** incremental context refresh baseline **`easyspecs.factory.updateContext.lastRunAt`** **or** max workspace **`.gluecharm/context`** mtime git commits after baseline analysis worktree seed check (optional copy from workspace if **HEAD** worktree lacks context) **`changes-since-date.md`** optional scoped zero-reference remediation **`--promote` / `--no-promote`** (global) optional **`--upload`** (files touched this run via mtime gate) persist **`lastRunAt`**. **`--upload`** requires **`auth`** + **`easyspecs.easyspecsProjectId`**. |
142
- | `diagnose reference-coverage` | **`--root workspace`** \| **`--root worktree`**, optional **`--worktree <path>`** | Gate when **`easyspecs.diagnose.zeroReference.maxPercentNonReferenced`** is a finite number (not **`null`**): failure when metric exceeds it. |
143
- | `diagnose coordination-duplicates` | Same **`--root`** / **`--worktree`** | **`easyspecs.diagnose.coordinationDuplicates.strict`**: when **`true`** (default), duplicate/orphan issues fail the exit code. |
144
- | `diagnose coverage-report` | Same **`--root`** / **`--worktree`** | Uses repo/worktree paths only; no extra env in `main.ts`. |
145
- | `diagnose missing-artefacts` | Same **`--root`** / **`--worktree`** | Reads artefact snapshot from workspace state; no OpenCode. |
146
- | `diagnose zero-reference` | Optional **`--worktree <path>`** (no `--root` branch in this handler) | **`requireOpenCode`**; **`merged.pipelineOpenCode`** for pool concurrency/argv/timeout. Checkout from **`--worktree`** or snapshot ([`resolveAdHocCheckoutRoot`](../../src/cli/main.ts)). On full success, runs **SRS-51** markdown link graph on **`<checkout>/.gluecharm/context`** before exit (**non-zero** if link validation fails). |
147
- | `context link-graph` | **`--root workspace`** \| **`--root worktree`**, optional **`--worktree <path>`** | **SRS-51:** deterministic navigation sections in context markdown under **`<root>/.gluecharm/context`**. No OpenCode. **`--json`**: **`ok`**, **`contextDir`**, **`error`**, **`brokenLinks`**. Exit **`validation`** on broken relative links inside EasySpecs nav regions. |
148
- | `context drift <referencePath>` | **`--label <slug>`**, **`--index <path>`**, **`--dry-run`**. Optional **`--root`** / **`--worktree`** tail tokens are accepted and ignored for v1 routing. | **SRS-56:** analysis worktree OpenCode drift agent **`.gluecharm/context/drift/drift-<slug>-<date>.md`** + reference index patch global **`--promote` / `--no-promote`**. Success stdout: drift report path. |
149
- | `download context` | Optional **`--force`**, **`--replace-from-cloud`** | **SRS-49:** requires **`auth`** session. **`GET /api/content/application/:id`** **`srs_discovery`** ids **`POST /api/batch/content/srs_discovery/get`**writes files under **`<repoRoot>/.gluecharm/context`**. **`--force`** overwrites existing paths; **`--replace-from-cloud`** deletes local context files first (preserves root **`easyspecs-upload-target.json`**). **`--json`** stdout: **`downloaded`**, **`skipped`**, **`failed`**, **`localRemoved`**. Exit **`upload`** when any row fails. |
150
- | `upload context` | | Requires **`auth`** session. Context dir: **`<repoRoot>/.gluecharm/context`**. Project id: **`easyspecs.easyspecsProjectId`** in **`config.json`** only. **SRS-46:** on full success, optional cloud status GET (see **`fetchContextAnalyzedInCloud`**); **`--json`** may add **`contextAnalyzedInCloud`** / **`contextAnalyzedInCloudAt`**; updates **`easyspecs.factory.cloudContext*`** when fetch is enabled (legacy **`easyspecs.analysis.cloudContext*`**). |
151
- | `upload republish` | — | Same auth + upload pipeline; context dir from **`easyspecs.upload.contextDirectory`** if non-empty and valid, else analysis worktree **`…/.gluecharm/context`** from snapshot, else error. Same project id rule as **`upload context`**. Same **SRS-46** JSON + cache behaviour as **`upload context`**. |
152
- | `ace clear` | — | Deletes **`<repoRoot>/.gluecharm/context/learnings`**. |
153
- | `ace learn` | Optional **`--worktree <path>`** | **`requireOpenCode`**; worktree chosen if `--worktree` points at checkout with **`.opencode/schemas/ace`**, else **`repoRoot`** ([`main.ts`](../../src/cli/main.ts)). **`merged.pipelineOpenCode`** for spawn argv/timeout. |
154
- | `ace auto-learn` | Optional **`--worktree <path>`** | **`requireOpenCode`**; checkout = `--worktree` if valid git dir, else **`repoRoot`**. **`merged.pipelineOpenCode.maxConcurrentOpenCodeAgents`** caps parallelism. |
137
+
138
+ | Command | Command-specific flags / tokens | Configuration & notes |
139
+ | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
140
+ | `help`, `--help` | — | Global options only; prints usage. |
141
+ | `version` | | Prints `[PKG_VERSION](../../src/cli/main.ts)` from the bundle. |
142
+ | `doctor` | Optional `**--readiness`**, `**--inspect-config**` | **Does not** create `config.json`. Default (no flags) = `**--readiness`**: repo root, resolved API URL, OpenCode installed/credentials, agents dir. `**--inspect-config**` alone: redacted `**merged**` + `**easyspecsConfig**`. `**--readiness --inspect-config**`: both. Global flags apply (`**--cwd**`, `**--ci**`, `**--api-base-url**`, `**--session-path**`, `**--environment**`, `**--promote**` / `**--no-promote**`). |
143
+ | `config init` | Optional `**--overwrite**` | Creates `**<repo>/.easyspecs/config.json**` with full defaults if missing; imports legacy `**cli.json**` / `**settings.json**` (ACE) when present, same as first-time bootstrap. If the file already exists, does nothing unless `**--overwrite**` (replaces with that bootstrap content). Does not run other commands. |
144
+ | `config set-project-id <id>` | — | Writes `**easyspecs.easyspecsProjectId**` to `**config.json**`, replacing any previous value. Creates `**config.json**` (defaults + legacy import) if missing. |
145
+ | `config set-git-remote <url>` | | Writes `**easyspecs.defaultGitRemoteUrl**` to `**config.json**`, replacing any previous value. Same bootstrap-if-missing behaviour as `**set-project-id**`. |
146
+ | `auth login` | `**--email <email> --password <password>**`, optional `**--session-path <path>**` (tail; updates `**config.json**`) | Calls `**POST /api/authentication/login**`. On success prints `**OK**` (stdout), exit **0**, and writes tokens + `**apiBaseUrl`** to the session file. Tail `**--session-path**` updates `**easyspecs.cliSessionPath**` in `**config.json**` (normalized repo-relative when under the repo) and writes the session there for this run; omit it to use the existing `**easyspecs.cliSessionPath**` / default `**~/.easyspecs/cli-session.json**`. Global `**--session-path**` (before the command) overrides the effective session file for any command without changing `**config.json**`. On failure prints `**KO: …**` (stderr), exit `**auth**`. `**easyspecs-cli --ci auth login**` without argv credentials uses `**easyspecs.auth.ciLogin**` in `**config.json**`. `**--password**` on argv is visible to `**ps**`. |
147
+ | `auth logout` | — | Deletes the effective session file (same path rules as `**auth login**`). |
148
+ | `auth status` | — | Reads session file. |
149
+ | `run synthesis` | — | Single SRS-9 context pass (same as extension **Run Analysis**). `**requireOpenCode`** executable + credentials unless skip flag. Uses `**merged.pipelineOpenCode**` from `**config.json**`. `**--promote` / `--no-promote**` controls promotion after success. |
150
+ | `run synthesis resume-missing`, `run synthesis resume-synthesis` | Optional `**--worktree <path>**` | Same implementation: resolves checkout via `--worktree` or stored snapshot (`[resolveAdHocCheckoutRoot](../../src/cli/main.ts)`). OpenCode + `**merged.pipelineOpenCode**`. |
151
+ | `analysis` | Optional tail: `**--force-new-context-analysis**`. **`--upload`** usage exit. **`--synthesis-only`**: accepted as a **hidden** Commander option (legacy scripts); **ignored** with one stderr **`[deprecated]`** line (**SRS-60**). | **SRS-32** full **Factory** loop: synthesis convergence (until no missing artefacts), coverage, zero-ref, report, **link mapping**, index assembly; **Phase 7** backend sync is skipped in CLI (**`skipBackendSync`**). Push context with **`upload context`** / **`upload republish`** after analysis. Factory timing from `**merged.factory`** + `**--ci**` defaults. Debug: `**easyspecs.factory.debug**`. OpenCode options from `**merged.pipelineOpenCode**`. **SRS-46:** if `**easyspecs.factory.cloudContextAnalyzed`** is `**true**` and `**--force-new-context-analysis**` is absent, exits **0** without running the Factory (`**analysisSkipped**`, …). **SRS-59:** stale worktree registration recovery see **§ Analysis git checkout** below. |
152
+ | `update context` | — (no subcommand flags; **SRS-60** removed `**--upload**`) | **SRS-55:** incremental context refresh baseline git delta worktree → `**changes-since-date.md`** optional remediation **`--promote` / `--no-promote**` (global) → persist `**lastRunAt**`. Run **`upload context`** separately if you need cloud sync. |
153
+ | `diagnose reference-coverage` | `**--root workspace**` | `**--root worktree**`, optional `**--worktree <path>**` | Gate when `**easyspecs.diagnose.zeroReference.maxPercentNonReferenced**` is a finite number (not `**null**`): failure when metric exceeds it. |
154
+ | `diagnose coordination-duplicates` | Same `**--root**` / `**--worktree**` | `**easyspecs.diagnose.coordinationDuplicates.strict**`: when `**true**` (default), duplicate/orphan issues fail the exit code. |
155
+ | `diagnose coverage-report` | Same `**--root**` / `**--worktree**` | Uses repo/worktree paths only; no extra env in `main.ts`. |
156
+ | `diagnose missing-artefacts` | Same `**--root**` / `**--worktree**` | Reads artefact snapshot from workspace state; no OpenCode. |
157
+ | `diagnose zero-reference` | Optional `**--worktree <path>**` (no `--root` branch in this handler) | `**requireOpenCode**`; `**merged.pipelineOpenCode**` for pool concurrency/argv/timeout. Checkout from `**--worktree**` or snapshot (`[resolveAdHocCheckoutRoot](../../src/cli/main.ts)`). On full success, runs **SRS-51** markdown link graph on `**<checkout>/.gluecharm/context`** before exit (**non-zero** if link validation fails). |
158
+ | `context link-graph` | `**--root workspace`** | `**--root worktree**`, optional `**--worktree <path>**` | **SRS-51:** deterministic navigation sections in context markdown under `**<root>/.gluecharm/context`**. No OpenCode. `**--json**`: `**ok**`, `**contextDir**`, `**error**`, `**brokenLinks**`. Exit `**validation**` on broken relative links inside EasySpecs nav regions. |
159
+ | `context drift <referencePath>` | `**--label <slug>**`, `**--index <path>**`, `**--dry-run**`. Optional `**--root**` / `**--worktree**` tail tokens are accepted and ignored for v1 routing. | **SRS-56:** analysis worktree OpenCode drift agent → `**.gluecharm/context/drift/drift-<slug>-<date>.md`** + reference index patch global `**--promote` / `--no-promote**`. Success stdout: drift report path. |
160
+ | `download context` | Optional `**--force**`, `**--replace-from-cloud**` | **SRS-49:** requires `**auth`** session. `**GET /api/content/application/:id**` → `**srs_discovery**` ids → `**POST /api/batch/content/srs_discovery/get**` → writes files under `**<repoRoot>/.gluecharm/context**`. `**--force**` overwrites existing paths; `**--replace-from-cloud**` deletes local context files first (preserves root `**easyspecs-upload-target.json**`). `**--json**` stdout: `**downloaded**`, `**skipped**`, `**failed**`, `**localRemoved**`. Exit `**upload**` when any row fails. |
161
+ | `upload context` | — | Requires `**auth**` session. Context dir: `**<repoRoot>/.gluecharm/context**`. Project id: `**easyspecs.easyspecsProjectId**` in `**config.json**` only. **SRS-46:** on full success, optional cloud status GET (see `**fetchContextAnalyzedInCloud`**); `**--json**` may add `**contextAnalyzedInCloud**` / `**contextAnalyzedInCloudAt**`; updates `**easyspecs.factory.cloudContext***` when fetch is enabled (legacy `**easyspecs.analysis.cloudContext***`). |
162
+ | `upload republish` | — | Same auth + upload pipeline; context dir from `**easyspecs.upload.contextDirectory**` if non-empty and valid, else analysis worktree `**…/.gluecharm/context**` from snapshot, else error. Same project id rule as `**upload context**`. Same **SRS-46** JSON + cache behaviour as `**upload context`**. |
163
+ | `ace clear` | | Deletes `**<repoRoot>/.gluecharm/context/learnings**`. |
164
+ | `ace learn` | Optional `**--worktree <path>**` | `**requireOpenCode**`; worktree chosen if `--worktree` points at checkout with `**.opencode/schemas/ace**`, else `**repoRoot**` (`[main.ts](../../src/cli/main.ts)`). `**merged.pipelineOpenCode**` for spawn argv/timeout. |
165
+ | `ace auto-learn` | Optional `**--worktree <path>**` | `**requireOpenCode**`; checkout = `--worktree` if valid git dir, else `**repoRoot**`. `**merged.pipelineOpenCode.maxConcurrentOpenCodeAgents**` caps parallelism. |
166
+
155
167
 
156
168
  ### Analysis git checkout (**SRS-59**)
157
169
 
158
- The Factory creates a **detached** analysis checkout under **`$TMPDIR/easyspecs-analysis/easyspecs-NNN`** ([`worktreeManager.ts`](../../src/analysis/worktreeManager.ts)). If the OS removes that folder (or it is deleted) **without** **`git worktree remove`**, Git may still list the path and **`git worktree add`** fails with *missing but already registered worktree*. **SRS-59:** **`easyspecs-cli`** detects that failure class, runs **`git worktree prune`** with **`cwd`** = the repository root (from **`--cwd`** / current directory), then retries **`git worktree add`** **once** at the same allocated path ([`gitWorktreeStaleRecovery.ts`](../../src/analysis/gitWorktreeStaleRecovery.ts)). Stderr may include **`[worktree] git worktree prune — cleared stale registration for <folder> (<absolute path>)`** before the retry. Manual troubleshooting: [`.gluecharm/docs/srs/USER-MANUAL-SRS-59.md`](../../.gluecharm/docs/srs/USER-MANUAL-SRS-59.md).
170
+ The Factory creates a **detached** analysis checkout under `**$TMPDIR/easyspecs-analysis/easyspecs-NNN`** (`[worktreeManager.ts](../../src/analysis/worktreeManager.ts)`). If the OS removes that folder (or it is deleted) **without** `**git worktree remove`**, Git may still list the path and `**git worktree add**` fails with *missing but already registered worktree*. **SRS-59:** `**easyspecs-cli*`* detects that failure class, runs `**git worktree prune**` with `**cwd**` = the repository root (from `**--cwd**` / current directory), then retries `**git worktree add**` **once** at the same allocated path (`[gitWorktreeStaleRecovery.ts](../../src/analysis/gitWorktreeStaleRecovery.ts)`). Stderr may include `**[worktree] git worktree prune — cleared stale registration for <folder> (<absolute path>)`** before the retry. Manual troubleshooting: `[.gluecharm/docs/srs/USER-MANUAL-SRS-59.md](../../.gluecharm/docs/srs/USER-MANUAL-SRS-59.md)`.
159
171
 
160
172
  ---
161
173
 
162
174
  ## Notes
163
175
 
164
- - Commands that **spawn OpenCode** call **`requireOpenCode`**: binary must respond (`easyspecs.openCode.executable` / `opencode` on **`PATH`**), and credentials must look ready unless **`easyspecs.openCode.skipCredentialsCheck`**, or provider keys exist in **`config.json`**, or the parent shell already has provider env (probe behaviour in [`opencodeCli`](../../src/opencodeCli.ts)).
165
- - **`download context`** / **`upload`** / **`analysis --upload`** / **`update context --upload`** require a prior **`auth login`** session (**`--email`** / **`--password`**, or **`--ci`** with **`easyspecs.auth.ciLogin`** in **`config.json`**).
176
+ - Commands that **spawn OpenCode** call `**requireOpenCode`**: binary must respond (`easyspecs.openCode.executable` / `opencode` on `**PATH**`), and credentials must look ready unless `**easyspecs.openCode.skipCredentialsCheck**`, or provider keys exist in `**config.json**`, or the parent shell already has provider env (probe behaviour in `[opencodeCli](../../src/opencodeCli.ts)`).
177
+ - `**download context**` / `**upload context**` / `**upload republish**` require a prior `**auth login**` session (`**--email**` / `**--password**`, or `**--ci**` with `**easyspecs.auth.ciLogin**` in `**config.json**`).
166
178
  - Unknown commands print help and exit with a usage error.
167
- - Git subprocesses may set **`GIT_TERMINAL_PROMPT=0`** on the child environment ([`runCoveragePipeline`](../../src/pipelines/coverage/coveragePipeline.ts)).
168
- - Any command path that **creates** the analysis git worktree (**`analysis`**, **`run synthesis`**, **`update context`**, **`context drift`** without **`--dry-run`**, etc.) benefits from **SRS-59** stale-registration recovery in **`createAnalysisWorktree`**, not only **`analysis`**.
179
+ - Git subprocesses may set `**GIT_TERMINAL_PROMPT=0**` on the child environment (`[runCoveragePipeline](../../src/pipelines/coverage/coveragePipeline.ts)`).
180
+ - Any command path that **creates** the analysis git worktree (`**analysis`**, `**run synthesis**`, `**update context**`, `**context drift**` without `**--dry-run**`, etc.) benefits from **SRS-59** stale-registration recovery in `**createAnalysisWorktree`**, not only `**analysis**`.
181
+