openplanr 1.13.3 → 1.14.1

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 (151) hide show
  1. package/README.md +46 -4
  2. package/dist/cli/commands/operate.d.ts +3 -0
  3. package/dist/cli/commands/operate.d.ts.map +1 -0
  4. package/dist/cli/commands/operate.js +568 -0
  5. package/dist/cli/commands/operate.js.map +1 -0
  6. package/dist/cli/index.js +42 -2
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/services/ai-service.d.ts +9 -2
  9. package/dist/services/ai-service.d.ts.map +1 -1
  10. package/dist/services/ai-service.js +14 -6
  11. package/dist/services/ai-service.js.map +1 -1
  12. package/dist/services/operate/advisors.d.ts +219 -0
  13. package/dist/services/operate/advisors.d.ts.map +1 -0
  14. package/dist/services/operate/advisors.js +745 -0
  15. package/dist/services/operate/advisors.js.map +1 -0
  16. package/dist/services/operate/artifact-route-generation.d.ts +111 -0
  17. package/dist/services/operate/artifact-route-generation.d.ts.map +1 -0
  18. package/dist/services/operate/artifact-route-generation.js +459 -0
  19. package/dist/services/operate/artifact-route-generation.js.map +1 -0
  20. package/dist/services/operate/artifacts.d.ts +26 -0
  21. package/dist/services/operate/artifacts.d.ts.map +1 -0
  22. package/dist/services/operate/artifacts.js +92 -0
  23. package/dist/services/operate/artifacts.js.map +1 -0
  24. package/dist/services/operate/canonical.d.ts +18 -0
  25. package/dist/services/operate/canonical.d.ts.map +1 -0
  26. package/dist/services/operate/canonical.js +157 -0
  27. package/dist/services/operate/canonical.js.map +1 -0
  28. package/dist/services/operate/config.d.ts +56 -0
  29. package/dist/services/operate/config.d.ts.map +1 -0
  30. package/dist/services/operate/config.js +644 -0
  31. package/dist/services/operate/config.js.map +1 -0
  32. package/dist/services/operate/consolidation.d.ts +18 -0
  33. package/dist/services/operate/consolidation.d.ts.map +1 -0
  34. package/dist/services/operate/consolidation.js +539 -0
  35. package/dist/services/operate/consolidation.js.map +1 -0
  36. package/dist/services/operate/doctor.d.ts +12 -0
  37. package/dist/services/operate/doctor.d.ts.map +1 -0
  38. package/dist/services/operate/doctor.js +307 -0
  39. package/dist/services/operate/doctor.js.map +1 -0
  40. package/dist/services/operate/engine.d.ts +53 -0
  41. package/dist/services/operate/engine.d.ts.map +1 -0
  42. package/dist/services/operate/engine.js +1097 -0
  43. package/dist/services/operate/engine.js.map +1 -0
  44. package/dist/services/operate/event-store.d.ts +57 -0
  45. package/dist/services/operate/event-store.d.ts.map +1 -0
  46. package/dist/services/operate/event-store.js +232 -0
  47. package/dist/services/operate/event-store.js.map +1 -0
  48. package/dist/services/operate/evidence-cache.d.ts +17 -0
  49. package/dist/services/operate/evidence-cache.d.ts.map +1 -0
  50. package/dist/services/operate/evidence-cache.js +96 -0
  51. package/dist/services/operate/evidence-cache.js.map +1 -0
  52. package/dist/services/operate/evidence-import.d.ts +40 -0
  53. package/dist/services/operate/evidence-import.d.ts.map +1 -0
  54. package/dist/services/operate/evidence-import.js +340 -0
  55. package/dist/services/operate/evidence-import.js.map +1 -0
  56. package/dist/services/operate/evidence-readiness.d.ts +8 -0
  57. package/dist/services/operate/evidence-readiness.d.ts.map +1 -0
  58. package/dist/services/operate/evidence-readiness.js +78 -0
  59. package/dist/services/operate/evidence-readiness.js.map +1 -0
  60. package/dist/services/operate/evidence.d.ts +71 -0
  61. package/dist/services/operate/evidence.d.ts.map +1 -0
  62. package/dist/services/operate/evidence.js +1022 -0
  63. package/dist/services/operate/evidence.js.map +1 -0
  64. package/dist/services/operate/ids.d.ts +7 -0
  65. package/dist/services/operate/ids.d.ts.map +1 -0
  66. package/dist/services/operate/ids.js +23 -0
  67. package/dist/services/operate/ids.js.map +1 -0
  68. package/dist/services/operate/index.d.ts +14 -0
  69. package/dist/services/operate/index.d.ts.map +1 -0
  70. package/dist/services/operate/index.js +881 -0
  71. package/dist/services/operate/index.js.map +1 -0
  72. package/dist/services/operate/journal.d.ts +34 -0
  73. package/dist/services/operate/journal.d.ts.map +1 -0
  74. package/dist/services/operate/journal.js +229 -0
  75. package/dist/services/operate/journal.js.map +1 -0
  76. package/dist/services/operate/legacy-import-service.d.ts +58 -0
  77. package/dist/services/operate/legacy-import-service.d.ts.map +1 -0
  78. package/dist/services/operate/legacy-import-service.js +922 -0
  79. package/dist/services/operate/legacy-import-service.js.map +1 -0
  80. package/dist/services/operate/lifecycle.d.ts +88 -0
  81. package/dist/services/operate/lifecycle.d.ts.map +1 -0
  82. package/dist/services/operate/lifecycle.js +556 -0
  83. package/dist/services/operate/lifecycle.js.map +1 -0
  84. package/dist/services/operate/lock-service.d.ts +37 -0
  85. package/dist/services/operate/lock-service.d.ts.map +1 -0
  86. package/dist/services/operate/lock-service.js +215 -0
  87. package/dist/services/operate/lock-service.js.map +1 -0
  88. package/dist/services/operate/maintenance.d.ts +38 -0
  89. package/dist/services/operate/maintenance.d.ts.map +1 -0
  90. package/dist/services/operate/maintenance.js +699 -0
  91. package/dist/services/operate/maintenance.js.map +1 -0
  92. package/dist/services/operate/outcomes.d.ts +48 -0
  93. package/dist/services/operate/outcomes.d.ts.map +1 -0
  94. package/dist/services/operate/outcomes.js +312 -0
  95. package/dist/services/operate/outcomes.js.map +1 -0
  96. package/dist/services/operate/pipeline-handoff.d.ts +138 -0
  97. package/dist/services/operate/pipeline-handoff.d.ts.map +1 -0
  98. package/dist/services/operate/pipeline-handoff.js +175 -0
  99. package/dist/services/operate/pipeline-handoff.js.map +1 -0
  100. package/dist/services/operate/projection-persistence.d.ts +55 -0
  101. package/dist/services/operate/projection-persistence.d.ts.map +1 -0
  102. package/dist/services/operate/projection-persistence.js +393 -0
  103. package/dist/services/operate/projection-persistence.js.map +1 -0
  104. package/dist/services/operate/projection.d.ts +4 -0
  105. package/dist/services/operate/projection.d.ts.map +1 -0
  106. package/dist/services/operate/projection.js +128 -0
  107. package/dist/services/operate/projection.js.map +1 -0
  108. package/dist/services/operate/protocol.d.ts +60 -0
  109. package/dist/services/operate/protocol.d.ts.map +1 -0
  110. package/dist/services/operate/protocol.js +62 -0
  111. package/dist/services/operate/protocol.js.map +1 -0
  112. package/dist/services/operate/read-only-providers.d.ts +38 -0
  113. package/dist/services/operate/read-only-providers.d.ts.map +1 -0
  114. package/dist/services/operate/read-only-providers.js +286 -0
  115. package/dist/services/operate/read-only-providers.js.map +1 -0
  116. package/dist/services/operate/redaction.d.ts +47 -0
  117. package/dist/services/operate/redaction.d.ts.map +1 -0
  118. package/dist/services/operate/redaction.js +279 -0
  119. package/dist/services/operate/redaction.js.map +1 -0
  120. package/dist/services/operate/reducer.d.ts +10 -0
  121. package/dist/services/operate/reducer.d.ts.map +1 -0
  122. package/dist/services/operate/reducer.js +11 -0
  123. package/dist/services/operate/reducer.js.map +1 -0
  124. package/dist/services/operate/routes.d.ts +49 -0
  125. package/dist/services/operate/routes.d.ts.map +1 -0
  126. package/dist/services/operate/routes.js +996 -0
  127. package/dist/services/operate/routes.js.map +1 -0
  128. package/dist/services/operate/shipment-observer.d.ts +14 -0
  129. package/dist/services/operate/shipment-observer.d.ts.map +1 -0
  130. package/dist/services/operate/shipment-observer.js +321 -0
  131. package/dist/services/operate/shipment-observer.js.map +1 -0
  132. package/dist/services/operate/stalled-item-service.d.ts +18 -0
  133. package/dist/services/operate/stalled-item-service.d.ts.map +1 -0
  134. package/dist/services/operate/stalled-item-service.js +121 -0
  135. package/dist/services/operate/stalled-item-service.js.map +1 -0
  136. package/dist/services/operate/subprocess-env.d.ts +4 -0
  137. package/dist/services/operate/subprocess-env.d.ts.map +1 -0
  138. package/dist/services/operate/subprocess-env.js +45 -0
  139. package/dist/services/operate/subprocess-env.js.map +1 -0
  140. package/dist/services/operate/types.d.ts +729 -0
  141. package/dist/services/operate/types.d.ts.map +1 -0
  142. package/dist/services/operate/types.js +13 -0
  143. package/dist/services/operate/types.js.map +1 -0
  144. package/dist/services/operate/workspace.d.ts +59 -0
  145. package/dist/services/operate/workspace.d.ts.map +1 -0
  146. package/dist/services/operate/workspace.js +316 -0
  147. package/dist/services/operate/workspace.js.map +1 -0
  148. package/dist/services/runtime-manager-service.d.ts.map +1 -1
  149. package/dist/services/runtime-manager-service.js +71 -2
  150. package/dist/services/runtime-manager-service.js.map +1 -1
  151. package/package.json +10 -4
package/README.md CHANGED
@@ -4,15 +4,17 @@
4
4
 
5
5
  ### Dedicated planning CLI and cross-runtime workflow control plane
6
6
 
7
- **Plan continuously. Route feature delivery anywhere.** Certified first for **Claude Code**, **Cursor**, and **Codex** through Protocol v1.0 artifacts plus v1.1 runtime contracts.
7
+ **Plan continuously. Operate from evidence. Route feature delivery anywhere.**
8
+ Certified first for **Claude Code**, **Cursor**, and **Codex** through Protocol
9
+ v1.0 artifacts plus additive v1.1/v1.2 runtime and operating contracts.
8
10
 
9
11
  [![npm version](https://img.shields.io/npm/v/openplanr.svg?style=flat-square&color=cb3837&logo=npm)](https://www.npmjs.com/package/openplanr)
10
12
  [![node](https://img.shields.io/node/v/openplanr.svg?style=flat-square&color=339933&logo=node.js&logoColor=white)](https://nodejs.org)
11
13
  [![license](https://img.shields.io/npm/l/openplanr.svg?style=flat-square&color=blue)](https://github.com/openplanr/OpenPlanr/blob/main/LICENSE)
12
- [![protocol](https://img.shields.io/badge/protocol-v1.0.0-7c3aed?style=flat-square)](https://github.com/openplanr/planr-pipeline/tree/main/docs/protocol)
14
+ [![protocol](https://img.shields.io/badge/protocol-v1.2.0-7c3aed?style=flat-square)](https://github.com/openplanr/planr-pipeline/tree/main/docs/protocol)
13
15
  [![runtimes](https://img.shields.io/badge/runtimes-Claude%20Code%20%7C%20Cursor%20%7C%20Codex-f97316?style=flat-square)](https://github.com/openplanr/planr-pipeline/blob/main/docs/compatibility-matrix.md)
14
16
 
15
- **[Website](https://openplanr.dev)** · **[Setup guide](docs/CROSS_RUNTIME_SETUP.md)** · **[Artifact review](docs/ARTIFACT_REVIEW.md)** · **[Compatibility matrix](https://github.com/openplanr/planr-pipeline/blob/main/docs/compatibility-matrix.md)** · **[Protocol spec](https://github.com/openplanr/planr-pipeline/tree/main/docs/protocol)** · **[CLI reference](docs/CLI.md)**
17
+ **[Website](https://openplanr.dev)** · **[Setup guide](docs/CROSS_RUNTIME_SETUP.md)** · **[Operating Board](docs/OPERATING_BOARD.md)** · **[Artifact review](docs/ARTIFACT_REVIEW.md)** · **[Compatibility matrix](https://github.com/openplanr/planr-pipeline/blob/main/docs/compatibility-matrix.md)** · **[Protocol spec](https://github.com/openplanr/planr-pipeline/tree/main/docs/protocol)** · **[CLI reference](docs/CLI.md)**
16
18
 
17
19
  </div>
18
20
 
@@ -45,9 +47,12 @@ installations use `--minimal`; the full pipeline is the default.
45
47
  AI coding agents are powerful but lack structured planning context. Without a clear plan, they generate code that drifts from requirements, churn on the same problem across sessions, and can't be audited. OpenPlanr fixes this with four properties:
46
48
 
47
49
  1. **Markdown artifacts in your repo** — plans live next to your code, version-controlled, gittable, gradable. No external SaaS, no DB.
48
- 2. **One contract, every runtime** — Claude Code, Cursor, and Codex consume the same v1.0 artifacts while locks, adapter capabilities, and provenance use additive v1.1 contracts.
50
+ 2. **One contract, every runtime** — Claude Code, Cursor, and Codex consume the same v1.0 planning artifacts while locks, adapter capabilities, and provenance use additive v1.1 contracts and Operating Board uses Protocol v1.2.
49
51
  3. **Three planning postures** — agile, quick task, or spec-driven planning, independent from the pipeline's feature-local PO phase.
50
52
  4. **Safe runtime migration** — setup previews exact changes, preserves hand-written content, records ownership, backs up exact bytes, and supports rollback.
53
+ 5. **Evidence-to-decision operations** — `planr operate` produces cited,
54
+ reviewable DEV, OWNER, and AGENT routes while preserving human authority and
55
+ the PLAN→SHIP gate.
51
56
 
52
57
  ---
53
58
 
@@ -163,10 +168,47 @@ room. Immutable fragments and encrypted short links remain available with
163
168
  `--snapshot`; the service stores ciphertext only.
164
169
  See the [artifact review and privacy guide](docs/ARTIFACT_REVIEW.md).
165
170
 
171
+ ### Run an operating cycle
172
+
173
+ ```bash
174
+ planr operate inspect # no initialization or credentials required
175
+ planr operate demo # deterministic, credential-free, no project writes
176
+ planr operate init
177
+ planr operate run --preview # no writes and no provider/model calls
178
+ planr operate run # provider calls require disclosed consent
179
+ planr operate review
180
+ ```
181
+
182
+ Operating Board governs direction; it never deploys, publishes, spends,
183
+ contacts customers, or invokes SHIP. Missing evidence marks a lens
184
+ `not_evaluated`. Accepting a finding records governance only; the exact route is
185
+ previewed and applied separately. Planning-only installations retain
186
+ `operate --help`, `inspect`, and `demo`; commands that require Protocol v1.2
187
+ return `E_PIPELINE_NOT_INSTALLED` with the full-install recovery command. See the
188
+ [Operating Board guide](docs/OPERATING_BOARD.md).
189
+
166
190
  ---
167
191
 
168
192
  ## Commands
169
193
 
194
+ ### Operating Board
195
+
196
+ | Command | Description |
197
+ |---|---|
198
+ | `planr operate inspect` | Inspect workspace, runtime, evidence, and package readiness without initialization |
199
+ | `planr operate demo` | Produce a real cited brief from sanitized deterministic fixtures |
200
+ | `planr operate init` | Guide charter, workspace, runtime, privacy, and source setup |
201
+ | `planr operate run` | Collect evidence and stop at a reviewable operating cycle |
202
+ | `planr operate review` / `brief` / `status` | Review the concise brief and canonical lifecycle state |
203
+ | `planr operate findings accept <id>` | Record governance without applying a route |
204
+ | `planr operate routes apply <id>` | Apply one confirmed, digest-bound local route; Pipeline-PO DEV routes may return `awaiting-plan` and an exact native PLAN command |
205
+ | `planr operate decisions decide <id>` | Record an owner decision |
206
+ | `planr operate gaps answer <id>` | Supply missing evidence or charter context |
207
+ | `planr operate gaps verify <id> --evidence-ref <id>` | Verify an answered gap against explicit evidence before closing it |
208
+ | `planr operate run --review-only` | Reconcile verified shipment proofs and due outcome observations without evidence collection or model calls |
209
+ | `planr operate cache status` / `purge` | Inspect or purge machine-local evidence |
210
+ | `planr operate integrity status` / `enable` | Inspect integrity or enable externally keyed signed checkpoints |
211
+
170
212
  ### Spec-driven mode
171
213
 
172
214
  Third planning posture — designed for handing features to AI coding agents. Specs decompose into User Stories and Tasks with explicit file Create / Modify / Preserve lists, `Type: UI | Tech`, agent assignment, and DoD with build / test commands. Schema matches [OpenPlanr Protocol v1.0.0](https://github.com/openplanr/planr-pipeline/tree/main/docs/protocol); canonical JSON Schemas for this cleanup cycle live in `openplanr/planr-pipeline` under `schemas/v1.0.0/`.
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerOperateCommand(program: Command): void;
3
+ //# sourceMappingURL=operate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/operate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,WAAW,CAAC;AAkXvD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwe7D"}
@@ -0,0 +1,568 @@
1
+ import { isNonInteractive } from '../../services/interactive-state.js';
2
+ import { executeOperateAction, } from '../../services/operate/index.js';
3
+ import { promptCheckbox, promptConfirm, promptMultiText, promptSelect, promptText, } from '../../services/prompt-service.js';
4
+ import { display, logger } from '../../utils/logger.js';
5
+ const MAX_STDIN_BYTES = 64 * 1024;
6
+ function collect(value, previous) {
7
+ return [...previous, value];
8
+ }
9
+ function projectDir(program) {
10
+ return String(program.opts().projectDir);
11
+ }
12
+ function wantsJson(command, options) {
13
+ return Boolean(options.json || command.optsWithGlobals().json);
14
+ }
15
+ async function readBoundedStdin(enabled) {
16
+ if (!enabled)
17
+ return undefined;
18
+ const chunks = [];
19
+ let bytes = 0;
20
+ for await (const value of process.stdin) {
21
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
22
+ bytes += chunk.byteLength;
23
+ if (bytes > MAX_STDIN_BYTES) {
24
+ const error = new Error(`Standard input exceeds the ${MAX_STDIN_BYTES}-byte limit.`);
25
+ error.name = 'E_OPERATE_INPUT_TOO_LARGE';
26
+ throw error;
27
+ }
28
+ chunks.push(chunk);
29
+ }
30
+ return Buffer.concat(chunks).toString('utf8').trimEnd();
31
+ }
32
+ function renderHuman(result) {
33
+ if (result.message) {
34
+ if (result.ok)
35
+ logger.success(result.message);
36
+ else
37
+ logger.warn(result.message);
38
+ }
39
+ if (result.lines) {
40
+ for (const line of result.lines)
41
+ display.line(line);
42
+ }
43
+ if (result.data !== undefined) {
44
+ if (result.action === 'inspect' &&
45
+ typeof result.data === 'object' &&
46
+ result.data !== null &&
47
+ !Array.isArray(result.data)) {
48
+ const data = result.data;
49
+ const pipeline = typeof data.pipeline === 'object' && data.pipeline !== null
50
+ ? data.pipeline
51
+ : {};
52
+ display.line(`Project context: ${data.project === true ? 'detected' : 'not detected'}`);
53
+ display.line(`Initialization: ${data.initialized === true ? 'configured' : 'not configured'}`);
54
+ display.line(pipeline.available === true
55
+ ? `Pipeline: Protocol ${String(pipeline.protocolVersion ?? 'compatible')} ready`
56
+ : 'Pipeline: not installed (read-only inspection remains available)');
57
+ if (typeof data.commitSafeRoot === 'string') {
58
+ display.line(`Commit-safe state: ${data.commitSafeRoot}`);
59
+ }
60
+ if (typeof data.machineLocalState === 'string') {
61
+ display.line(`Machine-local data: ${data.machineLocalState}`);
62
+ }
63
+ }
64
+ else if (result.action === 'demo' &&
65
+ typeof result.data === 'object' &&
66
+ result.data !== null &&
67
+ !Array.isArray(result.data)) {
68
+ const data = result.data;
69
+ if (typeof data.brief === 'string')
70
+ display.line(data.brief);
71
+ const evidenceCount = Array.isArray(data.evidence) ? data.evidence.length : 0;
72
+ display.line(`Evidence: ${evidenceCount} sanitized deterministic record${evidenceCount === 1 ? '' : 's'}`);
73
+ if (typeof data.note === 'string')
74
+ display.line(data.note);
75
+ }
76
+ else if (typeof result.data === 'string')
77
+ display.line(result.data);
78
+ else
79
+ display.line(JSON.stringify(result.data, null, 2));
80
+ }
81
+ if (result.preview !== undefined) {
82
+ display.heading('Preview:');
83
+ display.line(JSON.stringify(result.preview, null, 2));
84
+ }
85
+ if (result.next?.length) {
86
+ display.blank();
87
+ display.heading('Next:');
88
+ for (const command of result.next)
89
+ display.line(` ${command}`);
90
+ }
91
+ }
92
+ async function executeForResult(program, command, action, args, options) {
93
+ const json = wantsJson(command, options);
94
+ let stdin;
95
+ try {
96
+ stdin = await readBoundedStdin(Boolean(options.stdin));
97
+ }
98
+ catch (error) {
99
+ const result = {
100
+ schemaVersion: '1.0.0',
101
+ protocolVersion: '1.2.0',
102
+ ok: false,
103
+ action,
104
+ code: error instanceof Error && error.name.startsWith('E_')
105
+ ? error.name
106
+ : 'E_OPERATE_INPUT_TOO_LARGE',
107
+ message: error instanceof Error ? error.message : String(error),
108
+ state: null,
109
+ paths: {},
110
+ counts: {},
111
+ warnings: [],
112
+ nextActions: ['Reduce the stdin payload to 65536 bytes or fewer and retry.'],
113
+ next: ['Reduce the stdin payload to 65536 bytes or fewer and retry.'],
114
+ exitCode: 2,
115
+ };
116
+ if (json)
117
+ display.line(JSON.stringify(result));
118
+ else
119
+ renderHuman(result);
120
+ process.exitCode = result.exitCode;
121
+ return result;
122
+ }
123
+ const request = {
124
+ action,
125
+ projectRoot: projectDir(program),
126
+ arguments: Object.fromEntries(Object.entries(args).filter((entry) => entry[1] !== undefined)),
127
+ options: {
128
+ ...options,
129
+ ...(Array.isArray(options.source) ? { sources: options.source } : {}),
130
+ ...(Array.isArray(options.component) ? { components: options.component } : {}),
131
+ json,
132
+ yes: Boolean(options.yes || program.opts().yes),
133
+ },
134
+ interactive: !json && !isNonInteractive(),
135
+ ...(stdin === undefined ? {} : { stdin }),
136
+ };
137
+ const result = await executeOperateAction(request);
138
+ if (json)
139
+ display.line(JSON.stringify(result));
140
+ else
141
+ renderHuman(result);
142
+ if (!result.ok)
143
+ process.exitCode = result.exitCode ?? 1;
144
+ return result;
145
+ }
146
+ async function execute(program, command, action, args, options) {
147
+ await executeForResult(program, command, action, args, options);
148
+ }
149
+ async function executeRunWithProviderConsent(program, command, options) {
150
+ const first = await executeForResult(program, command, 'run', {}, options);
151
+ if (first.ok ||
152
+ first.code !== 'E_OPERATE_AUTHORITY_REQUIRED' ||
153
+ wantsJson(command, options) ||
154
+ isNonInteractive()) {
155
+ return first;
156
+ }
157
+ const approved = await promptConfirm('Approve the disclosed provider policy for this operating run?', false);
158
+ if (!approved)
159
+ return first;
160
+ process.exitCode = undefined;
161
+ return executeForResult(program, command, 'run', {}, {
162
+ ...options,
163
+ yes: true,
164
+ });
165
+ }
166
+ async function guidedInitOptions(options) {
167
+ if (isNonInteractive())
168
+ return options;
169
+ const noChoices = options.profile === undefined &&
170
+ options.profileFile === undefined &&
171
+ options.decisionOwner === undefined &&
172
+ options.planningEngine === undefined &&
173
+ options.runtime === undefined &&
174
+ options.cadence === undefined &&
175
+ options.timezone === undefined &&
176
+ (!Array.isArray(options.component) || options.component.length === 0) &&
177
+ (!Array.isArray(options.source) || options.source.length === 0) &&
178
+ (!Array.isArray(options.evidenceFile) || options.evidenceFile.length === 0) &&
179
+ options.sensitivityCeiling === undefined;
180
+ if (!noChoices)
181
+ return options;
182
+ logger.heading('OpenPlanr Operating Board');
183
+ logger.dim('Configure one product workspace. Component repositories remain read-only.');
184
+ const profile = await promptSelect('Operating profile:', [
185
+ { name: 'SaaS — balanced product, growth, risk, and operations', value: 'saas' },
186
+ { name: 'Product — activation and customer outcomes', value: 'product' },
187
+ { name: 'Engineering — delivery, reliability, and risk', value: 'engineering' },
188
+ { name: 'Custom — validated profile file', value: 'custom' },
189
+ ], 'saas');
190
+ const profileFile = profile === 'custom' ? await promptText('Validated custom profile file:') : undefined;
191
+ const decisionOwner = await promptText('Who owns final operating decisions?');
192
+ const planningEngine = await promptSelect('Which engine creates accepted DEV specs?', [
193
+ { name: 'OpenPlanr — dedicated planning CLI', value: 'openplanr' },
194
+ { name: 'Pipeline PO — feature-local planning handoff', value: 'pipeline-po' },
195
+ ], 'openplanr');
196
+ const runtime = await promptSelect('Preferred coding runtime:', [
197
+ { name: 'Auto-detect a compatible runtime', value: 'auto' },
198
+ { name: 'Claude Code', value: 'claude' },
199
+ { name: 'Codex', value: 'codex' },
200
+ { name: 'Cursor', value: 'cursor' },
201
+ ], 'auto');
202
+ const cadence = await promptSelect('Operating cadence:', [
203
+ { name: 'Manual — run only when requested', value: 'manual' },
204
+ { name: 'Weekly display cadence', value: 'weekly' },
205
+ { name: 'Monthly display cadence', value: 'monthly' },
206
+ ], 'manual');
207
+ const timezone = await promptText('Display timezone (IANA):', Intl.DateTimeFormat().resolvedOptions().timeZone);
208
+ const sensitivityCeiling = await promptSelect('Highest evidence class allowed in this workspace:', [
209
+ { name: 'Internal — recommended', value: 'internal' },
210
+ { name: 'Public only', value: 'public' },
211
+ { name: 'Confidential', value: 'confidential' },
212
+ { name: 'Restricted', value: 'restricted' },
213
+ ], 'internal');
214
+ const sources = await promptCheckbox('Evidence sources:', [
215
+ { name: 'Repository files and metadata', value: 'repository', checked: true },
216
+ { name: 'OpenPlanr planning and delivery records', value: 'planr', checked: true },
217
+ { name: 'Git history and working-tree metadata', value: 'git', checked: true },
218
+ { name: 'GitHub (read-only; requires configured credentials)', value: 'github' },
219
+ { name: 'Linear (read-only; requires configured credentials)', value: 'linear' },
220
+ { name: 'Local JSON/CSV files (workspace-contained)', value: 'file-import' },
221
+ ]);
222
+ const evidenceFiles = sources.includes('file-import')
223
+ ? await promptMultiText('Workspace-contained JSON/CSV evidence paths', 'comma-separated paths')
224
+ : [];
225
+ const components = await promptMultiText('Read-only component repository paths (leave empty for this repository only)', 'comma-separated paths');
226
+ const charter = {
227
+ purpose: await promptText('What product outcome does this workspace exist to create?'),
228
+ stage: await promptText('Current product stage:'),
229
+ businessModel: await promptText('Business model:', 'Not yet specified'),
230
+ idealCustomer: await promptText('Ideal customer profile:', 'Not yet specified'),
231
+ goals: await promptMultiText('Current goals', 'comma-separated'),
232
+ successMetrics: await promptMultiText('Success metrics', 'comma-separated'),
233
+ guardrails: await promptMultiText('Human authority and product guardrails', 'comma-separated'),
234
+ knownUnknowns: await promptMultiText('Known unknowns', 'comma-separated'),
235
+ };
236
+ return {
237
+ ...options,
238
+ profile,
239
+ ...(profileFile ? { profileFile } : {}),
240
+ decisionOwner,
241
+ planningEngine,
242
+ runtime,
243
+ cadence,
244
+ timezone,
245
+ sensitivityCeiling,
246
+ sources,
247
+ evidenceFile: evidenceFiles,
248
+ components,
249
+ charter,
250
+ };
251
+ }
252
+ function json(command) {
253
+ return command.option('--json', 'emit one versioned machine-readable result', false);
254
+ }
255
+ function preview(command) {
256
+ return command
257
+ .option('--preview', 'inspect without writes or provider/model calls', false)
258
+ .option('--dry-run', 'allow disclosed model calls but commit no state', false);
259
+ }
260
+ function confirmed(command) {
261
+ return command.option('--yes', 'confirm this named action non-interactively', false);
262
+ }
263
+ function stdin(command) {
264
+ return command.option('--stdin', `read the sensitive answer from standard input (maximum ${MAX_STDIN_BYTES} bytes)`, false);
265
+ }
266
+ function machineBinding(command) {
267
+ return command
268
+ .option('--cycle-id <cycleId>', 'prepared operating cycle')
269
+ .option('--evidence-digest <digest>', 'immutable evidence snapshot digest')
270
+ .option('--lease <lease>', 'active adapter lease')
271
+ .option('--idempotency-key <key>', 'idempotent lifecycle call key');
272
+ }
273
+ function readGroup(program, parent, noun, singularArgument) {
274
+ json(parent.command('list').description(`List ${noun}`)).action(function (opts) {
275
+ return execute(program, this, `${noun}.list`, {}, opts);
276
+ });
277
+ json(parent.command(`show <${singularArgument}>`).description(`Show one ${noun.replace(/s$/, '')}`)).action(function (id, opts) {
278
+ return execute(program, this, `${noun}.show`, { id }, opts);
279
+ });
280
+ return parent;
281
+ }
282
+ export function registerOperateCommand(program) {
283
+ const operate = program
284
+ .command('operate')
285
+ .description('Turn verified product evidence into governed DEV, OWNER, and AGENT routes');
286
+ json(operate
287
+ .command('inspect')
288
+ .description('Inspect Operating Board readiness without initialization or credentials')).action(function (opts) {
289
+ return execute(program, this, 'inspect', {}, opts);
290
+ });
291
+ json(operate
292
+ .command('demo')
293
+ .description('Produce a deterministic credential-free operating brief without project writes')).action(function (opts) {
294
+ return execute(program, this, 'demo', {}, opts);
295
+ });
296
+ json(confirmed(preview(operate
297
+ .command('init')
298
+ .description('Initialize the product charter, workspace, privacy, and runtime policy')
299
+ .option('--profile <profile>', 'saas, product, engineering, or custom')
300
+ .option('--profile-file <path>', 'custom operating profile')
301
+ .option('--decision-owner <name>', 'human decision owner')
302
+ .option('--planning-engine <engine>', 'openplanr or pipeline-po')
303
+ .option('--runtime <runtime>', 'auto, claude, codex, or cursor')
304
+ .option('--cadence <cadence>', 'manual, weekly, or monthly')
305
+ .option('--timezone <zone>', 'IANA display timezone')
306
+ .option('--component <path>', 'read-only component repository (repeatable)', collect, [])
307
+ .option('--source <source>', 'evidence source (repeatable)', collect, [])
308
+ .option('--evidence-file <path>', 'workspace-contained JSON/CSV evidence file (repeatable)', collect, [])
309
+ .option('--sensitivity-ceiling <class>', 'public, internal, confidential, or restricted')))).action(function (opts) {
310
+ return (async () => {
311
+ const resolved = await guidedInitOptions(opts);
312
+ const interactive = !wantsJson(this, resolved) && !isNonInteractive() && !resolved.yes && !program.opts().yes;
313
+ let result;
314
+ if (interactive && !resolved.preview && !resolved.dryRun) {
315
+ const previewResult = await executeForResult(program, this, 'init', {}, {
316
+ ...resolved,
317
+ preview: true,
318
+ });
319
+ if (!previewResult.ok)
320
+ return;
321
+ if (!(await promptConfirm('Apply this exact Operating Board configuration?', true))) {
322
+ return;
323
+ }
324
+ result = await executeForResult(program, this, 'init', {}, {
325
+ ...resolved,
326
+ preview: false,
327
+ yes: true,
328
+ });
329
+ }
330
+ else {
331
+ result = await executeForResult(program, this, 'init', {}, resolved);
332
+ }
333
+ const legacyMigration = result.data?.legacyMigration;
334
+ if (result.ok &&
335
+ !resolved.preview &&
336
+ !resolved.dryRun &&
337
+ !resolved.json &&
338
+ !isNonInteractive() &&
339
+ legacyMigration?.record?.state === 'previewed') {
340
+ const count = legacyMigration.counts?.importable ?? 0;
341
+ if (await promptConfirm(`Import ${count} unambiguous legacy .planr/board record(s) now? Original files will remain untouched.`, false)) {
342
+ const migrationResult = await executeForResult(program, this, 'migrate.apply', {}, { yes: true });
343
+ if (!migrationResult.ok)
344
+ return;
345
+ }
346
+ }
347
+ if (result.ok &&
348
+ !resolved.preview &&
349
+ !resolved.dryRun &&
350
+ !resolved.json &&
351
+ !isNonInteractive() &&
352
+ (await promptConfirm('Run the first operating cycle now?', true))) {
353
+ await executeRunWithProviderConsent(program, this, {
354
+ runtime: resolved.runtime ?? 'auto',
355
+ depth: 'standard',
356
+ focus: [],
357
+ offline: false,
358
+ reviewOnly: false,
359
+ preview: false,
360
+ dryRun: false,
361
+ yes: false,
362
+ json: false,
363
+ });
364
+ }
365
+ })();
366
+ });
367
+ const config = operate
368
+ .command('config')
369
+ .description('Inspect or validate operating configuration');
370
+ json(config.command('show')).action(function (opts) {
371
+ return execute(program, this, 'config.show', {}, opts);
372
+ });
373
+ json(config.command('edit')).action(function (opts) {
374
+ return execute(program, this, 'config.edit', {}, opts);
375
+ });
376
+ json(config.command('validate')).action(function (opts) {
377
+ return execute(program, this, 'config.validate', {}, opts);
378
+ });
379
+ const profiles = operate.command('profiles').description('Inspect operating profiles');
380
+ json(profiles.command('list')).action(function (opts) {
381
+ return execute(program, this, 'profiles.list', {}, opts);
382
+ });
383
+ json(profiles.command('show <profile>')).action(function (profile, opts) {
384
+ return execute(program, this, 'profiles.show', { profile }, opts);
385
+ });
386
+ json(profiles.command('validate <path>')).action(function (file, opts) {
387
+ return execute(program, this, 'profiles.validate', { file }, opts);
388
+ });
389
+ const sources = operate.command('sources').description('Inspect and test evidence sources');
390
+ json(sources.command('list')).action(function (opts) {
391
+ return execute(program, this, 'sources.list', {}, opts);
392
+ });
393
+ json(sources.command('show <source>')).action(function (source, opts) {
394
+ return execute(program, this, 'sources.show', { source }, opts);
395
+ });
396
+ json(sources.command('test <source>')).action(function (source, opts) {
397
+ return execute(program, this, 'sources.test', { source }, opts);
398
+ });
399
+ json(confirmed(preview(operate
400
+ .command('run')
401
+ .description('Collect evidence and produce a reviewable operating cycle')
402
+ .option('--focus <lens>', 'evaluate one lens (repeatable)', collect, [])
403
+ .option('--depth <depth>', 'standard or deep', 'standard')
404
+ .option('--runtime <runtime>', 'auto, claude, codex, or cursor', 'auto')
405
+ .option('--offline', 'use local evidence and deterministic providers only', false)
406
+ .option('--review-only', 'reconcile existing routes and outcomes only', false)))).action(function (opts) {
407
+ return executeRunWithProviderConsent(program, this, opts).then(() => undefined);
408
+ });
409
+ json(operate.command('review [cycleId]').description('Review a cycle at the human gate')).action(function (cycleId, opts) {
410
+ return execute(program, this, 'review', { cycleId }, opts);
411
+ });
412
+ json(operate.command('status').description('Show current operating status')).action(function (opts) {
413
+ return execute(program, this, 'status', {}, opts);
414
+ });
415
+ json(operate.command('brief [cycleId]').description('Render the concise operating brief')).action(function (cycleId, opts) {
416
+ return execute(program, this, 'brief', { cycleId }, opts);
417
+ });
418
+ const cycles = readGroup(program, operate.command('cycles').description('Manage operating cycle lifecycle'), 'cycles', 'cycleId');
419
+ for (const action of ['resume', 'cancel', 'recover', 'close']) {
420
+ json(confirmed(cycles.command(`${action} <cycleId>`).description(`${action} an operating cycle`))).action(function (cycleId, opts) {
421
+ return execute(program, this, `cycles.${action}`, { cycleId }, opts);
422
+ });
423
+ }
424
+ const findings = readGroup(program, operate.command('findings').description('Govern operating findings'), 'findings', 'findingId');
425
+ for (const action of ['accept', 'reject', 'supersede']) {
426
+ json(confirmed(findings
427
+ .command(`${action} <findingId>`)
428
+ .description(action === 'accept'
429
+ ? 'Accept governance for a finding without applying its route'
430
+ : `${action} a finding`)
431
+ .option('--impact <score>', 'audited Impact amendment')
432
+ .option('--confidence <score>', 'audited Confidence amendment')
433
+ .option('--ease <score>', 'audited Ease amendment')
434
+ .option('--reason <text>', 'audit reason for the decision'))).action(function (findingId, opts) {
435
+ return execute(program, this, `findings.${action}`, { findingId }, opts);
436
+ });
437
+ }
438
+ const routes = readGroup(program, operate.command('routes').description('Preview, apply, or roll back governed routes'), 'routes', 'routeId');
439
+ json(confirmed(preview(routes
440
+ .command('apply <routeId>')
441
+ .description('Preview or apply the exact digest-bound route')
442
+ .option('--preview-digest <digest>', 'digest returned by the route preview')))).action(function (routeId, opts) {
443
+ return (async () => {
444
+ const interactive = !wantsJson(this, opts) && !isNonInteractive() && !opts.yes && !program.opts().yes;
445
+ if (!interactive || opts.preview || opts.dryRun) {
446
+ await execute(program, this, 'routes.apply', { routeId }, opts);
447
+ return;
448
+ }
449
+ let previewDigest = opts.previewDigest;
450
+ if (!previewDigest) {
451
+ const previewResult = await executeForResult(program, this, 'routes.apply', { routeId }, { ...opts, preview: true });
452
+ if (!previewResult.ok)
453
+ return;
454
+ previewDigest = previewResult.data
455
+ ?.previewDigest;
456
+ }
457
+ if (!previewDigest ||
458
+ !(await promptConfirm(`Apply route ${routeId} using this exact preview digest?`, true))) {
459
+ return;
460
+ }
461
+ await execute(program, this, 'routes.apply', { routeId }, {
462
+ ...opts,
463
+ preview: false,
464
+ previewDigest,
465
+ yes: true,
466
+ });
467
+ })();
468
+ });
469
+ json(confirmed(routes.command('rollback <routeId>'))).action(function (routeId, opts) {
470
+ return execute(program, this, 'routes.rollback', { routeId }, opts);
471
+ });
472
+ const decisions = readGroup(program, operate.command('decisions').description('Inspect and answer owner decisions'), 'decisions', 'decisionId');
473
+ json(confirmed(stdin(decisions
474
+ .command('decide <decisionId>')
475
+ .description('Record an owner decision')
476
+ .option('--value <value>', 'decision value')
477
+ .option('--reason <text>', 'decision rationale')))).action(function (decisionId, opts) {
478
+ return execute(program, this, 'decisions.decide', { decisionId }, opts);
479
+ });
480
+ const gaps = readGroup(program, operate.command('gaps').description('Inspect and answer evidence gaps'), 'gaps', 'gapId');
481
+ json(confirmed(stdin(gaps
482
+ .command('answer <gapId>')
483
+ .description('Answer an evidence or charter gap')
484
+ .option('--value <value>', 'answer value')))).action(function (gapId, opts) {
485
+ return execute(program, this, 'gaps.answer', { gapId }, opts);
486
+ });
487
+ json(confirmed(gaps
488
+ .command('verify <gapId>')
489
+ .description('Verify an answered gap against collected evidence')
490
+ .option('--evidence-ref <id>', 'verified evidence identifier (repeatable)', collect, []))).action(function (gapId, opts) {
491
+ return execute(program, this, 'gaps.verify', { gapId }, opts);
492
+ });
493
+ readGroup(program, operate.command('evidence').description('Inspect sanitized evidence metadata'), 'evidence', 'evidenceId');
494
+ const migrate = operate.command('migrate').description('Inspect or apply legacy board migration');
495
+ json(migrate.command('inspect')).action(function (opts) {
496
+ return execute(program, this, 'migrate.inspect', {}, opts);
497
+ });
498
+ json(confirmed(migrate.command('apply'))).action(function (opts) {
499
+ return (async () => {
500
+ const interactive = !wantsJson(this, opts) && !isNonInteractive() && !opts.yes && !program.opts().yes;
501
+ if (!interactive) {
502
+ await execute(program, this, 'migrate.apply', {}, opts);
503
+ return;
504
+ }
505
+ const inspection = await executeForResult(program, this, 'migrate.inspect', {}, opts);
506
+ if (!inspection.ok)
507
+ return;
508
+ const record = inspection.data?.record;
509
+ if (!record)
510
+ return;
511
+ if (record.state !== 'previewed' ||
512
+ !(await promptConfirm(`Apply legacy migration ${record.id}? Exact source bytes will be backed up and left untouched.`, false))) {
513
+ return;
514
+ }
515
+ await execute(program, this, 'migrate.apply', {}, { ...opts, yes: true });
516
+ })();
517
+ });
518
+ const migrations = readGroup(program, operate.command('migrations').description('Inspect or roll back operating migrations'), 'migrations', 'migrationId');
519
+ json(confirmed(migrations.command('rollback <migrationId>'))).action(function (migrationId, opts) {
520
+ return (async () => {
521
+ const interactive = !wantsJson(this, opts) && !isNonInteractive() && !opts.yes && !program.opts().yes;
522
+ if (interactive &&
523
+ !(await promptConfirm(`Roll back imported state for ${migrationId}? Legacy source files will not be changed.`, false))) {
524
+ return;
525
+ }
526
+ await execute(program, this, 'migrations.rollback', { migrationId }, interactive ? { ...opts, yes: true } : opts);
527
+ })();
528
+ });
529
+ const cache = operate.command('cache').description('Inspect or purge machine-local evidence');
530
+ json(cache.command('status')).action(function (opts) {
531
+ return execute(program, this, 'cache.status', {}, opts);
532
+ });
533
+ json(confirmed(cache.command('purge'))).action(function (opts) {
534
+ return execute(program, this, 'cache.purge', {}, opts);
535
+ });
536
+ const integrity = operate
537
+ .command('integrity')
538
+ .description('Inspect or enable signed checkpoints');
539
+ json(integrity.command('status')).action(function (opts) {
540
+ return execute(program, this, 'integrity.status', {}, opts);
541
+ });
542
+ json(confirmed(integrity.command('enable'))).action(function (opts) {
543
+ return execute(program, this, 'integrity.enable', {}, opts);
544
+ });
545
+ const diagnostics = operate.command('diagnostics').description('Export redacted diagnostics');
546
+ json(diagnostics.command('export').option('--output <path>', 'output archive or JSON path')).action(function (opts) {
547
+ return execute(program, this, 'diagnostics.export', {}, opts);
548
+ });
549
+ const security = operate.command('security').description('Exceptional sensitive-data repair');
550
+ json(confirmed(security.command('repair'))).action(function (opts) {
551
+ return execute(program, this, 'security.repair', {}, opts);
552
+ });
553
+ const adapter = operate
554
+ .command('adapter')
555
+ .description('Machine-only, lease-bound runtime adapter lifecycle');
556
+ json(machineBinding(adapter.command('prepare')).option('--role <roles>', 'comma-separated advisor roles bound to this isolated dispatch')).action(function (opts) {
557
+ return execute(program, this, 'adapter.prepare', {}, { ...opts, json: true });
558
+ });
559
+ json(stdin(machineBinding(adapter.command('record').requiredOption('--role <role>', 'operating advisor role')))).action(function (opts) {
560
+ return execute(program, this, 'adapter.record', {}, { ...opts, json: true });
561
+ });
562
+ for (const action of ['finalize', 'resume', 'cancel']) {
563
+ json(machineBinding(adapter.command(action))).action(function (opts) {
564
+ return execute(program, this, `adapter.${action}`, {}, { ...opts, json: true });
565
+ });
566
+ }
567
+ }
568
+ //# sourceMappingURL=operate.js.map