@deftai/directive 0.104.0 → 0.106.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.d.ts +4 -29
- package/dist/authz.js +16 -181
- package/dist/cli-router/route-argv.js +1 -0
- package/dist/dispatch.d.ts +7 -1
- package/dist/dispatch.js +56 -20
- package/dist/human-presence-mint.d.ts +70 -0
- package/dist/human-presence-mint.js +203 -0
- package/dist/occupancy-steal.d.ts +9 -0
- package/dist/occupancy-steal.js +54 -0
- package/dist/plan-sequence.d.ts +10 -0
- package/dist/plan-sequence.js +3 -1
- package/dist/policy.d.ts +3 -2
- package/dist/policy.js +52 -7
- package/dist/preflight-cache.d.ts +2 -0
- package/dist/preflight-cache.js +7 -0
- package/dist/scm-sync-default.d.ts +34 -0
- package/dist/scm-sync-default.js +210 -0
- package/dist/scope-record-approved-scope.d.ts +6 -1
- package/dist/scope-record-approved-scope.js +72 -24
- package/dist/session-start.d.ts +4 -0
- package/dist/session-start.js +23 -0
- package/dist/triage-actions.js +2 -0
- package/dist/triage-queue.js +4 -1
- package/dist/verify-ac.d.ts +2 -0
- package/dist/verify-ac.js +30 -6
- package/dist/verify-completed-tracked.d.ts +2 -1
- package/dist/verify-completed-tracked.js +31 -1
- package/dist/verify-forward-coverage.d.ts +4 -0
- package/dist/verify-forward-coverage.js +77 -11
- package/dist/verify-lifecycle-visible.d.ts +13 -0
- package/dist/verify-lifecycle-visible.js +68 -0
- package/dist/verify-literal-ac.js +7 -0
- package/dist/verify-orphan-active.d.ts +1 -0
- package/dist/verify-orphan-active.js +30 -0
- package/dist/verify-session-ritual.d.ts +10 -2
- package/dist/verify-session-ritual.js +16 -3
- package/package.json +3 -3
package/dist/authz.d.ts
CHANGED
|
@@ -1,32 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
export declare const AUTHZ_AGENT_SHELL_ENV_MARKERS: readonly ["CLAUDECODE", "CLAUDE_CODE", "CLAUDE_CODE_ENTRYPOINT", "CURSOR_AGENT", "CURSOR_TRACE_ID", "CURSOR_SESSION_ID", "AIDER", "CONTINUE_CLI", "CODEX_SANDBOX", "CODEX_CI", "OPENAI_CODEX", "OPENCLAW", "OPENCLAW_STATE_DIR", "DEFT_PROBE_OPENCLAW", "DEFT_HOOK_HOST", "DEFT_AGENT_SHELL", "DEFT_AGENT_RUNTIME", "WARP_SESSION_ID", "WARP_HARNESS", "WARP_RUN_ID", "GEMINI_CLI", "AMP_CLI", "SWARM_AGENT", "AI_AGENT", "CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS", "GITLAB_CI", "CIRCLECI", "BUILDKITE", "TRAVIS", "JENKINS_URL", "TEAMCITY_VERSION", "TF_BUILD", "APPVEYOR", "BITBUCKET_BUILD_NUMBER", "CODEBUILD_BUILD_ID"];
|
|
8
|
-
/** Phrase an operator must type on the controlling TTY after --confirm (#3110). */
|
|
9
|
-
export declare const AUTHZ_INTERACTIVE_CONFIRM_PHRASE = "mint";
|
|
10
|
-
/** Testable seams for TTY / agent-shell detection (#3110). */
|
|
11
|
-
export interface AuthzMainSeams {
|
|
12
|
-
/**
|
|
13
|
-
* When true, interactive human TTY is present.
|
|
14
|
-
* Default: both stdin and stdout report isTTY (pseudo-TTY residual; #3110).
|
|
15
|
-
*/
|
|
16
|
-
readonly isTty?: () => boolean;
|
|
17
|
-
/** Environ for agent-shell marker detection (default: process.env). */
|
|
18
|
-
readonly environ?: NodeJS.ProcessEnv;
|
|
19
|
-
/**
|
|
20
|
-
* True when a controlling terminal device is available (`/dev/tty` or `CONIN$`).
|
|
21
|
-
* Default: open/close the platform controlling terminal (fail-closed on error).
|
|
22
|
-
*/
|
|
23
|
-
readonly hasControllingTerminal?: () => boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Read one interactive confirmation line from the operator (trimmed).
|
|
26
|
-
* Default: one line from stdin. Tests inject a fixed phrase.
|
|
27
|
-
*/
|
|
28
|
-
readonly readInteractiveConfirm?: () => string | null;
|
|
29
|
-
}
|
|
30
|
-
export declare function main(argv?: string[], seams?: AuthzMainSeams): number;
|
|
2
|
+
import { type HumanPresenceMintSeams } from "./human-presence-mint.js";
|
|
3
|
+
export type { HumanPresenceMintSeams as AuthzMainSeams } from "./human-presence-mint.js";
|
|
4
|
+
export { AUTHZ_AGENT_SHELL_ENV_MARKERS, AUTHZ_INTERACTIVE_CONFIRM_PHRASE, } from "./human-presence-mint.js";
|
|
5
|
+
export declare function main(argv?: string[], seams?: HumanPresenceMintSeams): number;
|
|
31
6
|
export default main;
|
|
32
7
|
//# sourceMappingURL=authz.d.ts.map
|
package/dist/authz.js
CHANGED
|
@@ -22,57 +22,11 @@
|
|
|
22
22
|
* TTY + controlling terminal + `--confirm` + typed phrase `mint`; agent/CI env
|
|
23
23
|
* markers refuse fail-closed. Argv `--confirm` alone is never enough.
|
|
24
24
|
*/
|
|
25
|
-
import {
|
|
25
|
+
import { existsSync } from "node:fs";
|
|
26
26
|
import { isAbsolute, resolve } from "node:path";
|
|
27
|
-
import { AFK_TEMPLATE_NAMES, AUTHZ_OPERATIONS, CLOSED_VERB_TEMPLATE_NAMES, FINISH_LOOP_TEMPLATE_NAME, formatDecomposeStructuralMintCommand, isAfkTemplateName, isClosedVerbTemplateName, isFinishLoopTemplateName,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
* (pseudo-terminal residual; #3110 Greptile). Presence refuses mutating authz.
|
|
31
|
-
* Expanded for dogfood conf 5/5 — markers are fail-closed (any non-empty value).
|
|
32
|
-
*/
|
|
33
|
-
export const AUTHZ_AGENT_SHELL_ENV_MARKERS = [
|
|
34
|
-
// Coding agents / IDEs
|
|
35
|
-
"CLAUDECODE",
|
|
36
|
-
"CLAUDE_CODE",
|
|
37
|
-
"CLAUDE_CODE_ENTRYPOINT",
|
|
38
|
-
"CURSOR_AGENT",
|
|
39
|
-
"CURSOR_TRACE_ID",
|
|
40
|
-
"CURSOR_SESSION_ID",
|
|
41
|
-
"AIDER",
|
|
42
|
-
"CONTINUE_CLI",
|
|
43
|
-
"CODEX_SANDBOX",
|
|
44
|
-
"CODEX_CI",
|
|
45
|
-
"OPENAI_CODEX",
|
|
46
|
-
"OPENCLAW",
|
|
47
|
-
"OPENCLAW_STATE_DIR",
|
|
48
|
-
"DEFT_PROBE_OPENCLAW",
|
|
49
|
-
"DEFT_HOOK_HOST",
|
|
50
|
-
"DEFT_AGENT_SHELL",
|
|
51
|
-
"DEFT_AGENT_RUNTIME",
|
|
52
|
-
"WARP_SESSION_ID",
|
|
53
|
-
"WARP_HARNESS",
|
|
54
|
-
"WARP_RUN_ID",
|
|
55
|
-
"GEMINI_CLI",
|
|
56
|
-
"AMP_CLI",
|
|
57
|
-
"SWARM_AGENT",
|
|
58
|
-
"AI_AGENT",
|
|
59
|
-
// CI / automation (never a human interactive operator mint)
|
|
60
|
-
"CI",
|
|
61
|
-
"CONTINUOUS_INTEGRATION",
|
|
62
|
-
"GITHUB_ACTIONS",
|
|
63
|
-
"GITLAB_CI",
|
|
64
|
-
"CIRCLECI",
|
|
65
|
-
"BUILDKITE",
|
|
66
|
-
"TRAVIS",
|
|
67
|
-
"JENKINS_URL",
|
|
68
|
-
"TEAMCITY_VERSION",
|
|
69
|
-
"TF_BUILD",
|
|
70
|
-
"APPVEYOR",
|
|
71
|
-
"BITBUCKET_BUILD_NUMBER",
|
|
72
|
-
"CODEBUILD_BUILD_ID",
|
|
73
|
-
];
|
|
74
|
-
/** Phrase an operator must type on the controlling TTY after --confirm (#3110). */
|
|
75
|
-
export const AUTHZ_INTERACTIVE_CONFIRM_PHRASE = "mint";
|
|
27
|
+
import { AFK_TEMPLATE_NAMES, AUTHZ_OPERATIONS, CLOSED_VERB_TEMPLATE_NAMES, FINISH_LOOP_TEMPLATE_NAME, formatDecomposeStructuralMintCommand, isAfkTemplateName, isClosedVerbTemplateName, isFinishLoopTemplateName, mintAfkTemplateGrant, mintDecomposeStructuralApplyGrant, mintHumanOriginGrant, revokeGrant, showAuthzSnapshot, startUatLease, suspendUatLease, toProjectRelativePosix, } from "@deftai/directive-core/authz";
|
|
28
|
+
import { refuseMintWhileUatActive, refuseNonInteractiveMint, resolveHumanPresenceMintSeams, } from "./human-presence-mint.js";
|
|
29
|
+
export { AUTHZ_AGENT_SHELL_ENV_MARKERS, AUTHZ_INTERACTIVE_CONFIRM_PHRASE, } from "./human-presence-mint.js";
|
|
76
30
|
function parseOps(raw) {
|
|
77
31
|
const allowed = new Set(AUTHZ_OPERATIONS);
|
|
78
32
|
const out = [];
|
|
@@ -295,130 +249,6 @@ function helpText() {
|
|
|
295
249
|
" Env bypass for a single shell: DEFT_ALLOW_RELEASE_PUBLISH=1 / DEFT_ALLOW_FINISH_LOOP=1.",
|
|
296
250
|
].join("\n");
|
|
297
251
|
}
|
|
298
|
-
function looksLikeAgentShell(environ) {
|
|
299
|
-
for (const key of AUTHZ_AGENT_SHELL_ENV_MARKERS) {
|
|
300
|
-
const v = environ[key];
|
|
301
|
-
if (v !== undefined && String(v).trim().length > 0)
|
|
302
|
-
return true;
|
|
303
|
-
}
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
function defaultHasControllingTerminal() {
|
|
307
|
-
try {
|
|
308
|
-
const path = process.platform === "win32" ? "CONIN$" : "/dev/tty";
|
|
309
|
-
const fd = openSync(path, "r");
|
|
310
|
-
closeSync(fd);
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
catch {
|
|
314
|
-
return false;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
function defaultReadInteractiveConfirm() {
|
|
318
|
-
// Read from the controlling terminal device — not redirected/piped stdin —
|
|
319
|
-
// so agent-controlled stdin alone cannot supply the confirm phrase (#3110).
|
|
320
|
-
let fd = null;
|
|
321
|
-
try {
|
|
322
|
-
const path = process.platform === "win32" ? "CONIN$" : "/dev/tty";
|
|
323
|
-
fd = openSync(path, "r");
|
|
324
|
-
const buf = Buffer.alloc(256);
|
|
325
|
-
const n = readSync(fd, buf, 0, buf.length, null);
|
|
326
|
-
if (n <= 0)
|
|
327
|
-
return null;
|
|
328
|
-
return buf.subarray(0, n).toString("utf8").trim();
|
|
329
|
-
}
|
|
330
|
-
catch {
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
finally {
|
|
334
|
-
if (fd !== null) {
|
|
335
|
-
try {
|
|
336
|
-
closeSync(fd);
|
|
337
|
-
}
|
|
338
|
-
catch {
|
|
339
|
-
/* ignore */
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* While any UAT lease is active, refuse ALL mutating authz CLI verbs (#3110).
|
|
346
|
-
*
|
|
347
|
-
* No multi-factor escape: TTY, `--confirm`, and typed phrase never authorize.
|
|
348
|
-
* Self-approval under UAT is impossible by construction — agents with a PTY
|
|
349
|
-
* cannot mint/suspend/revoke operator-cli authority during an active lease.
|
|
350
|
-
* Operators mint fix-cohort grants *before* `uat-start`.
|
|
351
|
-
*
|
|
352
|
-
* Returns exit code when blocked, or null when the command may continue.
|
|
353
|
-
*/
|
|
354
|
-
function refuseMutatingAuthzWhileUatActive(projectRoot, cmd) {
|
|
355
|
-
if (cmd === "show")
|
|
356
|
-
return null;
|
|
357
|
-
const state = loadAuthzState(projectRoot);
|
|
358
|
-
if (state.uat === null || !state.uat.active)
|
|
359
|
-
return null;
|
|
360
|
-
process.stderr.write(`authz:${cmd}: refusing mutating authz while UAT lease is ACTIVE ` +
|
|
361
|
-
`(campaign=${state.uat.campaignId}). Under active UAT, grant / uat-start / ` +
|
|
362
|
-
"uat-suspend / revoke are hard-refused — no TTY, --confirm, or phrase path " +
|
|
363
|
-
"authorizes self-approval (#3110). Mint grants before uat-start; clear the " +
|
|
364
|
-
"lease out-of-band (edit .deft/authz/state.json as a human outside agent hooks) " +
|
|
365
|
-
"to end UAT.\n");
|
|
366
|
-
return 2;
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* Refuse non-interactive / agent-shell operator-cli stamps outside UAT (#3110).
|
|
370
|
-
*
|
|
371
|
-
* Multi-factor human-presence gate (applies only when UAT lease is inactive):
|
|
372
|
-
* 1. No known agent/CI env markers
|
|
373
|
-
* 2. Interactive TTY (stdin + stdout isTTY)
|
|
374
|
-
* 3. Controlling terminal device present (`/dev/tty` / `CONIN$`)
|
|
375
|
-
* 4. Explicit argv `--confirm` (flag alone never enough)
|
|
376
|
-
* 5. Interactive typed phrase `mint` (argv --confirm alone never enough even on PTY)
|
|
377
|
-
*
|
|
378
|
-
* Fail-closed: if a real human interactive path cannot be proven, refuse mint.
|
|
379
|
-
* Returns an exit code when blocked, or null when the mutation may proceed.
|
|
380
|
-
*/
|
|
381
|
-
function refuseNonInteractiveMint(cmd, isTty, environ, confirm, hasControllingTerminal, readInteractiveConfirm) {
|
|
382
|
-
if (cmd === "show")
|
|
383
|
-
return null;
|
|
384
|
-
if (looksLikeAgentShell(environ)) {
|
|
385
|
-
process.stderr.write(`authz:${cmd}: refusing operator-cli stamp from an agent/host/CI shell ` +
|
|
386
|
-
`(detected agent or CI env marker). Mutating authz requires a human interactive ` +
|
|
387
|
-
"TTY without agent-shell markers, plus --confirm and typed phrase (#3110).\n");
|
|
388
|
-
return 2;
|
|
389
|
-
}
|
|
390
|
-
const tty = isTty();
|
|
391
|
-
if (!tty && !confirm) {
|
|
392
|
-
process.stderr.write(`authz:${cmd}: refusing non-interactive operator-cli stamp. ` +
|
|
393
|
-
"Mutating authz verbs require interactive TTY, --confirm, and typed phrase " +
|
|
394
|
-
`'${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' (#3110).\n`);
|
|
395
|
-
return 2;
|
|
396
|
-
}
|
|
397
|
-
if (!tty) {
|
|
398
|
-
process.stderr.write(`authz:${cmd}: refusing non-TTY operator-cli stamp. ` +
|
|
399
|
-
"--confirm alone never authorizes mint — interactive TTY is required (#3110).\n");
|
|
400
|
-
return 2;
|
|
401
|
-
}
|
|
402
|
-
if (!confirm) {
|
|
403
|
-
process.stderr.write(`authz:${cmd}: refusing operator-cli stamp without --confirm. ` +
|
|
404
|
-
"Interactive TTY alone never authorizes mint — pass --confirm explicitly (#3110).\n");
|
|
405
|
-
return 2;
|
|
406
|
-
}
|
|
407
|
-
if (!hasControllingTerminal()) {
|
|
408
|
-
process.stderr.write(`authz:${cmd}: refusing operator-cli stamp without a controlling terminal. ` +
|
|
409
|
-
"Open a real interactive console (not a headless/agent pipe) to mint (#3110).\n");
|
|
410
|
-
return 2;
|
|
411
|
-
}
|
|
412
|
-
process.stderr.write(`authz:${cmd}: type '${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' and press Enter to confirm operator mint: `);
|
|
413
|
-
const line = readInteractiveConfirm();
|
|
414
|
-
const phrase = (line ?? "").trim().toLowerCase();
|
|
415
|
-
if (phrase !== AUTHZ_INTERACTIVE_CONFIRM_PHRASE) {
|
|
416
|
-
process.stderr.write(`\nauthz:${cmd}: interactive confirm phrase mismatch (got ${JSON.stringify(line ?? "")}). ` +
|
|
417
|
-
`Type exactly '${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' on the controlling TTY (#3110).\n`);
|
|
418
|
-
return 2;
|
|
419
|
-
}
|
|
420
|
-
return null;
|
|
421
|
-
}
|
|
422
252
|
export function main(argv = process.argv.slice(2), seams = {}) {
|
|
423
253
|
const args = parseArgv(argv);
|
|
424
254
|
if (args.error === "help") {
|
|
@@ -430,11 +260,7 @@ export function main(argv = process.argv.slice(2), seams = {}) {
|
|
|
430
260
|
process.stderr.write(`${helpText()}\n`);
|
|
431
261
|
return 2;
|
|
432
262
|
}
|
|
433
|
-
|
|
434
|
-
const isTty = seams.isTty ?? (() => process.stdin.isTTY === true && process.stdout.isTTY === true);
|
|
435
|
-
const environ = seams.environ ?? process.env;
|
|
436
|
-
const hasControllingTerminal = seams.hasControllingTerminal ?? defaultHasControllingTerminal;
|
|
437
|
-
const readInteractiveConfirm = seams.readInteractiveConfirm ?? defaultReadInteractiveConfirm;
|
|
263
|
+
const resolved = resolveHumanPresenceMintSeams(seams);
|
|
438
264
|
/**
|
|
439
265
|
* Mutating-verb gate stack (#3110):
|
|
440
266
|
* 1. Active UAT → hard refuse (no multi-factor escape; self-approval impossible)
|
|
@@ -442,10 +268,19 @@ export function main(argv = process.argv.slice(2), seams = {}) {
|
|
|
442
268
|
* Required-arg validation runs before this so missing --campaign / --ops still report clearly.
|
|
443
269
|
*/
|
|
444
270
|
const gateConfirm = () => {
|
|
445
|
-
|
|
271
|
+
if (args.cmd === "show")
|
|
272
|
+
return null;
|
|
273
|
+
const uatBlocked = refuseMintWhileUatActive(`authz:${args.cmd}`, args.projectRoot);
|
|
446
274
|
if (uatBlocked !== null)
|
|
447
275
|
return uatBlocked;
|
|
448
|
-
return refuseNonInteractiveMint(
|
|
276
|
+
return refuseNonInteractiveMint({
|
|
277
|
+
verb: `authz:${args.cmd}`,
|
|
278
|
+
confirm: args.confirm,
|
|
279
|
+
isTty: resolved.isTty,
|
|
280
|
+
environ: resolved.environ,
|
|
281
|
+
hasControllingTerminal: resolved.hasControllingTerminal,
|
|
282
|
+
readInteractiveConfirm: resolved.readInteractiveConfirm,
|
|
283
|
+
});
|
|
449
284
|
};
|
|
450
285
|
try {
|
|
451
286
|
switch (args.cmd) {
|
|
@@ -83,6 +83,7 @@ export const SUBCOMMAND_ROUTES = {
|
|
|
83
83
|
"policy:allow-direct-commits": ["policy", "allow-direct-commits"],
|
|
84
84
|
"policy:allow-bot-merge": ["policy", "allow-bot-merge"],
|
|
85
85
|
"policy:enable-value-feedback": ["policy", "enable-value-feedback"],
|
|
86
|
+
"policy:disable-host-hooks": ["policy", "disable-host-hooks"],
|
|
86
87
|
"policy:set-ceremony-dial": ["policy", "set-ceremony-dial"],
|
|
87
88
|
"policy:clear-value-feedback": ["policy", "clear-value-feedback"],
|
|
88
89
|
"authz:show": ["authz", "show"],
|
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", "lifecycle-event", "lifecycle-stats", "session-start", "session-ready", "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-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", "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"];
|
|
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). */
|
|
@@ -177,6 +177,12 @@ export declare function printCommandsList(io?: DispatchIo): void;
|
|
|
177
177
|
* (#2172). Preserves the init/update/doctor first-run guidance from #2273.
|
|
178
178
|
*/
|
|
179
179
|
export declare function printHelp(io?: DispatchIo): void;
|
|
180
|
+
/**
|
|
181
|
+
* Unknown-colon-verb remediation (#3439 / #2652).
|
|
182
|
+
* Agent-facing spelling is `deft <verb>` (works on consumer CLI and source).
|
|
183
|
+
* Bare `task <verb>` is not consumer-runnable on include-only Taskfiles.
|
|
184
|
+
*/
|
|
185
|
+
export declare function unknownColonVerbHint(verb: string): string;
|
|
180
186
|
/** Dispatch argv to a registered verb; returns the handler exit code. */
|
|
181
187
|
export declare function dispatch(argv: string[], io?: DispatchIo): Promise<number>;
|
|
182
188
|
/** Test seam: reset lazy handler cache between cases. */
|
package/dist/dispatch.js
CHANGED
|
@@ -10,7 +10,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:pat
|
|
|
10
10
|
import { engineInfo, userConfig } from "@deftai/directive-core";
|
|
11
11
|
import { assertWriteTargetSafe } from "@deftai/directive-core/dist/fs/projection-containment.js";
|
|
12
12
|
import { parseInitArgv, runInitDepositCli } from "@deftai/directive-core/init-deposit";
|
|
13
|
-
import { appendAuditLog, disclosureLine, migrateLegacyPolicyKey, PLAN_POLICY_KEY, policyColonInvocation, policySetInvocation, projectDefinitionPath, resolvePolicy, resolveWipCap, setPolicy, } from "@deftai/directive-core/policy";
|
|
13
|
+
import { appendAuditLog, disclosureLine, migrateLegacyPolicyKey, PLAN_POLICY_KEY, POLICY_AUDIT_NOOP_STDOUT, policyColonInvocation, policySetInvocation, projectDefinitionPath, resolvePolicy, resolveWipCap, setPolicy, stampChangedToken, } from "@deftai/directive-core/policy";
|
|
14
14
|
import { defaultWhich } from "@deftai/directive-core/scm";
|
|
15
15
|
import { KNOWN_SUBAGENT_BACKEND_IDS, probeSubagentBackends, resolveSwarmSubagentBackend, } from "@deftai/directive-core/swarm";
|
|
16
16
|
import { atomicWriteProjectDefinition } from "@deftai/directive-core/vbrief-build";
|
|
@@ -69,10 +69,12 @@ export const CLI_MODULE_VERBS = [
|
|
|
69
69
|
"release-rollback",
|
|
70
70
|
"scope-lifecycle",
|
|
71
71
|
"scope-record-approved-scope",
|
|
72
|
+
"scm-sync-default",
|
|
72
73
|
"lifecycle-event",
|
|
73
74
|
"lifecycle-stats",
|
|
74
75
|
"session-start",
|
|
75
76
|
"session-ready",
|
|
77
|
+
"occupancy-steal",
|
|
76
78
|
"plan-sequence",
|
|
77
79
|
"slice",
|
|
78
80
|
"subagent-monitor",
|
|
@@ -138,6 +140,7 @@ export const CLI_MODULE_VERBS = [
|
|
|
138
140
|
"verify-tools",
|
|
139
141
|
"verify-wip-cap",
|
|
140
142
|
"verify-orphan-active",
|
|
143
|
+
"verify-lifecycle-visible",
|
|
141
144
|
"verify-completed-tracked",
|
|
142
145
|
"verify-literal-ac",
|
|
143
146
|
"verify-ac",
|
|
@@ -218,6 +221,7 @@ export const POLICY_ACTION_ALIAS_SUBCOMMANDS = {
|
|
|
218
221
|
"policy:allow-direct-commits": "allow-direct-commits",
|
|
219
222
|
"policy:allow-bot-merge": "allow-bot-merge",
|
|
220
223
|
"policy:enable-value-feedback": "enable-value-feedback",
|
|
224
|
+
"policy:disable-host-hooks": "disable-host-hooks",
|
|
221
225
|
"policy:set-ceremony-dial": "set-ceremony-dial",
|
|
222
226
|
"policy:clear-value-feedback": "clear-value-feedback",
|
|
223
227
|
"policy:disable-directive": "disable-directive",
|
|
@@ -280,6 +284,7 @@ export const VERB_ALIASES = {
|
|
|
280
284
|
"verify:vbrief-conformance": "vbrief-validate",
|
|
281
285
|
"verify:wip-cap": "verify-wip-cap",
|
|
282
286
|
"verify:orphan-active": "verify-orphan-active",
|
|
287
|
+
"verify:lifecycle-visible": "verify-lifecycle-visible",
|
|
283
288
|
"verify:completed-tracked": "verify-completed-tracked",
|
|
284
289
|
"verify:literal-ac": "verify-literal-ac",
|
|
285
290
|
"verify:literal-acceptance": "verify-literal-ac",
|
|
@@ -293,6 +298,11 @@ export const VERB_ALIASES = {
|
|
|
293
298
|
"verify:no-task-runtime": "verify-no-task-runtime",
|
|
294
299
|
"vbrief:validate": "vbrief-validate",
|
|
295
300
|
"vbrief:preflight": "vbrief-preflight",
|
|
301
|
+
// xbrief:-prefixed aliases for the canonical post-#2109 lifecycle spelling.
|
|
302
|
+
// xbrief:validate closes the #3483 gap: the swarm skill named it at MUST
|
|
303
|
+
// level but only vbrief:validate resolved.
|
|
304
|
+
"xbrief:validate": "vbrief-validate",
|
|
305
|
+
"xbrief:activate": "vbrief-activate",
|
|
296
306
|
"xbrief:preflight": "vbrief-preflight",
|
|
297
307
|
"xbrief:create": "xbrief-create",
|
|
298
308
|
"xbrief:verify": "xbrief-verify",
|
|
@@ -352,6 +362,7 @@ export const VERB_ALIASES = {
|
|
|
352
362
|
upgrade: "install-upgrade",
|
|
353
363
|
"session:start": "session-start",
|
|
354
364
|
"session:ready": "session-ready",
|
|
365
|
+
"occupancy:steal": "occupancy-steal",
|
|
355
366
|
...FRESHNESS_COLON_ALIASES,
|
|
356
367
|
"lifecycle:event": "lifecycle-event",
|
|
357
368
|
"lifecycle:stats": "lifecycle-stats",
|
|
@@ -380,6 +391,7 @@ export const VERB_ALIASES = {
|
|
|
380
391
|
"setup:ghx": "setup-ghx",
|
|
381
392
|
"scm:status": "scm-readiness",
|
|
382
393
|
"scm:readiness": "scm-readiness",
|
|
394
|
+
"scm:sync-default": "scm-sync-default",
|
|
383
395
|
};
|
|
384
396
|
/** CLI modules living under verify-source-cli/ or content-validate-cli/ subdirs. */
|
|
385
397
|
const SUBDIR_CLI_STEMS = {
|
|
@@ -2113,7 +2125,7 @@ function loadProjectDefinitionForWrite(projectRoot) {
|
|
|
2113
2125
|
throw new PolicySetError("PROJECT-DEFINITION 'plan' is not an object", "config");
|
|
2114
2126
|
}
|
|
2115
2127
|
const planObj = plan;
|
|
2116
|
-
migrateLegacyPolicyKey(planObj);
|
|
2128
|
+
const legacyMigrated = migrateLegacyPolicyKey(planObj);
|
|
2117
2129
|
let policy = planObj[PLAN_POLICY_KEY];
|
|
2118
2130
|
if (policy === undefined) {
|
|
2119
2131
|
policy = {};
|
|
@@ -2122,31 +2134,31 @@ function loadProjectDefinitionForWrite(projectRoot) {
|
|
|
2122
2134
|
if (typeof policy !== "object" || policy === null || Array.isArray(policy)) {
|
|
2123
2135
|
throw new PolicySetError("plan.policy is not an object", "config");
|
|
2124
2136
|
}
|
|
2125
|
-
return { path, data, policyBlock: policy };
|
|
2137
|
+
return { path, data, policyBlock: policy, legacyMigrated };
|
|
2126
2138
|
}
|
|
2127
2139
|
/** Write plan.policy.wipCap in place + append the audit row (mirrors set_wip_cap). */
|
|
2128
2140
|
function writeWipCap(projectRoot, cap, actor, note) {
|
|
2129
|
-
const { path, data, policyBlock } = loadProjectDefinitionForWrite(projectRoot);
|
|
2141
|
+
const { path, data, policyBlock, legacyMigrated } = loadProjectDefinitionForWrite(projectRoot);
|
|
2130
2142
|
const previous = policyBlock.wipCap;
|
|
2131
2143
|
policyBlock.wipCap = cap;
|
|
2132
|
-
|
|
2133
|
-
atomicWriteProjectDefinition(path, data);
|
|
2134
|
-
const changed = previous !== cap;
|
|
2144
|
+
const changed = previous !== cap || legacyMigrated;
|
|
2135
2145
|
const parts = [`actor=${actor}`, `wipCap=${cap}`, `previous=${pyRepr(previous)}`];
|
|
2136
2146
|
if (note)
|
|
2137
2147
|
parts.push(`note=${sanitizeNote(note)}`);
|
|
2138
|
-
const auditEntry = parts.join(" ");
|
|
2139
|
-
|
|
2148
|
+
const auditEntry = stampChangedToken(parts.join(" "), changed);
|
|
2149
|
+
if (changed) {
|
|
2150
|
+
assertWriteTargetSafe(projectRoot, path);
|
|
2151
|
+
atomicWriteProjectDefinition(path, data);
|
|
2152
|
+
}
|
|
2153
|
+
appendAuditLog(projectRoot, auditEntry, changed);
|
|
2140
2154
|
return { changed, auditEntry };
|
|
2141
2155
|
}
|
|
2142
2156
|
/** Write plan.policy.swarmSubagentBackend in place + append the audit row. */
|
|
2143
2157
|
function writeSubagentBackend(projectRoot, backendId, actor, note) {
|
|
2144
|
-
const { path, data, policyBlock } = loadProjectDefinitionForWrite(projectRoot);
|
|
2158
|
+
const { path, data, policyBlock, legacyMigrated } = loadProjectDefinitionForWrite(projectRoot);
|
|
2145
2159
|
const previous = policyBlock.swarmSubagentBackend;
|
|
2146
2160
|
policyBlock.swarmSubagentBackend = backendId;
|
|
2147
|
-
|
|
2148
|
-
atomicWriteProjectDefinition(path, data);
|
|
2149
|
-
const changed = previous !== backendId;
|
|
2161
|
+
const changed = previous !== backendId || legacyMigrated;
|
|
2150
2162
|
const parts = [
|
|
2151
2163
|
`actor=${actor}`,
|
|
2152
2164
|
`swarmSubagentBackend=${backendId}`,
|
|
@@ -2154,8 +2166,12 @@ function writeSubagentBackend(projectRoot, backendId, actor, note) {
|
|
|
2154
2166
|
];
|
|
2155
2167
|
if (note)
|
|
2156
2168
|
parts.push(`note=${sanitizeNote(note)}`);
|
|
2157
|
-
const auditEntry = parts.join(" ");
|
|
2158
|
-
|
|
2169
|
+
const auditEntry = stampChangedToken(parts.join(" "), changed);
|
|
2170
|
+
if (changed) {
|
|
2171
|
+
assertWriteTargetSafe(projectRoot, path);
|
|
2172
|
+
atomicWriteProjectDefinition(path, data);
|
|
2173
|
+
}
|
|
2174
|
+
appendAuditLog(projectRoot, auditEntry, changed);
|
|
2159
2175
|
return { changed, auditEntry };
|
|
2160
2176
|
}
|
|
2161
2177
|
/** Serialise the probe output for `subagent-backends --format json`. */
|
|
@@ -2220,7 +2236,7 @@ function applyBranchPolicy(args, io) {
|
|
|
2220
2236
|
io.writeOut(` audit: meta/policy-changes.log :: ${result.auditEntry}\n`);
|
|
2221
2237
|
}
|
|
2222
2238
|
else {
|
|
2223
|
-
io.writeOut(
|
|
2239
|
+
io.writeOut(`${POLICY_AUDIT_NOOP_STDOUT}\n`);
|
|
2224
2240
|
}
|
|
2225
2241
|
io.writeOut(`${disclosureLine(resolvePolicy(args.projectRoot))}\n`);
|
|
2226
2242
|
return 0;
|
|
@@ -2249,7 +2265,7 @@ function applyWipCap(args, io) {
|
|
|
2249
2265
|
io.writeOut(` audit: meta/policy-changes.log :: ${res.auditEntry}\n`);
|
|
2250
2266
|
}
|
|
2251
2267
|
else {
|
|
2252
|
-
io.writeOut(
|
|
2268
|
+
io.writeOut(`${POLICY_AUDIT_NOOP_STDOUT}\n`);
|
|
2253
2269
|
}
|
|
2254
2270
|
const result = resolveWipCap(args.projectRoot);
|
|
2255
2271
|
io.writeOut(`[deft policy] plan.policy.wipCap=${result.cap} (source: ${result.source}).\n`);
|
|
@@ -2269,7 +2285,7 @@ function applySubagentBackend(args, io) {
|
|
|
2269
2285
|
io.writeOut(` audit: meta/policy-changes.log :: ${res.auditEntry}\n`);
|
|
2270
2286
|
}
|
|
2271
2287
|
else {
|
|
2272
|
-
io.writeOut(
|
|
2288
|
+
io.writeOut(`${POLICY_AUDIT_NOOP_STDOUT}\n`);
|
|
2273
2289
|
}
|
|
2274
2290
|
const result = resolveSwarmSubagentBackend(args.projectRoot);
|
|
2275
2291
|
io.writeOut(`[deft policy] plan.policy.swarmSubagentBackend=${pyRepr(result.backend_id)} ` +
|
|
@@ -2599,6 +2615,10 @@ const CURATED_HELP_GROUPS = [
|
|
|
2599
2615
|
name: "session:ready",
|
|
2600
2616
|
summary: "One-shot recovery to gated write-ready (session + ritual + cache)",
|
|
2601
2617
|
},
|
|
2618
|
+
{
|
|
2619
|
+
name: "occupancy:steal",
|
|
2620
|
+
summary: "Supersede a live worktree occupancy lease (--confirm --occupant)",
|
|
2621
|
+
},
|
|
2602
2622
|
{
|
|
2603
2623
|
name: "freshness:report",
|
|
2604
2624
|
summary: "Bound vs live deposit generation (current|stale_soft|stale_hard)",
|
|
@@ -2707,6 +2727,23 @@ async function invokeHandler(handler, argv) {
|
|
|
2707
2727
|
return typeof code === "number" ? code : 0;
|
|
2708
2728
|
}
|
|
2709
2729
|
const CLI_PACKAGE = "@deftai/directive";
|
|
2730
|
+
const PLAN_SEQUENCE_VERBS = "set|current|clear|advance";
|
|
2731
|
+
/**
|
|
2732
|
+
* Unknown-colon-verb remediation (#3439 / #2652).
|
|
2733
|
+
* Agent-facing spelling is `deft <verb>` (works on consumer CLI and source).
|
|
2734
|
+
* Bare `task <verb>` is not consumer-runnable on include-only Taskfiles.
|
|
2735
|
+
*/
|
|
2736
|
+
export function unknownColonVerbHint(verb) {
|
|
2737
|
+
if (verb.startsWith("plan-sequence:") && !(verb in PLAN_SEQUENCE_ALIAS_SUBCOMMANDS)) {
|
|
2738
|
+
return (`hint: plan-sequence verbs are ${PLAN_SEQUENCE_VERBS} ` +
|
|
2739
|
+
`(e.g. \`deft plan-sequence:current\`). '${verb}' is not a verb. ` +
|
|
2740
|
+
`Do not run bare \`task ${verb}\` -- consumer include-only Taskfiles cannot resolve it.\n`);
|
|
2741
|
+
}
|
|
2742
|
+
const hyphen = verb.replaceAll(":", "-");
|
|
2743
|
+
return (`hint: try \`deft ${verb}\` (CLI) or \`task deft:${verb}\` (consumer Taskfile). ` +
|
|
2744
|
+
`Bare \`task ${verb}\` does not exist on include-only deposits. ` +
|
|
2745
|
+
`Hyphen stem: ${hyphen}.\n`);
|
|
2746
|
+
}
|
|
2710
2747
|
function versionBanner() {
|
|
2711
2748
|
const info = engineInfo();
|
|
2712
2749
|
return `${CLI_PACKAGE} (engine: ${info.name}@${info.version})\n`;
|
|
@@ -2730,8 +2767,7 @@ export async function dispatch(argv, io = defaultIo()) {
|
|
|
2730
2767
|
if (canonical === null) {
|
|
2731
2768
|
io.writeErr(`directive: unknown verb '${verb}'\n`);
|
|
2732
2769
|
if (verb?.includes(":")) {
|
|
2733
|
-
io.writeErr(
|
|
2734
|
-
`(e.g. pr:watch → pr-watch / \`task pr:watch\`)\n`);
|
|
2770
|
+
io.writeErr(unknownColonVerbHint(verb));
|
|
2735
2771
|
}
|
|
2736
2772
|
return 1;
|
|
2737
2773
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Env markers that indicate an agent/host/CI shell even when stdin reports a TTY
|
|
3
|
+
* (pseudo-terminal residual; #3110 Greptile). Presence refuses mint.
|
|
4
|
+
* Expanded for dogfood conf 5/5 — markers are fail-closed (any non-empty value).
|
|
5
|
+
*/
|
|
6
|
+
export declare const AUTHZ_AGENT_SHELL_ENV_MARKERS: readonly ["CLAUDECODE", "CLAUDE_CODE", "CLAUDE_CODE_ENTRYPOINT", "CURSOR_AGENT", "CURSOR_TRACE_ID", "CURSOR_SESSION_ID", "AIDER", "CONTINUE_CLI", "CODEX_SANDBOX", "CODEX_CI", "OPENAI_CODEX", "OPENCLAW", "OPENCLAW_STATE_DIR", "DEFT_PROBE_OPENCLAW", "DEFT_HOOK_HOST", "DEFT_AGENT_SHELL", "DEFT_AGENT_RUNTIME", "WARP_SESSION_ID", "WARP_HARNESS", "WARP_RUN_ID", "GEMINI_CLI", "AMP_CLI", "SWARM_AGENT", "AI_AGENT", "CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS", "GITLAB_CI", "CIRCLECI", "BUILDKITE", "TRAVIS", "JENKINS_URL", "TEAMCITY_VERSION", "TF_BUILD", "APPVEYOR", "BITBUCKET_BUILD_NUMBER", "CODEBUILD_BUILD_ID"];
|
|
7
|
+
/** Phrase an operator must type on the controlling TTY after --confirm (#3110). */
|
|
8
|
+
export declare const AUTHZ_INTERACTIVE_CONFIRM_PHRASE = "mint";
|
|
9
|
+
/** Testable seams for TTY / agent-shell detection (#3110 / #3384). */
|
|
10
|
+
export interface HumanPresenceMintSeams {
|
|
11
|
+
/**
|
|
12
|
+
* When true, interactive human TTY is present.
|
|
13
|
+
* Default: both stdin and stdout report isTTY (pseudo-TTY residual; #3110).
|
|
14
|
+
*/
|
|
15
|
+
readonly isTty?: () => boolean;
|
|
16
|
+
/** Environ for agent-shell marker detection (default: process.env). */
|
|
17
|
+
readonly environ?: NodeJS.ProcessEnv;
|
|
18
|
+
/**
|
|
19
|
+
* True when a controlling terminal device is available (`/dev/tty` or `CONIN$`).
|
|
20
|
+
* Default: open/close the platform controlling terminal (fail-closed on error).
|
|
21
|
+
*/
|
|
22
|
+
readonly hasControllingTerminal?: () => boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Read one interactive confirmation line from the operator (trimmed).
|
|
25
|
+
* Default: one line from the controlling terminal. Tests inject a fixed phrase.
|
|
26
|
+
*/
|
|
27
|
+
readonly readInteractiveConfirm?: () => string | null;
|
|
28
|
+
}
|
|
29
|
+
export declare function looksLikeAgentShell(environ: NodeJS.ProcessEnv): boolean;
|
|
30
|
+
/** Platform controlling-terminal path (`CONIN$` on win32, `/dev/tty` elsewhere). */
|
|
31
|
+
export declare function controllingTerminalPath(platform?: NodeJS.Platform): string;
|
|
32
|
+
/**
|
|
33
|
+
* Open flag for the platform controlling-terminal device (#3596).
|
|
34
|
+
*
|
|
35
|
+
* Windows `CONIN$` generally requires read/write (`r+`); `r` (O_RDONLY) fails
|
|
36
|
+
* in a real interactive console and made operator mint unreachable on win32.
|
|
37
|
+
*/
|
|
38
|
+
export declare function controllingTerminalOpenFlag(platform?: NodeJS.Platform): "r" | "r+";
|
|
39
|
+
export declare function resolveHumanPresenceMintSeams(seams?: HumanPresenceMintSeams): Required<HumanPresenceMintSeams>;
|
|
40
|
+
/** Active UAT campaign id, or null when no lease is active. */
|
|
41
|
+
export declare function activeUatCampaignId(projectRoot: string): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* While any UAT lease is active, refuse mint (#3110 / #3384).
|
|
44
|
+
*
|
|
45
|
+
* No multi-factor escape: TTY, `--confirm`, and typed phrase never authorize.
|
|
46
|
+
* Returns an exit code when blocked, or null when mint may continue.
|
|
47
|
+
*/
|
|
48
|
+
export declare function refuseMintWhileUatActive(verb: string, projectRoot: string): number | null;
|
|
49
|
+
/**
|
|
50
|
+
* Refuse non-interactive / agent-shell mint outside UAT (#3110 / #3384).
|
|
51
|
+
*
|
|
52
|
+
* Multi-factor human-presence gate (applies only when UAT lease is inactive):
|
|
53
|
+
* 1. No known agent/CI env markers
|
|
54
|
+
* 2. Interactive TTY (stdin + stdout isTTY)
|
|
55
|
+
* 3. Controlling terminal device present (`/dev/tty` / `CONIN$`)
|
|
56
|
+
* 4. Explicit argv `--confirm` (flag alone never enough)
|
|
57
|
+
* 5. Interactive typed phrase `mint` (argv --confirm alone never enough even on PTY)
|
|
58
|
+
*
|
|
59
|
+
* Fail-closed: if a real human interactive path cannot be proven, refuse mint.
|
|
60
|
+
* Returns an exit code when blocked, or null when the mutation may proceed.
|
|
61
|
+
*/
|
|
62
|
+
export declare function refuseNonInteractiveMint(input: {
|
|
63
|
+
readonly verb: string;
|
|
64
|
+
readonly confirm: boolean;
|
|
65
|
+
readonly isTty: () => boolean;
|
|
66
|
+
readonly environ: NodeJS.ProcessEnv;
|
|
67
|
+
readonly hasControllingTerminal: () => boolean;
|
|
68
|
+
readonly readInteractiveConfirm: () => string | null;
|
|
69
|
+
}): number | null;
|
|
70
|
+
//# sourceMappingURL=human-presence-mint.d.ts.map
|