@deftai/directive 0.107.0 → 0.108.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/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +75 -51
- package/dist/occupancy-grant.d.ts +18 -0
- package/dist/occupancy-grant.js +120 -0
- package/dist/occupancy-heartbeat.d.ts +8 -0
- package/dist/occupancy-heartbeat.js +62 -0
- package/dist/occupancy-release.d.ts +1 -0
- package/dist/occupancy-release.js +26 -2
- package/dist/occupancy-steal.d.ts +1 -0
- package/dist/occupancy-steal.js +32 -4
- package/dist/render-cli/prd-render-cli.js +6 -10
- package/dist/session-ready.d.ts +2 -0
- package/dist/session-ready.js +37 -5
- package/dist/session-start.d.ts +2 -0
- package/dist/session-start.js +39 -6
- package/dist/toolchain-check.d.ts +1 -0
- package/dist/toolchain-check.js +41 -2
- package/dist/verify-pr-closeout-attestable.d.ts +14 -0
- package/dist/verify-pr-closeout-attestable.js +96 -0
- package/dist/verify-subagent-alive.js +5 -1
- package/package.json +3 -3
package/dist/dispatch.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface DispatchIo {
|
|
|
10
10
|
writeErr: (text: string) => void;
|
|
11
11
|
}
|
|
12
12
|
/** CLI modules in packages/cli/src (excluding parity harnesses and bin/index). */
|
|
13
|
-
export declare const CLI_MODULE_VERBS: readonly ["agents-refresh", "cache", "check", "capacity-backfill", "capacity-show", "codebase-default-extractor", "codebase-map", "codebase-map-fresh", "codebase-projection-registry", "codebase-provider", "doctor", "install-upgrade", "install-uninstall", "migrate-preflight", "migrate-xbrief", "migrate-category-b", "framework-check-updates", "hook-dispatch", "umbrella-current-shape", "changelog-check", "change-init", "commit-lint", "coverage-hotspots", "policy", "authz", "escalation-cli", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "pr-watch", "pr-finish-loop", "directive-finish-loop", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "scope-lifecycle", "scope-record-approved-scope", "scm-sync-default", "lifecycle-event", "lifecycle-stats", "session-start", "session-ready", "occupancy-steal", "occupancy-release", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "triage-evaluate", "triage-help", "triage-queue", "triage-reconcile", "triage-refresh", "triage-scope", "triage-scope-drift", "triage-smoketest", "triage-subscribe", "triage-summary", "triage-welcome", "ts-check-lane", "vbrief-activate", "vbrief-build", "vbrief-preflight", "vbrief-reconcile", "vbrief-validate", "vbrief-validation", "xbrief-create", "xbrief-verify", "verify-branch", "verify-encoding", "verify-forward-coverage", "verify-test-boundary", "verify-scope-provenance", "verify-consumer-check-contract", "verify-hooks-installed", "verify-investigation", "verify-judgment-gates", "verify-no-task-runtime", "validate-links", "validate-strategy-output", "verify-biome-config", "verify-bridge-drift", "verify-capacity", "verify-contained-writes", "verify-telemetry-coverage", "verify-content-manifest", "verify-skill-external-fetch-gate", "verify-contract-drift", "verify-cursor-tier1", "verify-openclaw-tier1", "verify-go-freeze", "verify-scm-boundary", "verify-session-ritual", "verify-plan-sequence", "verify-stubs", "verify-xbrief-drift", "rule-ownership-lint", "verify-story-ready", "verify-review-monitor", "verify-l4-owner", "verify-subagent-alive", "review-monitor-register", "review-monitor-release", "verify-tools", "verify-wip-cap", "verify-orphan-active", "verify-lifecycle-visible", "verify-completed-tracked", "verify-completed-write-guard", "verify-literal-ac", "verify-ac", "verify-agents-md-budget", "verify-agents-md-advisory", "verify-eval-health-relocation", "verify-eval-triggers-relocation", "eval-health", "eval-run", "eval-report", "eval-triggers"];
|
|
13
|
+
export declare const CLI_MODULE_VERBS: readonly ["agents-refresh", "cache", "check", "capacity-backfill", "capacity-show", "codebase-default-extractor", "codebase-map", "codebase-map-fresh", "codebase-projection-registry", "codebase-provider", "doctor", "install-upgrade", "install-uninstall", "migrate-preflight", "migrate-xbrief", "migrate-category-b", "framework-check-updates", "hook-dispatch", "umbrella-current-shape", "changelog-check", "change-init", "commit-lint", "coverage-hotspots", "policy", "authz", "escalation-cli", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "pr-watch", "pr-finish-loop", "directive-finish-loop", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "scope-lifecycle", "scope-record-approved-scope", "scm-sync-default", "lifecycle-event", "lifecycle-stats", "session-start", "session-ready", "occupancy-steal", "occupancy-release", "occupancy-heartbeat", "occupancy-grant", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "triage-evaluate", "triage-help", "triage-queue", "triage-reconcile", "triage-refresh", "triage-scope", "triage-scope-drift", "triage-smoketest", "triage-subscribe", "triage-summary", "triage-welcome", "ts-check-lane", "vbrief-activate", "vbrief-build", "vbrief-preflight", "vbrief-reconcile", "vbrief-validate", "vbrief-validation", "xbrief-create", "xbrief-verify", "verify-branch", "verify-encoding", "verify-forward-coverage", "verify-test-boundary", "verify-scope-provenance", "verify-consumer-check-contract", "verify-hooks-installed", "verify-investigation", "verify-judgment-gates", "verify-no-task-runtime", "validate-links", "validate-strategy-output", "verify-biome-config", "verify-bridge-drift", "verify-capacity", "verify-contained-writes", "verify-telemetry-coverage", "verify-content-manifest", "verify-skill-external-fetch-gate", "verify-contract-drift", "verify-cursor-tier1", "verify-openclaw-tier1", "verify-go-freeze", "verify-scm-boundary", "verify-session-ritual", "verify-plan-sequence", "verify-stubs", "verify-xbrief-drift", "rule-ownership-lint", "verify-story-ready", "verify-review-monitor", "verify-l4-owner", "verify-subagent-alive", "review-monitor-register", "review-monitor-release", "verify-tools", "verify-wip-cap", "verify-orphan-active", "verify-pr-closeout-attestable", "verify-lifecycle-visible", "verify-completed-tracked", "verify-completed-write-guard", "verify-literal-ac", "verify-ac", "verify-agents-md-budget", "verify-agents-md-advisory", "verify-eval-health-relocation", "verify-eval-triggers-relocation", "eval-health", "eval-run", "eval-report", "eval-triggers"];
|
|
14
14
|
/** Core-only CLI entrypoints without a packages/cli wrapper. */
|
|
15
15
|
export declare const CORE_MODULE_VERBS: readonly ["scm", "scm-readiness", "github-auth-modes", "github-body", "issue-emit", "issue-ingest", "issue-sync-from-xbrief", "reconcile-issues", "swarm-launch", "swarm-complete-cohort", "swarm-finalize-cohort", "swarm-pre-dispatch", "swarm-readiness", "swarm-routing-verify", "swarm-routing-set", "swarm-verify-review-clean", "swarm-worktrees", "framework-commands", "pack-render", "packs-slice", "prd-render", "export-spec", "project-render", "roadmap-render", "rule-map", "spec-render", "spec-validate", "code-structure-validate", "pack-migrate-skills", "pack-migrate-rules", "pack-migrate-strategies", "pack-migrate-patterns", "pack-migrate-swarm-spec", "policy-set", "setup-ghx", "scope-undo", "scope-demote", "scope-decompose", "changelog-resolve-unreleased", "architecture-preflight-sor", "feedback-file", "value-readback", "product-signal", "freshness-report", "decision-write", "decision-list"];
|
|
16
16
|
/** Colon aliases for triage-actions (mirrors cli-router SUBCOMMAND_ROUTES). */
|
package/dist/dispatch.js
CHANGED
|
@@ -8,12 +8,11 @@ import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, readSync
|
|
|
8
8
|
import { homedir, tmpdir } from "node:os";
|
|
9
9
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
10
10
|
import { engineInfo, userConfig } from "@deftai/directive-core";
|
|
11
|
-
import { assertWriteTargetSafe } from "@deftai/directive-core/dist/fs/projection-containment.js";
|
|
12
11
|
import { parseInitArgv, runInitDepositCli } from "@deftai/directive-core/init-deposit";
|
|
13
12
|
import { appendAuditLog, disclosureLine, migrateLegacyPolicyKey, PLAN_POLICY_KEY, POLICY_AUDIT_NOOP_STDOUT, policyColonInvocation, policySetInvocation, projectDefinitionPath, resolvePolicy, resolveWipCap, setPolicy, stampChangedToken, } from "@deftai/directive-core/policy";
|
|
14
13
|
import { defaultWhich } from "@deftai/directive-core/scm";
|
|
15
14
|
import { KNOWN_SUBAGENT_BACKEND_IDS, probeSubagentBackends, resolveSwarmSubagentBackend, } from "@deftai/directive-core/swarm";
|
|
16
|
-
import {
|
|
15
|
+
import { withProjectDefinitionMutation, } from "@deftai/directive-core/vbrief-build";
|
|
17
16
|
const HANDLER_KEYS = [
|
|
18
17
|
"run",
|
|
19
18
|
"main",
|
|
@@ -76,6 +75,8 @@ export const CLI_MODULE_VERBS = [
|
|
|
76
75
|
"session-ready",
|
|
77
76
|
"occupancy-steal",
|
|
78
77
|
"occupancy-release",
|
|
78
|
+
"occupancy-heartbeat",
|
|
79
|
+
"occupancy-grant",
|
|
79
80
|
"plan-sequence",
|
|
80
81
|
"slice",
|
|
81
82
|
"subagent-monitor",
|
|
@@ -142,6 +143,7 @@ export const CLI_MODULE_VERBS = [
|
|
|
142
143
|
"verify-tools",
|
|
143
144
|
"verify-wip-cap",
|
|
144
145
|
"verify-orphan-active",
|
|
146
|
+
"verify-pr-closeout-attestable",
|
|
145
147
|
"verify-lifecycle-visible",
|
|
146
148
|
"verify-completed-tracked",
|
|
147
149
|
"verify-completed-write-guard",
|
|
@@ -287,6 +289,7 @@ export const VERB_ALIASES = {
|
|
|
287
289
|
"verify:vbrief-conformance": "vbrief-validate",
|
|
288
290
|
"verify:wip-cap": "verify-wip-cap",
|
|
289
291
|
"verify:orphan-active": "verify-orphan-active",
|
|
292
|
+
"verify:pr-closeout-attestable": "verify-pr-closeout-attestable",
|
|
290
293
|
"verify:lifecycle-visible": "verify-lifecycle-visible",
|
|
291
294
|
"verify:completed-tracked": "verify-completed-tracked",
|
|
292
295
|
"verify:completed-write-guard": "verify-completed-write-guard",
|
|
@@ -369,6 +372,8 @@ export const VERB_ALIASES = {
|
|
|
369
372
|
"session:ready": "session-ready",
|
|
370
373
|
"occupancy:steal": "occupancy-steal",
|
|
371
374
|
"occupancy:release": "occupancy-release",
|
|
375
|
+
"occupancy:heartbeat": "occupancy-heartbeat",
|
|
376
|
+
"occupancy:grant": "occupancy-grant",
|
|
372
377
|
"session:end": "occupancy-release",
|
|
373
378
|
...FRESHNESS_COLON_ALIASES,
|
|
374
379
|
"lifecycle:event": "lifecycle-event",
|
|
@@ -2104,25 +2109,26 @@ function parsePolicySetArgs(argv) {
|
|
|
2104
2109
|
}
|
|
2105
2110
|
return args;
|
|
2106
2111
|
}
|
|
2107
|
-
/**
|
|
2108
|
-
|
|
2109
|
-
|
|
2112
|
+
/**
|
|
2113
|
+
* Load PROJECT-DEFINITION for an in-place typed-field write (mirrors the
|
|
2114
|
+
* .setdefault chain). Reads the artifact the mutation lock captured (#3796) so
|
|
2115
|
+
* these CLI writers can no longer resolve, read, and write a PROJECT-DEFINITION
|
|
2116
|
+
* outside the shared mutation lock.
|
|
2117
|
+
*/
|
|
2118
|
+
function loadProjectDefinitionForWrite(mutation) {
|
|
2119
|
+
const path = mutation.artifactPath;
|
|
2110
2120
|
if (!existsSync(path)) {
|
|
2111
|
-
throw new PolicySetError(`PROJECT-DEFINITION not found at ${
|
|
2121
|
+
throw new PolicySetError(`PROJECT-DEFINITION not found at ${mutation.artifactLabel}`, "not-found");
|
|
2112
2122
|
}
|
|
2113
|
-
let
|
|
2123
|
+
let data;
|
|
2114
2124
|
try {
|
|
2115
|
-
|
|
2125
|
+
// The shared loader rejects unreadable, malformed, and non-object top-level
|
|
2126
|
+
// payloads; every one of those is a config error for the CLI writers.
|
|
2127
|
+
data = mutation.load();
|
|
2116
2128
|
}
|
|
2117
2129
|
catch (err) {
|
|
2118
|
-
throw new PolicySetError(
|
|
2130
|
+
throw new PolicySetError(err instanceof Error ? err.message : String(err), "config");
|
|
2119
2131
|
}
|
|
2120
|
-
// JSON.parse can yield a non-object top level (null / array / scalar) without
|
|
2121
|
-
// throwing; reject it before the .plan/.policy property chain dereferences it.
|
|
2122
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
2123
|
-
throw new PolicySetError(`PROJECT-DEFINITION at ${path} is not a JSON object`, "config");
|
|
2124
|
-
}
|
|
2125
|
-
const data = parsed;
|
|
2126
2132
|
let plan = data.plan;
|
|
2127
2133
|
if (plan === undefined) {
|
|
2128
2134
|
plan = {};
|
|
@@ -2141,45 +2147,47 @@ function loadProjectDefinitionForWrite(projectRoot) {
|
|
|
2141
2147
|
if (typeof policy !== "object" || policy === null || Array.isArray(policy)) {
|
|
2142
2148
|
throw new PolicySetError("plan.policy is not an object", "config");
|
|
2143
2149
|
}
|
|
2144
|
-
return {
|
|
2150
|
+
return { data, policyBlock: policy, legacyMigrated };
|
|
2145
2151
|
}
|
|
2146
2152
|
/** Write plan.policy.wipCap in place + append the audit row (mirrors set_wip_cap). */
|
|
2147
2153
|
function writeWipCap(projectRoot, cap, actor, note) {
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2154
|
+
return withProjectDefinitionMutation(projectRoot, (mutation) => {
|
|
2155
|
+
const { data, policyBlock, legacyMigrated } = loadProjectDefinitionForWrite(mutation);
|
|
2156
|
+
const previous = policyBlock.wipCap;
|
|
2157
|
+
policyBlock.wipCap = cap;
|
|
2158
|
+
const changed = previous !== cap || legacyMigrated;
|
|
2159
|
+
const parts = [`actor=${actor}`, `wipCap=${cap}`, `previous=${pyRepr(previous)}`];
|
|
2160
|
+
if (note)
|
|
2161
|
+
parts.push(`note=${sanitizeNote(note)}`);
|
|
2162
|
+
const auditEntry = stampChangedToken(parts.join(" "), changed);
|
|
2163
|
+
if (changed) {
|
|
2164
|
+
mutation.persist(data);
|
|
2165
|
+
}
|
|
2166
|
+
appendAuditLog(projectRoot, auditEntry, changed);
|
|
2167
|
+
return { changed, auditEntry };
|
|
2168
|
+
});
|
|
2162
2169
|
}
|
|
2163
2170
|
/** Write plan.policy.swarmSubagentBackend in place + append the audit row. */
|
|
2164
2171
|
function writeSubagentBackend(projectRoot, backendId, actor, note) {
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2172
|
+
return withProjectDefinitionMutation(projectRoot, (mutation) => {
|
|
2173
|
+
const { data, policyBlock, legacyMigrated } = loadProjectDefinitionForWrite(mutation);
|
|
2174
|
+
const previous = policyBlock.swarmSubagentBackend;
|
|
2175
|
+
policyBlock.swarmSubagentBackend = backendId;
|
|
2176
|
+
const changed = previous !== backendId || legacyMigrated;
|
|
2177
|
+
const parts = [
|
|
2178
|
+
`actor=${actor}`,
|
|
2179
|
+
`swarmSubagentBackend=${backendId}`,
|
|
2180
|
+
`previous=${pyRepr(previous)}`,
|
|
2181
|
+
];
|
|
2182
|
+
if (note)
|
|
2183
|
+
parts.push(`note=${sanitizeNote(note)}`);
|
|
2184
|
+
const auditEntry = stampChangedToken(parts.join(" "), changed);
|
|
2185
|
+
if (changed) {
|
|
2186
|
+
mutation.persist(data);
|
|
2187
|
+
}
|
|
2188
|
+
appendAuditLog(projectRoot, auditEntry, changed);
|
|
2189
|
+
return { changed, auditEntry };
|
|
2190
|
+
});
|
|
2183
2191
|
}
|
|
2184
2192
|
/** Serialise the probe output for `subagent-backends --format json`. */
|
|
2185
2193
|
function subagentBackendsToJson(backends) {
|
|
@@ -2617,19 +2625,30 @@ const CURATED_HELP_GROUPS = [
|
|
|
2617
2625
|
{
|
|
2618
2626
|
title: "Session & ritual",
|
|
2619
2627
|
commands: [
|
|
2620
|
-
{
|
|
2628
|
+
{
|
|
2629
|
+
name: "session:start",
|
|
2630
|
+
summary: "Claim occupancy and record ritual state for one session owner",
|
|
2631
|
+
},
|
|
2621
2632
|
{
|
|
2622
2633
|
name: "session:ready",
|
|
2623
2634
|
summary: "One-shot recovery to gated write-ready (session + ritual + cache)",
|
|
2624
2635
|
},
|
|
2625
2636
|
{
|
|
2626
2637
|
name: "occupancy:steal",
|
|
2627
|
-
summary: "
|
|
2638
|
+
summary: "Replace only the live lease; use session:start --steal to align ritual",
|
|
2628
2639
|
},
|
|
2629
2640
|
{
|
|
2630
2641
|
name: "occupancy:release",
|
|
2631
2642
|
summary: "Release this worktree occupancy lease (owner live, or expired residue)",
|
|
2632
2643
|
},
|
|
2644
|
+
{
|
|
2645
|
+
name: "occupancy:heartbeat",
|
|
2646
|
+
summary: "Refresh your own live lease during long quiet stretches (never claims)",
|
|
2647
|
+
},
|
|
2648
|
+
{
|
|
2649
|
+
name: "occupancy:grant",
|
|
2650
|
+
summary: "Admit a dispatched child to your lease for writes (--revoke withdraws)",
|
|
2651
|
+
},
|
|
2633
2652
|
{
|
|
2634
2653
|
name: "session:end",
|
|
2635
2654
|
summary: "End this mutation session by releasing occupancy (same as occupancy:release)",
|
|
@@ -2795,6 +2814,9 @@ export async function dispatch(argv, io = defaultIo()) {
|
|
|
2795
2814
|
const planSequenceSubcommand = verb !== undefined ? PLAN_SEQUENCE_ALIAS_SUBCOMMANDS[verb] : undefined;
|
|
2796
2815
|
const productSignalSubcommand = verb !== undefined ? PRODUCT_SIGNAL_ALIAS_SUBCOMMANDS[verb] : undefined;
|
|
2797
2816
|
const freshnessSubcommand = verb !== undefined ? FRESHNESS_ALIAS_SUBCOMMANDS[verb] : undefined;
|
|
2817
|
+
const vbriefValidateSubcommand = verb === "verify:vbrief-conformance" && canonical === "vbrief-validate"
|
|
2818
|
+
? "conformance"
|
|
2819
|
+
: undefined;
|
|
2798
2820
|
const handlerArgv = canonical === "framework-commands" && verb !== undefined && verb !== canonical
|
|
2799
2821
|
? [verb, ...rest]
|
|
2800
2822
|
: triageSubcommand !== undefined && canonical === "triage-actions"
|
|
@@ -2811,7 +2833,9 @@ export async function dispatch(argv, io = defaultIo()) {
|
|
|
2811
2833
|
? [productSignalSubcommand, ...rest]
|
|
2812
2834
|
: freshnessSubcommand !== undefined && canonical === "freshness-report"
|
|
2813
2835
|
? [freshnessSubcommand, ...rest]
|
|
2814
|
-
:
|
|
2836
|
+
: vbriefValidateSubcommand !== undefined
|
|
2837
|
+
? [vbriefValidateSubcommand, ...rest]
|
|
2838
|
+
: rest;
|
|
2815
2839
|
return await invokeHandler(handler, handlerArgv);
|
|
2816
2840
|
}
|
|
2817
2841
|
catch (err) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type OccupancyJoinProtocol } from "@deftai/directive-core/session";
|
|
3
|
+
export interface GrantArgs {
|
|
4
|
+
projectRoot: string;
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
childSessionId?: string;
|
|
7
|
+
role?: string;
|
|
8
|
+
worktree?: string;
|
|
9
|
+
ttlMinutes?: number;
|
|
10
|
+
host?: string;
|
|
11
|
+
address?: string;
|
|
12
|
+
joinProtocol?: OccupancyJoinProtocol;
|
|
13
|
+
revoke: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function parseArgs(argv: readonly string[]): GrantArgs;
|
|
17
|
+
export declare function run(argv: readonly string[]): number;
|
|
18
|
+
//# sourceMappingURL=occupancy-grant.d.ts.map
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { grantOccupancyMembership, OCCUPANCY_JOIN_PROTOCOLS, revokeOccupancyMembership, } from "@deftai/directive-core/session";
|
|
4
|
+
const VALUE_FLAGS = [
|
|
5
|
+
"--project-root",
|
|
6
|
+
"--session-id",
|
|
7
|
+
"--child-session-id",
|
|
8
|
+
"--role",
|
|
9
|
+
"--worktree",
|
|
10
|
+
"--ttl-minutes",
|
|
11
|
+
"--host",
|
|
12
|
+
"--address",
|
|
13
|
+
"--join-protocol",
|
|
14
|
+
];
|
|
15
|
+
function readValue(argv, index, flag) {
|
|
16
|
+
const arg = argv[index] ?? "";
|
|
17
|
+
const inline = `${flag}=`;
|
|
18
|
+
const raw = arg.startsWith(inline) ? arg.slice(inline.length) : argv[index + 1];
|
|
19
|
+
if (raw === undefined || raw.startsWith("--")) {
|
|
20
|
+
return { error: `argument ${flag}: expected one argument` };
|
|
21
|
+
}
|
|
22
|
+
const value = raw.trim();
|
|
23
|
+
if (value.length === 0) {
|
|
24
|
+
return { error: `argument ${flag}: expected a non-empty value` };
|
|
25
|
+
}
|
|
26
|
+
return { value, next: arg.startsWith(inline) ? index : index + 1 };
|
|
27
|
+
}
|
|
28
|
+
export function parseArgs(argv) {
|
|
29
|
+
const parsed = { projectRoot: ".", revoke: false };
|
|
30
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
31
|
+
const arg = argv[i] ?? "";
|
|
32
|
+
if (arg === "--revoke")
|
|
33
|
+
continue;
|
|
34
|
+
const flag = VALUE_FLAGS.find((name) => arg === name || arg.startsWith(`${name}=`));
|
|
35
|
+
if (flag === undefined) {
|
|
36
|
+
return {
|
|
37
|
+
...parsed,
|
|
38
|
+
revoke: argv.includes("--revoke"),
|
|
39
|
+
error: `unrecognized argument: ${arg}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const read = readValue(argv, i, flag);
|
|
43
|
+
if ("error" in read)
|
|
44
|
+
return { ...parsed, revoke: argv.includes("--revoke"), error: read.error };
|
|
45
|
+
i = read.next;
|
|
46
|
+
switch (flag) {
|
|
47
|
+
case "--project-root":
|
|
48
|
+
parsed.projectRoot = read.value;
|
|
49
|
+
break;
|
|
50
|
+
case "--session-id":
|
|
51
|
+
parsed.sessionId = read.value;
|
|
52
|
+
break;
|
|
53
|
+
case "--child-session-id":
|
|
54
|
+
parsed.childSessionId = read.value;
|
|
55
|
+
break;
|
|
56
|
+
case "--role":
|
|
57
|
+
parsed.role = read.value;
|
|
58
|
+
break;
|
|
59
|
+
case "--worktree":
|
|
60
|
+
parsed.worktree = read.value;
|
|
61
|
+
break;
|
|
62
|
+
case "--host":
|
|
63
|
+
parsed.host = read.value;
|
|
64
|
+
break;
|
|
65
|
+
case "--address":
|
|
66
|
+
parsed.address = read.value;
|
|
67
|
+
break;
|
|
68
|
+
case "--ttl-minutes": {
|
|
69
|
+
const minutes = Number(read.value);
|
|
70
|
+
if (!Number.isFinite(minutes) || minutes <= 0) {
|
|
71
|
+
return {
|
|
72
|
+
...parsed,
|
|
73
|
+
revoke: argv.includes("--revoke"),
|
|
74
|
+
error: "argument --ttl-minutes: expected a positive number of minutes",
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
parsed.ttlMinutes = minutes;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case "--join-protocol": {
|
|
81
|
+
if (!OCCUPANCY_JOIN_PROTOCOLS.includes(read.value)) {
|
|
82
|
+
return {
|
|
83
|
+
...parsed,
|
|
84
|
+
revoke: argv.includes("--revoke"),
|
|
85
|
+
error: `argument --join-protocol: expected one of ${OCCUPANCY_JOIN_PROTOCOLS.join(", ")}`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
parsed.joinProtocol = read.value;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { ...parsed, revoke: argv.includes("--revoke") };
|
|
94
|
+
}
|
|
95
|
+
export function run(argv) {
|
|
96
|
+
const args = parseArgs(argv);
|
|
97
|
+
if (args.error !== undefined) {
|
|
98
|
+
process.stderr.write(`occupancy:grant: ${args.error}\n`);
|
|
99
|
+
return 2;
|
|
100
|
+
}
|
|
101
|
+
const projectRoot = resolve(args.projectRoot);
|
|
102
|
+
const input = {
|
|
103
|
+
sessionId: args.sessionId,
|
|
104
|
+
childSessionId: args.childSessionId,
|
|
105
|
+
role: args.role,
|
|
106
|
+
worktreePath: args.worktree,
|
|
107
|
+
ttlMs: args.ttlMinutes === undefined ? undefined : args.ttlMinutes * 60 * 1000,
|
|
108
|
+
host: args.host,
|
|
109
|
+
address: args.address,
|
|
110
|
+
joinProtocol: args.joinProtocol,
|
|
111
|
+
env: process.env,
|
|
112
|
+
};
|
|
113
|
+
const result = args.revoke
|
|
114
|
+
? revokeOccupancyMembership(projectRoot, input)
|
|
115
|
+
: grantOccupancyMembership(projectRoot, input);
|
|
116
|
+
const sink = result.code === 0 ? process.stdout : process.stderr;
|
|
117
|
+
sink.write(`${result.message}\n`);
|
|
118
|
+
return result.code;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=occupancy-grant.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export declare function parseArgs(argv: readonly string[]): {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
sessionId?: string;
|
|
5
|
+
error?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function run(argv: readonly string[]): number;
|
|
8
|
+
//# sourceMappingURL=occupancy-heartbeat.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { heartbeatOccupancy } from "@deftai/directive-core/session";
|
|
4
|
+
export function parseArgs(argv) {
|
|
5
|
+
const parsed = { projectRoot: "." };
|
|
6
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
7
|
+
const arg = argv[i];
|
|
8
|
+
if (arg === "--project-root") {
|
|
9
|
+
const value = argv[i + 1];
|
|
10
|
+
if (value === undefined || value.startsWith("--")) {
|
|
11
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
12
|
+
}
|
|
13
|
+
parsed.projectRoot = value;
|
|
14
|
+
i += 1;
|
|
15
|
+
}
|
|
16
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
17
|
+
const value = arg.slice("--project-root=".length);
|
|
18
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
19
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
20
|
+
}
|
|
21
|
+
parsed.projectRoot = value;
|
|
22
|
+
}
|
|
23
|
+
else if (arg === "--session-id") {
|
|
24
|
+
const value = argv[i + 1];
|
|
25
|
+
if (value === undefined || value.startsWith("--")) {
|
|
26
|
+
return { ...parsed, error: "argument --session-id: expected one argument" };
|
|
27
|
+
}
|
|
28
|
+
const sessionId = value.trim();
|
|
29
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
30
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
31
|
+
}
|
|
32
|
+
parsed.sessionId = sessionId;
|
|
33
|
+
i += 1;
|
|
34
|
+
}
|
|
35
|
+
else if (arg?.startsWith("--session-id=")) {
|
|
36
|
+
const sessionId = arg.slice("--session-id=".length).trim();
|
|
37
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
38
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
39
|
+
}
|
|
40
|
+
parsed.sessionId = sessionId;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return parsed;
|
|
47
|
+
}
|
|
48
|
+
export function run(argv) {
|
|
49
|
+
const args = parseArgs(argv);
|
|
50
|
+
if (args.error !== undefined) {
|
|
51
|
+
process.stderr.write(`occupancy:heartbeat: ${args.error}\n`);
|
|
52
|
+
return 2;
|
|
53
|
+
}
|
|
54
|
+
const result = heartbeatOccupancy(resolve(args.projectRoot), {
|
|
55
|
+
sessionId: args.sessionId,
|
|
56
|
+
env: process.env,
|
|
57
|
+
});
|
|
58
|
+
const sink = result.code === 0 ? process.stdout : process.stderr;
|
|
59
|
+
sink.write(`${result.message}\n`);
|
|
60
|
+
return result.code;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=occupancy-heartbeat.js.map
|
|
@@ -7,14 +7,37 @@ export function parseArgs(argv) {
|
|
|
7
7
|
const arg = argv[i];
|
|
8
8
|
if (arg === "--project-root") {
|
|
9
9
|
const value = argv[i + 1];
|
|
10
|
-
if (value === undefined) {
|
|
10
|
+
if (value === undefined || value.startsWith("--")) {
|
|
11
11
|
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
12
12
|
}
|
|
13
13
|
parsed.projectRoot = value;
|
|
14
14
|
i += 1;
|
|
15
15
|
}
|
|
16
16
|
else if (arg?.startsWith("--project-root=")) {
|
|
17
|
-
|
|
17
|
+
const value = arg.slice("--project-root=".length);
|
|
18
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
19
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
20
|
+
}
|
|
21
|
+
parsed.projectRoot = value;
|
|
22
|
+
}
|
|
23
|
+
else if (arg === "--session-id") {
|
|
24
|
+
const value = argv[i + 1];
|
|
25
|
+
if (value === undefined || value.startsWith("--")) {
|
|
26
|
+
return { ...parsed, error: "argument --session-id: expected one argument" };
|
|
27
|
+
}
|
|
28
|
+
const sessionId = value.trim();
|
|
29
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
30
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
31
|
+
}
|
|
32
|
+
parsed.sessionId = sessionId;
|
|
33
|
+
i += 1;
|
|
34
|
+
}
|
|
35
|
+
else if (arg?.startsWith("--session-id=")) {
|
|
36
|
+
const sessionId = arg.slice("--session-id=".length).trim();
|
|
37
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
38
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
39
|
+
}
|
|
40
|
+
parsed.sessionId = sessionId;
|
|
18
41
|
}
|
|
19
42
|
else {
|
|
20
43
|
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
@@ -29,6 +52,7 @@ export function run(argv) {
|
|
|
29
52
|
return 2;
|
|
30
53
|
}
|
|
31
54
|
const result = releaseOccupancy(resolve(args.projectRoot), {
|
|
55
|
+
sessionId: args.sessionId,
|
|
32
56
|
env: process.env,
|
|
33
57
|
});
|
|
34
58
|
const sink = result.code === 0 ? process.stdout : process.stderr;
|
package/dist/occupancy-steal.js
CHANGED
|
@@ -10,25 +10,52 @@ export function parseArgs(argv) {
|
|
|
10
10
|
}
|
|
11
11
|
else if (arg === "--occupant") {
|
|
12
12
|
const value = argv[i + 1];
|
|
13
|
-
if (value === undefined) {
|
|
13
|
+
if (value === undefined || value.startsWith("--")) {
|
|
14
14
|
return { ...parsed, error: "argument --occupant: expected one argument" };
|
|
15
15
|
}
|
|
16
16
|
parsed.occupant = value;
|
|
17
17
|
i += 1;
|
|
18
18
|
}
|
|
19
19
|
else if (arg?.startsWith("--occupant=")) {
|
|
20
|
-
|
|
20
|
+
const value = arg.slice("--occupant=".length);
|
|
21
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
22
|
+
return { ...parsed, error: "argument --occupant: expected one argument" };
|
|
23
|
+
}
|
|
24
|
+
parsed.occupant = value;
|
|
21
25
|
}
|
|
22
26
|
else if (arg === "--project-root") {
|
|
23
27
|
const value = argv[i + 1];
|
|
24
|
-
if (value === undefined) {
|
|
28
|
+
if (value === undefined || value.startsWith("--")) {
|
|
25
29
|
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
26
30
|
}
|
|
27
31
|
parsed.projectRoot = value;
|
|
28
32
|
i += 1;
|
|
29
33
|
}
|
|
30
34
|
else if (arg?.startsWith("--project-root=")) {
|
|
31
|
-
|
|
35
|
+
const value = arg.slice("--project-root=".length);
|
|
36
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
37
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
38
|
+
}
|
|
39
|
+
parsed.projectRoot = value;
|
|
40
|
+
}
|
|
41
|
+
else if (arg === "--session-id") {
|
|
42
|
+
const value = argv[i + 1];
|
|
43
|
+
if (value === undefined || value.startsWith("--")) {
|
|
44
|
+
return { ...parsed, error: "argument --session-id: expected one argument" };
|
|
45
|
+
}
|
|
46
|
+
const sessionId = value.trim();
|
|
47
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
48
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
49
|
+
}
|
|
50
|
+
parsed.sessionId = sessionId;
|
|
51
|
+
i += 1;
|
|
52
|
+
}
|
|
53
|
+
else if (arg?.startsWith("--session-id=")) {
|
|
54
|
+
const sessionId = arg.slice("--session-id=".length).trim();
|
|
55
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
56
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
57
|
+
}
|
|
58
|
+
parsed.sessionId = sessionId;
|
|
32
59
|
}
|
|
33
60
|
else {
|
|
34
61
|
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
@@ -43,6 +70,7 @@ export function run(argv) {
|
|
|
43
70
|
return 2;
|
|
44
71
|
}
|
|
45
72
|
const result = stealOccupancy(resolve(args.projectRoot), {
|
|
73
|
+
sessionId: args.sessionId,
|
|
46
74
|
confirm: args.confirm,
|
|
47
75
|
occupant: args.occupant ?? undefined,
|
|
48
76
|
env: process.env,
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Thin CLI wrapper for prd-render (mirrors ``scripts/prd_render.py``).
|
|
3
3
|
*
|
|
4
|
-
* Supports `--project-root <dir>` to resolve
|
|
5
|
-
* resolver (#2132
|
|
6
|
-
* trees and falling back to `vbrief/specification.vbrief.json` on legacy trees.
|
|
4
|
+
* Supports `--project-root <dir>` to resolve full-spec or greenfield authority
|
|
5
|
+
* through the shared authority resolver (#2132 / #3598).
|
|
7
6
|
* When `--spec` is explicitly provided it takes precedence over `--project-root`.
|
|
8
7
|
* Direct `--spec` / `--output` / `--force` flags are still accepted unchanged.
|
|
9
8
|
*/
|
|
10
|
-
import { layout } from "@deftai/directive-core";
|
|
11
9
|
import { parsePrdArgv, prdRenderMain } from "@deftai/directive-core/render";
|
|
12
10
|
function parsePrdRenderCliArgv(argv) {
|
|
13
11
|
const remaining = [];
|
|
@@ -30,12 +28,10 @@ function parsePrdRenderCliArgv(argv) {
|
|
|
30
28
|
export function runPrdRenderCli(argv) {
|
|
31
29
|
const { projectRoot, remaining } = parsePrdRenderCliArgv(argv);
|
|
32
30
|
const parsedArgs = parsePrdArgv(remaining);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: projectRoot
|
|
36
|
-
|
|
37
|
-
: undefined;
|
|
38
|
-
prdRenderMain({ ...parsedArgs, spec });
|
|
31
|
+
prdRenderMain({
|
|
32
|
+
...parsedArgs,
|
|
33
|
+
projectRoot: parsedArgs.spec === undefined ? projectRoot : undefined,
|
|
34
|
+
});
|
|
39
35
|
return 0;
|
|
40
36
|
}
|
|
41
37
|
//# sourceMappingURL=prd-render-cli.js.map
|
package/dist/session-ready.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export interface ParsedSessionReadyArgs {
|
|
|
4
4
|
emitJson: boolean;
|
|
5
5
|
withNetwork: boolean;
|
|
6
6
|
repo: string | null;
|
|
7
|
+
/** #3611: explicit lifecycle owner injected by a host hook bridge. */
|
|
8
|
+
sessionId: string | null;
|
|
7
9
|
error?: string;
|
|
8
10
|
}
|
|
9
11
|
/** Parse session:ready CLI args. */
|
package/dist/session-ready.js
CHANGED
|
@@ -15,6 +15,7 @@ export function parseArgs(argv) {
|
|
|
15
15
|
emitJson: false,
|
|
16
16
|
withNetwork: false,
|
|
17
17
|
repo: null,
|
|
18
|
+
sessionId: null,
|
|
18
19
|
};
|
|
19
20
|
for (let i = 0; i < argv.length; i += 1) {
|
|
20
21
|
const arg = argv[i];
|
|
@@ -33,13 +34,13 @@ export function parseArgs(argv) {
|
|
|
33
34
|
if (arg === "--help" || arg === "-h") {
|
|
34
35
|
return {
|
|
35
36
|
...parsed,
|
|
36
|
-
error: "usage: session:ready [--project-root <path>] [--repo OWNER/NAME] [--with-network] [--json]\n" +
|
|
37
|
+
error: "usage: session:ready [--project-root <path>] [--repo OWNER/NAME] [--session-id <id>] [--with-network] [--json]\n" +
|
|
37
38
|
" One-shot recovery: session:start (if needed) + gated ritual + cache recovery (#2993).",
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
if (arg === "--project-root") {
|
|
41
42
|
const value = argv[i + 1];
|
|
42
|
-
if (value === undefined) {
|
|
43
|
+
if (value === undefined || value.startsWith("--")) {
|
|
43
44
|
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
44
45
|
}
|
|
45
46
|
parsed.projectRoot = value;
|
|
@@ -47,12 +48,37 @@ export function parseArgs(argv) {
|
|
|
47
48
|
continue;
|
|
48
49
|
}
|
|
49
50
|
if (arg.startsWith("--project-root=")) {
|
|
50
|
-
|
|
51
|
+
const value = arg.slice("--project-root=".length);
|
|
52
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
53
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
54
|
+
}
|
|
55
|
+
parsed.projectRoot = value;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (arg === "--session-id") {
|
|
59
|
+
const value = argv[i + 1];
|
|
60
|
+
if (value === undefined || value.startsWith("--")) {
|
|
61
|
+
return { ...parsed, error: "argument --session-id: expected one argument" };
|
|
62
|
+
}
|
|
63
|
+
const sessionId = value.trim();
|
|
64
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
65
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
66
|
+
}
|
|
67
|
+
parsed.sessionId = sessionId;
|
|
68
|
+
i += 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (arg.startsWith("--session-id=")) {
|
|
72
|
+
const sessionId = arg.slice("--session-id=".length).trim();
|
|
73
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
74
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
75
|
+
}
|
|
76
|
+
parsed.sessionId = sessionId;
|
|
51
77
|
continue;
|
|
52
78
|
}
|
|
53
79
|
if (arg === "--repo") {
|
|
54
80
|
const value = argv[i + 1];
|
|
55
|
-
if (value === undefined) {
|
|
81
|
+
if (value === undefined || value.startsWith("--")) {
|
|
56
82
|
return { ...parsed, error: "argument --repo: expected one argument" };
|
|
57
83
|
}
|
|
58
84
|
parsed.repo = value;
|
|
@@ -60,7 +86,11 @@ export function parseArgs(argv) {
|
|
|
60
86
|
continue;
|
|
61
87
|
}
|
|
62
88
|
if (arg.startsWith("--repo=")) {
|
|
63
|
-
|
|
89
|
+
const value = arg.slice("--repo=".length);
|
|
90
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
91
|
+
return { ...parsed, error: "argument --repo: expected one argument" };
|
|
92
|
+
}
|
|
93
|
+
parsed.repo = value;
|
|
64
94
|
continue;
|
|
65
95
|
}
|
|
66
96
|
if (arg.startsWith("-")) {
|
|
@@ -80,6 +110,7 @@ export function run(argv = process.argv.slice(2)) {
|
|
|
80
110
|
const projectRoot = resolve(args.projectRoot);
|
|
81
111
|
const result = runSessionReady(projectRoot, {
|
|
82
112
|
repo: args.repo,
|
|
113
|
+
sessionId: args.sessionId ?? undefined,
|
|
83
114
|
sessionStartOptions: {
|
|
84
115
|
allowOptionalNetwork: args.withNetwork ? true : undefined,
|
|
85
116
|
writeHistory: false,
|
|
@@ -89,6 +120,7 @@ export function run(argv = process.argv.slice(2)) {
|
|
|
89
120
|
process.stdout.write(`${JSON.stringify({
|
|
90
121
|
ready: result.code === 0,
|
|
91
122
|
exit_code: result.code,
|
|
123
|
+
session_id: result.sessionId,
|
|
92
124
|
path: result.path,
|
|
93
125
|
message: result.message,
|
|
94
126
|
steps: result.steps,
|
package/dist/session-start.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export interface ParsedSessionStartArgs {
|
|
|
36
36
|
steal: boolean;
|
|
37
37
|
confirm: boolean;
|
|
38
38
|
occupant: string | null;
|
|
39
|
+
/** #3611: explicit lifecycle owner injected by a host hook bridge. */
|
|
40
|
+
sessionId: string | null;
|
|
39
41
|
error?: string;
|
|
40
42
|
}
|
|
41
43
|
/** Parse session:start CLI args, mirroring scripts/session_start.py. */
|
package/dist/session-start.js
CHANGED
|
@@ -34,6 +34,7 @@ export function parseArgs(argv) {
|
|
|
34
34
|
steal: false,
|
|
35
35
|
confirm: false,
|
|
36
36
|
occupant: null,
|
|
37
|
+
sessionId: null,
|
|
37
38
|
};
|
|
38
39
|
const dialInputs = {};
|
|
39
40
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -82,25 +83,33 @@ export function parseArgs(argv) {
|
|
|
82
83
|
}
|
|
83
84
|
else if (arg === "--project-root") {
|
|
84
85
|
const value = argv[i + 1];
|
|
85
|
-
if (value === undefined) {
|
|
86
|
+
if (value === undefined || value.startsWith("--")) {
|
|
86
87
|
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
87
88
|
}
|
|
88
89
|
parsed.projectRoot = value;
|
|
89
90
|
i += 1;
|
|
90
91
|
}
|
|
91
92
|
else if (arg?.startsWith("--project-root=")) {
|
|
92
|
-
|
|
93
|
+
const value = arg.slice("--project-root=".length);
|
|
94
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
95
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
96
|
+
}
|
|
97
|
+
parsed.projectRoot = value;
|
|
93
98
|
}
|
|
94
99
|
else if (arg === "--defer") {
|
|
95
100
|
const value = argv[i + 1];
|
|
96
|
-
if (value === undefined) {
|
|
101
|
+
if (value === undefined || value.startsWith("--")) {
|
|
97
102
|
return { ...parsed, error: "argument --defer: expected one argument" };
|
|
98
103
|
}
|
|
99
104
|
parsed.deferValues.push(value);
|
|
100
105
|
i += 1;
|
|
101
106
|
}
|
|
102
107
|
else if (arg?.startsWith("--defer=")) {
|
|
103
|
-
|
|
108
|
+
const value = arg.slice("--defer=".length);
|
|
109
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
110
|
+
return { ...parsed, error: "argument --defer: expected one argument" };
|
|
111
|
+
}
|
|
112
|
+
parsed.deferValues.push(value);
|
|
104
113
|
}
|
|
105
114
|
else if (arg === "--task-size" || arg === "--ceremony-task-size") {
|
|
106
115
|
const value = argv[i + 1];
|
|
@@ -282,16 +291,39 @@ export function parseArgs(argv) {
|
|
|
282
291
|
else if (arg === "--confirm") {
|
|
283
292
|
parsed.confirm = true;
|
|
284
293
|
}
|
|
294
|
+
else if (arg === "--session-id") {
|
|
295
|
+
const value = argv[i + 1];
|
|
296
|
+
if (value === undefined || value.startsWith("--")) {
|
|
297
|
+
return { ...parsed, error: "argument --session-id: expected one argument" };
|
|
298
|
+
}
|
|
299
|
+
const sessionId = value.trim();
|
|
300
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
301
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
302
|
+
}
|
|
303
|
+
parsed.sessionId = sessionId;
|
|
304
|
+
i += 1;
|
|
305
|
+
}
|
|
306
|
+
else if (arg?.startsWith("--session-id=")) {
|
|
307
|
+
const sessionId = arg.slice("--session-id=".length).trim();
|
|
308
|
+
if (sessionId.length === 0 || sessionId.startsWith("--")) {
|
|
309
|
+
return { ...parsed, error: "argument --session-id: expected a non-empty value" };
|
|
310
|
+
}
|
|
311
|
+
parsed.sessionId = sessionId;
|
|
312
|
+
}
|
|
285
313
|
else if (arg === "--occupant") {
|
|
286
314
|
const value = argv[i + 1];
|
|
287
|
-
if (value === undefined) {
|
|
315
|
+
if (value === undefined || value.startsWith("--")) {
|
|
288
316
|
return { ...parsed, error: "argument --occupant: expected one argument" };
|
|
289
317
|
}
|
|
290
318
|
parsed.occupant = value;
|
|
291
319
|
i += 1;
|
|
292
320
|
}
|
|
293
321
|
else if (arg?.startsWith("--occupant=")) {
|
|
294
|
-
|
|
322
|
+
const value = arg.slice("--occupant=".length);
|
|
323
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
324
|
+
return { ...parsed, error: "argument --occupant: expected one argument" };
|
|
325
|
+
}
|
|
326
|
+
parsed.occupant = value;
|
|
295
327
|
}
|
|
296
328
|
else {
|
|
297
329
|
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
@@ -358,6 +390,7 @@ export function run(argv) {
|
|
|
358
390
|
steal: args.steal ? true : undefined,
|
|
359
391
|
confirm: args.confirm ? true : undefined,
|
|
360
392
|
occupant: args.occupant ?? undefined,
|
|
393
|
+
sessionId: args.sessionId ?? undefined,
|
|
361
394
|
...(args.ceremonyDepthOverride !== null
|
|
362
395
|
? {
|
|
363
396
|
ceremonyDial: selectCeremonyDepth({
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { type CommandRunner } from "@deftai/directive-core/verify-env";
|
|
3
3
|
export interface ToolchainCheckRunOptions {
|
|
4
4
|
readonly runner?: CommandRunner;
|
|
5
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
5
6
|
}
|
|
6
7
|
export declare function run(argv?: readonly string[], options?: ToolchainCheckRunOptions): number;
|
|
7
8
|
//# sourceMappingURL=toolchain-check.d.ts.map
|
package/dist/toolchain-check.js
CHANGED
|
@@ -1,9 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { runToolchainCheck } from "@deftai/directive-core/verify-env";
|
|
4
|
+
function parseArgs(argv) {
|
|
5
|
+
let consumer = false;
|
|
6
|
+
let projectRoot = process.cwd();
|
|
7
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
8
|
+
const arg = argv[index] ?? "";
|
|
9
|
+
if (arg === "--consumer") {
|
|
10
|
+
consumer = true;
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (arg === "--project-root") {
|
|
14
|
+
const value = argv[index + 1];
|
|
15
|
+
if (value === undefined || value.trim() === "" || value.startsWith("-")) {
|
|
16
|
+
return { consumer, projectRoot, error: "--project-root requires a path" };
|
|
17
|
+
}
|
|
18
|
+
projectRoot = value;
|
|
19
|
+
index += 1;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (arg.startsWith("--project-root=")) {
|
|
23
|
+
const value = arg.slice("--project-root=".length);
|
|
24
|
+
if (value.trim() === "") {
|
|
25
|
+
return { consumer, projectRoot, error: "--project-root requires a path" };
|
|
26
|
+
}
|
|
27
|
+
projectRoot = value;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
return { consumer, projectRoot, error: `unrecognized argument: ${arg}` };
|
|
31
|
+
}
|
|
32
|
+
return { consumer, projectRoot };
|
|
33
|
+
}
|
|
4
34
|
export function run(argv = process.argv.slice(2), options = {}) {
|
|
5
|
-
const
|
|
6
|
-
|
|
35
|
+
const parsed = parseArgs(argv);
|
|
36
|
+
if (parsed.error !== undefined) {
|
|
37
|
+
process.stderr.write(`toolchain-check: ${parsed.error}\n`);
|
|
38
|
+
process.stderr.write("Usage: deft toolchain-check [--consumer] [--project-root <path>]\n");
|
|
39
|
+
return 2;
|
|
40
|
+
}
|
|
41
|
+
const result = runToolchainCheck(options.runner, {
|
|
42
|
+
consumer: parsed.consumer,
|
|
43
|
+
projectRoot: parsed.projectRoot,
|
|
44
|
+
env: options.env ?? process.env,
|
|
45
|
+
});
|
|
7
46
|
for (const line of result.lines) {
|
|
8
47
|
process.stdout.write(`${line}\n`);
|
|
9
48
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
repo: string | null;
|
|
5
|
+
pr: number | null;
|
|
6
|
+
quiet: boolean;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Parse verify-pr-closeout-attestable CLI args. */
|
|
10
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
11
|
+
/** Run the gate and return the process exit code. */
|
|
12
|
+
export declare function run(argv: string[]): number;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=verify-pr-closeout-attestable.d.ts.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { evaluate } from "@deftai/directive-core/pr-closeout-attestable";
|
|
5
|
+
function parsePrNumber(raw) {
|
|
6
|
+
const trimmed = raw.startsWith("#") ? raw.slice(1) : raw;
|
|
7
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const value = Number(trimmed);
|
|
11
|
+
return Number.isInteger(value) && value > 0 ? value : null;
|
|
12
|
+
}
|
|
13
|
+
/** Parse verify-pr-closeout-attestable CLI args. */
|
|
14
|
+
export function parseArgs(argv) {
|
|
15
|
+
const parsed = { projectRoot: ".", repo: null, pr: null, quiet: false };
|
|
16
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
17
|
+
const arg = argv[i];
|
|
18
|
+
if (arg === "--quiet") {
|
|
19
|
+
parsed.quiet = true;
|
|
20
|
+
}
|
|
21
|
+
else if (arg === "--project-root") {
|
|
22
|
+
const value = argv[i + 1];
|
|
23
|
+
if (value === undefined) {
|
|
24
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
25
|
+
}
|
|
26
|
+
parsed.projectRoot = value;
|
|
27
|
+
i += 1;
|
|
28
|
+
}
|
|
29
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
30
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
31
|
+
}
|
|
32
|
+
else if (arg === "--repo") {
|
|
33
|
+
const value = argv[i + 1];
|
|
34
|
+
if (value === undefined) {
|
|
35
|
+
return { ...parsed, error: "argument --repo: expected one argument" };
|
|
36
|
+
}
|
|
37
|
+
parsed.repo = value;
|
|
38
|
+
i += 1;
|
|
39
|
+
}
|
|
40
|
+
else if (arg?.startsWith("--repo=")) {
|
|
41
|
+
parsed.repo = arg.slice("--repo=".length);
|
|
42
|
+
}
|
|
43
|
+
else if (arg === "--pr") {
|
|
44
|
+
const value = argv[i + 1];
|
|
45
|
+
if (value === undefined) {
|
|
46
|
+
return { ...parsed, error: "argument --pr: expected one argument" };
|
|
47
|
+
}
|
|
48
|
+
const pr = parsePrNumber(value);
|
|
49
|
+
if (pr === null) {
|
|
50
|
+
return { ...parsed, error: `argument --pr: expected a positive integer, got ${value}` };
|
|
51
|
+
}
|
|
52
|
+
parsed.pr = pr;
|
|
53
|
+
i += 1;
|
|
54
|
+
}
|
|
55
|
+
else if (arg?.startsWith("--pr=")) {
|
|
56
|
+
const value = arg.slice("--pr=".length);
|
|
57
|
+
const pr = parsePrNumber(value);
|
|
58
|
+
if (pr === null) {
|
|
59
|
+
return { ...parsed, error: `argument --pr: expected a positive integer, got ${value}` };
|
|
60
|
+
}
|
|
61
|
+
parsed.pr = pr;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (parsed.pr === null) {
|
|
68
|
+
return { ...parsed, error: "argument --pr is required" };
|
|
69
|
+
}
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
/** Run the gate and return the process exit code. */
|
|
73
|
+
export function run(argv) {
|
|
74
|
+
const args = parseArgs(argv);
|
|
75
|
+
if (args.error !== undefined) {
|
|
76
|
+
process.stderr.write(`verify_pr_closeout_attestable: ${args.error}\n`);
|
|
77
|
+
return 2;
|
|
78
|
+
}
|
|
79
|
+
const result = evaluate(resolve(args.projectRoot), args.pr, {
|
|
80
|
+
repo: args.repo,
|
|
81
|
+
quiet: args.quiet,
|
|
82
|
+
});
|
|
83
|
+
if (result.message.length > 0) {
|
|
84
|
+
if (result.stream === "stdout") {
|
|
85
|
+
process.stdout.write(`${result.message}\n`);
|
|
86
|
+
}
|
|
87
|
+
else if (result.stream === "stderr") {
|
|
88
|
+
process.stderr.write(`${result.message}\n`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return result.code;
|
|
92
|
+
}
|
|
93
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
94
|
+
process.exit(run(process.argv.slice(2)));
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=verify-pr-closeout-attestable.js.map
|
|
@@ -166,7 +166,11 @@ export function evaluateSubagentAliveGate(args, cwd = process.cwd()) {
|
|
|
166
166
|
}
|
|
167
167
|
lines.push("");
|
|
168
168
|
lines.push("REDISPATCH_OK: host-reported running + missing/STALE heartbeat authorizes takeover.");
|
|
169
|
-
lines.push("
|
|
169
|
+
lines.push("A killed worker's delivery attempt stays running until cancelled.");
|
|
170
|
+
lines.push("Takeover: task swarm:pre-dispatch -- --scope-id <id> --target-id <worktree> --action cancel");
|
|
171
|
+
lines.push("then: task swarm:pre-dispatch -- --scope-id <id> --target-id <worktree>");
|
|
172
|
+
lines.push("If verify:session-ritual --tier=gated fails, run session:start --rearm --session-id=<same> first.");
|
|
173
|
+
lines.push("Do not wait on Cursor false-alive state. Do not spawn while DENY_DUPLICATE_ACTIVE.");
|
|
170
174
|
return {
|
|
171
175
|
exitCode: EXIT_STALE,
|
|
172
176
|
redispatchOk: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftai/directive",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.108.0",
|
|
4
4
|
"description": "Directive CLI — npm install path for the Deft Directive framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://deftai.github.io/directive/",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"provenance": true
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@deftai/directive-core": "^0.
|
|
38
|
-
"@deftai/directive-content": "^0.
|
|
37
|
+
"@deftai/directive-core": "^0.108.0",
|
|
38
|
+
"@deftai/directive-content": "^0.108.0"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc -b"
|