@adhd/backlog 0.0.1 → 0.0.2

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
@@ -54,10 +54,46 @@ const abort = new AbortController();
54
54
  await startBacklogServer({ transport: 'both', port: 3400, signal: abort.signal });
55
55
  ```
56
56
 
57
- - `POST /backlog/createItem`, `GET /backlog/getItem`, ... — every `client.ts`
58
- export, mounted live via `@adhd/apigen-plugin-api-fastify`.
59
- - Every export is also available as an MCP tool via `@adhd/apigen-plugin-mcp`
60
- (stdio transport by default).
57
+ - `POST /backlog/client-d/create-item`, `GET /backlog/client-d/get-item`, ... —
58
+ every `client.ts` export, mounted live via `@adhd/apigen-plugin-api-fastify`.
59
+ (The `client-d` route segment is not a typo — see `DESIGN.md` §7's CLI
60
+ section / `SPEC.md` §7's transport table for why it's there.)
61
+ - Every export is also available as an MCP tool (e.g. `backlog_client_d_get_item`)
62
+ via `@adhd/apigen-plugin-mcp` (stdio transport by default).
63
+
64
+ ## CLI (`backlog`, live apigen mount — no codegen)
65
+
66
+ ```bash
67
+ pnpm add -g @adhd/backlog # installs the `backlog` bin
68
+ backlog --help # live-derived command listing
69
+ backlog create-item --input '{"family":"BUG-EXAMPLE","title":"t","body":"b","repo":"org/repo"}'
70
+ backlog get-item --repo org/repo --human-id BUG-EXAMPLE-001
71
+ backlog list-items --filter '{"status":"OPEN"}'
72
+ ```
73
+
74
+ - Same architecture as the HTTP/MCP transports above — `entrypoint/backlog/src/cli.ts`'s
75
+ `runBacklogCli()` reuses `buildBacklogApigenPackage()` and hands it straight
76
+ to `@adhd/apigen-plugin-cli-output`'s `run()`. No `apigen generate`, no
77
+ bespoke argument parsing — routing, flag parsing, validation, dispatch, and
78
+ exit codes all come from that plugin.
79
+ - **You type `backlog <command>`, never the internal `client-d` segment.**
80
+ `runBacklogCli` derives the real command-table prefix from the live
81
+ `operations` list at runtime (`resolveCommandPrefix`) and prepends it before
82
+ dispatch — so `backlog get-item …` resolves even though the plugin's real
83
+ command table is keyed `backlog client-d get-item` internally (same
84
+ `client-d` artifact as the HTTP/MCP routes above; the CLI is the one
85
+ transport that hides it from the caller).
86
+ - Flags are the schema's domain params, kebab-cased (`humanId` → `--human-id`);
87
+ object/array-typed params take a JSON string (`--input '{...}'`,
88
+ `--filter '{...}'`).
89
+ - Exit codes follow `@adhd/apigen-base-errors`'s `CLI_EXIT_CODE` table: `0`
90
+ success, `2` invalid argument (bad/unknown flag, failed validation), `4`
91
+ unknown command, etc. Result is printed as JSON to stdout; errors as JSON to
92
+ stderr.
93
+ - Honors the same `ADHD_BACKLOG_SCOPE`/`ADHD_ENV_SCOPE` scope env vars as the
94
+ library API (see Scope below) — there is no separate CLI-only config.
95
+ - `runBacklogCli(argv?, opts?)` is also exported for in-process programmatic
96
+ use (e.g. a test harness), symmetric with `startBacklogServer`.
61
97
 
62
98
  ## Scope
63
99
 
package/dist/cli.d.ts ADDED
@@ -0,0 +1,82 @@
1
+ import { Operation } from '@adhd/apigen-core-client';
2
+ import { Scope } from '@adhd/environment-base-spec';
3
+
4
+ /**
5
+ * Derives the internal command-path PREFIX every `client.ts` operation
6
+ * shares in `@adhd/apigen-plugin-cli-output`'s command table
7
+ * (`buildCommandTable()`: `cliPath = project(op).cli.path`, and
8
+ * `project()`'s `cli.path = [namespace, ...path].map(toKebab)` —
9
+ * `@adhd/apigen-engine-naming`'s `naming.ts`).
10
+ *
11
+ * NOT simply `['backlog']`. `extract()` (`@adhd/apigen-core-client`'s
12
+ * `extract.ts`) unconditionally builds every operation's `path` as
13
+ * `[fileSegment, exportSegment]`, where `fileSegment` is derived from the
14
+ * EXTRACTED SOURCE FILE's own name (`normalizeFileName('client.d.ts')` →
15
+ * `'client-d'` — strips one extension, then folds remaining `.`/`_` to `-`).
16
+ * `server.ts`'s `extractClientOperations()` always points extraction at the
17
+ * built `client.d.ts` (see that file's DEVIATION doc comment), so EVERY
18
+ * `client.ts` export's real `cli.path` is
19
+ * `['backlog', 'client-d', '<kebab-export-name>']` — confirmed empirically
20
+ * (not assumed) by inspecting a real built `pkg`/`operations` pair; see
21
+ * `cli.spec.ts`'s "command-prefix derivation" suite. The HTTP
22
+ * (`apigen-plugin-api-fastify`) and MCP (`apigen-plugin-mcp`) transports
23
+ * both route by bare `fnName` and never consult `project(op)` at all, so
24
+ * this `client-d` segment is INVISIBLE on those two transports — it is
25
+ * cli-output-specific, and would leak into every command a user types
26
+ * (`backlog client-d get-item …`) if this file naively hardcoded a
27
+ * single-segment `'backlog'` prefix instead of deriving the REAL prefix from
28
+ * the live `operations` list.
29
+ *
30
+ * Since every `client.ts` export shares the same namespace + same source
31
+ * file, every operation's `cli.path` differs ONLY in its final (export)
32
+ * segment — so the shared prefix is simply "everything but the last
33
+ * segment" of any one operation's projected `cli.path`. Computed fresh from
34
+ * `operations` on every call (never cached as a literal), so a future change
35
+ * to the extraction source file name, or to `apigen-core-client`'s file-
36
+ * segment derivation, can never silently desync this from the real command
37
+ * table the way a hardcoded constant would.
38
+ */
39
+ export declare function resolveCommandPrefix(operations: readonly Operation[]): string[];
40
+ /**
41
+ * Prepends `prefix` (the real, namespace-qualified command path segments
42
+ * every `client.ts` export shares — see {@link resolveCommandPrefix}) to a
43
+ * user-typed argv, so `backlog get-item --repo … --human-id …` (what a
44
+ * consumer actually types — the bin's own name is never part of `argv`)
45
+ * resolves against the cli-output plugin's command table, which is keyed by
46
+ * the FULL internal path (`['backlog', 'client-d', 'get-item']`).
47
+ *
48
+ * Idempotent / defensive:
49
+ * - Empty argv is returned unchanged — `run()` treats `argv.length === 0`
50
+ * as the usage listing regardless of any prefix.
51
+ * - Argv already starting with the full `prefix` (in order) is returned
52
+ * unchanged — never double-prefixed.
53
+ * - A leading flag (`--help`, `-h`, or any other top-level `-`-prefixed
54
+ * token) is returned unchanged — `run()` special-cases `--help`/`-h`
55
+ * BEFORE ever consulting the command table
56
+ * (`if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h')`),
57
+ * so prefixing here would shadow that check and break `backlog --help`.
58
+ */
59
+ export declare function prefixCommand(userArgv: readonly string[], prefix: readonly string[]): string[];
60
+ export interface RunBacklogCliOpts {
61
+ scope?: Scope;
62
+ /** Test-only override — see `buildBacklogEnv`'s `BuildBacklogEnvOptions`. */
63
+ adhdRoot?: string;
64
+ cwd?: string;
65
+ signal?: AbortSignal;
66
+ }
67
+ /**
68
+ * Opens (or reuses) the backlog store + env, then dispatches EXACTLY ONE CLI
69
+ * command live through `@adhd/apigen-plugin-cli-output`'s `run()` — no code
70
+ * generation, no bespoke argument parsing. Mirrors `startBacklogServer`'s
71
+ * env→store→ctx→`buildBacklogApigenPackage` setup precisely; the only
72
+ * divergence is transport-specific: `cliPlugin.run()` is one-shot (it
73
+ * resolves after dispatching a single command rather than listening), so
74
+ * there is no `Promise.all` of long-lived transports to await here.
75
+ *
76
+ * @param argv Command + flags, WITHOUT the `backlog` bin name (e.g.
77
+ * `['get-item', '--repo', 'org/repo', '--human-id', 'BUG-1']`). Defaults
78
+ * to `process.argv.slice(2)` — the real CLI invocation's own argv — when
79
+ * omitted, matching `cliPlugin.run()`'s own `resolveArgv()` fallback
80
+ * convention.
81
+ */
82
+ export declare function runBacklogCli(argv?: string[], opts?: RunBacklogCliOpts): Promise<void>;
@@ -1,12 +1,24 @@
1
1
  import { GraphBacklogStore } from './store/graph-backlog-store.js';
2
2
  import { BacklogConfig } from './env.js';
3
- import { ArchiveOpts, ArchiveResult, AuditTrailResult, BacklogFilter, BacklogItem, BacklogStats, BacklogStatus, ClaimOpts, ClaimResult, Citation, CreateItemInput, CreateItemResult, DependencyGraph, ImportMarkdownInput, ImportResult, Priority, ReleaseResult, StatsScope, TopoOrderResult, TransitionOpts, UpdateItemInput } from './model.js';
3
+ import { ArchiveOpts, ArchiveResult, AuditTrailResult, BacklogFilter, BacklogItem, BacklogStats, BacklogStatus, ClaimOpts, ClaimResult, Citation, CreateItemInput, CreateItemResult, DependencyGraph, ImportMarkdownInput, ImportResult, MigrationPhase, MigrationStatusResult, Priority, ReleaseResult, SetMigrationPhaseResult, StatsScope, TopoOrderResult, TransitionOpts, UpdateItemInput } from './model.js';
4
4
  import { Environment } from '@adhd/environment';
5
5
 
6
6
  /** The one type apigen special-cases via the `ctx-name-only` invariant. */
7
7
  export interface BacklogCtx {
8
8
  store: GraphBacklogStore;
9
9
  env: Environment<BacklogConfig>;
10
+ /**
11
+ * Test-isolation escape hatch ONLY — mirrors `BuildBacklogEnvOptions.adhdRoot`
12
+ * (the same value passed to `buildBacklogEnv({ adhdRoot })` when constructing
13
+ * `env`). NEVER set this in production code (`server.ts`/`cli.ts` never do).
14
+ * `setMigrationPhase` threads it through to `writeMigrationPhase` so a
15
+ * temp-rooted test `ctx` can never write to the real machine-global
16
+ * `~/.adhd` — omitting this on a real ctx write is exactly the bug
17
+ * `migration-admin.spec.ts`'s negative control caught (a test run wrote
18
+ * `phase-4` to the real `~/.adhd/backlog/production/config.yaml` before
19
+ * this field existed; reverted, see CHANGELOG).
20
+ */
21
+ adhdRoot?: string;
10
22
  }
11
23
  /**
12
24
  * Dedupe-scans (FTS + symbol/path/errorText metadata match) before writing.
@@ -70,3 +82,22 @@ export declare function renderToMarkdown(ctx: BacklogCtx, filter?: BacklogFilter
70
82
  export declare function exportJson(ctx: BacklogCtx, filter?: BacklogFilter): Promise<BacklogItem[]>;
71
83
  /** Bi-temporal history + supersession chain. */
72
84
  export declare function auditTrail(ctx: BacklogCtx, repo: string, humanId: string): Promise<AuditTrailResult>;
85
+ /**
86
+ * MIGRATION.md §4.4 — a QUERIED signal, never hardcoded prose: reports the
87
+ * live `migration.phase` config value (`env.ts`, env-overridable via
88
+ * `ADHD_BACKLOG_MIGRATION_PHASE`) plus a human-readable meaning, so an agent
89
+ * (or the `backlog-usage` skill) always asks the tool which of BACKLOG.md or
90
+ * the tool is authoritative right now, instead of trusting a stale doc
91
+ * sentence. NOT yet per-repo-keyed (MIGRATION.md §9 open decision 6) — one
92
+ * global value for the whole machine.
93
+ */
94
+ export declare function migrationStatus(ctx: BacklogCtx): Promise<MigrationStatusResult>;
95
+ /**
96
+ * MIGRATION.md §4.4's "admin CLI call" half: writes `migration.phase`
97
+ * THROUGH to the GLOBAL layer's `config.yaml` (`migration-admin.ts`) so the
98
+ * new value is a durable, cross-process, cross-repo signal — not merely an
99
+ * env var scoped to whoever's shell happened to export it. Whoever executes
100
+ * a phase's Definition of Done calls this exactly once, after verifying the
101
+ * DoD, never speculatively.
102
+ */
103
+ export declare function setMigrationPhase(ctx: BacklogCtx, phase: MigrationPhase): Promise<SetMigrationPhaseResult>;
@@ -4,10 +4,14 @@ import { Environment } from '@adhd/environment';
4
4
  export interface BacklogConfig {
5
5
  readonly db: {
6
6
  readonly path: string | undefined;
7
+ readonly busyTimeoutMs: number;
7
8
  };
8
9
  readonly logging: {
9
10
  readonly level: string;
10
11
  };
12
+ readonly migration: {
13
+ readonly phase: string;
14
+ };
11
15
  }
12
16
  export declare const backlogEnvironmentSpec: EnvironmentSpec<BacklogConfig>;
13
17
  /**
@@ -0,0 +1,17 @@
1
+ export { addCitation, addDependency, appendNote, archiveResolved, assignItem, attachToPlan, auditTrail, blockers, claimItem, createItem, dependencyGraph, exportJson, getItem, importFromMarkdown, linkRelated, listItems, mergeItems, migrationStatus, readyItems, releaseClaim, removeDependency, renderToMarkdown, renewClaim, resolveItem, setMigrationPhase, setPriority, softDeleteItem, spotlight, splitItem, staleClaims, startWork, stats, supersedeItem, topoOrder, transitionStatus, updateItem, } from './client.js';
2
+ export type { BacklogCtx } from './client.js';
3
+ export { startBacklogServer, buildBacklogApigenPackage } from './server.js';
4
+ export type { StartOpts } from './server.js';
5
+ export { runBacklogCli, resolveCommandPrefix, prefixCommand } from './cli.js';
6
+ export type { RunBacklogCliOpts } from './cli.js';
7
+ export { installSkill, runInstallSkillCommand } from './install-skill.js';
8
+ export type { InstallSkillResult, SkillHost, SkillScope } from './install-skill.js';
9
+ export { runServeCommand } from './serve.js';
10
+ export type { RunServeCommandOpts } from './serve.js';
11
+ export { buildBacklogEnv, resolveBacklogScope, suggestClaimantIdentity, backlogEnvironmentSpec } from './env.js';
12
+ export type { BacklogConfig, BuildBacklogEnvOptions } from './env.js';
13
+ export { openGraphBacklogStore, closeGraphBacklogStore } from './store/graph-backlog-store.js';
14
+ export type { GraphBacklogStore } from './store/graph-backlog-store.js';
15
+ export { buildChangelogSection, classifyStatus, detectPriority, detectStatus, normalizeLegacyStatus, parseBacklogMarkdown, parseBacklogMarkdownWithDiagnostics, renderItemsToMarkdown, toImportItems, } from './markdown.js';
16
+ export type { ParsedImportItem, ParsedMarkdownItem, ParseWithDiagnosticsResult } from './markdown.js';
17
+ export * from './model.js';