@zigrivers/mmr 1.3.0 → 1.4.1

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 (130) hide show
  1. package/README.md +444 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +4 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/ack.d.ts +11 -0
  6. package/dist/commands/ack.d.ts.map +1 -0
  7. package/dist/commands/ack.js +123 -0
  8. package/dist/commands/ack.js.map +1 -0
  9. package/dist/commands/config.d.ts +5 -0
  10. package/dist/commands/config.d.ts.map +1 -1
  11. package/dist/commands/config.js +248 -14
  12. package/dist/commands/config.js.map +1 -1
  13. package/dist/commands/jobs.d.ts.map +1 -1
  14. package/dist/commands/jobs.js +3 -4
  15. package/dist/commands/jobs.js.map +1 -1
  16. package/dist/commands/reconcile.d.ts.map +1 -1
  17. package/dist/commands/reconcile.js +12 -5
  18. package/dist/commands/reconcile.js.map +1 -1
  19. package/dist/commands/results.d.ts.map +1 -1
  20. package/dist/commands/results.js +13 -5
  21. package/dist/commands/results.js.map +1 -1
  22. package/dist/commands/review.d.ts +25 -0
  23. package/dist/commands/review.d.ts.map +1 -1
  24. package/dist/commands/review.js +459 -44
  25. package/dist/commands/review.js.map +1 -1
  26. package/dist/commands/sessions.d.ts +58 -0
  27. package/dist/commands/sessions.d.ts.map +1 -0
  28. package/dist/commands/sessions.js +266 -0
  29. package/dist/commands/sessions.js.map +1 -0
  30. package/dist/commands/status.d.ts.map +1 -1
  31. package/dist/commands/status.js +2 -3
  32. package/dist/commands/status.js.map +1 -1
  33. package/dist/config/defaults.d.ts +2 -2
  34. package/dist/config/defaults.d.ts.map +1 -1
  35. package/dist/config/defaults.js +76 -0
  36. package/dist/config/defaults.js.map +1 -1
  37. package/dist/config/loader.d.ts +22 -0
  38. package/dist/config/loader.d.ts.map +1 -1
  39. package/dist/config/loader.js +279 -36
  40. package/dist/config/loader.js.map +1 -1
  41. package/dist/config/schema.d.ts +897 -53
  42. package/dist/config/schema.d.ts.map +1 -1
  43. package/dist/config/schema.js +155 -4
  44. package/dist/config/schema.js.map +1 -1
  45. package/dist/core/ack-store.d.ts +109 -0
  46. package/dist/core/ack-store.d.ts.map +1 -0
  47. package/dist/core/ack-store.js +363 -0
  48. package/dist/core/ack-store.js.map +1 -0
  49. package/dist/core/auth.d.ts +10 -1
  50. package/dist/core/auth.d.ts.map +1 -1
  51. package/dist/core/auth.js +106 -35
  52. package/dist/core/auth.js.map +1 -1
  53. package/dist/core/compensator.d.ts +33 -4
  54. package/dist/core/compensator.d.ts.map +1 -1
  55. package/dist/core/compensator.js +120 -15
  56. package/dist/core/compensator.js.map +1 -1
  57. package/dist/core/diff-introspect.d.ts +21 -0
  58. package/dist/core/diff-introspect.d.ts.map +1 -0
  59. package/dist/core/diff-introspect.js +42 -0
  60. package/dist/core/diff-introspect.js.map +1 -0
  61. package/dist/core/dispatcher.d.ts +10 -0
  62. package/dist/core/dispatcher.d.ts.map +1 -1
  63. package/dist/core/dispatcher.js +91 -20
  64. package/dist/core/dispatcher.js.map +1 -1
  65. package/dist/core/git-show.d.ts +31 -0
  66. package/dist/core/git-show.d.ts.map +1 -0
  67. package/dist/core/git-show.js +72 -0
  68. package/dist/core/git-show.js.map +1 -0
  69. package/dist/core/host-isolation.d.ts +24 -0
  70. package/dist/core/host-isolation.d.ts.map +1 -0
  71. package/dist/core/host-isolation.js +107 -0
  72. package/dist/core/host-isolation.js.map +1 -0
  73. package/dist/core/http-dispatcher.d.ts +20 -0
  74. package/dist/core/http-dispatcher.d.ts.map +1 -0
  75. package/dist/core/http-dispatcher.js +125 -0
  76. package/dist/core/http-dispatcher.js.map +1 -0
  77. package/dist/core/job-store.d.ts +7 -1
  78. package/dist/core/job-store.d.ts.map +1 -1
  79. package/dist/core/job-store.js +21 -1
  80. package/dist/core/job-store.js.map +1 -1
  81. package/dist/core/jsonpath.d.ts +15 -0
  82. package/dist/core/jsonpath.d.ts.map +1 -0
  83. package/dist/core/jsonpath.js +63 -0
  84. package/dist/core/jsonpath.js.map +1 -0
  85. package/dist/core/oss-examples.d.ts +18 -0
  86. package/dist/core/oss-examples.d.ts.map +1 -0
  87. package/dist/core/oss-examples.js +66 -0
  88. package/dist/core/oss-examples.js.map +1 -0
  89. package/dist/core/parser.d.ts +8 -3
  90. package/dist/core/parser.d.ts.map +1 -1
  91. package/dist/core/parser.js +157 -6
  92. package/dist/core/parser.js.map +1 -1
  93. package/dist/core/project-root.d.ts +10 -0
  94. package/dist/core/project-root.d.ts.map +1 -0
  95. package/dist/core/project-root.js +23 -0
  96. package/dist/core/project-root.js.map +1 -0
  97. package/dist/core/reconciler.d.ts +1 -1
  98. package/dist/core/reconciler.d.ts.map +1 -1
  99. package/dist/core/reconciler.js +100 -18
  100. package/dist/core/reconciler.js.map +1 -1
  101. package/dist/core/redact.d.ts +17 -0
  102. package/dist/core/redact.d.ts.map +1 -0
  103. package/dist/core/redact.js +140 -0
  104. package/dist/core/redact.js.map +1 -0
  105. package/dist/core/results-pipeline.d.ts +8 -2
  106. package/dist/core/results-pipeline.d.ts.map +1 -1
  107. package/dist/core/results-pipeline.js +50 -3
  108. package/dist/core/results-pipeline.js.map +1 -1
  109. package/dist/core/runtime-probe.d.ts +14 -0
  110. package/dist/core/runtime-probe.d.ts.map +1 -0
  111. package/dist/core/runtime-probe.js +57 -0
  112. package/dist/core/runtime-probe.js.map +1 -0
  113. package/dist/core/stable-id.d.ts +19 -0
  114. package/dist/core/stable-id.d.ts.map +1 -0
  115. package/dist/core/stable-id.js +148 -0
  116. package/dist/core/stable-id.js.map +1 -0
  117. package/dist/core/trust-mode.d.ts +29 -0
  118. package/dist/core/trust-mode.d.ts.map +1 -0
  119. package/dist/core/trust-mode.js +103 -0
  120. package/dist/core/trust-mode.js.map +1 -0
  121. package/dist/formatters/markdown.d.ts.map +1 -1
  122. package/dist/formatters/markdown.js +9 -0
  123. package/dist/formatters/markdown.js.map +1 -1
  124. package/dist/formatters/text.d.ts.map +1 -1
  125. package/dist/formatters/text.js +9 -0
  126. package/dist/formatters/text.js.map +1 -1
  127. package/dist/types.d.ts +44 -1
  128. package/dist/types.d.ts.map +1 -1
  129. package/dist/types.js.map +1 -1
  130. package/package.json +2 -2
@@ -1,4 +1,5 @@
1
1
  import { dispatchChannel } from './dispatcher.js';
2
+ import { dispatchHttpChannel } from './http-dispatcher.js';
2
3
  /** Focus areas for compensating passes, keyed by the channel being compensated */
3
4
  const COMPENSATING_FOCUS = {
4
5
  codex: 'Focus your review on: implementation correctness, security vulnerabilities,'
@@ -7,30 +8,115 @@ const COMPENSATING_FOCUS = {
7
8
  gemini: 'Focus your review on: architectural patterns, design consistency,'
8
9
  + ' broad-context reasoning, separation of concerns, and dependency analysis.'
9
10
  + ' You are compensating for a missing Gemini review.',
11
+ grok: 'Focus your review on: an independent second-opinion pass over correctness'
12
+ + ' and code quality — edge cases, logic errors, and risky assumptions other'
13
+ + ' reviewers may have anchored past. You are compensating for a missing Grok review.',
10
14
  };
11
- /** Channels that should NOT be compensated (e.g., claude can't compensate for itself) */
12
- const SKIP_COMPENSATION = new Set(['claude']);
15
+ function defaultCompensatorDispatch(config) {
16
+ return {
17
+ command: 'claude',
18
+ flags: ['-p', '--output-format', 'json'],
19
+ env: {},
20
+ timeout: config.defaults.timeout,
21
+ prompt_wrapper: '{{prompt}}',
22
+ stderr: 'capture',
23
+ output_parser: 'default',
24
+ };
25
+ }
26
+ export function resolveCompensatorDispatch(config) {
27
+ const { defaults } = config;
28
+ const channelName = defaults.compensator?.channel;
29
+ if (!channelName) {
30
+ return defaultCompensatorDispatch(config);
31
+ }
32
+ const channelConfig = getDispatchableCompensatorChannel(config, channelName);
33
+ return {
34
+ command: channelConfig.command,
35
+ flags: channelConfig.flags,
36
+ env: channelConfig.env,
37
+ timeout: channelConfig.timeout ?? config.defaults.timeout,
38
+ prompt_wrapper: channelConfig.prompt_wrapper ?? '{{prompt}}',
39
+ stderr: channelConfig.stderr,
40
+ output_parser: channelConfig.output_parser,
41
+ prompt_delivery: channelConfig.prompt_delivery,
42
+ cwd: channelConfig.cwd,
43
+ };
44
+ }
45
+ export function resolveCompensatorChannelName(config) {
46
+ return config.defaults.compensator?.channel ?? 'claude';
47
+ }
48
+ /**
49
+ * Resolve the configured compensator channel config (any kind), or undefined
50
+ * when none is configured (the default `claude -p` subprocess fallback applies).
51
+ * Throws only for a missing / abstract reference. Unlike
52
+ * getDispatchableCompensatorChannel this does NOT require a `command`, so it is
53
+ * safe for http compensators.
54
+ */
55
+ export function getCompensatorChannel(config) {
56
+ const channelName = config.defaults.compensator?.channel;
57
+ if (!channelName)
58
+ return undefined;
59
+ const channelConfig = config.channels[channelName];
60
+ if (!channelConfig) {
61
+ throw new Error(`Compensator channel "${channelName}" not found in config`);
62
+ }
63
+ if (channelConfig.abstract) {
64
+ throw new Error(`Compensator channel "${channelName}" is abstract and cannot be dispatched`);
65
+ }
66
+ return channelConfig;
67
+ }
68
+ /** Output parser for the configured compensator channel (any kind); 'default' when none. */
69
+ export function resolveCompensatorOutputParser(config) {
70
+ return getCompensatorChannel(config)?.output_parser ?? 'default';
71
+ }
72
+ export function getDispatchableCompensatorChannel(config, channelName) {
73
+ const channelConfig = config.channels[channelName];
74
+ if (!channelConfig) {
75
+ throw new Error(`Compensator channel "${channelName}" not found in config`);
76
+ }
77
+ if (channelConfig.abstract) {
78
+ throw new Error(`Compensator channel "${channelName}" is abstract and cannot be dispatched`);
79
+ }
80
+ if (!channelConfig.command) {
81
+ throw new Error(`Compensator channel "${channelName}" has no command`);
82
+ }
83
+ return channelConfig;
84
+ }
85
+ function applyPromptWrapper(wrapper, prompt) {
86
+ return wrapper === '{{prompt}}'
87
+ ? prompt
88
+ : wrapper.replaceAll('{{prompt}}', () => prompt);
89
+ }
90
+ /**
91
+ * Resolve the focus-area prompt prefix for a compensating pass.
92
+ */
93
+ export function resolveCompensatorFocus(config, originalChannel) {
94
+ const override = config.defaults.compensator?.channel_focus_map?.[originalChannel];
95
+ if (typeof override === 'string' && override.trim().length > 0)
96
+ return override;
97
+ const builtin = COMPENSATING_FOCUS[originalChannel];
98
+ if (builtin)
99
+ return builtin;
100
+ return `Focus your review on areas typically covered by ${originalChannel}.`
101
+ + ` You are compensating for a missing ${originalChannel} review.`;
102
+ }
13
103
  /**
14
104
  * Determine which channels need compensating passes.
15
105
  * Returns a list of compensating channel descriptors.
16
106
  */
17
- export function getCompensatingChannels(channelStatuses) {
107
+ export function getCompensatingChannels(channelStatuses, compensatorChannel) {
18
108
  const compensating = [];
19
109
  for (const [name, status] of Object.entries(channelStatuses)) {
20
- if (SKIP_COMPENSATION.has(name))
110
+ if (name === compensatorChannel)
21
111
  continue;
22
112
  if (status === 'not_installed'
23
113
  || status === 'auth_failed'
24
114
  || status === 'timeout'
25
115
  || status === 'skipped'
26
116
  || status === 'failed') {
27
- const focus = COMPENSATING_FOCUS[name]
28
- ?? `Focus your review on areas typically covered by ${name}.`
29
- + ` You are compensating for a missing ${name} review.`;
30
117
  compensating.push({
31
118
  originalChannel: name,
32
119
  compensatingName: `compensating-${name}`,
33
- focusPrompt: focus,
34
120
  });
35
121
  }
36
122
  }
@@ -40,16 +126,35 @@ export function getCompensatingChannels(channelStatuses) {
40
126
  * Dispatch compensating passes via claude CLI for unavailable channels.
41
127
  * Each compensating pass uses the same prompt but with a focused preamble.
42
128
  */
43
- export async function dispatchCompensatingPasses(store, jobId, prompt, compensatingChannels, timeout) {
129
+ export async function dispatchCompensatingPasses(store, jobId, prompt, compensatingChannels, config) {
130
+ const compChannel = getCompensatorChannel(config);
131
+ // HTTP compensator: route each pass through the HTTP dispatcher.
132
+ if (compChannel && compChannel.kind === 'http') {
133
+ await Promise.all(compensatingChannels.map((comp) => {
134
+ const focus = resolveCompensatorFocus(config, comp.originalChannel);
135
+ const compensatingPrompt = applyPromptWrapper(compChannel.prompt_wrapper ?? '{{prompt}}', `${focus}\n\n${prompt}`);
136
+ return dispatchHttpChannel(store, jobId, comp.compensatingName, {
137
+ channel: compChannel,
138
+ prompt: compensatingPrompt,
139
+ timeout: compChannel.timeout ?? config.defaults.timeout,
140
+ });
141
+ }));
142
+ return;
143
+ }
144
+ // Subprocess compensator (default `claude -p` or a configured command).
145
+ const dispatch = resolveCompensatorDispatch(config);
44
146
  await Promise.all(compensatingChannels.map((comp) => {
45
- const compensatingPrompt = `${comp.focusPrompt}\n\n${prompt}`;
147
+ const focus = resolveCompensatorFocus(config, comp.originalChannel);
148
+ const compensatingPrompt = applyPromptWrapper(dispatch.prompt_wrapper, `${focus}\n\n${prompt}`);
46
149
  return dispatchChannel(store, jobId, comp.compensatingName, {
47
- command: 'claude -p',
150
+ command: dispatch.command,
48
151
  prompt: compensatingPrompt,
49
- flags: ['--output-format', 'json'],
50
- env: {},
51
- timeout,
52
- stderr: 'capture',
152
+ flags: dispatch.flags,
153
+ env: dispatch.env,
154
+ timeout: dispatch.timeout,
155
+ stderr: dispatch.stderr,
156
+ promptDelivery: dispatch.prompt_delivery,
157
+ cwd: dispatch.cwd,
53
158
  });
54
159
  }));
55
160
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compensator.js","sourceRoot":"","sources":["../../src/core/compensator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAIjD,kFAAkF;AAClF,MAAM,kBAAkB,GAA2B;IACjD,KAAK,EACH,6EAA6E;UAC3E,iEAAiE;UACjE,mDAAmD;IACvD,MAAM,EACJ,mEAAmE;UACjE,4EAA4E;UAC5E,oDAAoD;CACzD,CAAA;AAED,yFAAyF;AACzF,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;AAW7C;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,eAA8C;IAE9C,MAAM,YAAY,GAA0B,EAAE,CAAA;IAE9C,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QAC7D,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAQ;QACzC,IACE,MAAM,KAAK,eAAe;eACvB,MAAM,KAAK,aAAa;eACxB,MAAM,KAAK,SAAS;eACpB,MAAM,KAAK,SAAS;eACpB,MAAM,KAAK,QAAQ,EACtB,CAAC;YACD,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC;mBACjC,mDAAmD,IAAI,GAAG;sBAC3D,uCAAuC,IAAI,UAAU,CAAA;YACzD,YAAY,CAAC,IAAI,CAAC;gBAChB,eAAe,EAAE,IAAI;gBACrB,gBAAgB,EAAE,gBAAgB,IAAI,EAAE;gBACxC,WAAW,EAAE,KAAK;aACnB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAA;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,KAAe,EACf,KAAa,EACb,MAAc,EACd,oBAA2C,EAC3C,OAAe;IAEf,MAAM,OAAO,CAAC,GAAG,CACf,oBAAoB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAChC,MAAM,kBAAkB,GAAG,GAAG,IAAI,CAAC,WAAW,OAAO,MAAM,EAAE,CAAA;QAC7D,OAAO,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE;YAC1D,OAAO,EAAE,WAAW;YACpB,MAAM,EAAE,kBAAkB;YAC1B,KAAK,EAAE,CAAC,iBAAiB,EAAE,MAAM,CAAC;YAClC,GAAG,EAAE,EAAE;YACP,OAAO;YACP,MAAM,EAAE,SAAS;SAClB,CAAC,CAAA;IACJ,CAAC,CAAC,CACH,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"compensator.js","sourceRoot":"","sources":["../../src/core/compensator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface ConfigChangeReport {
2
+ /** Whether the diff touches `./.mmr.yaml` at all. */
3
+ config_file_changed: boolean;
4
+ /** Paths under `./.mmr/acks/` touched by the diff (added/modified/removed). */
5
+ ack_files_changed: string[];
6
+ }
7
+ /**
8
+ * Inspect a unified diff for changes to MMR trust-relevant files: the project
9
+ * config (`.mmr.yaml`) and any project acks (`.mmr/acks/*`). Callers use this
10
+ * to force `needs-user-decision` when a diff under review proposes new
11
+ * config/acks, so an untrusted PR can't silently change channels or suppress
12
+ * its own findings.
13
+ *
14
+ * The diff is attacker-controllable (`--diff`/stdin), so detection is
15
+ * deliberately liberal: it matches across diff producers (git a/b, --no-prefix,
16
+ * raw diff -u, merge `--cc`, rename/copy) and is case-insensitive. Spurious
17
+ * over-detection only forces a (overridable) user decision — the safe
18
+ * direction — while a miss would silently trust attacker config/acks.
19
+ */
20
+ export declare function detectConfigChanges(diff: string): ConfigChangeReport;
21
+ //# sourceMappingURL=diff-introspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-introspect.d.ts","sourceRoot":"","sources":["../../src/core/diff-introspect.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,mBAAmB,EAAE,OAAO,CAAA;IAC5B,+EAA+E;IAC/E,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAC5B;AAgBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAWpE"}
@@ -0,0 +1,42 @@
1
+ // Lines that name files in a unified/combined diff, across producers:
2
+ // `git diff` (a/ b/), `git diff --no-prefix`, raw `diff -u` (---/+++ only),
3
+ // merge diffs (`diff --cc`), and rename/copy metadata. We inspect only these
4
+ // header-ish lines (not hunk bodies) for the sentinel paths.
5
+ const HEADER_RE = /^(?:diff --git |diff --cc |diff --combined |--- |\+\+\+ |rename (?:from|to) |copy (?:from|to) )/;
6
+ // `.mmr.yaml` as a path component (start, separator, or quote on each side),
7
+ // case-insensitive so a casing variant on case-insensitive filesystems still
8
+ // trips the gate (over-detection is the safe failure mode here).
9
+ const CONFIG_RE = /(?:^|[\s/"'])\.mmr\.yaml(?:["'\s]|$)/i;
10
+ // Any `.mmr/acks/<file>` occurrence; the match starts at `.mmr` so a leading
11
+ // a//b/ prefix is naturally excluded.
12
+ const ACK_RE = /\.mmr\/acks\/[^\s"']+/gi;
13
+ /**
14
+ * Inspect a unified diff for changes to MMR trust-relevant files: the project
15
+ * config (`.mmr.yaml`) and any project acks (`.mmr/acks/*`). Callers use this
16
+ * to force `needs-user-decision` when a diff under review proposes new
17
+ * config/acks, so an untrusted PR can't silently change channels or suppress
18
+ * its own findings.
19
+ *
20
+ * The diff is attacker-controllable (`--diff`/stdin), so detection is
21
+ * deliberately liberal: it matches across diff producers (git a/b, --no-prefix,
22
+ * raw diff -u, merge `--cc`, rename/copy) and is case-insensitive. Spurious
23
+ * over-detection only forces a (overridable) user decision — the safe
24
+ * direction — while a miss would silently trust attacker config/acks.
25
+ */
26
+ export function detectConfigChanges(diff) {
27
+ const report = { config_file_changed: false, ack_files_changed: [] };
28
+ if (!diff)
29
+ return report;
30
+ const acks = new Set();
31
+ for (const line of diff.split('\n')) {
32
+ if (!HEADER_RE.test(line))
33
+ continue;
34
+ if (CONFIG_RE.test(line))
35
+ report.config_file_changed = true;
36
+ for (const m of line.matchAll(ACK_RE))
37
+ acks.add(m[0]);
38
+ }
39
+ report.ack_files_changed = [...acks];
40
+ return report;
41
+ }
42
+ //# sourceMappingURL=diff-introspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-introspect.js","sourceRoot":"","sources":["../../src/core/diff-introspect.ts"],"names":[],"mappings":"AAOA,sEAAsE;AACtE,4EAA4E;AAC5E,6EAA6E;AAC7E,6DAA6D;AAC7D,MAAM,SAAS,GACb,iGAAiG,CAAA;AACnG,6EAA6E;AAC7E,6EAA6E;AAC7E,iEAAiE;AACjE,MAAM,SAAS,GAAG,uCAAuC,CAAA;AACzD,6EAA6E;AAC7E,sCAAsC;AACtC,MAAM,MAAM,GAAG,yBAAyB,CAAA;AAExC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,MAAM,GAAuB,EAAE,mBAAmB,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAAA;IACxF,IAAI,CAAC,IAAI;QAAE,OAAO,MAAM,CAAA;IACxB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAQ;QACnC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,mBAAmB,GAAG,IAAI,CAAA;QAC3D,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACvD,CAAC;IACD,MAAM,CAAC,iBAAiB,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;IACpC,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -7,6 +7,16 @@ export interface DispatchOptions {
7
7
  env: Record<string, string>;
8
8
  timeout: number;
9
9
  stderr: 'capture' | 'suppress' | 'passthrough';
10
+ /**
11
+ * How to hand the prompt to the process. 'stdin' (default) pipes it to
12
+ * stdin. 'prompt-file' writes it to a file in the channel dir and passes
13
+ * the path via a {{prompt_file}} placeholder in flags (or appended when no
14
+ * placeholder is present), for CLIs that require the prompt as an arg.
15
+ */
16
+ promptDelivery?: 'stdin' | 'prompt-file';
17
+ /** Working directory for the spawned process. {{neutral_cwd}} is expanded
18
+ * (with {{neutral_home}} in env) into a per-run isolated dir before spawn. */
19
+ cwd?: string;
10
20
  }
11
21
  /** Check whether a channel status represents a terminal (done) state */
12
22
  export declare function isChannelComplete(status: ChannelStatus): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/core/dispatcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE9C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;CAC/C;AAyBD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAEhE;AAED,qEAAqE;AACrE,wBAAsB,eAAe,CACnC,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,IAAI,CAAC,CAqIf"}
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/core/dispatcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAG9C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;IAC9C;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,aAAa,CAAA;IACxC;mFAC+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAiDD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAEhE;AAED,qEAAqE;AACrE,wBAAsB,eAAe,CACnC,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,IAAI,CAAC,CAgLf"}
@@ -2,8 +2,17 @@ import { spawn } from 'node:child_process';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { TERMINAL_STATUSES } from '../types.js';
5
+ import { withNeutralPosture, sweepStaleNeutralDirs } from './host-isolation.js';
6
+ /** Placeholder token replaced with the prompt-file path in prompt-file mode. */
7
+ const PROMPT_FILE_PLACEHOLDER = '{{prompt_file}}';
5
8
  /** Track active child PIDs for cleanup on parent exit */
6
9
  const activeChildren = new Set();
10
+ /**
11
+ * Track per-dispatch neutral-posture cleanups so a SIGINT/SIGTERM that
12
+ * terminates the run also removes the isolated HOME/cwd temp dirs (which hold a
13
+ * grok auth symlink). Each entry is removed once its own dispatch settles.
14
+ */
15
+ const activePostureCleanups = new Set();
7
16
  function cleanupChildren() {
8
17
  for (const pid of activeChildren) {
9
18
  try {
@@ -14,6 +23,15 @@ function cleanupChildren() {
14
23
  }
15
24
  }
16
25
  activeChildren.clear();
26
+ // Remove any neutral-posture temp dirs from interrupted dispatches. Snapshot
27
+ // first: a cleanup callback (or a settling dispatch) could mutate the live Set.
28
+ for (const cleanup of [...activePostureCleanups]) {
29
+ try {
30
+ cleanup();
31
+ }
32
+ catch { /* best effort */ }
33
+ }
34
+ activePostureCleanups.clear();
17
35
  }
18
36
  // Register cleanup once
19
37
  let cleanupRegistered = false;
@@ -24,6 +42,17 @@ function ensureCleanupRegistered() {
24
42
  process.on('SIGINT', () => { cleanupChildren(); process.exit(130); });
25
43
  process.on('SIGTERM', () => { cleanupChildren(); process.exit(143); });
26
44
  }
45
+ // Sweep stale neutral dirs once at process start
46
+ let sweepDone = false;
47
+ function ensureSweepOnce() {
48
+ if (sweepDone)
49
+ return;
50
+ sweepDone = true;
51
+ try {
52
+ sweepStaleNeutralDirs();
53
+ }
54
+ catch { /* best effort — never block dispatch */ }
55
+ }
27
56
  /** Check whether a channel status represents a terminal (done) state */
28
57
  export function isChannelComplete(status) {
29
58
  return TERMINAL_STATUSES.has(status);
@@ -31,6 +60,7 @@ export function isChannelComplete(status) {
31
60
  /** Spawn a background process for a review channel and monitor it */
32
61
  export async function dispatchChannel(store, jobId, channelName, opts) {
33
62
  ensureCleanupRegistered();
63
+ ensureSweepOnce();
34
64
  if (!/^[a-zA-Z0-9._-]+$/.test(channelName)) {
35
65
  throw new Error(`Unsafe channel name: ${channelName}`);
36
66
  }
@@ -38,7 +68,20 @@ export async function dispatchChannel(store, jobId, channelName, opts) {
38
68
  const channelsDir = path.join(jobDir, 'channels');
39
69
  // Split multi-word commands (e.g. "claude -p" → ["claude", "-p"])
40
70
  const [cmd, ...cmdArgs] = opts.command.split(/\s+/);
41
- const args = [...cmdArgs, ...opts.flags];
71
+ let args = [...cmdArgs, ...opts.flags];
72
+ // In prompt-file mode, write the prompt to a file in the channel dir and
73
+ // substitute its path for the {{prompt_file}} placeholder (or append it).
74
+ // The prompt is NOT piped to stdin in this mode.
75
+ const promptDelivery = opts.promptDelivery ?? 'stdin';
76
+ if (promptDelivery === 'prompt-file') {
77
+ const promptFile = path.join(channelsDir, `${channelName}.prompt.txt`);
78
+ // Async write: prompts can carry large diffs and channels dispatch in
79
+ // parallel, so avoid blocking the event loop.
80
+ await fs.promises.writeFile(promptFile, opts.prompt);
81
+ args = args.some((a) => a.includes(PROMPT_FILE_PLACEHOLDER))
82
+ ? args.map((a) => a.split(PROMPT_FILE_PLACEHOLDER).join(promptFile))
83
+ : [...args, promptFile];
84
+ }
42
85
  // Update channel to running
43
86
  store.updateChannel(jobId, channelName, {
44
87
  status: 'running',
@@ -48,25 +91,50 @@ export async function dispatchChannel(store, jobId, channelName, opts) {
48
91
  const stderrStdio = opts.stderr === 'passthrough' ? 'inherit'
49
92
  : opts.stderr === 'capture' ? 'pipe'
50
93
  : 'ignore'; // suppress
51
- // Pipe prompt via stdin to avoid E2BIG on large diffs
52
- const proc = spawn(cmd, args, {
53
- detached: true,
54
- stdio: ['pipe', 'pipe', stderrStdio],
55
- env: { ...process.env, ...opts.env },
56
- });
57
- if (proc.pid)
58
- activeChildren.add(proc.pid);
59
- // Handle stdin pipe errors (child may close stdin early)
60
- // stdin is always 'pipe' so proc.stdin is guaranteed non-null
61
- proc.stdin.on('error', () => {
62
- // Swallow EPIPE the close handler will deal with the process exit
63
- });
64
- // Write prompt to stdin
65
- proc.stdin.write(opts.prompt);
66
- proc.stdin.end();
67
- // Write PID file
68
- const pidFile = path.join(channelsDir, `${channelName}.pid`);
69
- fs.writeFileSync(pidFile, String(proc.pid));
94
+ // Expand neutral posture placeholders ({{neutral_home}}, {{neutral_cwd}});
95
+ // for channels without placeholders, withNeutralPosture is a passthrough.
96
+ const posture = withNeutralPosture(opts.env, opts.cwd);
97
+ // Register for SIGINT/SIGTERM cleanup, and remove + run once this dispatch
98
+ // settles. cleanup is idempotent, so a signal firing alongside a terminal
99
+ // handler is safe.
100
+ activePostureCleanups.add(posture.cleanup);
101
+ const runPostureCleanup = () => {
102
+ activePostureCleanups.delete(posture.cleanup);
103
+ posture.cleanup();
104
+ };
105
+ // Spawn + all synchronous setup (stdin, PID file) in one guarded block: any
106
+ // throw between dir creation and the async close/error handlers being armed
107
+ // would otherwise leak the per-run temp dir.
108
+ let proc;
109
+ try {
110
+ // Pipe prompt via stdin to avoid E2BIG on large diffs
111
+ proc = spawn(cmd, args, {
112
+ detached: true,
113
+ stdio: ['pipe', 'pipe', stderrStdio],
114
+ env: { ...process.env, ...posture.env },
115
+ cwd: posture.cwd, // undefined ⇒ inherit parent cwd (unchanged for non-isolated channels)
116
+ });
117
+ if (proc.pid)
118
+ activeChildren.add(proc.pid);
119
+ // Handle stdin pipe errors (child may close stdin early)
120
+ // stdin is always 'pipe' so proc.stdin is guaranteed non-null
121
+ proc.stdin.on('error', () => {
122
+ // Swallow EPIPE — the close handler will deal with the process exit
123
+ });
124
+ // Write prompt to stdin (stdin delivery only; prompt-file mode passes the
125
+ // prompt as an arg). Always end stdin so processes that read it don't hang.
126
+ if (promptDelivery === 'stdin') {
127
+ proc.stdin.write(opts.prompt);
128
+ }
129
+ proc.stdin.end();
130
+ // Write PID file
131
+ const pidFile = path.join(channelsDir, `${channelName}.pid`);
132
+ fs.writeFileSync(pidFile, String(proc.pid));
133
+ }
134
+ catch (err) {
135
+ runPostureCleanup();
136
+ throw err;
137
+ }
70
138
  // Collect stdout and stderr
71
139
  let stdout = '';
72
140
  let stderr = '';
@@ -107,6 +175,7 @@ export async function dispatchChannel(store, jobId, channelName, opts) {
107
175
  if (stderr) {
108
176
  store.saveChannelLog(jobId, channelName, stderr);
109
177
  }
178
+ runPostureCleanup();
110
179
  resolve();
111
180
  }, timeoutMs);
112
181
  // Handle process close
@@ -134,6 +203,7 @@ export async function dispatchChannel(store, jobId, channelName, opts) {
134
203
  completed_at: completedAt,
135
204
  });
136
205
  }
206
+ runPostureCleanup();
137
207
  resolve();
138
208
  });
139
209
  // Handle spawn errors
@@ -149,6 +219,7 @@ export async function dispatchChannel(store, jobId, channelName, opts) {
149
219
  completed_at: new Date().toISOString(),
150
220
  });
151
221
  store.saveChannelLog(jobId, channelName, err.message);
222
+ runPostureCleanup();
152
223
  resolve();
153
224
  });
154
225
  });
@@ -1 +1 @@
1
- {"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/core/dispatcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/core/dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /** Whether a git ref is safe to embed in `git show <ref>:<path>`. */
2
+ export declare function isSafeRef(ref: string): boolean;
3
+ export interface ReadFileAtRefOptions {
4
+ cwd: string;
5
+ ref: string;
6
+ /** Path relative to the repo root, with leading `./` allowed. */
7
+ filePath: string;
8
+ }
9
+ /**
10
+ * Read file contents at a specific Git ref via `git show <ref>:<path>`.
11
+ * Returns `undefined` when the ref or the path does not exist at the ref.
12
+ * Never throws; callers must handle the undefined-fallback case.
13
+ *
14
+ * Fails closed (returns undefined) on an unsafe ref or path rather than
15
+ * trusting callers to pre-validate — this is the §5-decision-1 trust boundary,
16
+ * so the guard lives at the boundary itself.
17
+ */
18
+ export declare function readFileAtRef(opts: ReadFileAtRefOptions): string | undefined;
19
+ export interface ListFilesAtRefOptions {
20
+ cwd: string;
21
+ ref: string;
22
+ /** Repo-relative directory to list, with leading `./` allowed. */
23
+ dirPath: string;
24
+ }
25
+ /**
26
+ * List the file paths (repo-root-relative) under a directory at a Git ref via
27
+ * `git ls-tree`. Returns `[]` on an unsafe ref/path, a missing ref/dir, or any
28
+ * git error. Never throws.
29
+ */
30
+ export declare function listFilesAtRef(opts: ListFilesAtRefOptions): string[];
31
+ //# sourceMappingURL=git-show.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-show.d.ts","sourceRoot":"","sources":["../../src/core/git-show.ts"],"names":[],"mappings":"AAQA,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAS9C;AAQD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAa5E;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAiBpE"}
@@ -0,0 +1,72 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ // Conservative git refname allow-list: letters, digits, . _ - / and the safe
3
+ // relative-rev modifiers ~ ^. Rejects the constructs that could smuggle
4
+ // surprising rev/path syntax into `git show <ref>:<path>` — ':' (the rev:path
5
+ // separator), '..' (ranges), '@{' (reflog), and leading '-'/'/'.
6
+ const SAFE_REF_RE = /^[A-Za-z0-9._/~^-]+$/;
7
+ /** Whether a git ref is safe to embed in `git show <ref>:<path>`. */
8
+ export function isSafeRef(ref) {
9
+ return (SAFE_REF_RE.test(ref) &&
10
+ !ref.includes('..') &&
11
+ !ref.includes('@{') &&
12
+ !ref.startsWith('-') &&
13
+ !ref.startsWith('/') &&
14
+ !ref.endsWith('/'));
15
+ }
16
+ /** Whether a repo-relative path is safe (no rev separator, no traversal). */
17
+ function isSafePath(p) {
18
+ if (p.length === 0 || p.includes(':'))
19
+ return false;
20
+ return !p.split('/').includes('..');
21
+ }
22
+ /**
23
+ * Read file contents at a specific Git ref via `git show <ref>:<path>`.
24
+ * Returns `undefined` when the ref or the path does not exist at the ref.
25
+ * Never throws; callers must handle the undefined-fallback case.
26
+ *
27
+ * Fails closed (returns undefined) on an unsafe ref or path rather than
28
+ * trusting callers to pre-validate — this is the §5-decision-1 trust boundary,
29
+ * so the guard lives at the boundary itself.
30
+ */
31
+ export function readFileAtRef(opts) {
32
+ const cleanedPath = opts.filePath.replace(/^\.\//, '');
33
+ if (!isSafeRef(opts.ref) || !isSafePath(cleanedPath))
34
+ return undefined;
35
+ try {
36
+ return execFileSync('git', ['-C', opts.cwd, 'show', `${opts.ref}:${cleanedPath}`], {
37
+ encoding: 'utf-8',
38
+ stdio: ['ignore', 'pipe', 'ignore'],
39
+ maxBuffer: 10 * 1024 * 1024,
40
+ timeout: 10000,
41
+ });
42
+ }
43
+ catch {
44
+ return undefined;
45
+ }
46
+ }
47
+ /**
48
+ * List the file paths (repo-root-relative) under a directory at a Git ref via
49
+ * `git ls-tree`. Returns `[]` on an unsafe ref/path, a missing ref/dir, or any
50
+ * git error. Never throws.
51
+ */
52
+ export function listFilesAtRef(opts) {
53
+ const cleaned = opts.dirPath.replace(/^\.\//, '').replace(/\/$/, '');
54
+ if (!isSafeRef(opts.ref) || !isSafePath(cleaned))
55
+ return [];
56
+ try {
57
+ const out = execFileSync('git', ['-C', opts.cwd, 'ls-tree', '--name-only', opts.ref, '--', `${cleaned}/`], {
58
+ encoding: 'utf-8',
59
+ stdio: ['ignore', 'pipe', 'ignore'],
60
+ maxBuffer: 10 * 1024 * 1024,
61
+ timeout: 10000,
62
+ });
63
+ return out
64
+ .split('\n')
65
+ .map((line) => line.trim())
66
+ .filter((line) => line.length > 0);
67
+ }
68
+ catch {
69
+ return [];
70
+ }
71
+ }
72
+ //# sourceMappingURL=git-show.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-show.js","sourceRoot":"","sources":["../../src/core/git-show.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export declare const NEUTRAL_HOME_PLACEHOLDER = "{{neutral_home}}";
2
+ export declare const NEUTRAL_CWD_PLACEHOLDER = "{{neutral_cwd}}";
3
+ export interface NeutralPosture {
4
+ env: Record<string, string>;
5
+ cwd?: string;
6
+ /** Synchronous, idempotent removal of any dir this call created. */
7
+ cleanup: () => void;
8
+ }
9
+ /**
10
+ * Expand {{neutral_home}}/{{neutral_cwd}} placeholders into a single fresh
11
+ * per-call temp directory (unique → safe for parallel channel runs; each call
12
+ * owns its dir lifetime). Returns the concrete env/cwd plus a synchronous
13
+ * cleanup fn. When no placeholder is present, returns the inputs unchanged with
14
+ * a no-op cleanup.
15
+ */
16
+ export declare function withNeutralPosture(env: Record<string, string>, cwd?: string): NeutralPosture;
17
+ /**
18
+ * Backstop for dirs orphaned by SIGKILL/crashes: remove stale mmr-grok-* temp
19
+ * dirs older than `maxAgeMs`. Call once at process start. Best-effort/sync.
20
+ * Default is 24h — comfortably longer than any plausible review timeout, so the
21
+ * sweep never reaps the HOME/cwd of a still-running long review.
22
+ */
23
+ export declare function sweepStaleNeutralDirs(maxAgeMs?: number): void;
24
+ //# sourceMappingURL=host-isolation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-isolation.d.ts","sourceRoot":"","sources":["../../src/core/host-isolation.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,qBAAqB,CAAA;AAC1D,eAAO,MAAM,uBAAuB,oBAAoB,CAAA;AAQxD,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,oEAAoE;IACpE,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAOD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAgD5F;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,SAAsB,GAAG,IAAI,CAa1E"}