@deftai/directive 0.103.0 → 0.105.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 CHANGED
@@ -1,32 +1,7 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Env markers that indicate an agent/host/CI shell even when stdin reports a TTY
4
- * (pseudo-terminal residual; #3110 Greptile). Presence refuses mutating authz.
5
- * Expanded for dogfood conf 5/5 — markers are fail-closed (any non-empty value).
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 { closeSync, existsSync, openSync, readSync } from "node:fs";
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, loadAuthzState, mintAfkTemplateGrant, mintDecomposeStructuralApplyGrant, mintHumanOriginGrant, revokeGrant, showAuthzSnapshot, startUatLease, suspendUatLease, toProjectRelativePosix, } from "@deftai/directive-core/authz";
28
- /**
29
- * Env markers that indicate an agent/host/CI shell even when stdin reports a TTY
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
- // Both stdin and stdout TTY — agent-allocated single-side PTY is not enough.
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
- const uatBlocked = refuseMutatingAuthzWhileUatActive(args.projectRoot, args.cmd);
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(args.cmd, isTty, environ, args.confirm, hasControllingTerminal, readInteractiveConfirm);
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) {
@@ -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-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-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). */
package/dist/dispatch.js CHANGED
@@ -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",
@@ -116,6 +118,7 @@ export const CLI_MODULE_VERBS = [
116
118
  "verify-bridge-drift",
117
119
  "verify-capacity",
118
120
  "verify-contained-writes",
121
+ "verify-telemetry-coverage",
119
122
  "verify-content-manifest",
120
123
  "verify-skill-external-fetch-gate",
121
124
  "verify-contract-drift",
@@ -292,6 +295,11 @@ export const VERB_ALIASES = {
292
295
  "verify:no-task-runtime": "verify-no-task-runtime",
293
296
  "vbrief:validate": "vbrief-validate",
294
297
  "vbrief:preflight": "vbrief-preflight",
298
+ // xbrief:-prefixed aliases for the canonical post-#2109 lifecycle spelling.
299
+ // xbrief:validate closes the #3483 gap: the swarm skill named it at MUST
300
+ // level but only vbrief:validate resolved.
301
+ "xbrief:validate": "vbrief-validate",
302
+ "xbrief:activate": "vbrief-activate",
295
303
  "xbrief:preflight": "vbrief-preflight",
296
304
  "xbrief:create": "xbrief-create",
297
305
  "xbrief:verify": "xbrief-verify",
@@ -313,6 +321,7 @@ export const VERB_ALIASES = {
313
321
  "rule:ownership-lint": "rule-ownership-lint",
314
322
  "verify:biome-config": "verify-biome-config",
315
323
  "verify:contained-writes": "verify-contained-writes",
324
+ "verify:telemetry-coverage": "verify-telemetry-coverage",
316
325
  "verify:content-manifest": "verify-content-manifest",
317
326
  "verify:skill-external-fetch-gate": "verify-skill-external-fetch-gate",
318
327
  "verify:contract-drift": "verify-contract-drift",
@@ -350,6 +359,7 @@ export const VERB_ALIASES = {
350
359
  upgrade: "install-upgrade",
351
360
  "session:start": "session-start",
352
361
  "session:ready": "session-ready",
362
+ "occupancy:steal": "occupancy-steal",
353
363
  ...FRESHNESS_COLON_ALIASES,
354
364
  "lifecycle:event": "lifecycle-event",
355
365
  "lifecycle:stats": "lifecycle-stats",
@@ -378,6 +388,7 @@ export const VERB_ALIASES = {
378
388
  "setup:ghx": "setup-ghx",
379
389
  "scm:status": "scm-readiness",
380
390
  "scm:readiness": "scm-readiness",
391
+ "scm:sync-default": "scm-sync-default",
381
392
  };
382
393
  /** CLI modules living under verify-source-cli/ or content-validate-cli/ subdirs. */
383
394
  const SUBDIR_CLI_STEMS = {
@@ -385,6 +396,7 @@ const SUBDIR_CLI_STEMS = {
385
396
  "rule-ownership-lint": "verify-source-cli/rule-ownership-lint",
386
397
  "verify-biome-config": "verify-source-cli/verify-biome-config",
387
398
  "verify-contained-writes": "verify-source-cli/verify-contained-writes",
399
+ "verify-telemetry-coverage": "verify-source-cli/verify-telemetry-coverage",
388
400
  "verify-content-manifest": "verify-source-cli/verify-content-manifest",
389
401
  "verify-skill-external-fetch-gate": "verify-source-cli/verify-skill-external-fetch-gate",
390
402
  "verify-contract-drift": "verify-source-cli/verify-contract-drift",
@@ -2596,6 +2608,10 @@ const CURATED_HELP_GROUPS = [
2596
2608
  name: "session:ready",
2597
2609
  summary: "One-shot recovery to gated write-ready (session + ritual + cache)",
2598
2610
  },
2611
+ {
2612
+ name: "occupancy:steal",
2613
+ summary: "Supersede a live worktree occupancy lease (--confirm --occupant)",
2614
+ },
2599
2615
  {
2600
2616
  name: "freshness:report",
2601
2617
  summary: "Bound vs live deposit generation (current|stale_soft|stale_hard)",
@@ -0,0 +1,61 @@
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
+ export declare function resolveHumanPresenceMintSeams(seams?: HumanPresenceMintSeams): Required<HumanPresenceMintSeams>;
31
+ /** Active UAT campaign id, or null when no lease is active. */
32
+ export declare function activeUatCampaignId(projectRoot: string): string | null;
33
+ /**
34
+ * While any UAT lease is active, refuse mint (#3110 / #3384).
35
+ *
36
+ * No multi-factor escape: TTY, `--confirm`, and typed phrase never authorize.
37
+ * Returns an exit code when blocked, or null when mint may continue.
38
+ */
39
+ export declare function refuseMintWhileUatActive(verb: string, projectRoot: string): number | null;
40
+ /**
41
+ * Refuse non-interactive / agent-shell mint outside UAT (#3110 / #3384).
42
+ *
43
+ * Multi-factor human-presence gate (applies only when UAT lease is inactive):
44
+ * 1. No known agent/CI env markers
45
+ * 2. Interactive TTY (stdin + stdout isTTY)
46
+ * 3. Controlling terminal device present (`/dev/tty` / `CONIN$`)
47
+ * 4. Explicit argv `--confirm` (flag alone never enough)
48
+ * 5. Interactive typed phrase `mint` (argv --confirm alone never enough even on PTY)
49
+ *
50
+ * Fail-closed: if a real human interactive path cannot be proven, refuse mint.
51
+ * Returns an exit code when blocked, or null when the mutation may proceed.
52
+ */
53
+ export declare function refuseNonInteractiveMint(input: {
54
+ readonly verb: string;
55
+ readonly confirm: boolean;
56
+ readonly isTty: () => boolean;
57
+ readonly environ: NodeJS.ProcessEnv;
58
+ readonly hasControllingTerminal: () => boolean;
59
+ readonly readInteractiveConfirm: () => string | null;
60
+ }): number | null;
61
+ //# sourceMappingURL=human-presence-mint.d.ts.map
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Shared #3110 human-presence mint gate (#3384).
3
+ *
4
+ * Used by `authz` mutating verbs and `scope:record-approved-scope`. Multi-factor
5
+ * human presence: interactive TTY + controlling terminal + `--confirm` + typed
6
+ * phrase `mint`. Agent/CI env markers refuse fail-closed. `--actor` is never
7
+ * an input here — display only at the caller.
8
+ */
9
+ import { closeSync, openSync, readSync } from "node:fs";
10
+ import { loadAuthzState } from "@deftai/directive-core/authz";
11
+ /**
12
+ * Env markers that indicate an agent/host/CI shell even when stdin reports a TTY
13
+ * (pseudo-terminal residual; #3110 Greptile). Presence refuses mint.
14
+ * Expanded for dogfood conf 5/5 — markers are fail-closed (any non-empty value).
15
+ */
16
+ export const AUTHZ_AGENT_SHELL_ENV_MARKERS = [
17
+ // Coding agents / IDEs
18
+ "CLAUDECODE",
19
+ "CLAUDE_CODE",
20
+ "CLAUDE_CODE_ENTRYPOINT",
21
+ "CURSOR_AGENT",
22
+ "CURSOR_TRACE_ID",
23
+ "CURSOR_SESSION_ID",
24
+ "AIDER",
25
+ "CONTINUE_CLI",
26
+ "CODEX_SANDBOX",
27
+ "CODEX_CI",
28
+ "OPENAI_CODEX",
29
+ "OPENCLAW",
30
+ "OPENCLAW_STATE_DIR",
31
+ "DEFT_PROBE_OPENCLAW",
32
+ "DEFT_HOOK_HOST",
33
+ "DEFT_AGENT_SHELL",
34
+ "DEFT_AGENT_RUNTIME",
35
+ "WARP_SESSION_ID",
36
+ "WARP_HARNESS",
37
+ "WARP_RUN_ID",
38
+ "GEMINI_CLI",
39
+ "AMP_CLI",
40
+ "SWARM_AGENT",
41
+ "AI_AGENT",
42
+ // CI / automation (never a human interactive operator mint)
43
+ "CI",
44
+ "CONTINUOUS_INTEGRATION",
45
+ "GITHUB_ACTIONS",
46
+ "GITLAB_CI",
47
+ "CIRCLECI",
48
+ "BUILDKITE",
49
+ "TRAVIS",
50
+ "JENKINS_URL",
51
+ "TEAMCITY_VERSION",
52
+ "TF_BUILD",
53
+ "APPVEYOR",
54
+ "BITBUCKET_BUILD_NUMBER",
55
+ "CODEBUILD_BUILD_ID",
56
+ ];
57
+ /** Phrase an operator must type on the controlling TTY after --confirm (#3110). */
58
+ export const AUTHZ_INTERACTIVE_CONFIRM_PHRASE = "mint";
59
+ export function looksLikeAgentShell(environ) {
60
+ for (const key of AUTHZ_AGENT_SHELL_ENV_MARKERS) {
61
+ const v = environ[key];
62
+ if (v !== undefined && String(v).trim().length > 0)
63
+ return true;
64
+ }
65
+ return false;
66
+ }
67
+ function defaultIsTty() {
68
+ return process.stdin.isTTY === true && process.stdout.isTTY === true;
69
+ }
70
+ function defaultHasControllingTerminal() {
71
+ try {
72
+ const path = process.platform === "win32" ? "CONIN$" : "/dev/tty";
73
+ const fd = openSync(path, "r");
74
+ closeSync(fd);
75
+ return true;
76
+ }
77
+ catch {
78
+ return false;
79
+ }
80
+ }
81
+ function defaultReadInteractiveConfirm() {
82
+ // Read from the controlling terminal device — not redirected/piped stdin —
83
+ // so agent-controlled stdin alone cannot supply the confirm phrase (#3110).
84
+ let fd = null;
85
+ try {
86
+ const path = process.platform === "win32" ? "CONIN$" : "/dev/tty";
87
+ fd = openSync(path, "r");
88
+ const buf = Buffer.alloc(256);
89
+ const n = readSync(fd, buf, 0, buf.length, null);
90
+ if (n <= 0)
91
+ return null;
92
+ return buf.subarray(0, n).toString("utf8").trim();
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ finally {
98
+ if (fd !== null) {
99
+ try {
100
+ closeSync(fd);
101
+ }
102
+ catch {
103
+ /* ignore */
104
+ }
105
+ }
106
+ }
107
+ }
108
+ export function resolveHumanPresenceMintSeams(seams = {}) {
109
+ return {
110
+ isTty: seams.isTty ?? defaultIsTty,
111
+ environ: seams.environ ?? process.env,
112
+ hasControllingTerminal: seams.hasControllingTerminal ?? defaultHasControllingTerminal,
113
+ readInteractiveConfirm: seams.readInteractiveConfirm ?? defaultReadInteractiveConfirm,
114
+ };
115
+ }
116
+ /** Active UAT campaign id, or null when no lease is active. */
117
+ export function activeUatCampaignId(projectRoot) {
118
+ const state = loadAuthzState(projectRoot);
119
+ if (state.uat === null || !state.uat.active)
120
+ return null;
121
+ return state.uat.campaignId;
122
+ }
123
+ /**
124
+ * While any UAT lease is active, refuse mint (#3110 / #3384).
125
+ *
126
+ * No multi-factor escape: TTY, `--confirm`, and typed phrase never authorize.
127
+ * Returns an exit code when blocked, or null when mint may continue.
128
+ */
129
+ export function refuseMintWhileUatActive(verb, projectRoot) {
130
+ const campaignId = activeUatCampaignId(projectRoot);
131
+ if (campaignId === null)
132
+ return null;
133
+ process.stderr.write(`${verb}: refusing mint while UAT lease is ACTIVE (campaign=${campaignId}). ` +
134
+ "Under active UAT, mint is hard-refused — no TTY, --confirm, or phrase path " +
135
+ "authorizes remint (#3110 / #3384). Mint before uat-start; clear the lease " +
136
+ "out-of-band to end UAT.\n");
137
+ return 2;
138
+ }
139
+ /**
140
+ * Refuse non-interactive / agent-shell mint outside UAT (#3110 / #3384).
141
+ *
142
+ * Multi-factor human-presence gate (applies only when UAT lease is inactive):
143
+ * 1. No known agent/CI env markers
144
+ * 2. Interactive TTY (stdin + stdout isTTY)
145
+ * 3. Controlling terminal device present (`/dev/tty` / `CONIN$`)
146
+ * 4. Explicit argv `--confirm` (flag alone never enough)
147
+ * 5. Interactive typed phrase `mint` (argv --confirm alone never enough even on PTY)
148
+ *
149
+ * Fail-closed: if a real human interactive path cannot be proven, refuse mint.
150
+ * Returns an exit code when blocked, or null when the mutation may proceed.
151
+ */
152
+ export function refuseNonInteractiveMint(input) {
153
+ const { verb, confirm } = input;
154
+ if (looksLikeAgentShell(input.environ)) {
155
+ process.stderr.write(`${verb}: refusing operator-cli stamp from an agent/host/CI shell ` +
156
+ `(detected agent or CI env marker). Mint requires a human interactive ` +
157
+ "TTY without agent-shell markers, plus --confirm and typed phrase (#3110).\n");
158
+ return 2;
159
+ }
160
+ const tty = input.isTty();
161
+ if (!tty && !confirm) {
162
+ process.stderr.write(`${verb}: refusing non-interactive operator-cli stamp. ` +
163
+ "Mint requires interactive TTY, --confirm, and typed phrase " +
164
+ `'${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' (#3110).\n`);
165
+ return 2;
166
+ }
167
+ if (!tty) {
168
+ process.stderr.write(`${verb}: refusing non-TTY operator-cli stamp. ` +
169
+ "--confirm alone never authorizes mint — interactive TTY is required (#3110).\n");
170
+ return 2;
171
+ }
172
+ if (!confirm) {
173
+ process.stderr.write(`${verb}: refusing operator-cli stamp without --confirm. ` +
174
+ "Interactive TTY alone never authorizes mint — pass --confirm explicitly (#3110).\n");
175
+ return 2;
176
+ }
177
+ if (!input.hasControllingTerminal()) {
178
+ process.stderr.write(`${verb}: refusing operator-cli stamp without a controlling terminal. ` +
179
+ "Open a real interactive console (not a headless/agent pipe) to mint (#3110).\n");
180
+ return 2;
181
+ }
182
+ process.stderr.write(`${verb}: type '${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' and press Enter to confirm operator mint: `);
183
+ const line = input.readInteractiveConfirm();
184
+ const phrase = (line ?? "").trim().toLowerCase();
185
+ if (phrase !== AUTHZ_INTERACTIVE_CONFIRM_PHRASE) {
186
+ process.stderr.write(`\n${verb}: interactive confirm phrase mismatch (got ${JSON.stringify(line ?? "")}). ` +
187
+ `Type exactly '${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' on the controlling TTY (#3110).\n`);
188
+ return 2;
189
+ }
190
+ return null;
191
+ }
192
+ //# sourceMappingURL=human-presence-mint.js.map
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ export declare function parseArgs(argv: readonly string[]): {
3
+ projectRoot: string;
4
+ confirm: boolean;
5
+ occupant: string | null;
6
+ error?: string;
7
+ };
8
+ export declare function run(argv: readonly string[]): number;
9
+ //# sourceMappingURL=occupancy-steal.d.ts.map