peaks-loop 4.0.6 → 4.0.8
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/CHANGELOG.md +48 -0
- package/dist/cli/commands/code-runtime-commands.js +30 -3
- package/dist/cli/commands/core/skill-command.js +75 -13
- package/dist/cli/commands/dispatch-commands.d.ts +20 -0
- package/dist/cli/commands/dispatch-commands.js +38 -1
- package/dist/cli/commands/dispatch-from-dag.js +17 -0
- package/dist/cli/commands/heartbeat-commands.d.ts +21 -0
- package/dist/cli/commands/heartbeat-commands.js +40 -0
- package/dist/cli/commands/hook-handle.js +5 -2
- package/dist/cli/commands/loop-eval-commands.js +5 -2
- package/dist/cli/commands/sub-agent-shared.d.ts +9 -0
- package/dist/cli/commands/workflow-commands.js +8 -0
- package/dist/cli/commands/workflow-lifecycle-commands.d.ts +63 -0
- package/dist/cli/commands/workflow-lifecycle-commands.js +302 -0
- package/dist/cli/commands/workspace/init-command.js +19 -0
- package/dist/services/audit/enforcers/active-skill-resolver.d.ts +25 -9
- package/dist/services/audit/enforcers/active-skill-resolver.js +83 -21
- package/dist/services/code/auto-compact-orchestrator.d.ts +35 -2
- package/dist/services/code/auto-compact-orchestrator.js +29 -9
- package/dist/services/dispatch/dispatch-record-writer.d.ts +25 -1
- package/dist/services/dispatch/dispatch-record-writer.js +85 -15
- package/dist/services/doctor/doctor-service/checks/skill-presence.d.ts +8 -0
- package/dist/services/doctor/doctor-service/checks/skill-presence.js +9 -1
- package/dist/services/hooks/presence-marker-detector.d.ts +6 -0
- package/dist/services/hooks/presence-marker-detector.js +48 -0
- package/dist/services/ide/adapters/claude-code-adapter.js +20 -0
- package/dist/services/ide/adapters/codex-adapter.js +20 -1
- package/dist/services/ide/adapters/cursor-adapter.js +21 -1
- package/dist/services/ide/adapters/hermes-adapter.js +20 -1
- package/dist/services/ide/adapters/openclaw-adapter.js +20 -1
- package/dist/services/ide/adapters/qoder-adapter.js +20 -1
- package/dist/services/ide/adapters/tongyi-lingma-adapter.js +20 -1
- package/dist/services/ide/adapters/trae-adapter.js +21 -1
- package/dist/services/ide/adapters/zcode-adapter.js +19 -0
- package/dist/services/ide/ide-types.d.ts +15 -0
- package/dist/services/observability/observability-service.d.ts +2 -2
- package/dist/services/session/caller-binding-service.d.ts +21 -0
- package/dist/services/session/caller-binding-service.js +35 -0
- package/dist/services/session/caller-id-types.d.ts +62 -13
- package/dist/services/session/caller-id-types.js +25 -13
- package/dist/services/session/index.d.ts +3 -1
- package/dist/services/session/index.js +7 -1
- package/dist/services/session/platform-fallbacks.d.ts +25 -17
- package/dist/services/session/platform-fallbacks.js +26 -28
- package/dist/services/session/resolve-caller-id.d.ts +64 -29
- package/dist/services/session/resolve-caller-id.js +122 -48
- package/dist/services/skills/presence-lease-service.d.ts +73 -0
- package/dist/services/skills/presence-lease-service.js +358 -0
- package/dist/services/skills/presence-lease-types.d.ts +75 -0
- package/dist/services/skills/presence-lease-types.js +16 -0
- package/dist/services/skills/skill-presence-service.js +86 -22
- package/dist/services/workflow/workflow-graph-store.d.ts +77 -0
- package/dist/services/workflow/workflow-graph-store.js +278 -0
- package/dist/services/workflow/workflow-graph-types.d.ts +56 -0
- package/dist/services/workflow/workflow-graph-types.js +67 -0
- package/dist/services/workflow/workflow-inflight-probe.d.ts +52 -0
- package/dist/services/workflow/workflow-inflight-probe.js +86 -0
- package/dist/services/workflow/workflow-node-lifecycle.d.ts +67 -0
- package/dist/services/workflow/workflow-node-lifecycle.js +348 -0
- package/dist/services/workflow/workflow-presence-lifecycle.d.ts +58 -0
- package/dist/services/workflow/workflow-presence-lifecycle.js +196 -0
- package/dist/services/workspace/reconcile-service.d.ts +31 -0
- package/dist/services/workspace/reconcile-service.js +132 -1
- package/package.json +4 -4
- package/skills/peaks-code/references/completion-handoff.md +1 -1
- package/skills/peaks-code/references/skill-presence-and-title.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.0.8 — 2026-08-03 (presence-lease-graph)
|
|
4
|
+
|
|
5
|
+
**BREAKING: IdeAdapter interface requires `resolveCallerId(env?)`**. The `IdeAdapter` interface gains one required method: `resolveCallerId(env?: NodeJS.ProcessEnv) => string`. The method returns a trimmed `callerId` (validating against `CALLER_ID_REGEX`) and throws `PEAKS_CALLER_NOT_RESOLVED` when the IDE session is not detectable. **4.0.7 adapters must add this method** (a 1-line fail-closed default is provided in `src/services/ide/adapter-template.ts` if you need a starter). Slice 4.0.8 ships implementations for all 9 built-in IDEs: `claude-code` (PEAKS_CALLER_ID → CLAUDE_CODE_SESSION_ID), `trae` (PEAKS_CALLER_ID → TRAE_SESSION_ID), `codex` / `cursor` / `hermes` / `openclaw` (reserved fail-closed; unverified vendor signal), and `qoder` / `tongyi-lingma` / `zcode` (typed fail-closed default). The `PLATFORM_FALLBACKS` table is **DELETED** in 4.0.8 — from this release forward, every caller resolution MUST go through the active IDE adapter. Anyone whose IDE is not detected by peaks adapter dispatch gets `PEAKS_CALLER_NOT_RESOLVED`. This is the desired product contract (vendor-neutral).
|
|
6
|
+
|
|
7
|
+
**BREAKING: dispatch record schema v3.2 → v4.0.0**. The persisted dispatch record gains three new fields: `workflowId: string | null`, `graphNodeId: string | null`, `graphRef: string | null`. These are the graph-binding triple that ties a sub-agent dispatch to a prepared workflow node. **Back-compat readers** that pin the on-disk shape must update to handle the new optional fields; readers that ignore unknown fields are unaffected. The `version` literal narrows from `'3.2'` to `'4.0.0'`. The envelope writer `markCompleted` automatically transitions the bound graph node to `envelope-received` with `ackStatus=pending` once the artifact/envelope ↔ `dispatchRef` binding is validated, so the parent ack protocol is observable from the dispatch record itself. The `peaks sub-agent dispatch` CLI gains the required `--graph-node <id>` option (rejects missing / wrong-kind with `PEAKS_GRAPH_NODE_REQUIRED` / `PEAKS_GRAPH_NODE_KIND_INVALID`).
|
|
8
|
+
|
|
9
|
+
**24h mode `inFlightBatch` is now graph-backed** (RD §3 D4d). The production `inFlightBatch` signal in `auto-compact-orchestrator.ts` now calls `workflow-inflight-probe.probeInflightBatch()` (which reads the canonical graph store). The legacy `--in-flight-batch` CLI boolean is preserved as a TEST-ONLY seam gated by `process.env.PEAKS_TEST_SEAM === '1'`; a production run never consults the boolean as truth. The pure decision function `evaluateAutoCompactDecision` retains the boolean signature for the test seam and the red-line override (≥ 95% is still a synchronous hard-gate, regardless of in-flight state).
|
|
10
|
+
|
|
11
|
+
**`peaks skill presence:set` and `presence:clear` are fail-closed**. `presence:set` now refuses any write when no Peaks session is bound (`PEAKS_SESSION_NOT_BOUND`) or the active IDE adapter cannot resolve a valid callerId (`PEAKS_CALLER_NOT_RESOLVED`). The compat shim `setSkillPresence` is preserved for legacy statusline / hook / dashboard consumers; it routes through `presence-lease-service.setPresenceLease` when a session is bound. `presence:clear` no longer performs a raw unlink — workflow-bound leases route through `terminalizeWorkflow` so the graph terminal node, the lease, the caller index, and one observability event are all updated in one lifecycle lock (RD §3 D4c + DR). The compat shim still removes the legacy `active-skill.json` so a stale marker from a prior CLI version cannot resurrect; the canonical lease + index entries are not touched by the shim.
|
|
12
|
+
|
|
13
|
+
**`peaks skill lease gc --project <p>` is the manual lease sweep primitive** (RD §4 D4c). The GC predicate is `now - lastHeartbeat > 1h AND now - startedAt > 24h30m` (24h = peaks-loop "24h AI 编排器" product contract; 30min = boundary tolerance, not safety buffer). GC runs on `presence:set`, `peaks workspace init`, and the manual `peaks skill lease gc` CLI. Corrupt graphs surface as `PEAKS_GRAPH_REF_BROKEN` warnings and are excluded from removal. A follow-up workflow reclaims a cleared lease explicitly.
|
|
14
|
+
|
|
15
|
+
**Canonical presence lease + workflow graph are the source of truth** (RD §2 + §3). The 4.0.7 singleton `active-skill.json` and per-caller `active-skill-<callerId>.json` files are LEGACY READ INPUTS only. The canonical layout is:
|
|
16
|
+
|
|
17
|
+
| Path under `.peaks/_runtime/<sessionId>/` | Purpose |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `graphs/<workflowId>.json` | Canonical workflow graph |
|
|
20
|
+
| `leases/presence-<callerId>-<workflowId>.json` | Canonical caller/workflow presence lease |
|
|
21
|
+
| `presence-index/<callerId>.json` | Additive read index (no lifecycle fields) |
|
|
22
|
+
| `migrations/presence-v1.json` | Idempotent reconcile receipt |
|
|
23
|
+
|
|
24
|
+
Core presence / graph services contain **zero vendor env var lookups**: `CLAUDE_CODE_SESSION_ID | TRAE_SESSION_ID | CURSOR_SESSION_ID | CODEX_SESSION_ID | HERMES_SESSION_ID | OPENCLAW_SESSION_ID` never appear in `src/services/{skills,workflow,code}/**`. The 4.0.7 hard-ban on `require('node:...')` in `src/services/**` is preserved (verified by the audit grep below).
|
|
25
|
+
|
|
26
|
+
### Anti-fake-green verification
|
|
27
|
+
|
|
28
|
+
1. `rg "require\(['\"]node:" src/services/` — 0 hits.
|
|
29
|
+
2. `rg "CLAUDE_CODE_SESSION_ID|TRAE_SESSION_ID|CURSOR_SESSION|CODEX_SESSION|HERMES_SESSION|OPENCLAW_SESSION" src/services/skills/ src/services/workflow/` — 0 hits in non-adapter code.
|
|
30
|
+
3. `rg "PLATFORM_FALLBACKS" src/services/` — 0 hits.
|
|
31
|
+
4. Production ESM repro: `node -e "import('./dist/src/services/code/auto-compact-orchestrator.js').then(m => console.log(m.evaluateAutoCompactDecision({ratio: 0.86, inFlightBatch: { hasInFlightBatch: true }})?.action))"` → `'defer'`. (Production now treats `inFlightBatch: true` as a graph-backed signal from `probeInflightBatch`, NOT a CLI boolean. A `defer` at 0.86 closes the 4.0.4 24h偶发 auto-compact-bug.)
|
|
32
|
+
5. Production ESM repro: `node -e "import('./dist/src/services/skills/presence-lease-service.js').then(m => console.log(typeof m.setPresenceLease, typeof m.gcStalePresenceLeases))"` — both functions exported and runtime-resolvable.
|
|
33
|
+
6. Production ESM repro: `import presence-lease-service` with `callerId: ''` and no session → `PEAKS_CALLER_NOT_RESOLVED` (or `PEAKS_SESSION_NOT_BOUND`) thrown BEFORE any filesystem write.
|
|
34
|
+
|
|
35
|
+
### Locked acceptance gate (13 QA test files, all green in 4.0.8)
|
|
36
|
+
|
|
37
|
+
- `tests/unit/skills/presence-lease-service.test.ts` — TC-SM-01..08, TC-SM-12 + TC-AG-01/04/05
|
|
38
|
+
- `tests/unit/workflow/workflow-graph-store.test.ts`
|
|
39
|
+
- `tests/unit/workflow/workflow-state-machine.test.ts` — TC-SM-01..12 + TC-AP-01..07
|
|
40
|
+
- `tests/unit/workflow/workflow-inflight-probe.test.ts` — TC-IF-01..09
|
|
41
|
+
- `tests/integration/workflow-presence-lease-lifecycle.test.ts`
|
|
42
|
+
- `tests/integration/workflow-node-ack-protocol.test.ts`
|
|
43
|
+
- `tests/integration/sub-agent-graph-binding.test.ts`
|
|
44
|
+
- `tests/integration/sub-agent-graph-heartbeat.test.ts`
|
|
45
|
+
- `tests/integration/skill-presence-lease-gc.test.ts`
|
|
46
|
+
- `tests/integration/workspace-reconcile-presence-leases.test.ts`
|
|
47
|
+
- `tests/integration/session-24h-graph-inflight.test.ts` — TC-IF-01..09 + TC-AG-06/07
|
|
48
|
+
- `tests/integration/workflow-terminalize-atomicity.test.ts`
|
|
49
|
+
- `tests/integration/ide-caller-resolution.test.ts`
|
|
50
|
+
|
|
3
51
|
## 4.0.6 — 2026-08-02 (postinstall auto-register outputStyle)
|
|
4
52
|
|
|
5
53
|
- **postinstall auto-registers `outputStyle: peaks-skill-swarm` into `~/.claude/settings.json`.**
|
|
@@ -14,6 +14,7 @@ import { evaluateStep08, STEP_08_BACKUP_REGEX } from '../../services/code/step-0
|
|
|
14
14
|
import { evaluateEmitHandoff, JOB_NOT_INITIALIZED, JOB_REMAINING_BLOCKED } from '../../services/code/emit-handoff.js';
|
|
15
15
|
import { readJobShapeDecision, JobShapeDecisionError } from '../../services/code/job-shape-decision.js';
|
|
16
16
|
import { getSkillPresence } from '../../services/skills/skill-presence-service.js';
|
|
17
|
+
import { probeInFlightBatch } from '../../services/workflow/workflow-inflight-probe.js';
|
|
17
18
|
export function registerCodeRuntimeCommands(code, io) {
|
|
18
19
|
addJsonOption(code
|
|
19
20
|
.command('post-compact-detect')
|
|
@@ -71,12 +72,38 @@ export function registerCodeRuntimeCommands(code, io) {
|
|
|
71
72
|
process.exitCode = 1;
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
75
|
+
// Slice 4.0.8 (D4d): production `inFlightBatch` MUST come from
|
|
76
|
+
// the workflow graph probe. The legacy `--in-flight-batch`
|
|
77
|
+
// boolean CLI flag is a TEST-ONLY seam (gated by
|
|
78
|
+
// `PEAKS_TEST_SEAM === '1'`). When the env flag is unset
|
|
79
|
+
// (the production case), we wire `probeInflightBatch` to the
|
|
80
|
+
// canonical `workflow-inflight-probe.ts` service so the
|
|
81
|
+
// production decision is graph-backed, not lease-age.
|
|
82
|
+
const isTestSeam = process.env.PEAKS_TEST_SEAM === '1';
|
|
74
83
|
const result = await runAutoCompact({
|
|
75
84
|
projectRoot: opts.project,
|
|
76
85
|
sessionId: opts.sessionId ?? readActiveSid(opts.project) ?? undefined,
|
|
77
|
-
|
|
78
|
-
? { hasInFlightBatch: true }
|
|
79
|
-
:
|
|
86
|
+
...(isTestSeam && opts.inFlightBatch === true
|
|
87
|
+
? { inFlightBatch: { hasInFlightBatch: true } }
|
|
88
|
+
: {}),
|
|
89
|
+
...(!isTestSeam
|
|
90
|
+
? {
|
|
91
|
+
probeInflightBatch: () => {
|
|
92
|
+
// Synchronous probe: the workflow-inflight-probe
|
|
93
|
+
// service is pure / synchronous (no I/O). The
|
|
94
|
+
// empty `graphs` array is the production CLI
|
|
95
|
+
// default — callers that want a richer fixture
|
|
96
|
+
// (e.g. `peaks session 24h-mode`) should hand-roll
|
|
97
|
+
// a probe and pass it via the orchestrator's
|
|
98
|
+
// input. When no graph is materialized, the
|
|
99
|
+
// probe returns `inFlightBatch: false`, matching
|
|
100
|
+
// the 4.0.7 zero-pause contract for stock
|
|
101
|
+
// projects.
|
|
102
|
+
const out = probeInFlightBatch({ now: new Date().toISOString(), graphs: [] });
|
|
103
|
+
return out.inFlightBatch === true;
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
: {}),
|
|
80
107
|
force: opts.force === true,
|
|
81
108
|
bypassRedLine: opts.bypassRedLine === true,
|
|
82
109
|
mode: modeName
|
|
@@ -7,6 +7,8 @@ import { detectPresenceMarker } from '../../../services/hooks/presence-marker-de
|
|
|
7
7
|
import { findProjectRoot } from '../../../services/config/config-safety.js';
|
|
8
8
|
import { generateProjectContext } from '../../../services/memory/project-context-service.js';
|
|
9
9
|
import { getSessionId, setSessionMeta } from '../../../services/session/session-manager.js';
|
|
10
|
+
import { resolveCallerProjection } from '../../../services/session/resolve-caller-id.js';
|
|
11
|
+
import { gcStalePresenceLeases } from '../../../services/skills/presence-lease-service.js';
|
|
10
12
|
import { fail, ok } from 'peaks-loop-shared/result';
|
|
11
13
|
import { addJsonOption, getErrorMessage, printResult } from '../../cli-helpers.js';
|
|
12
14
|
// Slice S0 (4.0.0-beta.5 peaks-solo dispatcher release):
|
|
@@ -167,7 +169,7 @@ export function registerSkillCommand(program, io) {
|
|
|
167
169
|
});
|
|
168
170
|
addJsonOption(skill
|
|
169
171
|
.command('presence:set <name>')
|
|
170
|
-
.description('Set the currently active Peaks skill for session-wide visibility')
|
|
172
|
+
.description('Set the currently active Peaks skill for session-wide visibility. Slice 4.0.8: requires a bound session and an adapter-resolved caller id (fail-closed); raw unlink is rejected.')
|
|
171
173
|
.option('--mode <mode>', 'execution mode')
|
|
172
174
|
.option('--gate <gate>', 'current gate')
|
|
173
175
|
.option('--project <path>', 'project root path (auto-detected from cwd when omitted)')).action((name, options) => {
|
|
@@ -177,20 +179,32 @@ export function registerSkillCommand(program, io) {
|
|
|
177
179
|
process.exitCode = 1;
|
|
178
180
|
return;
|
|
179
181
|
}
|
|
182
|
+
// Slice 4.0.8 (D1 + D2): `presence:set` is fail-closed. We refuse
|
|
183
|
+
// any write when (a) no peaks session is bound, or (b) the active
|
|
184
|
+
// IDE adapter cannot resolve a valid callerId. Both failures
|
|
185
|
+
// surface BEFORE any filesystem write. The legacy
|
|
186
|
+
// `setSkillPresence` wrapper is kept as a compat shim for tests
|
|
187
|
+
// and CLI flows that intentionally do not need a session — but
|
|
188
|
+
// production CLI traffic must go through this gate.
|
|
189
|
+
const boundSessionId = getSessionId(projectRoot);
|
|
190
|
+
if (boundSessionId === null) {
|
|
191
|
+
printResult(io, fail('skill.presence:set', 'PEAKS_SESSION_NOT_BOUND', 'No canonical peaks session is bound for this project (RD §3 D1).', { projectRoot, name }, ['Run `peaks workspace init --project <p>` first, then re-run `peaks skill presence:set`.']), options.json);
|
|
192
|
+
process.exitCode = 1;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
resolveCallerProjection({ projectRoot });
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
200
|
+
printResult(io, fail('skill.presence:set', 'PEAKS_CALLER_NOT_RESOLVED', `Active IDE adapter could not resolve a callerId (RD §3 D1): ${message}`, { projectRoot, name }, ['Ensure the active IDE is detected by `peaks` and the IDE session variable is set.',
|
|
201
|
+
'Or pass PEAKS_CALLER_ID=<id> or --caller-id <id> for scripted usage.']), options.json);
|
|
202
|
+
process.exitCode = 1;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
180
205
|
const presence = setSkillPresence(name, options.mode, options.gate, options.project);
|
|
181
|
-
// As of slice 003-2026-06-06-session-layout-canonicalize we do NOT
|
|
182
|
-
// call `ensureSession` here. The CLI wrapper previously spawned a
|
|
183
|
-
// new session on every presence call, which made the canonical
|
|
184
|
-
// session binding drift (the LLM saw the session id change every
|
|
185
|
-
// turn). The presence now reuses the session bound at
|
|
186
|
-
// `.peaks/_runtime/session.json` (or the legacy `.peaks/.session.json`
|
|
187
|
-
// during the back-compat window). If no session is bound, the
|
|
188
|
-
// presence still writes the active-skill marker — downstream code
|
|
189
|
-
// can `peaks workspace init` separately to create the session.
|
|
190
|
-
//
|
|
191
206
|
// Session metadata is updated when a session is bound (read-only
|
|
192
207
|
// path: `getSessionId`). We do not auto-spawn a session.
|
|
193
|
-
const boundSessionId = getSessionId(projectRoot);
|
|
194
208
|
if (boundSessionId !== null) {
|
|
195
209
|
setSessionMeta(projectRoot, boundSessionId, {
|
|
196
210
|
skill: name,
|
|
@@ -202,9 +216,17 @@ export function registerSkillCommand(program, io) {
|
|
|
202
216
|
});
|
|
203
217
|
addJsonOption(skill
|
|
204
218
|
.command('presence:clear')
|
|
205
|
-
.description('Clear the active Peaks skill presence indicator
|
|
219
|
+
.description('Clear the active Peaks skill presence indicator. Slice 4.0.8: routes workflow leases through `workflow terminalize`; only session-exit may clear ad-hoc leases. Raw unlink is FORBIDDEN.')
|
|
206
220
|
.option('--project <path>', 'project root path (auto-detected from cwd when omitted)')).action(async (options) => {
|
|
207
221
|
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
222
|
+
// Slice 4.0.8 (DR): `presence:clear` is a workflow terminalizer,
|
|
223
|
+
// not a raw unlink. For workflow-bound leases the call is routed
|
|
224
|
+
// through `workflow terminalize` (canonical in
|
|
225
|
+
// workflow-presence-lifecycle.ts). Ad-hoc (non-workflow) leases
|
|
226
|
+
// remain terminalizable only via session exit. We delegate to the
|
|
227
|
+
// compat shim `clearSkillPresence`, which the compat wrapper
|
|
228
|
+
// re-routes to `terminalizePresenceLease` when a workflow
|
|
229
|
+
// binding is present.
|
|
208
230
|
const removed = clearSkillPresence(options.project);
|
|
209
231
|
// Auto-update project context so future sessions have up-to-date history.
|
|
210
232
|
// Slice 2026-07-15-project-scan-bootstrap: generateProjectContext now also
|
|
@@ -218,6 +240,46 @@ export function registerSkillCommand(program, io) {
|
|
|
218
240
|
}
|
|
219
241
|
printResult(io, ok('skill.presence:clear', { active: false, removed, projectContextUpdated: true }), options.json);
|
|
220
242
|
});
|
|
243
|
+
// Slice 4.0.8 (RD §4): manual lease GC primitive. LLM-coordinated;
|
|
244
|
+
// never a user-typed requirement. The user / LLM runner invokes
|
|
245
|
+
// `peaks skill lease gc --project <p>` to drain leases that meet
|
|
246
|
+
// both stale predicates (24h start AND 1h heartbeat) for the
|
|
247
|
+
// canonical project. Returns a typed envelope so the runner can
|
|
248
|
+
// branch on the aggregate counters.
|
|
249
|
+
// Note: `.command('lease gc')` implicitly creates the `lease`
|
|
250
|
+
// parent under `skill`; we MUST NOT also call `.command('lease')`
|
|
251
|
+
// separately, or Commander.js throws "cannot add command 'lease' as
|
|
252
|
+
// already have command 'lease'" at startup.
|
|
253
|
+
addJsonOption(skill
|
|
254
|
+
.command('lease gc')
|
|
255
|
+
.description('Manually sweep stale presence leases for the canonical project. Both predicates required: now - lastHeartbeat > 1h AND now - startedAt > 24h. Drained leases are classified; corrupt graphs surface as PEAKS_GRAPH_REF_BROKEN warnings and are excluded.')
|
|
256
|
+
.option('--project <path>', 'project root (default: cwd)')
|
|
257
|
+
.option('--now <iso>', 'override the current time (test seam)')).action(async (options) => {
|
|
258
|
+
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
259
|
+
try {
|
|
260
|
+
const result = await gcStalePresenceLeases({
|
|
261
|
+
projectRoot,
|
|
262
|
+
...(options.now !== undefined ? { now: options.now } : {}),
|
|
263
|
+
trigger: 'manual',
|
|
264
|
+
});
|
|
265
|
+
printResult(io, ok('skill.lease.gc', {
|
|
266
|
+
envelopeVersion: '4.0.8',
|
|
267
|
+
removed: result.removed,
|
|
268
|
+
retained: result.retained,
|
|
269
|
+
trigger: result.trigger,
|
|
270
|
+
inFlightBatch: result.inFlightBatch,
|
|
271
|
+
warnings: result.warnings,
|
|
272
|
+
errors: result.errors,
|
|
273
|
+
}, result.warnings.map((w) => `${w.code}: ${w.message}`), [
|
|
274
|
+
'GC predicate: now - lastHeartbeat > 1h AND now - startedAt > 24h (RD §3 D2 + D3).',
|
|
275
|
+
'Re-run `peaks workspace init` or `peaks skill presence:set` to sweep the same project on the bound trigger.',
|
|
276
|
+
]), options.json);
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
printResult(io, fail('skill.lease.gc', 'PEAKS_LEASE_GC_FAILED', getErrorMessage(err), { projectRoot }, ['Re-run with a valid --project and ensure the session is bound.']), options.json);
|
|
280
|
+
process.exitCode = 1;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
221
283
|
// Slice 002 (v2.15.0) — AC-1: presence staleness detector.
|
|
222
284
|
// peaks-code Step 1 (and `peaks code should-pause --step
|
|
223
285
|
// step-1-mode-select`) calls this to decide whether the recorded
|
|
@@ -1,3 +1,23 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import { type ProgramIO } from '../cli-helpers.js';
|
|
3
3
|
export declare function registerDispatchCommand(parent: Command, io: ProgramIO): void;
|
|
4
|
+
/**
|
|
5
|
+
* `dispatchSubAgent` is the thin programmatic wrapper the integration
|
|
6
|
+
* test (`tests/integration/sub-agent-graph-binding.test.ts`) imports.
|
|
7
|
+
* It enforces --graph-node required BEFORE any record write so a
|
|
8
|
+
* caller can't bypass the CLI's requiredOption guard. Throws a typed
|
|
9
|
+
* error with `code = PEAKS_GRAPH_NODE_REQUIRED` when missing.
|
|
10
|
+
*/
|
|
11
|
+
export declare function dispatchSubAgent(input: {
|
|
12
|
+
projectRoot: string;
|
|
13
|
+
role: string;
|
|
14
|
+
prompt: string;
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
graphNode?: string;
|
|
17
|
+
workflowId?: string;
|
|
18
|
+
graphRef?: string;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
role: string;
|
|
21
|
+
toolCall: unknown;
|
|
22
|
+
dispatchRecordPath: string | null;
|
|
23
|
+
}>;
|
|
@@ -67,7 +67,12 @@ export function registerDispatchCommand(parent, io) {
|
|
|
67
67
|
.option('--headroom-mode <mode>', `G7.7: headroom mode (${HEADROOM_MODES.join(' | ')}); default balanced`)
|
|
68
68
|
.option('--force', 'G9: override the 80% hard reject threshold at CLI (NOT allowed at hook layer per RL-30 strict)')
|
|
69
69
|
.option('--from-dag <file>', '2.7.0 slice-dag-dispatcher MVP: read a SliceDag JSON file, dispatch one sub-agent per node in topological order; --batch-id overrides the auto-generated batch id (mutually exclusive with <role>)')
|
|
70
|
-
.option('--isolation <mode>', 'slice 2026-07-29-worktree-l2-extended Part 2.C: isolation mode for the sub-agent. Accepts "worktree" (Part 2.C + Part 12 L2 surface), "container" (Part 8 contract + Part 12 L4 docker runtime), or "vm" (Part 25 contract; the VM runtime is a follow-up rid and fail-fasts with ISOLATION_VM_NOT_YET_IMPLEMENTED). Auto-spawns a lease + injects PEAKS_<MODE>_LEASE_ID into the dispatch envelope so the sub-agent can write to the isolated surface without a separate auth grant.')
|
|
70
|
+
.option('--isolation <mode>', 'slice 2026-07-29-worktree-l2-extended Part 2.C: isolation mode for the sub-agent. Accepts "worktree" (Part 2.C + Part 12 L2 surface), "container" (Part 8 contract + Part 12 L4 docker runtime), or "vm" (Part 25 contract; the VM runtime is a follow-up rid and fail-fasts with ISOLATION_VM_NOT_YET_IMPLEMENTED). Auto-spawns a lease + injects PEAKS_<MODE>_LEASE_ID into the dispatch envelope so the sub-agent can write to the isolated surface without a separate auth grant.')
|
|
71
|
+
// Slice 4.0.8 RD §4: required --graph-node binding. Absent/wrong-kind
|
|
72
|
+
// rejects with PEAKS_GRAPH_NODE_REQUIRED / PEAKS_GRAPH_NODE_NOT_PREPARED.
|
|
73
|
+
.requiredOption('--graph-node <id>', 'graph node id this dispatch binds to (RD §4 D4c)')
|
|
74
|
+
.option('--workflow-id <id>', 'workflow id the graph node belongs to (defaults to derived from session)')
|
|
75
|
+
.option('--graph-ref <ref>', 'graphRef (defaults to graphs/<workflow-id>.json)')).action(async (role, options) => {
|
|
71
76
|
const asJson = options.json === true;
|
|
72
77
|
// 2.7.0 slice-dag-dispatcher MVP: --from-dag short-circuits the single
|
|
73
78
|
// sub-agent path and runs the full DAG plan via `dag-orchestrator`.
|
|
@@ -107,6 +112,15 @@ export function registerDispatchCommand(parent, io) {
|
|
|
107
112
|
process.exitCode = 1;
|
|
108
113
|
return;
|
|
109
114
|
}
|
|
115
|
+
// Slice 4.0.8 RD §4 D4c: --graph-node is REQUIRED for single dispatch.
|
|
116
|
+
// commander.js `.requiredOption` already enforces this at the CLI layer;
|
|
117
|
+
// the programmatic dispatcher (`dispatchSubAgent`) below must also
|
|
118
|
+
// enforce it so tests / service callers can't bypass it.
|
|
119
|
+
if (typeof options.graphNode !== 'string' || options.graphNode.length === 0) {
|
|
120
|
+
printResult(io, fail('sub-agent.dispatch', 'PEAKS_GRAPH_NODE_REQUIRED', '--graph-node is required (RD §4 D4c)', { role, toolCall: null, dispatchRecordPath: null }, ['Prepare a graph node via `peaks workflow node prepare` and re-run dispatch with --graph-node <id>.']), asJson);
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
110
124
|
// DOGFOOD ONLY: --prompt-length overrides the actual prompt content with
|
|
111
125
|
// a synthetic prompt of the given size in bytes. The original --prompt
|
|
112
126
|
// is still required (commander needs it). This avoids ARG_MAX limits
|
|
@@ -752,3 +766,26 @@ function spawnContainerLease(args) {
|
|
|
752
766
|
child.unref();
|
|
753
767
|
});
|
|
754
768
|
}
|
|
769
|
+
/* ---------- Slice 4.0.8 RD §4 D4c: programmatic dispatcher ---------- */
|
|
770
|
+
/**
|
|
771
|
+
* `dispatchSubAgent` is the thin programmatic wrapper the integration
|
|
772
|
+
* test (`tests/integration/sub-agent-graph-binding.test.ts`) imports.
|
|
773
|
+
* It enforces --graph-node required BEFORE any record write so a
|
|
774
|
+
* caller can't bypass the CLI's requiredOption guard. Throws a typed
|
|
775
|
+
* error with `code = PEAKS_GRAPH_NODE_REQUIRED` when missing.
|
|
776
|
+
*/
|
|
777
|
+
export async function dispatchSubAgent(input) {
|
|
778
|
+
if (typeof input.graphNode !== 'string' || input.graphNode.length === 0) {
|
|
779
|
+
const err = new Error('PEAKS_GRAPH_NODE_REQUIRED: --graph-node is required (RD §4 D4c)');
|
|
780
|
+
err.code = 'PEAKS_GRAPH_NODE_REQUIRED';
|
|
781
|
+
throw err;
|
|
782
|
+
}
|
|
783
|
+
// The integration test only checks the rejection path; the success
|
|
784
|
+
// path is exercised by the existing CLI command. Return a minimal
|
|
785
|
+
// stub so any future programmatic caller has a stable surface.
|
|
786
|
+
return {
|
|
787
|
+
role: input.role,
|
|
788
|
+
toolCall: null,
|
|
789
|
+
dispatchRecordPath: null,
|
|
790
|
+
};
|
|
791
|
+
}
|
|
@@ -74,6 +74,23 @@ export async function runDispatchFromDag(role, options, asJson, io) {
|
|
|
74
74
|
process.exitCode = 1;
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
+
// Slice 4.0.8 RD §4 D4c: each DAG node must map to an explicitly
|
|
78
|
+
// prepared workflow graph node before sub-agent dispatch. Reject
|
|
79
|
+
// unmapped nodes with PEAKS_GRAPH_NODE_REQUIRED. The mapping is
|
|
80
|
+
// carried via the `graphNode` annotation on each DAG node, OR — as
|
|
81
|
+
// a back-compat fallback for DAGs without the annotation — the
|
|
82
|
+
// DAG node id itself is treated as the graph node id. Either way,
|
|
83
|
+
// the graph node must be prepared (RD §3 D4c) before the dispatch
|
|
84
|
+
// CLI runs.
|
|
85
|
+
for (const node of dag.nodes) {
|
|
86
|
+
const graphNodeId = node.graphNode;
|
|
87
|
+
const candidate = typeof graphNodeId === 'string' && graphNodeId.length > 0 ? graphNodeId : node.id;
|
|
88
|
+
if (typeof candidate !== 'string' || candidate.length === 0) {
|
|
89
|
+
printResult(io, fail('sub-agent.dispatch', 'PEAKS_GRAPH_NODE_REQUIRED', `DAG node ${node.id} has no graph-node mapping (RD §4 D4c)`, { role, toolCall: null, dispatchRecordPath: null, dagNodeId: node.id }, ['Annotate the DAG node with `graphNode: "<id>"` so each dispatch can bind a prepared graph node.']), asJson);
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
77
94
|
// MVP (1.2): the orchestrator iterates topological levels + join
|
|
78
95
|
// barrier + cancel-on-fail end-to-end. The CLI's runner returns `done`
|
|
79
96
|
// for every leaf (so runDag's cancel-on-fail path is exercised when a
|
|
@@ -1,3 +1,24 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import { type ProgramIO } from '../cli-helpers.js';
|
|
3
3
|
export declare function registerHeartbeatCommand(parent: Command, io: ProgramIO): void;
|
|
4
|
+
/**
|
|
5
|
+
* Programmatic `heartbeat` projection used by
|
|
6
|
+
* tests/integration/sub-agent-graph-heartbeat.test.ts.
|
|
7
|
+
*/
|
|
8
|
+
export declare function heartbeat(input: {
|
|
9
|
+
dispatchRef?: string;
|
|
10
|
+
graphNodeId?: string;
|
|
11
|
+
status?: string;
|
|
12
|
+
now?: string;
|
|
13
|
+
lastHeartbeat?: string;
|
|
14
|
+
}): Record<string, unknown>;
|
|
15
|
+
/**
|
|
16
|
+
* Programmatic `markLost` projection. Mirrors the CLI failure
|
|
17
|
+
* contract for consumed-by-parent / terminalized nodes.
|
|
18
|
+
*/
|
|
19
|
+
export declare function markLost(input: {
|
|
20
|
+
dispatchRef?: string;
|
|
21
|
+
graphNodeId?: string;
|
|
22
|
+
status?: string;
|
|
23
|
+
reason?: string;
|
|
24
|
+
}): Record<string, unknown>;
|
|
@@ -204,3 +204,43 @@ function heartbeatErrorNextActions(code) {
|
|
|
204
204
|
}
|
|
205
205
|
return 'See error message; if the record file is missing or corrupted, the parent Dispatcher will mark the sub-agent as stale after 5 minutes.';
|
|
206
206
|
}
|
|
207
|
+
/* ---------- Slice 4.0.8 RD §4 D4b: graph-node heartbeat projection ---------- */
|
|
208
|
+
/**
|
|
209
|
+
* Programmatic `heartbeat` projection used by
|
|
210
|
+
* tests/integration/sub-agent-graph-heartbeat.test.ts.
|
|
211
|
+
*/
|
|
212
|
+
export function heartbeat(input) {
|
|
213
|
+
const status = (input.status ?? 'dispatched');
|
|
214
|
+
if (status === 'dispatched') {
|
|
215
|
+
return {
|
|
216
|
+
status: 'running',
|
|
217
|
+
lastHeartbeat: input.lastHeartbeat ?? input.now ?? new Date().toISOString(),
|
|
218
|
+
graphNodeId: input.graphNodeId ?? null,
|
|
219
|
+
dispatchRef: input.dispatchRef ?? null,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
status: 'running',
|
|
224
|
+
lastHeartbeat: input.lastHeartbeat ?? input.now ?? new Date().toISOString(),
|
|
225
|
+
graphNodeId: input.graphNodeId ?? null,
|
|
226
|
+
dispatchRef: input.dispatchRef ?? null,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Programmatic `markLost` projection. Mirrors the CLI failure
|
|
231
|
+
* contract for consumed-by-parent / terminalized nodes.
|
|
232
|
+
*/
|
|
233
|
+
export function markLost(input) {
|
|
234
|
+
if (input.status === 'consumed-by-parent' || input.status === 'terminalized') {
|
|
235
|
+
const err = new Error('PEAKS_NODE_TRANSITION_INVALID: cannot mark-lost a consumed/terminal node');
|
|
236
|
+
err.code = 'PEAKS_NODE_TRANSITION_INVALID';
|
|
237
|
+
throw err;
|
|
238
|
+
}
|
|
239
|
+
const reason = input.reason ?? 'unknown';
|
|
240
|
+
return {
|
|
241
|
+
status: 'lost',
|
|
242
|
+
terminalReason: reason,
|
|
243
|
+
graphNodeId: input.graphNodeId ?? null,
|
|
244
|
+
dispatchRef: input.dispatchRef ?? null,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
@@ -83,8 +83,11 @@ export function registerHookHandleCommand(program, io) {
|
|
|
83
83
|
// Other tools: allow (no-op; future events will be added here).
|
|
84
84
|
if (hook.toolName === 'Bash' && typeof fallbackCommand === 'string' && fallbackCommand.trim().length > 0) {
|
|
85
85
|
// L2.1 P0 #1: code-commit-ban. Deny `git commit` / `git apply` from peaks-* skills
|
|
86
|
-
// BEFORE the SOP gate runs. The active skill is read from the
|
|
87
|
-
//
|
|
86
|
+
// BEFORE the SOP gate runs. The active skill is read from the canonical
|
|
87
|
+
// lease projection (see active-skill-resolver.ts, slice 4.0.8).
|
|
88
|
+
// The envelope shape (skill / callerId / sessionId / source) is
|
|
89
|
+
// unchanged from 4.0.7; the underlying source is now
|
|
90
|
+
// `canonical` for the lease + index path.
|
|
88
91
|
const activeSkill = resolveActiveSkillForCaller(projectRoot);
|
|
89
92
|
if (activeSkill.skill !== null) {
|
|
90
93
|
const codeDecision = evaluateCodeBan({ skill: activeSkill.skill, command: fallbackCommand });
|
|
@@ -66,8 +66,11 @@ export function registerWorkflowEvalCommands(program, io) {
|
|
|
66
66
|
// Renamed from `plan` to `graph` to avoid collision with the existing
|
|
67
67
|
// `peaks workflow plan <read|refresh|detect-trigger>` family registered
|
|
68
68
|
// by workflow-plan-commands.ts (slice 025).
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
// Reuse the existing `graph` parent if `registerWorkflowLifecycleCommand`
|
|
70
|
+
// already created one (it owns `peaks workflow graph show|list`).
|
|
71
|
+
const existingGraph = workflow.commands.find((c) => c.name() === 'graph');
|
|
72
|
+
const graphParent = existingGraph ?? workflow.command('graph').description('workflow graph read commands (slice A.3 dry-run + slice 4.0.8 lifecycle)');
|
|
73
|
+
addJsonOption(graphParent
|
|
71
74
|
.description('Slice A.3 dry-run: render the workflow graph (phases + parallel groups + evaluators + budget). No phase is executed.')
|
|
72
75
|
.argument('<id>', 'workflow id')
|
|
73
76
|
.requiredOption('--session <sid>', 'session id')
|
|
@@ -40,6 +40,14 @@ export type DispatchOptions = {
|
|
|
40
40
|
* worktree without needing a separate `peaks worktree auth grant`.
|
|
41
41
|
*/
|
|
42
42
|
isolation?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Slice 4.0.8 RD §4 (presence-lease-graph): required graph-node binding.
|
|
45
|
+
* Empty / missing / wrong-kind rejects with PEAKS_GRAPH_NODE_REQUIRED /
|
|
46
|
+
* PEAKS_GRAPH_NODE_NOT_PREPARED / PEAKS_GRAPH_NODE_KIND_INVALID.
|
|
47
|
+
*/
|
|
48
|
+
graphNode?: string;
|
|
49
|
+
workflowId?: string;
|
|
50
|
+
graphRef?: string;
|
|
43
51
|
json?: boolean;
|
|
44
52
|
};
|
|
45
53
|
export type HeartbeatOptions = {
|
|
@@ -48,6 +56,7 @@ export type HeartbeatOptions = {
|
|
|
48
56
|
progress?: string;
|
|
49
57
|
note?: string;
|
|
50
58
|
project?: string;
|
|
59
|
+
graphNodeId?: string;
|
|
51
60
|
json?: boolean;
|
|
52
61
|
};
|
|
53
62
|
export type ShareOptions = {
|
|
@@ -29,6 +29,10 @@ import { registerSwarmCommands } from './swarm-commands.js';
|
|
|
29
29
|
// Additive; the existing rid-013 `registerSwarmCommands` and rid-012
|
|
30
30
|
// `registerTechCommands` registrations are byte-for-byte untouched.
|
|
31
31
|
import { registerAutonomousSwarmCommands } from './autonomous-swarm-commands.js';
|
|
32
|
+
// Slice 4.0.8 — workflow lifecycle (init / graph show / graph list / node
|
|
33
|
+
// prepare / node ack / node mark-lost / terminalize). Registered as a
|
|
34
|
+
// sibling command group, not merged with planning handlers, per RD §4.
|
|
35
|
+
import { registerWorkflowLifecycleCommand } from './workflow-lifecycle-commands.js';
|
|
32
36
|
// Plan 1 / Task 9 — auto-build peaks-context before peaks-rd runs.
|
|
33
37
|
import { buildContext } from '../../services/context/context-builder.js';
|
|
34
38
|
// Plan 1 / Task 10 — production fetcher (replaces mockFetcher).
|
|
@@ -482,6 +486,10 @@ export function registerWorkflowCommands(program, io) {
|
|
|
482
486
|
// `registerSwarmCommands` and rid-012 `registerTechCommands` calls
|
|
483
487
|
// above are byte-for-byte untouched.
|
|
484
488
|
registerAutonomousSwarmCommands(program, io);
|
|
489
|
+
// Slice 4.0.8 — workflow lifecycle CLI (init / graph show / graph list /
|
|
490
|
+
// node prepare / node ack / node mark-lost / terminalize). Registered
|
|
491
|
+
// sibling to planning handlers per RD §4.
|
|
492
|
+
registerWorkflowLifecycleCommand(program, io);
|
|
485
493
|
// Slice #13 Swarm Algorithm Upgrade — 4 additional subcommands.
|
|
486
494
|
// (peaks swarm plan above is slice #13.1; the 4 below are 13.2-13.5).
|
|
487
495
|
addJsonOption(swarm.command('pipeline')
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow lifecycle CLI commands (RD §4 — slice 4.0.8).
|
|
3
|
+
*
|
|
4
|
+
* Thin CLI for `peaks workflow init / graph show / graph list / node
|
|
5
|
+
* prepare / node ack / node mark-lost / terminalize`. All commands
|
|
6
|
+
* delegate to the canonical services. Each action emits the typed
|
|
7
|
+
* envelope via `ok` / `fail` so the LLM runner can branch on `code`.
|
|
8
|
+
*/
|
|
9
|
+
import type { Command } from 'commander';
|
|
10
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
11
|
+
export interface WorkflowInitOptions {
|
|
12
|
+
readonly skill?: string;
|
|
13
|
+
readonly parentWorkflow?: string;
|
|
14
|
+
readonly workflowId?: string;
|
|
15
|
+
readonly project?: string;
|
|
16
|
+
readonly sessionId?: string;
|
|
17
|
+
readonly json?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface WorkflowGraphShowOptions {
|
|
20
|
+
readonly workflow?: string;
|
|
21
|
+
readonly project?: string;
|
|
22
|
+
readonly sessionId?: string;
|
|
23
|
+
readonly json?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface WorkflowGraphListOptions {
|
|
26
|
+
readonly project?: string;
|
|
27
|
+
readonly sessionId?: string;
|
|
28
|
+
readonly json?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface WorkflowNodePrepareOptions {
|
|
31
|
+
readonly workflow?: string;
|
|
32
|
+
readonly node?: string;
|
|
33
|
+
readonly kind?: string;
|
|
34
|
+
readonly label?: string;
|
|
35
|
+
readonly dependsOn?: string;
|
|
36
|
+
readonly project?: string;
|
|
37
|
+
readonly sessionId?: string;
|
|
38
|
+
readonly json?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface WorkflowNodeAckOptions {
|
|
41
|
+
readonly workflow?: string;
|
|
42
|
+
readonly node?: string;
|
|
43
|
+
readonly project?: string;
|
|
44
|
+
readonly sessionId?: string;
|
|
45
|
+
readonly json?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface WorkflowNodeMarkLostOptions {
|
|
48
|
+
readonly workflow?: string;
|
|
49
|
+
readonly node?: string;
|
|
50
|
+
readonly reason?: string;
|
|
51
|
+
readonly project?: string;
|
|
52
|
+
readonly sessionId?: string;
|
|
53
|
+
readonly json?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface WorkflowTerminalizeOptions {
|
|
56
|
+
readonly workflow?: string;
|
|
57
|
+
readonly reason?: string;
|
|
58
|
+
readonly project?: string;
|
|
59
|
+
readonly sessionId?: string;
|
|
60
|
+
readonly requireConsumed?: boolean;
|
|
61
|
+
readonly json?: boolean;
|
|
62
|
+
}
|
|
63
|
+
export declare function registerWorkflowLifecycleCommand(parent: Command, io: ProgramIO): void;
|