opencode-swarm 7.87.1 → 7.87.2
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/cli/{evidence-summary-service-gg5m9z57.js → evidence-summary-service-5me91eq8.js} +1 -1
- package/dist/cli/{guardrail-explain-scym5r5y.js → guardrail-explain-9fngqx80.js} +3 -3
- package/dist/cli/{index-gwzpy671.js → index-6qkwgdsg.js} +458 -163
- package/dist/cli/{index-89xjr3h4.js → index-8y7qetpg.js} +48 -19
- package/dist/cli/{index-ts2j1wjr.js → index-f41fa3f0.js} +1 -1
- package/dist/cli/{index-dsjyfd3g.js → index-gjdq4na6.js} +3 -3
- package/dist/cli/index.js +2 -2
- package/dist/commands/close.d.ts +6 -0
- package/dist/git/branch.d.ts +5 -0
- package/dist/git/pr.d.ts +18 -0
- package/dist/index.js +658 -299
- package/dist/tools/checkpoint.d.ts +1 -0
- package/dist/utils/transient-retry.d.ts +30 -0
- package/package.json +1 -1
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
stripKnownSwarmPrefix
|
|
61
61
|
} from "./index-q9h0wb04.js";
|
|
62
62
|
import {
|
|
63
|
+
MAX_TRANSIENT_RETRIES,
|
|
63
64
|
PlanSchema,
|
|
64
65
|
RetrospectiveEvidenceSchema,
|
|
65
66
|
appendLedgerEvent,
|
|
@@ -81,6 +82,7 @@ import {
|
|
|
81
82
|
isGlobalFile,
|
|
82
83
|
isProtectedPath,
|
|
83
84
|
isStateUnreadable,
|
|
85
|
+
isTransientSpawnError,
|
|
84
86
|
isValidEvidenceType,
|
|
85
87
|
listEvidenceTaskIds,
|
|
86
88
|
loadEpicSessionState,
|
|
@@ -97,9 +99,10 @@ import {
|
|
|
97
99
|
sanitizeTaskId,
|
|
98
100
|
saveEvidence,
|
|
99
101
|
savePlan,
|
|
102
|
+
transientBackoff,
|
|
100
103
|
validateProjectRoot,
|
|
101
104
|
writeProjectedSpecSync
|
|
102
|
-
} from "./index-
|
|
105
|
+
} from "./index-8y7qetpg.js";
|
|
103
106
|
import {
|
|
104
107
|
_internals as _internals2,
|
|
105
108
|
_internals1 as _internals3,
|
|
@@ -894,7 +897,7 @@ var init_executor = __esm(() => {
|
|
|
894
897
|
// package.json
|
|
895
898
|
var package_default = {
|
|
896
899
|
name: "opencode-swarm",
|
|
897
|
-
version: "7.87.
|
|
900
|
+
version: "7.87.2",
|
|
898
901
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
899
902
|
main: "dist/index.js",
|
|
900
903
|
types: "dist/index.d.ts",
|
|
@@ -5231,6 +5234,7 @@ function createSwarmTool(opts) {
|
|
|
5231
5234
|
var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
|
|
5232
5235
|
var MAX_LABEL_LENGTH = 100;
|
|
5233
5236
|
var GIT_TIMEOUT_MS = 30000;
|
|
5237
|
+
var GIT_MAX_BUFFER_BYTES = 5 * 1024 * 1024;
|
|
5234
5238
|
var SHELL_METACHARACTERS = /[;|&$`(){}<>!'"]/;
|
|
5235
5239
|
var SAFE_LABEL_PATTERN = /^[a-zA-Z0-9_ -]+$/;
|
|
5236
5240
|
var CONTROL_CHAR_PATTERN = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/;
|
|
@@ -5305,20 +5309,31 @@ function writeCheckpointLog(log2, directory) {
|
|
|
5305
5309
|
fs7.renameSync(tempPath, logPath);
|
|
5306
5310
|
}
|
|
5307
5311
|
function gitExec(args, cwd) {
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5312
|
+
for (let attempt = 0;attempt < MAX_TRANSIENT_RETRIES; attempt++) {
|
|
5313
|
+
const result = child_process.spawnSync("git", args, {
|
|
5314
|
+
cwd,
|
|
5315
|
+
encoding: "utf-8",
|
|
5316
|
+
timeout: GIT_TIMEOUT_MS,
|
|
5317
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5318
|
+
windowsHide: true,
|
|
5319
|
+
maxBuffer: GIT_MAX_BUFFER_BYTES
|
|
5320
|
+
});
|
|
5321
|
+
if (result.error) {
|
|
5322
|
+
const code = result.error.code;
|
|
5323
|
+
const message = result.error.message ?? "";
|
|
5324
|
+
const isTransient = isTransientSpawnError(result.error) || /ETIMEDOUT|timed out/i.test(message);
|
|
5325
|
+
if (!isTransient || attempt >= MAX_TRANSIENT_RETRIES - 1) {
|
|
5326
|
+
throw new Error(`git failed to start: ${code ?? "unknown"} \u2014 ${message}`);
|
|
5327
|
+
}
|
|
5328
|
+
transientBackoff(attempt);
|
|
5329
|
+
continue;
|
|
5330
|
+
}
|
|
5331
|
+
if (result.status === 0) {
|
|
5332
|
+
return result.stdout ?? "";
|
|
5333
|
+
}
|
|
5319
5334
|
throw new Error(result.stderr?.trim() || `git exited with code ${result.status}`);
|
|
5320
5335
|
}
|
|
5321
|
-
|
|
5336
|
+
throw new Error("git command failed after transient retries");
|
|
5322
5337
|
}
|
|
5323
5338
|
function appendRetentionEvent(directory, event) {
|
|
5324
5339
|
try {
|
|
@@ -5335,9 +5350,20 @@ function getCurrentSha(directory) {
|
|
|
5335
5350
|
function isGitRepo2(directory) {
|
|
5336
5351
|
try {
|
|
5337
5352
|
gitExec(["rev-parse", "--git-dir"], directory);
|
|
5338
|
-
return true;
|
|
5339
|
-
} catch {
|
|
5340
|
-
|
|
5353
|
+
return { isRepo: true };
|
|
5354
|
+
} catch (e) {
|
|
5355
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
5356
|
+
const isTransient = /ETIMEDOUT|timed out/i.test(message) && !/not a git repository/i.test(message);
|
|
5357
|
+
if (isTransient) {
|
|
5358
|
+
return {
|
|
5359
|
+
isRepo: false,
|
|
5360
|
+
warning: "git probe failed after retry exhaustion \u2014 treating as not a git repository"
|
|
5361
|
+
};
|
|
5362
|
+
}
|
|
5363
|
+
return {
|
|
5364
|
+
isRepo: false,
|
|
5365
|
+
warning: "git probe failed \u2014 directory may not be a git repository"
|
|
5366
|
+
};
|
|
5341
5367
|
}
|
|
5342
5368
|
}
|
|
5343
5369
|
function handleSave(label, directory) {
|
|
@@ -5480,11 +5506,12 @@ var checkpoint = createSwarmTool({
|
|
|
5480
5506
|
label: exports_external.string().optional().describe("Checkpoint label (required for save, restore, delete)")
|
|
5481
5507
|
},
|
|
5482
5508
|
execute: async (args, directory) => {
|
|
5483
|
-
|
|
5509
|
+
const repoProbe = isGitRepo2(directory);
|
|
5510
|
+
if (!repoProbe.isRepo) {
|
|
5484
5511
|
return JSON.stringify({
|
|
5485
5512
|
action: "unknown",
|
|
5486
5513
|
success: false,
|
|
5487
|
-
error: "not a git repository"
|
|
5514
|
+
error: `${repoProbe.warning ?? "not a git repository"} \u2014 checkpoint tools require a git repository`
|
|
5488
5515
|
}, null, 2);
|
|
5489
5516
|
}
|
|
5490
5517
|
let action;
|
|
@@ -5673,6 +5700,7 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
5673
5700
|
}
|
|
5674
5701
|
|
|
5675
5702
|
// src/commands/close.ts
|
|
5703
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
5676
5704
|
import * as fsSync2 from "fs";
|
|
5677
5705
|
import { promises as fs11 } from "fs";
|
|
5678
5706
|
import path24 from "path";
|
|
@@ -6079,7 +6107,8 @@ async function runCuratorPostMortem(directory, options = {}) {
|
|
|
6079
6107
|
} catch {
|
|
6080
6108
|
warnings.push("Failed to load plan data.");
|
|
6081
6109
|
}
|
|
6082
|
-
const
|
|
6110
|
+
const effectivePlanId = planId === "unknown" ? `unknown-${Date.now()}` : planId;
|
|
6111
|
+
const reportFilename = `post-mortem-${effectivePlanId}.md`;
|
|
6083
6112
|
let reportPath;
|
|
6084
6113
|
try {
|
|
6085
6114
|
reportPath = validateSwarmPath(directory, reportFilename);
|
|
@@ -6095,22 +6124,22 @@ async function runCuratorPostMortem(directory, options = {}) {
|
|
|
6095
6124
|
if (!options.force && isReportValid(reportPath)) {
|
|
6096
6125
|
return {
|
|
6097
6126
|
success: true,
|
|
6098
|
-
planId,
|
|
6127
|
+
planId: effectivePlanId,
|
|
6099
6128
|
reportPath,
|
|
6100
6129
|
summary: "Post-mortem report already exists (idempotent skip).",
|
|
6101
6130
|
warnings
|
|
6102
6131
|
};
|
|
6103
6132
|
}
|
|
6104
|
-
const lock = await _internals13.acquirePostMortemLock(directory,
|
|
6133
|
+
const lock = await _internals13.acquirePostMortemLock(directory, effectivePlanId);
|
|
6105
6134
|
if (!lock.acquired) {
|
|
6106
6135
|
return {
|
|
6107
6136
|
success: false,
|
|
6108
|
-
planId,
|
|
6137
|
+
planId: effectivePlanId,
|
|
6109
6138
|
reportPath,
|
|
6110
6139
|
summary: null,
|
|
6111
6140
|
warnings: [
|
|
6112
6141
|
...warnings,
|
|
6113
|
-
`Concurrent post-mortem run in progress for plan ${
|
|
6142
|
+
`Concurrent post-mortem run in progress for plan ${effectivePlanId}; skipped.`
|
|
6114
6143
|
]
|
|
6115
6144
|
};
|
|
6116
6145
|
}
|
|
@@ -6160,7 +6189,7 @@ async function runCuratorPostMortem(directory, options = {}) {
|
|
|
6160
6189
|
if (options.llmDelegate) {
|
|
6161
6190
|
try {
|
|
6162
6191
|
const { CURATOR_POSTMORTEM_PROMPT: CURATOR_POSTMORTEM_PROMPT2 } = await import("./explorer-gz70sm9b.js");
|
|
6163
|
-
const userInput = assembleLLMInput(
|
|
6192
|
+
const userInput = assembleLLMInput(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
|
|
6164
6193
|
const ac = new AbortController;
|
|
6165
6194
|
const timer = setTimeout(() => ac.abort(), 300000);
|
|
6166
6195
|
let llmOutput;
|
|
@@ -6176,17 +6205,17 @@ async function runCuratorPostMortem(directory, options = {}) {
|
|
|
6176
6205
|
} finally {
|
|
6177
6206
|
clearTimeout(timer);
|
|
6178
6207
|
}
|
|
6179
|
-
reportContent = `# Post-Mortem Report: ${
|
|
6208
|
+
reportContent = `# Post-Mortem Report: ${effectivePlanId}
|
|
6180
6209
|
Generated: ${new Date().toISOString()}
|
|
6181
6210
|
|
|
6182
6211
|
${llmOutput}`;
|
|
6183
6212
|
} catch (err) {
|
|
6184
6213
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6185
6214
|
warnings.push(`LLM delegate failed, falling back to data-only report: ${msg}`);
|
|
6186
|
-
reportContent = _internals13.buildDataOnlyReport(
|
|
6215
|
+
reportContent = _internals13.buildDataOnlyReport(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
|
|
6187
6216
|
}
|
|
6188
6217
|
} else {
|
|
6189
|
-
reportContent = _internals13.buildDataOnlyReport(
|
|
6218
|
+
reportContent = _internals13.buildDataOnlyReport(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
|
|
6190
6219
|
}
|
|
6191
6220
|
try {
|
|
6192
6221
|
const { mkdirSync: mkdirSync6 } = await import("fs");
|
|
@@ -6196,7 +6225,7 @@ ${llmOutput}`;
|
|
|
6196
6225
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6197
6226
|
return {
|
|
6198
6227
|
success: false,
|
|
6199
|
-
planId,
|
|
6228
|
+
planId: effectivePlanId,
|
|
6200
6229
|
reportPath: null,
|
|
6201
6230
|
summary: null,
|
|
6202
6231
|
warnings: [...warnings, `Failed to write report: ${msg}`]
|
|
@@ -6206,13 +6235,13 @@ ${llmOutput}`;
|
|
|
6206
6235
|
const neverAppliedCount = knowledgeSummary.filter((e) => e.applied === 0 && e.violated === 0 && e.ignored === 0).length;
|
|
6207
6236
|
const totalViolations = knowledgeSummary.reduce((s, e) => s + e.violated, 0);
|
|
6208
6237
|
const summary = [
|
|
6209
|
-
`Post-mortem for plan "${
|
|
6238
|
+
`Post-mortem for plan "${effectivePlanId}": ${totalEntries} knowledge entries reviewed.`,
|
|
6210
6239
|
`${neverAppliedCount} never-applied entries flagged; ${totalViolations} total violations recorded.`,
|
|
6211
6240
|
`${proposals.length} pending proposals, ${unactionable.length} quarantined entries.`
|
|
6212
6241
|
].join(" ");
|
|
6213
6242
|
return {
|
|
6214
6243
|
success: true,
|
|
6215
|
-
planId,
|
|
6244
|
+
planId: effectivePlanId,
|
|
6216
6245
|
reportPath,
|
|
6217
6246
|
summary,
|
|
6218
6247
|
warnings
|
|
@@ -11097,8 +11126,9 @@ function countSessionKnowledgeEntries(entries, sessionStart, fallbackCount) {
|
|
|
11097
11126
|
return Number.isFinite(createdAtMs) && createdAtMs >= sessionStartMs;
|
|
11098
11127
|
}).length;
|
|
11099
11128
|
}
|
|
11100
|
-
async function
|
|
11129
|
+
async function copyDirRecursiveWithFailures(src, dest) {
|
|
11101
11130
|
let count = 0;
|
|
11131
|
+
const failures = [];
|
|
11102
11132
|
const entries = await fs11.readdir(src);
|
|
11103
11133
|
await fs11.mkdir(dest, { recursive: true });
|
|
11104
11134
|
for (const entry of entries) {
|
|
@@ -11107,17 +11137,32 @@ async function copyDirRecursive(src, dest) {
|
|
|
11107
11137
|
try {
|
|
11108
11138
|
const stat4 = await fs11.stat(srcEntry);
|
|
11109
11139
|
if (stat4.isDirectory()) {
|
|
11110
|
-
const
|
|
11111
|
-
count +=
|
|
11140
|
+
const subResult = await copyDirRecursiveWithFailures(srcEntry, destEntry);
|
|
11141
|
+
count += subResult.copied;
|
|
11142
|
+
failures.push(...subResult.failures);
|
|
11112
11143
|
} else {
|
|
11113
11144
|
try {
|
|
11114
11145
|
await fs11.copyFile(srcEntry, destEntry);
|
|
11115
11146
|
count++;
|
|
11116
|
-
} catch {
|
|
11147
|
+
} catch (err) {
|
|
11148
|
+
const errno = err?.code;
|
|
11149
|
+
if (errno !== "ENOENT") {
|
|
11150
|
+
failures.push(`${srcEntry}: ${err instanceof Error ? err.message : String(err)}`);
|
|
11151
|
+
}
|
|
11152
|
+
}
|
|
11117
11153
|
}
|
|
11118
|
-
} catch {
|
|
11154
|
+
} catch (err) {
|
|
11155
|
+
const errno = err?.code;
|
|
11156
|
+
if (errno !== "ENOENT") {
|
|
11157
|
+
failures.push(`${srcEntry}: ${err instanceof Error ? err.message : String(err)}`);
|
|
11158
|
+
}
|
|
11159
|
+
}
|
|
11119
11160
|
}
|
|
11120
|
-
return count;
|
|
11161
|
+
return { copied: count, failures };
|
|
11162
|
+
}
|
|
11163
|
+
async function copyDirRecursive(src, dest) {
|
|
11164
|
+
const result = await copyDirRecursiveWithFailures(src, dest);
|
|
11165
|
+
return result.copied;
|
|
11121
11166
|
}
|
|
11122
11167
|
var ARCHIVE_ARTIFACTS = [
|
|
11123
11168
|
"plan.json",
|
|
@@ -11436,31 +11481,145 @@ async function runFinalizeStage(ctx) {
|
|
|
11436
11481
|
ctx.warnings.push(`Post-mortem failed: ${msg}`);
|
|
11437
11482
|
}
|
|
11438
11483
|
}
|
|
11484
|
+
async function copySqliteSafe(srcPath, destPath) {
|
|
11485
|
+
if (!fsSync2.existsSync(srcPath)) {
|
|
11486
|
+
return {
|
|
11487
|
+
success: true,
|
|
11488
|
+
skipped: true,
|
|
11489
|
+
reason: "source does not exist (ENOENT)"
|
|
11490
|
+
};
|
|
11491
|
+
}
|
|
11492
|
+
let checkpointVerified = false;
|
|
11493
|
+
try {
|
|
11494
|
+
const result = spawnSync5("sqlite3", [srcPath, "PRAGMA wal_checkpoint(TRUNCATE);"], {
|
|
11495
|
+
cwd: path24.dirname(srcPath),
|
|
11496
|
+
encoding: "utf-8",
|
|
11497
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
11498
|
+
timeout: 1e4,
|
|
11499
|
+
windowsHide: true,
|
|
11500
|
+
maxBuffer: 1024
|
|
11501
|
+
});
|
|
11502
|
+
if (result.error) {
|
|
11503
|
+
const code = result.error.code;
|
|
11504
|
+
if (code === "ENOENT") {
|
|
11505
|
+
try {
|
|
11506
|
+
await fs11.copyFile(srcPath, destPath);
|
|
11507
|
+
return {
|
|
11508
|
+
success: true,
|
|
11509
|
+
reason: "copied without WAL checkpoint (sqlite3 CLI unavailable)"
|
|
11510
|
+
};
|
|
11511
|
+
} catch (copyErr) {
|
|
11512
|
+
return {
|
|
11513
|
+
success: false,
|
|
11514
|
+
reason: `fallback copy failed: ${copyErr instanceof Error ? copyErr.message : String(copyErr)}`
|
|
11515
|
+
};
|
|
11516
|
+
}
|
|
11517
|
+
}
|
|
11518
|
+
return {
|
|
11519
|
+
success: false,
|
|
11520
|
+
reason: `wal_checkpoint failed: ${result.error instanceof Error ? result.error.message : String(result.error)}`
|
|
11521
|
+
};
|
|
11522
|
+
}
|
|
11523
|
+
if (result.status !== 0) {
|
|
11524
|
+
return {
|
|
11525
|
+
success: false,
|
|
11526
|
+
reason: `wal_checkpoint exited with code ${result.status}`
|
|
11527
|
+
};
|
|
11528
|
+
}
|
|
11529
|
+
const output = (result.stdout || "").trim();
|
|
11530
|
+
const lines = output.split(`
|
|
11531
|
+
`).filter((l) => l.trim());
|
|
11532
|
+
if (lines.length >= 1) {
|
|
11533
|
+
const dataLine = lines[0];
|
|
11534
|
+
const columns = dataLine.split("|");
|
|
11535
|
+
const busyFlag = parseInt(columns[0], 10);
|
|
11536
|
+
checkpointVerified = !Number.isNaN(busyFlag) && busyFlag === 0;
|
|
11537
|
+
}
|
|
11538
|
+
} catch (err) {
|
|
11539
|
+
return {
|
|
11540
|
+
success: false,
|
|
11541
|
+
reason: `wal_checkpoint error: ${err instanceof Error ? err.message : String(err)}`
|
|
11542
|
+
};
|
|
11543
|
+
}
|
|
11544
|
+
try {
|
|
11545
|
+
await fs11.copyFile(srcPath, destPath);
|
|
11546
|
+
if (checkpointVerified) {
|
|
11547
|
+
return { success: true };
|
|
11548
|
+
}
|
|
11549
|
+
return {
|
|
11550
|
+
success: true,
|
|
11551
|
+
reason: "WAL checkpoint incomplete (busy) \u2014 archive copy may be stale, original preserved"
|
|
11552
|
+
};
|
|
11553
|
+
} catch (err) {
|
|
11554
|
+
return {
|
|
11555
|
+
success: false,
|
|
11556
|
+
reason: `copy failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11557
|
+
};
|
|
11558
|
+
}
|
|
11559
|
+
}
|
|
11439
11560
|
async function runArchiveStage(ctx) {
|
|
11440
11561
|
ctx.timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
11441
11562
|
ctx.archiveSuffix = Math.random().toString(36).slice(2, 8);
|
|
11442
11563
|
ctx.archiveDir = path24.join(ctx.swarmDir, "archive", `swarm-${ctx.timestamp}-${ctx.archiveSuffix}`);
|
|
11443
11564
|
try {
|
|
11444
11565
|
await fs11.mkdir(ctx.archiveDir, { recursive: true });
|
|
11566
|
+
const WAL_SIDECAR_FILES = new Set(["swarm.db-shm", "swarm.db-wal"]);
|
|
11445
11567
|
for (const artifact of ARCHIVE_ARTIFACTS) {
|
|
11568
|
+
if (WAL_SIDECAR_FILES.has(artifact)) {
|
|
11569
|
+
continue;
|
|
11570
|
+
}
|
|
11446
11571
|
const srcPath = path24.join(ctx.swarmDir, artifact);
|
|
11447
11572
|
const destPath = path24.join(ctx.archiveDir, artifact);
|
|
11448
|
-
|
|
11449
|
-
await
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
|
|
11573
|
+
if (artifact === "swarm.db") {
|
|
11574
|
+
const result = await copySqliteSafe(srcPath, destPath);
|
|
11575
|
+
if (result.skipped) {} else if (result.success) {
|
|
11576
|
+
ctx.archivedFileCount++;
|
|
11577
|
+
if (result.reason) {
|
|
11578
|
+
ctx.warnings.push(`Archived ${artifact}: ${result.reason}. Original preserved to prevent data loss.`);
|
|
11579
|
+
} else {
|
|
11580
|
+
ctx.archivedActiveStateFiles.add(artifact);
|
|
11581
|
+
}
|
|
11582
|
+
} else {
|
|
11583
|
+
ctx.archiveFailureReasons.set(artifact, result.reason);
|
|
11584
|
+
ctx.warnings.push(`Failed to archive ${artifact}: ${result.reason}. File preserved (not cleaned up).`);
|
|
11453
11585
|
}
|
|
11454
|
-
}
|
|
11586
|
+
} else {
|
|
11587
|
+
try {
|
|
11588
|
+
await fs11.copyFile(srcPath, destPath);
|
|
11589
|
+
ctx.archivedFileCount++;
|
|
11590
|
+
if (ACTIVE_STATE_TO_CLEAN.includes(artifact)) {
|
|
11591
|
+
ctx.archivedActiveStateFiles.add(artifact);
|
|
11592
|
+
}
|
|
11593
|
+
} catch (err) {
|
|
11594
|
+
const errno = err?.code;
|
|
11595
|
+
if (errno === "ENOENT") {} else {
|
|
11596
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11597
|
+
ctx.archiveFailureReasons.set(artifact, `${errno ?? "unknown"}: ${reason}`);
|
|
11598
|
+
ctx.warnings.push(`Failed to archive ${artifact} [${errno ?? "unknown"}]: ${reason}. File preserved (not cleaned up).`);
|
|
11599
|
+
}
|
|
11600
|
+
}
|
|
11601
|
+
}
|
|
11455
11602
|
}
|
|
11456
11603
|
for (const dirName of ACTIVE_STATE_DIRS_TO_CLEAN) {
|
|
11457
11604
|
const srcDir = path24.join(ctx.swarmDir, dirName);
|
|
11458
11605
|
const destDir = path24.join(ctx.archiveDir, dirName);
|
|
11459
11606
|
try {
|
|
11460
|
-
const
|
|
11461
|
-
ctx.archivedFileCount += copied;
|
|
11462
|
-
|
|
11463
|
-
|
|
11607
|
+
const result = await copyDirRecursiveWithFailures(srcDir, destDir);
|
|
11608
|
+
ctx.archivedFileCount += result.copied;
|
|
11609
|
+
if (result.failures.length === 0) {
|
|
11610
|
+
ctx.archivedActiveStateDirs.add(dirName);
|
|
11611
|
+
} else {
|
|
11612
|
+
ctx.warnings.push(`Directory ${dirName} not fully archived (${result.failures.length} failure(s)). Source preserved.`);
|
|
11613
|
+
for (const failure of result.failures) {
|
|
11614
|
+
ctx.warnings.push(` - ${failure}`);
|
|
11615
|
+
}
|
|
11616
|
+
}
|
|
11617
|
+
} catch (err) {
|
|
11618
|
+
const code = err.code;
|
|
11619
|
+
if (code !== "ENOENT") {
|
|
11620
|
+
ctx.warnings.push(`Failed to archive directory ${dirName} [${code ?? "unknown"}]: ${err.message}. Source preserved.`);
|
|
11621
|
+
}
|
|
11622
|
+
}
|
|
11464
11623
|
}
|
|
11465
11624
|
ctx.archiveResult = `Archived ${ctx.archivedFileCount} artifact(s) to .swarm/archive/swarm-${ctx.timestamp}-${ctx.archiveSuffix}/`;
|
|
11466
11625
|
} catch (archiveError) {
|
|
@@ -11501,14 +11660,21 @@ async function runCleanStage(ctx) {
|
|
|
11501
11660
|
if (ctx.archivedActiveStateFiles.size > 0) {
|
|
11502
11661
|
for (const artifact of ACTIVE_STATE_TO_CLEAN) {
|
|
11503
11662
|
if (!ctx.archivedActiveStateFiles.has(artifact)) {
|
|
11504
|
-
ctx.
|
|
11663
|
+
const reason = ctx.archiveFailureReasons?.get(artifact);
|
|
11664
|
+
ctx.warnings.push(reason ? `Preserved ${artifact} because it was not successfully archived: ${reason}.` : `Preserved ${artifact} because it was not successfully archived.`);
|
|
11505
11665
|
continue;
|
|
11506
11666
|
}
|
|
11507
11667
|
const filePath = path24.join(ctx.swarmDir, artifact);
|
|
11508
11668
|
try {
|
|
11509
11669
|
await fs11.unlink(filePath);
|
|
11510
11670
|
cleanedFiles.push(artifact);
|
|
11511
|
-
} catch {
|
|
11671
|
+
} catch (err) {
|
|
11672
|
+
const errno = err?.code;
|
|
11673
|
+
if (errno === "ENOENT") {} else {
|
|
11674
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11675
|
+
ctx.warnings.push(`Failed to clean active-state file ${artifact} [${errno ?? "unknown"}]: ${reason}`);
|
|
11676
|
+
}
|
|
11677
|
+
}
|
|
11512
11678
|
}
|
|
11513
11679
|
} else {
|
|
11514
11680
|
ctx.warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");
|
|
@@ -11530,15 +11696,33 @@ async function runCleanStage(ctx) {
|
|
|
11530
11696
|
try {
|
|
11531
11697
|
await fs11.unlink(path24.join(ctx.swarmDir, backup));
|
|
11532
11698
|
configBackupsRemoved++;
|
|
11533
|
-
} catch {
|
|
11699
|
+
} catch (err) {
|
|
11700
|
+
const errno = err?.code;
|
|
11701
|
+
if (errno === "ENOENT") {} else {
|
|
11702
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11703
|
+
ctx.warnings.push(`Failed to clean config-backup ${backup} [${errno ?? "unknown"}]: ${reason}`);
|
|
11704
|
+
}
|
|
11705
|
+
}
|
|
11534
11706
|
}
|
|
11535
11707
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
11536
11708
|
for (const sibling of ledgerSiblings) {
|
|
11537
11709
|
try {
|
|
11538
11710
|
await fs11.unlink(path24.join(ctx.swarmDir, sibling));
|
|
11539
|
-
} catch {
|
|
11711
|
+
} catch (err) {
|
|
11712
|
+
const errno = err?.code;
|
|
11713
|
+
if (errno === "ENOENT") {} else {
|
|
11714
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11715
|
+
ctx.warnings.push(`Failed to clean ledger sibling ${sibling} [${errno ?? "unknown"}]: ${reason}`);
|
|
11716
|
+
}
|
|
11717
|
+
}
|
|
11540
11718
|
}
|
|
11541
|
-
} catch {
|
|
11719
|
+
} catch (err) {
|
|
11720
|
+
const errno = err?.code;
|
|
11721
|
+
if (errno === "ENOENT") {} else {
|
|
11722
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11723
|
+
ctx.warnings.push(`Failed to read ${ctx.swarmDir} for stale-file cleanup [${errno ?? "unknown"}]: ${reason}`);
|
|
11724
|
+
}
|
|
11725
|
+
}
|
|
11542
11726
|
let swarmPlanFilesRemoved = 0;
|
|
11543
11727
|
const candidates = [
|
|
11544
11728
|
path24.join(ctx.directory, ".swarm", "SWARM_PLAN.json"),
|
|
@@ -11564,9 +11748,21 @@ async function runCleanStage(ctx) {
|
|
|
11564
11748
|
try {
|
|
11565
11749
|
await fs11.unlink(path24.join(ctx.swarmDir, tmp));
|
|
11566
11750
|
tmpFilesRemoved++;
|
|
11567
|
-
} catch {
|
|
11751
|
+
} catch (err) {
|
|
11752
|
+
const errno = err?.code;
|
|
11753
|
+
if (errno === "ENOENT") {} else {
|
|
11754
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11755
|
+
ctx.warnings.push(`Failed to clean tmp file ${tmp} [${errno ?? "unknown"}]: ${reason}`);
|
|
11756
|
+
}
|
|
11757
|
+
}
|
|
11568
11758
|
}
|
|
11569
|
-
} catch {
|
|
11759
|
+
} catch (err) {
|
|
11760
|
+
const errno = err?.code;
|
|
11761
|
+
if (errno === "ENOENT") {} else {
|
|
11762
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11763
|
+
ctx.warnings.push(`Failed to read ${ctx.swarmDir} for tmp-file cleanup [${errno ?? "unknown"}]: ${reason}`);
|
|
11764
|
+
}
|
|
11765
|
+
}
|
|
11570
11766
|
if (tmpFilesRemoved > 0) {
|
|
11571
11767
|
cleanedFiles.push(`${tmpFilesRemoved} .tmp.* file(s)`);
|
|
11572
11768
|
}
|
|
@@ -11583,9 +11779,14 @@ async function runCleanStage(ctx) {
|
|
|
11583
11779
|
""
|
|
11584
11780
|
].join(`
|
|
11585
11781
|
`);
|
|
11782
|
+
const contextTempPath = path24.join(path24.dirname(contextPath), `${path24.basename(contextPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
11586
11783
|
try {
|
|
11587
|
-
await fs11.writeFile(
|
|
11784
|
+
await fs11.writeFile(contextTempPath, contextContent, "utf-8");
|
|
11785
|
+
fsSync2.renameSync(contextTempPath, contextPath);
|
|
11588
11786
|
} catch (error2) {
|
|
11787
|
+
try {
|
|
11788
|
+
fsSync2.unlinkSync(contextTempPath);
|
|
11789
|
+
} catch {}
|
|
11589
11790
|
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
11590
11791
|
ctx.warnings.push(`Failed to reset context.md: ${msg}`);
|
|
11591
11792
|
console.warn("[close-command] Failed to write context.md:", error2);
|
|
@@ -11679,15 +11880,33 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
11679
11880
|
if (!finalizeLock.acquired) {
|
|
11680
11881
|
return `\u274C Another /swarm finalize is already running for this project. If you are certain no other run is active, wait for the lock to expire or remove the stale lock and retry.`;
|
|
11681
11882
|
}
|
|
11682
|
-
const phases = planData.phases ?? [];
|
|
11683
|
-
const inProgressPhases = phases.filter((p) => p.status === "in_progress");
|
|
11684
|
-
const isForced = args.includes("--force");
|
|
11685
|
-
const runSkillReview = args.includes("--skill-review");
|
|
11686
|
-
let planAlreadyDone = false;
|
|
11687
|
-
if (planExists) {
|
|
11688
|
-
planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
|
|
11689
|
-
}
|
|
11690
11883
|
try {
|
|
11884
|
+
if (!planExists) {
|
|
11885
|
+
const archiveDir = path24.join(swarmDir, "archive");
|
|
11886
|
+
try {
|
|
11887
|
+
const archiveEntries = await fs11.readdir(archiveDir);
|
|
11888
|
+
const hasArchiveBundle = archiveEntries.some((entry) => entry.startsWith("swarm-"));
|
|
11889
|
+
if (hasArchiveBundle) {
|
|
11890
|
+
const hasActiveState = [
|
|
11891
|
+
...ACTIVE_STATE_TO_CLEAN,
|
|
11892
|
+
...ACTIVE_STATE_DIRS_TO_CLEAN
|
|
11893
|
+
].some((entry) => fsSync2.existsSync(path24.join(swarmDir, entry)));
|
|
11894
|
+
if (!hasActiveState) {
|
|
11895
|
+
return `\u2705 Already finalized \u2014 nothing to do.
|
|
11896
|
+
|
|
11897
|
+
This project was already finalized in a previous /swarm close run. The plan has been archived and cleaned up. No further action is needed.`;
|
|
11898
|
+
}
|
|
11899
|
+
}
|
|
11900
|
+
} catch {}
|
|
11901
|
+
}
|
|
11902
|
+
const phases = planData.phases ?? [];
|
|
11903
|
+
const inProgressPhases = phases.filter((p) => p.status === "in_progress");
|
|
11904
|
+
const isForced = args.includes("--force");
|
|
11905
|
+
const runSkillReview = args.includes("--skill-review");
|
|
11906
|
+
let planAlreadyDone = false;
|
|
11907
|
+
if (planExists) {
|
|
11908
|
+
planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
|
|
11909
|
+
}
|
|
11691
11910
|
const { config: loadedConfig } = _internals19.loadPluginConfigWithMeta(directory);
|
|
11692
11911
|
const config = KnowledgeConfigSchema.parse(loadedConfig.knowledge ?? {});
|
|
11693
11912
|
const ctx = {
|
|
@@ -11724,6 +11943,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
11724
11943
|
archivedFileCount: 0,
|
|
11725
11944
|
archivedActiveStateFiles: new Set,
|
|
11726
11945
|
archivedActiveStateDirs: new Set,
|
|
11946
|
+
archiveFailureReasons: new Map,
|
|
11727
11947
|
timestamp: "",
|
|
11728
11948
|
archiveDir: "",
|
|
11729
11949
|
archiveSuffix: "",
|
|
@@ -11786,9 +12006,14 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
11786
12006
|
...ctx.warnings.length > 0 ? ["## Warnings", ...ctx.warnings.map((w) => `- ${w}`), ""] : []
|
|
11787
12007
|
].join(`
|
|
11788
12008
|
`);
|
|
12009
|
+
const closeSummaryTempPath = path24.join(path24.dirname(closeSummaryPath), `${path24.basename(closeSummaryPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
11789
12010
|
try {
|
|
11790
|
-
await fs11.writeFile(
|
|
12011
|
+
await fs11.writeFile(closeSummaryTempPath, summaryContent, "utf-8");
|
|
12012
|
+
fsSync2.renameSync(closeSummaryTempPath, closeSummaryPath);
|
|
11791
12013
|
} catch (error2) {
|
|
12014
|
+
try {
|
|
12015
|
+
fsSync2.unlinkSync(closeSummaryTempPath);
|
|
12016
|
+
} catch {}
|
|
11792
12017
|
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
11793
12018
|
ctx.warnings.push(`Failed to write close-summary.md: ${msg}`);
|
|
11794
12019
|
console.warn("[close-command] Failed to write close-summary.md:", error2);
|
|
@@ -12129,7 +12354,7 @@ async function handleConfigCommand(directory, _args) {
|
|
|
12129
12354
|
}
|
|
12130
12355
|
|
|
12131
12356
|
// src/services/skill-consolidation.ts
|
|
12132
|
-
import { existsSync as
|
|
12357
|
+
import { existsSync as existsSync14 } from "fs";
|
|
12133
12358
|
import { mkdir as mkdir8, readFile as readFile8, rename as rename4, writeFile as writeFile8 } from "fs/promises";
|
|
12134
12359
|
import * as path26 from "path";
|
|
12135
12360
|
|
|
@@ -12160,7 +12385,7 @@ function consolidationStatePath(directory) {
|
|
|
12160
12385
|
}
|
|
12161
12386
|
async function readState2(directory) {
|
|
12162
12387
|
const filePath = consolidationStatePath(directory);
|
|
12163
|
-
if (!
|
|
12388
|
+
if (!existsSync14(filePath))
|
|
12164
12389
|
return {};
|
|
12165
12390
|
try {
|
|
12166
12391
|
const parsed = JSON.parse(await readFile8(filePath, "utf-8"));
|
|
@@ -13607,7 +13832,7 @@ ${USAGE5}`;
|
|
|
13607
13832
|
|
|
13608
13833
|
// src/services/diagnose-service.ts
|
|
13609
13834
|
import * as child_process4 from "child_process";
|
|
13610
|
-
import { existsSync as
|
|
13835
|
+
import { existsSync as existsSync17, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync6 } from "fs";
|
|
13611
13836
|
import path31 from "path";
|
|
13612
13837
|
import { fileURLToPath } from "url";
|
|
13613
13838
|
|
|
@@ -13660,11 +13885,11 @@ init_capability_probe();
|
|
|
13660
13885
|
init_executor();
|
|
13661
13886
|
|
|
13662
13887
|
// src/services/knowledge-diagnostics.ts
|
|
13663
|
-
import { existsSync as
|
|
13888
|
+
import { existsSync as existsSync16 } from "fs";
|
|
13664
13889
|
import { readFile as readFile10 } from "fs/promises";
|
|
13665
13890
|
|
|
13666
13891
|
// src/services/version-check.ts
|
|
13667
|
-
import { existsSync as
|
|
13892
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
13668
13893
|
import { homedir as homedir4 } from "os";
|
|
13669
13894
|
import { join as join25 } from "path";
|
|
13670
13895
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -13679,7 +13904,7 @@ function cacheFile() {
|
|
|
13679
13904
|
function readVersionCache() {
|
|
13680
13905
|
try {
|
|
13681
13906
|
const path31 = cacheFile();
|
|
13682
|
-
if (!
|
|
13907
|
+
if (!existsSync15(path31))
|
|
13683
13908
|
return null;
|
|
13684
13909
|
const raw = readFileSync8(path31, "utf-8");
|
|
13685
13910
|
const parsed = JSON.parse(raw);
|
|
@@ -13720,7 +13945,7 @@ var SEVEN_DAYS_MS2 = 7 * 24 * 60 * 60 * 1000;
|
|
|
13720
13945
|
var UNACTIONABLE_BACKLOG_WARN = 100;
|
|
13721
13946
|
var INSIGHT_BACKLOG_WARN = 50;
|
|
13722
13947
|
async function readRawLines(filePath) {
|
|
13723
|
-
if (!
|
|
13948
|
+
if (!existsSync16(filePath))
|
|
13724
13949
|
return { entries: [], corrupt: 0 };
|
|
13725
13950
|
const content = await readFile10(filePath, "utf-8");
|
|
13726
13951
|
const entries = [];
|
|
@@ -13845,7 +14070,7 @@ async function computeKnowledgeDebug(directory) {
|
|
|
13845
14070
|
};
|
|
13846
14071
|
}
|
|
13847
14072
|
async function safeJsonlCount(filePath) {
|
|
13848
|
-
if (!filePath || !
|
|
14073
|
+
if (!filePath || !existsSync16(filePath))
|
|
13849
14074
|
return 0;
|
|
13850
14075
|
try {
|
|
13851
14076
|
const content = await readFile10(filePath, "utf-8");
|
|
@@ -14166,7 +14391,7 @@ async function checkConfigBackups(directory) {
|
|
|
14166
14391
|
}
|
|
14167
14392
|
async function checkGitRepository(directory) {
|
|
14168
14393
|
try {
|
|
14169
|
-
if (!
|
|
14394
|
+
if (!existsSync17(directory) || !statSync6(directory).isDirectory()) {
|
|
14170
14395
|
return {
|
|
14171
14396
|
name: "Git Repository",
|
|
14172
14397
|
status: "\u274C",
|
|
@@ -14231,7 +14456,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
14231
14456
|
}
|
|
14232
14457
|
async function checkConfigParseability(directory) {
|
|
14233
14458
|
const configPath = path31.join(directory, ".opencode/opencode-swarm.json");
|
|
14234
|
-
if (!
|
|
14459
|
+
if (!existsSync17(configPath)) {
|
|
14235
14460
|
return {
|
|
14236
14461
|
name: "Config Parseability",
|
|
14237
14462
|
status: "\u2705",
|
|
@@ -14286,11 +14511,11 @@ async function checkGrammarWasmFiles() {
|
|
|
14286
14511
|
const thisDir = path31.dirname(fileURLToPath(import.meta.url));
|
|
14287
14512
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
14288
14513
|
const missing = [];
|
|
14289
|
-
if (!
|
|
14514
|
+
if (!existsSync17(path31.join(grammarDir, "tree-sitter.wasm"))) {
|
|
14290
14515
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
14291
14516
|
}
|
|
14292
14517
|
for (const file of grammarFiles) {
|
|
14293
|
-
if (!
|
|
14518
|
+
if (!existsSync17(path31.join(grammarDir, file))) {
|
|
14294
14519
|
missing.push(file);
|
|
14295
14520
|
}
|
|
14296
14521
|
}
|
|
@@ -14309,7 +14534,7 @@ async function checkGrammarWasmFiles() {
|
|
|
14309
14534
|
}
|
|
14310
14535
|
async function checkCheckpointManifest(directory) {
|
|
14311
14536
|
const manifestPath = path31.join(directory, ".swarm/checkpoints.json");
|
|
14312
|
-
if (!
|
|
14537
|
+
if (!existsSync17(manifestPath)) {
|
|
14313
14538
|
return {
|
|
14314
14539
|
name: "Checkpoint Manifest",
|
|
14315
14540
|
status: "\u2705",
|
|
@@ -14361,7 +14586,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
14361
14586
|
}
|
|
14362
14587
|
async function checkEventStreamIntegrity(directory) {
|
|
14363
14588
|
const eventsPath = path31.join(directory, ".swarm/events.jsonl");
|
|
14364
|
-
if (!
|
|
14589
|
+
if (!existsSync17(eventsPath)) {
|
|
14365
14590
|
return {
|
|
14366
14591
|
name: "Event Stream",
|
|
14367
14592
|
status: "\u2705",
|
|
@@ -14402,7 +14627,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
14402
14627
|
}
|
|
14403
14628
|
async function checkSteeringDirectives(directory) {
|
|
14404
14629
|
const eventsPath = path31.join(directory, ".swarm/events.jsonl");
|
|
14405
|
-
if (!
|
|
14630
|
+
if (!existsSync17(eventsPath)) {
|
|
14406
14631
|
return {
|
|
14407
14632
|
name: "Steering Directives",
|
|
14408
14633
|
status: "\u2705",
|
|
@@ -14458,7 +14683,7 @@ async function checkCurator(directory) {
|
|
|
14458
14683
|
};
|
|
14459
14684
|
}
|
|
14460
14685
|
const summaryPath = path31.join(directory, ".swarm/curator-summary.json");
|
|
14461
|
-
if (!
|
|
14686
|
+
if (!existsSync17(summaryPath)) {
|
|
14462
14687
|
return {
|
|
14463
14688
|
name: "Curator",
|
|
14464
14689
|
status: "\u2705",
|
|
@@ -14660,7 +14885,7 @@ async function getDiagnoseData(directory) {
|
|
|
14660
14885
|
checks.push(await checkKnowledgeHealth(directory));
|
|
14661
14886
|
try {
|
|
14662
14887
|
const evidenceDir = path31.join(directory, ".swarm", "evidence");
|
|
14663
|
-
const snapshotFiles =
|
|
14888
|
+
const snapshotFiles = existsSync17(evidenceDir) ? readdirSync3(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
14664
14889
|
if (snapshotFiles.length > 0) {
|
|
14665
14890
|
const latest = snapshotFiles.sort().pop();
|
|
14666
14891
|
checks.push({
|
|
@@ -14693,7 +14918,7 @@ async function getDiagnoseData(directory) {
|
|
|
14693
14918
|
const cacheRows = [];
|
|
14694
14919
|
for (const cachePath of cachePaths) {
|
|
14695
14920
|
try {
|
|
14696
|
-
if (!
|
|
14921
|
+
if (!existsSync17(cachePath)) {
|
|
14697
14922
|
cacheRows.push(`\u2B1C ${cachePath} \u2014 absent`);
|
|
14698
14923
|
continue;
|
|
14699
14924
|
}
|
|
@@ -15731,7 +15956,7 @@ async function handleEvidenceCommand(directory, args) {
|
|
|
15731
15956
|
return formatTaskEvidenceMarkdown(evidenceData);
|
|
15732
15957
|
}
|
|
15733
15958
|
async function handleEvidenceSummaryCommand(directory) {
|
|
15734
|
-
const { buildEvidenceSummary } = await import("./evidence-summary-service-
|
|
15959
|
+
const { buildEvidenceSummary } = await import("./evidence-summary-service-5me91eq8.js");
|
|
15735
15960
|
const artifact = await buildEvidenceSummary(directory);
|
|
15736
15961
|
if (!artifact) {
|
|
15737
15962
|
return "No plan found. Run `/swarm plan` to check plan status.";
|
|
@@ -16235,7 +16460,7 @@ function buildStatusReport(directory, sessionID, sessionFlag) {
|
|
|
16235
16460
|
|
|
16236
16461
|
// src/commands/handoff.ts
|
|
16237
16462
|
import crypto4 from "crypto";
|
|
16238
|
-
import { renameSync as
|
|
16463
|
+
import { renameSync as renameSync9, unlinkSync as unlinkSync5 } from "fs";
|
|
16239
16464
|
|
|
16240
16465
|
// src/services/handoff-service.ts
|
|
16241
16466
|
var RTL_OVERRIDE_PATTERN = /[\u202e\u202d\u202c\u200f]/g;
|
|
@@ -16615,7 +16840,7 @@ var _internals26 = {
|
|
|
16615
16840
|
};
|
|
16616
16841
|
|
|
16617
16842
|
// src/session/snapshot-writer.ts
|
|
16618
|
-
import { closeSync as closeSync6, fsyncSync as fsyncSync2, mkdirSync as mkdirSync14, openSync as openSync6, renameSync as
|
|
16843
|
+
import { closeSync as closeSync6, fsyncSync as fsyncSync2, mkdirSync as mkdirSync14, openSync as openSync6, renameSync as renameSync8 } from "fs";
|
|
16619
16844
|
import * as path36 from "path";
|
|
16620
16845
|
var _writeInFlight = Promise.resolve();
|
|
16621
16846
|
function serializeAgentSession(s) {
|
|
@@ -16735,7 +16960,7 @@ async function writeSnapshot(directory, state) {
|
|
|
16735
16960
|
closeSync6(fd);
|
|
16736
16961
|
}
|
|
16737
16962
|
} catch {}
|
|
16738
|
-
|
|
16963
|
+
renameSync8(tempPath, resolvedPath);
|
|
16739
16964
|
} catch (error2) {
|
|
16740
16965
|
log("[snapshot-writer] write failed", {
|
|
16741
16966
|
error: error2 instanceof Error ? error2.message : String(error2)
|
|
@@ -16767,10 +16992,10 @@ async function handleHandoffCommand(directory, _args) {
|
|
|
16767
16992
|
const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
|
|
16768
16993
|
await bunWrite(tempPath, markdown);
|
|
16769
16994
|
try {
|
|
16770
|
-
|
|
16995
|
+
renameSync9(tempPath, resolvedPath);
|
|
16771
16996
|
} catch (renameErr) {
|
|
16772
16997
|
try {
|
|
16773
|
-
|
|
16998
|
+
unlinkSync5(tempPath);
|
|
16774
16999
|
} catch {}
|
|
16775
17000
|
throw renameErr;
|
|
16776
17001
|
}
|
|
@@ -16779,10 +17004,10 @@ async function handleHandoffCommand(directory, _args) {
|
|
|
16779
17004
|
const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
|
|
16780
17005
|
await bunWrite(promptTempPath, continuationPrompt);
|
|
16781
17006
|
try {
|
|
16782
|
-
|
|
17007
|
+
renameSync9(promptTempPath, promptPath);
|
|
16783
17008
|
} catch (renameErr) {
|
|
16784
17009
|
try {
|
|
16785
|
-
|
|
17010
|
+
unlinkSync5(promptTempPath);
|
|
16786
17011
|
} catch {}
|
|
16787
17012
|
throw renameErr;
|
|
16788
17013
|
}
|
|
@@ -16942,7 +17167,7 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
16942
17167
|
return formatHistoryMarkdown(historyData);
|
|
16943
17168
|
}
|
|
16944
17169
|
// src/commands/_shared/url-security.ts
|
|
16945
|
-
import { spawnSync as
|
|
17170
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
16946
17171
|
var MAX_URL_LEN = 2048;
|
|
16947
17172
|
var IPV4_PRIVATE = /^10\./;
|
|
16948
17173
|
var IPV4_LOOPBACK = /^127\./;
|
|
@@ -16952,7 +17177,7 @@ var IPV4_PRIVATE_192 = /^192\.168\./;
|
|
|
16952
17177
|
var IPV4_ZERO_NETWORK = /^0\./;
|
|
16953
17178
|
var IPV6_LINK_LOCAL = /^fe80:/i;
|
|
16954
17179
|
var IPV6_UNIQUE_LOCAL = /^f[cd][0-9a-f]{2}:/i;
|
|
16955
|
-
var _internals28 = { spawnSync:
|
|
17180
|
+
var _internals28 = { spawnSync: spawnSync6 };
|
|
16956
17181
|
function sanitizeUrl(raw) {
|
|
16957
17182
|
let urlStr = raw.trim();
|
|
16958
17183
|
urlStr = urlStr.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
|
|
@@ -17231,7 +17456,7 @@ import { join as join30 } from "path";
|
|
|
17231
17456
|
// src/hooks/knowledge-migrator.ts
|
|
17232
17457
|
init_logger();
|
|
17233
17458
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
17234
|
-
import { existsSync as
|
|
17459
|
+
import { existsSync as existsSync22, readFileSync as readFileSync14 } from "fs";
|
|
17235
17460
|
import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
|
|
17236
17461
|
import * as os8 from "os";
|
|
17237
17462
|
import * as path37 from "path";
|
|
@@ -17267,7 +17492,7 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
17267
17492
|
const sentinelPath = path37.join(directory, ".swarm", ".knowledge-migrated");
|
|
17268
17493
|
const contextPath = path37.join(directory, ".swarm", "context.md");
|
|
17269
17494
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
17270
|
-
if (
|
|
17495
|
+
if (existsSync22(sentinelPath)) {
|
|
17271
17496
|
return {
|
|
17272
17497
|
migrated: false,
|
|
17273
17498
|
entriesMigrated: 0,
|
|
@@ -17276,7 +17501,7 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
17276
17501
|
skippedReason: "sentinel-exists"
|
|
17277
17502
|
};
|
|
17278
17503
|
}
|
|
17279
|
-
if (!
|
|
17504
|
+
if (!existsSync22(contextPath)) {
|
|
17280
17505
|
return {
|
|
17281
17506
|
migrated: false,
|
|
17282
17507
|
entriesMigrated: 0,
|
|
@@ -17368,7 +17593,7 @@ async function migrateHiveKnowledgeLegacy(config) {
|
|
|
17368
17593
|
const legacyHivePath = _internals29.resolveLegacyHiveKnowledgePath();
|
|
17369
17594
|
const canonicalHivePath = resolveHiveKnowledgePath();
|
|
17370
17595
|
const sentinelPath = path37.join(path37.dirname(canonicalHivePath), ".hive-knowledge-migrated");
|
|
17371
|
-
if (
|
|
17596
|
+
if (existsSync22(sentinelPath)) {
|
|
17372
17597
|
return {
|
|
17373
17598
|
migrated: false,
|
|
17374
17599
|
entriesMigrated: 0,
|
|
@@ -17377,7 +17602,7 @@ async function migrateHiveKnowledgeLegacy(config) {
|
|
|
17377
17602
|
skippedReason: "sentinel-exists"
|
|
17378
17603
|
};
|
|
17379
17604
|
}
|
|
17380
|
-
if (!
|
|
17605
|
+
if (!existsSync22(legacyHivePath)) {
|
|
17381
17606
|
return {
|
|
17382
17607
|
migrated: false,
|
|
17383
17608
|
entriesMigrated: 0,
|
|
@@ -17579,7 +17804,7 @@ function truncateLesson2(text) {
|
|
|
17579
17804
|
}
|
|
17580
17805
|
function inferProjectName(directory) {
|
|
17581
17806
|
const packageJsonPath = path37.join(directory, "package.json");
|
|
17582
|
-
if (
|
|
17807
|
+
if (existsSync22(packageJsonPath)) {
|
|
17583
17808
|
try {
|
|
17584
17809
|
const pkg = JSON.parse(readFileSync14(packageJsonPath, "utf-8"));
|
|
17585
17810
|
if (pkg.name && typeof pkg.name === "string") {
|
|
@@ -18032,7 +18257,7 @@ ${USAGE7}`;
|
|
|
18032
18257
|
}
|
|
18033
18258
|
|
|
18034
18259
|
// src/commands/memory.ts
|
|
18035
|
-
import { existsSync as
|
|
18260
|
+
import { existsSync as existsSync25 } from "fs";
|
|
18036
18261
|
import * as path42 from "path";
|
|
18037
18262
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18038
18263
|
|
|
@@ -18130,7 +18355,7 @@ import * as path41 from "path";
|
|
|
18130
18355
|
|
|
18131
18356
|
// src/memory/local-jsonl-provider.ts
|
|
18132
18357
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
18133
|
-
import { existsSync as
|
|
18358
|
+
import { existsSync as existsSync23 } from "fs";
|
|
18134
18359
|
import {
|
|
18135
18360
|
appendFile as appendFile3,
|
|
18136
18361
|
mkdir as mkdir10,
|
|
@@ -19297,7 +19522,7 @@ function validateLoadedProposals(values, config) {
|
|
|
19297
19522
|
return { records, invalidCount };
|
|
19298
19523
|
}
|
|
19299
19524
|
async function readJsonl(filePath) {
|
|
19300
|
-
if (!
|
|
19525
|
+
if (!existsSync23(filePath))
|
|
19301
19526
|
return [];
|
|
19302
19527
|
const content = await readFile12(filePath, "utf-8");
|
|
19303
19528
|
const records = [];
|
|
@@ -19374,7 +19599,7 @@ import { createRequire as createRequire2 } from "module";
|
|
|
19374
19599
|
import * as path40 from "path";
|
|
19375
19600
|
|
|
19376
19601
|
// src/memory/jsonl-migration.ts
|
|
19377
|
-
import { existsSync as
|
|
19602
|
+
import { existsSync as existsSync24, renameSync as renameSync10, unlinkSync as unlinkSync6 } from "fs";
|
|
19378
19603
|
import { copyFile as copyFile2, mkdir as mkdir11, readFile as readFile13, stat as stat5, writeFile as writeFile11 } from "fs/promises";
|
|
19379
19604
|
import * as path39 from "path";
|
|
19380
19605
|
var LEGACY_JSONL_MIGRATION_VERSION = 2;
|
|
@@ -19408,10 +19633,10 @@ async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
|
19408
19633
|
const results = [];
|
|
19409
19634
|
for (const filename of ["memories.jsonl", "proposals.jsonl"]) {
|
|
19410
19635
|
const source = path39.join(storageDir, filename);
|
|
19411
|
-
if (!
|
|
19636
|
+
if (!existsSync24(source))
|
|
19412
19637
|
continue;
|
|
19413
19638
|
const backup = path39.join(backupDir, `${filename}.pre-sqlite-migration`);
|
|
19414
|
-
if (
|
|
19639
|
+
if (existsSync24(backup)) {
|
|
19415
19640
|
results.push({ source, backup, created: false });
|
|
19416
19641
|
continue;
|
|
19417
19642
|
}
|
|
@@ -19425,20 +19650,47 @@ async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
|
19425
19650
|
await mkdir11(exportDir, { recursive: true });
|
|
19426
19651
|
const memoriesPath = path39.join(exportDir, "memories.jsonl");
|
|
19427
19652
|
const proposalsPath = path39.join(exportDir, "proposals.jsonl");
|
|
19428
|
-
|
|
19429
|
-
|
|
19653
|
+
const memoriesTempPath = path39.join(path39.dirname(memoriesPath), `${path39.basename(memoriesPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
19654
|
+
try {
|
|
19655
|
+
await writeFile11(memoriesTempPath, toJsonl(memories), "utf-8");
|
|
19656
|
+
renameSync10(memoriesTempPath, memoriesPath);
|
|
19657
|
+
} catch (err) {
|
|
19658
|
+
try {
|
|
19659
|
+
unlinkSync6(memoriesTempPath);
|
|
19660
|
+
} catch {}
|
|
19661
|
+
throw err;
|
|
19662
|
+
}
|
|
19663
|
+
const proposalsTempPath = path39.join(path39.dirname(proposalsPath), `${path39.basename(proposalsPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
19664
|
+
try {
|
|
19665
|
+
await writeFile11(proposalsTempPath, toJsonl(proposals), "utf-8");
|
|
19666
|
+
renameSync10(proposalsTempPath, proposalsPath);
|
|
19667
|
+
} catch (err) {
|
|
19668
|
+
try {
|
|
19669
|
+
unlinkSync6(proposalsTempPath);
|
|
19670
|
+
} catch {}
|
|
19671
|
+
throw err;
|
|
19672
|
+
}
|
|
19430
19673
|
return { directory: exportDir, memoriesPath, proposalsPath };
|
|
19431
19674
|
}
|
|
19432
19675
|
async function writeMigrationReport(rootDirectory, report, config = {}) {
|
|
19433
19676
|
const reportPath = path39.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
19434
19677
|
await mkdir11(path39.dirname(reportPath), { recursive: true });
|
|
19435
|
-
|
|
19678
|
+
const reportTempPath = path39.join(path39.dirname(reportPath), `${path39.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
19679
|
+
try {
|
|
19680
|
+
await writeFile11(reportTempPath, `${JSON.stringify(report, null, 2)}
|
|
19436
19681
|
`, "utf-8");
|
|
19682
|
+
renameSync10(reportTempPath, reportPath);
|
|
19683
|
+
} catch (err) {
|
|
19684
|
+
try {
|
|
19685
|
+
unlinkSync6(reportTempPath);
|
|
19686
|
+
} catch {}
|
|
19687
|
+
throw err;
|
|
19688
|
+
}
|
|
19437
19689
|
return reportPath;
|
|
19438
19690
|
}
|
|
19439
19691
|
async function readMigrationReport(rootDirectory, config = {}) {
|
|
19440
19692
|
const reportPath = path39.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
19441
|
-
if (!
|
|
19693
|
+
if (!existsSync24(reportPath))
|
|
19442
19694
|
return null;
|
|
19443
19695
|
try {
|
|
19444
19696
|
return JSON.parse(await readFile13(reportPath, "utf-8"));
|
|
@@ -19452,13 +19704,13 @@ async function getLegacyJsonlFileStatus(rootDirectory, config = {}) {
|
|
|
19452
19704
|
for (const file of ["memories.jsonl", "proposals.jsonl"]) {
|
|
19453
19705
|
const filePath = path39.join(storageDir, file);
|
|
19454
19706
|
let sizeBytes = 0;
|
|
19455
|
-
if (
|
|
19707
|
+
if (existsSync24(filePath)) {
|
|
19456
19708
|
sizeBytes = (await stat5(filePath)).size;
|
|
19457
19709
|
}
|
|
19458
19710
|
statuses.push({
|
|
19459
19711
|
file,
|
|
19460
19712
|
path: filePath,
|
|
19461
|
-
exists:
|
|
19713
|
+
exists: existsSync24(filePath),
|
|
19462
19714
|
sizeBytes
|
|
19463
19715
|
});
|
|
19464
19716
|
}
|
|
@@ -19539,7 +19791,7 @@ async function readProposalJsonl(filePath, config) {
|
|
|
19539
19791
|
return { records, invalidRows, totalRows: rows.totalRows };
|
|
19540
19792
|
}
|
|
19541
19793
|
async function readJsonlRows(filePath) {
|
|
19542
|
-
if (!
|
|
19794
|
+
if (!existsSync24(filePath)) {
|
|
19543
19795
|
return { rows: [], invalidRows: [], totalRows: 0 };
|
|
19544
19796
|
}
|
|
19545
19797
|
const content = await readFile13(filePath, "utf-8");
|
|
@@ -20929,7 +21181,7 @@ async function handleMemoryStatusCommand(directory, _args) {
|
|
|
20929
21181
|
`- Provider: \`${config.provider}\``,
|
|
20930
21182
|
`- Storage: \`${storageDir}\``,
|
|
20931
21183
|
`- SQLite path: \`${sqlitePath}\``,
|
|
20932
|
-
`- SQLite database exists: \`${
|
|
21184
|
+
`- SQLite database exists: \`${existsSync25(sqlitePath)}\``,
|
|
20933
21185
|
`- Automatic destructive cleanup: \`disabled\``,
|
|
20934
21186
|
"",
|
|
20935
21187
|
"### Legacy JSONL"
|
|
@@ -24477,19 +24729,19 @@ function hasCompoundTestExtension(filename) {
|
|
|
24477
24729
|
const lower = filename.toLowerCase();
|
|
24478
24730
|
return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
24479
24731
|
}
|
|
24480
|
-
function isLanguageSpecificTestFile(
|
|
24481
|
-
const lower =
|
|
24732
|
+
function isLanguageSpecificTestFile(basename9) {
|
|
24733
|
+
const lower = basename9.toLowerCase();
|
|
24482
24734
|
if (lower.endsWith("_test.go"))
|
|
24483
24735
|
return true;
|
|
24484
24736
|
if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
|
|
24485
24737
|
return true;
|
|
24486
24738
|
if (lower.endsWith("_spec.rb"))
|
|
24487
24739
|
return true;
|
|
24488
|
-
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(
|
|
24740
|
+
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename9) || basename9.endsWith("Test.java") || basename9.endsWith("Tests.java") || lower.endsWith("it.java")))
|
|
24489
24741
|
return true;
|
|
24490
24742
|
if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
|
|
24491
24743
|
return true;
|
|
24492
|
-
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(
|
|
24744
|
+
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename9) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
|
|
24493
24745
|
return true;
|
|
24494
24746
|
if (lower.endsWith(".tests.ps1"))
|
|
24495
24747
|
return true;
|
|
@@ -24497,23 +24749,23 @@ function isLanguageSpecificTestFile(basename8) {
|
|
|
24497
24749
|
}
|
|
24498
24750
|
function isConventionTestFilePath(filePath) {
|
|
24499
24751
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
24500
|
-
const
|
|
24501
|
-
return hasCompoundTestExtension(
|
|
24752
|
+
const basename9 = path48.basename(filePath);
|
|
24753
|
+
return hasCompoundTestExtension(basename9) || basename9.includes(".spec.") || basename9.includes(".test.") || isLanguageSpecificTestFile(basename9) || isTestDirectoryPath(normalizedPath);
|
|
24502
24754
|
}
|
|
24503
24755
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
24504
24756
|
const testFiles = [];
|
|
24505
24757
|
for (const file of sourceFiles) {
|
|
24506
24758
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
24507
24759
|
const relativeFile = path48.relative(workingDir, absoluteFile);
|
|
24508
|
-
const
|
|
24760
|
+
const basename9 = path48.basename(absoluteFile);
|
|
24509
24761
|
const dirname23 = path48.dirname(absoluteFile);
|
|
24510
24762
|
const preferRelativeOutput = !path48.isAbsolute(file);
|
|
24511
24763
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
24512
24764
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
24513
24765
|
continue;
|
|
24514
24766
|
}
|
|
24515
|
-
const nameWithoutExt =
|
|
24516
|
-
const ext = path48.extname(
|
|
24767
|
+
const nameWithoutExt = basename9.replace(/\.[^.]+$/, "");
|
|
24768
|
+
const ext = path48.extname(basename9);
|
|
24517
24769
|
const genericTestNames = [
|
|
24518
24770
|
`${nameWithoutExt}.spec${ext}`,
|
|
24519
24771
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -24524,7 +24776,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
24524
24776
|
...languageSpecificTestNames
|
|
24525
24777
|
].map((candidateName) => path48.join(dirname23, candidateName));
|
|
24526
24778
|
const testDirectoryNames = [
|
|
24527
|
-
|
|
24779
|
+
basename9,
|
|
24528
24780
|
...genericTestNames,
|
|
24529
24781
|
...languageSpecificTestNames
|
|
24530
24782
|
];
|
|
@@ -27362,7 +27614,9 @@ async function handleResetCommand(directory, args) {
|
|
|
27362
27614
|
fs25.unlinkSync(rootPath);
|
|
27363
27615
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
27364
27616
|
}
|
|
27365
|
-
} catch {
|
|
27617
|
+
} catch (err) {
|
|
27618
|
+
results.push(`- \u274C Failed to delete ${filename}: ${err instanceof Error ? err.message : String(err)}`);
|
|
27619
|
+
}
|
|
27366
27620
|
}
|
|
27367
27621
|
try {
|
|
27368
27622
|
resetAutomationManager();
|
|
@@ -27885,6 +28139,11 @@ function resetPrmSessionState(session, sessionId) {
|
|
|
27885
28139
|
}
|
|
27886
28140
|
|
|
27887
28141
|
// src/commands/reset-session.ts
|
|
28142
|
+
function errorMessage(err) {
|
|
28143
|
+
if (err instanceof Error)
|
|
28144
|
+
return err.message;
|
|
28145
|
+
return String(err);
|
|
28146
|
+
}
|
|
27888
28147
|
async function handleResetSessionCommand(directory, _args) {
|
|
27889
28148
|
const results = [];
|
|
27890
28149
|
try {
|
|
@@ -27898,22 +28157,30 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
27898
28157
|
} catch {
|
|
27899
28158
|
results.push("\u274C Failed to delete state.json");
|
|
27900
28159
|
}
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
|
|
27904
|
-
|
|
27905
|
-
|
|
27906
|
-
|
|
27907
|
-
|
|
27908
|
-
const filePath = path52.join(sessionDir, file);
|
|
27909
|
-
if (fs27.lstatSync(filePath).isFile()) {
|
|
27910
|
-
fs27.unlinkSync(filePath);
|
|
27911
|
-
deletedCount++;
|
|
27912
|
-
}
|
|
27913
|
-
}
|
|
27914
|
-
results.push(`\u2705 Cleaned ${deletedCount} additional session file(s)`);
|
|
28160
|
+
const sessionDir = path52.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
28161
|
+
let sessionFiles = [];
|
|
28162
|
+
if (fs27.existsSync(sessionDir)) {
|
|
28163
|
+
try {
|
|
28164
|
+
sessionFiles = fs27.readdirSync(sessionDir);
|
|
28165
|
+
} catch (err) {
|
|
28166
|
+
results.push(`\u274C Failed to read session directory: ${errorMessage(err)}`);
|
|
27915
28167
|
}
|
|
27916
|
-
}
|
|
28168
|
+
}
|
|
28169
|
+
for (const file of sessionFiles) {
|
|
28170
|
+
if (file === "state.json")
|
|
28171
|
+
continue;
|
|
28172
|
+
const filePath = path52.join(sessionDir, file);
|
|
28173
|
+
try {
|
|
28174
|
+
if (!fs27.existsSync(filePath))
|
|
28175
|
+
continue;
|
|
28176
|
+
if (!fs27.lstatSync(filePath).isFile())
|
|
28177
|
+
continue;
|
|
28178
|
+
fs27.unlinkSync(filePath);
|
|
28179
|
+
results.push(`\u2713 Deleted ${file}`);
|
|
28180
|
+
} catch (err) {
|
|
28181
|
+
results.push(`\u274C Failed to delete ${file}: ${errorMessage(err)}`);
|
|
28182
|
+
}
|
|
28183
|
+
}
|
|
27917
28184
|
const sessionCount = swarmState.agentSessions.size;
|
|
27918
28185
|
for (const [sessionId, session] of swarmState.agentSessions) {
|
|
27919
28186
|
resetPrmSessionState(session, sessionId);
|
|
@@ -28075,6 +28342,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28075
28342
|
]);
|
|
28076
28343
|
const successes = [];
|
|
28077
28344
|
const failures = [];
|
|
28345
|
+
const warnings = [];
|
|
28078
28346
|
for (const file of checkpointFiles) {
|
|
28079
28347
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
28080
28348
|
continue;
|
|
@@ -28100,30 +28368,39 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28100
28368
|
`);
|
|
28101
28369
|
}
|
|
28102
28370
|
const existingLedgerPath = path54.join(swarmDir, "plan-ledger.jsonl");
|
|
28371
|
+
let ledgerDeletionFailed = false;
|
|
28103
28372
|
if (fs28.existsSync(existingLedgerPath)) {
|
|
28104
|
-
|
|
28105
|
-
|
|
28106
|
-
|
|
28107
|
-
|
|
28108
|
-
|
|
28109
|
-
|
|
28110
|
-
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
28111
|
-
const planId = derivePlanId(plan);
|
|
28112
|
-
const planHash = computePlanHash(plan);
|
|
28113
|
-
await initLedger(directory, planId, planHash, plan);
|
|
28114
|
-
await appendLedgerEvent(directory, {
|
|
28115
|
-
event_type: "plan_rebuilt",
|
|
28116
|
-
source: "rollback",
|
|
28117
|
-
plan_id: planId
|
|
28118
|
-
});
|
|
28373
|
+
try {
|
|
28374
|
+
fs28.unlinkSync(existingLedgerPath);
|
|
28375
|
+
} catch (err) {
|
|
28376
|
+
ledgerDeletionFailed = true;
|
|
28377
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
28378
|
+
warnings.push(`\u26A0\uFE0F Warning: Could not delete stale ledger (${errMsg}). The ledger may be inconsistent with the restored plan. Run /swarm reset-session to clean up session state.`);
|
|
28119
28379
|
}
|
|
28120
|
-
}
|
|
28121
|
-
|
|
28122
|
-
|
|
28123
|
-
|
|
28124
|
-
|
|
28125
|
-
|
|
28380
|
+
}
|
|
28381
|
+
if (!ledgerDeletionFailed) {
|
|
28382
|
+
try {
|
|
28383
|
+
const planJsonPath = path54.join(swarmDir, "plan.json");
|
|
28384
|
+
if (fs28.existsSync(planJsonPath)) {
|
|
28385
|
+
const planRaw = fs28.readFileSync(planJsonPath, "utf-8");
|
|
28386
|
+
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
28387
|
+
const planId = derivePlanId(plan);
|
|
28388
|
+
const planHash = computePlanHash(plan);
|
|
28389
|
+
await initLedger(directory, planId, planHash, plan);
|
|
28390
|
+
await appendLedgerEvent(directory, {
|
|
28391
|
+
event_type: "plan_rebuilt",
|
|
28392
|
+
source: "rollback",
|
|
28393
|
+
plan_id: planId
|
|
28394
|
+
});
|
|
28395
|
+
}
|
|
28396
|
+
} catch (initError) {
|
|
28397
|
+
return [
|
|
28398
|
+
`Rollback restored files but failed to initialize ledger: ${initError instanceof Error ? initError.message : String(initError)}`,
|
|
28399
|
+
"The .swarm/plan.json has been restored but the ledger may be out of sync.",
|
|
28400
|
+
"Run /swarm reset-session to reinitialize the ledger."
|
|
28401
|
+
].join(`
|
|
28126
28402
|
`);
|
|
28403
|
+
}
|
|
28127
28404
|
}
|
|
28128
28405
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
28129
28406
|
const rollbackEvent = {
|
|
@@ -28138,6 +28415,14 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28138
28415
|
} catch (error2) {
|
|
28139
28416
|
console.error("Failed to write rollback event:", error2 instanceof Error ? error2.message : String(error2));
|
|
28140
28417
|
}
|
|
28418
|
+
if (warnings.length > 0) {
|
|
28419
|
+
return [
|
|
28420
|
+
...warnings,
|
|
28421
|
+
"",
|
|
28422
|
+
`Rolled back to phase ${targetPhase}: ${checkpoint2.label || "no label"}`
|
|
28423
|
+
].join(`
|
|
28424
|
+
`);
|
|
28425
|
+
}
|
|
28141
28426
|
return `Rolled back to phase ${targetPhase}: ${checkpoint2.label || "no label"}`;
|
|
28142
28427
|
}
|
|
28143
28428
|
|
|
@@ -28307,6 +28592,7 @@ async function handleSddCommand(_directory, _args) {
|
|
|
28307
28592
|
}
|
|
28308
28593
|
|
|
28309
28594
|
// src/commands/simulate.ts
|
|
28595
|
+
import { renameSync as renameSync11, unlinkSync as unlinkSync11 } from "fs";
|
|
28310
28596
|
async function handleSimulateCommand(directory, args) {
|
|
28311
28597
|
const thresholdIndex = args.indexOf("--threshold");
|
|
28312
28598
|
const minCommitsIndex = args.indexOf("--min-commits");
|
|
@@ -28358,7 +28644,16 @@ Ensure this is a git repository with commit history.`;
|
|
|
28358
28644
|
const path55 = await import("path");
|
|
28359
28645
|
const reportPath = path55.join(directory, ".swarm", "simulate-report.md");
|
|
28360
28646
|
await fs29.mkdir(path55.dirname(reportPath), { recursive: true });
|
|
28361
|
-
|
|
28647
|
+
const reportTempPath = path55.join(path55.dirname(reportPath), `${path55.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
28648
|
+
try {
|
|
28649
|
+
await fs29.writeFile(reportTempPath, report, "utf-8");
|
|
28650
|
+
renameSync11(reportTempPath, reportPath);
|
|
28651
|
+
} catch (err) {
|
|
28652
|
+
try {
|
|
28653
|
+
unlinkSync11(reportTempPath);
|
|
28654
|
+
} catch {}
|
|
28655
|
+
throw err;
|
|
28656
|
+
}
|
|
28362
28657
|
} catch (err) {
|
|
28363
28658
|
const writeErr = err instanceof Error ? err.message : String(err);
|
|
28364
28659
|
warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
|
|
@@ -29255,7 +29550,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
29255
29550
|
async function handleHelpCommand(ctx) {
|
|
29256
29551
|
const targetCommand = ctx.args.join(" ");
|
|
29257
29552
|
if (!targetCommand) {
|
|
29258
|
-
const { buildHelpText } = await import("./index-
|
|
29553
|
+
const { buildHelpText } = await import("./index-gjdq4na6.js");
|
|
29259
29554
|
return buildHelpText();
|
|
29260
29555
|
}
|
|
29261
29556
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -29264,7 +29559,7 @@ async function handleHelpCommand(ctx) {
|
|
|
29264
29559
|
return _internals44.buildDetailedHelp(resolved.key, resolved.entry);
|
|
29265
29560
|
}
|
|
29266
29561
|
const similar = _internals44.findSimilarCommands(targetCommand);
|
|
29267
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
29562
|
+
const { buildHelpText: fullHelp } = await import("./index-gjdq4na6.js");
|
|
29268
29563
|
if (similar.length > 0) {
|
|
29269
29564
|
return `Command '/swarm ${targetCommand}' not found.
|
|
29270
29565
|
|
|
@@ -29397,7 +29692,7 @@ var COMMAND_REGISTRY = {
|
|
|
29397
29692
|
},
|
|
29398
29693
|
"guardrail explain": {
|
|
29399
29694
|
handler: async (ctx) => {
|
|
29400
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
29695
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-9fngqx80.js");
|
|
29401
29696
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
29402
29697
|
},
|
|
29403
29698
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|