@deftai/directive 0.106.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/authz.js +1 -1
- package/dist/cli-router/route-argv.js +3 -0
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +90 -51
- package/dist/human-presence-mint.d.ts +6 -6
- package/dist/human-presence-mint.js +7 -6
- 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 +8 -0
- package/dist/occupancy-release.js +62 -0
- 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/triage-actions.js +2 -3
- package/dist/triage-evaluate.d.ts +14 -0
- package/dist/triage-evaluate.js +153 -0
- package/dist/verify-completed-tracked.js +34 -1
- package/dist/verify-completed-write-guard.d.ts +13 -0
- package/dist/verify-completed-write-guard.js +72 -0
- 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/authz.js
CHANGED
|
@@ -225,7 +225,7 @@ function helpText() {
|
|
|
225
225
|
" (grant / uat-start / uat-suspend / revoke) — no TTY, --confirm, or phrase path.",
|
|
226
226
|
" Self-approval under UAT is impossible by construction. Mint grants BEFORE uat-start.",
|
|
227
227
|
"Outside UAT, mutating verbs require multi-factor human presence (#3110):",
|
|
228
|
-
" - Interactive TTY (stdin+stdout) + controlling terminal (/dev/tty
|
|
228
|
+
" - Interactive TTY (stdin+stdout) + controlling terminal (/dev/tty|\\\\.\\CONIN$)",
|
|
229
229
|
" - Explicit --confirm (argv flag alone never enough)",
|
|
230
230
|
" - Typed phrase 'mint' on the controlling TTY (PTY+--confirm alone never enough)",
|
|
231
231
|
" - Known agent/CI env markers always refuse (fail-closed).",
|
|
@@ -197,6 +197,9 @@ function routeNamespaceVerb(ns, verb, rest) {
|
|
|
197
197
|
return { kind: "dispatch", argv: [verifyStem, ...rest] };
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
+
if (ns === "scm" && verb === "issue:design-critique-chip") {
|
|
201
|
+
return { kind: "dispatch", argv: ["scm", "issue", "design-critique-chip", ...rest] };
|
|
202
|
+
}
|
|
200
203
|
if (ns === "issue" && verb === "ingest") {
|
|
201
204
|
return { kind: "dispatch", argv: ["issue-ingest", ...rest] };
|
|
202
205
|
}
|
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", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "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-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",
|
|
@@ -75,6 +74,9 @@ export const CLI_MODULE_VERBS = [
|
|
|
75
74
|
"session-start",
|
|
76
75
|
"session-ready",
|
|
77
76
|
"occupancy-steal",
|
|
77
|
+
"occupancy-release",
|
|
78
|
+
"occupancy-heartbeat",
|
|
79
|
+
"occupancy-grant",
|
|
78
80
|
"plan-sequence",
|
|
79
81
|
"slice",
|
|
80
82
|
"subagent-monitor",
|
|
@@ -83,6 +85,7 @@ export const CLI_MODULE_VERBS = [
|
|
|
83
85
|
"triage-bootstrap",
|
|
84
86
|
"triage-bulk",
|
|
85
87
|
"triage-classify",
|
|
88
|
+
"triage-evaluate",
|
|
86
89
|
"triage-help",
|
|
87
90
|
"triage-queue",
|
|
88
91
|
"triage-reconcile",
|
|
@@ -140,8 +143,10 @@ export const CLI_MODULE_VERBS = [
|
|
|
140
143
|
"verify-tools",
|
|
141
144
|
"verify-wip-cap",
|
|
142
145
|
"verify-orphan-active",
|
|
146
|
+
"verify-pr-closeout-attestable",
|
|
143
147
|
"verify-lifecycle-visible",
|
|
144
148
|
"verify-completed-tracked",
|
|
149
|
+
"verify-completed-write-guard",
|
|
145
150
|
"verify-literal-ac",
|
|
146
151
|
"verify-ac",
|
|
147
152
|
"verify-agents-md-budget",
|
|
@@ -284,8 +289,10 @@ export const VERB_ALIASES = {
|
|
|
284
289
|
"verify:vbrief-conformance": "vbrief-validate",
|
|
285
290
|
"verify:wip-cap": "verify-wip-cap",
|
|
286
291
|
"verify:orphan-active": "verify-orphan-active",
|
|
292
|
+
"verify:pr-closeout-attestable": "verify-pr-closeout-attestable",
|
|
287
293
|
"verify:lifecycle-visible": "verify-lifecycle-visible",
|
|
288
294
|
"verify:completed-tracked": "verify-completed-tracked",
|
|
295
|
+
"verify:completed-write-guard": "verify-completed-write-guard",
|
|
289
296
|
"verify:literal-ac": "verify-literal-ac",
|
|
290
297
|
"verify:literal-acceptance": "verify-literal-ac",
|
|
291
298
|
"verify:ac": "verify-ac",
|
|
@@ -346,6 +353,7 @@ export const VERB_ALIASES = {
|
|
|
346
353
|
"triage:bootstrap": "triage-bootstrap",
|
|
347
354
|
"triage:summary": "triage-summary",
|
|
348
355
|
"triage:queue": "triage-queue",
|
|
356
|
+
"triage:evaluate": "triage-evaluate",
|
|
349
357
|
"triage:scope": "triage-scope",
|
|
350
358
|
...TRIAGE_ACTION_COLON_ALIASES,
|
|
351
359
|
...POLICY_ACTION_COLON_ALIASES,
|
|
@@ -363,6 +371,10 @@ export const VERB_ALIASES = {
|
|
|
363
371
|
"session:start": "session-start",
|
|
364
372
|
"session:ready": "session-ready",
|
|
365
373
|
"occupancy:steal": "occupancy-steal",
|
|
374
|
+
"occupancy:release": "occupancy-release",
|
|
375
|
+
"occupancy:heartbeat": "occupancy-heartbeat",
|
|
376
|
+
"occupancy:grant": "occupancy-grant",
|
|
377
|
+
"session:end": "occupancy-release",
|
|
366
378
|
...FRESHNESS_COLON_ALIASES,
|
|
367
379
|
"lifecycle:event": "lifecycle-event",
|
|
368
380
|
"lifecycle:stats": "lifecycle-stats",
|
|
@@ -2097,25 +2109,26 @@ function parsePolicySetArgs(argv) {
|
|
|
2097
2109
|
}
|
|
2098
2110
|
return args;
|
|
2099
2111
|
}
|
|
2100
|
-
/**
|
|
2101
|
-
|
|
2102
|
-
|
|
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;
|
|
2103
2120
|
if (!existsSync(path)) {
|
|
2104
|
-
throw new PolicySetError(`PROJECT-DEFINITION not found at ${
|
|
2121
|
+
throw new PolicySetError(`PROJECT-DEFINITION not found at ${mutation.artifactLabel}`, "not-found");
|
|
2105
2122
|
}
|
|
2106
|
-
let
|
|
2123
|
+
let data;
|
|
2107
2124
|
try {
|
|
2108
|
-
|
|
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();
|
|
2109
2128
|
}
|
|
2110
2129
|
catch (err) {
|
|
2111
|
-
throw new PolicySetError(
|
|
2112
|
-
}
|
|
2113
|
-
// JSON.parse can yield a non-object top level (null / array / scalar) without
|
|
2114
|
-
// throwing; reject it before the .plan/.policy property chain dereferences it.
|
|
2115
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
2116
|
-
throw new PolicySetError(`PROJECT-DEFINITION at ${path} is not a JSON object`, "config");
|
|
2130
|
+
throw new PolicySetError(err instanceof Error ? err.message : String(err), "config");
|
|
2117
2131
|
}
|
|
2118
|
-
const data = parsed;
|
|
2119
2132
|
let plan = data.plan;
|
|
2120
2133
|
if (plan === undefined) {
|
|
2121
2134
|
plan = {};
|
|
@@ -2134,45 +2147,47 @@ function loadProjectDefinitionForWrite(projectRoot) {
|
|
|
2134
2147
|
if (typeof policy !== "object" || policy === null || Array.isArray(policy)) {
|
|
2135
2148
|
throw new PolicySetError("plan.policy is not an object", "config");
|
|
2136
2149
|
}
|
|
2137
|
-
return {
|
|
2150
|
+
return { data, policyBlock: policy, legacyMigrated };
|
|
2138
2151
|
}
|
|
2139
2152
|
/** Write plan.policy.wipCap in place + append the audit row (mirrors set_wip_cap). */
|
|
2140
2153
|
function writeWipCap(projectRoot, cap, actor, note) {
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
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
|
+
});
|
|
2155
2169
|
}
|
|
2156
2170
|
/** Write plan.policy.swarmSubagentBackend in place + append the audit row. */
|
|
2157
2171
|
function writeSubagentBackend(projectRoot, backendId, actor, note) {
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
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
|
+
});
|
|
2176
2191
|
}
|
|
2177
2192
|
/** Serialise the probe output for `subagent-backends --format json`. */
|
|
2178
2193
|
function subagentBackendsToJson(backends) {
|
|
@@ -2610,14 +2625,33 @@ const CURATED_HELP_GROUPS = [
|
|
|
2610
2625
|
{
|
|
2611
2626
|
title: "Session & ritual",
|
|
2612
2627
|
commands: [
|
|
2613
|
-
{
|
|
2628
|
+
{
|
|
2629
|
+
name: "session:start",
|
|
2630
|
+
summary: "Claim occupancy and record ritual state for one session owner",
|
|
2631
|
+
},
|
|
2614
2632
|
{
|
|
2615
2633
|
name: "session:ready",
|
|
2616
2634
|
summary: "One-shot recovery to gated write-ready (session + ritual + cache)",
|
|
2617
2635
|
},
|
|
2618
2636
|
{
|
|
2619
2637
|
name: "occupancy:steal",
|
|
2620
|
-
summary: "
|
|
2638
|
+
summary: "Replace only the live lease; use session:start --steal to align ritual",
|
|
2639
|
+
},
|
|
2640
|
+
{
|
|
2641
|
+
name: "occupancy:release",
|
|
2642
|
+
summary: "Release this worktree occupancy lease (owner live, or expired residue)",
|
|
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
|
+
},
|
|
2652
|
+
{
|
|
2653
|
+
name: "session:end",
|
|
2654
|
+
summary: "End this mutation session by releasing occupancy (same as occupancy:release)",
|
|
2621
2655
|
},
|
|
2622
2656
|
{
|
|
2623
2657
|
name: "freshness:report",
|
|
@@ -2780,6 +2814,9 @@ export async function dispatch(argv, io = defaultIo()) {
|
|
|
2780
2814
|
const planSequenceSubcommand = verb !== undefined ? PLAN_SEQUENCE_ALIAS_SUBCOMMANDS[verb] : undefined;
|
|
2781
2815
|
const productSignalSubcommand = verb !== undefined ? PRODUCT_SIGNAL_ALIAS_SUBCOMMANDS[verb] : undefined;
|
|
2782
2816
|
const freshnessSubcommand = verb !== undefined ? FRESHNESS_ALIAS_SUBCOMMANDS[verb] : undefined;
|
|
2817
|
+
const vbriefValidateSubcommand = verb === "verify:vbrief-conformance" && canonical === "vbrief-validate"
|
|
2818
|
+
? "conformance"
|
|
2819
|
+
: undefined;
|
|
2783
2820
|
const handlerArgv = canonical === "framework-commands" && verb !== undefined && verb !== canonical
|
|
2784
2821
|
? [verb, ...rest]
|
|
2785
2822
|
: triageSubcommand !== undefined && canonical === "triage-actions"
|
|
@@ -2796,7 +2833,9 @@ export async function dispatch(argv, io = defaultIo()) {
|
|
|
2796
2833
|
? [productSignalSubcommand, ...rest]
|
|
2797
2834
|
: freshnessSubcommand !== undefined && canonical === "freshness-report"
|
|
2798
2835
|
? [freshnessSubcommand, ...rest]
|
|
2799
|
-
:
|
|
2836
|
+
: vbriefValidateSubcommand !== undefined
|
|
2837
|
+
? [vbriefValidateSubcommand, ...rest]
|
|
2838
|
+
: rest;
|
|
2800
2839
|
return await invokeHandler(handler, handlerArgv);
|
|
2801
2840
|
}
|
|
2802
2841
|
catch (err) {
|
|
@@ -16,7 +16,7 @@ export interface HumanPresenceMintSeams {
|
|
|
16
16
|
/** Environ for agent-shell marker detection (default: process.env). */
|
|
17
17
|
readonly environ?: NodeJS.ProcessEnv;
|
|
18
18
|
/**
|
|
19
|
-
* True when a controlling terminal device is available (`/dev/tty` or
|
|
19
|
+
* True when a controlling terminal device is available (`/dev/tty` or `\\.\CONIN$`).
|
|
20
20
|
* Default: open/close the platform controlling terminal (fail-closed on error).
|
|
21
21
|
*/
|
|
22
22
|
readonly hasControllingTerminal?: () => boolean;
|
|
@@ -27,13 +27,13 @@ export interface HumanPresenceMintSeams {
|
|
|
27
27
|
readonly readInteractiveConfirm?: () => string | null;
|
|
28
28
|
}
|
|
29
29
|
export declare function looksLikeAgentShell(environ: NodeJS.ProcessEnv): boolean;
|
|
30
|
-
/** Platform controlling-terminal path (
|
|
30
|
+
/** Platform controlling-terminal path (`\\.\CONIN$` on win32, `/dev/tty` elsewhere). */
|
|
31
31
|
export declare function controllingTerminalPath(platform?: NodeJS.Platform): string;
|
|
32
32
|
/**
|
|
33
|
-
* Open flag for the platform controlling-terminal device (#3596).
|
|
33
|
+
* Open flag for the platform controlling-terminal device (#3596 leftover).
|
|
34
34
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
35
|
+
* Win32 stays `r+` so the probe and phrase-read share one flag. The leftover
|
|
36
|
+
* path is the Windows device-namespace CONIN$ string, not bare CONIN$.
|
|
37
37
|
*/
|
|
38
38
|
export declare function controllingTerminalOpenFlag(platform?: NodeJS.Platform): "r" | "r+";
|
|
39
39
|
export declare function resolveHumanPresenceMintSeams(seams?: HumanPresenceMintSeams): Required<HumanPresenceMintSeams>;
|
|
@@ -52,7 +52,7 @@ export declare function refuseMintWhileUatActive(verb: string, projectRoot: stri
|
|
|
52
52
|
* Multi-factor human-presence gate (applies only when UAT lease is inactive):
|
|
53
53
|
* 1. No known agent/CI env markers
|
|
54
54
|
* 2. Interactive TTY (stdin + stdout isTTY)
|
|
55
|
-
* 3. Controlling terminal device present (`/dev/tty` /
|
|
55
|
+
* 3. Controlling terminal device present (`/dev/tty` / `\\.\CONIN$`)
|
|
56
56
|
* 4. Explicit argv `--confirm` (flag alone never enough)
|
|
57
57
|
* 5. Interactive typed phrase `mint` (argv --confirm alone never enough even on PTY)
|
|
58
58
|
*
|
|
@@ -67,15 +67,16 @@ export function looksLikeAgentShell(environ) {
|
|
|
67
67
|
function defaultIsTty() {
|
|
68
68
|
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
69
69
|
}
|
|
70
|
-
/** Platform controlling-terminal path (
|
|
70
|
+
/** Platform controlling-terminal path (`\\.\CONIN$` on win32, `/dev/tty` elsewhere). */
|
|
71
71
|
export function controllingTerminalPath(platform = process.platform) {
|
|
72
|
-
|
|
72
|
+
// Real-console diagnostic on #3596: bare CONIN$ and CON ENOENT; device-namespace path opens.
|
|
73
|
+
return platform === "win32" ? "\\\\.\\CONIN$" : "/dev/tty";
|
|
73
74
|
}
|
|
74
75
|
/**
|
|
75
|
-
* Open flag for the platform controlling-terminal device (#3596).
|
|
76
|
+
* Open flag for the platform controlling-terminal device (#3596 leftover).
|
|
76
77
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
78
|
+
* Win32 stays `r+` so the probe and phrase-read share one flag. The leftover
|
|
79
|
+
* path is the Windows device-namespace CONIN$ string, not bare CONIN$.
|
|
79
80
|
*/
|
|
80
81
|
export function controllingTerminalOpenFlag(platform = process.platform) {
|
|
81
82
|
return platform === "win32" ? "r+" : "r";
|
|
@@ -153,7 +154,7 @@ export function refuseMintWhileUatActive(verb, projectRoot) {
|
|
|
153
154
|
* Multi-factor human-presence gate (applies only when UAT lease is inactive):
|
|
154
155
|
* 1. No known agent/CI env markers
|
|
155
156
|
* 2. Interactive TTY (stdin + stdout isTTY)
|
|
156
|
-
* 3. Controlling terminal device present (`/dev/tty` /
|
|
157
|
+
* 3. Controlling terminal device present (`/dev/tty` / `\\.\CONIN$`)
|
|
157
158
|
* 4. Explicit argv `--confirm` (flag alone never enough)
|
|
158
159
|
* 5. Interactive typed phrase `mint` (argv --confirm alone never enough even on PTY)
|
|
159
160
|
*
|
|
@@ -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
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { releaseOccupancy } 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:release: ${args.error}\n`);
|
|
52
|
+
return 2;
|
|
53
|
+
}
|
|
54
|
+
const result = releaseOccupancy(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-release.js.map
|