openplanr 1.13.3 → 1.14.0
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 +46 -4
- package/dist/cli/commands/operate.d.ts +3 -0
- package/dist/cli/commands/operate.d.ts.map +1 -0
- package/dist/cli/commands/operate.js +568 -0
- package/dist/cli/commands/operate.js.map +1 -0
- package/dist/cli/index.js +42 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/services/ai-service.d.ts +9 -2
- package/dist/services/ai-service.d.ts.map +1 -1
- package/dist/services/ai-service.js +14 -6
- package/dist/services/ai-service.js.map +1 -1
- package/dist/services/operate/advisors.d.ts +219 -0
- package/dist/services/operate/advisors.d.ts.map +1 -0
- package/dist/services/operate/advisors.js +745 -0
- package/dist/services/operate/advisors.js.map +1 -0
- package/dist/services/operate/artifact-route-generation.d.ts +111 -0
- package/dist/services/operate/artifact-route-generation.d.ts.map +1 -0
- package/dist/services/operate/artifact-route-generation.js +459 -0
- package/dist/services/operate/artifact-route-generation.js.map +1 -0
- package/dist/services/operate/artifacts.d.ts +26 -0
- package/dist/services/operate/artifacts.d.ts.map +1 -0
- package/dist/services/operate/artifacts.js +92 -0
- package/dist/services/operate/artifacts.js.map +1 -0
- package/dist/services/operate/canonical.d.ts +18 -0
- package/dist/services/operate/canonical.d.ts.map +1 -0
- package/dist/services/operate/canonical.js +157 -0
- package/dist/services/operate/canonical.js.map +1 -0
- package/dist/services/operate/config.d.ts +56 -0
- package/dist/services/operate/config.d.ts.map +1 -0
- package/dist/services/operate/config.js +644 -0
- package/dist/services/operate/config.js.map +1 -0
- package/dist/services/operate/consolidation.d.ts +18 -0
- package/dist/services/operate/consolidation.d.ts.map +1 -0
- package/dist/services/operate/consolidation.js +539 -0
- package/dist/services/operate/consolidation.js.map +1 -0
- package/dist/services/operate/doctor.d.ts +12 -0
- package/dist/services/operate/doctor.d.ts.map +1 -0
- package/dist/services/operate/doctor.js +307 -0
- package/dist/services/operate/doctor.js.map +1 -0
- package/dist/services/operate/engine.d.ts +53 -0
- package/dist/services/operate/engine.d.ts.map +1 -0
- package/dist/services/operate/engine.js +1097 -0
- package/dist/services/operate/engine.js.map +1 -0
- package/dist/services/operate/event-store.d.ts +57 -0
- package/dist/services/operate/event-store.d.ts.map +1 -0
- package/dist/services/operate/event-store.js +232 -0
- package/dist/services/operate/event-store.js.map +1 -0
- package/dist/services/operate/evidence-cache.d.ts +17 -0
- package/dist/services/operate/evidence-cache.d.ts.map +1 -0
- package/dist/services/operate/evidence-cache.js +96 -0
- package/dist/services/operate/evidence-cache.js.map +1 -0
- package/dist/services/operate/evidence-import.d.ts +40 -0
- package/dist/services/operate/evidence-import.d.ts.map +1 -0
- package/dist/services/operate/evidence-import.js +340 -0
- package/dist/services/operate/evidence-import.js.map +1 -0
- package/dist/services/operate/evidence-readiness.d.ts +8 -0
- package/dist/services/operate/evidence-readiness.d.ts.map +1 -0
- package/dist/services/operate/evidence-readiness.js +78 -0
- package/dist/services/operate/evidence-readiness.js.map +1 -0
- package/dist/services/operate/evidence.d.ts +71 -0
- package/dist/services/operate/evidence.d.ts.map +1 -0
- package/dist/services/operate/evidence.js +1022 -0
- package/dist/services/operate/evidence.js.map +1 -0
- package/dist/services/operate/ids.d.ts +7 -0
- package/dist/services/operate/ids.d.ts.map +1 -0
- package/dist/services/operate/ids.js +23 -0
- package/dist/services/operate/ids.js.map +1 -0
- package/dist/services/operate/index.d.ts +14 -0
- package/dist/services/operate/index.d.ts.map +1 -0
- package/dist/services/operate/index.js +881 -0
- package/dist/services/operate/index.js.map +1 -0
- package/dist/services/operate/journal.d.ts +34 -0
- package/dist/services/operate/journal.d.ts.map +1 -0
- package/dist/services/operate/journal.js +229 -0
- package/dist/services/operate/journal.js.map +1 -0
- package/dist/services/operate/legacy-import-service.d.ts +58 -0
- package/dist/services/operate/legacy-import-service.d.ts.map +1 -0
- package/dist/services/operate/legacy-import-service.js +922 -0
- package/dist/services/operate/legacy-import-service.js.map +1 -0
- package/dist/services/operate/lifecycle.d.ts +88 -0
- package/dist/services/operate/lifecycle.d.ts.map +1 -0
- package/dist/services/operate/lifecycle.js +556 -0
- package/dist/services/operate/lifecycle.js.map +1 -0
- package/dist/services/operate/lock-service.d.ts +37 -0
- package/dist/services/operate/lock-service.d.ts.map +1 -0
- package/dist/services/operate/lock-service.js +208 -0
- package/dist/services/operate/lock-service.js.map +1 -0
- package/dist/services/operate/maintenance.d.ts +38 -0
- package/dist/services/operate/maintenance.d.ts.map +1 -0
- package/dist/services/operate/maintenance.js +699 -0
- package/dist/services/operate/maintenance.js.map +1 -0
- package/dist/services/operate/outcomes.d.ts +48 -0
- package/dist/services/operate/outcomes.d.ts.map +1 -0
- package/dist/services/operate/outcomes.js +312 -0
- package/dist/services/operate/outcomes.js.map +1 -0
- package/dist/services/operate/pipeline-handoff.d.ts +138 -0
- package/dist/services/operate/pipeline-handoff.d.ts.map +1 -0
- package/dist/services/operate/pipeline-handoff.js +175 -0
- package/dist/services/operate/pipeline-handoff.js.map +1 -0
- package/dist/services/operate/projection-persistence.d.ts +55 -0
- package/dist/services/operate/projection-persistence.d.ts.map +1 -0
- package/dist/services/operate/projection-persistence.js +393 -0
- package/dist/services/operate/projection-persistence.js.map +1 -0
- package/dist/services/operate/projection.d.ts +4 -0
- package/dist/services/operate/projection.d.ts.map +1 -0
- package/dist/services/operate/projection.js +128 -0
- package/dist/services/operate/projection.js.map +1 -0
- package/dist/services/operate/protocol.d.ts +60 -0
- package/dist/services/operate/protocol.d.ts.map +1 -0
- package/dist/services/operate/protocol.js +62 -0
- package/dist/services/operate/protocol.js.map +1 -0
- package/dist/services/operate/read-only-providers.d.ts +38 -0
- package/dist/services/operate/read-only-providers.d.ts.map +1 -0
- package/dist/services/operate/read-only-providers.js +286 -0
- package/dist/services/operate/read-only-providers.js.map +1 -0
- package/dist/services/operate/redaction.d.ts +47 -0
- package/dist/services/operate/redaction.d.ts.map +1 -0
- package/dist/services/operate/redaction.js +279 -0
- package/dist/services/operate/redaction.js.map +1 -0
- package/dist/services/operate/reducer.d.ts +10 -0
- package/dist/services/operate/reducer.d.ts.map +1 -0
- package/dist/services/operate/reducer.js +11 -0
- package/dist/services/operate/reducer.js.map +1 -0
- package/dist/services/operate/routes.d.ts +49 -0
- package/dist/services/operate/routes.d.ts.map +1 -0
- package/dist/services/operate/routes.js +996 -0
- package/dist/services/operate/routes.js.map +1 -0
- package/dist/services/operate/shipment-observer.d.ts +14 -0
- package/dist/services/operate/shipment-observer.d.ts.map +1 -0
- package/dist/services/operate/shipment-observer.js +321 -0
- package/dist/services/operate/shipment-observer.js.map +1 -0
- package/dist/services/operate/stalled-item-service.d.ts +18 -0
- package/dist/services/operate/stalled-item-service.d.ts.map +1 -0
- package/dist/services/operate/stalled-item-service.js +121 -0
- package/dist/services/operate/stalled-item-service.js.map +1 -0
- package/dist/services/operate/subprocess-env.d.ts +4 -0
- package/dist/services/operate/subprocess-env.d.ts.map +1 -0
- package/dist/services/operate/subprocess-env.js +45 -0
- package/dist/services/operate/subprocess-env.js.map +1 -0
- package/dist/services/operate/types.d.ts +729 -0
- package/dist/services/operate/types.d.ts.map +1 -0
- package/dist/services/operate/types.js +13 -0
- package/dist/services/operate/types.js.map +1 -0
- package/dist/services/operate/workspace.d.ts +59 -0
- package/dist/services/operate/workspace.d.ts.map +1 -0
- package/dist/services/operate/workspace.js +316 -0
- package/dist/services/operate/workspace.js.map +1 -0
- package/dist/services/runtime-manager-service.d.ts.map +1 -1
- package/dist/services/runtime-manager-service.js +71 -2
- package/dist/services/runtime-manager-service.js.map +1 -1
- 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.**
|
|
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
|
[](https://www.npmjs.com/package/openplanr)
|
|
10
12
|
[](https://nodejs.org)
|
|
11
13
|
[](https://github.com/openplanr/OpenPlanr/blob/main/LICENSE)
|
|
12
|
-
[](https://github.com/openplanr/planr-pipeline/tree/main/docs/protocol)
|
|
13
15
|
[](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 @@
|
|
|
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
|