@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.
Files changed (37) hide show
  1. package/dist/authz.d.ts +4 -29
  2. package/dist/authz.js +16 -181
  3. package/dist/cli-router/route-argv.js +1 -0
  4. package/dist/dispatch.d.ts +7 -1
  5. package/dist/dispatch.js +56 -20
  6. package/dist/human-presence-mint.d.ts +70 -0
  7. package/dist/human-presence-mint.js +203 -0
  8. package/dist/occupancy-steal.d.ts +9 -0
  9. package/dist/occupancy-steal.js +54 -0
  10. package/dist/plan-sequence.d.ts +10 -0
  11. package/dist/plan-sequence.js +3 -1
  12. package/dist/policy.d.ts +3 -2
  13. package/dist/policy.js +52 -7
  14. package/dist/preflight-cache.d.ts +2 -0
  15. package/dist/preflight-cache.js +7 -0
  16. package/dist/scm-sync-default.d.ts +34 -0
  17. package/dist/scm-sync-default.js +210 -0
  18. package/dist/scope-record-approved-scope.d.ts +6 -1
  19. package/dist/scope-record-approved-scope.js +72 -24
  20. package/dist/session-start.d.ts +4 -0
  21. package/dist/session-start.js +23 -0
  22. package/dist/triage-actions.js +2 -0
  23. package/dist/triage-queue.js +4 -1
  24. package/dist/verify-ac.d.ts +2 -0
  25. package/dist/verify-ac.js +30 -6
  26. package/dist/verify-completed-tracked.d.ts +2 -1
  27. package/dist/verify-completed-tracked.js +31 -1
  28. package/dist/verify-forward-coverage.d.ts +4 -0
  29. package/dist/verify-forward-coverage.js +77 -11
  30. package/dist/verify-lifecycle-visible.d.ts +13 -0
  31. package/dist/verify-lifecycle-visible.js +68 -0
  32. package/dist/verify-literal-ac.js +7 -0
  33. package/dist/verify-orphan-active.d.ts +1 -0
  34. package/dist/verify-orphan-active.js +30 -0
  35. package/dist/verify-session-ritual.d.ts +10 -2
  36. package/dist/verify-session-ritual.js +16 -3
  37. package/package.json +3 -3
@@ -0,0 +1,203 @@
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
+ /** Platform controlling-terminal path (`CONIN$` on win32, `/dev/tty` elsewhere). */
71
+ export function controllingTerminalPath(platform = process.platform) {
72
+ return platform === "win32" ? "CONIN$" : "/dev/tty";
73
+ }
74
+ /**
75
+ * Open flag for the platform controlling-terminal device (#3596).
76
+ *
77
+ * Windows `CONIN$` generally requires read/write (`r+`); `r` (O_RDONLY) fails
78
+ * in a real interactive console and made operator mint unreachable on win32.
79
+ */
80
+ export function controllingTerminalOpenFlag(platform = process.platform) {
81
+ return platform === "win32" ? "r+" : "r";
82
+ }
83
+ function defaultHasControllingTerminal() {
84
+ try {
85
+ const fd = openSync(controllingTerminalPath(), controllingTerminalOpenFlag());
86
+ closeSync(fd);
87
+ return true;
88
+ }
89
+ catch {
90
+ return false;
91
+ }
92
+ }
93
+ function defaultReadInteractiveConfirm() {
94
+ // Read from the controlling terminal device — not redirected/piped stdin —
95
+ // so agent-controlled stdin alone cannot supply the confirm phrase (#3110).
96
+ let fd = null;
97
+ try {
98
+ fd = openSync(controllingTerminalPath(), controllingTerminalOpenFlag());
99
+ const buf = Buffer.alloc(256);
100
+ const n = readSync(fd, buf, 0, buf.length, null);
101
+ if (n <= 0)
102
+ return null;
103
+ return buf.subarray(0, n).toString("utf8").trim();
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ finally {
109
+ if (fd !== null) {
110
+ try {
111
+ closeSync(fd);
112
+ }
113
+ catch {
114
+ /* ignore */
115
+ }
116
+ }
117
+ }
118
+ }
119
+ export function resolveHumanPresenceMintSeams(seams = {}) {
120
+ return {
121
+ isTty: seams.isTty ?? defaultIsTty,
122
+ environ: seams.environ ?? process.env,
123
+ hasControllingTerminal: seams.hasControllingTerminal ?? defaultHasControllingTerminal,
124
+ readInteractiveConfirm: seams.readInteractiveConfirm ?? defaultReadInteractiveConfirm,
125
+ };
126
+ }
127
+ /** Active UAT campaign id, or null when no lease is active. */
128
+ export function activeUatCampaignId(projectRoot) {
129
+ const state = loadAuthzState(projectRoot);
130
+ if (state.uat === null || !state.uat.active)
131
+ return null;
132
+ return state.uat.campaignId;
133
+ }
134
+ /**
135
+ * While any UAT lease is active, refuse mint (#3110 / #3384).
136
+ *
137
+ * No multi-factor escape: TTY, `--confirm`, and typed phrase never authorize.
138
+ * Returns an exit code when blocked, or null when mint may continue.
139
+ */
140
+ export function refuseMintWhileUatActive(verb, projectRoot) {
141
+ const campaignId = activeUatCampaignId(projectRoot);
142
+ if (campaignId === null)
143
+ return null;
144
+ process.stderr.write(`${verb}: refusing mint while UAT lease is ACTIVE (campaign=${campaignId}). ` +
145
+ "Under active UAT, mint is hard-refused — no TTY, --confirm, or phrase path " +
146
+ "authorizes remint (#3110 / #3384). Mint before uat-start; clear the lease " +
147
+ "out-of-band to end UAT.\n");
148
+ return 2;
149
+ }
150
+ /**
151
+ * Refuse non-interactive / agent-shell mint outside UAT (#3110 / #3384).
152
+ *
153
+ * Multi-factor human-presence gate (applies only when UAT lease is inactive):
154
+ * 1. No known agent/CI env markers
155
+ * 2. Interactive TTY (stdin + stdout isTTY)
156
+ * 3. Controlling terminal device present (`/dev/tty` / `CONIN$`)
157
+ * 4. Explicit argv `--confirm` (flag alone never enough)
158
+ * 5. Interactive typed phrase `mint` (argv --confirm alone never enough even on PTY)
159
+ *
160
+ * Fail-closed: if a real human interactive path cannot be proven, refuse mint.
161
+ * Returns an exit code when blocked, or null when the mutation may proceed.
162
+ */
163
+ export function refuseNonInteractiveMint(input) {
164
+ const { verb, confirm } = input;
165
+ if (looksLikeAgentShell(input.environ)) {
166
+ process.stderr.write(`${verb}: refusing operator-cli stamp from an agent/host/CI shell ` +
167
+ `(detected agent or CI env marker). Mint requires a human interactive ` +
168
+ "TTY without agent-shell markers, plus --confirm and typed phrase (#3110).\n");
169
+ return 2;
170
+ }
171
+ const tty = input.isTty();
172
+ if (!tty && !confirm) {
173
+ process.stderr.write(`${verb}: refusing non-interactive operator-cli stamp. ` +
174
+ "Mint requires interactive TTY, --confirm, and typed phrase " +
175
+ `'${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' (#3110).\n`);
176
+ return 2;
177
+ }
178
+ if (!tty) {
179
+ process.stderr.write(`${verb}: refusing non-TTY operator-cli stamp. ` +
180
+ "--confirm alone never authorizes mint — interactive TTY is required (#3110).\n");
181
+ return 2;
182
+ }
183
+ if (!confirm) {
184
+ process.stderr.write(`${verb}: refusing operator-cli stamp without --confirm. ` +
185
+ "Interactive TTY alone never authorizes mint — pass --confirm explicitly (#3110).\n");
186
+ return 2;
187
+ }
188
+ if (!input.hasControllingTerminal()) {
189
+ process.stderr.write(`${verb}: refusing operator-cli stamp without a controlling terminal. ` +
190
+ "Open a real interactive console (not a headless/agent pipe) to mint (#3110).\n");
191
+ return 2;
192
+ }
193
+ process.stderr.write(`${verb}: type '${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' and press Enter to confirm operator mint: `);
194
+ const line = input.readInteractiveConfirm();
195
+ const phrase = (line ?? "").trim().toLowerCase();
196
+ if (phrase !== AUTHZ_INTERACTIVE_CONFIRM_PHRASE) {
197
+ process.stderr.write(`\n${verb}: interactive confirm phrase mismatch (got ${JSON.stringify(line ?? "")}). ` +
198
+ `Type exactly '${AUTHZ_INTERACTIVE_CONFIRM_PHRASE}' on the controlling TTY (#3110).\n`);
199
+ return 2;
200
+ }
201
+ return null;
202
+ }
203
+ //# 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
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import { stealOccupancy } from "@deftai/directive-core/session";
4
+ export function parseArgs(argv) {
5
+ const parsed = { projectRoot: ".", confirm: false, occupant: null };
6
+ for (let i = 0; i < argv.length; i += 1) {
7
+ const arg = argv[i];
8
+ if (arg === "--confirm") {
9
+ parsed.confirm = true;
10
+ }
11
+ else if (arg === "--occupant") {
12
+ const value = argv[i + 1];
13
+ if (value === undefined) {
14
+ return { ...parsed, error: "argument --occupant: expected one argument" };
15
+ }
16
+ parsed.occupant = value;
17
+ i += 1;
18
+ }
19
+ else if (arg?.startsWith("--occupant=")) {
20
+ parsed.occupant = arg.slice("--occupant=".length);
21
+ }
22
+ else if (arg === "--project-root") {
23
+ const value = argv[i + 1];
24
+ if (value === undefined) {
25
+ return { ...parsed, error: "argument --project-root: expected one argument" };
26
+ }
27
+ parsed.projectRoot = value;
28
+ i += 1;
29
+ }
30
+ else if (arg?.startsWith("--project-root=")) {
31
+ parsed.projectRoot = arg.slice("--project-root=".length);
32
+ }
33
+ else {
34
+ return { ...parsed, error: `unrecognized argument: ${arg}` };
35
+ }
36
+ }
37
+ return parsed;
38
+ }
39
+ export function run(argv) {
40
+ const args = parseArgs(argv);
41
+ if (args.error !== undefined) {
42
+ process.stderr.write(`occupancy:steal: ${args.error}\n`);
43
+ return 2;
44
+ }
45
+ const result = stealOccupancy(resolve(args.projectRoot), {
46
+ confirm: args.confirm,
47
+ occupant: args.occupant ?? undefined,
48
+ env: process.env,
49
+ });
50
+ const sink = result.code === 0 ? process.stdout : process.stderr;
51
+ sink.write(`${result.message}\n`);
52
+ return result.code;
53
+ }
54
+ //# sourceMappingURL=occupancy-steal.js.map
@@ -1,3 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ interface Parsed {
3
+ projectRoot: string;
4
+ action: "set" | "current" | "clear" | "advance" | null;
5
+ file: string | null;
6
+ jsonInline: string | null;
7
+ emitJson: boolean;
8
+ error?: string;
9
+ }
10
+ export declare function parseArgs(argv: string[]): Parsed;
2
11
  export declare function main(argv?: string[]): number;
12
+ export {};
3
13
  //# sourceMappingURL=plan-sequence.d.ts.map
@@ -6,7 +6,7 @@ import { readFileSync } from "node:fs";
6
6
  import { resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { advancePlanSequence, clearPlanSequence, createPlanSequence, parsePlanSequence, readPlanSequence, writePlanSequence, } from "@deftai/directive-core/plan-sequence";
9
- function parseArgs(argv) {
9
+ export function parseArgs(argv) {
10
10
  const parsed = {
11
11
  projectRoot: ".",
12
12
  action: null,
@@ -19,6 +19,8 @@ function parseArgs(argv) {
19
19
  const arg = argv[i];
20
20
  if (arg === undefined)
21
21
  continue;
22
+ if (arg === "--")
23
+ continue;
22
24
  if (arg === "--json") {
23
25
  parsed.emitJson = true;
24
26
  }
package/dist/policy.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { type CeremonyDepth } from "@deftai/directive-core/policy";
2
+ import { type CeremonyDepth, type HookHost } from "@deftai/directive-core/policy";
3
3
  interface ShowArgs {
4
4
  format: "text" | "json";
5
5
  changedOnly: boolean;
@@ -8,10 +8,11 @@ interface ShowArgs {
8
8
  error?: string;
9
9
  }
10
10
  interface SetArgs {
11
- cmd: "show" | "enforce-branches" | "allow-direct-commits" | "allow-bot-merge" | "enable-value-feedback" | "clear-value-feedback" | "set-ceremony-dial" | "disable-directive" | "enable-directive" | "resolve";
11
+ cmd: "show" | "enforce-branches" | "allow-direct-commits" | "allow-bot-merge" | "enable-value-feedback" | "clear-value-feedback" | "set-ceremony-dial" | "disable-host-hooks" | "disable-directive" | "enable-directive" | "resolve";
12
12
  confirm: boolean;
13
13
  actor: string;
14
14
  note: string;
15
+ host?: HookHost;
15
16
  projectRoot: string;
16
17
  format: "text" | "json";
17
18
  changedOnly: boolean;
package/dist/policy.js CHANGED
@@ -6,7 +6,7 @@
6
6
  import { existsSync } from "node:fs";
7
7
  import { resolve as pathResolve, relative } from "node:path";
8
8
  import { fileURLToPath } from "node:url";
9
- import { ALLOW_BOT_MERGE_CAPABILITY_COST, CEREMONY_DEPTHS, clearValueFeedback, createNoDeftDirectiveFlag, describeShadowedPlanExtension, detectNoDeftDirective, detectShadowedPlanExtensions, disclosureLine, enableValueFeedback, FIELD_VALUE_FEEDBACK, FIELD_VALUE_FEEDBACK_CLI_ALIAS, formatValueFeedbackStatusLine, humanMergeDisclosureLine, inspectAllPolicies, inspectOnePolicy, loadProjectDefinition, NO_DEFT_DIRECTIVE_DISABLED_MESSAGE, NO_DEFT_DIRECTIVE_FLAG_NAME, NO_DEFT_DIRECTIVE_INCONSISTENT_MESSAGE, policyColonInvocation, projectDefinitionPath, pythonListRepr, pythonStringRepr, registeredPolicyNames, removeNoDeftDirectiveFlag, renderJson, renderText, resolveHumanMergePolicy, resolvePolicy, resolveValueFeedback, setCeremonyDial, setPolicy, setRequireHumanMerge, } from "@deftai/directive-core/policy";
9
+ import { ALLOW_BOT_MERGE_CAPABILITY_COST, CEREMONY_DEPTHS, clearValueFeedback, createNoDeftDirectiveFlag, describeShadowedPlanExtension, detectNoDeftDirective, detectShadowedPlanExtensions, disableHostHooks, disclosureLine, enableValueFeedback, FIELD_VALUE_FEEDBACK, FIELD_VALUE_FEEDBACK_CLI_ALIAS, formatValueFeedbackStatusLine, humanMergeDisclosureLine, inspectAllPolicies, inspectOnePolicy, loadProjectDefinition, NO_DEFT_DIRECTIVE_DISABLED_MESSAGE, NO_DEFT_DIRECTIVE_FLAG_NAME, NO_DEFT_DIRECTIVE_INCONSISTENT_MESSAGE, POLICY_AUDIT_NOOP_STDOUT, parseHookHost, policyColonInvocation, projectDefinitionPath, pythonListRepr, pythonStringRepr, registeredPolicyNames, removeNoDeftDirectiveFlag, renderJson, renderText, resolveHumanMergePolicy, resolvePolicy, resolveValueFeedback, setCeremonyDial, setPolicy, setRequireHumanMerge, } from "@deftai/directive-core/policy";
10
10
  const CAPABILITY_COST_DISCLOSURE = "\u26a0 Capability-cost disclosure -- enabling direct commits to the default " +
11
11
  "branch turns OFF the deft branch-protection policy.\n" +
12
12
  " \u2022 Pre-commit + pre-push hooks will no longer block default-branch " +
@@ -114,7 +114,7 @@ export function parseShowArgs(argv) {
114
114
  /** Parse argv for the policy CLI (show + set subcommands). */
115
115
  export function parseArgs(argv) {
116
116
  if (argv.length === 0) {
117
- const usage = "usage: policy [show|enforce-branches|allow-direct-commits|allow-bot-merge|enable-value-feedback|clear-value-feedback|set-ceremony-dial|disable-directive|enable-directive|resolve] ...";
117
+ const usage = "usage: policy [show|enforce-branches|allow-direct-commits|allow-bot-merge|enable-value-feedback|clear-value-feedback|set-ceremony-dial|disable-host-hooks|disable-directive|enable-directive|resolve] ...";
118
118
  return makeSetError(usage);
119
119
  }
120
120
  const cmd = argv[0];
@@ -152,6 +152,7 @@ export function parseArgs(argv) {
152
152
  cmd === "enable-value-feedback" ||
153
153
  cmd === "clear-value-feedback" ||
154
154
  cmd === "set-ceremony-dial" ||
155
+ cmd === "disable-host-hooks" ||
155
156
  cmd === "disable-directive" ||
156
157
  cmd === "enable-directive") {
157
158
  let confirm = false;
@@ -167,11 +168,14 @@ export function parseArgs(argv) {
167
168
  ? policyColonInvocation("clear-value-feedback")
168
169
  : cmd === "set-ceremony-dial"
169
170
  ? policyColonInvocation("set-ceremony-dial")
170
- : cmd === "disable-directive"
171
- ? policyColonInvocation("disable-directive")
172
- : policyColonInvocation("enable-directive");
171
+ : cmd === "disable-host-hooks"
172
+ ? policyColonInvocation("disable-host-hooks")
173
+ : cmd === "disable-directive"
174
+ ? policyColonInvocation("disable-directive")
175
+ : policyColonInvocation("enable-directive");
173
176
  let note = "";
174
177
  let projectRoot = ".";
178
+ let host;
175
179
  let ceremonyOverride;
176
180
  let ceremonyEnabled;
177
181
  for (let i = 1; i < argv.length; i += 1) {
@@ -253,10 +257,32 @@ export function parseArgs(argv) {
253
257
  }
254
258
  ceremonyEnabled = v === "true";
255
259
  }
260
+ else if (cmd === "disable-host-hooks" && arg === "--host") {
261
+ const v = argv[i + 1];
262
+ const parsedHost = parseHookHost(v);
263
+ if (parsedHost === null) {
264
+ return makeSetError("argument --host: expected claude|cursor|grok|codex");
265
+ }
266
+ host = parsedHost;
267
+ i += 1;
268
+ }
269
+ else if (cmd === "disable-host-hooks" && arg?.startsWith("--host=")) {
270
+ const parsedHost = parseHookHost(arg.slice("--host=".length));
271
+ if (parsedHost === null) {
272
+ return makeSetError("argument --host: expected claude|cursor|grok|codex");
273
+ }
274
+ host = parsedHost;
275
+ }
276
+ else if (arg === "--") {
277
+ continue;
278
+ }
256
279
  else {
257
280
  return makeSetError(`unrecognized argument: ${arg}`);
258
281
  }
259
282
  }
283
+ if (cmd === "disable-host-hooks" && host === undefined) {
284
+ return makeSetError("disable-host-hooks requires --host claude|cursor|grok|codex");
285
+ }
260
286
  return {
261
287
  cmd,
262
288
  confirm,
@@ -266,6 +292,7 @@ export function parseArgs(argv) {
266
292
  format: "text",
267
293
  changedOnly: false,
268
294
  field: null,
295
+ host,
269
296
  ceremonyOverride,
270
297
  ceremonyEnabled,
271
298
  };
@@ -352,6 +379,21 @@ function runEnableValueFeedback(args) {
352
379
  process.stdout.write(result.stdout);
353
380
  return result.exitCode;
354
381
  }
382
+ function runDisableHostHooks(args) {
383
+ const host = args.host;
384
+ if (host === undefined) {
385
+ process.stderr.write("policy: disable-host-hooks requires --host claude|cursor|grok|codex\n");
386
+ return 2;
387
+ }
388
+ const result = disableHostHooks(pathResolve(args.projectRoot), {
389
+ host,
390
+ confirm: args.confirm,
391
+ actor: args.actor,
392
+ note: args.note,
393
+ });
394
+ process.stdout.write(result.stdout);
395
+ return result.exitCode;
396
+ }
355
397
  function runSet(args) {
356
398
  const projectRoot = pathResolve(args.projectRoot);
357
399
  if (args.cmd === "allow-direct-commits" && !args.confirm) {
@@ -373,7 +415,7 @@ function runSet(args) {
373
415
  process.stdout.write(` audit: meta/policy-changes.log :: ${auditEntry}\n`);
374
416
  }
375
417
  else {
376
- process.stdout.write(" no-op: value already matched (audit entry still appended for trail).\n");
418
+ process.stdout.write(`${POLICY_AUDIT_NOOP_STDOUT}\n`);
377
419
  }
378
420
  process.stdout.write(`${disclosureLine(resolvePolicy(projectRoot))}\n`);
379
421
  return 0;
@@ -454,7 +496,7 @@ function runAllowBotMerge(args) {
454
496
  process.stdout.write(` audit: meta/policy-changes.log :: ${auditEntry}\n`);
455
497
  }
456
498
  else {
457
- process.stdout.write(" no-op: value already matched (audit entry still appended for trail).\n");
499
+ process.stdout.write(`${POLICY_AUDIT_NOOP_STDOUT}\n`);
458
500
  }
459
501
  const line = humanMergeDisclosureLine(resolveHumanMergePolicy(projectRoot));
460
502
  if (line !== null) {
@@ -504,6 +546,9 @@ export function run(argv) {
504
546
  if (args.cmd === "enable-value-feedback") {
505
547
  return runEnableValueFeedback(args);
506
548
  }
549
+ if (args.cmd === "disable-host-hooks") {
550
+ return runDisableHostHooks(args);
551
+ }
507
552
  if (args.cmd === "clear-value-feedback") {
508
553
  return runClearValueFeedback(args);
509
554
  }
@@ -7,6 +7,8 @@ interface ParsedArgs {
7
7
  forIssue?: number;
8
8
  allowStale?: boolean;
9
9
  allowMissingBootstrap?: boolean;
10
+ skipDriftProbe?: boolean;
11
+ workSelection?: boolean;
10
12
  quiet?: boolean;
11
13
  error?: string;
12
14
  }
@@ -58,6 +58,12 @@ export function parseArgs(argv) {
58
58
  else if (arg === "--allow-missing-bootstrap") {
59
59
  parsed.allowMissingBootstrap = true;
60
60
  }
61
+ else if (arg === "--skip-drift-probe") {
62
+ parsed.skipDriftProbe = true;
63
+ }
64
+ else if (arg === "--work-selection") {
65
+ parsed.workSelection = true;
66
+ }
61
67
  else if (arg === "--quiet") {
62
68
  parsed.quiet = true;
63
69
  }
@@ -81,6 +87,7 @@ export function run(argv) {
81
87
  forIssue: args.forIssue ?? null,
82
88
  allowStale: args.allowStale ?? false,
83
89
  allowMissingBootstrap: args.allowMissingBootstrap ?? false,
90
+ skipDriftProbe: (args.skipDriftProbe ?? false) && !args.workSelection,
84
91
  });
85
92
  const quiet = args.quiet ?? false;
86
93
  if (result.code === 0) {
@@ -0,0 +1,34 @@
1
+ /**
2
+ * CLI for `scm:sync-default` (#3391).
3
+ *
4
+ * Opens dest-targeted default-branch sync PRs using the shared detector and
5
+ * syncMaxFiles. Over-limit legs are new branches and new PRs.
6
+ */
7
+ import { planSyncDefault, type SyncDefaultForge, type SyncDefaultOpenPull } from "@deftai/directive-core/policy";
8
+ export declare const USAGE: string;
9
+ export interface SyncDefaultCliArgs {
10
+ readonly dryRun?: boolean;
11
+ readonly json?: boolean;
12
+ readonly help?: boolean;
13
+ readonly maxFiles?: number;
14
+ readonly projectRoot?: string;
15
+ readonly repo?: string;
16
+ }
17
+ export declare function parseSyncDefaultArgs(argv: readonly string[]): {
18
+ args: SyncDefaultCliArgs;
19
+ error: string | null;
20
+ };
21
+ export declare function pullsFromRestJson(payload: unknown): readonly SyncDefaultOpenPull[];
22
+ export declare function createGhSyncDefaultForge(): SyncDefaultForge;
23
+ export declare function resolveRepoFromGit(projectRoot: string): string | null;
24
+ export declare function runSyncDefaultCli(args: SyncDefaultCliArgs, options?: {
25
+ writeOut?: (s: string) => void;
26
+ writeErr?: (s: string) => void;
27
+ forge?: SyncDefaultForge;
28
+ cwd?: string;
29
+ runGit?: Parameters<typeof planSyncDefault>[0]["runGit"];
30
+ resolveRepo?: (projectRoot: string) => string | null;
31
+ }): number;
32
+ export declare function mainEntry(argv?: string[]): number;
33
+ export declare function main(argv?: string[]): number;
34
+ //# sourceMappingURL=scm-sync-default.d.ts.map