@telora/daemon 0.20.54 → 0.20.57

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 (75) hide show
  1. package/build-info.json +6 -3
  2. package/dist/cli/session-state.d.ts +9 -0
  3. package/dist/cli/session-state.d.ts.map +1 -1
  4. package/dist/cli/session-state.js.map +1 -1
  5. package/dist/completion/review-exit-escalations.d.ts +85 -0
  6. package/dist/completion/review-exit-escalations.d.ts.map +1 -0
  7. package/dist/completion/review-exit-escalations.js +203 -0
  8. package/dist/completion/review-exit-escalations.js.map +1 -0
  9. package/dist/completion/review-exit-phase.d.ts.map +1 -1
  10. package/dist/completion/review-exit-phase.js +43 -135
  11. package/dist/completion/review-exit-phase.js.map +1 -1
  12. package/dist/delivery-advance-block.d.ts.map +1 -1
  13. package/dist/delivery-advance-block.js +8 -1
  14. package/dist/delivery-advance-block.js.map +1 -1
  15. package/dist/external-hold.d.ts +104 -0
  16. package/dist/external-hold.d.ts.map +1 -0
  17. package/dist/external-hold.js +149 -0
  18. package/dist/external-hold.js.map +1 -0
  19. package/dist/listener-auto-advance.d.ts.map +1 -1
  20. package/dist/listener-auto-advance.js +12 -0
  21. package/dist/listener-auto-advance.js.map +1 -1
  22. package/dist/listener.d.ts.map +1 -1
  23. package/dist/listener.js +56 -11
  24. package/dist/listener.js.map +1 -1
  25. package/dist/prompt-sections/execution-sections.d.ts.map +1 -1
  26. package/dist/prompt-sections/execution-sections.js +25 -23
  27. package/dist/prompt-sections/execution-sections.js.map +1 -1
  28. package/dist/queries/deliveries.d.ts +62 -0
  29. package/dist/queries/deliveries.d.ts.map +1 -1
  30. package/dist/queries/deliveries.js +1 -0
  31. package/dist/queries/deliveries.js.map +1 -1
  32. package/dist/queries/schemas.d.ts +2 -0
  33. package/dist/queries/schemas.d.ts.map +1 -1
  34. package/dist/queries/schemas.js +5 -0
  35. package/dist/queries/schemas.js.map +1 -1
  36. package/dist/resolver-dispatch.d.ts +108 -0
  37. package/dist/resolver-dispatch.d.ts.map +1 -0
  38. package/dist/resolver-dispatch.js +83 -0
  39. package/dist/resolver-dispatch.js.map +1 -0
  40. package/dist/resolver-reach.d.ts +192 -0
  41. package/dist/resolver-reach.d.ts.map +1 -0
  42. package/dist/resolver-reach.js +168 -0
  43. package/dist/resolver-reach.js.map +1 -0
  44. package/dist/resolvers/git-diff-against-base.d.ts.map +1 -1
  45. package/dist/resolvers/git-diff-against-base.js +8 -2
  46. package/dist/resolvers/git-diff-against-base.js.map +1 -1
  47. package/dist/resolvers/index.d.ts +1 -1
  48. package/dist/resolvers/index.d.ts.map +1 -1
  49. package/dist/resolvers/index.js +1 -1
  50. package/dist/resolvers/index.js.map +1 -1
  51. package/dist/resolvers/shared/git-diff.d.ts +47 -0
  52. package/dist/resolvers/shared/git-diff.d.ts.map +1 -1
  53. package/dist/resolvers/shared/git-diff.js +103 -15
  54. package/dist/resolvers/shared/git-diff.js.map +1 -1
  55. package/dist/spawn/review-role-fallback.d.ts +37 -3
  56. package/dist/spawn/review-role-fallback.d.ts.map +1 -1
  57. package/dist/spawn/review-role-fallback.js +38 -3
  58. package/dist/spawn/review-role-fallback.js.map +1 -1
  59. package/dist/verification-engine.d.ts +10 -0
  60. package/dist/verification-engine.d.ts.map +1 -1
  61. package/dist/verification-engine.js +142 -96
  62. package/dist/verification-engine.js.map +1 -1
  63. package/dist/verification-feedback.d.ts +44 -1
  64. package/dist/verification-feedback.d.ts.map +1 -1
  65. package/dist/verification-feedback.js +130 -1
  66. package/dist/verification-feedback.js.map +1 -1
  67. package/dist/verify-reconciliation.d.ts +25 -1
  68. package/dist/verify-reconciliation.d.ts.map +1 -1
  69. package/dist/verify-reconciliation.js +64 -2
  70. package/dist/verify-reconciliation.js.map +1 -1
  71. package/dist/verify-restatement.d.ts +22 -4
  72. package/dist/verify-restatement.d.ts.map +1 -1
  73. package/dist/verify-restatement.js +18 -1
  74. package/dist/verify-restatement.js.map +1 -1
  75. package/package.json +1 -1
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Resolver reach is BOUNDED up front, and its out-of-worktree actions are ON
3
+ * THE RECORD. The negative branch of the resolver-dispatch seam
4
+ * (resolver-dispatch.ts).
5
+ *
6
+ * The resolver only closes anything if it holds reach the sandboxed worktree
7
+ * agent lacks (spawn-sandbox.ts documents that asymmetry: a git worktree bounds
8
+ * the branch but NOT the OS -- credentials to other machines, sibling repos, the
9
+ * operator's home are all reachable). That same reach, granted without a
10
+ * declared bound, is unattended credentialed action on hosts with nothing
11
+ * reviewing what it did: a resolver's host actions produce no diff and pass no
12
+ * review gate, unlike code changes. Today's paste-into-Claude-Code workaround at
13
+ * least happens with a human watching; removing the human removes that too.
14
+ *
15
+ * Two invariants, both provable without a live host:
16
+ *
17
+ * 1. REACH IS DECLARED IN ADVANCE, PER BLOCKAGE CLASS, and FAIL-CLOSED. A
18
+ * resolver acts only within a bound declared before it runs ("this class may
19
+ * restart a container on host H"); an action outside that bound is REFUSED,
20
+ * not permitted-and-logged. An unrecognized or undeclared blockage class
21
+ * yields NO reach -- never a default to broad reach. This follows the
22
+ * spawn-sandbox.ts shape: explicit, fail-closed, declared rather than
23
+ * ambient. Reach is a property of the declared grant, never inferred from
24
+ * what an attempt happened to touch (a reach granted by outcome is not a
25
+ * bound).
26
+ *
27
+ * 2. EVERY OUT-OF-WORKTREE ACTION IS RECORDED, durably and credential-free, on
28
+ * the success, failure, AND throwing paths -- a failed unattended action is
29
+ * exactly the one that must not vanish. The record identifies the blockage,
30
+ * the action attempted, and its outcome. The sink is injectable (tests
31
+ * capture records without a live host); the default writes a structured line
32
+ * to the canonical daemon log, which is durable and human-reviewable.
33
+ *
34
+ * This module is NOT a second resolver and does not re-open the dispatch design.
35
+ * It supplies the reach `bound` that feeds `BlockageResolver.reach` and wraps a
36
+ * single host action so it is authorized against the bound and recorded --
37
+ * composing with dispatchBlockage, not rewriting it.
38
+ *
39
+ * @module resolver-reach
40
+ */
41
+ /**
42
+ * A blockage class -- the unit at which reach is declared in advance. Stable,
43
+ * coarse identifiers (e.g. 'dirty_worktree', 'restart_container'), NOT
44
+ * per-incident strings: the grant is authored against the class, so the class
45
+ * must be knowable before any specific blockage occurs.
46
+ */
47
+ export type BlockageClass = string;
48
+ /**
49
+ * One host action a resolver may attempt OUTSIDE the worktree. `kind` and
50
+ * `target` are what the bound is checked against; `summary` is the
51
+ * human-readable line that lands in the record.
52
+ */
53
+ export interface ResolverAction {
54
+ /** The blockage class this action serves (checked against its grant). */
55
+ blockageClass: BlockageClass;
56
+ /** Stable action-kind id (e.g. 'restart_container'), matched against the grant. */
57
+ kind: string;
58
+ /** The host/resource the action touches (e.g. 'host-H'), matched against the grant. */
59
+ target: string;
60
+ /** Human-readable description of what will be attempted. Author-controlled; never carry credentials here. */
61
+ summary: string;
62
+ }
63
+ /**
64
+ * A DECLARED grant: exactly what a blockage class is permitted to do, authored
65
+ * in advance. An action is authorized only if BOTH its kind and its target are
66
+ * listed. An empty `allowedActionKinds` or `allowedTargets` therefore grants no
67
+ * reach at all -- the fail-closed floor.
68
+ */
69
+ export interface ReachGrant {
70
+ blockageClass: BlockageClass;
71
+ /** Action kinds this class may attempt. Empty => no reach. */
72
+ allowedActionKinds: readonly string[];
73
+ /** Targets (hosts/resources) this class may touch. Empty => no reach. */
74
+ allowedTargets: readonly string[];
75
+ }
76
+ /** The declared grants, keyed by blockage class. Injectable so tests supply their own. */
77
+ export type ReachRegistry = ReadonlyMap<BlockageClass, ReachGrant>;
78
+ /** The resolved reach bound for one blockage class. */
79
+ export interface ReachBound {
80
+ blockageClass: BlockageClass;
81
+ /** True only when a grant is declared for this class with non-empty allowed kinds AND targets. */
82
+ reach: boolean;
83
+ /** The declared grant when reach is real; null when the class is undeclared or empty. */
84
+ grant: ReachGrant | null;
85
+ }
86
+ /** The decision of authorizing one action against a bound. */
87
+ export type ReachDecision = {
88
+ authorized: true;
89
+ } | {
90
+ authorized: false;
91
+ reason: string;
92
+ };
93
+ /**
94
+ * Resolve a blockage class to its declared reach bound. FAIL-CLOSED: an
95
+ * unrecognized/undeclared class -- or a declared grant that permits no kind or
96
+ * no target -- yields `reach: false` and `grant: null`. There is no path that
97
+ * defaults an unknown class to broad reach.
98
+ */
99
+ export declare function resolveReachBound(blockageClass: BlockageClass, registry: ReachRegistry): ReachBound;
100
+ /**
101
+ * Authorize a single action against a resolved bound. REFUSES (does not
102
+ * permit-and-log) when the bound has no reach, the action serves a different
103
+ * class than the bound, or the action's kind/target is outside the declared
104
+ * grant. A refusal means the action must NOT run.
105
+ */
106
+ export declare function authorizeAction(bound: ReachBound, action: ResolverAction): ReachDecision;
107
+ /** The terminal outcome of one recorded resolver action. */
108
+ export type ResolverActionOutcome = 'success' | 'failure' | 'refused';
109
+ /**
110
+ * A durable record of one out-of-worktree resolver action. Carries NO
111
+ * credential material by construction: only the blockage class, the action's
112
+ * kind/target/summary, the outcome, and a REDACTED free-text detail.
113
+ */
114
+ export interface ResolverActionRecord {
115
+ blockageClass: BlockageClass;
116
+ action: {
117
+ kind: string;
118
+ target: string;
119
+ summary: string;
120
+ };
121
+ outcome: ResolverActionOutcome;
122
+ /** Redacted free-text detail (failure reason / refusal reason). Never raw secrets. */
123
+ detail?: string;
124
+ /** ISO timestamp the record was written. */
125
+ recordedAt: string;
126
+ }
127
+ /**
128
+ * The injectable record sink. Called on EVERY path -- success, failure,
129
+ * refusal, and throw. Tests supply a capturing sink; the default writes to the
130
+ * canonical daemon log. May be async; the runner awaits it.
131
+ */
132
+ export type ResolverActionRecorder = (record: ResolverActionRecord) => void | Promise<void>;
133
+ /**
134
+ * The default production recorder: a structured line in the canonical daemon
135
+ * log (~/.telora/daemon.log) -- durable, rotated, and human-reviewable after
136
+ * the fact, which is precisely what a diff-less host action otherwise lacks.
137
+ * The record's `detail` is already redacted before it arrives here, so this
138
+ * sink cannot leak credentials.
139
+ */
140
+ export declare const logResolverAction: ResolverActionRecorder;
141
+ /**
142
+ * Redact credential-shaped material from free-text before it enters a record.
143
+ * A record a human reviews must never itself become a credential leak, so this
144
+ * scrubs bearer/authorization values, `key=value` pairs whose key names a
145
+ * secret, and long opaque token blobs. Conservative and lossy on purpose --
146
+ * over-redaction is safe; under-redaction is the failure.
147
+ */
148
+ export declare function redactResolverDetail(text: string): string;
149
+ /** What a bounded action's `execute` reports back. */
150
+ export interface ResolverExecuteResult {
151
+ /** True when the host action succeeded. */
152
+ ok: boolean;
153
+ /** Free-text detail (never pre-redacted -- the runner redacts it). */
154
+ detail?: string;
155
+ }
156
+ /** The terminal outcome of {@link runReachBoundedAction}. */
157
+ export type ReachBoundedOutcome = {
158
+ outcome: 'success';
159
+ } | {
160
+ outcome: 'failure';
161
+ detail?: string;
162
+ } | {
163
+ outcome: 'refused';
164
+ reason: string;
165
+ };
166
+ /** Collaborators for {@link runReachBoundedAction}; all injectable for tests. */
167
+ export interface ReachBoundedDeps {
168
+ /** The declared grants. Reach is resolved from here BEFORE the action runs. */
169
+ registry: ReachRegistry;
170
+ /** The record sink, called on every path. Defaults to {@link logResolverAction}. */
171
+ record?: ResolverActionRecorder;
172
+ /** Detail redactor. Defaults to {@link redactResolverDetail}. */
173
+ redact?: (text: string) => string;
174
+ /** Clock for `recordedAt`. Defaults to ISO-now. */
175
+ clock?: () => string;
176
+ }
177
+ /**
178
+ * Run one out-of-worktree resolver action within its declared bound, recording
179
+ * every path.
180
+ *
181
+ * Guarantees, all provable without a live host:
182
+ * - The action is AUTHORIZED against the pre-declared bound FIRST. An action
183
+ * outside the bound (or under an undeclared class) is REFUSED -- `execute` is
184
+ * never called -- and the refusal is recorded.
185
+ * - On execution, `success` or `failure` is recorded from the result.
186
+ * - If `execute` THROWS, a `failure` record is written (via catch) BEFORE the
187
+ * error propagates -- the failed unattended action never vanishes.
188
+ * - The recorded `detail` is always redacted, so no credential material enters
189
+ * the record regardless of the sink.
190
+ */
191
+ export declare function runReachBoundedAction(deps: ReachBoundedDeps, action: ResolverAction, execute: () => Promise<ResolverExecuteResult>): Promise<ReachBoundedOutcome>;
192
+ //# sourceMappingURL=resolver-reach.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver-reach.d.ts","sourceRoot":"","sources":["../src/resolver-reach.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Resolver reach is BOUNDED up front, and its out-of-worktree actions are ON
3
+ * THE RECORD. The negative branch of the resolver-dispatch seam
4
+ * (resolver-dispatch.ts).
5
+ *
6
+ * The resolver only closes anything if it holds reach the sandboxed worktree
7
+ * agent lacks (spawn-sandbox.ts documents that asymmetry: a git worktree bounds
8
+ * the branch but NOT the OS -- credentials to other machines, sibling repos, the
9
+ * operator's home are all reachable). That same reach, granted without a
10
+ * declared bound, is unattended credentialed action on hosts with nothing
11
+ * reviewing what it did: a resolver's host actions produce no diff and pass no
12
+ * review gate, unlike code changes. Today's paste-into-Claude-Code workaround at
13
+ * least happens with a human watching; removing the human removes that too.
14
+ *
15
+ * Two invariants, both provable without a live host:
16
+ *
17
+ * 1. REACH IS DECLARED IN ADVANCE, PER BLOCKAGE CLASS, and FAIL-CLOSED. A
18
+ * resolver acts only within a bound declared before it runs ("this class may
19
+ * restart a container on host H"); an action outside that bound is REFUSED,
20
+ * not permitted-and-logged. An unrecognized or undeclared blockage class
21
+ * yields NO reach -- never a default to broad reach. This follows the
22
+ * spawn-sandbox.ts shape: explicit, fail-closed, declared rather than
23
+ * ambient. Reach is a property of the declared grant, never inferred from
24
+ * what an attempt happened to touch (a reach granted by outcome is not a
25
+ * bound).
26
+ *
27
+ * 2. EVERY OUT-OF-WORKTREE ACTION IS RECORDED, durably and credential-free, on
28
+ * the success, failure, AND throwing paths -- a failed unattended action is
29
+ * exactly the one that must not vanish. The record identifies the blockage,
30
+ * the action attempted, and its outcome. The sink is injectable (tests
31
+ * capture records without a live host); the default writes a structured line
32
+ * to the canonical daemon log, which is durable and human-reviewable.
33
+ *
34
+ * This module is NOT a second resolver and does not re-open the dispatch design.
35
+ * It supplies the reach `bound` that feeds `BlockageResolver.reach` and wraps a
36
+ * single host action so it is authorized against the bound and recorded --
37
+ * composing with dispatchBlockage, not rewriting it.
38
+ *
39
+ * @module resolver-reach
40
+ */
41
+ import { createLogger } from './log.js';
42
+ const log = createLogger({ module: 'resolver-reach' });
43
+ /**
44
+ * Resolve a blockage class to its declared reach bound. FAIL-CLOSED: an
45
+ * unrecognized/undeclared class -- or a declared grant that permits no kind or
46
+ * no target -- yields `reach: false` and `grant: null`. There is no path that
47
+ * defaults an unknown class to broad reach.
48
+ */
49
+ export function resolveReachBound(blockageClass, registry) {
50
+ const grant = registry.get(blockageClass) ?? null;
51
+ const reach = grant !== null &&
52
+ grant.allowedActionKinds.length > 0 &&
53
+ grant.allowedTargets.length > 0;
54
+ return { blockageClass, reach, grant: reach ? grant : null };
55
+ }
56
+ /**
57
+ * Authorize a single action against a resolved bound. REFUSES (does not
58
+ * permit-and-log) when the bound has no reach, the action serves a different
59
+ * class than the bound, or the action's kind/target is outside the declared
60
+ * grant. A refusal means the action must NOT run.
61
+ */
62
+ export function authorizeAction(bound, action) {
63
+ if (!bound.reach || bound.grant === null) {
64
+ return { authorized: false, reason: `no declared reach for blockage class "${action.blockageClass}"` };
65
+ }
66
+ if (action.blockageClass !== bound.blockageClass) {
67
+ return {
68
+ authorized: false,
69
+ reason: `action serves class "${action.blockageClass}" but bound is for "${bound.blockageClass}"`,
70
+ };
71
+ }
72
+ if (!bound.grant.allowedActionKinds.includes(action.kind)) {
73
+ return { authorized: false, reason: `action kind "${action.kind}" is outside the declared bound for "${bound.blockageClass}"` };
74
+ }
75
+ if (!bound.grant.allowedTargets.includes(action.target)) {
76
+ return { authorized: false, reason: `target "${action.target}" is outside the declared bound for "${bound.blockageClass}"` };
77
+ }
78
+ return { authorized: true };
79
+ }
80
+ /**
81
+ * The default production recorder: a structured line in the canonical daemon
82
+ * log (~/.telora/daemon.log) -- durable, rotated, and human-reviewable after
83
+ * the fact, which is precisely what a diff-less host action otherwise lacks.
84
+ * The record's `detail` is already redacted before it arrives here, so this
85
+ * sink cannot leak credentials.
86
+ */
87
+ export const logResolverAction = (record) => {
88
+ log.info('resolver action recorded', {
89
+ blockageClass: record.blockageClass,
90
+ actionKind: record.action.kind,
91
+ target: record.action.target,
92
+ summary: record.action.summary,
93
+ outcome: record.outcome,
94
+ ...(record.detail !== undefined ? { detail: record.detail } : {}),
95
+ recordedAt: record.recordedAt,
96
+ });
97
+ };
98
+ /**
99
+ * Redact credential-shaped material from free-text before it enters a record.
100
+ * A record a human reviews must never itself become a credential leak, so this
101
+ * scrubs bearer/authorization values, `key=value` pairs whose key names a
102
+ * secret, and long opaque token blobs. Conservative and lossy on purpose --
103
+ * over-redaction is safe; under-redaction is the failure.
104
+ */
105
+ export function redactResolverDetail(text) {
106
+ return text
107
+ // Authorization: Bearer <token> / bearer <token>
108
+ .replace(/\b(bearer)\s+[A-Za-z0-9._\-+/=]+/gi, '$1 [REDACTED]')
109
+ // key=value / key: value where the key names a secret
110
+ .replace(/\b(authorization|api[_-]?key|secret|password|passwd|token|access[_-]?key|private[_-]?key|client[_-]?secret)\b(\s*[:=]\s*)("?)[^\s"']+\3/gi, '$1$2[REDACTED]')
111
+ // Long opaque token blobs (>=24 chars of token alphabet) not otherwise caught.
112
+ .replace(/\b[A-Za-z0-9._\-+/=]{24,}\b/g, '[REDACTED]');
113
+ }
114
+ /**
115
+ * Run one out-of-worktree resolver action within its declared bound, recording
116
+ * every path.
117
+ *
118
+ * Guarantees, all provable without a live host:
119
+ * - The action is AUTHORIZED against the pre-declared bound FIRST. An action
120
+ * outside the bound (or under an undeclared class) is REFUSED -- `execute` is
121
+ * never called -- and the refusal is recorded.
122
+ * - On execution, `success` or `failure` is recorded from the result.
123
+ * - If `execute` THROWS, a `failure` record is written (via catch) BEFORE the
124
+ * error propagates -- the failed unattended action never vanishes.
125
+ * - The recorded `detail` is always redacted, so no credential material enters
126
+ * the record regardless of the sink.
127
+ */
128
+ export async function runReachBoundedAction(deps, action, execute) {
129
+ const record = deps.record ?? logResolverAction;
130
+ const redact = deps.redact ?? redactResolverDetail;
131
+ const clock = deps.clock ?? (() => new Date().toISOString());
132
+ const write = async (outcome, detail) => {
133
+ const entry = {
134
+ blockageClass: action.blockageClass,
135
+ action: { kind: action.kind, target: action.target, summary: action.summary },
136
+ outcome,
137
+ recordedAt: clock(),
138
+ };
139
+ if (detail !== undefined)
140
+ entry.detail = redact(detail);
141
+ await record(entry);
142
+ };
143
+ const bound = resolveReachBound(action.blockageClass, deps.registry);
144
+ const decision = authorizeAction(bound, action);
145
+ if (!decision.authorized) {
146
+ // Refused: the action is NOT executed. Record the refusal for the audit trail.
147
+ await write('refused', decision.reason);
148
+ return { outcome: 'refused', reason: decision.reason };
149
+ }
150
+ try {
151
+ const result = await execute();
152
+ if (result.ok) {
153
+ await write('success', result.detail);
154
+ return { outcome: 'success' };
155
+ }
156
+ await write('failure', result.detail);
157
+ return result.detail !== undefined
158
+ ? { outcome: 'failure', detail: redact(result.detail) }
159
+ : { outcome: 'failure' };
160
+ }
161
+ catch (err) {
162
+ // A throwing action is exactly the one whose record must not vanish.
163
+ const message = err instanceof Error ? err.message : String(err);
164
+ await write('failure', message);
165
+ throw err;
166
+ }
167
+ }
168
+ //# sourceMappingURL=resolver-reach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver-reach.js","sourceRoot":"","sources":["../src/resolver-reach.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"git-diff-against-base.d.ts","sourceRoot":"","sources":["../../src/resolvers/git-diff-against-base.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,oGAAoG;AACpG,wBAAgB,kCAAkC,IAAI,IAAI,CAqCzD"}
1
+ {"version":3,"file":"git-diff-against-base.d.ts","sourceRoot":"","sources":["../../src/resolvers/git-diff-against-base.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,oGAAoG;AACpG,wBAAgB,kCAAkC,IAAI,IAAI,CA2CzD"}
@@ -1,5 +1,5 @@
1
1
  import { registerSourceResolver } from '../assembly-engine.js';
2
- import { getGitDiff, getDiffStatSummary, MAX_DIFF_BYTES } from './shared/git-diff.js';
2
+ import { getGitDiff, getDeliveryDiff, getDiffStatSummary, MAX_DIFF_BYTES } from './shared/git-diff.js';
3
3
  import { createLogger } from '../log.js';
4
4
  const log = createLogger({ module: 'assembly-engine' });
5
5
  /**
@@ -19,7 +19,13 @@ export function registerGitDiffAgainstBaseResolver() {
19
19
  // (reviewed_through_sha) so a resumed reviewer sees only watermark..tip;
20
20
  // every other caller diffs against the integration branch.
21
21
  const baseBranch = context.diffBaseOverride ?? context.config.integrationBranch;
22
- const diff = getGitDiff(context.worktreePath, baseBranch);
22
+ // For the watermark-override case the range is always ahead by construction,
23
+ // so a plain base...HEAD diff is correct. For the default integration base,
24
+ // use the delivery-diff resolver so a focus branch that has ALREADY merged
25
+ // (level with integration) still yields its work rather than an empty diff.
26
+ const diff = context.diffBaseOverride
27
+ ? getGitDiff(context.worktreePath, baseBranch)
28
+ : getDeliveryDiff(context.worktreePath, baseBranch);
23
29
  if (!diff.trim())
24
30
  return '';
25
31
  if (diff.length > MAX_DIFF_BYTES) {
@@ -1 +1 @@
1
- {"version":3,"file":"git-diff-against-base.js","sourceRoot":"","sources":["../../src/resolvers/git-diff-against-base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;AAGxD;;;;;GAKG;AACH,oGAAoG;AACpG,MAAM,UAAU,kCAAkC;IAChD,sBAAsB,CAAC,uBAAuB,EAAE,KAAK,EAAE,OAAwB,EAAmB,EAAE;QAClG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;YAC9D,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,2DAA2D;QAC3D,MAAM,UAAU,GAAG,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAChF,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAE1D,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO,EAAE,CAAC;QAE5B,IAAI,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YAClE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;YAChD,OAAO;gBACL,wBAAwB,UAAU,GAAG;gBACrC,EAAE;gBACF,8BAA8B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,qBAAqB,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK;gBACvH,EAAE;gBACF,kBAAkB;gBAClB,EAAE;gBACF,KAAK;gBACL,IAAI,CAAC,IAAI,EAAE;gBACX,KAAK;gBACL,EAAE;gBACF,SAAS;gBACT,SAAS;gBACT,KAAK;aACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;QAED,OAAO,wBAAwB,UAAU,oBAAoB,IAAI,UAAU,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"git-diff-against-base.js","sourceRoot":"","sources":["../../src/resolvers/git-diff-against-base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACvG,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;AAGxD;;;;;GAKG;AACH,oGAAoG;AACpG,MAAM,UAAU,kCAAkC;IAChD,sBAAsB,CAAC,uBAAuB,EAAE,KAAK,EAAE,OAAwB,EAAmB,EAAE;QAClG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;YAC9D,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,2DAA2D;QAC3D,MAAM,UAAU,GAAG,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAChF,6EAA6E;QAC7E,4EAA4E;QAC5E,2EAA2E;QAC3E,4EAA4E;QAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,gBAAgB;YACnC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC;YAC9C,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAEtD,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO,EAAE,CAAC;QAE5B,IAAI,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YAClE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;YAChD,OAAO;gBACL,wBAAwB,UAAU,GAAG;gBACrC,EAAE;gBACF,8BAA8B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,qBAAqB,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK;gBACvH,EAAE;gBACF,kBAAkB;gBAClB,EAAE;gBACF,KAAK;gBACL,IAAI,CAAC,IAAI,EAAE;gBACX,KAAK;gBACL,EAAE;gBACF,SAAS;gBACT,SAAS;gBACT,KAAK;aACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;QAED,OAAO,wBAAwB,UAAU,oBAAoB,IAAI,UAAU,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -28,7 +28,7 @@
28
28
  * (FocusEngine.init) can list them in the startup log.
29
29
  */
30
30
  export declare function initResolvers(): string[];
31
- export { MAX_DIFF_BYTES, getGitDiff, getDiffStatSummary, getChangedFiles, getCommitsAhead } from './shared/git-diff.js';
31
+ export { MAX_DIFF_BYTES, getGitDiff, getDiffStatSummary, getChangedFiles, getCommitsAhead, getGitDiffRange, getDiffStatRange, getChangedFilesRange, findDeliveryMergeCommit, resolveDeliveryDiffRange, getDeliveryDiff, } from './shared/git-diff.js';
32
32
  export { CRT_DUMP_BUDGET_CHARS, renderRealityTreeDump, FOCUS_REALITY_TREE_EMPTY_STATE, } from './shared/reality-tree.js';
33
33
  export type { RealityTreeRow, RealityTreeListResponse, RealityNodeRow, RealityEdgeRow, NodeListResponse, EdgeListResponse, } from './shared/reality-tree.js';
34
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resolvers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAyFH;;;;;;;;;GASG;AACH,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAgBxC;AAGD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACxH,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,8BAA8B,GAC/B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,cAAc,EACd,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resolvers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAyFH;;;;;;;;;GASG;AACH,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAgBxC;AAGD,OAAO,EACL,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,8BAA8B,GAC/B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,cAAc,EACd,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC"}
@@ -125,6 +125,6 @@ export function initResolvers() {
125
125
  return keys;
126
126
  }
127
127
  // ── Shared public surface (re-exports for external consumers) ─────────
128
- export { MAX_DIFF_BYTES, getGitDiff, getDiffStatSummary, getChangedFiles, getCommitsAhead } from './shared/git-diff.js';
128
+ export { MAX_DIFF_BYTES, getGitDiff, getDiffStatSummary, getChangedFiles, getCommitsAhead, getGitDiffRange, getDiffStatRange, getChangedFilesRange, findDeliveryMergeCommit, resolveDeliveryDiffRange, getDeliveryDiff, } from './shared/git-diff.js';
129
129
  export { CRT_DUMP_BUDGET_CHARS, renderRealityTreeDump, FOCUS_REALITY_TREE_EMPTY_STATE, } from './shared/reality-tree.js';
130
130
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resolvers/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resolvers/index.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,16 @@
2
2
  * Git diff helpers shared across resolvers.
3
3
  */
4
4
  export declare const MAX_DIFF_BYTES: number;
5
+ /**
6
+ * Run `git diff <range>` in a worktree. Returns the raw diff output, or empty
7
+ * string on failure. `range` is any ref expression git diff accepts, e.g.
8
+ * `integration...HEAD` or `<merge>^1...<merge>`.
9
+ */
10
+ export declare function getGitDiffRange(worktreePath: string, range: string): string;
11
+ /** `git diff --stat <range>` (for the truncation header). Empty on failure. */
12
+ export declare function getDiffStatRange(worktreePath: string, range: string): string;
13
+ /** `git diff --name-only <range>` (name-only). Empty array on failure. */
14
+ export declare function getChangedFilesRange(worktreePath: string, range: string): string[];
5
15
  /**
6
16
  * Run git diff in a worktree against the base branch.
7
17
  * Returns the raw diff output, or empty string on failure.
@@ -24,4 +34,41 @@ export declare function getChangedFiles(worktreePath: string, baseBranch: string
24
34
  * worktree. Returns 0 on failure so callers treat "unknown" as "no commits".
25
35
  */
26
36
  export declare function getCommitsAhead(worktreePath: string, baseBranch: string): number;
37
+ /**
38
+ * Find the merge commit on `baseBranch` that merged the current focus branch
39
+ * (the worktree's HEAD) into it.
40
+ *
41
+ * `git diff base...HEAD` answers "what is left to merge"; it empties the moment
42
+ * the focus branch merges into the base. But when the base advanced past the
43
+ * fork point, the merge is a real merge commit whose non-first parent IS the
44
+ * focus tip -- so `git diff <merge>^1 <merge>` still recovers exactly the
45
+ * delivery's contribution. This locates that merge commit deterministically
46
+ * from what is in the repo (no session ids, no reflog): scan the base branch's
47
+ * merge commits for one whose second (or later) parent equals HEAD.
48
+ *
49
+ * Returns null when no such merge exists -- an unmerged branch, or a merge that
50
+ * FAST-FORWARDED (no merge commit, so the fork point leaves no in-tree marker).
51
+ * The caller then yields an empty diff, which the instrument-fault path handles.
52
+ */
53
+ export declare function findDeliveryMergeCommit(worktreePath: string, baseBranch: string): string | null;
54
+ /**
55
+ * Resolve the git range that contains a delivery's work, robust to the focus
56
+ * branch having already merged into its base:
57
+ *
58
+ * - branch AHEAD of base -> `base...HEAD` (historic behaviour,
59
+ * byte-identical to the old getGitDiff)
60
+ * - branch LEVEL/BEHIND after merge -> `<merge>^1...<merge>` (recovered from
61
+ * the merge commit that brought it in)
62
+ * - no attributable commits -> null (caller yields empty; the
63
+ * instrument-fault path handles it)
64
+ */
65
+ export declare function resolveDeliveryDiffRange(worktreePath: string, baseBranch: string): string | null;
66
+ /**
67
+ * The delivery's diff, resolved from the range that actually contains its work
68
+ * (see resolveDeliveryDiffRange). For a branch still ahead of base this is
69
+ * byte-identical to `getGitDiff(worktreePath, baseBranch)`; for a merged branch
70
+ * it recovers the delivery's contribution from the merge commit; for a delivery
71
+ * with no attributable commits it returns ''.
72
+ */
73
+ export declare function getDeliveryDiff(worktreePath: string, baseBranch: string): string;
27
74
  //# sourceMappingURL=git-diff.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git-diff.d.ts","sourceRoot":"","sources":["../../../src/resolvers/shared/git-diff.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,eAAO,MAAM,cAAc,QAAY,CAAC;AAExC;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAU3E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CASnF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAUlF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAWhF"}
1
+ {"version":3,"file":"git-diff.d.ts","sourceRoot":"","sources":["../../../src/resolvers/shared/git-diff.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,eAAO,MAAM,cAAc,QAAY,CAAC;AAExC;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAU3E;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS5E;AAED,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAUlF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAElF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAWhF;AAKD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsB/F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKhG;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAGhF"}