claude-code-session-manager 0.75.3 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AgentLibrary-CzQqcObq.js → AgentLibrary-B2ie8bbw.js} +2 -2
- package/dist/assets/{DataModel-Bj_WlLz8.js → DataModel-BIJPYw32.js} +1 -1
- package/dist/assets/{History-DnSi_OHm.js → History-CeY6dk9S.js} +2 -2
- package/dist/assets/{Hooks-0BB0dp3S.js → Hooks-BFH2ocKg.js} +2 -2
- package/dist/assets/{HostBilko-DHpwwsLQ.js → HostBilko-36gj9wLz.js} +1 -1
- package/dist/assets/{Library-CaJVqVvi.js → Library-C-hBct39.js} +1 -1
- package/dist/assets/{ListDetail-C1W2HmC2.js → ListDetail-CNq64VWV.js} +1 -1
- package/dist/assets/{MarkdownEditor-5Ob9FW3z.js → MarkdownEditor-Bh3qt5-1.js} +1 -1
- package/dist/assets/{McpServers-JxCSfm1S.js → McpServers-DpGN0oyz.js} +1 -1
- package/dist/assets/{Memory-BDeqlqwH.js → Memory-D59hUjC4.js} +6 -6
- package/dist/assets/{Panel-Dh9ZHuEj.js → Panel-DCgbaoci.js} +1 -1
- package/dist/assets/{Permissions-DXy-CbEY.js → Permissions-DAmQ0DYV.js} +2 -2
- package/dist/assets/{Plugins-_n1Iuc8T.js → Plugins-Dyfgn6Is.js} +2 -2
- package/dist/assets/{ProvenanceBadge-BP_evfxE.js → ProvenanceBadge-BiYhPO1U.js} +1 -1
- package/dist/assets/SaveBar-RV7B6sOh.js +1 -0
- package/dist/assets/Scheduler-BPaNqx1b.js +14 -0
- package/dist/assets/{ScopeSwitcher-CAWzM6RI.js → ScopeSwitcher-P4mdLGNU.js} +1 -1
- package/dist/assets/{Settings-DRRozLyT.js → Settings-BL4vf5aX.js} +1 -1
- package/dist/assets/{SkillReferenceGraph-DGHDWlz4.js → SkillReferenceGraph-BRBDyi1_.js} +1 -1
- package/dist/assets/{Skills-D8L66eiX.js → Skills-BV08gDUH.js} +2 -2
- package/dist/assets/{SystemPrompt-CYtUsonD.js → SystemPrompt-CLftSsDw.js} +1 -1
- package/dist/assets/TagLibrary-Bp8jGsd5.js +1 -0
- package/dist/assets/{TiptapBody-B2hRgbPE.js → TiptapBody-jCpuB6E5.js} +1 -1
- package/dist/assets/{Toggle-BTwsbxam.js → Toggle-D2paA1xf.js} +1 -1
- package/dist/assets/{index-DijufvkJ.js → index-BDRSqBl3.js} +704 -704
- package/dist/assets/{index-CMLnzdZC.css → index-CYhdtisq.css} +1 -1
- package/dist/assets/{settingsSchema-D6wzxAi6.js → settingsSchema-6IOLjZZN.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +8 -2
- package/plugins/session-manager-dev/skills/develop/standards.md +1 -1
- package/scripts/lib/activeSessions.cjs +116 -6
- package/scripts/project-pages-logic/dist/logic.cjs +4709 -0
- package/scripts/render-project-pages/dist/renderer.cjs +18900 -0
- package/scripts/render-project-pages.cjs +70 -0
- package/scripts/scheduler-mcp-server.cjs +269 -96
- package/scripts/validate-project-pages-summary.cjs +62 -0
- package/src/main/__tests__/agentModelResolve.test.cjs +66 -0
- package/src/main/__tests__/epicStatusMirror.test.cjs +110 -0
- package/src/main/__tests__/health-delegation-chain.test.cjs +106 -0
- package/src/main/__tests__/prdAdminRoutes.test.cjs +295 -0
- package/src/main/__tests__/prdAgentType.test.cjs +103 -0
- package/src/main/__tests__/prdCreate.test.cjs +247 -0
- package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +117 -0
- package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +108 -0
- package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +485 -0
- package/src/main/__tests__/projectPages.test.cjs +73 -1
- package/src/main/__tests__/rcaReport.test.cjs +54 -0
- package/src/main/__tests__/runVerify.test.cjs +94 -0
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +58 -3
- package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +103 -0
- package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +41 -0
- package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +10 -0
- package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +78 -0
- package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +242 -0
- package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +31 -0
- package/src/main/__tests__/scheduler-launch-failure.test.cjs +201 -0
- package/src/main/__tests__/scheduler-leftover-fields.test.cjs +52 -0
- package/src/main/__tests__/scheduler-looks-done.test.cjs +241 -0
- package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +135 -0
- package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +222 -0
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +207 -1
- package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +212 -0
- package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +185 -0
- package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +194 -0
- package/src/main/__tests__/seedAgentPersonas.test.cjs +75 -14
- package/src/main/__tests__/seedSchedulerMcp.test.cjs +66 -0
- package/src/main/__tests__/uniquePrdNumbers.test.cjs +14 -5
- package/src/main/bilkoHost.cjs +4 -3
- package/src/main/chatRunner.cjs +6 -1
- package/src/main/config.cjs +25 -33
- package/src/main/health.cjs +153 -2
- package/src/main/index.cjs +64 -5
- package/src/main/ipcSchemas.cjs +69 -1
- package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +179 -0
- package/src/main/lib/__tests__/childWithLog.test.cjs +141 -0
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +391 -42
- package/src/main/lib/__tests__/ephemeralCwd.test.cjs +91 -0
- package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +5 -3
- package/src/main/lib/__tests__/fixChainDepth.test.cjs +40 -0
- package/src/main/lib/__tests__/gitWorktree.test.cjs +290 -5
- package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +107 -0
- package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +153 -0
- package/src/main/lib/__tests__/jobWorktree.test.cjs +6 -4
- package/src/main/lib/__tests__/landedSinceRun.test.cjs +73 -0
- package/src/main/lib/__tests__/launchFailure.test.cjs +220 -0
- package/src/main/lib/__tests__/loadGate.test.cjs +159 -0
- package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +102 -0
- package/src/main/lib/__tests__/opsOwnership.test.cjs +7 -0
- package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +151 -0
- package/src/main/lib/__tests__/opsRootResolve.test.cjs +149 -0
- package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +82 -0
- package/src/main/lib/__tests__/projectRootResolve.test.cjs +148 -0
- package/src/main/lib/__tests__/queueHealth.test.cjs +58 -0
- package/src/main/lib/__tests__/quietMachineLease.test.cjs +39 -0
- package/src/main/lib/__tests__/reaperHelpers.test.cjs +133 -0
- package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +19 -9
- package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +213 -0
- package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +125 -0
- package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +127 -0
- package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +109 -0
- package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +71 -0
- package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +217 -0
- package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +350 -0
- package/src/main/lib/activeIndexMerge.cjs +15 -0
- package/src/main/lib/activeIndexRebuild.cjs +133 -0
- package/src/main/lib/agentModelResolve.cjs +58 -0
- package/src/main/lib/buildTarget.cjs +3 -2
- package/src/main/lib/childWithLog.cjs +69 -2
- package/src/main/lib/claudeBin.cjs +54 -1
- package/src/main/lib/crossProjectFeedback.cjs +8 -1
- package/src/main/lib/definitionOfDone.cjs +3 -2
- package/src/main/lib/delegationReadiness.cjs +514 -26
- package/src/main/lib/ephemeralCwd.cjs +78 -0
- package/src/main/lib/epicDelegationStats.cjs +2 -1
- package/src/main/lib/epicMint.cjs +17 -1
- package/src/main/lib/epicStatusMirror.cjs +95 -0
- package/src/main/lib/epicValidationHook.cjs +2 -1
- package/src/main/lib/epicWorktreeMint.cjs +5 -2
- package/src/main/lib/fixChainDepth.cjs +45 -0
- package/src/main/lib/gitWorktree.cjs +520 -21
- package/src/main/lib/jobWorktree.cjs +2 -0
- package/src/main/lib/landedSinceRun.cjs +55 -0
- package/src/main/lib/launchFailure.cjs +357 -0
- package/src/main/lib/loadGate.cjs +134 -0
- package/src/main/lib/mcpToolCatalog.cjs +370 -0
- package/src/main/lib/opsErrorLog.cjs +12 -1
- package/src/main/lib/opsOwnership.cjs +106 -0
- package/src/main/lib/prdAdminRoutes.cjs +43 -3
- package/src/main/lib/prdAgentType.cjs +84 -0
- package/src/main/lib/prdCreate.cjs +103 -15
- package/src/main/lib/prdDeclaredPaths.cjs +70 -0
- package/src/main/lib/prdFrontmatter.cjs +17 -3
- package/src/main/lib/prdLocations.cjs +13 -6
- package/src/main/lib/projectHomeAdminRoutes.cjs +402 -0
- package/src/main/lib/projectPageSummarySchema.cjs +181 -0
- package/src/main/lib/projectRootResolve.cjs +134 -0
- package/src/main/lib/promptSessionSchema.cjs +7 -0
- package/src/main/lib/queueHealth.cjs +38 -0
- package/src/main/lib/queueStore.cjs +40 -7
- package/src/main/lib/quietMachineLease.cjs +48 -0
- package/src/main/lib/rcaReport.cjs +54 -4
- package/src/main/lib/reaperHelpers.cjs +64 -1
- package/src/main/lib/scheduleJobSchema.cjs +31 -0
- package/src/main/lib/scheduleJobTransitions.cjs +6 -2
- package/src/main/lib/schedulerBatch.cjs +301 -55
- package/src/main/lib/schedulerConfig.cjs +99 -0
- package/src/main/projectBrief.cjs +3 -2
- package/src/main/projectPages.cjs +162 -3
- package/src/main/promptSessionTranscript.cjs +0 -0
- package/src/main/pty.cjs +5 -0
- package/src/main/queueOps.cjs +15 -8
- package/src/main/runVerify.cjs +50 -9
- package/src/main/scheduler/prdParser.cjs +18 -1
- package/src/main/scheduler.cjs +1701 -130
- package/src/main/seedAgentPersonas.cjs +62 -21
- package/src/main/seedSchedulerMcp.cjs +58 -4
- package/src/main/templates/project-pages-catalog.json +741 -0
- package/src/main/templates/project-pages-pipeline.md +417 -0
- package/src/preload/api.d.ts +187 -3
- package/src/preload/index.cjs +9 -0
- package/src/seed/agents/project-home-builder.md +59 -0
- package/dist/assets/SaveBar-D-gCUx4n.js +0 -1
- package/dist/assets/Scheduler-Bpd4OGju.js +0 -14
- package/dist/assets/TagLibrary-E5CLeuVk.js +0 -1
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
* killedByWatchdog — string | null
|
|
41
41
|
* error — Error | undefined (child 'error' event or sync spawn throw)
|
|
42
42
|
* spawnFailed — boolean, true when the error came from a synchronous spawn throw
|
|
43
|
+
* leakedDescendants — { pid, pcpu, etimes, comm }[], the process-group survivors
|
|
44
|
+
* sweepChildProcessGroup found still alive right before it
|
|
45
|
+
* swept them. [] in the normal case (nothing leaked, or
|
|
46
|
+
* non-Linux, or enumeration failed). See sweepChildProcessGroup.
|
|
43
47
|
* safeLog — same safeLog (usable inside onExit for final log lines)
|
|
44
48
|
*
|
|
45
49
|
* Returns { child, cancel } where cancel() clears all timers + SIGKILLs.
|
|
@@ -47,7 +51,11 @@
|
|
|
47
51
|
*/
|
|
48
52
|
|
|
49
53
|
const fs = require('node:fs');
|
|
50
|
-
const { spawn } = require('node:child_process');
|
|
54
|
+
const { spawn, execFileSync } = require('node:child_process');
|
|
55
|
+
|
|
56
|
+
// Grace period between the post-exit SIGTERM sweep and the follow-up SIGKILL
|
|
57
|
+
// sweep of a detached child's process group. See sweepChildProcessGroup below.
|
|
58
|
+
const POST_EXIT_GROUP_SWEEP_GRACE_MS = 5000;
|
|
51
59
|
|
|
52
60
|
// ---------- Phase 1 ----------
|
|
53
61
|
|
|
@@ -119,6 +127,63 @@ function openLog(logPath) {
|
|
|
119
127
|
* }} opts
|
|
120
128
|
* @returns {{ child: import('child_process').ChildProcess | null, cancel: () => void }}
|
|
121
129
|
*/
|
|
130
|
+
// Post-exit process-group sweep.
|
|
131
|
+
//
|
|
132
|
+
// Incident (2026-08-31, ~/Projects/starry-night-ships): scheduler jobs spawn
|
|
133
|
+
// detached: true, and every watchdog path (result-tail, deadman, idle-tail)
|
|
134
|
+
// kills the whole process group via ctx.killTree — but only on an *overrun*
|
|
135
|
+
// exit. When the executor child exits normally, nothing swept the group, so
|
|
136
|
+
// anything the agent had backgrounded to work around the foreground call cap
|
|
137
|
+
// (the `bash -c '<gate> > /tmp/x.log; echo $? > /tmp/x.done'` shape) reparented
|
|
138
|
+
// to init and kept running for nobody: three orphaned test batteries at PPID 1
|
|
139
|
+
// were found, one burning ~5 cores for 56 minutes. The invariant this restores:
|
|
140
|
+
// a job's descendants must not outlive the job. Killing the job's own process
|
|
141
|
+
// group at the job's own exit is ownership-based and needs no /proc heuristics
|
|
142
|
+
// to distinguish an abandoned descendant from a live one.
|
|
143
|
+
// Enumerate the still-alive members of process group `pgid` (Linux only).
|
|
144
|
+
// Read-only — never throws, never blocks the caller's exit path. Used to
|
|
145
|
+
// report what sweepChildProcessGroup is about to kill, since the kill itself
|
|
146
|
+
// is silent (ESRCH on the normal empty-group case).
|
|
147
|
+
function enumerateProcessGroupSurvivors(pgid) {
|
|
148
|
+
if (process.platform !== 'linux') return [];
|
|
149
|
+
if (!pgid || pgid <= 1) return [];
|
|
150
|
+
try {
|
|
151
|
+
const out = execFileSync('ps', ['-eo', 'pid,pgrp,pcpu,etimes,comm'], { encoding: 'utf8', timeout: 2000 });
|
|
152
|
+
const survivors = [];
|
|
153
|
+
for (const line of out.split('\n').slice(1)) {
|
|
154
|
+
const m = line.trim().match(/^(\d+)\s+(\d+)\s+([\d.]+)\s+(\d+)\s+(.+)$/);
|
|
155
|
+
if (!m) continue;
|
|
156
|
+
const [, pidStr, pgrpStr, pcpuStr, etimesStr, comm] = m;
|
|
157
|
+
if (Number(pgrpStr) !== pgid) continue;
|
|
158
|
+
survivors.push({ pid: Number(pidStr), pcpu: Number(pcpuStr), etimes: Number(etimesStr), comm });
|
|
159
|
+
}
|
|
160
|
+
return survivors;
|
|
161
|
+
} catch {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Returns the leaked descendants found (see enumerateProcessGroupSurvivors),
|
|
167
|
+
// having enumerated them BEFORE issuing SIGTERM so the report reflects what
|
|
168
|
+
// was actually swept, not what happened to still be running afterward.
|
|
169
|
+
function sweepChildProcessGroup(child, detached) {
|
|
170
|
+
if (!detached) return [];
|
|
171
|
+
if (!child || !child.pid || child.pid <= 1) return [];
|
|
172
|
+
// Defensive: never target the Session Manager process's own group.
|
|
173
|
+
if (child.pid === process.pid) return [];
|
|
174
|
+
|
|
175
|
+
const leaked = enumerateProcessGroupSurvivors(child.pid).filter((p) => p.pid !== child.pid);
|
|
176
|
+
|
|
177
|
+
try { process.kill(-child.pid, 'SIGTERM'); } catch { /* ESRCH: empty group, the normal case */ }
|
|
178
|
+
|
|
179
|
+
const t = setTimeout(() => {
|
|
180
|
+
try { process.kill(-child.pid, 'SIGKILL'); } catch { /* ESRCH: empty group, the normal case */ }
|
|
181
|
+
}, POST_EXIT_GROUP_SWEEP_GRACE_MS);
|
|
182
|
+
if (t.unref) t.unref();
|
|
183
|
+
|
|
184
|
+
return leaked;
|
|
185
|
+
}
|
|
186
|
+
|
|
122
187
|
function withChildAndLog({ fd, logPath, safeLog, closeFd, spawn: spawnSpec, watchdogs = [], onExit }) {
|
|
123
188
|
const startedAt = Date.now();
|
|
124
189
|
|
|
@@ -173,6 +238,7 @@ function withChildAndLog({ fd, logPath, safeLog, closeFd, spawn: spawnSpec, watc
|
|
|
173
238
|
// calls onExit (caller may still safeLog inside), then closes the fd.
|
|
174
239
|
const handleDone = (exitCode, signal, error, spawnFailed) => {
|
|
175
240
|
clearAllTimers();
|
|
241
|
+
const leakedDescendants = sweepChildProcessGroup(ctx.child, !!spawnSpec.options?.detached);
|
|
176
242
|
if (onExit) {
|
|
177
243
|
onExit({
|
|
178
244
|
exitCode,
|
|
@@ -180,6 +246,7 @@ function withChildAndLog({ fd, logPath, safeLog, closeFd, spawn: spawnSpec, watc
|
|
|
180
246
|
killedByWatchdog: ctx.killedByWatchdog,
|
|
181
247
|
error,
|
|
182
248
|
spawnFailed: spawnFailed ?? false,
|
|
249
|
+
leakedDescendants,
|
|
183
250
|
safeLog,
|
|
184
251
|
});
|
|
185
252
|
}
|
|
@@ -215,4 +282,4 @@ function withChildAndLog({ fd, logPath, safeLog, closeFd, spawn: spawnSpec, watc
|
|
|
215
282
|
return { child, cancel };
|
|
216
283
|
}
|
|
217
284
|
|
|
218
|
-
module.exports = { openLog, withChildAndLog };
|
|
285
|
+
module.exports = { openLog, withChildAndLog, POST_EXIT_GROUP_SWEEP_GRACE_MS };
|
|
@@ -39,4 +39,57 @@ function resolveClaudeBin() {
|
|
|
39
39
|
return cached;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
// ---------- version probe ----------
|
|
43
|
+
//
|
|
44
|
+
// `claude --version`, cached. The scheduler's launch circuit breaker
|
|
45
|
+
// (lib/launchFailure.cjs) records the CLI version a launch block was armed
|
|
46
|
+
// under and drops the block the moment the version changes — the incident
|
|
47
|
+
// behind it (issue #11: an outdated CLI sending a thinking parameter the
|
|
48
|
+
// model rejects) is fixed by `claude update`, and the queue must notice
|
|
49
|
+
// that without a human pressing anything. Async, bounded, never throws:
|
|
50
|
+
// a probe failure yields null and the breaker simply loses the
|
|
51
|
+
// version-change shortcut (backoff still recovers).
|
|
52
|
+
const VERSION_TTL_MS = 5 * 60_000;
|
|
53
|
+
const VERSION_PROBE_TIMEOUT_MS = 8_000;
|
|
54
|
+
let versionCache = { at: 0, value: null, inflight: null };
|
|
55
|
+
|
|
56
|
+
function probeClaudeVersion({ now = Date.now(), execFileImpl } = {}) {
|
|
57
|
+
// Operator/test pin: skips executing the binary entirely.
|
|
58
|
+
if (process.env.SM_CLAUDE_VERSION) return Promise.resolve(process.env.SM_CLAUDE_VERSION);
|
|
59
|
+
if (versionCache.inflight) return versionCache.inflight;
|
|
60
|
+
if (versionCache.value !== null && now - versionCache.at < VERSION_TTL_MS) {
|
|
61
|
+
return Promise.resolve(versionCache.value);
|
|
62
|
+
}
|
|
63
|
+
const execFile = execFileImpl || require('node:child_process').execFile;
|
|
64
|
+
const bin = resolveClaudeBin();
|
|
65
|
+
versionCache.inflight = new Promise((resolve) => {
|
|
66
|
+
let settled = false;
|
|
67
|
+
const done = (value) => {
|
|
68
|
+
if (settled) return;
|
|
69
|
+
settled = true;
|
|
70
|
+
versionCache = { at: Date.now(), value, inflight: null };
|
|
71
|
+
resolve(value);
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
// cwd is a neutral temp dir on purpose: the version does not depend on
|
|
75
|
+
// it, and the binary must never be handed the caller's working tree —
|
|
76
|
+
// a stub `claude` (tests point SM_CLAUDE_BIN at one) that writes
|
|
77
|
+
// markers or commits into process.cwd() once did so in the real repo.
|
|
78
|
+
execFile(bin, ['--version'], { timeout: VERSION_PROBE_TIMEOUT_MS, windowsHide: true, cwd: os.tmpdir() }, (err, stdout) => {
|
|
79
|
+
if (err) return done(null);
|
|
80
|
+
const m = /(\d+\.\d+\.\d+[^\s]*)/.exec(String(stdout || ''));
|
|
81
|
+
done(m ? m[1] : (String(stdout || '').trim() || null));
|
|
82
|
+
});
|
|
83
|
+
} catch {
|
|
84
|
+
done(null);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
return versionCache.inflight;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Test hook — forget the cached version so the next probe re-executes. */
|
|
91
|
+
function resetClaudeVersionCache() {
|
|
92
|
+
versionCache = { at: 0, value: null, inflight: null };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = { resolveClaudeBin, probeClaudeVersion, resetClaudeVersionCache };
|
|
@@ -66,6 +66,7 @@ const {
|
|
|
66
66
|
} = require('./epicMint.cjs');
|
|
67
67
|
const { appendAuditEvent } = require('./auditLog.cjs');
|
|
68
68
|
const { OPS_ROOT_DIR } = require('./opsOwnership.cjs');
|
|
69
|
+
const { resolveProjectContext } = require('./projectRootResolve.cjs');
|
|
69
70
|
|
|
70
71
|
/** Only these three Epic tags make sense for an inbound report — they are
|
|
71
72
|
* exactly the tags that route through /develop (tagLibrary.ts). 'build',
|
|
@@ -251,8 +252,14 @@ function validateFeedbackInput(input = {}) {
|
|
|
251
252
|
} catch (e) {
|
|
252
253
|
return bad(400, `toCwd rejected: ${e.message}`);
|
|
253
254
|
}
|
|
255
|
+
// Normalize fromCwd (worktree -> main tree, ops-internal path -> project
|
|
256
|
+
// root) BEFORE validatePath/the same-project check below — an agent
|
|
257
|
+
// sending feedback from inside its own Epic's worktree pwd must be
|
|
258
|
+
// compared/chained against its REAL project, not the ephemeral checkout.
|
|
259
|
+
// See projectRootResolve.cjs's header.
|
|
260
|
+
const normalizedFromCwd = resolveProjectContext({ cwd: input.fromCwd }).cwd || input.fromCwd;
|
|
254
261
|
try {
|
|
255
|
-
fromCwd = config.validatePath(path.resolve(
|
|
262
|
+
fromCwd = config.validatePath(path.resolve(normalizedFromCwd));
|
|
256
263
|
} catch (e) {
|
|
257
264
|
return bad(400, `fromCwd rejected: ${e.message}`);
|
|
258
265
|
}
|
|
@@ -328,7 +328,7 @@ const RISK_HEURISTICS = [
|
|
|
328
328
|
* @param {string} headingText Case-insensitive heading to find.
|
|
329
329
|
* @returns {string}
|
|
330
330
|
*/
|
|
331
|
-
function
|
|
331
|
+
function extractSection(body, headingText) {
|
|
332
332
|
const escapedHeading = headingText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
333
333
|
const headingRe = new RegExp(`^#+\\s+${escapedHeading}`, 'i');
|
|
334
334
|
const lines = body.split('\n');
|
|
@@ -398,7 +398,7 @@ function flagRiskySurfaces(jobs, { prdsDir, gitTimeoutMs = 10_000 } = {}) {
|
|
|
398
398
|
try {
|
|
399
399
|
const raw = fs.readFileSync(path.join(resolvedPrdsDir, `${job.slug}.md`), 'utf8');
|
|
400
400
|
const body = splitFrontmatter(raw).body;
|
|
401
|
-
candidateText =
|
|
401
|
+
candidateText = extractSection(body, 'Implementation notes');
|
|
402
402
|
} catch { /* no candidate text — skip */ }
|
|
403
403
|
}
|
|
404
404
|
|
|
@@ -573,6 +573,7 @@ module.exports = {
|
|
|
573
573
|
reportPathFor,
|
|
574
574
|
reportExists,
|
|
575
575
|
extractAcCommand,
|
|
576
|
+
extractSection,
|
|
576
577
|
reverifyAc,
|
|
577
578
|
reverifyBatch,
|
|
578
579
|
flagRiskySurfaces,
|