opencode-swarm 7.98.2 → 7.99.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/README.md +1 -0
- package/dist/cli/{config-doctor-7yrxfa6b.js → config-doctor-9fhfy6p7.js} +2 -2
- package/dist/cli/{evidence-summary-service-559nas1m.js → evidence-summary-service-4hs44n2c.js} +5 -5
- package/dist/cli/{gate-evidence-nphg8hay.js → gate-evidence-ywys9vfs.js} +4 -4
- package/dist/cli/{guardrail-explain-xktjjh53.js → guardrail-explain-ktm6szbm.js} +13 -13
- package/dist/cli/{guardrail-log-53z1cf46.js → guardrail-log-ya49kpwn.js} +3 -3
- package/dist/cli/{index-91qtsbce.js → index-3naa2ajc.js} +1 -1
- package/dist/cli/{index-chan9mkv.js → index-4pt2py5p.js} +16 -14
- package/dist/cli/{index-a0dv2c7k.js → index-5fxjagjt.js} +1 -1
- package/dist/cli/{index-471qxz9g.js → index-7hnwnw5g.js} +11 -1
- package/dist/cli/{index-kv4dd5c5.js → index-9b7qp18e.js} +1 -1
- package/dist/cli/{index-hb10a2g8.js → index-f7nma02k.js} +2 -2
- package/dist/cli/{index-rvweaxsd.js → index-ft4gehk1.js} +2 -2
- package/dist/cli/{index-gnd1280x.js → index-h9ptj4b1.js} +1 -1
- package/dist/cli/{index-72k57f21.js → index-hw8r3e5p.js} +1098 -790
- package/dist/cli/{index-mh1ej70w.js → index-r8f89sm9.js} +2 -2
- package/dist/cli/{index-zy22fg5h.js → index-svf2zjxs.js} +5 -1
- package/dist/cli/{index-xchgryg4.js → index-vn263hqt.js} +16 -2
- package/dist/cli/{index-fjxjb66n.js → index-vwyjkzgs.js} +3 -3
- package/dist/cli/{index-yrzfbqqh.js → index-wwnjw0fb.js} +3 -3
- package/dist/cli/{index-5z2e78tv.js → index-xsswhy6k.js} +1 -1
- package/dist/cli/index.js +12 -12
- package/dist/cli/{knowledge-store-pa58msy5.js → knowledge-store-tsa8ezka.js} +4 -4
- package/dist/cli/{pending-delegations-8b2js1vq.js → pending-delegations-c785p5n2.js} +2 -2
- package/dist/cli/{pr-subscriptions-ttvr1ta9.js → pr-subscriptions-fqrzm0tv.js} +3 -3
- package/dist/cli/{schema-mygkbbe9.js → schema-nz638xc3.js} +5 -1
- package/dist/cli/{skill-generator-3tkwcg4x.js → skill-generator-99rrfwae.js} +5 -5
- package/dist/cli/{telemetry-aa1ma1dr.js → telemetry-jm7t8031.js} +1 -1
- package/dist/commands/costs.d.ts +4 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/registry.d.ts +9 -2
- package/dist/config/evidence-schema.d.ts +44 -44
- package/dist/config/index.d.ts +2 -2
- package/dist/config/schema.d.ts +24 -0
- package/dist/index.js +2933 -2314
- package/dist/services/cost-accounting.d.ts +65 -0
- package/dist/telemetry.d.ts +2 -1
- package/package.json +1 -1
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
validateActionability,
|
|
24
24
|
validateActionableFields,
|
|
25
25
|
validateLesson
|
|
26
|
-
} from "./index-
|
|
26
|
+
} from "./index-vwyjkzgs.js";
|
|
27
27
|
import {
|
|
28
28
|
appendKnowledge,
|
|
29
29
|
appendRejectedLesson,
|
|
@@ -51,13 +51,13 @@ import {
|
|
|
51
51
|
transactFile,
|
|
52
52
|
transactKnowledge,
|
|
53
53
|
writeLinkPointer
|
|
54
|
-
} from "./index-
|
|
54
|
+
} from "./index-f7nma02k.js";
|
|
55
55
|
import {
|
|
56
56
|
detectStraySwarmDirs,
|
|
57
57
|
readDoctorArtifact,
|
|
58
58
|
removeStraySwarmDir,
|
|
59
59
|
runConfigDoctor
|
|
60
|
-
} from "./index-
|
|
60
|
+
} from "./index-svf2zjxs.js";
|
|
61
61
|
import {
|
|
62
62
|
AGENT_TOOL_MAP,
|
|
63
63
|
ALL_SUBAGENT_NAMES,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
TOOL_NAME_SET,
|
|
71
71
|
resolveExternalSkillsConfig,
|
|
72
72
|
stripKnownSwarmPrefix
|
|
73
|
-
} from "./index-
|
|
73
|
+
} from "./index-7hnwnw5g.js";
|
|
74
74
|
import {
|
|
75
75
|
MAX_TRANSIENT_RETRIES,
|
|
76
76
|
PlanSchema,
|
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
transientBackoff,
|
|
115
115
|
validateProjectRoot,
|
|
116
116
|
writeProjectedSpecSync
|
|
117
|
-
} from "./index-
|
|
117
|
+
} from "./index-wwnjw0fb.js";
|
|
118
118
|
import {
|
|
119
119
|
_internals as _internals2,
|
|
120
120
|
_internals1 as _internals3,
|
|
@@ -132,13 +132,13 @@ import {
|
|
|
132
132
|
} from "./index-v4fcn4tr.js";
|
|
133
133
|
import {
|
|
134
134
|
atomicWriteFile
|
|
135
|
-
} from "./index-
|
|
135
|
+
} from "./index-9b7qp18e.js";
|
|
136
136
|
import {
|
|
137
137
|
buildCorrelationId,
|
|
138
138
|
listActive,
|
|
139
139
|
subscribe,
|
|
140
140
|
unsubscribe
|
|
141
|
-
} from "./index-
|
|
141
|
+
} from "./index-5fxjagjt.js";
|
|
142
142
|
import {
|
|
143
143
|
readSwarmFileAsync,
|
|
144
144
|
safeHook,
|
|
@@ -156,7 +156,7 @@ import {
|
|
|
156
156
|
import {
|
|
157
157
|
require_proper_lockfile,
|
|
158
158
|
tryAcquireLock
|
|
159
|
-
} from "./index-
|
|
159
|
+
} from "./index-3naa2ajc.js";
|
|
160
160
|
import {
|
|
161
161
|
exports_external
|
|
162
162
|
} from "./index-293f68mj.js";
|
|
@@ -166,7 +166,7 @@ import {
|
|
|
166
166
|
} from "./index-b9v501fr.js";
|
|
167
167
|
import {
|
|
168
168
|
telemetry
|
|
169
|
-
} from "./index-
|
|
169
|
+
} from "./index-vn263hqt.js";
|
|
170
170
|
import {
|
|
171
171
|
__esm,
|
|
172
172
|
__export,
|
|
@@ -909,7 +909,7 @@ var init_executor = __esm(() => {
|
|
|
909
909
|
// package.json
|
|
910
910
|
var package_default = {
|
|
911
911
|
name: "opencode-swarm",
|
|
912
|
-
version: "7.
|
|
912
|
+
version: "7.99.0",
|
|
913
913
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
914
914
|
main: "dist/index.js",
|
|
915
915
|
types: "dist/index.d.ts",
|
|
@@ -3624,15 +3624,30 @@ function classifySwarmCommandToolUse(resolved) {
|
|
|
3624
3624
|
}
|
|
3625
3625
|
}
|
|
3626
3626
|
if (canonicalKey === "benchmark") {
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3627
|
+
for (let i = 0;i < args.length; i++) {
|
|
3628
|
+
const arg = args[i];
|
|
3629
|
+
if (arg === "--cumulative" || arg === "--ci-gate")
|
|
3630
|
+
continue;
|
|
3631
|
+
if (arg === "--max-cost-usd" && i + 1 < args.length && /^\d+(\.\d+)?$/.test(args[i + 1])) {
|
|
3632
|
+
i++;
|
|
3633
|
+
continue;
|
|
3634
|
+
}
|
|
3630
3635
|
return {
|
|
3631
3636
|
allowed: false,
|
|
3632
|
-
message: "Only `--cumulative
|
|
3637
|
+
message: "Only `--cumulative`, `--ci-gate`, and `--max-cost-usd <n>` are supported for `/swarm benchmark` through swarm_command."
|
|
3633
3638
|
};
|
|
3634
3639
|
}
|
|
3635
3640
|
}
|
|
3641
|
+
if (canonicalKey === "costs") {
|
|
3642
|
+
if (args.length === 0)
|
|
3643
|
+
return { allowed: true };
|
|
3644
|
+
if (args.length === 1 && args[0] === "--json")
|
|
3645
|
+
return { allowed: true };
|
|
3646
|
+
return {
|
|
3647
|
+
allowed: false,
|
|
3648
|
+
message: "Usage through swarm_command: `/swarm costs` or `/swarm costs --json`."
|
|
3649
|
+
};
|
|
3650
|
+
}
|
|
3636
3651
|
if (canonicalKey === "show-plan") {
|
|
3637
3652
|
if (args.length > 1 || args[0] && !/^\d+$/.test(args[0])) {
|
|
3638
3653
|
return {
|
|
@@ -5981,7 +5996,7 @@ function hasActiveEpicMode(sessionID) {
|
|
|
5981
5996
|
async function rehydratePrSubscriptions(sessionID, directory) {
|
|
5982
5997
|
const map = new Map;
|
|
5983
5998
|
try {
|
|
5984
|
-
const { listActive: listActive2 } = await import("./pr-subscriptions-
|
|
5999
|
+
const { listActive: listActive2 } = await import("./pr-subscriptions-fqrzm0tv.js");
|
|
5985
6000
|
const records = await listActive2(directory);
|
|
5986
6001
|
for (const record of records) {
|
|
5987
6002
|
if (record.sessionID !== sessionID)
|
|
@@ -6058,6 +6073,199 @@ async function handleAutoProceedCommand(_directory, args, sessionID) {
|
|
|
6058
6073
|
}
|
|
6059
6074
|
}
|
|
6060
6075
|
|
|
6076
|
+
// src/services/cost-accounting.ts
|
|
6077
|
+
import * as fs7 from "fs";
|
|
6078
|
+
import * as os6 from "os";
|
|
6079
|
+
import * as path12 from "path";
|
|
6080
|
+
function summarizeTelemetryCosts(directory) {
|
|
6081
|
+
const summary = createEmptySummary();
|
|
6082
|
+
for (const event of readTelemetryEvents(directory)) {
|
|
6083
|
+
if (event.event !== "delegation_end")
|
|
6084
|
+
continue;
|
|
6085
|
+
addDelegationEvent(summary, event);
|
|
6086
|
+
}
|
|
6087
|
+
return finalizeSummary(summary);
|
|
6088
|
+
}
|
|
6089
|
+
function readTelemetryEvents(directory) {
|
|
6090
|
+
const swarmDir = path12.join(directory, ".swarm");
|
|
6091
|
+
const files = [
|
|
6092
|
+
path12.join(swarmDir, "telemetry.jsonl.1"),
|
|
6093
|
+
path12.join(swarmDir, "telemetry.jsonl")
|
|
6094
|
+
];
|
|
6095
|
+
const tmpDir = fs7.mkdtempSync(path12.join(os6.tmpdir(), "telemetry-snapshot-"));
|
|
6096
|
+
const snapshotFiles = [];
|
|
6097
|
+
try {
|
|
6098
|
+
for (const file of files) {
|
|
6099
|
+
if (!fs7.existsSync(file))
|
|
6100
|
+
continue;
|
|
6101
|
+
const snap = path12.join(tmpDir, path12.basename(file));
|
|
6102
|
+
try {
|
|
6103
|
+
fs7.copyFileSync(file, snap);
|
|
6104
|
+
snapshotFiles.push(snap);
|
|
6105
|
+
} catch {}
|
|
6106
|
+
}
|
|
6107
|
+
} catch {}
|
|
6108
|
+
const events = [];
|
|
6109
|
+
for (const file of snapshotFiles) {
|
|
6110
|
+
let content = "";
|
|
6111
|
+
try {
|
|
6112
|
+
content = fs7.readFileSync(file, "utf-8");
|
|
6113
|
+
} catch {
|
|
6114
|
+
continue;
|
|
6115
|
+
}
|
|
6116
|
+
for (const line of content.split(/\r?\n/)) {
|
|
6117
|
+
const trimmed = line.trim();
|
|
6118
|
+
if (!trimmed)
|
|
6119
|
+
continue;
|
|
6120
|
+
try {
|
|
6121
|
+
const parsed = JSON.parse(trimmed);
|
|
6122
|
+
if (isRecord(parsed))
|
|
6123
|
+
events.push(parsed);
|
|
6124
|
+
} catch {}
|
|
6125
|
+
}
|
|
6126
|
+
}
|
|
6127
|
+
try {
|
|
6128
|
+
for (const f of snapshotFiles) {
|
|
6129
|
+
try {
|
|
6130
|
+
fs7.unlinkSync(f);
|
|
6131
|
+
} catch {}
|
|
6132
|
+
}
|
|
6133
|
+
fs7.rmdirSync(tmpDir);
|
|
6134
|
+
} catch {}
|
|
6135
|
+
return events;
|
|
6136
|
+
}
|
|
6137
|
+
function readNumber(record, keys) {
|
|
6138
|
+
for (const key of keys) {
|
|
6139
|
+
const value = record[key];
|
|
6140
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0)
|
|
6141
|
+
return value;
|
|
6142
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
6143
|
+
const parsed = Number(value);
|
|
6144
|
+
if (Number.isFinite(parsed) && parsed >= 0)
|
|
6145
|
+
return parsed;
|
|
6146
|
+
}
|
|
6147
|
+
}
|
|
6148
|
+
return null;
|
|
6149
|
+
}
|
|
6150
|
+
function isRecord(value) {
|
|
6151
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6152
|
+
}
|
|
6153
|
+
function createEmptySummary() {
|
|
6154
|
+
return {
|
|
6155
|
+
total_cost_usd: 0,
|
|
6156
|
+
total_reported_usd: 0,
|
|
6157
|
+
total_estimated_usd: 0,
|
|
6158
|
+
total_input_tokens: 0,
|
|
6159
|
+
total_output_tokens: 0,
|
|
6160
|
+
total_reasoning_tokens: 0,
|
|
6161
|
+
total_cache_tokens: 0,
|
|
6162
|
+
delegations: 0,
|
|
6163
|
+
unavailable_delegations: 0,
|
|
6164
|
+
by_agent: [],
|
|
6165
|
+
by_task: [],
|
|
6166
|
+
by_gate: [],
|
|
6167
|
+
by_retry: [],
|
|
6168
|
+
by_source: {
|
|
6169
|
+
reported: { delegations: 0, cost_usd: 0 },
|
|
6170
|
+
estimated: { delegations: 0, cost_usd: 0 },
|
|
6171
|
+
unavailable: { delegations: 0, cost_usd: 0 }
|
|
6172
|
+
}
|
|
6173
|
+
};
|
|
6174
|
+
}
|
|
6175
|
+
function addDelegationEvent(summary, event) {
|
|
6176
|
+
const costSource = parseCostSource(event.cost_source);
|
|
6177
|
+
const cost = readNumber(event, ["cost_usd"]) ?? 0;
|
|
6178
|
+
const usage = {
|
|
6179
|
+
tokens_input: readNumber(event, ["tokens_input"]) ?? 0,
|
|
6180
|
+
tokens_output: readNumber(event, ["tokens_output"]) ?? 0,
|
|
6181
|
+
tokens_reasoning: readNumber(event, ["tokens_reasoning"]) ?? 0,
|
|
6182
|
+
tokens_cache: readNumber(event, ["tokens_cache"]) ?? 0
|
|
6183
|
+
};
|
|
6184
|
+
summary.delegations++;
|
|
6185
|
+
summary.total_cost_usd += cost;
|
|
6186
|
+
summary.total_input_tokens += usage.tokens_input;
|
|
6187
|
+
summary.total_output_tokens += usage.tokens_output;
|
|
6188
|
+
summary.total_reasoning_tokens += usage.tokens_reasoning;
|
|
6189
|
+
summary.total_cache_tokens += usage.tokens_cache;
|
|
6190
|
+
summary.by_source[costSource].delegations++;
|
|
6191
|
+
summary.by_source[costSource].cost_usd += cost;
|
|
6192
|
+
if (costSource === "reported")
|
|
6193
|
+
summary.total_reported_usd += cost;
|
|
6194
|
+
if (costSource === "estimated")
|
|
6195
|
+
summary.total_estimated_usd += cost;
|
|
6196
|
+
if (costSource === "unavailable")
|
|
6197
|
+
summary.unavailable_delegations++;
|
|
6198
|
+
addRow(summary.by_agent, String(event.agentName ?? event.agent ?? "unknown"), {
|
|
6199
|
+
cost,
|
|
6200
|
+
costSource,
|
|
6201
|
+
usage
|
|
6202
|
+
});
|
|
6203
|
+
addRow(summary.by_task, String(event.taskId ?? event.task_id ?? "unknown"), {
|
|
6204
|
+
cost,
|
|
6205
|
+
costSource,
|
|
6206
|
+
usage
|
|
6207
|
+
});
|
|
6208
|
+
addRow(summary.by_gate, String(event.gate ?? "unknown"), {
|
|
6209
|
+
cost,
|
|
6210
|
+
costSource,
|
|
6211
|
+
usage
|
|
6212
|
+
});
|
|
6213
|
+
addRow(summary.by_retry, String(readNumber(event, ["retry_index", "retryIndex"]) ?? 0), {
|
|
6214
|
+
cost,
|
|
6215
|
+
costSource,
|
|
6216
|
+
usage
|
|
6217
|
+
});
|
|
6218
|
+
}
|
|
6219
|
+
function addRow(rows, name, input) {
|
|
6220
|
+
let row = rows.find((candidate) => candidate.name === name);
|
|
6221
|
+
if (!row) {
|
|
6222
|
+
row = {
|
|
6223
|
+
name,
|
|
6224
|
+
delegations: 0,
|
|
6225
|
+
cost_usd: 0,
|
|
6226
|
+
input_tokens: 0,
|
|
6227
|
+
output_tokens: 0,
|
|
6228
|
+
reasoning_tokens: 0,
|
|
6229
|
+
cache_tokens: 0,
|
|
6230
|
+
unavailable_delegations: 0
|
|
6231
|
+
};
|
|
6232
|
+
rows.push(row);
|
|
6233
|
+
}
|
|
6234
|
+
row.delegations++;
|
|
6235
|
+
row.cost_usd += input.cost;
|
|
6236
|
+
row.input_tokens += input.usage.tokens_input;
|
|
6237
|
+
row.output_tokens += input.usage.tokens_output;
|
|
6238
|
+
row.reasoning_tokens += input.usage.tokens_reasoning;
|
|
6239
|
+
row.cache_tokens += input.usage.tokens_cache;
|
|
6240
|
+
if (input.costSource === "unavailable")
|
|
6241
|
+
row.unavailable_delegations++;
|
|
6242
|
+
}
|
|
6243
|
+
function finalizeSummary(summary) {
|
|
6244
|
+
summary.total_cost_usd = roundUsd(summary.total_cost_usd);
|
|
6245
|
+
summary.total_reported_usd = roundUsd(summary.total_reported_usd);
|
|
6246
|
+
summary.total_estimated_usd = roundUsd(summary.total_estimated_usd);
|
|
6247
|
+
for (const source of Object.values(summary.by_source)) {
|
|
6248
|
+
source.cost_usd = roundUsd(source.cost_usd);
|
|
6249
|
+
}
|
|
6250
|
+
for (const rows of [
|
|
6251
|
+
summary.by_agent,
|
|
6252
|
+
summary.by_task,
|
|
6253
|
+
summary.by_gate,
|
|
6254
|
+
summary.by_retry
|
|
6255
|
+
]) {
|
|
6256
|
+
for (const row of rows)
|
|
6257
|
+
row.cost_usd = roundUsd(row.cost_usd);
|
|
6258
|
+
rows.sort((a, b) => b.cost_usd - a.cost_usd || b.delegations - a.delegations);
|
|
6259
|
+
}
|
|
6260
|
+
return summary;
|
|
6261
|
+
}
|
|
6262
|
+
function parseCostSource(value) {
|
|
6263
|
+
return value === "reported" || value === "estimated" || value === "unavailable" ? value : "unavailable";
|
|
6264
|
+
}
|
|
6265
|
+
function roundUsd(value) {
|
|
6266
|
+
return Math.round(value * 1e6) / 1e6;
|
|
6267
|
+
}
|
|
6268
|
+
|
|
6061
6269
|
// src/commands/benchmark.ts
|
|
6062
6270
|
var CI = {
|
|
6063
6271
|
review_pass_rate: 70,
|
|
@@ -6073,7 +6281,9 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
6073
6281
|
let cumulative = args.includes("--cumulative");
|
|
6074
6282
|
if (args.includes("--ci-gate"))
|
|
6075
6283
|
cumulative = true;
|
|
6284
|
+
const maxCostUsd = parseMaxCostUsd(args);
|
|
6076
6285
|
const mode = cumulative ? "cumulative" : "in-memory";
|
|
6286
|
+
const costSummary = cumulative ? summarizeTelemetryCosts(directory) : undefined;
|
|
6077
6287
|
const agentMap = new Map;
|
|
6078
6288
|
for (const [, s] of swarmState.agentSessions) {
|
|
6079
6289
|
const e = agentMap.get(s.agentName) || {
|
|
@@ -6265,6 +6475,15 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
6265
6475
|
passed: !hasQualityEvidence || testToCodeRatio >= CI.min_test_to_code_ratio
|
|
6266
6476
|
}
|
|
6267
6477
|
];
|
|
6478
|
+
if (maxCostUsd !== null) {
|
|
6479
|
+
checks.push({
|
|
6480
|
+
name: "Total cost",
|
|
6481
|
+
value: costSummary?.total_cost_usd ?? 0,
|
|
6482
|
+
threshold: maxCostUsd,
|
|
6483
|
+
operator: "<=",
|
|
6484
|
+
passed: (costSummary?.total_cost_usd ?? 0) <= maxCostUsd
|
|
6485
|
+
});
|
|
6486
|
+
}
|
|
6268
6487
|
ciGate = { passed: checks.every((c) => c.passed), checks };
|
|
6269
6488
|
}
|
|
6270
6489
|
const lines = [
|
|
@@ -6316,16 +6535,23 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
6316
6535
|
lines.push(`- Test-to-Code Ratio: ${qualityMetrics.testToCodeRatio}% (min: ${qualityMetrics.thresholds.minTestToCodeRatio}%) ${qualityMetrics.testToCodeRatio >= qualityMetrics.thresholds.minTestToCodeRatio ? "\u2705" : "\u274C"}`);
|
|
6317
6536
|
lines.push("");
|
|
6318
6537
|
}
|
|
6538
|
+
if (costSummary) {
|
|
6539
|
+
lines.push("### Cost Signals");
|
|
6540
|
+
lines.push(`- Total tracked cost: $${costSummary.total_cost_usd.toFixed(6)} (${costSummary.delegations} delegations)`, `- Reported: $${costSummary.total_reported_usd.toFixed(6)}; estimated: $${costSummary.total_estimated_usd.toFixed(6)}; unavailable: ${costSummary.unavailable_delegations}`);
|
|
6541
|
+
lines.push("");
|
|
6542
|
+
}
|
|
6319
6543
|
if (ciGate) {
|
|
6320
6544
|
lines.push("### CI Gate", ciGate.passed ? "\u2705 PASSED" : "\u274C FAILED");
|
|
6321
6545
|
for (const c of ciGate.checks) {
|
|
6322
6546
|
let valueStr;
|
|
6323
6547
|
if (c.name === "Complexity Delta" || c.name === "Public API Delta") {
|
|
6324
6548
|
valueStr = `${c.value}`;
|
|
6549
|
+
} else if (c.name === "Total cost") {
|
|
6550
|
+
valueStr = `$${c.value.toFixed(6)}`;
|
|
6325
6551
|
} else {
|
|
6326
6552
|
valueStr = `${c.value}%`;
|
|
6327
6553
|
}
|
|
6328
|
-
const thresholdStr = c.name === "Complexity Delta" || c.name === "Public API Delta" ? `${c.threshold}` : `${c.threshold}%`;
|
|
6554
|
+
const thresholdStr = c.name === "Complexity Delta" || c.name === "Public API Delta" ? `${c.threshold}` : c.name === "Total cost" ? `$${c.threshold.toFixed(6)}` : `${c.threshold}%`;
|
|
6329
6555
|
lines.push(`- ${c.name}: ${valueStr} ${c.operator} ${thresholdStr} ${c.passed ? "\u2705" : "\u274C"}`);
|
|
6330
6556
|
}
|
|
6331
6557
|
lines.push("");
|
|
@@ -6366,6 +6592,18 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
6366
6592
|
thresholds: qualityMetrics.thresholds,
|
|
6367
6593
|
has_evidence: qualityMetrics.hasEvidence
|
|
6368
6594
|
};
|
|
6595
|
+
if (costSummary)
|
|
6596
|
+
json.costs = {
|
|
6597
|
+
total_cost_usd: costSummary.total_cost_usd,
|
|
6598
|
+
total_reported_usd: costSummary.total_reported_usd,
|
|
6599
|
+
total_estimated_usd: costSummary.total_estimated_usd,
|
|
6600
|
+
total_input_tokens: costSummary.total_input_tokens,
|
|
6601
|
+
total_output_tokens: costSummary.total_output_tokens,
|
|
6602
|
+
total_reasoning_tokens: costSummary.total_reasoning_tokens,
|
|
6603
|
+
total_cache_tokens: costSummary.total_cache_tokens,
|
|
6604
|
+
delegations: costSummary.delegations,
|
|
6605
|
+
unavailable_delegations: costSummary.unavailable_delegations
|
|
6606
|
+
};
|
|
6369
6607
|
if (ciGate)
|
|
6370
6608
|
json.ci_gate = {
|
|
6371
6609
|
passed: ciGate.passed,
|
|
@@ -6381,6 +6619,20 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
6381
6619
|
return lines.join(`
|
|
6382
6620
|
`);
|
|
6383
6621
|
}
|
|
6622
|
+
function parseMaxCostUsd(args) {
|
|
6623
|
+
const index = args.indexOf("--max-cost-usd");
|
|
6624
|
+
if (index === -1)
|
|
6625
|
+
return null;
|
|
6626
|
+
const raw = args[index + 1];
|
|
6627
|
+
if (!raw || raw.startsWith("--")) {
|
|
6628
|
+
throw new Error("Invalid --max-cost-usd value: expected a non-negative number.");
|
|
6629
|
+
}
|
|
6630
|
+
const parsed = Number(raw);
|
|
6631
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
6632
|
+
throw new Error("Invalid --max-cost-usd value: expected a non-negative number.");
|
|
6633
|
+
}
|
|
6634
|
+
return parsed;
|
|
6635
|
+
}
|
|
6384
6636
|
|
|
6385
6637
|
// src/commands/brainstorm.ts
|
|
6386
6638
|
function sanitizeTopic(raw) {
|
|
@@ -6402,8 +6654,8 @@ async function handleBrainstormCommand(_directory, args) {
|
|
|
6402
6654
|
|
|
6403
6655
|
// src/tools/checkpoint.ts
|
|
6404
6656
|
import * as child_process from "child_process";
|
|
6405
|
-
import * as
|
|
6406
|
-
import * as
|
|
6657
|
+
import * as fs8 from "fs";
|
|
6658
|
+
import * as path13 from "path";
|
|
6407
6659
|
|
|
6408
6660
|
// src/tools/create-tool.ts
|
|
6409
6661
|
function classifyToolError(error2) {
|
|
@@ -6490,13 +6742,13 @@ function validateLabel(label) {
|
|
|
6490
6742
|
return null;
|
|
6491
6743
|
}
|
|
6492
6744
|
function getCheckpointLogPath(directory) {
|
|
6493
|
-
return
|
|
6745
|
+
return path13.join(directory, CHECKPOINT_LOG_PATH);
|
|
6494
6746
|
}
|
|
6495
6747
|
function readCheckpointLog(directory) {
|
|
6496
6748
|
const logPath = getCheckpointLogPath(directory);
|
|
6497
6749
|
try {
|
|
6498
|
-
if (
|
|
6499
|
-
const content =
|
|
6750
|
+
if (fs8.existsSync(logPath)) {
|
|
6751
|
+
const content = fs8.readFileSync(logPath, "utf-8");
|
|
6500
6752
|
const parsed = JSON.parse(content);
|
|
6501
6753
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
6502
6754
|
return { version: 1, checkpoints: [] };
|
|
@@ -6508,13 +6760,13 @@ function readCheckpointLog(directory) {
|
|
|
6508
6760
|
}
|
|
6509
6761
|
function writeCheckpointLog(log2, directory) {
|
|
6510
6762
|
const logPath = getCheckpointLogPath(directory);
|
|
6511
|
-
const dir =
|
|
6512
|
-
if (!
|
|
6513
|
-
|
|
6763
|
+
const dir = path13.dirname(logPath);
|
|
6764
|
+
if (!fs8.existsSync(dir)) {
|
|
6765
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
6514
6766
|
}
|
|
6515
6767
|
const tempPath = `${logPath}.tmp`;
|
|
6516
|
-
|
|
6517
|
-
|
|
6768
|
+
fs8.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
|
|
6769
|
+
fs8.renameSync(tempPath, logPath);
|
|
6518
6770
|
}
|
|
6519
6771
|
function gitExec(args, cwd) {
|
|
6520
6772
|
for (let attempt = 0;attempt < MAX_TRANSIENT_RETRIES; attempt++) {
|
|
@@ -6545,10 +6797,10 @@ function gitExec(args, cwd) {
|
|
|
6545
6797
|
}
|
|
6546
6798
|
function appendRetentionEvent(directory, event) {
|
|
6547
6799
|
try {
|
|
6548
|
-
const eventsPath =
|
|
6800
|
+
const eventsPath = path13.join(directory, ".swarm", "events.jsonl");
|
|
6549
6801
|
const line = `${JSON.stringify({ ...event, timestamp: new Date().toISOString() })}
|
|
6550
6802
|
`;
|
|
6551
|
-
|
|
6803
|
+
fs8.appendFileSync(eventsPath, line);
|
|
6552
6804
|
} catch {}
|
|
6553
6805
|
}
|
|
6554
6806
|
function getCurrentSha(directory) {
|
|
@@ -6910,8 +7162,8 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
6910
7162
|
// src/commands/close.ts
|
|
6911
7163
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
6912
7164
|
import * as fsSync2 from "fs";
|
|
6913
|
-
import { promises as
|
|
6914
|
-
import
|
|
7165
|
+
import { promises as fs13 } from "fs";
|
|
7166
|
+
import path26 from "path";
|
|
6915
7167
|
|
|
6916
7168
|
// src/hooks/abort-utils.ts
|
|
6917
7169
|
function isAbortError(err) {
|
|
@@ -7040,8 +7292,8 @@ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
|
|
|
7040
7292
|
}
|
|
7041
7293
|
|
|
7042
7294
|
// src/hooks/curator-postmortem.ts
|
|
7043
|
-
import { existsSync as
|
|
7044
|
-
import * as
|
|
7295
|
+
import { existsSync as existsSync6, readdirSync, readFileSync as readFileSync6 } from "fs";
|
|
7296
|
+
import * as path14 from "path";
|
|
7045
7297
|
var MAX_INPUT_TEXT_CHARS = 500;
|
|
7046
7298
|
var MAX_KNOWLEDGE_ENTRIES = 500;
|
|
7047
7299
|
var MAX_PROPOSALS = 50;
|
|
@@ -7086,9 +7338,9 @@ async function collectKnowledgeSummary(directory) {
|
|
|
7086
7338
|
}
|
|
7087
7339
|
function readJsonlFile(filePath, maxLines) {
|
|
7088
7340
|
try {
|
|
7089
|
-
if (!
|
|
7341
|
+
if (!existsSync6(filePath))
|
|
7090
7342
|
return [];
|
|
7091
|
-
const content =
|
|
7343
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
7092
7344
|
const results = [];
|
|
7093
7345
|
const max = maxLines !== undefined && maxLines > 0 ? maxLines : Infinity;
|
|
7094
7346
|
for (const line of content.split(`
|
|
@@ -7108,16 +7360,16 @@ function readJsonlFile(filePath, maxLines) {
|
|
|
7108
7360
|
}
|
|
7109
7361
|
function collectRetrospectives(directory) {
|
|
7110
7362
|
const results = [];
|
|
7111
|
-
const evidenceDir =
|
|
7363
|
+
const evidenceDir = path14.join(directory, ".swarm", "evidence");
|
|
7112
7364
|
try {
|
|
7113
|
-
if (!
|
|
7365
|
+
if (!existsSync6(evidenceDir))
|
|
7114
7366
|
return results;
|
|
7115
7367
|
const retroDirs = readdirSync(evidenceDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("retro-")).slice(0, MAX_RETROSPECTIVES);
|
|
7116
7368
|
for (const entry of retroDirs) {
|
|
7117
|
-
const retroPath =
|
|
7118
|
-
if (
|
|
7369
|
+
const retroPath = path14.join(evidenceDir, entry.name, "evidence.json");
|
|
7370
|
+
if (existsSync6(retroPath)) {
|
|
7119
7371
|
try {
|
|
7120
|
-
results.push(
|
|
7372
|
+
results.push(readFileSync6(retroPath, "utf-8"));
|
|
7121
7373
|
} catch {}
|
|
7122
7374
|
}
|
|
7123
7375
|
}
|
|
@@ -7126,14 +7378,14 @@ function collectRetrospectives(directory) {
|
|
|
7126
7378
|
}
|
|
7127
7379
|
function collectDriftReports(directory) {
|
|
7128
7380
|
const results = [];
|
|
7129
|
-
const swarmDir =
|
|
7381
|
+
const swarmDir = path14.join(directory, ".swarm");
|
|
7130
7382
|
try {
|
|
7131
|
-
if (!
|
|
7383
|
+
if (!existsSync6(swarmDir))
|
|
7132
7384
|
return results;
|
|
7133
7385
|
const driftFiles = readdirSync(swarmDir).filter((e) => e.startsWith("drift-report-phase-") && e.endsWith(".json")).slice(0, MAX_DRIFT_REPORTS);
|
|
7134
7386
|
for (const entry of driftFiles) {
|
|
7135
7387
|
try {
|
|
7136
|
-
results.push(
|
|
7388
|
+
results.push(readFileSync6(path14.join(swarmDir, entry), "utf-8"));
|
|
7137
7389
|
} catch {}
|
|
7138
7390
|
}
|
|
7139
7391
|
} catch {}
|
|
@@ -7141,24 +7393,24 @@ function collectDriftReports(directory) {
|
|
|
7141
7393
|
}
|
|
7142
7394
|
function collectPendingProposals(directory) {
|
|
7143
7395
|
const results = [];
|
|
7144
|
-
const insightPath =
|
|
7145
|
-
if (
|
|
7396
|
+
const insightPath = path14.join(directory, ".swarm", "insight-candidates.jsonl");
|
|
7397
|
+
if (existsSync6(insightPath)) {
|
|
7146
7398
|
try {
|
|
7147
7399
|
results.push({
|
|
7148
7400
|
source: "insight-candidates",
|
|
7149
|
-
content:
|
|
7401
|
+
content: readFileSync6(insightPath, "utf-8")
|
|
7150
7402
|
});
|
|
7151
7403
|
} catch {}
|
|
7152
7404
|
}
|
|
7153
|
-
const proposalsDir =
|
|
7405
|
+
const proposalsDir = path14.join(directory, ".swarm", "skills", "proposals");
|
|
7154
7406
|
try {
|
|
7155
|
-
if (
|
|
7407
|
+
if (existsSync6(proposalsDir)) {
|
|
7156
7408
|
const proposalFiles = readdirSync(proposalsDir).filter((e) => e.endsWith(".md") || e.endsWith(".json")).slice(0, MAX_PROPOSALS);
|
|
7157
7409
|
for (const entry of proposalFiles) {
|
|
7158
7410
|
try {
|
|
7159
7411
|
results.push({
|
|
7160
7412
|
source: `proposals/${entry}`,
|
|
7161
|
-
content:
|
|
7413
|
+
content: readFileSync6(path14.join(proposalsDir, entry), "utf-8")
|
|
7162
7414
|
});
|
|
7163
7415
|
} catch {}
|
|
7164
7416
|
}
|
|
@@ -7168,9 +7420,9 @@ function collectPendingProposals(directory) {
|
|
|
7168
7420
|
}
|
|
7169
7421
|
function isReportValid(reportPath) {
|
|
7170
7422
|
try {
|
|
7171
|
-
if (!
|
|
7423
|
+
if (!existsSync6(reportPath))
|
|
7172
7424
|
return false;
|
|
7173
|
-
const content =
|
|
7425
|
+
const content = readFileSync6(reportPath, "utf-8").trim();
|
|
7174
7426
|
if (content.length === 0)
|
|
7175
7427
|
return false;
|
|
7176
7428
|
if (!content.startsWith("# Post-Mortem Report:"))
|
|
@@ -7379,7 +7631,7 @@ async function runCuratorPostMortem(directory, options = {}) {
|
|
|
7379
7631
|
warnings.push(`Pending proposals capped at ${MAX_PROPOSALS} (had ${proposals.length}); older entries truncated.`);
|
|
7380
7632
|
proposals = proposals.slice(0, MAX_PROPOSALS);
|
|
7381
7633
|
}
|
|
7382
|
-
const unactionablePath =
|
|
7634
|
+
const unactionablePath = path14.join(resolveKnowledgeStoreDir(directory), "knowledge-unactionable.jsonl");
|
|
7383
7635
|
let unactionable = readJsonlFile(unactionablePath, MAX_UNACTIONABLE);
|
|
7384
7636
|
if (unactionable.length > MAX_UNACTIONABLE) {
|
|
7385
7637
|
warnings.push(`Unactionable entries capped at ${MAX_UNACTIONABLE} (had ${unactionable.length}); older entries truncated.`);
|
|
@@ -7429,7 +7681,7 @@ ${llmOutput}`;
|
|
|
7429
7681
|
}
|
|
7430
7682
|
try {
|
|
7431
7683
|
const { mkdirSync: mkdirSync6 } = await import("fs");
|
|
7432
|
-
mkdirSync6(
|
|
7684
|
+
mkdirSync6(path14.dirname(reportPath), { recursive: true });
|
|
7433
7685
|
await atomicWriteFile(reportPath, reportContent);
|
|
7434
7686
|
} catch (err) {
|
|
7435
7687
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -7477,7 +7729,7 @@ var _internals13 = {
|
|
|
7477
7729
|
};
|
|
7478
7730
|
|
|
7479
7731
|
// src/hooks/hive-promoter.ts
|
|
7480
|
-
import
|
|
7732
|
+
import path17 from "path";
|
|
7481
7733
|
|
|
7482
7734
|
// src/background/event-bus.ts
|
|
7483
7735
|
class AutomationEventBus {
|
|
@@ -7981,9 +8233,9 @@ init_logger();
|
|
|
7981
8233
|
|
|
7982
8234
|
// src/services/skill-improver-quota.ts
|
|
7983
8235
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
7984
|
-
import { existsSync as
|
|
8236
|
+
import { existsSync as existsSync7 } from "fs";
|
|
7985
8237
|
import { mkdir as mkdir3, readFile as readFile3, rename, writeFile as writeFile2 } from "fs/promises";
|
|
7986
|
-
import * as
|
|
8238
|
+
import * as path15 from "path";
|
|
7987
8239
|
var LOCK_ACQUIRE_TIMEOUT_MS = 1e4;
|
|
7988
8240
|
var LOCK_RETRY_OPTS = {
|
|
7989
8241
|
retries: {
|
|
@@ -8012,7 +8264,7 @@ async function acquireLock(dir) {
|
|
|
8012
8264
|
}
|
|
8013
8265
|
function resolveQuotaPath(directory, scope = "skill-improver") {
|
|
8014
8266
|
const fileName = scope === "knowledge-enrichment" ? "knowledge-enrichment-quota.json" : "skill-improver-quota.json";
|
|
8015
|
-
return
|
|
8267
|
+
return path15.join(directory, ".swarm", fileName);
|
|
8016
8268
|
}
|
|
8017
8269
|
function todayKey(window, now = new Date) {
|
|
8018
8270
|
if (window === "utc") {
|
|
@@ -8024,7 +8276,7 @@ function todayKey(window, now = new Date) {
|
|
|
8024
8276
|
return `${yr}-${m}-${d}`;
|
|
8025
8277
|
}
|
|
8026
8278
|
async function readState(filePath) {
|
|
8027
|
-
if (!
|
|
8279
|
+
if (!existsSync7(filePath))
|
|
8028
8280
|
return null;
|
|
8029
8281
|
try {
|
|
8030
8282
|
const raw = await readFile3(filePath, "utf-8");
|
|
@@ -8038,7 +8290,7 @@ async function readState(filePath) {
|
|
|
8038
8290
|
}
|
|
8039
8291
|
}
|
|
8040
8292
|
async function writeState(filePath, state) {
|
|
8041
|
-
await mkdir3(
|
|
8293
|
+
await mkdir3(path15.dirname(filePath), { recursive: true });
|
|
8042
8294
|
const tmp = `${filePath}.tmp-${process.pid}`;
|
|
8043
8295
|
await writeFile2(tmp, JSON.stringify(state, null, 2), "utf-8");
|
|
8044
8296
|
await rename(tmp, filePath);
|
|
@@ -8061,10 +8313,10 @@ async function getQuotaState(directory, opts) {
|
|
|
8061
8313
|
}
|
|
8062
8314
|
async function reserveQuota(directory, opts) {
|
|
8063
8315
|
const filePath = resolveQuotaPath(directory, opts.scope);
|
|
8064
|
-
await mkdir3(
|
|
8316
|
+
await mkdir3(path15.dirname(filePath), { recursive: true });
|
|
8065
8317
|
let release = null;
|
|
8066
8318
|
try {
|
|
8067
|
-
release = await acquireLock(
|
|
8319
|
+
release = await acquireLock(path15.dirname(filePath));
|
|
8068
8320
|
const state = await getQuotaState(directory, opts);
|
|
8069
8321
|
if (state.calls_used + opts.nCalls > opts.maxCalls) {
|
|
8070
8322
|
return {
|
|
@@ -8091,10 +8343,10 @@ async function reserveQuota(directory, opts) {
|
|
|
8091
8343
|
}
|
|
8092
8344
|
async function releaseQuota(directory, opts) {
|
|
8093
8345
|
const filePath = resolveQuotaPath(directory, opts.scope);
|
|
8094
|
-
await mkdir3(
|
|
8346
|
+
await mkdir3(path15.dirname(filePath), { recursive: true });
|
|
8095
8347
|
let release = null;
|
|
8096
8348
|
try {
|
|
8097
|
-
release = await acquireLock(
|
|
8349
|
+
release = await acquireLock(path15.dirname(filePath));
|
|
8098
8350
|
const state = await getQuotaState(directory, opts);
|
|
8099
8351
|
const next = {
|
|
8100
8352
|
...state,
|
|
@@ -8117,8 +8369,8 @@ init_logger();
|
|
|
8117
8369
|
|
|
8118
8370
|
// src/hooks/skill-usage-log.ts
|
|
8119
8371
|
import * as crypto3 from "crypto";
|
|
8120
|
-
import * as
|
|
8121
|
-
import * as
|
|
8372
|
+
import * as fs9 from "fs";
|
|
8373
|
+
import * as path16 from "path";
|
|
8122
8374
|
function resolveLogPath(directory) {
|
|
8123
8375
|
return validateSwarmPath(directory, "skill-usage.jsonl");
|
|
8124
8376
|
}
|
|
@@ -8127,16 +8379,16 @@ function normalizeComplianceVerdict(verdict) {
|
|
|
8127
8379
|
}
|
|
8128
8380
|
var _internals14 = {
|
|
8129
8381
|
generateId: () => crypto3.randomUUID(),
|
|
8130
|
-
appendFileSync:
|
|
8131
|
-
readFileSync:
|
|
8132
|
-
writeFileSync:
|
|
8133
|
-
renameSync:
|
|
8134
|
-
mkdirSync:
|
|
8135
|
-
existsSync:
|
|
8136
|
-
statSync:
|
|
8137
|
-
openSync:
|
|
8138
|
-
readSync:
|
|
8139
|
-
closeSync:
|
|
8382
|
+
appendFileSync: fs9.appendFileSync.bind(fs9),
|
|
8383
|
+
readFileSync: fs9.readFileSync.bind(fs9),
|
|
8384
|
+
writeFileSync: fs9.writeFileSync.bind(fs9),
|
|
8385
|
+
renameSync: fs9.renameSync.bind(fs9),
|
|
8386
|
+
mkdirSync: fs9.mkdirSync.bind(fs9),
|
|
8387
|
+
existsSync: fs9.existsSync.bind(fs9),
|
|
8388
|
+
statSync: fs9.statSync.bind(fs9),
|
|
8389
|
+
openSync: fs9.openSync.bind(fs9),
|
|
8390
|
+
readSync: fs9.readSync.bind(fs9),
|
|
8391
|
+
closeSync: fs9.closeSync.bind(fs9),
|
|
8140
8392
|
pruneSkillUsageLog,
|
|
8141
8393
|
resolveSourceKnowledgeIds,
|
|
8142
8394
|
applySkillUsageFeedback,
|
|
@@ -8217,7 +8469,7 @@ function appendFeedbackAppliedMarker(directory, processedEntryIds) {
|
|
|
8217
8469
|
if (processedEntryIds.length === 0)
|
|
8218
8470
|
return;
|
|
8219
8471
|
const resolved = resolveLogPath(directory);
|
|
8220
|
-
const dir =
|
|
8472
|
+
const dir = path16.dirname(resolved);
|
|
8221
8473
|
if (!_internals14.existsSync(dir)) {
|
|
8222
8474
|
_internals14.mkdirSync(dir, { recursive: true });
|
|
8223
8475
|
}
|
|
@@ -8262,7 +8514,7 @@ function appendSkillUsageEntry(directory, entry) {
|
|
|
8262
8514
|
throw new Error("sessionID is required and must be a non-empty string");
|
|
8263
8515
|
}
|
|
8264
8516
|
const resolved = validateSwarmPath(directory, "skill-usage.jsonl");
|
|
8265
|
-
const dir =
|
|
8517
|
+
const dir = path16.dirname(resolved);
|
|
8266
8518
|
if (!_internals14.existsSync(dir)) {
|
|
8267
8519
|
_internals14.mkdirSync(dir, { recursive: true });
|
|
8268
8520
|
}
|
|
@@ -8438,8 +8690,8 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
8438
8690
|
}
|
|
8439
8691
|
if (entries.length === 0) {
|
|
8440
8692
|
if (preservedMarkers.length > 0) {
|
|
8441
|
-
const dir2 =
|
|
8442
|
-
const tmpPath2 =
|
|
8693
|
+
const dir2 = path16.dirname(resolved);
|
|
8694
|
+
const tmpPath2 = path16.join(dir2, `skill-usage-${Date.now()}.tmp`);
|
|
8443
8695
|
const content2 = preservedMarkers.join(`
|
|
8444
8696
|
`).concat(preservedMarkers.length > 0 ? `
|
|
8445
8697
|
` : "");
|
|
@@ -8481,8 +8733,8 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
8481
8733
|
if (pruned === 0) {
|
|
8482
8734
|
return { pruned: 0, remaining: entries.length };
|
|
8483
8735
|
}
|
|
8484
|
-
const dir =
|
|
8485
|
-
const tmpPath =
|
|
8736
|
+
const dir = path16.dirname(resolved);
|
|
8737
|
+
const tmpPath = path16.join(dir, `skill-usage-${Date.now()}.tmp`);
|
|
8486
8738
|
const entryLines = surviving.map((e) => JSON.stringify(e));
|
|
8487
8739
|
const allLines = [...entryLines, ...preservedMarkers];
|
|
8488
8740
|
const content = allLines.join(`
|
|
@@ -8511,9 +8763,9 @@ async function resolveSourceKnowledgeIds(directory, skillPath) {
|
|
|
8511
8763
|
if (/\.\.[/\\]/.test(cleanPath)) {
|
|
8512
8764
|
return [];
|
|
8513
8765
|
}
|
|
8514
|
-
const absolute =
|
|
8515
|
-
const baseDir =
|
|
8516
|
-
const isContained = process.platform === "win32" ? absolute.toLowerCase().startsWith((baseDir +
|
|
8766
|
+
const absolute = path16.normalize(path16.isAbsolute(cleanPath) ? cleanPath : path16.resolve(directory, cleanPath));
|
|
8767
|
+
const baseDir = path16.normalize(path16.resolve(directory));
|
|
8768
|
+
const isContained = process.platform === "win32" ? absolute.toLowerCase().startsWith((baseDir + path16.sep).toLowerCase()) : absolute.startsWith(baseDir + path16.sep);
|
|
8517
8769
|
if (!isContained) {
|
|
8518
8770
|
return [];
|
|
8519
8771
|
}
|
|
@@ -8825,7 +9077,7 @@ async function promoteToHive(directory, lesson, category) {
|
|
|
8825
9077
|
schema_version: 1,
|
|
8826
9078
|
created_at: new Date().toISOString(),
|
|
8827
9079
|
updated_at: new Date().toISOString(),
|
|
8828
|
-
source_project:
|
|
9080
|
+
source_project: path17.basename(directory) || "unknown",
|
|
8829
9081
|
encounter_score: 1
|
|
8830
9082
|
};
|
|
8831
9083
|
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
@@ -8877,9 +9129,9 @@ async function promoteFromSwarm(directory, lessonId) {
|
|
|
8877
9129
|
|
|
8878
9130
|
// src/hooks/knowledge-curator.ts
|
|
8879
9131
|
import { createHash as createHash3 } from "crypto";
|
|
8880
|
-
import { existsSync as
|
|
9132
|
+
import { existsSync as existsSync11 } from "fs";
|
|
8881
9133
|
import { appendFile as appendFile2, mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
8882
|
-
import * as
|
|
9134
|
+
import * as path22 from "path";
|
|
8883
9135
|
|
|
8884
9136
|
// src/services/synonym-map.ts
|
|
8885
9137
|
var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
|
|
@@ -8891,7 +9143,7 @@ import {
|
|
|
8891
9143
|
unlink as unlink2,
|
|
8892
9144
|
writeFile as writeFile3
|
|
8893
9145
|
} from "fs/promises";
|
|
8894
|
-
import * as
|
|
9146
|
+
import * as path18 from "path";
|
|
8895
9147
|
var SYNONYM_MAP_FILENAME = "synonym-map.json";
|
|
8896
9148
|
var MAX_TOKEN_LENGTH = 64;
|
|
8897
9149
|
var DEFAULT_MAX_PAIRS = 500;
|
|
@@ -9046,7 +9298,7 @@ async function readSynonymMap(directory, maxPairs = DEFAULT_MAX_PAIRS) {
|
|
|
9046
9298
|
}
|
|
9047
9299
|
}
|
|
9048
9300
|
async function writeSynonymMapAtomic(filePath, map) {
|
|
9049
|
-
await mkdir4(
|
|
9301
|
+
await mkdir4(path18.dirname(filePath), { recursive: true });
|
|
9050
9302
|
const tmp = `${filePath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
9051
9303
|
try {
|
|
9052
9304
|
await writeFile3(tmp, JSON.stringify(map, null, 2), "utf-8");
|
|
@@ -9059,7 +9311,7 @@ async function writeSynonymMapAtomic(filePath, map) {
|
|
|
9059
9311
|
}
|
|
9060
9312
|
async function rebuildSynonymMap(directory, entries, maxPairs = DEFAULT_MAX_PAIRS) {
|
|
9061
9313
|
const filePath = resolveSynonymMapPath(directory);
|
|
9062
|
-
const dir =
|
|
9314
|
+
const dir = path18.dirname(filePath);
|
|
9063
9315
|
await mkdir4(dir, { recursive: true });
|
|
9064
9316
|
let release = null;
|
|
9065
9317
|
try {
|
|
@@ -9122,19 +9374,19 @@ function reinforceSwarmKnowledgeEntry(entry, confirmation) {
|
|
|
9122
9374
|
}
|
|
9123
9375
|
|
|
9124
9376
|
// src/hooks/micro-reflector.ts
|
|
9125
|
-
import { existsSync as
|
|
9377
|
+
import { existsSync as existsSync10 } from "fs";
|
|
9126
9378
|
import { readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
9127
|
-
import * as
|
|
9379
|
+
import * as path21 from "path";
|
|
9128
9380
|
init_logger();
|
|
9129
9381
|
|
|
9130
9382
|
// src/hooks/skill-propagation-gate.ts
|
|
9131
|
-
import * as
|
|
9132
|
-
import * as
|
|
9383
|
+
import * as fs11 from "fs";
|
|
9384
|
+
import * as path20 from "path";
|
|
9133
9385
|
init_logger();
|
|
9134
9386
|
|
|
9135
9387
|
// src/hooks/skill-scoring.ts
|
|
9136
|
-
import * as
|
|
9137
|
-
import * as
|
|
9388
|
+
import * as fs10 from "fs";
|
|
9389
|
+
import * as path19 from "path";
|
|
9138
9390
|
var FREQUENCY_CAP = 10;
|
|
9139
9391
|
var FREQUENCY_WEIGHT = 0.3;
|
|
9140
9392
|
var COMPLIANCE_WEIGHT = 0.3;
|
|
@@ -9162,10 +9414,10 @@ var _internals15 = {
|
|
|
9162
9414
|
computeTriggerMatchBoost: null
|
|
9163
9415
|
};
|
|
9164
9416
|
function extractSkillName(skillPath) {
|
|
9165
|
-
const base =
|
|
9417
|
+
const base = path19.basename(skillPath, path19.extname(skillPath));
|
|
9166
9418
|
if (base !== "SKILL")
|
|
9167
9419
|
return base;
|
|
9168
|
-
const parent =
|
|
9420
|
+
const parent = path19.basename(path19.dirname(skillPath));
|
|
9169
9421
|
return parent;
|
|
9170
9422
|
}
|
|
9171
9423
|
function stripQuotes(value) {
|
|
@@ -9307,25 +9559,25 @@ function parseSkillFrontmatter(content, skillPath) {
|
|
|
9307
9559
|
return meta;
|
|
9308
9560
|
}
|
|
9309
9561
|
function readFilePrefix(filePath) {
|
|
9310
|
-
const fd =
|
|
9562
|
+
const fd = fs10.openSync(filePath, "r");
|
|
9311
9563
|
try {
|
|
9312
9564
|
const buffer = Buffer.alloc(SKILL_FRONTMATTER_READ_BYTES);
|
|
9313
|
-
const bytesRead =
|
|
9565
|
+
const bytesRead = fs10.readSync(fd, buffer, 0, SKILL_FRONTMATTER_READ_BYTES, 0);
|
|
9314
9566
|
return buffer.toString("utf-8", 0, bytesRead);
|
|
9315
9567
|
} finally {
|
|
9316
|
-
|
|
9568
|
+
fs10.closeSync(fd);
|
|
9317
9569
|
}
|
|
9318
9570
|
}
|
|
9319
9571
|
function readSkillMetadata(skillPath, directory) {
|
|
9320
9572
|
const normalizedPath = skillPath.replace(/^file:/, "").replace(/\\/g, "/");
|
|
9321
9573
|
const fallback = parseSkillFrontmatter("", normalizedPath);
|
|
9322
9574
|
try {
|
|
9323
|
-
if (
|
|
9575
|
+
if (path19.isAbsolute(normalizedPath) || normalizedPath.split("/").includes("..")) {
|
|
9324
9576
|
return fallback;
|
|
9325
9577
|
}
|
|
9326
|
-
const root =
|
|
9327
|
-
const absolutePath =
|
|
9328
|
-
if (absolutePath !== root && !absolutePath.startsWith(root +
|
|
9578
|
+
const root = path19.resolve(directory);
|
|
9579
|
+
const absolutePath = path19.resolve(directory, normalizedPath);
|
|
9580
|
+
if (absolutePath !== root && !absolutePath.startsWith(root + path19.sep)) {
|
|
9329
9581
|
return fallback;
|
|
9330
9582
|
}
|
|
9331
9583
|
const content = readFilePrefix(absolutePath);
|
|
@@ -9459,10 +9711,10 @@ function getSkillStats(skillPath, directory) {
|
|
|
9459
9711
|
};
|
|
9460
9712
|
}
|
|
9461
9713
|
function formatSkillIndexWithContext(skills, directory) {
|
|
9462
|
-
const usageLogPath =
|
|
9714
|
+
const usageLogPath = path19.join(directory, ".swarm", "skill-usage.jsonl");
|
|
9463
9715
|
let hasHistory = false;
|
|
9464
9716
|
try {
|
|
9465
|
-
const stat4 =
|
|
9717
|
+
const stat4 = fs10.statSync(usageLogPath);
|
|
9466
9718
|
hasHistory = stat4.size > 0;
|
|
9467
9719
|
} catch {}
|
|
9468
9720
|
if (!hasHistory) {
|
|
@@ -9593,7 +9845,7 @@ function parseYamlValue(value) {
|
|
|
9593
9845
|
return trimmed;
|
|
9594
9846
|
}
|
|
9595
9847
|
function loadRoutingSkills(directory, targetAgent) {
|
|
9596
|
-
const routingPath =
|
|
9848
|
+
const routingPath = path20.join(directory, ".opencode", "skill-routing.yaml");
|
|
9597
9849
|
if (!_internals16.existsSync(routingPath))
|
|
9598
9850
|
return [];
|
|
9599
9851
|
try {
|
|
@@ -9625,13 +9877,13 @@ var SKILL_SEARCH_ROOTS = [
|
|
|
9625
9877
|
];
|
|
9626
9878
|
var MAX_SCORING_SESSION_ENTRIES = 500;
|
|
9627
9879
|
var _internals16 = {
|
|
9628
|
-
readdirSync:
|
|
9629
|
-
existsSync:
|
|
9630
|
-
statSync:
|
|
9631
|
-
mkdirSync:
|
|
9632
|
-
appendFileSync:
|
|
9633
|
-
readFileSync:
|
|
9634
|
-
writeFileSync:
|
|
9880
|
+
readdirSync: fs11.readdirSync.bind(fs11),
|
|
9881
|
+
existsSync: fs11.existsSync.bind(fs11),
|
|
9882
|
+
statSync: fs11.statSync.bind(fs11),
|
|
9883
|
+
mkdirSync: fs11.mkdirSync.bind(fs11),
|
|
9884
|
+
appendFileSync: fs11.appendFileSync.bind(fs11),
|
|
9885
|
+
readFileSync: fs11.readFileSync.bind(fs11),
|
|
9886
|
+
writeFileSync: fs11.writeFileSync.bind(fs11),
|
|
9635
9887
|
skillPropagationGateBefore: null,
|
|
9636
9888
|
skillPropagationTransformScan: null,
|
|
9637
9889
|
SKILL_CAPABLE_AGENTS,
|
|
@@ -9653,7 +9905,7 @@ var _internals16 = {
|
|
|
9653
9905
|
function discoverAvailableSkills(directory) {
|
|
9654
9906
|
const results = [];
|
|
9655
9907
|
for (const root of SKILL_SEARCH_ROOTS) {
|
|
9656
|
-
const rootPath =
|
|
9908
|
+
const rootPath = path20.join(directory, root);
|
|
9657
9909
|
if (!_internals16.existsSync(rootPath))
|
|
9658
9910
|
continue;
|
|
9659
9911
|
let entries;
|
|
@@ -9665,13 +9917,13 @@ function discoverAvailableSkills(directory) {
|
|
|
9665
9917
|
for (const entry of entries) {
|
|
9666
9918
|
if (entry.startsWith("."))
|
|
9667
9919
|
continue;
|
|
9668
|
-
const skillDir =
|
|
9669
|
-
if (_internals16.existsSync(
|
|
9920
|
+
const skillDir = path20.join(rootPath, entry);
|
|
9921
|
+
if (_internals16.existsSync(path20.join(skillDir, "retired.marker")) || _internals16.existsSync(path20.join(skillDir, "stale.marker")))
|
|
9670
9922
|
continue;
|
|
9671
|
-
const skillFile =
|
|
9923
|
+
const skillFile = path20.join(skillDir, "SKILL.md");
|
|
9672
9924
|
try {
|
|
9673
9925
|
if (_internals16.statSync(skillDir).isDirectory() && _internals16.existsSync(skillFile)) {
|
|
9674
|
-
results.push(
|
|
9926
|
+
results.push(path20.join(root, entry, "SKILL.md").replace(/\\/g, "/"));
|
|
9675
9927
|
}
|
|
9676
9928
|
} catch (err) {
|
|
9677
9929
|
warn(`[skill-propagation-gate] failed to stat skill directory ${entry}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -9740,9 +9992,9 @@ function extractSkillsFieldFromPrompt(prompt) {
|
|
|
9740
9992
|
return "";
|
|
9741
9993
|
}
|
|
9742
9994
|
function writeWarnEvent(directory, record) {
|
|
9743
|
-
const filePath =
|
|
9995
|
+
const filePath = path20.join(directory, ".swarm", "events.jsonl");
|
|
9744
9996
|
try {
|
|
9745
|
-
const dir =
|
|
9997
|
+
const dir = path20.dirname(filePath);
|
|
9746
9998
|
if (!_internals16.existsSync(dir)) {
|
|
9747
9999
|
_internals16.mkdirSync(dir, { recursive: true });
|
|
9748
10000
|
}
|
|
@@ -9871,8 +10123,8 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
9871
10123
|
if (routingPaths.length > 0) {
|
|
9872
10124
|
const existingPaths = new Set(scored.map((s) => s.skillPath));
|
|
9873
10125
|
for (const routingPath of routingPaths) {
|
|
9874
|
-
const routedSkillDir =
|
|
9875
|
-
if (_internals16.existsSync(
|
|
10126
|
+
const routedSkillDir = path20.dirname(path20.join(directory, routingPath));
|
|
10127
|
+
if (_internals16.existsSync(path20.join(routedSkillDir, "retired.marker")) || _internals16.existsSync(path20.join(routedSkillDir, "stale.marker")))
|
|
9876
10128
|
continue;
|
|
9877
10129
|
if (!existingPaths.has(routingPath)) {
|
|
9878
10130
|
scored.push({
|
|
@@ -9891,8 +10143,8 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
9891
10143
|
let skillsForIndex = availableSkills;
|
|
9892
10144
|
if (scoringSkipped) {
|
|
9893
10145
|
skillsForIndex = [...availableSkills].sort((a, b) => {
|
|
9894
|
-
const nameA =
|
|
9895
|
-
const nameB =
|
|
10146
|
+
const nameA = path20.basename(path20.dirname(a));
|
|
10147
|
+
const nameB = path20.basename(path20.dirname(b));
|
|
9896
10148
|
return nameA.localeCompare(nameB);
|
|
9897
10149
|
});
|
|
9898
10150
|
} else if (typeof scored !== "undefined" && scored.length > 0) {
|
|
@@ -9900,7 +10152,7 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
9900
10152
|
}
|
|
9901
10153
|
const formattedIndex = _internals16.formatSkillIndexWithContext(skillsForIndex, directory);
|
|
9902
10154
|
if (formattedIndex.length > 0) {
|
|
9903
|
-
const contextPath =
|
|
10155
|
+
const contextPath = path20.join(directory, ".swarm", "context.md");
|
|
9904
10156
|
let existingContent = "";
|
|
9905
10157
|
if (_internals16.existsSync(contextPath)) {
|
|
9906
10158
|
existingContent = _internals16.readFileSync(contextPath, "utf-8");
|
|
@@ -9922,7 +10174,7 @@ ${newSection}`;
|
|
|
9922
10174
|
updatedContent = existingContent + newSection;
|
|
9923
10175
|
}
|
|
9924
10176
|
}
|
|
9925
|
-
const swarmDir =
|
|
10177
|
+
const swarmDir = path20.dirname(contextPath);
|
|
9926
10178
|
if (!_internals16.existsSync(swarmDir)) {
|
|
9927
10179
|
_internals16.mkdirSync(swarmDir, { recursive: true });
|
|
9928
10180
|
}
|
|
@@ -10148,9 +10400,9 @@ function resolveInsightCandidatesPath(directory) {
|
|
|
10148
10400
|
}
|
|
10149
10401
|
async function readTaskTrajectory(directory, taskId) {
|
|
10150
10402
|
try {
|
|
10151
|
-
const rel =
|
|
10403
|
+
const rel = path21.join("evidence", sanitizeTaskId(taskId), "trajectory.jsonl");
|
|
10152
10404
|
const filePath = validateSwarmPath(directory, rel);
|
|
10153
|
-
if (!
|
|
10405
|
+
if (!existsSync10(filePath))
|
|
10154
10406
|
return [];
|
|
10155
10407
|
const content = await readFile5(filePath, "utf-8");
|
|
10156
10408
|
const out = [];
|
|
@@ -10206,7 +10458,7 @@ var WRITE_TOOLS = new Set([
|
|
|
10206
10458
|
"apply_patch",
|
|
10207
10459
|
"swarm_apply_patch"
|
|
10208
10460
|
]);
|
|
10209
|
-
function
|
|
10461
|
+
function isRecord2(value) {
|
|
10210
10462
|
return typeof value === "object" && value !== null;
|
|
10211
10463
|
}
|
|
10212
10464
|
function normalizePathField(value) {
|
|
@@ -10216,13 +10468,13 @@ function firstPathFromRecord(record) {
|
|
|
10216
10468
|
return normalizePathField(record.path) ?? normalizePathField(record.filePath) ?? normalizePathField(record.file);
|
|
10217
10469
|
}
|
|
10218
10470
|
function normalizeWriteTrigger(input, output) {
|
|
10219
|
-
if (!
|
|
10471
|
+
if (!isRecord2(input))
|
|
10220
10472
|
return null;
|
|
10221
10473
|
const toolName = typeof input.toolName === "string" ? input.toolName : typeof input.tool === "string" ? input.tool : null;
|
|
10222
10474
|
if (!toolName || !WRITE_TOOLS.has(toolName))
|
|
10223
10475
|
return null;
|
|
10224
|
-
const inputArgs =
|
|
10225
|
-
const outputArgs =
|
|
10476
|
+
const inputArgs = isRecord2(input.args) ? input.args : null;
|
|
10477
|
+
const outputArgs = isRecord2(output) && isRecord2(output.args) ? output.args : null;
|
|
10226
10478
|
const filePath = firstPathFromRecord(input) ?? (inputArgs ? firstPathFromRecord(inputArgs) : null) ?? (outputArgs ? firstPathFromRecord(outputArgs) : null);
|
|
10227
10479
|
if (!filePath)
|
|
10228
10480
|
return null;
|
|
@@ -10578,8 +10830,8 @@ RETRY: your last output was missing ${result.missing.join("; ")}; produce valid
|
|
|
10578
10830
|
}
|
|
10579
10831
|
async function appendCuratorSkippedEvent(directory, record) {
|
|
10580
10832
|
try {
|
|
10581
|
-
const filePath =
|
|
10582
|
-
await mkdir5(
|
|
10833
|
+
const filePath = path22.join(directory, ".swarm", "events.jsonl");
|
|
10834
|
+
await mkdir5(path22.dirname(filePath), { recursive: true });
|
|
10583
10835
|
await appendFile2(filePath, `${JSON.stringify({
|
|
10584
10836
|
timestamp: new Date().toISOString(),
|
|
10585
10837
|
event: "curator_skipped",
|
|
@@ -10619,7 +10871,7 @@ function readInsightJsonl(content) {
|
|
|
10619
10871
|
async function consumeInsightCandidates(directory, batchLimit = MESO_INSIGHT_BATCH_LIMIT) {
|
|
10620
10872
|
try {
|
|
10621
10873
|
const filePath = resolveInsightCandidatesPath(directory);
|
|
10622
|
-
if (!
|
|
10874
|
+
if (!existsSync11(filePath))
|
|
10623
10875
|
return [];
|
|
10624
10876
|
const consumed = [];
|
|
10625
10877
|
await transactFile(filePath, async (p) => readInsightJsonl(await readFile6(p, "utf-8").catch(() => "")), async (p, data) => {
|
|
@@ -11032,8 +11284,8 @@ var _internals17 = {
|
|
|
11032
11284
|
};
|
|
11033
11285
|
|
|
11034
11286
|
// src/services/session-reflection.ts
|
|
11035
|
-
import { promises as
|
|
11036
|
-
import * as
|
|
11287
|
+
import { promises as fs12 } from "fs";
|
|
11288
|
+
import * as path23 from "path";
|
|
11037
11289
|
|
|
11038
11290
|
// src/hooks/skill-improver-llm-factory.ts
|
|
11039
11291
|
function resolveSkillImproverAgentName(sessionId) {
|
|
@@ -11186,13 +11438,13 @@ async function gatherRetroLessonsAndTaxonomy(directory) {
|
|
|
11186
11438
|
const lessons = [];
|
|
11187
11439
|
const taxonomy = {};
|
|
11188
11440
|
try {
|
|
11189
|
-
const evidenceDir =
|
|
11190
|
-
const entries = await
|
|
11441
|
+
const evidenceDir = path23.join(directory, ".swarm", "evidence");
|
|
11442
|
+
const entries = await fs12.readdir(evidenceDir);
|
|
11191
11443
|
const retroDirs = entries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
11192
11444
|
for (const retroDir of retroDirs) {
|
|
11193
|
-
const evidencePath =
|
|
11445
|
+
const evidencePath = path23.join(evidenceDir, retroDir, "evidence.json");
|
|
11194
11446
|
try {
|
|
11195
|
-
const content = await
|
|
11447
|
+
const content = await fs12.readFile(evidencePath, "utf-8");
|
|
11196
11448
|
const parsed = JSON.parse(content);
|
|
11197
11449
|
const bundleEntries = parsed.entries ?? [parsed];
|
|
11198
11450
|
for (const entry of bundleEntries) {
|
|
@@ -11219,14 +11471,14 @@ async function gatherRetroLessonsAndTaxonomy(directory) {
|
|
|
11219
11471
|
async function gatherGateFailures(directory) {
|
|
11220
11472
|
const failures = new Map;
|
|
11221
11473
|
try {
|
|
11222
|
-
const evidenceDir =
|
|
11223
|
-
const entries = await
|
|
11474
|
+
const evidenceDir = path23.join(directory, ".swarm", "evidence");
|
|
11475
|
+
const entries = await fs12.readdir(evidenceDir);
|
|
11224
11476
|
for (const entry of entries) {
|
|
11225
11477
|
if (entry.startsWith("retro-"))
|
|
11226
11478
|
continue;
|
|
11227
|
-
const evidencePath =
|
|
11479
|
+
const evidencePath = path23.join(evidenceDir, entry, "evidence.json");
|
|
11228
11480
|
try {
|
|
11229
|
-
const content = await
|
|
11481
|
+
const content = await fs12.readFile(evidencePath, "utf-8");
|
|
11230
11482
|
const parsed = JSON.parse(content);
|
|
11231
11483
|
const bundleEntries = parsed.entries ?? [parsed];
|
|
11232
11484
|
for (const e of bundleEntries) {
|
|
@@ -11418,19 +11670,19 @@ async function writeSessionReflection(directory, result) {
|
|
|
11418
11670
|
lines.push(result.architectReport);
|
|
11419
11671
|
const content = lines.join(`
|
|
11420
11672
|
`);
|
|
11421
|
-
await
|
|
11673
|
+
await fs12.writeFile(reflectionPath, content, "utf-8");
|
|
11422
11674
|
return reflectionPath;
|
|
11423
11675
|
}
|
|
11424
11676
|
|
|
11425
11677
|
// src/services/skill-improver.ts
|
|
11426
|
-
import { existsSync as
|
|
11678
|
+
import { existsSync as existsSync13 } from "fs";
|
|
11427
11679
|
import { mkdir as mkdir7, readFile as readFile7, rename as rename3, writeFile as writeFile7 } from "fs/promises";
|
|
11428
|
-
import * as
|
|
11680
|
+
import * as path25 from "path";
|
|
11429
11681
|
init_logger();
|
|
11430
11682
|
|
|
11431
11683
|
// src/services/trajectory-cluster.ts
|
|
11432
11684
|
import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
|
|
11433
|
-
import * as
|
|
11685
|
+
import * as path24 from "path";
|
|
11434
11686
|
init_logger();
|
|
11435
11687
|
var MACRO_TRAJECTORY_WINDOW = 200;
|
|
11436
11688
|
var MOTIF_MIN_TASKS = 2;
|
|
@@ -11562,11 +11814,11 @@ async function writeMotifProposals(directory, opts = {}) {
|
|
|
11562
11814
|
if (motifs.length === 0)
|
|
11563
11815
|
return result;
|
|
11564
11816
|
const max = opts.maxProposals ?? 10;
|
|
11565
|
-
const proposalsDir = validateSwarmPath(directory,
|
|
11817
|
+
const proposalsDir = validateSwarmPath(directory, path24.join("skills", "proposals"));
|
|
11566
11818
|
await mkdir6(proposalsDir, { recursive: true });
|
|
11567
11819
|
for (const motif of motifs.slice(0, max)) {
|
|
11568
11820
|
const slug = `motif-${slugify(motif.signature)}`;
|
|
11569
|
-
const filePath =
|
|
11821
|
+
const filePath = path24.join(proposalsDir, `${slug}.md`);
|
|
11570
11822
|
await writeFile6(filePath, buildMotifProposal(motif), "utf-8");
|
|
11571
11823
|
result.proposalsWritten.push(filePath);
|
|
11572
11824
|
}
|
|
@@ -11707,11 +11959,11 @@ async function writeSuccessMotifProposals(directory, opts = {}) {
|
|
|
11707
11959
|
if (motifs.length === 0)
|
|
11708
11960
|
return result;
|
|
11709
11961
|
const max = opts.maxProposals ?? 10;
|
|
11710
|
-
const proposalsDir = validateSwarmPath(directory,
|
|
11962
|
+
const proposalsDir = validateSwarmPath(directory, path24.join("skills", "proposals"));
|
|
11711
11963
|
await mkdir6(proposalsDir, { recursive: true });
|
|
11712
11964
|
for (const motif of motifs.slice(0, max)) {
|
|
11713
11965
|
const slug = workflowSlug(motif.signature);
|
|
11714
|
-
const filePath =
|
|
11966
|
+
const filePath = path24.join(proposalsDir, `${slug}.md`);
|
|
11715
11967
|
await writeFile6(filePath, buildWorkflowProposal(motif), "utf-8");
|
|
11716
11968
|
result.proposalsWritten.push(filePath);
|
|
11717
11969
|
}
|
|
@@ -11723,14 +11975,14 @@ async function writeSuccessMotifProposals(directory, opts = {}) {
|
|
|
11723
11975
|
}
|
|
11724
11976
|
|
|
11725
11977
|
// src/services/unactionable-hardening.ts
|
|
11726
|
-
import { existsSync as
|
|
11978
|
+
import { existsSync as existsSync12 } from "fs";
|
|
11727
11979
|
init_logger();
|
|
11728
11980
|
var HARDENING_BATCH_LIMIT = 5;
|
|
11729
11981
|
async function hardenUnactionableEntries(params) {
|
|
11730
11982
|
const result = { hardened: 0, retired: 0, remaining: 0 };
|
|
11731
11983
|
try {
|
|
11732
11984
|
const queuePath = resolveUnactionablePath(params.directory);
|
|
11733
|
-
if (!
|
|
11985
|
+
if (!existsSync12(queuePath))
|
|
11734
11986
|
return result;
|
|
11735
11987
|
const limit = params.batchLimit ?? HARDENING_BATCH_LIMIT;
|
|
11736
11988
|
const dedupThreshold = params.dedupThreshold ?? 0.6;
|
|
@@ -11834,7 +12086,7 @@ function timestampSlug(d) {
|
|
|
11834
12086
|
return d.toISOString().replace(/[:.]/g, "-");
|
|
11835
12087
|
}
|
|
11836
12088
|
async function atomicWrite(p, content) {
|
|
11837
|
-
await mkdir7(
|
|
12089
|
+
await mkdir7(path25.dirname(p), { recursive: true });
|
|
11838
12090
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
11839
12091
|
await writeFile7(tmp, content, "utf-8");
|
|
11840
12092
|
await rename3(tmp, p);
|
|
@@ -11842,7 +12094,7 @@ async function atomicWrite(p, content) {
|
|
|
11842
12094
|
async function gatherInventory(directory) {
|
|
11843
12095
|
const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
11844
12096
|
const hivePath = resolveHiveKnowledgePath();
|
|
11845
|
-
const hive =
|
|
12097
|
+
const hive = existsSync13(hivePath) ? await readKnowledge(hivePath) : [];
|
|
11846
12098
|
const archived = [...swarm, ...hive].filter((e) => e.status === "archived").length;
|
|
11847
12099
|
const skills = await listSkills(directory);
|
|
11848
12100
|
const knowledgeById = new Map([...swarm, ...hive].map((entry) => [entry.id, entry]));
|
|
@@ -12237,8 +12489,8 @@ async function runSkillImprover(req) {
|
|
|
12237
12489
|
}
|
|
12238
12490
|
throw err;
|
|
12239
12491
|
}
|
|
12240
|
-
const proposalDir =
|
|
12241
|
-
const proposalFile =
|
|
12492
|
+
const proposalDir = path25.join(req.directory, ".swarm", "skill-improver", "proposals");
|
|
12493
|
+
const proposalFile = path25.join(proposalDir, `${timestampSlug(now)}.md`);
|
|
12242
12494
|
const finalBody = source === "llm" ? buildLLMProposalFrame({
|
|
12243
12495
|
body,
|
|
12244
12496
|
targets,
|
|
@@ -12721,20 +12973,20 @@ function countSessionKnowledgeEntries(entries, sessionStart, fallbackCount) {
|
|
|
12721
12973
|
async function copyDirRecursiveWithFailures(src, dest) {
|
|
12722
12974
|
let count = 0;
|
|
12723
12975
|
const failures = [];
|
|
12724
|
-
const entries = await
|
|
12725
|
-
await
|
|
12976
|
+
const entries = await fs13.readdir(src);
|
|
12977
|
+
await fs13.mkdir(dest, { recursive: true });
|
|
12726
12978
|
for (const entry of entries) {
|
|
12727
|
-
const srcEntry =
|
|
12728
|
-
const destEntry =
|
|
12979
|
+
const srcEntry = path26.join(src, entry);
|
|
12980
|
+
const destEntry = path26.join(dest, entry);
|
|
12729
12981
|
try {
|
|
12730
|
-
const stat4 = await
|
|
12982
|
+
const stat4 = await fs13.stat(srcEntry);
|
|
12731
12983
|
if (stat4.isDirectory()) {
|
|
12732
12984
|
const subResult = await copyDirRecursiveWithFailures(srcEntry, destEntry);
|
|
12733
12985
|
count += subResult.copied;
|
|
12734
12986
|
failures.push(...subResult.failures);
|
|
12735
12987
|
} else {
|
|
12736
12988
|
try {
|
|
12737
|
-
await
|
|
12989
|
+
await fs13.copyFile(srcEntry, destEntry);
|
|
12738
12990
|
count++;
|
|
12739
12991
|
} catch (err) {
|
|
12740
12992
|
const errno = err?.code;
|
|
@@ -12909,20 +13161,20 @@ async function runFinalizeStage(ctx) {
|
|
|
12909
13161
|
ctx.warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
12910
13162
|
}
|
|
12911
13163
|
}
|
|
12912
|
-
const lessonsFilePath =
|
|
13164
|
+
const lessonsFilePath = path26.join(ctx.swarmDir, "close-lessons.md");
|
|
12913
13165
|
try {
|
|
12914
|
-
const lessonsText = await
|
|
13166
|
+
const lessonsText = await fs13.readFile(lessonsFilePath, "utf-8");
|
|
12915
13167
|
ctx.explicitLessons = lessonsText.split(`
|
|
12916
13168
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
12917
13169
|
} catch {}
|
|
12918
13170
|
try {
|
|
12919
|
-
const evidenceDir =
|
|
12920
|
-
const evidenceEntries = await
|
|
13171
|
+
const evidenceDir = path26.join(ctx.swarmDir, "evidence");
|
|
13172
|
+
const evidenceEntries = await fs13.readdir(evidenceDir);
|
|
12921
13173
|
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
12922
13174
|
for (const retroDir of retroDirs) {
|
|
12923
|
-
const evidencePath =
|
|
13175
|
+
const evidencePath = path26.join(evidenceDir, retroDir, "evidence.json");
|
|
12924
13176
|
try {
|
|
12925
|
-
const content = await
|
|
13177
|
+
const content = await fs13.readFile(evidencePath, "utf-8");
|
|
12926
13178
|
const parsed = JSON.parse(content);
|
|
12927
13179
|
const entries = parsed.entries ?? [parsed];
|
|
12928
13180
|
for (const entry of entries) {
|
|
@@ -12966,7 +13218,7 @@ async function runFinalizeStage(ctx) {
|
|
|
12966
13218
|
console.warn("[close-command] curateAndStoreSwarm error:", error2);
|
|
12967
13219
|
}
|
|
12968
13220
|
if (ctx.curationSucceeded && ctx.allLessons.length > 0) {
|
|
12969
|
-
await
|
|
13221
|
+
await fs13.unlink(lessonsFilePath).catch(() => {});
|
|
12970
13222
|
}
|
|
12971
13223
|
if (ctx.curationSucceeded) {
|
|
12972
13224
|
if (ctx.config.hive_enabled === false) {} else {
|
|
@@ -13072,7 +13324,7 @@ async function runFinalizeStage(ctx) {
|
|
|
13072
13324
|
}
|
|
13073
13325
|
}
|
|
13074
13326
|
try {
|
|
13075
|
-
const { CuratorConfigSchema: CCS } = await import("./schema-
|
|
13327
|
+
const { CuratorConfigSchema: CCS } = await import("./schema-nz638xc3.js");
|
|
13076
13328
|
const { config: pmLoadedConfig } = _internals20.loadPluginConfigWithMeta(ctx.directory);
|
|
13077
13329
|
const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
|
|
13078
13330
|
if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
|
|
@@ -13102,7 +13354,7 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
13102
13354
|
let checkpointVerified = false;
|
|
13103
13355
|
try {
|
|
13104
13356
|
const result = spawnSync5("sqlite3", [srcPath, "PRAGMA wal_checkpoint(TRUNCATE);"], {
|
|
13105
|
-
cwd:
|
|
13357
|
+
cwd: path26.dirname(srcPath),
|
|
13106
13358
|
encoding: "utf-8",
|
|
13107
13359
|
stdio: ["ignore", "pipe", "pipe"],
|
|
13108
13360
|
timeout: 1e4,
|
|
@@ -13113,7 +13365,7 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
13113
13365
|
const code = result.error.code;
|
|
13114
13366
|
if (code === "ENOENT") {
|
|
13115
13367
|
try {
|
|
13116
|
-
await
|
|
13368
|
+
await fs13.copyFile(srcPath, destPath);
|
|
13117
13369
|
return {
|
|
13118
13370
|
success: true,
|
|
13119
13371
|
reason: "copied without WAL checkpoint (sqlite3 CLI unavailable)"
|
|
@@ -13152,7 +13404,7 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
13152
13404
|
};
|
|
13153
13405
|
}
|
|
13154
13406
|
try {
|
|
13155
|
-
await
|
|
13407
|
+
await fs13.copyFile(srcPath, destPath);
|
|
13156
13408
|
if (checkpointVerified) {
|
|
13157
13409
|
return { success: true };
|
|
13158
13410
|
}
|
|
@@ -13170,9 +13422,9 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
13170
13422
|
async function runArchiveStage(ctx) {
|
|
13171
13423
|
ctx.timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
13172
13424
|
ctx.archiveSuffix = Math.random().toString(36).slice(2, 8);
|
|
13173
|
-
ctx.archiveDir =
|
|
13425
|
+
ctx.archiveDir = path26.join(ctx.swarmDir, "archive", `swarm-${ctx.timestamp}-${ctx.archiveSuffix}`);
|
|
13174
13426
|
try {
|
|
13175
|
-
await
|
|
13427
|
+
await fs13.mkdir(ctx.archiveDir, { recursive: true });
|
|
13176
13428
|
const WAL_SIDECAR_FILES = new Set(["swarm.db-shm", "swarm.db-wal"]);
|
|
13177
13429
|
const linkedKnowledgeShared = isLinked(ctx.directory);
|
|
13178
13430
|
if (linkedKnowledgeShared) {
|
|
@@ -13185,8 +13437,8 @@ async function runArchiveStage(ctx) {
|
|
|
13185
13437
|
if (linkedKnowledgeShared && KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact)) {
|
|
13186
13438
|
continue;
|
|
13187
13439
|
}
|
|
13188
|
-
const srcPath =
|
|
13189
|
-
const destPath =
|
|
13440
|
+
const srcPath = path26.join(ctx.swarmDir, artifact);
|
|
13441
|
+
const destPath = path26.join(ctx.archiveDir, artifact);
|
|
13190
13442
|
if (artifact === "swarm.db") {
|
|
13191
13443
|
const result = await copySqliteSafe(srcPath, destPath);
|
|
13192
13444
|
if (result.skipped) {} else if (result.success) {
|
|
@@ -13202,7 +13454,7 @@ async function runArchiveStage(ctx) {
|
|
|
13202
13454
|
}
|
|
13203
13455
|
} else {
|
|
13204
13456
|
try {
|
|
13205
|
-
await
|
|
13457
|
+
await fs13.copyFile(srcPath, destPath);
|
|
13206
13458
|
ctx.archivedFileCount++;
|
|
13207
13459
|
if (ACTIVE_STATE_TO_CLEAN.includes(artifact)) {
|
|
13208
13460
|
ctx.archivedActiveStateFiles.add(artifact);
|
|
@@ -13218,8 +13470,8 @@ async function runArchiveStage(ctx) {
|
|
|
13218
13470
|
}
|
|
13219
13471
|
}
|
|
13220
13472
|
for (const dirName of ACTIVE_STATE_DIRS_TO_CLEAN) {
|
|
13221
|
-
const srcDir =
|
|
13222
|
-
const destDir =
|
|
13473
|
+
const srcDir = path26.join(ctx.swarmDir, dirName);
|
|
13474
|
+
const destDir = path26.join(ctx.archiveDir, dirName);
|
|
13223
13475
|
try {
|
|
13224
13476
|
const result = await copyDirRecursiveWithFailures(srcDir, destDir);
|
|
13225
13477
|
ctx.archivedFileCount += result.copied;
|
|
@@ -13292,9 +13544,9 @@ async function runCleanStage(ctx) {
|
|
|
13292
13544
|
ctx.warnings.push(reason ? `Preserved ${artifact} because it was not successfully archived: ${reason}.` : `Preserved ${artifact} because it was not successfully archived.`);
|
|
13293
13545
|
continue;
|
|
13294
13546
|
}
|
|
13295
|
-
const filePath =
|
|
13547
|
+
const filePath = path26.join(ctx.swarmDir, artifact);
|
|
13296
13548
|
try {
|
|
13297
|
-
await
|
|
13549
|
+
await fs13.unlink(filePath);
|
|
13298
13550
|
cleanedFiles.push(artifact);
|
|
13299
13551
|
} catch (err) {
|
|
13300
13552
|
const errno = err?.code;
|
|
@@ -13311,18 +13563,18 @@ async function runCleanStage(ctx) {
|
|
|
13311
13563
|
if (!ctx.archivedActiveStateDirs.has(dirName)) {
|
|
13312
13564
|
continue;
|
|
13313
13565
|
}
|
|
13314
|
-
const dirPath =
|
|
13566
|
+
const dirPath = path26.join(ctx.swarmDir, dirName);
|
|
13315
13567
|
try {
|
|
13316
|
-
await
|
|
13568
|
+
await fs13.rm(dirPath, { recursive: true, force: true });
|
|
13317
13569
|
cleanedFiles.push(`${dirName}/`);
|
|
13318
13570
|
} catch {}
|
|
13319
13571
|
}
|
|
13320
13572
|
try {
|
|
13321
|
-
const swarmFiles = await
|
|
13573
|
+
const swarmFiles = await fs13.readdir(ctx.swarmDir);
|
|
13322
13574
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
13323
13575
|
for (const backup of configBackups) {
|
|
13324
13576
|
try {
|
|
13325
|
-
await
|
|
13577
|
+
await fs13.unlink(path26.join(ctx.swarmDir, backup));
|
|
13326
13578
|
configBackupsRemoved++;
|
|
13327
13579
|
} catch (err) {
|
|
13328
13580
|
const errno = err?.code;
|
|
@@ -13335,7 +13587,7 @@ async function runCleanStage(ctx) {
|
|
|
13335
13587
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
13336
13588
|
for (const sibling of ledgerSiblings) {
|
|
13337
13589
|
try {
|
|
13338
|
-
await
|
|
13590
|
+
await fs13.unlink(path26.join(ctx.swarmDir, sibling));
|
|
13339
13591
|
} catch (err) {
|
|
13340
13592
|
const errno = err?.code;
|
|
13341
13593
|
if (errno === "ENOENT") {} else {
|
|
@@ -13353,16 +13605,16 @@ async function runCleanStage(ctx) {
|
|
|
13353
13605
|
}
|
|
13354
13606
|
let swarmPlanFilesRemoved = 0;
|
|
13355
13607
|
const candidates = [
|
|
13356
|
-
|
|
13357
|
-
|
|
13358
|
-
|
|
13359
|
-
|
|
13360
|
-
|
|
13361
|
-
|
|
13608
|
+
path26.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.json"),
|
|
13609
|
+
path26.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.md"),
|
|
13610
|
+
path26.join(ctx.directory, ".swarm", "SWARM_PLAN.json"),
|
|
13611
|
+
path26.join(ctx.directory, ".swarm", "SWARM_PLAN.md"),
|
|
13612
|
+
path26.join(ctx.directory, "SWARM_PLAN.json"),
|
|
13613
|
+
path26.join(ctx.directory, "SWARM_PLAN.md")
|
|
13362
13614
|
];
|
|
13363
13615
|
for (const candidate of candidates) {
|
|
13364
13616
|
try {
|
|
13365
|
-
await
|
|
13617
|
+
await fs13.unlink(candidate);
|
|
13366
13618
|
swarmPlanFilesRemoved++;
|
|
13367
13619
|
} catch (err) {
|
|
13368
13620
|
if (err?.code !== "ENOENT") {
|
|
@@ -13372,11 +13624,11 @@ async function runCleanStage(ctx) {
|
|
|
13372
13624
|
}
|
|
13373
13625
|
let tmpFilesRemoved = 0;
|
|
13374
13626
|
try {
|
|
13375
|
-
const swarmFiles = await
|
|
13627
|
+
const swarmFiles = await fs13.readdir(ctx.swarmDir);
|
|
13376
13628
|
const tmpFiles = swarmFiles.filter((f) => f.startsWith(".tmp."));
|
|
13377
13629
|
for (const tmp of tmpFiles) {
|
|
13378
13630
|
try {
|
|
13379
|
-
await
|
|
13631
|
+
await fs13.unlink(path26.join(ctx.swarmDir, tmp));
|
|
13380
13632
|
tmpFilesRemoved++;
|
|
13381
13633
|
} catch (err) {
|
|
13382
13634
|
const errno = err?.code;
|
|
@@ -13397,7 +13649,7 @@ async function runCleanStage(ctx) {
|
|
|
13397
13649
|
cleanedFiles.push(`${tmpFilesRemoved} .tmp.* file(s)`);
|
|
13398
13650
|
}
|
|
13399
13651
|
clearAllScopes(ctx.directory);
|
|
13400
|
-
const contextPath =
|
|
13652
|
+
const contextPath = path26.join(ctx.swarmDir, "context.md");
|
|
13401
13653
|
const contextContent = [
|
|
13402
13654
|
"# Context",
|
|
13403
13655
|
"",
|
|
@@ -13409,9 +13661,9 @@ async function runCleanStage(ctx) {
|
|
|
13409
13661
|
""
|
|
13410
13662
|
].join(`
|
|
13411
13663
|
`);
|
|
13412
|
-
const contextTempPath =
|
|
13664
|
+
const contextTempPath = path26.join(path26.dirname(contextPath), `${path26.basename(contextPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
13413
13665
|
try {
|
|
13414
|
-
await
|
|
13666
|
+
await fs13.writeFile(contextTempPath, contextContent, "utf-8");
|
|
13415
13667
|
fsSync2.renameSync(contextTempPath, contextPath);
|
|
13416
13668
|
} catch (error2) {
|
|
13417
13669
|
try {
|
|
@@ -13473,7 +13725,7 @@ async function runAlignStage(ctx) {
|
|
|
13473
13725
|
return { gitAlignResult, prunedBranches };
|
|
13474
13726
|
}
|
|
13475
13727
|
async function handleCloseCommand(directory, args, options = {}) {
|
|
13476
|
-
const swarmDir =
|
|
13728
|
+
const swarmDir = path26.join(directory, ".swarm");
|
|
13477
13729
|
try {
|
|
13478
13730
|
const stat4 = fsSync2.lstatSync(swarmDir);
|
|
13479
13731
|
if (stat4.isSymbolicLink()) {
|
|
@@ -13487,18 +13739,18 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
13487
13739
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
13488
13740
|
let planExists = false;
|
|
13489
13741
|
let planData = {
|
|
13490
|
-
title:
|
|
13742
|
+
title: path26.basename(directory) || "Ad-hoc session",
|
|
13491
13743
|
phases: []
|
|
13492
13744
|
};
|
|
13493
13745
|
try {
|
|
13494
|
-
const content = await
|
|
13746
|
+
const content = await fs13.readFile(planPath, "utf-8");
|
|
13495
13747
|
planData = JSON.parse(content);
|
|
13496
13748
|
planExists = true;
|
|
13497
13749
|
} catch (error2) {
|
|
13498
13750
|
if (error2?.code !== "ENOENT") {
|
|
13499
13751
|
return `\u274C Failed to read plan.json: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
13500
13752
|
}
|
|
13501
|
-
const swarmDirExists = await
|
|
13753
|
+
const swarmDirExists = await fs13.access(swarmDir).then(() => true).catch(() => false);
|
|
13502
13754
|
if (!swarmDirExists) {
|
|
13503
13755
|
return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
|
|
13504
13756
|
}
|
|
@@ -13512,15 +13764,15 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
13512
13764
|
}
|
|
13513
13765
|
try {
|
|
13514
13766
|
if (!planExists) {
|
|
13515
|
-
const archiveDir =
|
|
13767
|
+
const archiveDir = path26.join(swarmDir, "archive");
|
|
13516
13768
|
try {
|
|
13517
|
-
const archiveEntries = await
|
|
13769
|
+
const archiveEntries = await fs13.readdir(archiveDir);
|
|
13518
13770
|
const hasArchiveBundle = archiveEntries.some((entry) => entry.startsWith("swarm-"));
|
|
13519
13771
|
if (hasArchiveBundle) {
|
|
13520
13772
|
const hasActiveState = [
|
|
13521
13773
|
...ACTIVE_STATE_TO_CLEAN,
|
|
13522
13774
|
...ACTIVE_STATE_DIRS_TO_CLEAN
|
|
13523
|
-
].some((entry) => fsSync2.existsSync(
|
|
13775
|
+
].some((entry) => fsSync2.existsSync(path26.join(swarmDir, entry)));
|
|
13524
13776
|
if (!hasActiveState) {
|
|
13525
13777
|
return `\u2705 Already finalized \u2014 nothing to do.
|
|
13526
13778
|
|
|
@@ -13643,9 +13895,9 @@ This project was already finalized in a previous /swarm close run. The plan has
|
|
|
13643
13895
|
...ctx.warnings.length > 0 ? ["## Warnings", ...ctx.warnings.map((w) => `- ${w}`), ""] : []
|
|
13644
13896
|
].join(`
|
|
13645
13897
|
`);
|
|
13646
|
-
const closeSummaryTempPath =
|
|
13898
|
+
const closeSummaryTempPath = path26.join(path26.dirname(closeSummaryPath), `${path26.basename(closeSummaryPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
13647
13899
|
try {
|
|
13648
|
-
await
|
|
13900
|
+
await fs13.writeFile(closeSummaryTempPath, summaryContent, "utf-8");
|
|
13649
13901
|
fsSync2.renameSync(closeSummaryTempPath, closeSummaryPath);
|
|
13650
13902
|
} catch (error2) {
|
|
13651
13903
|
try {
|
|
@@ -13985,15 +14237,15 @@ function buildStatusMessage(session, plan) {
|
|
|
13985
14237
|
}
|
|
13986
14238
|
|
|
13987
14239
|
// src/commands/config.ts
|
|
13988
|
-
import * as
|
|
13989
|
-
import * as
|
|
14240
|
+
import * as os7 from "os";
|
|
14241
|
+
import * as path27 from "path";
|
|
13990
14242
|
function getUserConfigDir2() {
|
|
13991
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
14243
|
+
return process.env.XDG_CONFIG_HOME || path27.join(os7.homedir(), ".config");
|
|
13992
14244
|
}
|
|
13993
14245
|
async function handleConfigCommand(directory, _args) {
|
|
13994
14246
|
const config = loadPluginConfig(directory);
|
|
13995
|
-
const userConfigPath =
|
|
13996
|
-
const projectConfigPath =
|
|
14247
|
+
const userConfigPath = path27.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
14248
|
+
const projectConfigPath = path27.join(directory, ".opencode", "opencode-swarm.json");
|
|
13997
14249
|
const lines = [
|
|
13998
14250
|
"## Swarm Configuration",
|
|
13999
14251
|
"",
|
|
@@ -14011,9 +14263,9 @@ async function handleConfigCommand(directory, _args) {
|
|
|
14011
14263
|
}
|
|
14012
14264
|
|
|
14013
14265
|
// src/services/skill-consolidation.ts
|
|
14014
|
-
import { existsSync as
|
|
14266
|
+
import { existsSync as existsSync15 } from "fs";
|
|
14015
14267
|
import { mkdir as mkdir8, readFile as readFile8, rename as rename4, writeFile as writeFile8 } from "fs/promises";
|
|
14016
|
-
import * as
|
|
14268
|
+
import * as path28 from "path";
|
|
14017
14269
|
|
|
14018
14270
|
// src/utils/timeout.ts
|
|
14019
14271
|
async function withTimeout(promise, ms, timeoutError) {
|
|
@@ -14038,11 +14290,11 @@ var DEFAULT_CONSOLIDATION_MAX_CALLS_PER_RUN = 1;
|
|
|
14038
14290
|
var CONSOLIDATION_RUN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
14039
14291
|
var runningByDirectory = new Map;
|
|
14040
14292
|
function consolidationStatePath(directory) {
|
|
14041
|
-
return
|
|
14293
|
+
return path28.join(directory, ".swarm", "skill-improver", "consolidation-state.json");
|
|
14042
14294
|
}
|
|
14043
14295
|
async function readState2(directory) {
|
|
14044
14296
|
const filePath = consolidationStatePath(directory);
|
|
14045
|
-
if (!
|
|
14297
|
+
if (!existsSync15(filePath))
|
|
14046
14298
|
return {};
|
|
14047
14299
|
try {
|
|
14048
14300
|
const parsed = JSON.parse(await readFile8(filePath, "utf-8"));
|
|
@@ -14054,7 +14306,7 @@ async function readState2(directory) {
|
|
|
14054
14306
|
}
|
|
14055
14307
|
}
|
|
14056
14308
|
async function atomicWrite2(filePath, content) {
|
|
14057
|
-
await mkdir8(
|
|
14309
|
+
await mkdir8(path28.dirname(filePath), { recursive: true });
|
|
14058
14310
|
const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
14059
14311
|
await writeFile8(tmp, content, "utf-8");
|
|
14060
14312
|
await rename4(tmp, filePath);
|
|
@@ -14134,7 +14386,7 @@ async function runSkillConsolidationInner(req) {
|
|
|
14134
14386
|
};
|
|
14135
14387
|
}
|
|
14136
14388
|
async function runSkillConsolidation(req) {
|
|
14137
|
-
const key =
|
|
14389
|
+
const key = path28.resolve(req.directory);
|
|
14138
14390
|
const existing = runningByDirectory.get(key);
|
|
14139
14391
|
if (existing) {
|
|
14140
14392
|
return {
|
|
@@ -14216,6 +14468,55 @@ async function handleConsolidateCommand(directory, args, options = {}) {
|
|
|
14216
14468
|
}
|
|
14217
14469
|
}
|
|
14218
14470
|
|
|
14471
|
+
// src/commands/costs.ts
|
|
14472
|
+
async function handleCostsCommand(directory, args) {
|
|
14473
|
+
const summary = summarizeTelemetryCosts(directory);
|
|
14474
|
+
const json = args.includes("--json");
|
|
14475
|
+
if (json) {
|
|
14476
|
+
return [
|
|
14477
|
+
"[COSTS_JSON]",
|
|
14478
|
+
JSON.stringify(summary, null, 2),
|
|
14479
|
+
"[/COSTS_JSON]"
|
|
14480
|
+
].join(`
|
|
14481
|
+
`);
|
|
14482
|
+
}
|
|
14483
|
+
return renderCostSummary(summary);
|
|
14484
|
+
}
|
|
14485
|
+
function renderCostSummary(summary) {
|
|
14486
|
+
const lines = [
|
|
14487
|
+
"## Swarm Costs",
|
|
14488
|
+
"",
|
|
14489
|
+
`Total tracked cost: ${formatUsd(summary.total_cost_usd)}`,
|
|
14490
|
+
`Delegations: ${summary.delegations}`,
|
|
14491
|
+
`Tokens: input ${summary.total_input_tokens.toLocaleString()}, output ${summary.total_output_tokens.toLocaleString()}, reasoning ${summary.total_reasoning_tokens.toLocaleString()}, cache ${summary.total_cache_tokens.toLocaleString()}`,
|
|
14492
|
+
`Cost source: reported ${formatUsd(summary.total_reported_usd)}, estimated ${formatUsd(summary.total_estimated_usd)}, unavailable ${summary.unavailable_delegations}`,
|
|
14493
|
+
"",
|
|
14494
|
+
"### By Agent"
|
|
14495
|
+
];
|
|
14496
|
+
appendCostRows(lines, "Agent", summary.by_agent, "No delegation cost telemetry recorded.");
|
|
14497
|
+
lines.push("", "### By Task");
|
|
14498
|
+
appendCostRows(lines, "Task", summary.by_task, "No task cost telemetry recorded.");
|
|
14499
|
+
lines.push("", "### By Gate");
|
|
14500
|
+
appendCostRows(lines, "Gate", summary.by_gate, "No gate cost telemetry recorded.");
|
|
14501
|
+
lines.push("", "### By Retry Loop");
|
|
14502
|
+
appendCostRows(lines, "Retry", summary.by_retry, "No retry-loop cost telemetry recorded.");
|
|
14503
|
+
return lines.join(`
|
|
14504
|
+
`);
|
|
14505
|
+
}
|
|
14506
|
+
function appendCostRows(lines, label, rows, emptyMessage) {
|
|
14507
|
+
if (rows.length === 0) {
|
|
14508
|
+
lines.push(emptyMessage);
|
|
14509
|
+
return;
|
|
14510
|
+
}
|
|
14511
|
+
lines.push(`| ${label} | Delegations | Cost | Input | Output | Reasoning | Cache | Unavailable |`, "|------|-------------|------|-------|--------|-----------|-------|-------------|");
|
|
14512
|
+
for (const row of rows) {
|
|
14513
|
+
lines.push(`| ${row.name} | ${row.delegations} | ${formatUsd(row.cost_usd)} | ${row.input_tokens.toLocaleString()} | ${row.output_tokens.toLocaleString()} | ${row.reasoning_tokens.toLocaleString()} | ${row.cache_tokens.toLocaleString()} | ${row.unavailable_delegations} |`);
|
|
14514
|
+
}
|
|
14515
|
+
}
|
|
14516
|
+
function formatUsd(value) {
|
|
14517
|
+
return `$${value.toFixed(6)}`;
|
|
14518
|
+
}
|
|
14519
|
+
|
|
14219
14520
|
// src/commands/council.ts
|
|
14220
14521
|
var MAX_QUESTION_LEN = 2000;
|
|
14221
14522
|
function sanitizeQuestion(raw) {
|
|
@@ -14286,8 +14587,8 @@ async function handleCouncilCommand(_directory, args) {
|
|
|
14286
14587
|
|
|
14287
14588
|
// src/commands/coupling.ts
|
|
14288
14589
|
import { randomBytes } from "crypto";
|
|
14289
|
-
import * as
|
|
14290
|
-
import * as
|
|
14590
|
+
import * as fs14 from "fs";
|
|
14591
|
+
import * as path30 from "path";
|
|
14291
14592
|
|
|
14292
14593
|
// src/turbo/epic/cochange-source.ts
|
|
14293
14594
|
import * as child_process3 from "child_process";
|
|
@@ -14297,7 +14598,7 @@ import { promisify as promisify2 } from "util";
|
|
|
14297
14598
|
import * as child_process2 from "child_process";
|
|
14298
14599
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
14299
14600
|
import { readdir as readdir4, readFile as readFile9, stat as stat4 } from "fs/promises";
|
|
14300
|
-
import * as
|
|
14601
|
+
import * as path29 from "path";
|
|
14301
14602
|
import { promisify } from "util";
|
|
14302
14603
|
function getExecFileAsync() {
|
|
14303
14604
|
return promisify(child_process2.execFile);
|
|
@@ -14401,7 +14702,7 @@ async function scanSourceFiles(dir) {
|
|
|
14401
14702
|
try {
|
|
14402
14703
|
const entries = await readdir4(dir, { withFileTypes: true });
|
|
14403
14704
|
for (const entry of entries) {
|
|
14404
|
-
const fullPath =
|
|
14705
|
+
const fullPath = path29.join(dir, entry.name);
|
|
14405
14706
|
if (entry.isDirectory()) {
|
|
14406
14707
|
if (skipDirs.has(entry.name)) {
|
|
14407
14708
|
continue;
|
|
@@ -14409,7 +14710,7 @@ async function scanSourceFiles(dir) {
|
|
|
14409
14710
|
const subFiles = await scanSourceFiles(fullPath);
|
|
14410
14711
|
results.push(...subFiles);
|
|
14411
14712
|
} else if (entry.isFile()) {
|
|
14412
|
-
const ext =
|
|
14713
|
+
const ext = path29.extname(entry.name);
|
|
14413
14714
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
14414
14715
|
results.push(fullPath);
|
|
14415
14716
|
}
|
|
@@ -14431,8 +14732,8 @@ async function getStaticEdges(directory) {
|
|
|
14431
14732
|
continue;
|
|
14432
14733
|
}
|
|
14433
14734
|
try {
|
|
14434
|
-
const sourceDir =
|
|
14435
|
-
const resolvedPath =
|
|
14735
|
+
const sourceDir = path29.dirname(sourceFile);
|
|
14736
|
+
const resolvedPath = path29.resolve(sourceDir, importPath);
|
|
14436
14737
|
const extensions = [
|
|
14437
14738
|
"",
|
|
14438
14739
|
".ts",
|
|
@@ -14457,8 +14758,8 @@ async function getStaticEdges(directory) {
|
|
|
14457
14758
|
if (!targetFile) {
|
|
14458
14759
|
continue;
|
|
14459
14760
|
}
|
|
14460
|
-
const relSource =
|
|
14461
|
-
const relTarget =
|
|
14761
|
+
const relSource = path29.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
14762
|
+
const relTarget = path29.relative(directory, targetFile).replace(/\\/g, "/");
|
|
14462
14763
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
14463
14764
|
edges.add(key);
|
|
14464
14765
|
} catch {}
|
|
@@ -14470,7 +14771,7 @@ async function getStaticEdges(directory) {
|
|
|
14470
14771
|
function isTestImplementationPair(fileA, fileB) {
|
|
14471
14772
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
14472
14773
|
const getBaseName = (filePath) => {
|
|
14473
|
-
const base =
|
|
14774
|
+
const base = path29.basename(filePath);
|
|
14474
14775
|
for (const pattern of testPatterns) {
|
|
14475
14776
|
if (base.endsWith(pattern)) {
|
|
14476
14777
|
return base.slice(0, -pattern.length);
|
|
@@ -14480,16 +14781,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
14480
14781
|
};
|
|
14481
14782
|
const baseA = getBaseName(fileA);
|
|
14482
14783
|
const baseB = getBaseName(fileB);
|
|
14483
|
-
return baseA === baseB && baseA !==
|
|
14784
|
+
return baseA === baseB && baseA !== path29.basename(fileA) && baseA !== path29.basename(fileB);
|
|
14484
14785
|
}
|
|
14485
14786
|
function hasSharedPrefix(fileA, fileB) {
|
|
14486
|
-
const dirA =
|
|
14487
|
-
const dirB =
|
|
14787
|
+
const dirA = path29.dirname(fileA);
|
|
14788
|
+
const dirB = path29.dirname(fileB);
|
|
14488
14789
|
if (dirA !== dirB) {
|
|
14489
14790
|
return false;
|
|
14490
14791
|
}
|
|
14491
|
-
const baseA =
|
|
14492
|
-
const baseB =
|
|
14792
|
+
const baseA = path29.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
14793
|
+
const baseB = path29.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
14493
14794
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
14494
14795
|
return true;
|
|
14495
14796
|
}
|
|
@@ -14544,8 +14845,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
14544
14845
|
const entries = [];
|
|
14545
14846
|
const now = new Date().toISOString();
|
|
14546
14847
|
for (const pair of pairs.slice(0, 10)) {
|
|
14547
|
-
const baseA =
|
|
14548
|
-
const baseB =
|
|
14848
|
+
const baseA = path29.basename(pair.fileA);
|
|
14849
|
+
const baseB = path29.basename(pair.fileB);
|
|
14549
14850
|
let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
14550
14851
|
if (lesson.length > 280) {
|
|
14551
14852
|
lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
@@ -14971,17 +15272,17 @@ function parseArgs3(args) {
|
|
|
14971
15272
|
return parsed;
|
|
14972
15273
|
}
|
|
14973
15274
|
function persistReportJson(directory, report) {
|
|
14974
|
-
const epicDir =
|
|
14975
|
-
|
|
14976
|
-
const filePath =
|
|
15275
|
+
const epicDir = path30.join(directory, ".swarm", "epic");
|
|
15276
|
+
fs14.mkdirSync(epicDir, { recursive: true });
|
|
15277
|
+
const filePath = path30.join(epicDir, "coupling-report.json");
|
|
14977
15278
|
const tmpPath = `${filePath}.tmp.${randomBytes(8).toString("hex")}`;
|
|
14978
|
-
|
|
15279
|
+
fs14.writeFileSync(tmpPath, `${JSON.stringify(report, null, 2)}
|
|
14979
15280
|
`, "utf-8");
|
|
14980
15281
|
try {
|
|
14981
|
-
|
|
15282
|
+
fs14.renameSync(tmpPath, filePath);
|
|
14982
15283
|
} catch (err) {
|
|
14983
15284
|
try {
|
|
14984
|
-
|
|
15285
|
+
fs14.unlinkSync(tmpPath);
|
|
14985
15286
|
} catch {}
|
|
14986
15287
|
throw err;
|
|
14987
15288
|
}
|
|
@@ -15032,7 +15333,7 @@ Usage: /swarm coupling [--phase <n>] [--threshold <-1..1>] [--min-co-changes <n>
|
|
|
15032
15333
|
persistStatus = {
|
|
15033
15334
|
requested: true,
|
|
15034
15335
|
written: true,
|
|
15035
|
-
path:
|
|
15336
|
+
path: path30.relative(directory, writtenAt)
|
|
15036
15337
|
};
|
|
15037
15338
|
} catch (err) {
|
|
15038
15339
|
persistStatus = {
|
|
@@ -15091,7 +15392,7 @@ function formatCurationSummary(summary) {
|
|
|
15091
15392
|
}
|
|
15092
15393
|
|
|
15093
15394
|
// src/commands/dark-matter.ts
|
|
15094
|
-
import
|
|
15395
|
+
import path31 from "path";
|
|
15095
15396
|
async function handleDarkMatterCommand(directory, args) {
|
|
15096
15397
|
const options = {};
|
|
15097
15398
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -15123,7 +15424,7 @@ Ensure this is a git repository with commit history.`;
|
|
|
15123
15424
|
const output = formatDarkMatterOutput(pairs);
|
|
15124
15425
|
if (pairs.length > 0) {
|
|
15125
15426
|
try {
|
|
15126
|
-
const projectName =
|
|
15427
|
+
const projectName = path31.basename(path31.resolve(directory));
|
|
15127
15428
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
15128
15429
|
if (entries.length > 0) {
|
|
15129
15430
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -15489,50 +15790,50 @@ ${USAGE5}`;
|
|
|
15489
15790
|
|
|
15490
15791
|
// src/services/diagnose-service.ts
|
|
15491
15792
|
import * as child_process4 from "child_process";
|
|
15492
|
-
import { existsSync as
|
|
15493
|
-
import
|
|
15793
|
+
import { existsSync as existsSync18, readdirSync as readdirSync3, readFileSync as readFileSync10, statSync as statSync6 } from "fs";
|
|
15794
|
+
import path33 from "path";
|
|
15494
15795
|
import { fileURLToPath } from "url";
|
|
15495
15796
|
|
|
15496
15797
|
// src/config/cache-paths.ts
|
|
15497
|
-
import * as
|
|
15498
|
-
import * as
|
|
15798
|
+
import * as os8 from "os";
|
|
15799
|
+
import * as path32 from "path";
|
|
15499
15800
|
function getPluginConfigDir() {
|
|
15500
|
-
return
|
|
15801
|
+
return path32.join(process.env.XDG_CONFIG_HOME || path32.join(os8.homedir(), ".config"), "opencode");
|
|
15501
15802
|
}
|
|
15502
15803
|
function getPluginCachePaths() {
|
|
15503
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
15804
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path32.join(os8.homedir(), ".cache");
|
|
15504
15805
|
const configDir = getPluginConfigDir();
|
|
15505
15806
|
const paths = [
|
|
15506
|
-
|
|
15507
|
-
|
|
15508
|
-
|
|
15807
|
+
path32.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
|
|
15808
|
+
path32.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
|
|
15809
|
+
path32.join(configDir, "node_modules", "opencode-swarm")
|
|
15509
15810
|
];
|
|
15510
15811
|
if (process.platform === "darwin") {
|
|
15511
|
-
const libCaches =
|
|
15512
|
-
paths.push(
|
|
15812
|
+
const libCaches = path32.join(os8.homedir(), "Library", "Caches");
|
|
15813
|
+
paths.push(path32.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path32.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
|
|
15513
15814
|
}
|
|
15514
15815
|
if (process.platform === "win32") {
|
|
15515
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
15516
|
-
const appData = process.env.APPDATA ||
|
|
15517
|
-
paths.push(
|
|
15816
|
+
const localAppData = process.env.LOCALAPPDATA || path32.join(os8.homedir(), "AppData", "Local");
|
|
15817
|
+
const appData = process.env.APPDATA || path32.join(os8.homedir(), "AppData", "Roaming");
|
|
15818
|
+
paths.push(path32.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path32.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path32.join(appData, "opencode", "node_modules", "opencode-swarm"));
|
|
15518
15819
|
}
|
|
15519
15820
|
return paths;
|
|
15520
15821
|
}
|
|
15521
15822
|
function getPluginLockFilePaths() {
|
|
15522
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
15823
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path32.join(os8.homedir(), ".cache");
|
|
15523
15824
|
const configDir = getPluginConfigDir();
|
|
15524
15825
|
const paths = [
|
|
15525
|
-
|
|
15526
|
-
|
|
15527
|
-
|
|
15826
|
+
path32.join(cacheBase, "opencode", "bun.lock"),
|
|
15827
|
+
path32.join(cacheBase, "opencode", "bun.lockb"),
|
|
15828
|
+
path32.join(configDir, "package-lock.json")
|
|
15528
15829
|
];
|
|
15529
15830
|
if (process.platform === "darwin") {
|
|
15530
|
-
const libCaches =
|
|
15531
|
-
paths.push(
|
|
15831
|
+
const libCaches = path32.join(os8.homedir(), "Library", "Caches");
|
|
15832
|
+
paths.push(path32.join(libCaches, "opencode", "bun.lock"), path32.join(libCaches, "opencode", "bun.lockb"));
|
|
15532
15833
|
}
|
|
15533
15834
|
if (process.platform === "win32") {
|
|
15534
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
15535
|
-
paths.push(
|
|
15835
|
+
const localAppData = process.env.LOCALAPPDATA || path32.join(os8.homedir(), "AppData", "Local");
|
|
15836
|
+
paths.push(path32.join(localAppData, "opencode", "bun.lock"), path32.join(localAppData, "opencode", "bun.lockb"));
|
|
15536
15837
|
}
|
|
15537
15838
|
return paths;
|
|
15538
15839
|
}
|
|
@@ -15542,28 +15843,28 @@ init_capability_probe();
|
|
|
15542
15843
|
init_executor();
|
|
15543
15844
|
|
|
15544
15845
|
// src/services/knowledge-diagnostics.ts
|
|
15545
|
-
import { existsSync as
|
|
15846
|
+
import { existsSync as existsSync17 } from "fs";
|
|
15546
15847
|
import { readFile as readFile10 } from "fs/promises";
|
|
15547
15848
|
|
|
15548
15849
|
// src/services/version-check.ts
|
|
15549
|
-
import { existsSync as
|
|
15850
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
15550
15851
|
import { homedir as homedir4 } from "os";
|
|
15551
|
-
import { join as
|
|
15852
|
+
import { join as join27 } from "path";
|
|
15552
15853
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
15553
15854
|
function cacheDir() {
|
|
15554
15855
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
15555
|
-
const base = xdg && xdg.length > 0 ? xdg :
|
|
15556
|
-
return
|
|
15856
|
+
const base = xdg && xdg.length > 0 ? xdg : join27(homedir4(), ".cache");
|
|
15857
|
+
return join27(base, "opencode-swarm");
|
|
15557
15858
|
}
|
|
15558
15859
|
function cacheFile() {
|
|
15559
|
-
return
|
|
15860
|
+
return join27(cacheDir(), "version-check.json");
|
|
15560
15861
|
}
|
|
15561
15862
|
function readVersionCache() {
|
|
15562
15863
|
try {
|
|
15563
|
-
const
|
|
15564
|
-
if (!
|
|
15864
|
+
const path33 = cacheFile();
|
|
15865
|
+
if (!existsSync16(path33))
|
|
15565
15866
|
return null;
|
|
15566
|
-
const raw =
|
|
15867
|
+
const raw = readFileSync9(path33, "utf-8");
|
|
15567
15868
|
const parsed = JSON.parse(raw);
|
|
15568
15869
|
if (typeof parsed?.checkedAt !== "number")
|
|
15569
15870
|
return null;
|
|
@@ -15602,7 +15903,7 @@ var SEVEN_DAYS_MS2 = 7 * 24 * 60 * 60 * 1000;
|
|
|
15602
15903
|
var UNACTIONABLE_BACKLOG_WARN = 100;
|
|
15603
15904
|
var INSIGHT_BACKLOG_WARN = 50;
|
|
15604
15905
|
async function readRawLines(filePath) {
|
|
15605
|
-
if (!
|
|
15906
|
+
if (!existsSync17(filePath))
|
|
15606
15907
|
return { entries: [], corrupt: 0 };
|
|
15607
15908
|
const content = await readFile10(filePath, "utf-8");
|
|
15608
15909
|
const entries = [];
|
|
@@ -15727,7 +16028,7 @@ async function computeKnowledgeDebug(directory) {
|
|
|
15727
16028
|
};
|
|
15728
16029
|
}
|
|
15729
16030
|
async function safeJsonlCount(filePath) {
|
|
15730
|
-
if (!filePath || !
|
|
16031
|
+
if (!filePath || !existsSync17(filePath))
|
|
15731
16032
|
return 0;
|
|
15732
16033
|
try {
|
|
15733
16034
|
const content = await readFile10(filePath, "utf-8");
|
|
@@ -16048,7 +16349,7 @@ async function checkConfigBackups(directory) {
|
|
|
16048
16349
|
}
|
|
16049
16350
|
async function checkGitRepository(directory) {
|
|
16050
16351
|
try {
|
|
16051
|
-
if (!
|
|
16352
|
+
if (!existsSync18(directory) || !statSync6(directory).isDirectory()) {
|
|
16052
16353
|
return {
|
|
16053
16354
|
name: "Git Repository",
|
|
16054
16355
|
status: "\u274C",
|
|
@@ -16112,8 +16413,8 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
16112
16413
|
};
|
|
16113
16414
|
}
|
|
16114
16415
|
async function checkConfigParseability(directory) {
|
|
16115
|
-
const configPath =
|
|
16116
|
-
if (!
|
|
16416
|
+
const configPath = path33.join(directory, ".opencode/opencode-swarm.json");
|
|
16417
|
+
if (!existsSync18(configPath)) {
|
|
16117
16418
|
return {
|
|
16118
16419
|
name: "Config Parseability",
|
|
16119
16420
|
status: "\u2705",
|
|
@@ -16121,7 +16422,7 @@ async function checkConfigParseability(directory) {
|
|
|
16121
16422
|
};
|
|
16122
16423
|
}
|
|
16123
16424
|
try {
|
|
16124
|
-
const content =
|
|
16425
|
+
const content = readFileSync10(configPath, "utf-8");
|
|
16125
16426
|
JSON.parse(content);
|
|
16126
16427
|
return {
|
|
16127
16428
|
name: "Config Parseability",
|
|
@@ -16141,7 +16442,7 @@ function resolveGrammarDir(thisDir) {
|
|
|
16141
16442
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
16142
16443
|
const isSource = normalized.endsWith("/src/services");
|
|
16143
16444
|
const isCliBundle = normalized.endsWith("/cli");
|
|
16144
|
-
return isSource || isCliBundle ?
|
|
16445
|
+
return isSource || isCliBundle ? path33.join(thisDir, "..", "lang", "grammars") : path33.join(thisDir, "lang", "grammars");
|
|
16145
16446
|
}
|
|
16146
16447
|
async function checkGrammarWasmFiles() {
|
|
16147
16448
|
const grammarFiles = [
|
|
@@ -16165,14 +16466,14 @@ async function checkGrammarWasmFiles() {
|
|
|
16165
16466
|
"tree-sitter-ini.wasm",
|
|
16166
16467
|
"tree-sitter-regex.wasm"
|
|
16167
16468
|
];
|
|
16168
|
-
const thisDir =
|
|
16469
|
+
const thisDir = path33.dirname(fileURLToPath(import.meta.url));
|
|
16169
16470
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
16170
16471
|
const missing = [];
|
|
16171
|
-
if (!
|
|
16472
|
+
if (!existsSync18(path33.join(grammarDir, "tree-sitter.wasm"))) {
|
|
16172
16473
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
16173
16474
|
}
|
|
16174
16475
|
for (const file of grammarFiles) {
|
|
16175
|
-
if (!
|
|
16476
|
+
if (!existsSync18(path33.join(grammarDir, file))) {
|
|
16176
16477
|
missing.push(file);
|
|
16177
16478
|
}
|
|
16178
16479
|
}
|
|
@@ -16190,8 +16491,8 @@ async function checkGrammarWasmFiles() {
|
|
|
16190
16491
|
};
|
|
16191
16492
|
}
|
|
16192
16493
|
async function checkCheckpointManifest(directory) {
|
|
16193
|
-
const manifestPath =
|
|
16194
|
-
if (!
|
|
16494
|
+
const manifestPath = path33.join(directory, ".swarm/checkpoints.json");
|
|
16495
|
+
if (!existsSync18(manifestPath)) {
|
|
16195
16496
|
return {
|
|
16196
16497
|
name: "Checkpoint Manifest",
|
|
16197
16498
|
status: "\u2705",
|
|
@@ -16199,7 +16500,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
16199
16500
|
};
|
|
16200
16501
|
}
|
|
16201
16502
|
try {
|
|
16202
|
-
const content =
|
|
16503
|
+
const content = readFileSync10(manifestPath, "utf-8");
|
|
16203
16504
|
const parsed = JSON.parse(content);
|
|
16204
16505
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
16205
16506
|
return {
|
|
@@ -16242,8 +16543,8 @@ async function checkCheckpointManifest(directory) {
|
|
|
16242
16543
|
}
|
|
16243
16544
|
}
|
|
16244
16545
|
async function checkEventStreamIntegrity(directory) {
|
|
16245
|
-
const eventsPath =
|
|
16246
|
-
if (!
|
|
16546
|
+
const eventsPath = path33.join(directory, ".swarm/events.jsonl");
|
|
16547
|
+
if (!existsSync18(eventsPath)) {
|
|
16247
16548
|
return {
|
|
16248
16549
|
name: "Event Stream",
|
|
16249
16550
|
status: "\u2705",
|
|
@@ -16251,7 +16552,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
16251
16552
|
};
|
|
16252
16553
|
}
|
|
16253
16554
|
try {
|
|
16254
|
-
const content =
|
|
16555
|
+
const content = readFileSync10(eventsPath, "utf-8");
|
|
16255
16556
|
const lines = content.split(`
|
|
16256
16557
|
`).filter((line) => line.trim() !== "");
|
|
16257
16558
|
let malformedCount = 0;
|
|
@@ -16283,8 +16584,8 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
16283
16584
|
}
|
|
16284
16585
|
}
|
|
16285
16586
|
async function checkSteeringDirectives(directory) {
|
|
16286
|
-
const eventsPath =
|
|
16287
|
-
if (!
|
|
16587
|
+
const eventsPath = path33.join(directory, ".swarm/events.jsonl");
|
|
16588
|
+
if (!existsSync18(eventsPath)) {
|
|
16288
16589
|
return {
|
|
16289
16590
|
name: "Steering Directives",
|
|
16290
16591
|
status: "\u2705",
|
|
@@ -16292,7 +16593,7 @@ async function checkSteeringDirectives(directory) {
|
|
|
16292
16593
|
};
|
|
16293
16594
|
}
|
|
16294
16595
|
try {
|
|
16295
|
-
const content =
|
|
16596
|
+
const content = readFileSync10(eventsPath, "utf-8");
|
|
16296
16597
|
const lines = content.split(`
|
|
16297
16598
|
`).filter((line) => line.trim() !== "");
|
|
16298
16599
|
const directivesIssued = [];
|
|
@@ -16339,8 +16640,8 @@ async function checkCurator(directory) {
|
|
|
16339
16640
|
detail: "Disabled (enable via curator.enabled)"
|
|
16340
16641
|
};
|
|
16341
16642
|
}
|
|
16342
|
-
const summaryPath =
|
|
16343
|
-
if (!
|
|
16643
|
+
const summaryPath = path33.join(directory, ".swarm/curator-summary.json");
|
|
16644
|
+
if (!existsSync18(summaryPath)) {
|
|
16344
16645
|
return {
|
|
16345
16646
|
name: "Curator",
|
|
16346
16647
|
status: "\u2705",
|
|
@@ -16348,7 +16649,7 @@ async function checkCurator(directory) {
|
|
|
16348
16649
|
};
|
|
16349
16650
|
}
|
|
16350
16651
|
try {
|
|
16351
|
-
const content =
|
|
16652
|
+
const content = readFileSync10(summaryPath, "utf-8");
|
|
16352
16653
|
const parsed = JSON.parse(content);
|
|
16353
16654
|
if (typeof parsed.schema_version !== "number" || parsed.schema_version !== 1) {
|
|
16354
16655
|
return {
|
|
@@ -16541,8 +16842,8 @@ async function getDiagnoseData(directory) {
|
|
|
16541
16842
|
checks.push(await checkCurator(directory));
|
|
16542
16843
|
checks.push(await checkKnowledgeHealth(directory));
|
|
16543
16844
|
try {
|
|
16544
|
-
const evidenceDir =
|
|
16545
|
-
const snapshotFiles =
|
|
16845
|
+
const evidenceDir = path33.join(directory, ".swarm", "evidence");
|
|
16846
|
+
const snapshotFiles = existsSync18(evidenceDir) ? readdirSync3(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
16546
16847
|
if (snapshotFiles.length > 0) {
|
|
16547
16848
|
const latest = snapshotFiles.sort().pop();
|
|
16548
16849
|
checks.push({
|
|
@@ -16575,13 +16876,13 @@ async function getDiagnoseData(directory) {
|
|
|
16575
16876
|
const cacheRows = [];
|
|
16576
16877
|
for (const cachePath of cachePaths) {
|
|
16577
16878
|
try {
|
|
16578
|
-
if (!
|
|
16879
|
+
if (!existsSync18(cachePath)) {
|
|
16579
16880
|
cacheRows.push(`\u2B1C ${cachePath} \u2014 absent`);
|
|
16580
16881
|
continue;
|
|
16581
16882
|
}
|
|
16582
|
-
const pkgJsonPath =
|
|
16883
|
+
const pkgJsonPath = path33.join(cachePath, "package.json");
|
|
16583
16884
|
try {
|
|
16584
|
-
const raw =
|
|
16885
|
+
const raw = readFileSync10(pkgJsonPath, "utf-8");
|
|
16585
16886
|
const parsed = JSON.parse(raw);
|
|
16586
16887
|
const installedVersion = typeof parsed.version === "string" ? parsed.version : "?";
|
|
16587
16888
|
cacheRows.push(`\u2705 ${cachePath} \u2014 v${installedVersion}`);
|
|
@@ -16800,7 +17101,7 @@ async function handleDoctorCommand(directory, args) {
|
|
|
16800
17101
|
const result = runConfigDoctor(config, directory);
|
|
16801
17102
|
let output;
|
|
16802
17103
|
if (enableAutoFix && result.hasAutoFixableIssues) {
|
|
16803
|
-
const { runConfigDoctorWithFixes } = await import("./config-doctor-
|
|
17104
|
+
const { runConfigDoctorWithFixes } = await import("./config-doctor-9fhfy6p7.js");
|
|
16804
17105
|
const fixResult = await runConfigDoctorWithFixes(directory, config, true);
|
|
16805
17106
|
output = formatDoctorMarkdown(fixResult.result);
|
|
16806
17107
|
} else {
|
|
@@ -16950,10 +17251,10 @@ function decideEpicActivation(tasks, cochangePairs, commitsObserved, options) {
|
|
|
16950
17251
|
|
|
16951
17252
|
// src/turbo/epic/calibration.ts
|
|
16952
17253
|
init_logger();
|
|
16953
|
-
import * as
|
|
16954
|
-
import * as
|
|
17254
|
+
import * as fs15 from "fs";
|
|
17255
|
+
import * as path34 from "path";
|
|
16955
17256
|
var STATE_FILE = "calibration.json";
|
|
16956
|
-
var STATE_REL_DIR =
|
|
17257
|
+
var STATE_REL_DIR = path34.join(".swarm", "epic");
|
|
16957
17258
|
function nowISO() {
|
|
16958
17259
|
return new Date().toISOString();
|
|
16959
17260
|
}
|
|
@@ -16975,13 +17276,13 @@ function markUnreadable(directory, reason) {
|
|
|
16975
17276
|
error(`[epic/calibration] state file unreadable for ${directory}: ${reason} \u2014 failing closed`);
|
|
16976
17277
|
}
|
|
16977
17278
|
function repairCalibrationUnreadable(directory) {
|
|
16978
|
-
const filePath =
|
|
16979
|
-
if (!
|
|
17279
|
+
const filePath = path34.join(directory, STATE_REL_DIR, STATE_FILE);
|
|
17280
|
+
if (!fs15.existsSync(filePath)) {
|
|
16980
17281
|
stateUnreadableMap.delete(directory);
|
|
16981
17282
|
return;
|
|
16982
17283
|
}
|
|
16983
17284
|
try {
|
|
16984
|
-
const raw =
|
|
17285
|
+
const raw = fs15.readFileSync(filePath, "utf-8");
|
|
16985
17286
|
const parsed = JSON.parse(raw);
|
|
16986
17287
|
if (!isValidCalibrationShape(parsed)) {
|
|
16987
17288
|
stateUnreadableMap.set(directory, true);
|
|
@@ -17007,9 +17308,9 @@ function isValidCalibrationShape(candidate) {
|
|
|
17007
17308
|
return true;
|
|
17008
17309
|
}
|
|
17009
17310
|
function ensureSwarmEpicDir(directory) {
|
|
17010
|
-
const dir =
|
|
17011
|
-
if (!
|
|
17012
|
-
|
|
17311
|
+
const dir = path34.resolve(directory, STATE_REL_DIR);
|
|
17312
|
+
if (!fs15.existsSync(dir)) {
|
|
17313
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
17013
17314
|
}
|
|
17014
17315
|
return dir;
|
|
17015
17316
|
}
|
|
@@ -17019,18 +17320,18 @@ function loadCalibrationState(directory) {
|
|
|
17019
17320
|
if (stateUnreadableMap.get(directory))
|
|
17020
17321
|
return null;
|
|
17021
17322
|
}
|
|
17022
|
-
const filePath =
|
|
17323
|
+
const filePath = path34.join(directory, STATE_REL_DIR, STATE_FILE);
|
|
17023
17324
|
try {
|
|
17024
|
-
if (!
|
|
17325
|
+
if (!fs15.existsSync(filePath)) {
|
|
17025
17326
|
const seed = emptyCalibrationState();
|
|
17026
17327
|
try {
|
|
17027
17328
|
ensureSwarmEpicDir(directory);
|
|
17028
|
-
|
|
17329
|
+
fs15.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
|
|
17029
17330
|
`, "utf-8");
|
|
17030
17331
|
} catch {}
|
|
17031
17332
|
return seed;
|
|
17032
17333
|
}
|
|
17033
|
-
const raw =
|
|
17334
|
+
const raw = fs15.readFileSync(filePath, "utf-8");
|
|
17034
17335
|
const parsed = JSON.parse(raw);
|
|
17035
17336
|
if (!isValidCalibrationShape(parsed)) {
|
|
17036
17337
|
markUnreadable(directory, `malformed shape (version=${parsed?.version}, hotModuleAdditions type=${Array.isArray(parsed?.hotModuleAdditions) ? "array" : typeof parsed?.hotModuleAdditions})`);
|
|
@@ -17045,36 +17346,36 @@ function loadCalibrationState(directory) {
|
|
|
17045
17346
|
|
|
17046
17347
|
// src/turbo/epic/divergence-recorder.ts
|
|
17047
17348
|
init_logger();
|
|
17048
|
-
import * as
|
|
17049
|
-
import * as
|
|
17050
|
-
var EVIDENCE_REL_DIR =
|
|
17349
|
+
import * as fs16 from "fs";
|
|
17350
|
+
import * as path35 from "path";
|
|
17351
|
+
var EVIDENCE_REL_DIR = path35.join(".swarm", "epic");
|
|
17051
17352
|
var EVIDENCE_FILE = "divergence.jsonl";
|
|
17052
17353
|
var MAX_TAIL_BYTES2 = 16 * 1024 * 1024;
|
|
17053
17354
|
function readDivergenceHistory(directory, options) {
|
|
17054
|
-
const filePath =
|
|
17055
|
-
if (!
|
|
17355
|
+
const filePath = path35.join(directory, EVIDENCE_REL_DIR, EVIDENCE_FILE);
|
|
17356
|
+
if (!fs16.existsSync(filePath)) {
|
|
17056
17357
|
return [];
|
|
17057
17358
|
}
|
|
17058
17359
|
const maxBytes = options?.maxBytes ?? MAX_TAIL_BYTES2;
|
|
17059
17360
|
let raw;
|
|
17060
17361
|
let tailTruncated = false;
|
|
17061
17362
|
try {
|
|
17062
|
-
const stat5 =
|
|
17363
|
+
const stat5 = fs16.statSync(filePath);
|
|
17063
17364
|
if (Number.isFinite(maxBytes) && stat5.size > maxBytes) {
|
|
17064
|
-
const fd =
|
|
17365
|
+
const fd = fs16.openSync(filePath, "r");
|
|
17065
17366
|
try {
|
|
17066
17367
|
const buf = Buffer.alloc(maxBytes);
|
|
17067
17368
|
const offset = stat5.size - maxBytes;
|
|
17068
|
-
|
|
17369
|
+
fs16.readSync(fd, buf, 0, maxBytes, offset);
|
|
17069
17370
|
raw = buf.toString("utf-8");
|
|
17070
17371
|
tailTruncated = true;
|
|
17071
17372
|
} finally {
|
|
17072
17373
|
try {
|
|
17073
|
-
|
|
17374
|
+
fs16.closeSync(fd);
|
|
17074
17375
|
} catch {}
|
|
17075
17376
|
}
|
|
17076
17377
|
} else {
|
|
17077
|
-
raw =
|
|
17378
|
+
raw = fs16.readFileSync(filePath, "utf-8");
|
|
17078
17379
|
}
|
|
17079
17380
|
} catch {
|
|
17080
17381
|
return [];
|
|
@@ -17099,16 +17400,16 @@ function readDivergenceHistory(directory, options) {
|
|
|
17099
17400
|
}
|
|
17100
17401
|
|
|
17101
17402
|
// src/turbo/epic/promotion-evidence.ts
|
|
17102
|
-
import * as
|
|
17103
|
-
import * as
|
|
17104
|
-
var EVIDENCE_REL_DIR2 =
|
|
17403
|
+
import * as fs17 from "fs";
|
|
17404
|
+
import * as path36 from "path";
|
|
17405
|
+
var EVIDENCE_REL_DIR2 = path36.join(".swarm", "evidence");
|
|
17105
17406
|
var EVIDENCE_FILE2 = "epic-promotions.jsonl";
|
|
17106
17407
|
function readPromotionEvidence(directory) {
|
|
17107
|
-
const filePath =
|
|
17108
|
-
if (!
|
|
17408
|
+
const filePath = path36.join(directory, EVIDENCE_REL_DIR2, EVIDENCE_FILE2);
|
|
17409
|
+
if (!fs17.existsSync(filePath)) {
|
|
17109
17410
|
return [];
|
|
17110
17411
|
}
|
|
17111
|
-
const raw =
|
|
17412
|
+
const raw = fs17.readFileSync(filePath, "utf-8");
|
|
17112
17413
|
const lines = raw.split(`
|
|
17113
17414
|
`).filter((l) => l.trim().length > 0);
|
|
17114
17415
|
const records = [];
|
|
@@ -17613,7 +17914,7 @@ async function handleEvidenceCommand(directory, args) {
|
|
|
17613
17914
|
return formatTaskEvidenceMarkdown(evidenceData);
|
|
17614
17915
|
}
|
|
17615
17916
|
async function handleEvidenceSummaryCommand(directory) {
|
|
17616
|
-
const { buildEvidenceSummary } = await import("./evidence-summary-service-
|
|
17917
|
+
const { buildEvidenceSummary } = await import("./evidence-summary-service-4hs44n2c.js");
|
|
17617
17918
|
const artifact = await buildEvidenceSummary(directory);
|
|
17618
17919
|
if (!artifact) {
|
|
17619
17920
|
return "No plan found. Run `/swarm plan` to check plan status.";
|
|
@@ -17677,8 +17978,8 @@ async function handleExportCommand(directory, _args) {
|
|
|
17677
17978
|
}
|
|
17678
17979
|
// src/full-auto/state.ts
|
|
17679
17980
|
var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
|
|
17680
|
-
import * as
|
|
17681
|
-
import * as
|
|
17981
|
+
import * as fs18 from "fs";
|
|
17982
|
+
import * as path37 from "path";
|
|
17682
17983
|
init_logger();
|
|
17683
17984
|
var lockfile4 = import_proper_lockfile4.default;
|
|
17684
17985
|
var STATE_FILE2 = "full-auto-state.json";
|
|
@@ -17686,9 +17987,9 @@ function nowISO2() {
|
|
|
17686
17987
|
return new Date().toISOString();
|
|
17687
17988
|
}
|
|
17688
17989
|
function ensureSwarmDir(directory) {
|
|
17689
|
-
const swarmDir =
|
|
17690
|
-
if (!
|
|
17691
|
-
|
|
17990
|
+
const swarmDir = path37.resolve(directory, ".swarm");
|
|
17991
|
+
if (!fs18.existsSync(swarmDir)) {
|
|
17992
|
+
fs18.mkdirSync(swarmDir, { recursive: true });
|
|
17692
17993
|
}
|
|
17693
17994
|
return swarmDir;
|
|
17694
17995
|
}
|
|
@@ -17746,7 +18047,7 @@ function withStateLock(directory, fn) {
|
|
|
17746
18047
|
let release;
|
|
17747
18048
|
try {
|
|
17748
18049
|
const lockTarget = validateSwarmPath(directory, STATE_FILE2);
|
|
17749
|
-
if (!
|
|
18050
|
+
if (!fs18.existsSync(lockTarget)) {
|
|
17750
18051
|
ensureSwarmDir(directory);
|
|
17751
18052
|
const seed = {
|
|
17752
18053
|
version: 2,
|
|
@@ -17754,7 +18055,7 @@ function withStateLock(directory, fn) {
|
|
|
17754
18055
|
oversightSequence: 0,
|
|
17755
18056
|
sessions: {}
|
|
17756
18057
|
};
|
|
17757
|
-
|
|
18058
|
+
fs18.writeFileSync(lockTarget, `${JSON.stringify(seed, null, 2)}
|
|
17758
18059
|
`, "utf-8");
|
|
17759
18060
|
}
|
|
17760
18061
|
release = lockfile4.lockSync(lockTarget, {
|
|
@@ -17804,7 +18105,7 @@ function readPersisted(directory) {
|
|
|
17804
18105
|
const filePath = validateSwarmPath(directory, STATE_FILE2);
|
|
17805
18106
|
let stats;
|
|
17806
18107
|
try {
|
|
17807
|
-
stats =
|
|
18108
|
+
stats = fs18.statSync(filePath);
|
|
17808
18109
|
} catch {
|
|
17809
18110
|
clearStateUnreadable();
|
|
17810
18111
|
readCache.delete(filePath);
|
|
@@ -17815,7 +18116,7 @@ function readPersisted(directory) {
|
|
|
17815
18116
|
clearStateUnreadable();
|
|
17816
18117
|
return structuredClone(cached.state);
|
|
17817
18118
|
}
|
|
17818
|
-
const raw =
|
|
18119
|
+
const raw = fs18.readFileSync(filePath, "utf-8");
|
|
17819
18120
|
const parsed = JSON.parse(raw);
|
|
17820
18121
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 2 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
|
|
17821
18122
|
markStateUnreadable(`malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
|
|
@@ -17840,8 +18141,8 @@ function readPersisted(directory) {
|
|
|
17840
18141
|
error(`[full-auto/state] Failed to read ${STATE_FILE2}: ${reason} \u2014 attempting .bak recovery`);
|
|
17841
18142
|
try {
|
|
17842
18143
|
const bakPath = validateSwarmPath(directory, `${STATE_FILE2}.bak`);
|
|
17843
|
-
if (
|
|
17844
|
-
const raw =
|
|
18144
|
+
if (fs18.existsSync(bakPath)) {
|
|
18145
|
+
const raw = fs18.readFileSync(bakPath, "utf-8");
|
|
17845
18146
|
const parsed = JSON.parse(raw);
|
|
17846
18147
|
if (parsed?.version === 2 && parsed.sessions && !Array.isArray(parsed.sessions)) {
|
|
17847
18148
|
warn(`[full-auto/state] Recovered from ${STATE_FILE2}.bak`);
|
|
@@ -17881,23 +18182,23 @@ function writePersisted(directory, persisted) {
|
|
|
17881
18182
|
throw new Error(`Full-Auto state persistence prepare failed: ${msg}`);
|
|
17882
18183
|
}
|
|
17883
18184
|
try {
|
|
17884
|
-
if (
|
|
17885
|
-
|
|
18185
|
+
if (fs18.existsSync(filePath)) {
|
|
18186
|
+
fs18.copyFileSync(filePath, bakPath);
|
|
17886
18187
|
}
|
|
17887
18188
|
} catch {}
|
|
17888
18189
|
try {
|
|
17889
|
-
|
|
18190
|
+
fs18.writeFileSync(tmpPath, payload, "utf-8");
|
|
17890
18191
|
try {
|
|
17891
|
-
const fd =
|
|
18192
|
+
const fd = fs18.openSync(tmpPath, "r+");
|
|
17892
18193
|
try {
|
|
17893
|
-
|
|
18194
|
+
fs18.fsyncSync(fd);
|
|
17894
18195
|
} finally {
|
|
17895
|
-
|
|
18196
|
+
fs18.closeSync(fd);
|
|
17896
18197
|
}
|
|
17897
18198
|
} catch {}
|
|
17898
|
-
|
|
18199
|
+
fs18.renameSync(tmpPath, filePath);
|
|
17899
18200
|
readCache.delete(filePath);
|
|
17900
|
-
const readback =
|
|
18201
|
+
const readback = fs18.readFileSync(filePath, "utf-8");
|
|
17901
18202
|
const parsed = JSON.parse(readback);
|
|
17902
18203
|
if (parsed?.version !== 2) {
|
|
17903
18204
|
throw new Error("Round-trip readback returned wrong version");
|
|
@@ -18117,7 +18418,7 @@ function buildStatusReport(directory, sessionID, sessionFlag) {
|
|
|
18117
18418
|
|
|
18118
18419
|
// src/commands/handoff.ts
|
|
18119
18420
|
import crypto4 from "crypto";
|
|
18120
|
-
import { renameSync as renameSync9, unlinkSync as
|
|
18421
|
+
import { renameSync as renameSync9, unlinkSync as unlinkSync6 } from "fs";
|
|
18121
18422
|
|
|
18122
18423
|
// src/services/handoff-service.ts
|
|
18123
18424
|
var RTL_OVERRIDE_PATTERN = /[\u202e\u202d\u202c\u200f]/g;
|
|
@@ -18498,7 +18799,7 @@ var _internals27 = {
|
|
|
18498
18799
|
|
|
18499
18800
|
// src/session/snapshot-writer.ts
|
|
18500
18801
|
import { closeSync as closeSync6, fsyncSync as fsyncSync2, mkdirSync as mkdirSync14, openSync as openSync6, renameSync as renameSync8 } from "fs";
|
|
18501
|
-
import * as
|
|
18802
|
+
import * as path38 from "path";
|
|
18502
18803
|
var _writeInFlight = Promise.resolve();
|
|
18503
18804
|
function serializeAgentSession(s) {
|
|
18504
18805
|
const gateLog = {};
|
|
@@ -18605,7 +18906,7 @@ async function writeSnapshot(directory, state) {
|
|
|
18605
18906
|
}
|
|
18606
18907
|
const content = JSON.stringify(snapshot, null, 2);
|
|
18607
18908
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
18608
|
-
const dir =
|
|
18909
|
+
const dir = path38.dirname(resolvedPath);
|
|
18609
18910
|
mkdirSync14(dir, { recursive: true });
|
|
18610
18911
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
18611
18912
|
await bunWrite(tempPath, content);
|
|
@@ -18652,7 +18953,7 @@ async function handleHandoffCommand(directory, _args) {
|
|
|
18652
18953
|
renameSync9(tempPath, resolvedPath);
|
|
18653
18954
|
} catch (renameErr) {
|
|
18654
18955
|
try {
|
|
18655
|
-
|
|
18956
|
+
unlinkSync6(tempPath);
|
|
18656
18957
|
} catch {}
|
|
18657
18958
|
throw renameErr;
|
|
18658
18959
|
}
|
|
@@ -18664,7 +18965,7 @@ async function handleHandoffCommand(directory, _args) {
|
|
|
18664
18965
|
renameSync9(promptTempPath, promptPath);
|
|
18665
18966
|
} catch (renameErr) {
|
|
18666
18967
|
try {
|
|
18667
|
-
|
|
18968
|
+
unlinkSync6(promptTempPath);
|
|
18668
18969
|
} catch {}
|
|
18669
18970
|
throw renameErr;
|
|
18670
18971
|
}
|
|
@@ -19108,15 +19409,15 @@ ${USAGE6}`;
|
|
|
19108
19409
|
}
|
|
19109
19410
|
|
|
19110
19411
|
// src/commands/knowledge.ts
|
|
19111
|
-
import { join as
|
|
19412
|
+
import { join as join32 } from "path";
|
|
19112
19413
|
|
|
19113
19414
|
// src/hooks/knowledge-migrator.ts
|
|
19114
19415
|
init_logger();
|
|
19115
19416
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
19116
|
-
import { existsSync as
|
|
19417
|
+
import { existsSync as existsSync23, readFileSync as readFileSync15 } from "fs";
|
|
19117
19418
|
import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
|
|
19118
|
-
import * as
|
|
19119
|
-
import * as
|
|
19419
|
+
import * as os9 from "os";
|
|
19420
|
+
import * as path39 from "path";
|
|
19120
19421
|
|
|
19121
19422
|
// src/hooks/knowledge-types.ts
|
|
19122
19423
|
var KNOWLEDGE_SCHEMA_VERSION = 2;
|
|
@@ -19146,10 +19447,10 @@ var _internals30 = {
|
|
|
19146
19447
|
resolveLegacyHiveKnowledgePath
|
|
19147
19448
|
};
|
|
19148
19449
|
async function migrateContextToKnowledge(directory, config) {
|
|
19149
|
-
const sentinelPath =
|
|
19150
|
-
const contextPath =
|
|
19450
|
+
const sentinelPath = path39.join(directory, ".swarm", ".knowledge-migrated");
|
|
19451
|
+
const contextPath = path39.join(directory, ".swarm", "context.md");
|
|
19151
19452
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
19152
|
-
if (
|
|
19453
|
+
if (existsSync23(sentinelPath)) {
|
|
19153
19454
|
return {
|
|
19154
19455
|
migrated: false,
|
|
19155
19456
|
entriesMigrated: 0,
|
|
@@ -19158,7 +19459,7 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
19158
19459
|
skippedReason: "sentinel-exists"
|
|
19159
19460
|
};
|
|
19160
19461
|
}
|
|
19161
|
-
if (!
|
|
19462
|
+
if (!existsSync23(contextPath)) {
|
|
19162
19463
|
return {
|
|
19163
19464
|
migrated: false,
|
|
19164
19465
|
entriesMigrated: 0,
|
|
@@ -19249,8 +19550,8 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
19249
19550
|
async function migrateHiveKnowledgeLegacy(config) {
|
|
19250
19551
|
const legacyHivePath = _internals30.resolveLegacyHiveKnowledgePath();
|
|
19251
19552
|
const canonicalHivePath = resolveHiveKnowledgePath();
|
|
19252
|
-
const sentinelPath =
|
|
19253
|
-
if (
|
|
19553
|
+
const sentinelPath = path39.join(path39.dirname(canonicalHivePath), ".hive-knowledge-migrated");
|
|
19554
|
+
if (existsSync23(sentinelPath)) {
|
|
19254
19555
|
return {
|
|
19255
19556
|
migrated: false,
|
|
19256
19557
|
entriesMigrated: 0,
|
|
@@ -19259,7 +19560,7 @@ async function migrateHiveKnowledgeLegacy(config) {
|
|
|
19259
19560
|
skippedReason: "sentinel-exists"
|
|
19260
19561
|
};
|
|
19261
19562
|
}
|
|
19262
|
-
if (!
|
|
19563
|
+
if (!existsSync23(legacyHivePath)) {
|
|
19263
19564
|
return {
|
|
19264
19565
|
migrated: false,
|
|
19265
19566
|
entriesMigrated: 0,
|
|
@@ -19460,16 +19761,16 @@ function truncateLesson2(text) {
|
|
|
19460
19761
|
return `${text.slice(0, 277)}...`;
|
|
19461
19762
|
}
|
|
19462
19763
|
function inferProjectName(directory) {
|
|
19463
|
-
const packageJsonPath =
|
|
19464
|
-
if (
|
|
19764
|
+
const packageJsonPath = path39.join(directory, "package.json");
|
|
19765
|
+
if (existsSync23(packageJsonPath)) {
|
|
19465
19766
|
try {
|
|
19466
|
-
const pkg = JSON.parse(
|
|
19767
|
+
const pkg = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
|
|
19467
19768
|
if (pkg.name && typeof pkg.name === "string") {
|
|
19468
19769
|
return pkg.name;
|
|
19469
19770
|
}
|
|
19470
19771
|
} catch {}
|
|
19471
19772
|
}
|
|
19472
|
-
return
|
|
19773
|
+
return path39.basename(directory);
|
|
19473
19774
|
}
|
|
19474
19775
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
19475
19776
|
const sentinel = {
|
|
@@ -19481,21 +19782,21 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
19481
19782
|
schema_version: 1,
|
|
19482
19783
|
migration_tool: "knowledge-migrator.ts"
|
|
19483
19784
|
};
|
|
19484
|
-
await mkdir9(
|
|
19785
|
+
await mkdir9(path39.dirname(sentinelPath), { recursive: true });
|
|
19485
19786
|
await writeFile9(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
19486
19787
|
}
|
|
19487
19788
|
function resolveLegacyHiveKnowledgePath() {
|
|
19488
19789
|
const platform = process.platform;
|
|
19489
|
-
const home = process.env.HOME ||
|
|
19790
|
+
const home = process.env.HOME || os9.homedir();
|
|
19490
19791
|
let dataDir;
|
|
19491
19792
|
if (platform === "win32") {
|
|
19492
|
-
dataDir =
|
|
19793
|
+
dataDir = path39.join(process.env.LOCALAPPDATA || path39.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
19493
19794
|
} else if (platform === "darwin") {
|
|
19494
|
-
dataDir =
|
|
19795
|
+
dataDir = path39.join(home, "Library", "Application Support", "opencode-swarm");
|
|
19495
19796
|
} else {
|
|
19496
|
-
dataDir =
|
|
19797
|
+
dataDir = path39.join(process.env.XDG_DATA_HOME || path39.join(home, ".local", "share"), "opencode-swarm");
|
|
19497
19798
|
}
|
|
19498
|
-
return
|
|
19799
|
+
return path39.join(dataDir, "hive-knowledge.jsonl");
|
|
19499
19800
|
}
|
|
19500
19801
|
|
|
19501
19802
|
// src/commands/knowledge.ts
|
|
@@ -19549,7 +19850,7 @@ async function handleKnowledgeRestoreCommand(directory, args) {
|
|
|
19549
19850
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
19550
19851
|
}
|
|
19551
19852
|
try {
|
|
19552
|
-
const quarantinePath =
|
|
19853
|
+
const quarantinePath = join32(resolveKnowledgeStoreDir(directory), "knowledge-quarantined.jsonl");
|
|
19553
19854
|
const entries = await readKnowledge(quarantinePath);
|
|
19554
19855
|
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
19555
19856
|
if ("error" in resolved) {
|
|
@@ -19800,15 +20101,15 @@ var _internals31 = {
|
|
|
19800
20101
|
};
|
|
19801
20102
|
|
|
19802
20103
|
// src/commands/link.ts
|
|
19803
|
-
import { existsSync as
|
|
19804
|
-
import * as
|
|
20104
|
+
import { existsSync as existsSync24 } from "fs";
|
|
20105
|
+
import * as path41 from "path";
|
|
19805
20106
|
|
|
19806
20107
|
// src/knowledge/identity.ts
|
|
19807
20108
|
import * as child_process5 from "child_process";
|
|
19808
20109
|
import { createHash as createHash4 } from "crypto";
|
|
19809
|
-
import * as
|
|
20110
|
+
import * as path40 from "path";
|
|
19810
20111
|
function deriveProjectHash(directory) {
|
|
19811
|
-
const absolutePath =
|
|
20112
|
+
const absolutePath = path40.resolve(directory);
|
|
19812
20113
|
let hashInput;
|
|
19813
20114
|
try {
|
|
19814
20115
|
const remoteUrl = child_process5.execSync("git remote get-url origin", {
|
|
@@ -19828,18 +20129,18 @@ function deriveProjectHash(directory) {
|
|
|
19828
20129
|
// src/commands/link.ts
|
|
19829
20130
|
var DEDUP_THRESHOLD = 0.6;
|
|
19830
20131
|
async function mergeLocalKnowledgeIntoLink(localSwarmDir, linkDir) {
|
|
19831
|
-
const localPath =
|
|
19832
|
-
const sharedPath =
|
|
19833
|
-
if (!
|
|
20132
|
+
const localPath = path41.join(localSwarmDir, "knowledge.jsonl");
|
|
20133
|
+
const sharedPath = path41.join(linkDir, "knowledge.jsonl");
|
|
20134
|
+
if (!existsSync24(localPath))
|
|
19834
20135
|
return { merged: 0, skipped: 0 };
|
|
19835
20136
|
let merged = 0;
|
|
19836
20137
|
let skipped = 0;
|
|
19837
|
-
const { readFileSync:
|
|
20138
|
+
const { readFileSync: readFileSync16 } = await import("fs");
|
|
19838
20139
|
let changed = false;
|
|
19839
20140
|
await transactKnowledge(sharedPath, (sharedEntries) => {
|
|
19840
20141
|
const localEntries = [];
|
|
19841
20142
|
try {
|
|
19842
|
-
const content =
|
|
20143
|
+
const content = readFileSync16(localPath, "utf-8");
|
|
19843
20144
|
for (const line of content.split(`
|
|
19844
20145
|
`)) {
|
|
19845
20146
|
if (line.trim()) {
|
|
@@ -19927,7 +20228,7 @@ ${formatStatus(directory)}`;
|
|
|
19927
20228
|
const linkDir = resolveLinkDir(linkId);
|
|
19928
20229
|
let merge;
|
|
19929
20230
|
try {
|
|
19930
|
-
merge = await mergeLocalKnowledgeIntoLink(
|
|
20231
|
+
merge = await mergeLocalKnowledgeIntoLink(path41.join(directory, ".swarm"), linkDir);
|
|
19931
20232
|
} catch (error2) {
|
|
19932
20233
|
return `\u274C Failed to merge local knowledge into the link store: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
19933
20234
|
}
|
|
@@ -20071,8 +20372,8 @@ ${USAGE7}`;
|
|
|
20071
20372
|
}
|
|
20072
20373
|
|
|
20073
20374
|
// src/commands/memory.ts
|
|
20074
|
-
import { existsSync as
|
|
20075
|
-
import * as
|
|
20375
|
+
import { existsSync as existsSync27 } from "fs";
|
|
20376
|
+
import * as path48 from "path";
|
|
20076
20377
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20077
20378
|
|
|
20078
20379
|
// src/memory/config.ts
|
|
@@ -20212,13 +20513,13 @@ class MemoryValidationError extends Error {
|
|
|
20212
20513
|
}
|
|
20213
20514
|
}
|
|
20214
20515
|
// src/memory/evaluation.ts
|
|
20215
|
-
import * as
|
|
20216
|
-
import * as
|
|
20217
|
-
import * as
|
|
20516
|
+
import * as fs19 from "fs/promises";
|
|
20517
|
+
import * as os10 from "os";
|
|
20518
|
+
import * as path46 from "path";
|
|
20218
20519
|
|
|
20219
20520
|
// src/memory/local-jsonl-provider.ts
|
|
20220
20521
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
20221
|
-
import { existsSync as
|
|
20522
|
+
import { existsSync as existsSync25 } from "fs";
|
|
20222
20523
|
import {
|
|
20223
20524
|
appendFile as appendFile3,
|
|
20224
20525
|
mkdir as mkdir10,
|
|
@@ -20226,7 +20527,7 @@ import {
|
|
|
20226
20527
|
rename as rename5,
|
|
20227
20528
|
writeFile as writeFile10
|
|
20228
20529
|
} from "fs/promises";
|
|
20229
|
-
import * as
|
|
20530
|
+
import * as path42 from "path";
|
|
20230
20531
|
|
|
20231
20532
|
// src/memory/schema.ts
|
|
20232
20533
|
import { createHash as createHash5 } from "crypto";
|
|
@@ -21087,7 +21388,7 @@ class LocalJsonlMemoryProvider {
|
|
|
21087
21388
|
pathFor(file) {
|
|
21088
21389
|
const storageDir = this.config.storageDir.replace(/^\.swarm[/\\]?/, "");
|
|
21089
21390
|
const filename = file === "memories" ? "memories.jsonl" : file === "proposals" ? "proposals.jsonl" : "audit.jsonl";
|
|
21090
|
-
return validateSwarmPath(this.rootDirectory,
|
|
21391
|
+
return validateSwarmPath(this.rootDirectory, path42.join(storageDir, filename));
|
|
21091
21392
|
}
|
|
21092
21393
|
async initialize() {
|
|
21093
21394
|
if (this.initialized)
|
|
@@ -21414,7 +21715,7 @@ function validateLoadedProposals(values, config) {
|
|
|
21414
21715
|
return { records, invalidCount };
|
|
21415
21716
|
}
|
|
21416
21717
|
async function readJsonl(filePath) {
|
|
21417
|
-
if (!
|
|
21718
|
+
if (!existsSync25(filePath))
|
|
21418
21719
|
return [];
|
|
21419
21720
|
const content = await readFile12(filePath, "utf-8");
|
|
21420
21721
|
const records = [];
|
|
@@ -21470,12 +21771,12 @@ function parseRecallUsageEvent(event) {
|
|
|
21470
21771
|
}
|
|
21471
21772
|
}
|
|
21472
21773
|
async function appendJsonl(filePath, value) {
|
|
21473
|
-
await mkdir10(
|
|
21774
|
+
await mkdir10(path42.dirname(filePath), { recursive: true });
|
|
21474
21775
|
await appendFile3(filePath, `${JSON.stringify(value)}
|
|
21475
21776
|
`, "utf-8");
|
|
21476
21777
|
}
|
|
21477
21778
|
async function writeJsonlAtomic(filePath, values) {
|
|
21478
|
-
await mkdir10(
|
|
21779
|
+
await mkdir10(path42.dirname(filePath), { recursive: true });
|
|
21479
21780
|
const tmp = `${filePath}.tmp.${randomUUID5()}`;
|
|
21480
21781
|
const content = values.map((value) => JSON.stringify(value)).join(`
|
|
21481
21782
|
`) + (values.length > 0 ? `
|
|
@@ -21486,18 +21787,18 @@ async function writeJsonlAtomic(filePath, values) {
|
|
|
21486
21787
|
|
|
21487
21788
|
// src/memory/provider-pool.ts
|
|
21488
21789
|
import { realpathSync as realpathSync2 } from "fs";
|
|
21489
|
-
import * as
|
|
21790
|
+
import * as path45 from "path";
|
|
21490
21791
|
|
|
21491
21792
|
// src/memory/sqlite-provider.ts
|
|
21492
21793
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
21493
21794
|
import { mkdirSync as mkdirSync15 } from "fs";
|
|
21494
21795
|
import { createRequire as createRequire2 } from "module";
|
|
21495
|
-
import * as
|
|
21796
|
+
import * as path44 from "path";
|
|
21496
21797
|
|
|
21497
21798
|
// src/memory/jsonl-migration.ts
|
|
21498
|
-
import { existsSync as
|
|
21799
|
+
import { existsSync as existsSync26, renameSync as renameSync10, unlinkSync as unlinkSync7 } from "fs";
|
|
21499
21800
|
import { copyFile as copyFile2, mkdir as mkdir11, readFile as readFile13, stat as stat5, writeFile as writeFile11 } from "fs/promises";
|
|
21500
|
-
import * as
|
|
21801
|
+
import * as path43 from "path";
|
|
21501
21802
|
var LEGACY_JSONL_MIGRATION_VERSION = 2;
|
|
21502
21803
|
var LEGACY_JSONL_MIGRATION_NAME = "legacy_jsonl_import_complete";
|
|
21503
21804
|
function resolveMemoryStorageDir(rootDirectory, config = {}) {
|
|
@@ -21513,8 +21814,8 @@ function resolveSqliteDatabasePath(rootDirectory, config = {}) {
|
|
|
21513
21814
|
async function readLegacyJsonl(rootDirectory, config = {}) {
|
|
21514
21815
|
const resolved = resolveConfig(config);
|
|
21515
21816
|
const storageDir = resolveMemoryStorageDir(rootDirectory, resolved);
|
|
21516
|
-
const memoryLoad = await readMemoryJsonl(
|
|
21517
|
-
const proposalLoad = await readProposalJsonl(
|
|
21817
|
+
const memoryLoad = await readMemoryJsonl(path43.join(storageDir, "memories.jsonl"), resolved);
|
|
21818
|
+
const proposalLoad = await readProposalJsonl(path43.join(storageDir, "proposals.jsonl"), resolved);
|
|
21518
21819
|
return {
|
|
21519
21820
|
memories: memoryLoad.records,
|
|
21520
21821
|
proposals: proposalLoad.records,
|
|
@@ -21524,15 +21825,15 @@ async function readLegacyJsonl(rootDirectory, config = {}) {
|
|
|
21524
21825
|
}
|
|
21525
21826
|
async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
21526
21827
|
const storageDir = resolveMemoryStorageDir(rootDirectory, config);
|
|
21527
|
-
const backupDir =
|
|
21828
|
+
const backupDir = path43.join(storageDir, "backups");
|
|
21528
21829
|
await mkdir11(backupDir, { recursive: true });
|
|
21529
21830
|
const results = [];
|
|
21530
21831
|
for (const filename of ["memories.jsonl", "proposals.jsonl"]) {
|
|
21531
|
-
const source =
|
|
21532
|
-
if (!
|
|
21832
|
+
const source = path43.join(storageDir, filename);
|
|
21833
|
+
if (!existsSync26(source))
|
|
21533
21834
|
continue;
|
|
21534
|
-
const backup =
|
|
21535
|
-
if (
|
|
21835
|
+
const backup = path43.join(backupDir, `${filename}.pre-sqlite-migration`);
|
|
21836
|
+
if (existsSync26(backup)) {
|
|
21536
21837
|
results.push({ source, backup, created: false });
|
|
21537
21838
|
continue;
|
|
21538
21839
|
}
|
|
@@ -21542,51 +21843,51 @@ async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
|
21542
21843
|
return results;
|
|
21543
21844
|
}
|
|
21544
21845
|
async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
21545
|
-
const exportDir =
|
|
21846
|
+
const exportDir = path43.join(resolveMemoryStorageDir(rootDirectory, config), "export");
|
|
21546
21847
|
await mkdir11(exportDir, { recursive: true });
|
|
21547
|
-
const memoriesPath =
|
|
21548
|
-
const proposalsPath =
|
|
21549
|
-
const memoriesTempPath =
|
|
21848
|
+
const memoriesPath = path43.join(exportDir, "memories.jsonl");
|
|
21849
|
+
const proposalsPath = path43.join(exportDir, "proposals.jsonl");
|
|
21850
|
+
const memoriesTempPath = path43.join(path43.dirname(memoriesPath), `${path43.basename(memoriesPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
21550
21851
|
try {
|
|
21551
21852
|
await writeFile11(memoriesTempPath, toJsonl(memories), "utf-8");
|
|
21552
21853
|
renameSync10(memoriesTempPath, memoriesPath);
|
|
21553
21854
|
} catch (err) {
|
|
21554
21855
|
try {
|
|
21555
|
-
|
|
21856
|
+
unlinkSync7(memoriesTempPath);
|
|
21556
21857
|
} catch {}
|
|
21557
21858
|
throw err;
|
|
21558
21859
|
}
|
|
21559
|
-
const proposalsTempPath =
|
|
21860
|
+
const proposalsTempPath = path43.join(path43.dirname(proposalsPath), `${path43.basename(proposalsPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
21560
21861
|
try {
|
|
21561
21862
|
await writeFile11(proposalsTempPath, toJsonl(proposals), "utf-8");
|
|
21562
21863
|
renameSync10(proposalsTempPath, proposalsPath);
|
|
21563
21864
|
} catch (err) {
|
|
21564
21865
|
try {
|
|
21565
|
-
|
|
21866
|
+
unlinkSync7(proposalsTempPath);
|
|
21566
21867
|
} catch {}
|
|
21567
21868
|
throw err;
|
|
21568
21869
|
}
|
|
21569
21870
|
return { directory: exportDir, memoriesPath, proposalsPath };
|
|
21570
21871
|
}
|
|
21571
21872
|
async function writeMigrationReport(rootDirectory, report, config = {}) {
|
|
21572
|
-
const reportPath =
|
|
21573
|
-
await mkdir11(
|
|
21574
|
-
const reportTempPath =
|
|
21873
|
+
const reportPath = path43.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
21874
|
+
await mkdir11(path43.dirname(reportPath), { recursive: true });
|
|
21875
|
+
const reportTempPath = path43.join(path43.dirname(reportPath), `${path43.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
21575
21876
|
try {
|
|
21576
21877
|
await writeFile11(reportTempPath, `${JSON.stringify(report, null, 2)}
|
|
21577
21878
|
`, "utf-8");
|
|
21578
21879
|
renameSync10(reportTempPath, reportPath);
|
|
21579
21880
|
} catch (err) {
|
|
21580
21881
|
try {
|
|
21581
|
-
|
|
21882
|
+
unlinkSync7(reportTempPath);
|
|
21582
21883
|
} catch {}
|
|
21583
21884
|
throw err;
|
|
21584
21885
|
}
|
|
21585
21886
|
return reportPath;
|
|
21586
21887
|
}
|
|
21587
21888
|
async function readMigrationReport(rootDirectory, config = {}) {
|
|
21588
|
-
const reportPath =
|
|
21589
|
-
if (!
|
|
21889
|
+
const reportPath = path43.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
21890
|
+
if (!existsSync26(reportPath))
|
|
21590
21891
|
return null;
|
|
21591
21892
|
try {
|
|
21592
21893
|
return JSON.parse(await readFile13(reportPath, "utf-8"));
|
|
@@ -21598,15 +21899,15 @@ async function getLegacyJsonlFileStatus(rootDirectory, config = {}) {
|
|
|
21598
21899
|
const storageDir = resolveMemoryStorageDir(rootDirectory, config);
|
|
21599
21900
|
const statuses = [];
|
|
21600
21901
|
for (const file of ["memories.jsonl", "proposals.jsonl"]) {
|
|
21601
|
-
const filePath =
|
|
21902
|
+
const filePath = path43.join(storageDir, file);
|
|
21602
21903
|
let sizeBytes = 0;
|
|
21603
|
-
if (
|
|
21904
|
+
if (existsSync26(filePath)) {
|
|
21604
21905
|
sizeBytes = (await stat5(filePath)).size;
|
|
21605
21906
|
}
|
|
21606
21907
|
statuses.push({
|
|
21607
21908
|
file,
|
|
21608
21909
|
path: filePath,
|
|
21609
|
-
exists:
|
|
21910
|
+
exists: existsSync26(filePath),
|
|
21610
21911
|
sizeBytes
|
|
21611
21912
|
});
|
|
21612
21913
|
}
|
|
@@ -21687,7 +21988,7 @@ async function readProposalJsonl(filePath, config) {
|
|
|
21687
21988
|
return { records, invalidRows, totalRows: rows.totalRows };
|
|
21688
21989
|
}
|
|
21689
21990
|
async function readJsonlRows(filePath) {
|
|
21690
|
-
if (!
|
|
21991
|
+
if (!existsSync26(filePath)) {
|
|
21691
21992
|
return { rows: [], invalidRows: [], totalRows: 0 };
|
|
21692
21993
|
}
|
|
21693
21994
|
const content = await readFile13(filePath, "utf-8");
|
|
@@ -21906,7 +22207,7 @@ class SQLiteMemoryProvider {
|
|
|
21906
22207
|
}
|
|
21907
22208
|
async doInitialize() {
|
|
21908
22209
|
const dbPath = this.databasePath();
|
|
21909
|
-
mkdirSync15(
|
|
22210
|
+
mkdirSync15(path44.dirname(dbPath), { recursive: true });
|
|
21910
22211
|
const Db = loadDatabaseCtor2();
|
|
21911
22212
|
this.db = new Db(dbPath);
|
|
21912
22213
|
this.db.run("PRAGMA journal_mode = WAL;");
|
|
@@ -22935,7 +23236,7 @@ function resolvePoolKey(directory) {
|
|
|
22935
23236
|
try {
|
|
22936
23237
|
return realpathSync2(directory);
|
|
22937
23238
|
} catch {
|
|
22938
|
-
return
|
|
23239
|
+
return path45.resolve(directory);
|
|
22939
23240
|
}
|
|
22940
23241
|
}
|
|
22941
23242
|
|
|
@@ -23007,7 +23308,7 @@ var DEFAULT_MODES = [
|
|
|
23007
23308
|
];
|
|
23008
23309
|
var DEFAULT_TIMESTAMP = "2026-05-26T12:00:00.000Z";
|
|
23009
23310
|
async function evaluateMemoryRecallFixtures(options) {
|
|
23010
|
-
const fixtureDirectory =
|
|
23311
|
+
const fixtureDirectory = path46.resolve(options.fixtureDirectory);
|
|
23011
23312
|
const providers = options.providers ?? DEFAULT_PROVIDERS;
|
|
23012
23313
|
const modes = options.modes ?? DEFAULT_MODES;
|
|
23013
23314
|
const generatedAt = new Date().toISOString();
|
|
@@ -23016,7 +23317,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
23016
23317
|
for (const fixture of fixtures) {
|
|
23017
23318
|
const materialized = materializeFixture(fixture);
|
|
23018
23319
|
for (const providerName of providers) {
|
|
23019
|
-
const tempRoot = await
|
|
23320
|
+
const tempRoot = await fs19.realpath(await fs19.mkdtemp(path46.join(os10.tmpdir(), "swarm-memory-eval-")));
|
|
23020
23321
|
const provider = createEvaluationProvider(providerName, tempRoot);
|
|
23021
23322
|
try {
|
|
23022
23323
|
await provider.initialize?.();
|
|
@@ -23040,7 +23341,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
23040
23341
|
} finally {
|
|
23041
23342
|
await provider.close?.();
|
|
23042
23343
|
if (!options.keepTempRoots) {
|
|
23043
|
-
await
|
|
23344
|
+
await fs19.rm(tempRoot, { recursive: true, force: true });
|
|
23044
23345
|
}
|
|
23045
23346
|
}
|
|
23046
23347
|
}
|
|
@@ -23056,11 +23357,11 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
23056
23357
|
};
|
|
23057
23358
|
}
|
|
23058
23359
|
async function loadRecallEvaluationFixtures(fixtureDirectory) {
|
|
23059
|
-
const entries = await
|
|
23360
|
+
const entries = await fs19.readdir(fixtureDirectory, { withFileTypes: true });
|
|
23060
23361
|
const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
23061
23362
|
const fixtures = [];
|
|
23062
23363
|
for (const file of files) {
|
|
23063
|
-
const raw = await
|
|
23364
|
+
const raw = await fs19.readFile(path46.join(fixtureDirectory, file), "utf-8");
|
|
23064
23365
|
fixtures.push(validateFixture(JSON.parse(raw), file));
|
|
23065
23366
|
}
|
|
23066
23367
|
return fixtures;
|
|
@@ -23337,8 +23638,8 @@ var CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
|
23337
23638
|
}).passthrough();
|
|
23338
23639
|
// src/memory/consolidation-log.ts
|
|
23339
23640
|
import { appendFile as appendFile4, mkdir as mkdir12, readFile as readFile15 } from "fs/promises";
|
|
23340
|
-
import * as
|
|
23341
|
-
var LOG_RELATIVE_PATH =
|
|
23641
|
+
import * as path47 from "path";
|
|
23642
|
+
var LOG_RELATIVE_PATH = path47.join("memory", "consolidation-log.jsonl");
|
|
23342
23643
|
async function readConsolidationLog(directory) {
|
|
23343
23644
|
const filePath = validateSwarmPath(directory, LOG_RELATIVE_PATH);
|
|
23344
23645
|
let raw;
|
|
@@ -23361,7 +23662,7 @@ async function readConsolidationLog(directory) {
|
|
|
23361
23662
|
}
|
|
23362
23663
|
|
|
23363
23664
|
// src/commands/memory.ts
|
|
23364
|
-
var PACKAGE_ROOT =
|
|
23665
|
+
var PACKAGE_ROOT = path48.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
|
|
23365
23666
|
async function handleMemoryCommand(_directory, _args) {
|
|
23366
23667
|
return [
|
|
23367
23668
|
"## Swarm Memory",
|
|
@@ -23419,7 +23720,7 @@ async function handleMemoryStatusCommand(directory, _args) {
|
|
|
23419
23720
|
`- Provider: \`${config.provider}\``,
|
|
23420
23721
|
`- Storage: \`${storageDir}\``,
|
|
23421
23722
|
`- SQLite path: \`${sqlitePath}\``,
|
|
23422
|
-
`- SQLite database exists: \`${
|
|
23723
|
+
`- SQLite database exists: \`${existsSync27(sqlitePath)}\``,
|
|
23423
23724
|
`- Automatic destructive cleanup: \`disabled\``,
|
|
23424
23725
|
"",
|
|
23425
23726
|
"### Legacy JSONL"
|
|
@@ -23659,7 +23960,7 @@ function resolveCommandMemoryConfig(directory) {
|
|
|
23659
23960
|
}
|
|
23660
23961
|
function parseEvaluateArgs(directory, args) {
|
|
23661
23962
|
let json = false;
|
|
23662
|
-
let fixtureDirectory =
|
|
23963
|
+
let fixtureDirectory = path48.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
|
|
23663
23964
|
for (let i = 0;i < args.length; i++) {
|
|
23664
23965
|
const arg = args[i];
|
|
23665
23966
|
if (arg === "--json") {
|
|
@@ -23673,10 +23974,10 @@ function parseEvaluateArgs(directory, args) {
|
|
|
23673
23974
|
error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
|
|
23674
23975
|
};
|
|
23675
23976
|
}
|
|
23676
|
-
const resolvedFixtures =
|
|
23677
|
-
const canonical =
|
|
23678
|
-
const allowedRootA =
|
|
23679
|
-
const allowedRootB =
|
|
23977
|
+
const resolvedFixtures = path48.resolve(directory, next);
|
|
23978
|
+
const canonical = path48.normalize(resolvedFixtures) + path48.sep;
|
|
23979
|
+
const allowedRootA = path48.normalize(directory) + path48.sep;
|
|
23980
|
+
const allowedRootB = path48.normalize(path48.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path48.sep;
|
|
23680
23981
|
if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
|
|
23681
23982
|
return {
|
|
23682
23983
|
error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
|
|
@@ -23715,15 +24016,15 @@ function parseMaintenanceArgs(args, options) {
|
|
|
23715
24016
|
return { limit, confirm };
|
|
23716
24017
|
}
|
|
23717
24018
|
function resolvePackageRootFromModule(modulePath) {
|
|
23718
|
-
const moduleDir =
|
|
23719
|
-
const leaf =
|
|
24019
|
+
const moduleDir = path48.dirname(modulePath);
|
|
24020
|
+
const leaf = path48.basename(moduleDir);
|
|
23720
24021
|
if (leaf === "commands" || leaf === "cli") {
|
|
23721
|
-
return
|
|
24022
|
+
return path48.resolve(moduleDir, "..", "..");
|
|
23722
24023
|
}
|
|
23723
24024
|
if (leaf === "dist") {
|
|
23724
|
-
return
|
|
24025
|
+
return path48.resolve(moduleDir, "..");
|
|
23725
24026
|
}
|
|
23726
|
-
return
|
|
24027
|
+
return path48.resolve(moduleDir, "..");
|
|
23727
24028
|
}
|
|
23728
24029
|
function formatMigrationResult(label, report) {
|
|
23729
24030
|
if (!report) {
|
|
@@ -24417,12 +24718,12 @@ var _internals36 = {
|
|
|
24417
24718
|
};
|
|
24418
24719
|
|
|
24419
24720
|
// src/services/preflight-service.ts
|
|
24420
|
-
import * as
|
|
24421
|
-
import * as
|
|
24721
|
+
import * as fs26 from "fs";
|
|
24722
|
+
import * as path55 from "path";
|
|
24422
24723
|
|
|
24423
24724
|
// src/tools/lint.ts
|
|
24424
|
-
import * as
|
|
24425
|
-
import * as
|
|
24725
|
+
import * as fs20 from "fs";
|
|
24726
|
+
import * as path49 from "path";
|
|
24426
24727
|
|
|
24427
24728
|
// src/utils/path-security.ts
|
|
24428
24729
|
function containsPathTraversal(str) {
|
|
@@ -24478,9 +24779,9 @@ function validateArgs(args) {
|
|
|
24478
24779
|
}
|
|
24479
24780
|
function getLinterCommand(linter, mode, projectDir) {
|
|
24480
24781
|
const isWindows = process.platform === "win32";
|
|
24481
|
-
const binDir =
|
|
24482
|
-
const biomeBin = isWindows ?
|
|
24483
|
-
const eslintBin = isWindows ?
|
|
24782
|
+
const binDir = path49.join(projectDir, "node_modules", ".bin");
|
|
24783
|
+
const biomeBin = isWindows ? path49.join(binDir, "biome.EXE") : path49.join(binDir, "biome");
|
|
24784
|
+
const eslintBin = isWindows ? path49.join(binDir, "eslint.cmd") : path49.join(binDir, "eslint");
|
|
24484
24785
|
switch (linter) {
|
|
24485
24786
|
case "biome":
|
|
24486
24787
|
if (mode === "fix") {
|
|
@@ -24496,7 +24797,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
24496
24797
|
}
|
|
24497
24798
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
24498
24799
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
24499
|
-
const gradlew =
|
|
24800
|
+
const gradlew = fs20.existsSync(path49.join(cwd, gradlewName)) ? path49.join(cwd, gradlewName) : null;
|
|
24500
24801
|
switch (linter) {
|
|
24501
24802
|
case "ruff":
|
|
24502
24803
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -24530,12 +24831,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
24530
24831
|
}
|
|
24531
24832
|
}
|
|
24532
24833
|
function detectRuff(cwd) {
|
|
24533
|
-
if (
|
|
24834
|
+
if (fs20.existsSync(path49.join(cwd, "ruff.toml")))
|
|
24534
24835
|
return isCommandAvailable("ruff");
|
|
24535
24836
|
try {
|
|
24536
|
-
const pyproject =
|
|
24537
|
-
if (
|
|
24538
|
-
const content =
|
|
24837
|
+
const pyproject = path49.join(cwd, "pyproject.toml");
|
|
24838
|
+
if (fs20.existsSync(pyproject)) {
|
|
24839
|
+
const content = fs20.readFileSync(pyproject, "utf-8");
|
|
24539
24840
|
if (content.includes("[tool.ruff]"))
|
|
24540
24841
|
return isCommandAvailable("ruff");
|
|
24541
24842
|
}
|
|
@@ -24543,21 +24844,21 @@ function detectRuff(cwd) {
|
|
|
24543
24844
|
return false;
|
|
24544
24845
|
}
|
|
24545
24846
|
function detectClippy(cwd) {
|
|
24546
|
-
return
|
|
24847
|
+
return fs20.existsSync(path49.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
24547
24848
|
}
|
|
24548
24849
|
function detectGolangciLint(cwd) {
|
|
24549
|
-
return
|
|
24850
|
+
return fs20.existsSync(path49.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
24550
24851
|
}
|
|
24551
24852
|
function detectCheckstyle(cwd) {
|
|
24552
|
-
const hasMaven =
|
|
24553
|
-
const hasGradle =
|
|
24554
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (
|
|
24853
|
+
const hasMaven = fs20.existsSync(path49.join(cwd, "pom.xml"));
|
|
24854
|
+
const hasGradle = fs20.existsSync(path49.join(cwd, "build.gradle")) || fs20.existsSync(path49.join(cwd, "build.gradle.kts"));
|
|
24855
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs20.existsSync(path49.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
24555
24856
|
return (hasMaven || hasGradle) && hasBinary;
|
|
24556
24857
|
}
|
|
24557
24858
|
function detectKtlint(cwd) {
|
|
24558
|
-
const hasKotlin =
|
|
24859
|
+
const hasKotlin = fs20.existsSync(path49.join(cwd, "build.gradle.kts")) || fs20.existsSync(path49.join(cwd, "build.gradle")) || (() => {
|
|
24559
24860
|
try {
|
|
24560
|
-
return
|
|
24861
|
+
return fs20.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
24561
24862
|
} catch {
|
|
24562
24863
|
return false;
|
|
24563
24864
|
}
|
|
@@ -24566,7 +24867,7 @@ function detectKtlint(cwd) {
|
|
|
24566
24867
|
}
|
|
24567
24868
|
function detectDotnetFormat(cwd) {
|
|
24568
24869
|
try {
|
|
24569
|
-
const files =
|
|
24870
|
+
const files = fs20.readdirSync(cwd);
|
|
24570
24871
|
const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
|
|
24571
24872
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
24572
24873
|
} catch {
|
|
@@ -24574,14 +24875,14 @@ function detectDotnetFormat(cwd) {
|
|
|
24574
24875
|
}
|
|
24575
24876
|
}
|
|
24576
24877
|
function detectCppcheck(cwd) {
|
|
24577
|
-
if (
|
|
24878
|
+
if (fs20.existsSync(path49.join(cwd, "CMakeLists.txt"))) {
|
|
24578
24879
|
return isCommandAvailable("cppcheck");
|
|
24579
24880
|
}
|
|
24580
24881
|
try {
|
|
24581
|
-
const dirsToCheck = [cwd,
|
|
24882
|
+
const dirsToCheck = [cwd, path49.join(cwd, "src")];
|
|
24582
24883
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
24583
24884
|
try {
|
|
24584
|
-
return
|
|
24885
|
+
return fs20.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
24585
24886
|
} catch {
|
|
24586
24887
|
return false;
|
|
24587
24888
|
}
|
|
@@ -24592,13 +24893,13 @@ function detectCppcheck(cwd) {
|
|
|
24592
24893
|
}
|
|
24593
24894
|
}
|
|
24594
24895
|
function detectSwiftlint(cwd) {
|
|
24595
|
-
return
|
|
24896
|
+
return fs20.existsSync(path49.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
24596
24897
|
}
|
|
24597
24898
|
function detectDartAnalyze(cwd) {
|
|
24598
|
-
return
|
|
24899
|
+
return fs20.existsSync(path49.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
24599
24900
|
}
|
|
24600
24901
|
function detectRubocop(cwd) {
|
|
24601
|
-
return (
|
|
24902
|
+
return (fs20.existsSync(path49.join(cwd, "Gemfile")) || fs20.existsSync(path49.join(cwd, "gems.rb")) || fs20.existsSync(path49.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
24602
24903
|
}
|
|
24603
24904
|
function detectAdditionalLinter(cwd) {
|
|
24604
24905
|
if (detectRuff(cwd))
|
|
@@ -24626,10 +24927,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
24626
24927
|
function findBinInAncestors(startDir, binName) {
|
|
24627
24928
|
let dir = startDir;
|
|
24628
24929
|
while (true) {
|
|
24629
|
-
const candidate =
|
|
24630
|
-
if (
|
|
24930
|
+
const candidate = path49.join(dir, "node_modules", ".bin", binName);
|
|
24931
|
+
if (fs20.existsSync(candidate))
|
|
24631
24932
|
return candidate;
|
|
24632
|
-
const parent =
|
|
24933
|
+
const parent = path49.dirname(dir);
|
|
24633
24934
|
if (parent === dir)
|
|
24634
24935
|
break;
|
|
24635
24936
|
dir = parent;
|
|
@@ -24638,11 +24939,11 @@ function findBinInAncestors(startDir, binName) {
|
|
|
24638
24939
|
}
|
|
24639
24940
|
function findBinInEnvPath(binName) {
|
|
24640
24941
|
const searchPath = process.env.PATH ?? "";
|
|
24641
|
-
for (const dir of searchPath.split(
|
|
24942
|
+
for (const dir of searchPath.split(path49.delimiter)) {
|
|
24642
24943
|
if (!dir)
|
|
24643
24944
|
continue;
|
|
24644
|
-
const candidate =
|
|
24645
|
-
if (
|
|
24945
|
+
const candidate = path49.join(dir, binName);
|
|
24946
|
+
if (fs20.existsSync(candidate))
|
|
24646
24947
|
return candidate;
|
|
24647
24948
|
}
|
|
24648
24949
|
return null;
|
|
@@ -24650,17 +24951,17 @@ function findBinInEnvPath(binName) {
|
|
|
24650
24951
|
async function detectAvailableLinter(directory) {
|
|
24651
24952
|
if (!directory)
|
|
24652
24953
|
return null;
|
|
24653
|
-
if (!
|
|
24954
|
+
if (!fs20.existsSync(directory))
|
|
24654
24955
|
return null;
|
|
24655
24956
|
const projectDir = directory;
|
|
24656
24957
|
const isWindows = process.platform === "win32";
|
|
24657
|
-
const biomeBin = isWindows ?
|
|
24658
|
-
const eslintBin = isWindows ?
|
|
24958
|
+
const biomeBin = isWindows ? path49.join(projectDir, "node_modules", ".bin", "biome.EXE") : path49.join(projectDir, "node_modules", ".bin", "biome");
|
|
24959
|
+
const eslintBin = isWindows ? path49.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path49.join(projectDir, "node_modules", ".bin", "eslint");
|
|
24659
24960
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
24660
24961
|
if (localResult)
|
|
24661
24962
|
return localResult;
|
|
24662
|
-
const biomeAncestor = findBinInAncestors(
|
|
24663
|
-
const eslintAncestor = findBinInAncestors(
|
|
24963
|
+
const biomeAncestor = findBinInAncestors(path49.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
24964
|
+
const eslintAncestor = findBinInAncestors(path49.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
24664
24965
|
if (biomeAncestor || eslintAncestor) {
|
|
24665
24966
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
24666
24967
|
}
|
|
@@ -24683,7 +24984,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
24683
24984
|
const result = await Promise.race([biomeExit, timeout]);
|
|
24684
24985
|
if (result === "timeout") {
|
|
24685
24986
|
biomeProc.kill();
|
|
24686
|
-
} else if (biomeProc.exitCode === 0 &&
|
|
24987
|
+
} else if (biomeProc.exitCode === 0 && fs20.existsSync(biomeBin)) {
|
|
24687
24988
|
return "biome";
|
|
24688
24989
|
}
|
|
24689
24990
|
} catch {}
|
|
@@ -24697,7 +24998,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
24697
24998
|
const result = await Promise.race([eslintExit, timeout]);
|
|
24698
24999
|
if (result === "timeout") {
|
|
24699
25000
|
eslintProc.kill();
|
|
24700
|
-
} else if (eslintProc.exitCode === 0 &&
|
|
25001
|
+
} else if (eslintProc.exitCode === 0 && fs20.existsSync(eslintBin)) {
|
|
24701
25002
|
return "eslint";
|
|
24702
25003
|
}
|
|
24703
25004
|
} catch {}
|
|
@@ -24873,8 +25174,8 @@ var _internals37 = {
|
|
|
24873
25174
|
};
|
|
24874
25175
|
|
|
24875
25176
|
// src/tools/secretscan.ts
|
|
24876
|
-
import * as
|
|
24877
|
-
import * as
|
|
25177
|
+
import * as fs21 from "fs";
|
|
25178
|
+
import * as path50 from "path";
|
|
24878
25179
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
24879
25180
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
24880
25181
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -25101,11 +25402,11 @@ function isGlobOrPathPattern(pattern) {
|
|
|
25101
25402
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
25102
25403
|
}
|
|
25103
25404
|
function loadSecretScanIgnore(scanDir) {
|
|
25104
|
-
const ignorePath =
|
|
25405
|
+
const ignorePath = path50.join(scanDir, ".secretscanignore");
|
|
25105
25406
|
try {
|
|
25106
|
-
if (!
|
|
25407
|
+
if (!fs21.existsSync(ignorePath))
|
|
25107
25408
|
return [];
|
|
25108
|
-
const content =
|
|
25409
|
+
const content = fs21.readFileSync(ignorePath, "utf8");
|
|
25109
25410
|
const patterns = [];
|
|
25110
25411
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
25111
25412
|
const line = rawLine.trim();
|
|
@@ -25124,7 +25425,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
25124
25425
|
if (exactNames.has(entry))
|
|
25125
25426
|
return true;
|
|
25126
25427
|
for (const pattern of globPatterns) {
|
|
25127
|
-
if (
|
|
25428
|
+
if (path50.matchesGlob(relPath, pattern))
|
|
25128
25429
|
return true;
|
|
25129
25430
|
}
|
|
25130
25431
|
return false;
|
|
@@ -25145,7 +25446,7 @@ function validateDirectoryInput(dir) {
|
|
|
25145
25446
|
return null;
|
|
25146
25447
|
}
|
|
25147
25448
|
function isBinaryFile(filePath, buffer) {
|
|
25148
|
-
const ext =
|
|
25449
|
+
const ext = path50.extname(filePath).toLowerCase();
|
|
25149
25450
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
25150
25451
|
return true;
|
|
25151
25452
|
}
|
|
@@ -25220,11 +25521,11 @@ function createRedactedContext(line, findings) {
|
|
|
25220
25521
|
result += line.slice(lastEnd);
|
|
25221
25522
|
return result;
|
|
25222
25523
|
}
|
|
25223
|
-
var O_NOFOLLOW = process.platform !== "win32" ?
|
|
25524
|
+
var O_NOFOLLOW = process.platform !== "win32" ? fs21.constants.O_NOFOLLOW : undefined;
|
|
25224
25525
|
function scanFileForSecrets(filePath) {
|
|
25225
25526
|
const findings = [];
|
|
25226
25527
|
try {
|
|
25227
|
-
const lstat2 =
|
|
25528
|
+
const lstat2 = fs21.lstatSync(filePath);
|
|
25228
25529
|
if (lstat2.isSymbolicLink()) {
|
|
25229
25530
|
return findings;
|
|
25230
25531
|
}
|
|
@@ -25233,14 +25534,14 @@ function scanFileForSecrets(filePath) {
|
|
|
25233
25534
|
}
|
|
25234
25535
|
let buffer;
|
|
25235
25536
|
if (O_NOFOLLOW !== undefined) {
|
|
25236
|
-
const fd =
|
|
25537
|
+
const fd = fs21.openSync(filePath, "r", O_NOFOLLOW);
|
|
25237
25538
|
try {
|
|
25238
|
-
buffer =
|
|
25539
|
+
buffer = fs21.readFileSync(fd);
|
|
25239
25540
|
} finally {
|
|
25240
|
-
|
|
25541
|
+
fs21.closeSync(fd);
|
|
25241
25542
|
}
|
|
25242
25543
|
} else {
|
|
25243
|
-
buffer =
|
|
25544
|
+
buffer = fs21.readFileSync(filePath);
|
|
25244
25545
|
}
|
|
25245
25546
|
if (isBinaryFile(filePath, buffer)) {
|
|
25246
25547
|
return findings;
|
|
@@ -25282,9 +25583,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
25282
25583
|
return false;
|
|
25283
25584
|
}
|
|
25284
25585
|
function isPathWithinScope(realPath, scanDir) {
|
|
25285
|
-
const resolvedScanDir =
|
|
25286
|
-
const resolvedRealPath =
|
|
25287
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
25586
|
+
const resolvedScanDir = path50.resolve(scanDir);
|
|
25587
|
+
const resolvedRealPath = path50.resolve(realPath);
|
|
25588
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path50.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
25288
25589
|
}
|
|
25289
25590
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
25290
25591
|
skippedDirs: 0,
|
|
@@ -25295,7 +25596,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
25295
25596
|
const files = [];
|
|
25296
25597
|
let entries;
|
|
25297
25598
|
try {
|
|
25298
|
-
entries =
|
|
25599
|
+
entries = fs21.readdirSync(dir);
|
|
25299
25600
|
} catch {
|
|
25300
25601
|
stats.fileErrors++;
|
|
25301
25602
|
return files;
|
|
@@ -25310,15 +25611,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
25310
25611
|
return a.localeCompare(b);
|
|
25311
25612
|
});
|
|
25312
25613
|
for (const entry of entries) {
|
|
25313
|
-
const fullPath =
|
|
25314
|
-
const relPath =
|
|
25614
|
+
const fullPath = path50.join(dir, entry);
|
|
25615
|
+
const relPath = path50.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
25315
25616
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
25316
25617
|
stats.skippedDirs++;
|
|
25317
25618
|
continue;
|
|
25318
25619
|
}
|
|
25319
25620
|
let lstat2;
|
|
25320
25621
|
try {
|
|
25321
|
-
lstat2 =
|
|
25622
|
+
lstat2 = fs21.lstatSync(fullPath);
|
|
25322
25623
|
} catch {
|
|
25323
25624
|
stats.fileErrors++;
|
|
25324
25625
|
continue;
|
|
@@ -25330,7 +25631,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
25330
25631
|
if (lstat2.isDirectory()) {
|
|
25331
25632
|
let realPath;
|
|
25332
25633
|
try {
|
|
25333
|
-
realPath =
|
|
25634
|
+
realPath = fs21.realpathSync(fullPath);
|
|
25334
25635
|
} catch {
|
|
25335
25636
|
stats.fileErrors++;
|
|
25336
25637
|
continue;
|
|
@@ -25346,7 +25647,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
25346
25647
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
25347
25648
|
files.push(...subFiles);
|
|
25348
25649
|
} else if (lstat2.isFile()) {
|
|
25349
|
-
const ext =
|
|
25650
|
+
const ext = path50.extname(fullPath).toLowerCase();
|
|
25350
25651
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
25351
25652
|
files.push(fullPath);
|
|
25352
25653
|
} else {
|
|
@@ -25412,15 +25713,15 @@ var secretscan = createSwarmTool({
|
|
|
25412
25713
|
}
|
|
25413
25714
|
}
|
|
25414
25715
|
try {
|
|
25415
|
-
const _scanDirRaw =
|
|
25716
|
+
const _scanDirRaw = path50.resolve(directory);
|
|
25416
25717
|
const scanDir = (() => {
|
|
25417
25718
|
try {
|
|
25418
|
-
return
|
|
25719
|
+
return fs21.realpathSync(_scanDirRaw);
|
|
25419
25720
|
} catch {
|
|
25420
25721
|
return _scanDirRaw;
|
|
25421
25722
|
}
|
|
25422
25723
|
})();
|
|
25423
|
-
if (!
|
|
25724
|
+
if (!fs21.existsSync(scanDir)) {
|
|
25424
25725
|
const errorResult = {
|
|
25425
25726
|
error: "directory not found",
|
|
25426
25727
|
scan_dir: directory,
|
|
@@ -25431,7 +25732,7 @@ var secretscan = createSwarmTool({
|
|
|
25431
25732
|
};
|
|
25432
25733
|
return JSON.stringify(errorResult, null, 2);
|
|
25433
25734
|
}
|
|
25434
|
-
const dirStat =
|
|
25735
|
+
const dirStat = fs21.statSync(scanDir);
|
|
25435
25736
|
if (!dirStat.isDirectory()) {
|
|
25436
25737
|
const errorResult = {
|
|
25437
25738
|
error: "target must be a directory, not a file",
|
|
@@ -25482,7 +25783,7 @@ var secretscan = createSwarmTool({
|
|
|
25482
25783
|
break;
|
|
25483
25784
|
const fileFindings = scanFileForSecrets(filePath);
|
|
25484
25785
|
try {
|
|
25485
|
-
const stat6 =
|
|
25786
|
+
const stat6 = fs21.statSync(filePath);
|
|
25486
25787
|
if (stat6.size > MAX_FILE_SIZE_BYTES) {
|
|
25487
25788
|
skippedFiles++;
|
|
25488
25789
|
continue;
|
|
@@ -25574,12 +25875,12 @@ var _internals38 = {
|
|
|
25574
25875
|
};
|
|
25575
25876
|
|
|
25576
25877
|
// src/tools/test-runner.ts
|
|
25577
|
-
import * as
|
|
25578
|
-
import * as
|
|
25878
|
+
import * as fs25 from "fs";
|
|
25879
|
+
import * as path54 from "path";
|
|
25579
25880
|
|
|
25580
25881
|
// src/test-impact/analyzer.ts
|
|
25581
|
-
import
|
|
25582
|
-
import
|
|
25882
|
+
import fs22 from "fs";
|
|
25883
|
+
import path51 from "path";
|
|
25583
25884
|
var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
25584
25885
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
25585
25886
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -25606,7 +25907,7 @@ function sharedTrailingSegments(a, b) {
|
|
|
25606
25907
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
25607
25908
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
25608
25909
|
try {
|
|
25609
|
-
const stat6 =
|
|
25910
|
+
const stat6 = fs22.statSync(sourcePath);
|
|
25610
25911
|
if (stat6.mtimeMs > generatedAtMs) {
|
|
25611
25912
|
return true;
|
|
25612
25913
|
}
|
|
@@ -25620,15 +25921,15 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
25620
25921
|
if (!importPath.startsWith(".")) {
|
|
25621
25922
|
return null;
|
|
25622
25923
|
}
|
|
25623
|
-
const resolved =
|
|
25624
|
-
if (
|
|
25625
|
-
if (
|
|
25924
|
+
const resolved = path51.resolve(fromDir, importPath);
|
|
25925
|
+
if (path51.extname(resolved)) {
|
|
25926
|
+
if (fs22.existsSync(resolved) && fs22.statSync(resolved).isFile()) {
|
|
25626
25927
|
return normalizePath2(resolved);
|
|
25627
25928
|
}
|
|
25628
25929
|
} else {
|
|
25629
25930
|
for (const ext of EXTENSIONS_TO_TRY) {
|
|
25630
25931
|
const withExt = resolved + ext;
|
|
25631
|
-
if (
|
|
25932
|
+
if (fs22.existsSync(withExt) && fs22.statSync(withExt).isFile()) {
|
|
25632
25933
|
return normalizePath2(withExt);
|
|
25633
25934
|
}
|
|
25634
25935
|
}
|
|
@@ -25641,30 +25942,30 @@ function resolvePythonImport(fromDir, module) {
|
|
|
25641
25942
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
25642
25943
|
let baseDir = fromDir;
|
|
25643
25944
|
for (let i = 1;i < leadingDots; i++) {
|
|
25644
|
-
baseDir =
|
|
25945
|
+
baseDir = path51.dirname(baseDir);
|
|
25645
25946
|
}
|
|
25646
25947
|
const rest = module.slice(leadingDots);
|
|
25647
25948
|
if (rest.length === 0) {
|
|
25648
|
-
const initPath =
|
|
25649
|
-
if (
|
|
25949
|
+
const initPath = path51.join(baseDir, "__init__.py");
|
|
25950
|
+
if (fs22.existsSync(initPath) && fs22.statSync(initPath).isFile()) {
|
|
25650
25951
|
return normalizePath2(initPath);
|
|
25651
25952
|
}
|
|
25652
25953
|
return null;
|
|
25653
25954
|
}
|
|
25654
|
-
const subpath = rest.replace(/\./g,
|
|
25955
|
+
const subpath = rest.replace(/\./g, path51.sep);
|
|
25655
25956
|
const candidates = [
|
|
25656
|
-
`${
|
|
25657
|
-
|
|
25957
|
+
`${path51.join(baseDir, subpath)}.py`,
|
|
25958
|
+
path51.join(baseDir, subpath, "__init__.py")
|
|
25658
25959
|
];
|
|
25659
25960
|
for (const c of candidates) {
|
|
25660
|
-
if (
|
|
25961
|
+
if (fs22.existsSync(c) && fs22.statSync(c).isFile())
|
|
25661
25962
|
return normalizePath2(c);
|
|
25662
25963
|
}
|
|
25663
25964
|
return null;
|
|
25664
25965
|
}
|
|
25665
25966
|
var goModuleCache = new Map;
|
|
25666
25967
|
function findGoModule(fromDir) {
|
|
25667
|
-
const resolved =
|
|
25968
|
+
const resolved = path51.resolve(fromDir);
|
|
25668
25969
|
let cur = resolved;
|
|
25669
25970
|
const walked = [];
|
|
25670
25971
|
for (let i = 0;i < 16; i++) {
|
|
@@ -25676,8 +25977,8 @@ function findGoModule(fromDir) {
|
|
|
25676
25977
|
}
|
|
25677
25978
|
walked.push(cur);
|
|
25678
25979
|
try {
|
|
25679
|
-
const goMod =
|
|
25680
|
-
const content =
|
|
25980
|
+
const goMod = path51.join(cur, "go.mod");
|
|
25981
|
+
const content = fs22.readFileSync(goMod, "utf-8");
|
|
25681
25982
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
25682
25983
|
if (moduleMatch) {
|
|
25683
25984
|
const result = { moduleRoot: cur, modulePath: moduleMatch[1] };
|
|
@@ -25687,10 +25988,10 @@ function findGoModule(fromDir) {
|
|
|
25687
25988
|
}
|
|
25688
25989
|
} catch {}
|
|
25689
25990
|
try {
|
|
25690
|
-
|
|
25991
|
+
fs22.accessSync(path51.join(cur, ".git"));
|
|
25691
25992
|
break;
|
|
25692
25993
|
} catch {}
|
|
25693
|
-
const parent =
|
|
25994
|
+
const parent = path51.dirname(cur);
|
|
25694
25995
|
if (parent === cur)
|
|
25695
25996
|
break;
|
|
25696
25997
|
cur = parent;
|
|
@@ -25702,20 +26003,20 @@ function findGoModule(fromDir) {
|
|
|
25702
26003
|
function resolveGoImport(fromDir, importPath) {
|
|
25703
26004
|
let dir = null;
|
|
25704
26005
|
if (importPath.startsWith(".")) {
|
|
25705
|
-
dir =
|
|
26006
|
+
dir = path51.resolve(fromDir, importPath);
|
|
25706
26007
|
} else {
|
|
25707
26008
|
const mod = findGoModule(fromDir);
|
|
25708
26009
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
25709
26010
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
25710
|
-
dir =
|
|
26011
|
+
dir = path51.join(mod.moduleRoot, subpath);
|
|
25711
26012
|
}
|
|
25712
26013
|
}
|
|
25713
26014
|
if (dir === null)
|
|
25714
26015
|
return [];
|
|
25715
|
-
if (!
|
|
26016
|
+
if (!fs22.existsSync(dir) || !fs22.statSync(dir).isDirectory())
|
|
25716
26017
|
return [];
|
|
25717
26018
|
try {
|
|
25718
|
-
return
|
|
26019
|
+
return fs22.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path51.join(dir, f)));
|
|
25719
26020
|
} catch {
|
|
25720
26021
|
return [];
|
|
25721
26022
|
}
|
|
@@ -25735,13 +26036,13 @@ function findTestFilesSync(cwd) {
|
|
|
25735
26036
|
function walk(dir, visitedInodes) {
|
|
25736
26037
|
let entries;
|
|
25737
26038
|
try {
|
|
25738
|
-
entries =
|
|
26039
|
+
entries = fs22.readdirSync(dir, { withFileTypes: true });
|
|
25739
26040
|
} catch {
|
|
25740
26041
|
return;
|
|
25741
26042
|
}
|
|
25742
26043
|
let dirInode;
|
|
25743
26044
|
try {
|
|
25744
|
-
dirInode =
|
|
26045
|
+
dirInode = fs22.statSync(dir).ino;
|
|
25745
26046
|
} catch {
|
|
25746
26047
|
return;
|
|
25747
26048
|
}
|
|
@@ -25754,15 +26055,15 @@ function findTestFilesSync(cwd) {
|
|
|
25754
26055
|
for (const entry of entries) {
|
|
25755
26056
|
if (entry.isDirectory()) {
|
|
25756
26057
|
if (!skipDirs.has(entry.name)) {
|
|
25757
|
-
walk(
|
|
26058
|
+
walk(path51.join(dir, entry.name), visitedInodes);
|
|
25758
26059
|
}
|
|
25759
26060
|
} else if (entry.isFile()) {
|
|
25760
26061
|
const name = entry.name;
|
|
25761
26062
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
25762
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
26063
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path51.sep}tests${path51.sep}`) && name.endsWith(".py");
|
|
25763
26064
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
25764
26065
|
if (isTsTest || isPyTest || isGoTest) {
|
|
25765
|
-
testFiles.push(normalizePath2(
|
|
26066
|
+
testFiles.push(normalizePath2(path51.join(dir, entry.name)));
|
|
25766
26067
|
}
|
|
25767
26068
|
}
|
|
25768
26069
|
}
|
|
@@ -25787,8 +26088,8 @@ function extractImports(content) {
|
|
|
25787
26088
|
];
|
|
25788
26089
|
}
|
|
25789
26090
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
25790
|
-
const ext =
|
|
25791
|
-
const testDir =
|
|
26091
|
+
const ext = path51.extname(testFile).toLowerCase();
|
|
26092
|
+
const testDir = path51.dirname(testFile);
|
|
25792
26093
|
function addEdge(source) {
|
|
25793
26094
|
if (!impactMap[source])
|
|
25794
26095
|
impactMap[source] = [];
|
|
@@ -25830,7 +26131,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
25830
26131
|
for (const testFile of testFiles) {
|
|
25831
26132
|
let content;
|
|
25832
26133
|
try {
|
|
25833
|
-
content =
|
|
26134
|
+
content = fs22.readFileSync(testFile, "utf-8");
|
|
25834
26135
|
} catch {
|
|
25835
26136
|
continue;
|
|
25836
26137
|
}
|
|
@@ -25861,10 +26162,10 @@ async function buildImpactMap(cwd) {
|
|
|
25861
26162
|
return impactMap;
|
|
25862
26163
|
}
|
|
25863
26164
|
async function loadImpactMap(cwd, options) {
|
|
25864
|
-
const cachePath =
|
|
25865
|
-
if (
|
|
26165
|
+
const cachePath = path51.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
26166
|
+
if (fs22.existsSync(cachePath)) {
|
|
25866
26167
|
try {
|
|
25867
|
-
const content =
|
|
26168
|
+
const content = fs22.readFileSync(cachePath, "utf-8");
|
|
25868
26169
|
const data = JSON.parse(content);
|
|
25869
26170
|
if (data.map !== null && typeof data.map === "object" && !Array.isArray(data.map)) {
|
|
25870
26171
|
const map = data.map;
|
|
@@ -25894,21 +26195,21 @@ async function loadImpactMap(cwd, options) {
|
|
|
25894
26195
|
return _internals39.buildImpactMap(cwd);
|
|
25895
26196
|
}
|
|
25896
26197
|
async function saveImpactMap(cwd, impactMap) {
|
|
25897
|
-
if (!
|
|
26198
|
+
if (!path51.isAbsolute(cwd)) {
|
|
25898
26199
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
25899
26200
|
}
|
|
25900
26201
|
_internals39.validateProjectRoot(cwd);
|
|
25901
|
-
const cacheDir2 =
|
|
25902
|
-
const cachePath =
|
|
25903
|
-
if (!
|
|
25904
|
-
|
|
26202
|
+
const cacheDir2 = path51.join(cwd, ".swarm", "cache");
|
|
26203
|
+
const cachePath = path51.join(cacheDir2, "impact-map.json");
|
|
26204
|
+
if (!fs22.existsSync(cacheDir2)) {
|
|
26205
|
+
fs22.mkdirSync(cacheDir2, { recursive: true });
|
|
25905
26206
|
}
|
|
25906
26207
|
const data = {
|
|
25907
26208
|
generatedAt: new Date().toISOString(),
|
|
25908
26209
|
fileCount: Object.keys(impactMap).length,
|
|
25909
26210
|
map: impactMap
|
|
25910
26211
|
};
|
|
25911
|
-
|
|
26212
|
+
fs22.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
25912
26213
|
}
|
|
25913
26214
|
async function analyzeImpact(changedFiles, cwd, budget) {
|
|
25914
26215
|
if (!Array.isArray(changedFiles)) {
|
|
@@ -25931,7 +26232,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
25931
26232
|
budgetExceeded = true;
|
|
25932
26233
|
break;
|
|
25933
26234
|
}
|
|
25934
|
-
const normalizedChanged = normalizePath2(
|
|
26235
|
+
const normalizedChanged = normalizePath2(path51.resolve(changedFile));
|
|
25935
26236
|
const tests = impactMap[normalizedChanged];
|
|
25936
26237
|
if (tests && tests.length > 0) {
|
|
25937
26238
|
for (const test of tests) {
|
|
@@ -25945,13 +26246,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
25945
26246
|
if (budgetExceeded)
|
|
25946
26247
|
break;
|
|
25947
26248
|
} else {
|
|
25948
|
-
const changedDir = normalizePath2(
|
|
25949
|
-
const changedInputDir = normalizePath2(
|
|
26249
|
+
const changedDir = normalizePath2(path51.dirname(normalizedChanged));
|
|
26250
|
+
const changedInputDir = normalizePath2(path51.dirname(changedFile));
|
|
25950
26251
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
25951
26252
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
25952
26253
|
}).sort(([sourceA], [sourceB]) => {
|
|
25953
|
-
const sourceDirA = normalizePath2(
|
|
25954
|
-
const sourceDirB = normalizePath2(
|
|
26254
|
+
const sourceDirA = normalizePath2(path51.dirname(sourceA));
|
|
26255
|
+
const sourceDirB = normalizePath2(path51.dirname(sourceB));
|
|
25955
26256
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
25956
26257
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
25957
26258
|
if (exactA !== exactB)
|
|
@@ -26277,8 +26578,8 @@ function detectFlakyTests(allHistory) {
|
|
|
26277
26578
|
}
|
|
26278
26579
|
|
|
26279
26580
|
// src/test-impact/history-store.ts
|
|
26280
|
-
import
|
|
26281
|
-
import
|
|
26581
|
+
import fs23 from "fs";
|
|
26582
|
+
import path52 from "path";
|
|
26282
26583
|
var MAX_HISTORY_PER_TEST = 20;
|
|
26283
26584
|
var MAX_ERROR_LENGTH = 500;
|
|
26284
26585
|
var MAX_STACK_LENGTH = 200;
|
|
@@ -26290,10 +26591,10 @@ function getHistoryPath(workingDir) {
|
|
|
26290
26591
|
if (!workingDir) {
|
|
26291
26592
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
26292
26593
|
}
|
|
26293
|
-
if (!
|
|
26594
|
+
if (!path52.isAbsolute(workingDir)) {
|
|
26294
26595
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
26295
26596
|
}
|
|
26296
|
-
return
|
|
26597
|
+
return path52.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
26297
26598
|
}
|
|
26298
26599
|
function sanitizeErrorMessage(errorMessage) {
|
|
26299
26600
|
if (errorMessage === undefined) {
|
|
@@ -26385,10 +26686,10 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
26385
26686
|
}
|
|
26386
26687
|
}
|
|
26387
26688
|
const historyPath = getHistoryPath(workingDir);
|
|
26388
|
-
const historyDir =
|
|
26689
|
+
const historyDir = path52.dirname(historyPath);
|
|
26389
26690
|
_internals40.validateProjectRoot(workingDir);
|
|
26390
|
-
if (!
|
|
26391
|
-
|
|
26691
|
+
if (!fs23.existsSync(historyDir)) {
|
|
26692
|
+
fs23.mkdirSync(historyDir, { recursive: true });
|
|
26392
26693
|
}
|
|
26393
26694
|
withHistoryWriteLock(historyPath, () => {
|
|
26394
26695
|
const existingRecords = readAllRecords(historyPath);
|
|
@@ -26422,13 +26723,13 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
26422
26723
|
`)}
|
|
26423
26724
|
`;
|
|
26424
26725
|
const tempPath = `${historyPath}.tmp`;
|
|
26425
|
-
|
|
26426
|
-
|
|
26726
|
+
fs23.writeFileSync(tempPath, content, "utf-8");
|
|
26727
|
+
fs23.renameSync(tempPath, historyPath);
|
|
26427
26728
|
} catch (err) {
|
|
26428
26729
|
try {
|
|
26429
26730
|
const tempPath = `${historyPath}.tmp`;
|
|
26430
|
-
if (
|
|
26431
|
-
|
|
26731
|
+
if (fs23.existsSync(tempPath)) {
|
|
26732
|
+
fs23.unlinkSync(tempPath);
|
|
26432
26733
|
}
|
|
26433
26734
|
} catch {}
|
|
26434
26735
|
throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -26440,7 +26741,7 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
26440
26741
|
const deadline = Date.now() + HISTORY_WRITE_LOCK_TIMEOUT_MS;
|
|
26441
26742
|
while (true) {
|
|
26442
26743
|
try {
|
|
26443
|
-
|
|
26744
|
+
fs23.mkdirSync(lockPath);
|
|
26444
26745
|
break;
|
|
26445
26746
|
} catch (error2) {
|
|
26446
26747
|
const code = error2 instanceof Error && "code" in error2 ? error2.code : undefined;
|
|
@@ -26451,9 +26752,9 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
26451
26752
|
throw new Error(`Timed out waiting for test history lock: ${historyPath}`);
|
|
26452
26753
|
}
|
|
26453
26754
|
try {
|
|
26454
|
-
const lockStat =
|
|
26755
|
+
const lockStat = fs23.statSync(lockPath);
|
|
26455
26756
|
if (Date.now() - lockStat.mtimeMs >= HISTORY_WRITE_LOCK_STALE_MS) {
|
|
26456
|
-
|
|
26757
|
+
fs23.rmSync(lockPath, { recursive: true, force: true });
|
|
26457
26758
|
continue;
|
|
26458
26759
|
}
|
|
26459
26760
|
} catch {}
|
|
@@ -26468,7 +26769,7 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
26468
26769
|
return fn();
|
|
26469
26770
|
} finally {
|
|
26470
26771
|
try {
|
|
26471
|
-
|
|
26772
|
+
fs23.rmSync(lockPath, { recursive: true, force: true });
|
|
26472
26773
|
} catch {}
|
|
26473
26774
|
}
|
|
26474
26775
|
function sleepSync(ms) {
|
|
@@ -26477,11 +26778,11 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
26477
26778
|
}
|
|
26478
26779
|
}
|
|
26479
26780
|
function readAllRecords(historyPath) {
|
|
26480
|
-
if (!
|
|
26781
|
+
if (!fs23.existsSync(historyPath)) {
|
|
26481
26782
|
return [];
|
|
26482
26783
|
}
|
|
26483
26784
|
try {
|
|
26484
|
-
const content =
|
|
26785
|
+
const content = fs23.readFileSync(historyPath, "utf-8");
|
|
26485
26786
|
const lines = content.split(`
|
|
26486
26787
|
`);
|
|
26487
26788
|
const records = [];
|
|
@@ -26514,8 +26815,8 @@ var _internals40 = {
|
|
|
26514
26815
|
};
|
|
26515
26816
|
|
|
26516
26817
|
// src/tools/resolve-working-directory.ts
|
|
26517
|
-
import * as
|
|
26518
|
-
import * as
|
|
26818
|
+
import * as fs24 from "fs";
|
|
26819
|
+
import * as path53 from "path";
|
|
26519
26820
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
26520
26821
|
if (workingDirectory == null || workingDirectory === "") {
|
|
26521
26822
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -26547,18 +26848,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
26547
26848
|
};
|
|
26548
26849
|
}
|
|
26549
26850
|
}
|
|
26550
|
-
const rawPathParts = workingDirectory.split(
|
|
26851
|
+
const rawPathParts = workingDirectory.split(path53.sep);
|
|
26551
26852
|
if (rawPathParts.includes("..")) {
|
|
26552
26853
|
return {
|
|
26553
26854
|
success: false,
|
|
26554
26855
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
26555
26856
|
};
|
|
26556
26857
|
}
|
|
26557
|
-
const normalizedDir =
|
|
26558
|
-
const resolvedDir =
|
|
26858
|
+
const normalizedDir = path53.normalize(workingDirectory);
|
|
26859
|
+
const resolvedDir = path53.resolve(normalizedDir);
|
|
26559
26860
|
let statResult;
|
|
26560
26861
|
try {
|
|
26561
|
-
statResult =
|
|
26862
|
+
statResult = fs24.statSync(resolvedDir);
|
|
26562
26863
|
} catch {
|
|
26563
26864
|
return {
|
|
26564
26865
|
success: false,
|
|
@@ -26574,16 +26875,16 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
26574
26875
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
26575
26876
|
return { success: true, directory: resolvedDir };
|
|
26576
26877
|
}
|
|
26577
|
-
const resolvedFallback =
|
|
26878
|
+
const resolvedFallback = path53.resolve(fallbackDirectory);
|
|
26578
26879
|
let fallbackExists = false;
|
|
26579
26880
|
try {
|
|
26580
|
-
|
|
26881
|
+
fs24.statSync(resolvedFallback);
|
|
26581
26882
|
fallbackExists = true;
|
|
26582
26883
|
} catch {
|
|
26583
26884
|
fallbackExists = false;
|
|
26584
26885
|
}
|
|
26585
26886
|
if (fallbackExists) {
|
|
26586
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
26887
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path53.sep);
|
|
26587
26888
|
if (isSubdirectory) {
|
|
26588
26889
|
return {
|
|
26589
26890
|
success: false,
|
|
@@ -26606,7 +26907,7 @@ async function estimateFanOut(sourceFiles, cwd) {
|
|
|
26606
26907
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
26607
26908
|
const uniqueTestFiles = new Set;
|
|
26608
26909
|
for (const sourceFile of sourceFiles) {
|
|
26609
|
-
const resolvedPath =
|
|
26910
|
+
const resolvedPath = path54.resolve(cwd, sourceFile);
|
|
26610
26911
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
26611
26912
|
const testFiles = impactMap[normalizedPath];
|
|
26612
26913
|
if (testFiles) {
|
|
@@ -26691,19 +26992,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
26691
26992
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
26692
26993
|
}
|
|
26693
26994
|
function detectGoTest(cwd) {
|
|
26694
|
-
return
|
|
26995
|
+
return fs25.existsSync(path54.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
26695
26996
|
}
|
|
26696
26997
|
function detectJavaMaven(cwd) {
|
|
26697
|
-
return
|
|
26998
|
+
return fs25.existsSync(path54.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
26698
26999
|
}
|
|
26699
27000
|
function detectGradle(cwd) {
|
|
26700
|
-
const hasBuildFile =
|
|
26701
|
-
const hasGradlew =
|
|
27001
|
+
const hasBuildFile = fs25.existsSync(path54.join(cwd, "build.gradle")) || fs25.existsSync(path54.join(cwd, "build.gradle.kts"));
|
|
27002
|
+
const hasGradlew = fs25.existsSync(path54.join(cwd, "gradlew")) || fs25.existsSync(path54.join(cwd, "gradlew.bat"));
|
|
26702
27003
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
26703
27004
|
}
|
|
26704
27005
|
function detectDotnetTest(cwd) {
|
|
26705
27006
|
try {
|
|
26706
|
-
const files =
|
|
27007
|
+
const files = fs25.readdirSync(cwd);
|
|
26707
27008
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
26708
27009
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
26709
27010
|
} catch {
|
|
@@ -26711,25 +27012,25 @@ function detectDotnetTest(cwd) {
|
|
|
26711
27012
|
}
|
|
26712
27013
|
}
|
|
26713
27014
|
function detectCTest(cwd) {
|
|
26714
|
-
const hasSource =
|
|
26715
|
-
const hasBuildCache =
|
|
27015
|
+
const hasSource = fs25.existsSync(path54.join(cwd, "CMakeLists.txt"));
|
|
27016
|
+
const hasBuildCache = fs25.existsSync(path54.join(cwd, "CMakeCache.txt")) || fs25.existsSync(path54.join(cwd, "build", "CMakeCache.txt"));
|
|
26716
27017
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
26717
27018
|
}
|
|
26718
27019
|
function detectSwiftTest(cwd) {
|
|
26719
|
-
return
|
|
27020
|
+
return fs25.existsSync(path54.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
26720
27021
|
}
|
|
26721
27022
|
function detectDartTest(cwd) {
|
|
26722
|
-
return
|
|
27023
|
+
return fs25.existsSync(path54.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
26723
27024
|
}
|
|
26724
27025
|
function detectRSpec(cwd) {
|
|
26725
|
-
const hasRSpecFile =
|
|
26726
|
-
const hasGemfile =
|
|
26727
|
-
const hasSpecDir =
|
|
27026
|
+
const hasRSpecFile = fs25.existsSync(path54.join(cwd, ".rspec"));
|
|
27027
|
+
const hasGemfile = fs25.existsSync(path54.join(cwd, "Gemfile"));
|
|
27028
|
+
const hasSpecDir = fs25.existsSync(path54.join(cwd, "spec"));
|
|
26728
27029
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
26729
27030
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
26730
27031
|
}
|
|
26731
27032
|
function detectMinitest(cwd) {
|
|
26732
|
-
return
|
|
27033
|
+
return fs25.existsSync(path54.join(cwd, "test")) && (fs25.existsSync(path54.join(cwd, "Gemfile")) || fs25.existsSync(path54.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
26733
27034
|
}
|
|
26734
27035
|
var DISPATCH_FRAMEWORK_MAP = {
|
|
26735
27036
|
bun: "bun",
|
|
@@ -26814,9 +27115,9 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
26814
27115
|
async function detectTestFramework(cwd) {
|
|
26815
27116
|
const baseDir = cwd;
|
|
26816
27117
|
try {
|
|
26817
|
-
const packageJsonPath =
|
|
26818
|
-
if (
|
|
26819
|
-
const content =
|
|
27118
|
+
const packageJsonPath = path54.join(baseDir, "package.json");
|
|
27119
|
+
if (fs25.existsSync(packageJsonPath)) {
|
|
27120
|
+
const content = fs25.readFileSync(packageJsonPath, "utf-8");
|
|
26820
27121
|
const pkg = JSON.parse(content);
|
|
26821
27122
|
const _deps = pkg.dependencies || {};
|
|
26822
27123
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -26835,38 +27136,38 @@ async function detectTestFramework(cwd) {
|
|
|
26835
27136
|
return "jest";
|
|
26836
27137
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
26837
27138
|
return "mocha";
|
|
26838
|
-
if (
|
|
27139
|
+
if (fs25.existsSync(path54.join(baseDir, "bun.lockb")) || fs25.existsSync(path54.join(baseDir, "bun.lock"))) {
|
|
26839
27140
|
if (scripts.test?.includes("bun"))
|
|
26840
27141
|
return "bun";
|
|
26841
27142
|
}
|
|
26842
27143
|
}
|
|
26843
27144
|
} catch {}
|
|
26844
27145
|
try {
|
|
26845
|
-
const pyprojectTomlPath =
|
|
26846
|
-
const setupCfgPath =
|
|
26847
|
-
const requirementsTxtPath =
|
|
26848
|
-
if (
|
|
26849
|
-
const content =
|
|
27146
|
+
const pyprojectTomlPath = path54.join(baseDir, "pyproject.toml");
|
|
27147
|
+
const setupCfgPath = path54.join(baseDir, "setup.cfg");
|
|
27148
|
+
const requirementsTxtPath = path54.join(baseDir, "requirements.txt");
|
|
27149
|
+
if (fs25.existsSync(pyprojectTomlPath)) {
|
|
27150
|
+
const content = fs25.readFileSync(pyprojectTomlPath, "utf-8");
|
|
26850
27151
|
if (content.includes("[tool.pytest"))
|
|
26851
27152
|
return "pytest";
|
|
26852
27153
|
if (content.includes("pytest"))
|
|
26853
27154
|
return "pytest";
|
|
26854
27155
|
}
|
|
26855
|
-
if (
|
|
26856
|
-
const content =
|
|
27156
|
+
if (fs25.existsSync(setupCfgPath)) {
|
|
27157
|
+
const content = fs25.readFileSync(setupCfgPath, "utf-8");
|
|
26857
27158
|
if (content.includes("[pytest]"))
|
|
26858
27159
|
return "pytest";
|
|
26859
27160
|
}
|
|
26860
|
-
if (
|
|
26861
|
-
const content =
|
|
27161
|
+
if (fs25.existsSync(requirementsTxtPath)) {
|
|
27162
|
+
const content = fs25.readFileSync(requirementsTxtPath, "utf-8");
|
|
26862
27163
|
if (content.includes("pytest"))
|
|
26863
27164
|
return "pytest";
|
|
26864
27165
|
}
|
|
26865
27166
|
} catch {}
|
|
26866
27167
|
try {
|
|
26867
|
-
const cargoTomlPath =
|
|
26868
|
-
if (
|
|
26869
|
-
const content =
|
|
27168
|
+
const cargoTomlPath = path54.join(baseDir, "Cargo.toml");
|
|
27169
|
+
if (fs25.existsSync(cargoTomlPath)) {
|
|
27170
|
+
const content = fs25.readFileSync(cargoTomlPath, "utf-8");
|
|
26870
27171
|
if (content.includes("[dev-dependencies]")) {
|
|
26871
27172
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
26872
27173
|
return "cargo";
|
|
@@ -26875,10 +27176,10 @@ async function detectTestFramework(cwd) {
|
|
|
26875
27176
|
}
|
|
26876
27177
|
} catch {}
|
|
26877
27178
|
try {
|
|
26878
|
-
const pesterConfigPath =
|
|
26879
|
-
const pesterConfigJsonPath =
|
|
26880
|
-
const pesterPs1Path =
|
|
26881
|
-
if (
|
|
27179
|
+
const pesterConfigPath = path54.join(baseDir, "pester.config.ps1");
|
|
27180
|
+
const pesterConfigJsonPath = path54.join(baseDir, "pester.config.ps1.json");
|
|
27181
|
+
const pesterPs1Path = path54.join(baseDir, "tests.ps1");
|
|
27182
|
+
if (fs25.existsSync(pesterConfigPath) || fs25.existsSync(pesterConfigJsonPath) || fs25.existsSync(pesterPs1Path)) {
|
|
26882
27183
|
return "pester";
|
|
26883
27184
|
}
|
|
26884
27185
|
} catch {}
|
|
@@ -26920,12 +27221,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
26920
27221
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
26921
27222
|
}
|
|
26922
27223
|
function resolveWorkspacePath(file, workingDir) {
|
|
26923
|
-
return
|
|
27224
|
+
return path54.isAbsolute(file) ? path54.resolve(file) : path54.resolve(workingDir, file);
|
|
26924
27225
|
}
|
|
26925
27226
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
26926
27227
|
if (!preferRelative)
|
|
26927
27228
|
return absolutePath;
|
|
26928
|
-
return
|
|
27229
|
+
return path54.relative(workingDir, absolutePath);
|
|
26929
27230
|
}
|
|
26930
27231
|
function dedupePush(target, value) {
|
|
26931
27232
|
if (!target.includes(value)) {
|
|
@@ -26962,18 +27263,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
26962
27263
|
}
|
|
26963
27264
|
}
|
|
26964
27265
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
26965
|
-
const relativeDir =
|
|
27266
|
+
const relativeDir = path54.dirname(relativePath);
|
|
26966
27267
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
26967
27268
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
26968
|
-
const rootDir =
|
|
26969
|
-
return nestedRelativeDir ? [rootDir,
|
|
27269
|
+
const rootDir = path54.join(workingDir, dirName);
|
|
27270
|
+
return nestedRelativeDir ? [rootDir, path54.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
26970
27271
|
});
|
|
26971
27272
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
26972
27273
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
26973
|
-
directories.push(
|
|
27274
|
+
directories.push(path54.join(workingDir, "src/test/java", path54.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
26974
27275
|
}
|
|
26975
27276
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
26976
|
-
directories.push(
|
|
27277
|
+
directories.push(path54.join(workingDir, "src/test/kotlin", path54.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
26977
27278
|
}
|
|
26978
27279
|
return [...new Set(directories)];
|
|
26979
27280
|
}
|
|
@@ -26981,19 +27282,19 @@ function hasCompoundTestExtension(filename) {
|
|
|
26981
27282
|
const lower = filename.toLowerCase();
|
|
26982
27283
|
return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
26983
27284
|
}
|
|
26984
|
-
function isLanguageSpecificTestFile(
|
|
26985
|
-
const lower =
|
|
27285
|
+
function isLanguageSpecificTestFile(basename10) {
|
|
27286
|
+
const lower = basename10.toLowerCase();
|
|
26986
27287
|
if (lower.endsWith("_test.go"))
|
|
26987
27288
|
return true;
|
|
26988
27289
|
if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
|
|
26989
27290
|
return true;
|
|
26990
27291
|
if (lower.endsWith("_spec.rb"))
|
|
26991
27292
|
return true;
|
|
26992
|
-
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(
|
|
27293
|
+
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename10) || basename10.endsWith("Test.java") || basename10.endsWith("Tests.java") || lower.endsWith("it.java")))
|
|
26993
27294
|
return true;
|
|
26994
27295
|
if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
|
|
26995
27296
|
return true;
|
|
26996
|
-
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(
|
|
27297
|
+
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename10) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
|
|
26997
27298
|
return true;
|
|
26998
27299
|
if (lower.endsWith(".tests.ps1"))
|
|
26999
27300
|
return true;
|
|
@@ -27001,23 +27302,23 @@ function isLanguageSpecificTestFile(basename9) {
|
|
|
27001
27302
|
}
|
|
27002
27303
|
function isConventionTestFilePath(filePath) {
|
|
27003
27304
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
27004
|
-
const
|
|
27005
|
-
return hasCompoundTestExtension(
|
|
27305
|
+
const basename10 = path54.basename(filePath);
|
|
27306
|
+
return hasCompoundTestExtension(basename10) || basename10.includes(".spec.") || basename10.includes(".test.") || isLanguageSpecificTestFile(basename10) || isTestDirectoryPath(normalizedPath);
|
|
27006
27307
|
}
|
|
27007
27308
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
27008
27309
|
const testFiles = [];
|
|
27009
27310
|
for (const file of sourceFiles) {
|
|
27010
27311
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
27011
|
-
const relativeFile =
|
|
27012
|
-
const
|
|
27013
|
-
const dirname25 =
|
|
27014
|
-
const preferRelativeOutput = !
|
|
27312
|
+
const relativeFile = path54.relative(workingDir, absoluteFile);
|
|
27313
|
+
const basename10 = path54.basename(absoluteFile);
|
|
27314
|
+
const dirname25 = path54.dirname(absoluteFile);
|
|
27315
|
+
const preferRelativeOutput = !path54.isAbsolute(file);
|
|
27015
27316
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
27016
27317
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
27017
27318
|
continue;
|
|
27018
27319
|
}
|
|
27019
|
-
const nameWithoutExt =
|
|
27020
|
-
const ext =
|
|
27320
|
+
const nameWithoutExt = basename10.replace(/\.[^.]+$/, "");
|
|
27321
|
+
const ext = path54.extname(basename10);
|
|
27021
27322
|
const genericTestNames = [
|
|
27022
27323
|
`${nameWithoutExt}.spec${ext}`,
|
|
27023
27324
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -27026,20 +27327,20 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
27026
27327
|
const colocatedCandidates = [
|
|
27027
27328
|
...genericTestNames,
|
|
27028
27329
|
...languageSpecificTestNames
|
|
27029
|
-
].map((candidateName) =>
|
|
27330
|
+
].map((candidateName) => path54.join(dirname25, candidateName));
|
|
27030
27331
|
const testDirectoryNames = [
|
|
27031
|
-
|
|
27332
|
+
basename10,
|
|
27032
27333
|
...genericTestNames,
|
|
27033
27334
|
...languageSpecificTestNames
|
|
27034
27335
|
];
|
|
27035
27336
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
27036
27337
|
const possibleTestFiles = [
|
|
27037
27338
|
...colocatedCandidates,
|
|
27038
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
27039
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
27339
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path54.join(dirname25, dirName, candidateName))),
|
|
27340
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path54.join(candidateDir, candidateName)))
|
|
27040
27341
|
];
|
|
27041
27342
|
for (const testFile of possibleTestFiles) {
|
|
27042
|
-
if (
|
|
27343
|
+
if (fs25.existsSync(testFile)) {
|
|
27043
27344
|
dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
|
|
27044
27345
|
}
|
|
27045
27346
|
}
|
|
@@ -27056,8 +27357,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27056
27357
|
for (const testFile of candidateTestFiles) {
|
|
27057
27358
|
try {
|
|
27058
27359
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
27059
|
-
const content =
|
|
27060
|
-
const testDir =
|
|
27360
|
+
const content = fs25.readFileSync(absoluteTestFile, "utf-8");
|
|
27361
|
+
const testDir = path54.dirname(absoluteTestFile);
|
|
27061
27362
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
27062
27363
|
let match;
|
|
27063
27364
|
match = importRegex.exec(content);
|
|
@@ -27065,8 +27366,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27065
27366
|
const importPath = match[1];
|
|
27066
27367
|
let resolvedImport;
|
|
27067
27368
|
if (importPath.startsWith(".")) {
|
|
27068
|
-
resolvedImport =
|
|
27069
|
-
const existingExt =
|
|
27369
|
+
resolvedImport = path54.resolve(testDir, importPath);
|
|
27370
|
+
const existingExt = path54.extname(resolvedImport);
|
|
27070
27371
|
if (!existingExt) {
|
|
27071
27372
|
for (const extToTry of [
|
|
27072
27373
|
".ts",
|
|
@@ -27077,7 +27378,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27077
27378
|
".cjs"
|
|
27078
27379
|
]) {
|
|
27079
27380
|
const withExt = resolvedImport + extToTry;
|
|
27080
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
27381
|
+
if (absoluteSourceFiles.includes(withExt) || fs25.existsSync(withExt)) {
|
|
27081
27382
|
resolvedImport = withExt;
|
|
27082
27383
|
break;
|
|
27083
27384
|
}
|
|
@@ -27086,12 +27387,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27086
27387
|
} else {
|
|
27087
27388
|
continue;
|
|
27088
27389
|
}
|
|
27089
|
-
const importBasename =
|
|
27090
|
-
const importDir =
|
|
27390
|
+
const importBasename = path54.basename(resolvedImport, path54.extname(resolvedImport));
|
|
27391
|
+
const importDir = path54.dirname(resolvedImport);
|
|
27091
27392
|
for (const sourceFile of absoluteSourceFiles) {
|
|
27092
|
-
const sourceDir =
|
|
27093
|
-
const sourceBasename =
|
|
27094
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
27393
|
+
const sourceDir = path54.dirname(sourceFile);
|
|
27394
|
+
const sourceBasename = path54.basename(sourceFile, path54.extname(sourceFile));
|
|
27395
|
+
const isRelatedDir = importDir === sourceDir || importDir === path54.join(sourceDir, "__tests__") || importDir === path54.join(sourceDir, "tests") || importDir === path54.join(sourceDir, "test") || importDir === path54.join(sourceDir, "spec");
|
|
27095
27396
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
27096
27397
|
dedupePush(testFiles, testFile);
|
|
27097
27398
|
break;
|
|
@@ -27104,8 +27405,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27104
27405
|
while (match !== null) {
|
|
27105
27406
|
const importPath = match[1];
|
|
27106
27407
|
if (importPath.startsWith(".")) {
|
|
27107
|
-
let resolvedImport =
|
|
27108
|
-
const existingExt =
|
|
27408
|
+
let resolvedImport = path54.resolve(testDir, importPath);
|
|
27409
|
+
const existingExt = path54.extname(resolvedImport);
|
|
27109
27410
|
if (!existingExt) {
|
|
27110
27411
|
for (const extToTry of [
|
|
27111
27412
|
".ts",
|
|
@@ -27116,18 +27417,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27116
27417
|
".cjs"
|
|
27117
27418
|
]) {
|
|
27118
27419
|
const withExt = resolvedImport + extToTry;
|
|
27119
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
27420
|
+
if (absoluteSourceFiles.includes(withExt) || fs25.existsSync(withExt)) {
|
|
27120
27421
|
resolvedImport = withExt;
|
|
27121
27422
|
break;
|
|
27122
27423
|
}
|
|
27123
27424
|
}
|
|
27124
27425
|
}
|
|
27125
|
-
const importDir =
|
|
27126
|
-
const importBasename =
|
|
27426
|
+
const importDir = path54.dirname(resolvedImport);
|
|
27427
|
+
const importBasename = path54.basename(resolvedImport, path54.extname(resolvedImport));
|
|
27127
27428
|
for (const sourceFile of absoluteSourceFiles) {
|
|
27128
|
-
const sourceDir =
|
|
27129
|
-
const sourceBasename =
|
|
27130
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
27429
|
+
const sourceDir = path54.dirname(sourceFile);
|
|
27430
|
+
const sourceBasename = path54.basename(sourceFile, path54.extname(sourceFile));
|
|
27431
|
+
const isRelatedDir = importDir === sourceDir || importDir === path54.join(sourceDir, "__tests__") || importDir === path54.join(sourceDir, "tests") || importDir === path54.join(sourceDir, "test") || importDir === path54.join(sourceDir, "spec");
|
|
27131
27432
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
27132
27433
|
dedupePush(testFiles, testFile);
|
|
27133
27434
|
break;
|
|
@@ -27247,8 +27548,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
27247
27548
|
return ["mvn", "test"];
|
|
27248
27549
|
case "gradle": {
|
|
27249
27550
|
const isWindows = process.platform === "win32";
|
|
27250
|
-
const hasGradlewBat =
|
|
27251
|
-
const hasGradlew =
|
|
27551
|
+
const hasGradlewBat = fs25.existsSync(path54.join(baseDir, "gradlew.bat"));
|
|
27552
|
+
const hasGradlew = fs25.existsSync(path54.join(baseDir, "gradlew"));
|
|
27252
27553
|
if (hasGradlewBat && isWindows)
|
|
27253
27554
|
return ["gradlew.bat", "test"];
|
|
27254
27555
|
if (hasGradlew)
|
|
@@ -27265,7 +27566,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
27265
27566
|
"cmake-build-release",
|
|
27266
27567
|
"out"
|
|
27267
27568
|
];
|
|
27268
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
27569
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs25.existsSync(path54.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
27269
27570
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
27270
27571
|
}
|
|
27271
27572
|
case "swift-test":
|
|
@@ -27699,13 +28000,13 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
27699
28000
|
};
|
|
27700
28001
|
}
|
|
27701
28002
|
const startTime = Date.now();
|
|
27702
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
28003
|
+
const vitestJsonOutputPath = framework === "vitest" ? path54.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
27703
28004
|
try {
|
|
27704
28005
|
if (vitestJsonOutputPath) {
|
|
27705
28006
|
try {
|
|
27706
|
-
|
|
27707
|
-
if (
|
|
27708
|
-
|
|
28007
|
+
fs25.mkdirSync(path54.dirname(vitestJsonOutputPath), { recursive: true });
|
|
28008
|
+
if (fs25.existsSync(vitestJsonOutputPath)) {
|
|
28009
|
+
fs25.unlinkSync(vitestJsonOutputPath);
|
|
27709
28010
|
}
|
|
27710
28011
|
} catch {}
|
|
27711
28012
|
}
|
|
@@ -27731,8 +28032,8 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
27731
28032
|
}
|
|
27732
28033
|
if (vitestJsonOutputPath) {
|
|
27733
28034
|
try {
|
|
27734
|
-
if (
|
|
27735
|
-
const vitestJsonOutput =
|
|
28035
|
+
if (fs25.existsSync(vitestJsonOutputPath)) {
|
|
28036
|
+
const vitestJsonOutput = fs25.readFileSync(vitestJsonOutputPath, "utf-8");
|
|
27736
28037
|
if (vitestJsonOutput.trim().length > 0) {
|
|
27737
28038
|
output += (output ? `
|
|
27738
28039
|
` : "") + vitestJsonOutput;
|
|
@@ -27871,10 +28172,10 @@ var SKIP_DIRECTORIES = new Set([
|
|
|
27871
28172
|
]);
|
|
27872
28173
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
27873
28174
|
const normalized = testFile.replace(/\\/g, "/");
|
|
27874
|
-
if (!
|
|
28175
|
+
if (!path54.isAbsolute(testFile))
|
|
27875
28176
|
return normalized;
|
|
27876
|
-
const relative8 =
|
|
27877
|
-
if (relative8.startsWith("..") ||
|
|
28177
|
+
const relative8 = path54.relative(workingDir, testFile);
|
|
28178
|
+
if (relative8.startsWith("..") || path54.isAbsolute(relative8)) {
|
|
27878
28179
|
return normalized;
|
|
27879
28180
|
}
|
|
27880
28181
|
return relative8.replace(/\\/g, "/");
|
|
@@ -28113,7 +28414,7 @@ var test_runner = createSwarmTool({
|
|
|
28113
28414
|
const sourceFiles = args.files.filter((file) => {
|
|
28114
28415
|
if (directTestFiles.includes(file))
|
|
28115
28416
|
return false;
|
|
28116
|
-
const ext =
|
|
28417
|
+
const ext = path54.extname(file).toLowerCase();
|
|
28117
28418
|
return SOURCE_EXTENSIONS.has(ext);
|
|
28118
28419
|
});
|
|
28119
28420
|
const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
|
|
@@ -28159,7 +28460,7 @@ var test_runner = createSwarmTool({
|
|
|
28159
28460
|
if (isConventionTestFilePath(f)) {
|
|
28160
28461
|
return false;
|
|
28161
28462
|
}
|
|
28162
|
-
const ext =
|
|
28463
|
+
const ext = path54.extname(f).toLowerCase();
|
|
28163
28464
|
return SOURCE_EXTENSIONS.has(ext);
|
|
28164
28465
|
});
|
|
28165
28466
|
if (sourceFiles.length === 0) {
|
|
@@ -28209,7 +28510,7 @@ var test_runner = createSwarmTool({
|
|
|
28209
28510
|
if (isConventionTestFilePath(f)) {
|
|
28210
28511
|
return false;
|
|
28211
28512
|
}
|
|
28212
|
-
const ext =
|
|
28513
|
+
const ext = path54.extname(f).toLowerCase();
|
|
28213
28514
|
return SOURCE_EXTENSIONS.has(ext);
|
|
28214
28515
|
});
|
|
28215
28516
|
if (sourceFiles.length === 0) {
|
|
@@ -28261,8 +28562,8 @@ var test_runner = createSwarmTool({
|
|
|
28261
28562
|
}
|
|
28262
28563
|
if (impactResult.impactedTests.length > 0) {
|
|
28263
28564
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
28264
|
-
const relativePath =
|
|
28265
|
-
return
|
|
28565
|
+
const relativePath = path54.relative(workingDir, absPath);
|
|
28566
|
+
return path54.isAbsolute(relativePath) ? absPath : relativePath;
|
|
28266
28567
|
});
|
|
28267
28568
|
} else {
|
|
28268
28569
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -28357,8 +28658,8 @@ function validateDirectoryPath(dir) {
|
|
|
28357
28658
|
if (dir.includes("..")) {
|
|
28358
28659
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
28359
28660
|
}
|
|
28360
|
-
const normalized =
|
|
28361
|
-
const absolutePath =
|
|
28661
|
+
const normalized = path55.normalize(dir);
|
|
28662
|
+
const absolutePath = path55.isAbsolute(normalized) ? normalized : path55.resolve(normalized);
|
|
28362
28663
|
return absolutePath;
|
|
28363
28664
|
}
|
|
28364
28665
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -28381,9 +28682,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
28381
28682
|
}
|
|
28382
28683
|
function getPackageVersion(dir) {
|
|
28383
28684
|
try {
|
|
28384
|
-
const packagePath =
|
|
28385
|
-
if (
|
|
28386
|
-
const content =
|
|
28685
|
+
const packagePath = path55.join(dir, "package.json");
|
|
28686
|
+
if (fs26.existsSync(packagePath)) {
|
|
28687
|
+
const content = fs26.readFileSync(packagePath, "utf-8");
|
|
28387
28688
|
const pkg = JSON.parse(content);
|
|
28388
28689
|
return pkg.version ?? null;
|
|
28389
28690
|
}
|
|
@@ -28392,9 +28693,9 @@ function getPackageVersion(dir) {
|
|
|
28392
28693
|
}
|
|
28393
28694
|
function getChangelogVersion(dir) {
|
|
28394
28695
|
try {
|
|
28395
|
-
const changelogPath =
|
|
28396
|
-
if (
|
|
28397
|
-
const content =
|
|
28696
|
+
const changelogPath = path55.join(dir, "CHANGELOG.md");
|
|
28697
|
+
if (fs26.existsSync(changelogPath)) {
|
|
28698
|
+
const content = fs26.readFileSync(changelogPath, "utf-8");
|
|
28398
28699
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
28399
28700
|
if (match) {
|
|
28400
28701
|
return match[1];
|
|
@@ -28406,10 +28707,10 @@ function getChangelogVersion(dir) {
|
|
|
28406
28707
|
function getVersionFileVersion(dir) {
|
|
28407
28708
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
28408
28709
|
for (const file of possibleFiles) {
|
|
28409
|
-
const filePath =
|
|
28410
|
-
if (
|
|
28710
|
+
const filePath = path55.join(dir, file);
|
|
28711
|
+
if (fs26.existsSync(filePath)) {
|
|
28411
28712
|
try {
|
|
28412
|
-
const content =
|
|
28713
|
+
const content = fs26.readFileSync(filePath, "utf-8").trim();
|
|
28413
28714
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
28414
28715
|
if (match) {
|
|
28415
28716
|
return match[1];
|
|
@@ -29143,8 +29444,8 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
29143
29444
|
}
|
|
29144
29445
|
|
|
29145
29446
|
// src/commands/reset.ts
|
|
29146
|
-
import * as
|
|
29147
|
-
import * as
|
|
29447
|
+
import * as fs27 from "fs";
|
|
29448
|
+
import * as path56 from "path";
|
|
29148
29449
|
|
|
29149
29450
|
// src/background/circuit-breaker.ts
|
|
29150
29451
|
class CircuitBreaker {
|
|
@@ -29851,8 +30152,8 @@ async function handleResetCommand(directory, args) {
|
|
|
29851
30152
|
for (const filename of filesToReset) {
|
|
29852
30153
|
try {
|
|
29853
30154
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
29854
|
-
if (
|
|
29855
|
-
|
|
30155
|
+
if (fs27.existsSync(resolvedPath)) {
|
|
30156
|
+
fs27.unlinkSync(resolvedPath);
|
|
29856
30157
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
29857
30158
|
} else {
|
|
29858
30159
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -29863,9 +30164,9 @@ async function handleResetCommand(directory, args) {
|
|
|
29863
30164
|
}
|
|
29864
30165
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
29865
30166
|
try {
|
|
29866
|
-
const rootPath =
|
|
29867
|
-
if (
|
|
29868
|
-
|
|
30167
|
+
const rootPath = path56.join(directory, filename);
|
|
30168
|
+
if (fs27.existsSync(rootPath)) {
|
|
30169
|
+
fs27.unlinkSync(rootPath);
|
|
29869
30170
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
29870
30171
|
}
|
|
29871
30172
|
} catch (err) {
|
|
@@ -29880,8 +30181,8 @@ async function handleResetCommand(directory, args) {
|
|
|
29880
30181
|
}
|
|
29881
30182
|
try {
|
|
29882
30183
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
29883
|
-
if (
|
|
29884
|
-
|
|
30184
|
+
if (fs27.existsSync(summariesPath)) {
|
|
30185
|
+
fs27.rmSync(summariesPath, { recursive: true, force: true });
|
|
29885
30186
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
29886
30187
|
} else {
|
|
29887
30188
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -29900,8 +30201,8 @@ async function handleResetCommand(directory, args) {
|
|
|
29900
30201
|
}
|
|
29901
30202
|
|
|
29902
30203
|
// src/commands/reset-session.ts
|
|
29903
|
-
import * as
|
|
29904
|
-
import * as
|
|
30204
|
+
import * as fs29 from "fs";
|
|
30205
|
+
import * as path58 from "path";
|
|
29905
30206
|
|
|
29906
30207
|
// src/hooks/trajectory-logger.ts
|
|
29907
30208
|
var callStartTimes = new Map;
|
|
@@ -30307,17 +30608,17 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
|
|
|
30307
30608
|
};
|
|
30308
30609
|
}
|
|
30309
30610
|
// src/prm/replay.ts
|
|
30310
|
-
import { promises as
|
|
30311
|
-
import
|
|
30611
|
+
import { promises as fs28 } from "fs";
|
|
30612
|
+
import path57 from "path";
|
|
30312
30613
|
function isPathSafe(targetPath, basePath) {
|
|
30313
|
-
const resolvedTarget =
|
|
30314
|
-
const resolvedBase =
|
|
30315
|
-
const rel =
|
|
30316
|
-
return !rel.startsWith("..") && !
|
|
30614
|
+
const resolvedTarget = path57.resolve(targetPath);
|
|
30615
|
+
const resolvedBase = path57.resolve(basePath);
|
|
30616
|
+
const rel = path57.relative(resolvedBase, resolvedTarget);
|
|
30617
|
+
return !rel.startsWith("..") && !path57.isAbsolute(rel);
|
|
30317
30618
|
}
|
|
30318
30619
|
function isWithinReplaysDir(targetPath) {
|
|
30319
|
-
const resolved =
|
|
30320
|
-
const parts = resolved.split(
|
|
30620
|
+
const resolved = path57.resolve(targetPath);
|
|
30621
|
+
const parts = resolved.split(path57.sep);
|
|
30321
30622
|
for (let i = 0;i < parts.length - 1; i++) {
|
|
30322
30623
|
if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
|
|
30323
30624
|
return true;
|
|
@@ -30330,15 +30631,15 @@ function sanitizeFilename(input) {
|
|
|
30330
30631
|
}
|
|
30331
30632
|
async function startReplayRecording(sessionID, directory) {
|
|
30332
30633
|
try {
|
|
30333
|
-
const replayDir =
|
|
30634
|
+
const replayDir = path57.join(directory, ".swarm", "replays");
|
|
30334
30635
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
30335
30636
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
30336
|
-
const filepath =
|
|
30637
|
+
const filepath = path57.join(replayDir, filename);
|
|
30337
30638
|
if (!isPathSafe(filepath, replayDir)) {
|
|
30338
30639
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
30339
30640
|
return null;
|
|
30340
30641
|
}
|
|
30341
|
-
await
|
|
30642
|
+
await fs28.mkdir(replayDir, { recursive: true });
|
|
30342
30643
|
return filepath;
|
|
30343
30644
|
} catch (err) {
|
|
30344
30645
|
console.warn(`[replay] Failed to start recording for session ${sessionID}: ${err}`);
|
|
@@ -30358,7 +30659,7 @@ async function recordReplayEntry(artifactPath, sessionID, entry) {
|
|
|
30358
30659
|
};
|
|
30359
30660
|
const line = `${JSON.stringify(fullEntry)}
|
|
30360
30661
|
`;
|
|
30361
|
-
await
|
|
30662
|
+
await fs28.appendFile(artifactPath, line, "utf-8");
|
|
30362
30663
|
} catch (err) {
|
|
30363
30664
|
console.warn(`[replay] Failed to record entry: ${err}`);
|
|
30364
30665
|
}
|
|
@@ -30402,8 +30703,8 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30402
30703
|
const results = [];
|
|
30403
30704
|
try {
|
|
30404
30705
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
30405
|
-
if (
|
|
30406
|
-
|
|
30706
|
+
if (fs29.existsSync(statePath)) {
|
|
30707
|
+
fs29.unlinkSync(statePath);
|
|
30407
30708
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
30408
30709
|
} else {
|
|
30409
30710
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -30411,11 +30712,11 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30411
30712
|
} catch {
|
|
30412
30713
|
results.push("\u274C Failed to delete state.json");
|
|
30413
30714
|
}
|
|
30414
|
-
const sessionDir =
|
|
30715
|
+
const sessionDir = path58.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
30415
30716
|
let sessionFiles = [];
|
|
30416
|
-
if (
|
|
30717
|
+
if (fs29.existsSync(sessionDir)) {
|
|
30417
30718
|
try {
|
|
30418
|
-
sessionFiles =
|
|
30719
|
+
sessionFiles = fs29.readdirSync(sessionDir);
|
|
30419
30720
|
} catch (err) {
|
|
30420
30721
|
results.push(`\u274C Failed to read session directory: ${errorMessage(err)}`);
|
|
30421
30722
|
}
|
|
@@ -30423,13 +30724,13 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30423
30724
|
for (const file of sessionFiles) {
|
|
30424
30725
|
if (file === "state.json")
|
|
30425
30726
|
continue;
|
|
30426
|
-
const filePath =
|
|
30727
|
+
const filePath = path58.join(sessionDir, file);
|
|
30427
30728
|
try {
|
|
30428
|
-
if (!
|
|
30729
|
+
if (!fs29.existsSync(filePath))
|
|
30429
30730
|
continue;
|
|
30430
|
-
if (!
|
|
30731
|
+
if (!fs29.lstatSync(filePath).isFile())
|
|
30431
30732
|
continue;
|
|
30432
|
-
|
|
30733
|
+
fs29.unlinkSync(filePath);
|
|
30433
30734
|
results.push(`\u2713 Deleted ${file}`);
|
|
30434
30735
|
} catch (err) {
|
|
30435
30736
|
results.push(`\u274C Failed to delete ${file}: ${errorMessage(err)}`);
|
|
@@ -30458,7 +30759,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30458
30759
|
}
|
|
30459
30760
|
|
|
30460
30761
|
// src/summaries/manager.ts
|
|
30461
|
-
import * as
|
|
30762
|
+
import * as path59 from "path";
|
|
30462
30763
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
30463
30764
|
function sanitizeSummaryId(id) {
|
|
30464
30765
|
if (!id || id.length === 0) {
|
|
@@ -30482,7 +30783,7 @@ function sanitizeSummaryId(id) {
|
|
|
30482
30783
|
}
|
|
30483
30784
|
async function loadFullOutput(directory, id) {
|
|
30484
30785
|
const sanitizedId = sanitizeSummaryId(id);
|
|
30485
|
-
const relativePath =
|
|
30786
|
+
const relativePath = path59.join("summaries", `${sanitizedId}.json`);
|
|
30486
30787
|
validateSwarmPath(directory, relativePath);
|
|
30487
30788
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
30488
30789
|
if (content === null) {
|
|
@@ -30534,18 +30835,18 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
|
30534
30835
|
}
|
|
30535
30836
|
|
|
30536
30837
|
// src/commands/rollback.ts
|
|
30537
|
-
import * as
|
|
30538
|
-
import * as
|
|
30838
|
+
import * as fs30 from "fs";
|
|
30839
|
+
import * as path60 from "path";
|
|
30539
30840
|
async function handleRollbackCommand(directory, args) {
|
|
30540
30841
|
const phaseArg = args[0];
|
|
30541
30842
|
if (!phaseArg) {
|
|
30542
30843
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
30543
|
-
if (!
|
|
30844
|
+
if (!fs30.existsSync(manifestPath2)) {
|
|
30544
30845
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
30545
30846
|
}
|
|
30546
30847
|
let manifest2;
|
|
30547
30848
|
try {
|
|
30548
|
-
manifest2 = JSON.parse(
|
|
30849
|
+
manifest2 = JSON.parse(fs30.readFileSync(manifestPath2, "utf-8"));
|
|
30549
30850
|
} catch {
|
|
30550
30851
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
30551
30852
|
}
|
|
@@ -30567,12 +30868,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30567
30868
|
return "Error: Phase number must be a positive integer.";
|
|
30568
30869
|
}
|
|
30569
30870
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
30570
|
-
if (!
|
|
30871
|
+
if (!fs30.existsSync(manifestPath)) {
|
|
30571
30872
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
30572
30873
|
}
|
|
30573
30874
|
let manifest;
|
|
30574
30875
|
try {
|
|
30575
|
-
manifest = JSON.parse(
|
|
30876
|
+
manifest = JSON.parse(fs30.readFileSync(manifestPath, "utf-8"));
|
|
30576
30877
|
} catch {
|
|
30577
30878
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
30578
30879
|
}
|
|
@@ -30582,10 +30883,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30582
30883
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
30583
30884
|
}
|
|
30584
30885
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
30585
|
-
if (!
|
|
30886
|
+
if (!fs30.existsSync(checkpointDir)) {
|
|
30586
30887
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
30587
30888
|
}
|
|
30588
|
-
const checkpointFiles =
|
|
30889
|
+
const checkpointFiles = fs30.readdirSync(checkpointDir);
|
|
30589
30890
|
if (checkpointFiles.length === 0) {
|
|
30590
30891
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
30591
30892
|
}
|
|
@@ -30601,10 +30902,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30601
30902
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
30602
30903
|
continue;
|
|
30603
30904
|
}
|
|
30604
|
-
const src =
|
|
30605
|
-
const dest =
|
|
30905
|
+
const src = path60.join(checkpointDir, file);
|
|
30906
|
+
const dest = path60.join(swarmDir, file);
|
|
30606
30907
|
try {
|
|
30607
|
-
|
|
30908
|
+
fs30.cpSync(src, dest, { recursive: true, force: true });
|
|
30608
30909
|
successes.push(file);
|
|
30609
30910
|
} catch (error2) {
|
|
30610
30911
|
failures.push({ file, error: error2.message });
|
|
@@ -30621,11 +30922,11 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30621
30922
|
].join(`
|
|
30622
30923
|
`);
|
|
30623
30924
|
}
|
|
30624
|
-
const existingLedgerPath =
|
|
30925
|
+
const existingLedgerPath = path60.join(swarmDir, "plan-ledger.jsonl");
|
|
30625
30926
|
let ledgerDeletionFailed = false;
|
|
30626
|
-
if (
|
|
30927
|
+
if (fs30.existsSync(existingLedgerPath)) {
|
|
30627
30928
|
try {
|
|
30628
|
-
|
|
30929
|
+
fs30.unlinkSync(existingLedgerPath);
|
|
30629
30930
|
} catch (err) {
|
|
30630
30931
|
ledgerDeletionFailed = true;
|
|
30631
30932
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -30634,9 +30935,9 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30634
30935
|
}
|
|
30635
30936
|
if (!ledgerDeletionFailed) {
|
|
30636
30937
|
try {
|
|
30637
|
-
const planJsonPath =
|
|
30638
|
-
if (
|
|
30639
|
-
const planRaw =
|
|
30938
|
+
const planJsonPath = path60.join(swarmDir, "plan.json");
|
|
30939
|
+
if (fs30.existsSync(planJsonPath)) {
|
|
30940
|
+
const planRaw = fs30.readFileSync(planJsonPath, "utf-8");
|
|
30640
30941
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
30641
30942
|
const planId = derivePlanId(plan);
|
|
30642
30943
|
const planHash = computePlanHash(plan);
|
|
@@ -30664,7 +30965,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30664
30965
|
timestamp: new Date().toISOString()
|
|
30665
30966
|
};
|
|
30666
30967
|
try {
|
|
30667
|
-
|
|
30968
|
+
fs30.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
30668
30969
|
`);
|
|
30669
30970
|
} catch (error2) {
|
|
30670
30971
|
console.error("Failed to write rollback event:", error2 instanceof Error ? error2.message : String(error2));
|
|
@@ -30846,7 +31147,7 @@ async function handleSddCommand(_directory, _args) {
|
|
|
30846
31147
|
}
|
|
30847
31148
|
|
|
30848
31149
|
// src/commands/simulate.ts
|
|
30849
|
-
import { renameSync as renameSync11, unlinkSync as
|
|
31150
|
+
import { renameSync as renameSync11, unlinkSync as unlinkSync12 } from "fs";
|
|
30850
31151
|
async function handleSimulateCommand(directory, args) {
|
|
30851
31152
|
const thresholdIndex = args.indexOf("--threshold");
|
|
30852
31153
|
const minCommitsIndex = args.indexOf("--min-commits");
|
|
@@ -30894,17 +31195,17 @@ Ensure this is a git repository with commit history.`;
|
|
|
30894
31195
|
const report = reportLines.filter(Boolean).join(`
|
|
30895
31196
|
`);
|
|
30896
31197
|
try {
|
|
30897
|
-
const
|
|
30898
|
-
const
|
|
30899
|
-
const reportPath =
|
|
30900
|
-
await
|
|
30901
|
-
const reportTempPath =
|
|
31198
|
+
const fs31 = await import("fs/promises");
|
|
31199
|
+
const path61 = await import("path");
|
|
31200
|
+
const reportPath = path61.join(directory, ".swarm", "simulate-report.md");
|
|
31201
|
+
await fs31.mkdir(path61.dirname(reportPath), { recursive: true });
|
|
31202
|
+
const reportTempPath = path61.join(path61.dirname(reportPath), `${path61.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
30902
31203
|
try {
|
|
30903
|
-
await
|
|
31204
|
+
await fs31.writeFile(reportTempPath, report, "utf-8");
|
|
30904
31205
|
renameSync11(reportTempPath, reportPath);
|
|
30905
31206
|
} catch (err) {
|
|
30906
31207
|
try {
|
|
30907
|
-
|
|
31208
|
+
unlinkSync12(reportTempPath);
|
|
30908
31209
|
} catch {}
|
|
30909
31210
|
throw err;
|
|
30910
31211
|
}
|
|
@@ -30927,20 +31228,20 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
30927
31228
|
// src/services/status-service.ts
|
|
30928
31229
|
import * as fsSync3 from "fs";
|
|
30929
31230
|
import { readFile as readFile16 } from "fs/promises";
|
|
30930
|
-
import * as
|
|
31231
|
+
import * as path62 from "path";
|
|
30931
31232
|
|
|
30932
31233
|
// src/turbo/lean/state.ts
|
|
30933
31234
|
init_logger();
|
|
30934
|
-
import * as
|
|
30935
|
-
import * as
|
|
31235
|
+
import * as fs31 from "fs";
|
|
31236
|
+
import * as path61 from "path";
|
|
30936
31237
|
var STATE_FILE3 = "turbo-state.json";
|
|
30937
31238
|
function nowISO3() {
|
|
30938
31239
|
return new Date().toISOString();
|
|
30939
31240
|
}
|
|
30940
31241
|
function ensureSwarmDir2(directory) {
|
|
30941
|
-
const swarmDir =
|
|
30942
|
-
if (!
|
|
30943
|
-
|
|
31242
|
+
const swarmDir = path61.resolve(directory, ".swarm");
|
|
31243
|
+
if (!fs31.existsSync(swarmDir)) {
|
|
31244
|
+
fs31.mkdirSync(swarmDir, { recursive: true });
|
|
30944
31245
|
}
|
|
30945
31246
|
return swarmDir;
|
|
30946
31247
|
}
|
|
@@ -30983,17 +31284,17 @@ function markStateUnreadable2(directory, reason) {
|
|
|
30983
31284
|
}
|
|
30984
31285
|
function readPersisted2(directory) {
|
|
30985
31286
|
try {
|
|
30986
|
-
const filePath =
|
|
30987
|
-
if (!
|
|
31287
|
+
const filePath = path61.join(directory, ".swarm", STATE_FILE3);
|
|
31288
|
+
if (!fs31.existsSync(filePath)) {
|
|
30988
31289
|
const seed = emptyPersisted2();
|
|
30989
31290
|
try {
|
|
30990
31291
|
ensureSwarmDir2(directory);
|
|
30991
|
-
|
|
31292
|
+
fs31.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
|
|
30992
31293
|
`, "utf-8");
|
|
30993
31294
|
} catch {}
|
|
30994
31295
|
return seed;
|
|
30995
31296
|
}
|
|
30996
|
-
const raw =
|
|
31297
|
+
const raw = fs31.readFileSync(filePath, "utf-8");
|
|
30997
31298
|
const parsed = JSON.parse(raw);
|
|
30998
31299
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
|
|
30999
31300
|
markStateUnreadable2(directory, `malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
|
|
@@ -31019,7 +31320,7 @@ function writePersisted2(directory, persisted) {
|
|
|
31019
31320
|
let payload;
|
|
31020
31321
|
try {
|
|
31021
31322
|
ensureSwarmDir2(directory);
|
|
31022
|
-
filePath =
|
|
31323
|
+
filePath = path61.join(directory, ".swarm", STATE_FILE3);
|
|
31023
31324
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
31024
31325
|
persisted.updatedAt = nowISO3();
|
|
31025
31326
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -31030,14 +31331,14 @@ function writePersisted2(directory, persisted) {
|
|
|
31030
31331
|
throw new Error(`Lean Turbo state persistence prepare failed: ${msg}`);
|
|
31031
31332
|
}
|
|
31032
31333
|
try {
|
|
31033
|
-
|
|
31034
|
-
|
|
31334
|
+
fs31.writeFileSync(tmpPath, payload, "utf-8");
|
|
31335
|
+
fs31.renameSync(tmpPath, filePath);
|
|
31035
31336
|
} catch (error2) {
|
|
31036
31337
|
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
31037
31338
|
error(`[turbo/lean/state] Failed to persist ${STATE_FILE3} atomically: ${msg}`);
|
|
31038
31339
|
try {
|
|
31039
|
-
if (
|
|
31040
|
-
|
|
31340
|
+
if (fs31.existsSync(tmpPath)) {
|
|
31341
|
+
fs31.unlinkSync(tmpPath);
|
|
31041
31342
|
}
|
|
31042
31343
|
} catch {}
|
|
31043
31344
|
throw new Error(`Lean Turbo state persistence failed: ${msg}`);
|
|
@@ -31137,7 +31438,7 @@ var _internals43 = {
|
|
|
31137
31438
|
};
|
|
31138
31439
|
function readSpecStalenessSnapshot(directory) {
|
|
31139
31440
|
try {
|
|
31140
|
-
const p =
|
|
31441
|
+
const p = path62.join(directory, ".swarm", "spec-staleness.json");
|
|
31141
31442
|
if (!fsSync3.existsSync(p))
|
|
31142
31443
|
return { stale: false };
|
|
31143
31444
|
const raw = fsSync3.readFileSync(p, "utf-8");
|
|
@@ -31669,13 +31970,13 @@ function buildStatusMessage2(session, directory, sessionID) {
|
|
|
31669
31970
|
}
|
|
31670
31971
|
|
|
31671
31972
|
// src/commands/unlink.ts
|
|
31672
|
-
import { existsSync as
|
|
31673
|
-
import * as
|
|
31973
|
+
import { existsSync as existsSync37 } from "fs";
|
|
31974
|
+
import * as path63 from "path";
|
|
31674
31975
|
var DEDUP_THRESHOLD2 = 0.6;
|
|
31675
31976
|
async function copySharedKnowledgeToLocal(linkDir, localSwarmDir) {
|
|
31676
|
-
const sharedPath =
|
|
31677
|
-
const localPath =
|
|
31678
|
-
if (!
|
|
31977
|
+
const sharedPath = path63.join(linkDir, "knowledge.jsonl");
|
|
31978
|
+
const localPath = path63.join(localSwarmDir, "knowledge.jsonl");
|
|
31979
|
+
if (!existsSync37(sharedPath))
|
|
31679
31980
|
return 0;
|
|
31680
31981
|
const sharedEntries = await readKnowledge(sharedPath);
|
|
31681
31982
|
if (sharedEntries.length === 0)
|
|
@@ -31709,7 +32010,7 @@ async function handleUnlinkCommand(directory, args) {
|
|
|
31709
32010
|
let copied = 0;
|
|
31710
32011
|
if (copyBack) {
|
|
31711
32012
|
try {
|
|
31712
|
-
copied = await copySharedKnowledgeToLocal(linkDir,
|
|
32013
|
+
copied = await copySharedKnowledgeToLocal(linkDir, path63.join(directory, ".swarm"));
|
|
31713
32014
|
} catch (error2) {
|
|
31714
32015
|
return `\u274C Failed to copy shared knowledge back to local: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
31715
32016
|
}
|
|
@@ -31864,7 +32165,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
31864
32165
|
async function handleHelpCommand(ctx) {
|
|
31865
32166
|
const targetCommand = ctx.args.join(" ");
|
|
31866
32167
|
if (!targetCommand) {
|
|
31867
|
-
const { buildHelpText } = await import("./index-
|
|
32168
|
+
const { buildHelpText } = await import("./index-4pt2py5p.js");
|
|
31868
32169
|
return buildHelpText();
|
|
31869
32170
|
}
|
|
31870
32171
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -31873,7 +32174,7 @@ async function handleHelpCommand(ctx) {
|
|
|
31873
32174
|
return _internals45.buildDetailedHelp(resolved.key, resolved.entry);
|
|
31874
32175
|
}
|
|
31875
32176
|
const similar = _internals45.findSimilarCommands(targetCommand);
|
|
31876
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
32177
|
+
const { buildHelpText: fullHelp } = await import("./index-4pt2py5p.js");
|
|
31877
32178
|
if (similar.length > 0) {
|
|
31878
32179
|
return `Command '/swarm ${targetCommand}' not found.
|
|
31879
32180
|
|
|
@@ -32006,7 +32307,7 @@ var COMMAND_REGISTRY = {
|
|
|
32006
32307
|
},
|
|
32007
32308
|
"guardrail explain": {
|
|
32008
32309
|
handler: async (ctx) => {
|
|
32009
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
32310
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-ktm6szbm.js");
|
|
32010
32311
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
32011
32312
|
},
|
|
32012
32313
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -32016,7 +32317,7 @@ var COMMAND_REGISTRY = {
|
|
|
32016
32317
|
},
|
|
32017
32318
|
"guardrail-log": {
|
|
32018
32319
|
handler: async (ctx) => {
|
|
32019
|
-
const { handleGuardrailLog } = await import("./guardrail-log-
|
|
32320
|
+
const { handleGuardrailLog } = await import("./guardrail-log-ya49kpwn.js");
|
|
32020
32321
|
return handleGuardrailLog(ctx.directory, ctx.args);
|
|
32021
32322
|
},
|
|
32022
32323
|
description: "Read the guardrail decision log (use --blocks-only for blocks)",
|
|
@@ -32041,8 +32342,15 @@ var COMMAND_REGISTRY = {
|
|
|
32041
32342
|
},
|
|
32042
32343
|
benchmark: {
|
|
32043
32344
|
handler: (ctx) => handleBenchmarkCommand(ctx.directory, ctx.args),
|
|
32044
|
-
description: "Show performance metrics [--cumulative] [--ci-gate]",
|
|
32045
|
-
args: "--cumulative, --ci-gate",
|
|
32345
|
+
description: "Show performance metrics [--cumulative] [--ci-gate] [--max-cost-usd <n>]",
|
|
32346
|
+
args: "--cumulative, --ci-gate, --max-cost-usd <n>",
|
|
32347
|
+
category: "diagnostics",
|
|
32348
|
+
toolPolicy: "agent"
|
|
32349
|
+
},
|
|
32350
|
+
costs: {
|
|
32351
|
+
handler: (ctx) => handleCostsCommand(ctx.directory, ctx.args),
|
|
32352
|
+
description: "Show per-agent and per-task token/cost telemetry [--json]",
|
|
32353
|
+
args: "--json",
|
|
32046
32354
|
category: "diagnostics",
|
|
32047
32355
|
toolPolicy: "agent"
|
|
32048
32356
|
},
|
|
@@ -32777,24 +33085,24 @@ function validateAliases() {
|
|
|
32777
33085
|
}
|
|
32778
33086
|
aliasTargets.get(target).push(name);
|
|
32779
33087
|
const visited = new Set;
|
|
32780
|
-
const
|
|
33088
|
+
const path64 = [];
|
|
32781
33089
|
let current = target;
|
|
32782
33090
|
while (current) {
|
|
32783
33091
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
32784
33092
|
if (!currentEntry)
|
|
32785
33093
|
break;
|
|
32786
33094
|
if (visited.has(current)) {
|
|
32787
|
-
const cycleStart =
|
|
33095
|
+
const cycleStart = path64.indexOf(current);
|
|
32788
33096
|
const fullChain = [
|
|
32789
33097
|
name,
|
|
32790
|
-
...
|
|
33098
|
+
...path64.slice(0, cycleStart > 0 ? cycleStart : path64.length),
|
|
32791
33099
|
current
|
|
32792
33100
|
].join(" \u2192 ");
|
|
32793
33101
|
errors.push(`Circular alias detected: ${fullChain}`);
|
|
32794
33102
|
break;
|
|
32795
33103
|
}
|
|
32796
33104
|
visited.add(current);
|
|
32797
|
-
|
|
33105
|
+
path64.push(current);
|
|
32798
33106
|
current = currentEntry.aliasOf || "";
|
|
32799
33107
|
}
|
|
32800
33108
|
}
|
|
@@ -32960,4 +33268,4 @@ ${text}`;
|
|
|
32960
33268
|
};
|
|
32961
33269
|
}
|
|
32962
33270
|
|
|
32963
|
-
export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS, _internals45 as _internals, resolveCommand };
|
|
33271
|
+
export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCostsCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS, _internals45 as _internals, resolveCommand };
|