halfcycle 0.4.13 → 0.4.15

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.
Files changed (79) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/bin/bin.bundle.mjs +6308 -588
  3. package/bin/pre-tool-use-filter.sh +134 -6
  4. package/commands/agent-teams-orchestration.md +1 -1
  5. package/commands/consistency-check.md +1 -1
  6. package/commands/context-update.md +1 -1
  7. package/commands/halfcycle-design.md +1 -1
  8. package/commands/halfcycle-setup.md +1 -1
  9. package/commands/stack-assembly-worker.md +1 -1
  10. package/commands/task-execution.md +1 -1
  11. package/commands/task-graph.md +1 -1
  12. package/commands/write-spec.md +1 -1
  13. package/dist/bin.d.ts +1 -0
  14. package/dist/bin.d.ts.map +1 -1
  15. package/dist/build-record/pair-io.d.ts +49 -0
  16. package/dist/build-record/pair-io.d.ts.map +1 -0
  17. package/dist/build-record/render-change.d.ts +25 -0
  18. package/dist/build-record/render-change.d.ts.map +1 -0
  19. package/dist/build-record/render-v2.d.ts +10 -5
  20. package/dist/build-record/render-v2.d.ts.map +1 -1
  21. package/dist/build-record/write-change.d.ts +63 -0
  22. package/dist/build-record/write-change.d.ts.map +1 -0
  23. package/dist/build-record/write.d.ts +5 -15
  24. package/dist/build-record/write.d.ts.map +1 -1
  25. package/dist/change.d.ts +136 -0
  26. package/dist/change.d.ts.map +1 -0
  27. package/dist/check-tasks.d.ts +71 -0
  28. package/dist/check-tasks.d.ts.map +1 -0
  29. package/dist/claude-plan.d.ts +133 -0
  30. package/dist/claude-plan.d.ts.map +1 -0
  31. package/dist/cli-contract.d.ts +12 -1
  32. package/dist/cli-contract.d.ts.map +1 -1
  33. package/dist/cli.js +9670 -4933
  34. package/dist/cli.js.map +3 -3
  35. package/dist/close-phase.d.ts +53 -1
  36. package/dist/close-phase.d.ts.map +1 -1
  37. package/dist/doctor.d.ts +34 -0
  38. package/dist/doctor.d.ts.map +1 -0
  39. package/dist/folder-refusals.d.ts +27 -0
  40. package/dist/folder-refusals.d.ts.map +1 -0
  41. package/dist/identity.d.ts +31 -1
  42. package/dist/identity.d.ts.map +1 -1
  43. package/dist/index.js +2832 -1324
  44. package/dist/index.js.map +3 -3
  45. package/dist/install-manifest.d.ts +11 -1
  46. package/dist/install-manifest.d.ts.map +1 -1
  47. package/dist/install-plan.d.ts +112 -0
  48. package/dist/install-plan.d.ts.map +1 -0
  49. package/dist/install.d.ts +593 -2
  50. package/dist/install.d.ts.map +1 -1
  51. package/dist/merge-settings.d.ts +21 -2
  52. package/dist/merge-settings.d.ts.map +1 -1
  53. package/dist/open-phase.d.ts +1 -1
  54. package/dist/open-phase.d.ts.map +1 -1
  55. package/dist/pace.d.ts +138 -0
  56. package/dist/pace.d.ts.map +1 -0
  57. package/dist/phase-work.d.ts +37 -0
  58. package/dist/phase-work.d.ts.map +1 -0
  59. package/dist/plan.d.ts +20 -4
  60. package/dist/plan.d.ts.map +1 -1
  61. package/dist/pre-create-checks.d.ts +28 -0
  62. package/dist/pre-create-checks.d.ts.map +1 -1
  63. package/dist/preview.d.ts +40 -0
  64. package/dist/preview.d.ts.map +1 -0
  65. package/dist/prove.d.ts +77 -0
  66. package/dist/prove.d.ts.map +1 -0
  67. package/dist/restore.d.ts +58 -0
  68. package/dist/restore.d.ts.map +1 -0
  69. package/dist/review.d.ts +19 -1
  70. package/dist/review.d.ts.map +1 -1
  71. package/dist/scan.d.ts +11 -0
  72. package/dist/scan.d.ts.map +1 -1
  73. package/dist/setup/discovery.d.ts.map +1 -1
  74. package/dist/setup/rows.d.ts +10 -6
  75. package/dist/setup/rows.d.ts.map +1 -1
  76. package/dist/system-report.d.ts +1 -1
  77. package/dist/system-report.d.ts.map +1 -1
  78. package/dist/uninstall.d.ts.map +1 -1
  79. package/package.json +2 -2
@@ -0,0 +1,136 @@
1
+ /**
2
+ * `npx halfcycle@latest change` — sorting a change, moving it up, and ending a small
3
+ * change (Safe, lean, fast · E3, feature `three-paths` AC2–AC4, AC6's writer, AC8's
4
+ * missing route; `mini-phase` *The CLI*).
5
+ *
6
+ * THREE FORMS, required flags declared once in `cli-contract.ts` (`missingRequirements`
7
+ * enforces them, and the remedy-string seam test reads the same table):
8
+ * - `change sort --request "<line>" --touches <path>… [--contract <from>:<to>]…
9
+ * [--stored-data] [--standing-rule] [--new-part]` checks `docs/system.json` exactly as
10
+ * `system` does (`checkAndReportDescription`, the one path), reads HEAD as the start
11
+ * commit (a project with no commit cannot sort), sends the description, then the
12
+ * sort, and prints control's answer: its sentence, the sorting's id, what to say next.
13
+ * The path is never worked out here: control re-runs the one rule (`sortChange`) and
14
+ * records its own answer. The request is checked locally with the contracts' own
15
+ * `checkChangeSortRequest` first, so a request control would refuse costs no request.
16
+ * - `change up <mini|full> --change <id>` moves an unfinished small change up and, the
17
+ * change now being finished, writes its record pair; `--phase <phase>` moves a mini
18
+ * phase up instead. A move down is refused here with the contracts' own sentence,
19
+ * before anything is sent; control refuses it again, as it refuses every move down.
20
+ * - `change done <id>` reads the record FIRST. A record found means the change has
21
+ * ended: the pair is written, the outcome printed, and nothing else happens — no
22
+ * runner is started, no report is sent. Only when the service says the change has
23
+ * not ended does it start the runner's `observe --change <id>`, which reads the
24
+ * basis, counts or finishes by the work standing, and prints one line this module
25
+ * parses with `observeChangeRunResultSchema` (one home, shared with the runner).
26
+ *
27
+ * THE RECORD'S FILENAME COMES FROM THE `<id>` ARGUMENT, checked as a change id here and
28
+ * again by the writer, never from a field of the record (INV-023).
29
+ *
30
+ * A SMALL CHANGE IS NOT A PHASE (INV-024): no line here asks for, mentions or marks an
31
+ * approval. Every sentence about a path is the contracts' `CHANGE_PATH_WORDS` or
32
+ * control's own answer; none is restated here (INV-003). Nothing a step id; the next
33
+ * thing to say is the phrase control's answer carries (INV-016).
34
+ *
35
+ * TOPOLOGY. Every route here takes the project credential alone: no GitHub
36
+ * installation, no open phase, no portal session (INV-022). A service without a route
37
+ * is told apart by `isMissingRoute`, and the CLI says so and exits 1.
38
+ *
39
+ * INV-001: Node builtins, the global `fetch`, `@halfcycle/events` and `@halfcycle/core`
40
+ * only; the runner is spawned, never imported. SHIPS TO CLIENT DISK inside the CLI: no
41
+ * comment sits beside an object member, and every string is a sentence a person reads.
42
+ */
43
+ import { type ChangeContract, type ObserveChangeRunResult, type SmallChangeRecord } from '@halfcycle/events';
44
+ import { type HeadCommitOutcome } from './close-phase.js';
45
+ import type { RepoCredential } from './open-phase.js';
46
+ import { type SystemDeps, type SystemRun } from './system-report.js';
47
+ import { type ChangeRecordPairResult } from './build-record/write-change.js';
48
+ /** The verb's usage, one home: printed by `--help` and by a usage error. */
49
+ export declare const CHANGE_USAGE: string;
50
+ /** What one invocation asks for, once its words have been read. */
51
+ export type ChangeArgs = {
52
+ readonly form: 'sort';
53
+ readonly request: string;
54
+ readonly touches: readonly string[];
55
+ readonly contracts: readonly ChangeContract[];
56
+ readonly storedData: boolean;
57
+ readonly standingRule: boolean;
58
+ readonly newPart: boolean;
59
+ readonly repoRoot?: string;
60
+ } | {
61
+ readonly form: 'up';
62
+ readonly to: 'mini' | 'full';
63
+ readonly target: {
64
+ readonly kind: 'change';
65
+ readonly sortingId: string;
66
+ } | {
67
+ readonly kind: 'phase';
68
+ readonly phase: string;
69
+ };
70
+ readonly repoRoot?: string;
71
+ } | {
72
+ readonly form: 'done';
73
+ readonly sortingId: string;
74
+ readonly repoRoot?: string;
75
+ };
76
+ /** The words read, or the line to print and the code to exit with. Nothing was sent. */
77
+ export type ParsedChange = {
78
+ ok: true;
79
+ args: ChangeArgs;
80
+ } | {
81
+ ok: false;
82
+ line: string;
83
+ exitCode: 1 | 2;
84
+ };
85
+ /**
86
+ * Read `rest` (the words after `change`). The required flags are the contract's
87
+ * (`missingRequirements`), refused first with the contract's own sentence; then each
88
+ * form's own words are read, and anything else is a usage error. Nothing is read from
89
+ * disk and nothing is sent.
90
+ */
91
+ export declare function parseChangeArgs(rest: readonly string[]): ParsedChange;
92
+ /** The pieces the verb reaches outside itself through; replaced in tests. */
93
+ export interface ChangeDeps extends SystemDeps {
94
+ readonly readHead: (repoRoot: string) => HeadCommitOutcome;
95
+ readonly fetch: typeof fetch;
96
+ readonly observeChange: (credential: RepoCredential, repoRoot: string, sortingId: string) => Promise<ObserveChangeRunResult>;
97
+ readonly writePair: (repoRoot: string, sortingId: string, rawRecord: unknown, record: SmallChangeRecord) => ChangeRecordPairResult;
98
+ }
99
+ /**
100
+ * The one line the `observe --change` child printed, read through the shared
101
+ * `observeChangeRunResultSchema`, or `unreachable` when stdout holds no such line.
102
+ */
103
+ export declare function readObserveChangeLine(stdout: string): ObserveChangeRunResult;
104
+ /**
105
+ * End a small change through the runner's `observe --change <id>`, spawned the way the
106
+ * close step spawns the runner's verbs (`runRunnerChild`), with the same credential.
107
+ * The id is the checked argument. Never throws.
108
+ */
109
+ export declare function runObserveChangeChild(binary: string | Error, credential: RepoCredential, repoRoot: string, sortingId: string): Promise<ObserveChangeRunResult>;
110
+ /** The line naming what to say next: the phrase the service's answer carries. */
111
+ export declare function nextSayLine(say: string): string;
112
+ /** The command that ends a small change, or writes its record again: the one remedy. */
113
+ export declare function changeDoneCommand(sortingId: string): string;
114
+ /** What a finished change's record says about how it ended, in the contracts' words. */
115
+ export declare function recordOutcomeLines(record: SmallChangeRecord): string;
116
+ /**
117
+ * `change sort`. The local check runs with the description that just passed and the
118
+ * HEAD just read; the description version is not known until the service answers, so
119
+ * the local check is given the lowest version there is, which no rule reads beyond its
120
+ * shape. The request that leaves carries the version the service gave.
121
+ */
122
+ export declare function runChangeSort(repoRoot: string, args: Extract<ChangeArgs, {
123
+ form: 'sort';
124
+ }>, deps: ChangeDeps): Promise<SystemRun>;
125
+ /** `change up`: a small change by its id, or a mini phase by its name. */
126
+ export declare function runChangeUp(repoRoot: string, args: Extract<ChangeArgs, {
127
+ form: 'up';
128
+ }>, deps: ChangeDeps): Promise<SystemRun>;
129
+ /**
130
+ * `change done <id>`. The record is read first; the runner is started only when the
131
+ * service says the change has not ended (three-paths AC4).
132
+ */
133
+ export declare function runChangeDone(repoRoot: string, sortingId: string, deps: ChangeDeps): Promise<SystemRun>;
134
+ /** The whole verb, once its words are read: the form's run. */
135
+ export declare function runChange(repoRoot: string, args: ChangeArgs, deps: ChangeDeps): Promise<SystemRun>;
136
+ //# sourceMappingURL=change.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change.d.ts","sourceRoot":"","sources":["../src/change.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * `npx halfcycle@latest check-tasks <phase> [--with-task-list] [--repo <root>]`
3
+ * (`collision-free-parallel-work` AC3; `checks-as-work-lands` AC3, AC6).
4
+ *
5
+ * OFFLINE, ALWAYS. This verb reads at most two files on the person's own machine —
6
+ * `docs/build-records/task-plan.json` and, with `--with-task-list`,
7
+ * `docs/build-records/build-tasks.json` — and nothing else. It opens no credential
8
+ * file, makes no network call, and needs no sign-in. Everything it prints comes from
9
+ * `checkTaskPlan` (`@halfcycle/core`), which is pure: this module's whole job is
10
+ * reading the two files, handing them to that function, and printing what it
11
+ * returns.
12
+ *
13
+ * ONE HOME FOR THE PLAN'S SHAPE AND ITS RULES (INV-003): `taskPlanSchema`,
14
+ * `taskListFileSchema`, `checkTaskPlan` and every line it prints live in
15
+ * `@halfcycle/core`'s `task-plan.ts`. This file restates none of them — it only
16
+ * turns a missing or unparsable file into the one kind of answer this verb gives for
17
+ * that (exit 2, naming the file), and turns the function's lines into the exit code
18
+ * the spec pins (0 clean, 1 any refusal).
19
+ *
20
+ * THE TASK LIST IS READ ONLY WHEN ASKED. Without `--with-task-list` this verb never
21
+ * opens `build-tasks.json`, so a stale or disagreeing list on disk from an earlier
22
+ * phase changes nothing about a planning run — the one case
23
+ * `collision-free-parallel-work`'s *Decisions taken* exists to prevent.
24
+ *
25
+ * A MISSING TASK LIST IS NOT AN ERROR. Only the plan file is required input; a task
26
+ * list that is missing, names another phase, or carries no phase at all (the shape
27
+ * written before this release) reads as `checkTaskPlan`'s note N1 and exits 0 on an
28
+ * otherwise clean plan. A plan file in the same state is always a hard failure (exit
29
+ * 2), because the plan is this verb's one required input.
30
+ *
31
+ * SHIPS TO CLIENT DISK inside the CLI (INV-001: Node builtins, `@halfcycle/core`
32
+ * only — no network, so no `@halfcycle/events` and no `fetch`). Every string here is
33
+ * a sentence a person reads in their own terminal, so none names an internal
34
+ * register, a route, or this project's own tooling; no comment sits beside an
35
+ * object member.
36
+ */
37
+ /** The usage line, printed for no phase, an extra argument or an unknown flag. */
38
+ export declare const CHECK_TASKS_USAGE = "npx halfcycle@latest check-tasks <phase> [--with-task-list] [--repo <root>]";
39
+ /**
40
+ * What the arguments after `check-tasks` came to. Exactly one positional (the
41
+ * phase), at most one `--with-task-list` and at most one `--repo <root>`; anything
42
+ * else, no phase included, is usage.
43
+ */
44
+ export type CheckTasksArgs = {
45
+ ok: true;
46
+ phase: string;
47
+ withTaskList: boolean;
48
+ repoRoot: string | undefined;
49
+ } | {
50
+ ok: false;
51
+ };
52
+ export declare function parseCheckTasksArgs(argv: readonly string[]): CheckTasksArgs;
53
+ /** What a run of the verb came to. */
54
+ export interface CheckTasksRun {
55
+ readonly stdout: string;
56
+ readonly stderr: string;
57
+ readonly exitCode: number;
58
+ }
59
+ /**
60
+ * The whole verb. Reads `docs/build-records/task-plan.json` under `repoRoot`, and,
61
+ * with `withTaskList`, `docs/build-records/build-tasks.json`; hands both to
62
+ * `checkTaskPlan` and prints its lines, one per line, in the order it returns them,
63
+ * or `checkTaskPlan`'s own clear line when there is nothing to report. Never throws.
64
+ *
65
+ * Exit 0 when nothing refuses, 1 when anything does, 2 when the plan file is
66
+ * missing or either file cannot be read or parsed as JSON or does not match the
67
+ * shape this tool reads (naming which file, and where). A missing task list is not
68
+ * an error (see the module header) and never changes the exit code on its own.
69
+ */
70
+ export declare function runCheckTasks(repoRoot: string, phase: string, withTaskList: boolean): CheckTasksRun;
71
+ //# sourceMappingURL=check-tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-tasks.d.ts","sourceRoot":"","sources":["../src/check-tasks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAgBH,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,gFAAgF,CAAC;AAE/G;;;;GAIG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAChF;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC;AAElB,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,CAuB3E;AA2CD,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,aAAa,CA4BnG"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * SETUP ASKS THE CLAUDE PLAN ONCE (`builds-paced-to-plan` AC2, setup half).
3
+ *
4
+ * `bin.ts`'s setup arm calls `setupClaudePlan` after the project is created or found.
5
+ * In order:
6
+ *
7
+ * 1. NOBODY IS ASKED, AND NOTHING IS SENT, unless this account owns the project
8
+ * and a person is there (`isInteractiveRun`: a terminal on standard input and no
9
+ * `CI`). That one gate covers a script, CI, an agent running `npx halfcycle` from
10
+ * its own shell (no terminal on standard input) and a guest. A remembered answer
11
+ * is not sent either: the spec's "a setup with no person there sends nothing".
12
+ * 2. A COMPUTER THAT WAS TOLD BEFORE is not asked again: the remembered plan is
13
+ * sent, and, once control has taken it, the remembered line says so. THIS STEP
14
+ * IS NOT GATED ON `--yes` (below) — a bounded network call with a timeout cannot
15
+ * wait forever on anybody, so there is nothing for `--yes` to protect against
16
+ * here, and a `--yes` run genuinely at a real terminal still wants its
17
+ * already-known plan kept in sync silently.
18
+ * 3. OTHERWISE THE QUESTION IS ASKED (`askLine`) — UNLESS `--yes` WAS GIVEN, in
19
+ * which case this step is skipped the same way "no person there" is (W-09 O-W9:
20
+ * a console can be attached with nobody at it — a Windows run started with no
21
+ * interactive session still measured a TTY — so `--yes` is read here the same
22
+ * way `confirmActingIdentity` already reads it, before the TTY is trusted, as
23
+ * the stronger, explicit signal that nobody is going to answer). Otherwise: the
24
+ * answer is remembered on this computer and sent. An answer that names no plan
25
+ * is asked again, up to `PLAN_QUESTION_TRIES` times in all; after that nothing is
26
+ * remembered or sent, and the plan stays unknown until the owner sets it in the
27
+ * console.
28
+ *
29
+ * ONE HOME FOR EVERY WORD AND SHAPE, AND IT IS NOT HERE. The question, the answer's
30
+ * reading, the remembered line, the seven plans and the request body are
31
+ * `@halfcycle/events`' `pacing.ts`; the remembered file's shape IS the request body
32
+ * (`claudePlanRequestSchema`), so the file and the wire cannot drift apart. This
33
+ * module holds only the order above and the file and network I/O.
34
+ *
35
+ * THE CREDENTIAL IS THE MACHINE'S ACCOUNT CREDENTIAL, read the way the create route's
36
+ * is (`HALFCYCLE_TOKEN` in the environment first, else this machine's saved sign-in),
37
+ * and never a browser sign-in: the project is already set up, and a sign-in for a
38
+ * question about pacing would be out of all proportion. The engagement credential is
39
+ * never sent; control refuses it on this route. With no account credential the answer
40
+ * is still remembered, so the next setup sends it.
41
+ *
42
+ * BEST EFFORT, NEVER A FAILURE. The install has already succeeded when this runs. A
43
+ * network error, a timeout, a refusal (control not yet carrying the route, or a
44
+ * project this account does not own after all) or a file that cannot be written is
45
+ * silent: the remembered answer is re-sent by the next setup, and the owner can set
46
+ * the plan in the console. Nothing here throws.
47
+ *
48
+ * A REMEMBERED ANSWER IS RE-SENT ON EVERY LATER SETUP, as the spec says, so a plan the
49
+ * owner changed in the console is set back by their next `npx halfcycle` on this
50
+ * computer. That is the spec's rule, written down here so it is not mistaken for a
51
+ * defect of this module.
52
+ *
53
+ * INV-001: Node builtins, `@halfcycle/core`, `@halfcycle/events` and this package's
54
+ * own modules. Nothing about usage crosses (ADR-015): only the plan's id.
55
+ */
56
+ import { type ClaudePlanId } from '@halfcycle/events';
57
+ /** The remembered answer's file name, under `~/.halfcycle/`. Machine-level, never in a project (INV-016). */
58
+ export declare const CLAUDE_PLAN_FILENAME = "claude-plan.json";
59
+ /** How many times the question is put before an answer that names no plan is given up on. */
60
+ export declare const PLAN_QUESTION_TRIES = 3;
61
+ /** `~/.halfcycle/claude-plan.json`. */
62
+ export declare function claudePlanPath(home?: string): string;
63
+ /**
64
+ * The plan this computer was told before, or `undefined` when it was never told or
65
+ * the file does not read as one: a file that does not parse is asked about again and
66
+ * overwritten, never an error.
67
+ */
68
+ export declare function readRememberedClaudePlan(home?: string): ClaudePlanId | undefined;
69
+ /**
70
+ * Remember the plan on this computer, owner-only, the account store's posture
71
+ * (`account-credential.ts`). Returns false when it could not be written.
72
+ */
73
+ export declare function rememberClaudePlan(plan: ClaudePlanId, home?: string): boolean;
74
+ /**
75
+ * The owner's settings page, under the project's console address, or `undefined` when
76
+ * this run has no console address (an older control, or none configured). No address
77
+ * is guessed: `bin.ts` passes the same address it prints as the project's console.
78
+ */
79
+ export declare function settingsPageUrl(consoleUrl: string | undefined): string | undefined;
80
+ /**
81
+ * Send the plan to `PUT /engagements/:engagementId/claude-plan` with the account
82
+ * credential. True only when control took it (a 2xx). Never throws.
83
+ */
84
+ export declare function sendClaudePlan(serviceUrl: string, engagementId: string, credential: string, plan: ClaudePlanId, fetchImpl?: typeof fetch): Promise<boolean>;
85
+ /** What `setupClaudePlan` did, for the caller's tests; `bin.ts` reads none of it. */
86
+ export type ClaudePlanSetupOutcome = {
87
+ readonly kind: 'not-owner';
88
+ } | {
89
+ readonly kind: 'no-person';
90
+ } | {
91
+ readonly kind: 'no-answer';
92
+ } | {
93
+ readonly kind: 'failed';
94
+ } | {
95
+ readonly kind: 'remembered';
96
+ readonly plan: ClaudePlanId;
97
+ readonly sent: boolean;
98
+ } | {
99
+ readonly kind: 'answered';
100
+ readonly plan: ClaudePlanId;
101
+ readonly sent: boolean;
102
+ };
103
+ export interface ClaudePlanSetupInput {
104
+ readonly serviceUrl: string;
105
+ readonly engagementId: string;
106
+ /** True when this run's account owns the project; false for a guest, or when ownership is not known. */
107
+ readonly ownsProject: boolean;
108
+ /** The project's console address this run prints, if any; the settings page is under it. */
109
+ readonly consoleUrl: string | undefined;
110
+ }
111
+ export interface ClaudePlanSetupDeps {
112
+ readonly interactive: () => boolean;
113
+ readonly ask: (question: string) => Promise<string>;
114
+ readonly write: (text: string) => void;
115
+ /**
116
+ * `--yes` on the command line: never ask the question, the same as `interactive()`
117
+ * false for THAT ONE STEP (W-09 O-W9 — a measured TTY is not proof somebody is there
118
+ * to answer it). Does NOT also suppress resending an already-remembered plan — that
119
+ * step is a bounded network call, never a wait on a human, so `--yes` has nothing to
120
+ * protect there and a real terminal that happens to pass `--yes` still wants its
121
+ * known plan kept in sync.
122
+ */
123
+ readonly assumeYes?: boolean;
124
+ readonly env?: NodeJS.ProcessEnv;
125
+ readonly home?: string;
126
+ readonly fetchImpl?: typeof fetch;
127
+ }
128
+ /**
129
+ * The setup arm's one call: ask the plan once, remember it, send it (module
130
+ * docblock). Never throws; the outcome is for tests.
131
+ */
132
+ export declare function setupClaudePlan(input: ClaudePlanSetupInput, deps: ClaudePlanSetupDeps): Promise<ClaudePlanSetupOutcome>;
133
+ //# sourceMappingURL=claude-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-plan.d.ts","sourceRoot":"","sources":["../src/claude-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAKH,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAG3B,6GAA6G;AAC7G,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AAEvD,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAQrC,uCAAuC;AACvC,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAOhF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAU7E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGlF;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,YAAY,EAClB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED,qFAAqF;AACrF,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACpF;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEvF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,wGAAwG;IACxG,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,4FAA4F;IAC5F,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACnC;AASD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,sBAAsB,CAAC,CAqCjC"}
@@ -62,7 +62,7 @@
62
62
  * home is the failure mode it exists to prevent.
63
63
  */
64
64
  /** The verbs the CLI dispatches. Anything else after `halfcycle ` is unknown. */
65
- export declare const CLI_VERBS: readonly ["install", "check-drift", "build-record", "open-phase", "close-phase", "system", "draw", "plan", "review", "uninstall"];
65
+ export declare const CLI_VERBS: readonly ["install", "check-drift", "build-record", "open-phase", "close-phase", "system", "draw", "plan", "review", "check-tasks", "uninstall", "change", "pace", "prove", "preview", "doctor", "restore"];
66
66
  export type CliVerb = (typeof CLI_VERBS)[number];
67
67
  /** A flag every invocation of the verb must carry. */
68
68
  export interface RequiredFlag {
@@ -85,10 +85,21 @@ export interface ConditionalFlag {
85
85
  readonly takesValue: boolean;
86
86
  readonly missingMessage: string;
87
87
  }
88
+ /**
89
+ * One form of a verb that has several, chosen by the first word after the verb
90
+ * (`change sort`, `change up`, `change done`). Each form declares its own required
91
+ * flags; the verb's own lists stay empty.
92
+ */
93
+ export interface FormContract {
94
+ readonly form: string;
95
+ readonly required: readonly RequiredFlag[];
96
+ readonly conditional: readonly ConditionalFlag[];
97
+ }
88
98
  export interface VerbContract {
89
99
  readonly verb: CliVerb;
90
100
  readonly required: readonly RequiredFlag[];
91
101
  readonly conditional: readonly ConditionalFlag[];
102
+ readonly forms?: readonly FormContract[];
92
103
  }
93
104
  /** The contract for a verb, or `undefined` when the CLI has no such verb. */
94
105
  export declare function contractFor(verb: string): VerbContract | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"cli-contract.d.ts","sourceRoot":"","sources":["../src/cli-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAIH,iFAAiF;AACjF,eAAO,MAAM,SAAS,mIAAoI,CAAC;AAE3J,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;CAClD;AAiFD,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAElE;AAED,iDAAiD;AACjD,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAmBD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAAE,CAyBxF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMvE;AASD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;CAErB,CAAC;AAyBX;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAa1F"}
1
+ {"version":3,"file":"cli-contract.d.ts","sourceRoot":"","sources":["../src/cli-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAIH,iFAAiF;AACjF,eAAO,MAAM,SAAS,6MAA8M,CAAC;AAErO,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;CAC1C;AAwID,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAElE;AAED,iDAAiD;AACjD,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAmBD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAAE,CAyBxF;AAuBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMvE;AASD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;CAErB,CAAC;AA0BX;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAa1F"}