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
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* First-boot seeder for the bundled Agent personas
|
|
2
|
+
* First-boot (and stay-current) seeder for the bundled Agent personas.
|
|
3
3
|
*
|
|
4
4
|
* On a fresh install `~/.claude/agents/` is empty, so the Agent Library has
|
|
5
5
|
* nothing to offer — no persona to select for an Epic's Actor. This seeder
|
|
6
|
-
* copies the personas bundled at `src/seed/agents/*.md` into `~/.claude/agents
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* copies the personas bundled at `src/seed/agents/*.md` into `~/.claude/agents/`,
|
|
7
|
+
* one file per persona, and NEVER overwrites a file that already exists there
|
|
8
|
+
* (hand-edited or user-authored personas win).
|
|
9
9
|
*
|
|
10
|
-
* Idempotent the same way as seedDevPlugin.cjs
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* Idempotent the same way as seedDevPlugin.cjs, but per-persona rather than
|
|
11
|
+
* whole-run: the marker (`~/.claude/session-manager/.agent-personas-seeded`)
|
|
12
|
+
* records the SET of persona names already delivered (`seeded: string[]`),
|
|
13
|
+
* not just a single `done` flag. Every boot, any name in `PERSONAS` not yet in
|
|
14
|
+
* that set gets copied (subject to the same never-overwrite guard) and added
|
|
15
|
+
* to the set. This is what lets a persona added to `PERSONAS` in a later
|
|
16
|
+
* release reach a machine that already booted successfully long ago — a
|
|
17
|
+
* plain one-shot `done:true` would silently never re-run and that persona
|
|
18
|
+
* would never arrive. A name already in `seeded` is skipped even if its
|
|
19
|
+
* on-disk file was later deleted by hand — deleting a seeded persona is
|
|
20
|
+
* read as an intentional opt-out, not a request to reseed it.
|
|
21
|
+
*
|
|
22
|
+
* A whole-run FAILURE (thrown before any per-persona copy could be attempted,
|
|
23
|
+
* e.g. the bundled source dir is missing) only bumps an attempt counter and
|
|
24
|
+
* retries on the next few boots (bounded by MAX_ATTEMPTS); once attempts are
|
|
25
|
+
* exhausted the seeder gives up permanently and the machine is left exactly
|
|
26
|
+
* where it was — whatever subset of `PERSONAS` it had already reached stays
|
|
27
|
+
* in `seeded`, nothing is retried automatically, and delivering the rest is a
|
|
28
|
+
* manual copy. This is a deliberate choice: an install that has already
|
|
29
|
+
* failed MAX_ATTEMPTS times has something wrong with it (e.g. a read-only
|
|
30
|
+
* home dir) that retrying forever would not fix, and endlessly retrying on
|
|
31
|
+
* every boot would cost a syscall per persona per boot for no benefit.
|
|
16
32
|
*
|
|
17
33
|
* Fire-and-forget: called post-window from index.cjs. Errors are logged,
|
|
18
34
|
* never thrown. Kill-switch: SM_SEED_AGENT_PERSONAS_DISABLE=1.
|
|
@@ -23,7 +39,12 @@ const path = require('node:path');
|
|
|
23
39
|
const os = require('node:os');
|
|
24
40
|
const { writeJsonSync } = require('./config.cjs');
|
|
25
41
|
|
|
26
|
-
const PERSONAS = ['architect', 'dev-lead'];
|
|
42
|
+
const PERSONAS = ['architect', 'dev-lead', 'project-home-builder'];
|
|
43
|
+
// What `{ done: true }` (the pre-seeded-set marker format) meant: only these two personas existed
|
|
44
|
+
// in PERSONAS at the time. Fixed, not derived from the current PERSONAS array above — otherwise
|
|
45
|
+
// every future persona added to PERSONAS would retroactively count as already delivered to a
|
|
46
|
+
// machine that finished its run under the old format, and would silently never seed there.
|
|
47
|
+
const LEGACY_DONE_PERSONAS = ['architect', 'dev-lead'];
|
|
27
48
|
const MAX_ATTEMPTS = 3; // give a transient first-boot failure a few chances
|
|
28
49
|
|
|
29
50
|
function bundledSourceDir() {
|
|
@@ -38,14 +59,30 @@ function markerPath() {
|
|
|
38
59
|
return path.join(os.homedir(), '.claude', 'session-manager', '.agent-personas-seeded');
|
|
39
60
|
}
|
|
40
61
|
|
|
41
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Read the marker → { seeded:string[], attempts:number }. Absent/corrupt/
|
|
64
|
+
* legacy = treated as fresh (a corrupt marker must never block seeding — a
|
|
65
|
+
* try/catch here is load-bearing, not defensive filler).
|
|
66
|
+
*
|
|
67
|
+
* Back-compat: an old-format marker (`{ done: true }`, no `seeded` array)
|
|
68
|
+
* reads as `seeded: LEGACY_DONE_PERSONAS` (the fixed set that existed when
|
|
69
|
+
* that format was the only one) — a machine that already completed a full
|
|
70
|
+
* run under the old scheme picks up only personas added to `PERSONAS` since,
|
|
71
|
+
* not a spurious reseed of architect/dev-lead.
|
|
72
|
+
*/
|
|
42
73
|
function readMarker() {
|
|
43
74
|
try {
|
|
44
75
|
const raw = fs.readFileSync(markerPath(), 'utf8').trim();
|
|
45
76
|
const m = JSON.parse(raw);
|
|
46
|
-
|
|
77
|
+
if (Array.isArray(m.seeded)) {
|
|
78
|
+
return { seeded: m.seeded.filter((n) => typeof n === 'string'), attempts: Number(m.attempts) || 0 };
|
|
79
|
+
}
|
|
80
|
+
if (m.done) {
|
|
81
|
+
return { seeded: [...LEGACY_DONE_PERSONAS], attempts: Number(m.attempts) || 0 };
|
|
82
|
+
}
|
|
83
|
+
return { seeded: [], attempts: Number(m.attempts) || 0 };
|
|
47
84
|
} catch {
|
|
48
|
-
return {
|
|
85
|
+
return { seeded: [], attempts: 0 };
|
|
49
86
|
}
|
|
50
87
|
}
|
|
51
88
|
|
|
@@ -60,23 +97,27 @@ function writeMarker(state) {
|
|
|
60
97
|
async function seedAgentPersonas({ logger = console, writeLog = () => {} } = {}) {
|
|
61
98
|
if (process.env.SM_SEED_AGENT_PERSONAS_DISABLE === '1') return;
|
|
62
99
|
const marker = readMarker();
|
|
63
|
-
|
|
100
|
+
const pending = PERSONAS.filter((name) => !marker.seeded.includes(name));
|
|
101
|
+
if (pending.length === 0) return; // every known persona already delivered.
|
|
64
102
|
if (marker.attempts >= MAX_ATTEMPTS) return; // gave up — manual copy only.
|
|
65
103
|
|
|
104
|
+
const seeded = [...marker.seeded];
|
|
66
105
|
try {
|
|
67
106
|
const srcDir = bundledSourceDir();
|
|
68
107
|
const destDir = destAgentsDir();
|
|
69
108
|
fs.mkdirSync(destDir, { recursive: true });
|
|
70
109
|
|
|
71
|
-
for (const name of
|
|
110
|
+
for (const name of pending) {
|
|
72
111
|
const src = path.join(srcDir, `${name}.md`);
|
|
73
112
|
const dest = path.join(destDir, `${name}.md`);
|
|
74
|
-
if (fs.existsSync(dest))
|
|
75
|
-
|
|
76
|
-
|
|
113
|
+
if (!fs.existsSync(dest)) {
|
|
114
|
+
fs.copyFileSync(src, dest);
|
|
115
|
+
logger.log?.(`[seedAgentPersonas] seeded ${name}.md`);
|
|
116
|
+
}
|
|
117
|
+
seeded.push(name); // never overwrite an existing persona, but count it delivered either way
|
|
77
118
|
}
|
|
78
119
|
|
|
79
|
-
writeMarker({
|
|
120
|
+
writeMarker({ seeded, attempts: marker.attempts });
|
|
80
121
|
} catch (err) {
|
|
81
122
|
logger.warn?.('[seedAgentPersonas] error:', err?.message ?? err);
|
|
82
123
|
writeLog({
|
|
@@ -85,7 +126,7 @@ async function seedAgentPersonas({ logger = console, writeLog = () => {} } = {})
|
|
|
85
126
|
message: 'seed error',
|
|
86
127
|
meta: { error: err?.message ?? String(err), attempt: marker.attempts + 1, maxAttempts: MAX_ATTEMPTS },
|
|
87
128
|
});
|
|
88
|
-
writeMarker({
|
|
129
|
+
writeMarker({ seeded, attempts: marker.attempts + 1 });
|
|
89
130
|
}
|
|
90
131
|
}
|
|
91
132
|
|
|
@@ -81,6 +81,27 @@ function alreadyRegistered() {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* true only when the user-scope entry EXISTS but its script arg no longer
|
|
86
|
+
* resolves on disk (repo moved, worktree deleted). An entry that is entirely
|
|
87
|
+
* ABSENT is a deliberate `claude mcp remove` and must stay removed — that
|
|
88
|
+
* case returns false here, same as any other "not registered" read.
|
|
89
|
+
*/
|
|
90
|
+
function scriptPathMissing() {
|
|
91
|
+
try {
|
|
92
|
+
const raw = fs.readFileSync(path.join(os.homedir(), '.claude.json'), 'utf8');
|
|
93
|
+
const servers = JSON.parse(raw)?.mcpServers;
|
|
94
|
+
const entry = servers && servers[SERVER_NAME];
|
|
95
|
+
if (!entry) return false;
|
|
96
|
+
const args = Array.isArray(entry.args) ? entry.args : [];
|
|
97
|
+
const scriptArg = args[args.length - 1];
|
|
98
|
+
if (typeof scriptArg !== 'string' || !scriptArg) return false;
|
|
99
|
+
return !fs.existsSync(scriptArg);
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
84
105
|
/** Run `claude mcp add session-manager-scheduler --scope user -- node <serverPath>`.
|
|
85
106
|
* No shell:true — argv array passed directly to spawn. */
|
|
86
107
|
function runClaudeMcpAdd(serverPath) {
|
|
@@ -106,14 +127,47 @@ function runClaudeMcpAdd(serverPath) {
|
|
|
106
127
|
});
|
|
107
128
|
}
|
|
108
129
|
|
|
109
|
-
|
|
130
|
+
/** Run `claude mcp remove session-manager-scheduler --scope user`, best-effort. */
|
|
131
|
+
function runClaudeMcpRemove() {
|
|
132
|
+
return new Promise((resolve) => {
|
|
133
|
+
const claudeBin = resolveClaudeBin();
|
|
134
|
+
let proc;
|
|
135
|
+
try {
|
|
136
|
+
proc = spawn(
|
|
137
|
+
claudeBin,
|
|
138
|
+
['mcp', 'remove', SERVER_NAME, '--scope', 'user'],
|
|
139
|
+
{ cwd: os.homedir(), env: cleanChildEnv({ PATH: pathWithUserBins() }), stdio: 'ignore' }
|
|
140
|
+
);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
resolve({ ok: false, error: err?.message ?? String(err) });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
proc.on('error', (err) => resolve({ ok: false, error: err?.message ?? String(err) }));
|
|
146
|
+
proc.on('close', (code) => resolve({ ok: code === 0, exitCode: code }));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function seedSchedulerMcp({ logger = console, addFn = runClaudeMcpAdd, removeFn = runClaudeMcpRemove, writeLog = () => {} } = {}) {
|
|
110
151
|
if (process.env.SM_SEED_SCHEDULER_MCP_DISABLE === '1') return;
|
|
111
152
|
const marker = readMarker();
|
|
112
|
-
|
|
113
|
-
|
|
153
|
+
|
|
154
|
+
// `claude mcp add` refuses when a server of this name already exists, so a
|
|
155
|
+
// repair must remove the stale entry first — but ONLY when the marker says
|
|
156
|
+
// `done` AND the registered script has actually gone missing. An entry
|
|
157
|
+
// that's simply absent (marker done, no ~/.claude.json entry at all) is a
|
|
158
|
+
// deliberate `claude mcp remove` and must stay removed exactly as today.
|
|
159
|
+
let repairing = false;
|
|
160
|
+
if (marker.done) {
|
|
161
|
+
if (!scriptPathMissing()) return;
|
|
162
|
+
repairing = true;
|
|
163
|
+
logger.warn?.('[seedSchedulerMcp] user-scope registration points at a missing script — repairing…');
|
|
164
|
+
await removeFn();
|
|
165
|
+
} else if (marker.attempts >= MAX_ATTEMPTS) {
|
|
166
|
+
return; // gave up — manual install only.
|
|
167
|
+
}
|
|
114
168
|
|
|
115
169
|
try {
|
|
116
|
-
if (alreadyRegistered()) {
|
|
170
|
+
if (!repairing && alreadyRegistered()) {
|
|
117
171
|
writeMarker({ done: true, attempts: marker.attempts });
|
|
118
172
|
return;
|
|
119
173
|
}
|