opencode-swarm 7.88.0 → 7.88.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.opencode/skills/brainstorm/SKILL.md +2 -1
- package/.opencode/skills/clarify/SKILL.md +7 -1
- package/.opencode/skills/clarify-spec/SKILL.md +1 -1
- package/.opencode/skills/issue-ingest/SKILL.md +3 -2
- package/.opencode/skills/plan/SKILL.md +7 -1
- package/.opencode/skills/specify/SKILL.md +3 -2
- package/README.md +1 -1
- package/dist/cli/{guardrail-explain-sw5bjxtk.js → guardrail-explain-qd243wrm.js} +2 -2
- package/dist/cli/{index-fwb5f2gr.js → index-09smngfp.js} +1 -1
- package/dist/cli/{index-dkytd370.js → index-tjr1m8wf.js} +2 -2
- package/dist/cli/{index-jch711dq.js → index-y72bw1wb.js} +543 -236
- package/dist/cli/index.js +1 -1
- package/dist/commands/pr-monitor-status.d.ts +1 -1
- package/dist/index.js +1371 -1006
- package/dist/memory/config.d.ts +1 -0
- package/dist/memory/gateway.d.ts +1 -0
- package/dist/memory/provider-pool.d.ts +50 -0
- package/dist/memory/sqlite-provider.d.ts +3 -0
- package/package.json +1 -1
|
@@ -899,7 +899,7 @@ var init_executor = __esm(() => {
|
|
|
899
899
|
// package.json
|
|
900
900
|
var package_default = {
|
|
901
901
|
name: "opencode-swarm",
|
|
902
|
-
version: "7.88.
|
|
902
|
+
version: "7.88.2",
|
|
903
903
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
904
904
|
main: "dist/index.js",
|
|
905
905
|
types: "dist/index.d.ts",
|
|
@@ -18335,7 +18335,7 @@ ${USAGE7}`;
|
|
|
18335
18335
|
|
|
18336
18336
|
// src/commands/memory.ts
|
|
18337
18337
|
import { existsSync as existsSync25 } from "fs";
|
|
18338
|
-
import * as
|
|
18338
|
+
import * as path43 from "path";
|
|
18339
18339
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18340
18340
|
|
|
18341
18341
|
// src/memory/config.ts
|
|
@@ -18367,7 +18367,8 @@ var DEFAULT_MEMORY_CONFIG = {
|
|
|
18367
18367
|
},
|
|
18368
18368
|
maintenance: {
|
|
18369
18369
|
lowUtilityMaxConfidence: 0.45,
|
|
18370
|
-
lowUtilityMinAgeDays: 30
|
|
18370
|
+
lowUtilityMinAgeDays: 30,
|
|
18371
|
+
autoCompactEveryNRecalls: 50
|
|
18371
18372
|
},
|
|
18372
18373
|
hardDelete: false
|
|
18373
18374
|
};
|
|
@@ -18428,7 +18429,7 @@ class MemoryValidationError extends Error {
|
|
|
18428
18429
|
// src/memory/evaluation.ts
|
|
18429
18430
|
import * as fs17 from "fs/promises";
|
|
18430
18431
|
import * as os9 from "os";
|
|
18431
|
-
import * as
|
|
18432
|
+
import * as path42 from "path";
|
|
18432
18433
|
|
|
18433
18434
|
// src/memory/local-jsonl-provider.ts
|
|
18434
18435
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -19669,6 +19670,10 @@ async function writeJsonlAtomic(filePath, values) {
|
|
|
19669
19670
|
await rename5(tmp, filePath);
|
|
19670
19671
|
}
|
|
19671
19672
|
|
|
19673
|
+
// src/memory/provider-pool.ts
|
|
19674
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
19675
|
+
import * as path41 from "path";
|
|
19676
|
+
|
|
19672
19677
|
// src/memory/sqlite-provider.ts
|
|
19673
19678
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
19674
19679
|
import { mkdirSync as mkdirSync15 } from "fs";
|
|
@@ -19907,6 +19912,7 @@ function loadDatabaseCtor2() {
|
|
|
19907
19912
|
_DatabaseCtor2 = req("bun:sqlite").Database;
|
|
19908
19913
|
return _DatabaseCtor2;
|
|
19909
19914
|
}
|
|
19915
|
+
var RECALL_CANDIDATE_LIMIT = 1000;
|
|
19910
19916
|
var FTS_SCHEMA_MIGRATION_NAME = "create_memory_fts5_shadow_index";
|
|
19911
19917
|
var FTS_TABLE_NAME = "memory_items_fts";
|
|
19912
19918
|
var FTS_INDEX_COLUMNS = [
|
|
@@ -20004,6 +20010,24 @@ var MIGRATIONS2 = [
|
|
|
20004
20010
|
${ftsCreateColumnsSql()}
|
|
20005
20011
|
);
|
|
20006
20012
|
`
|
|
20013
|
+
},
|
|
20014
|
+
{
|
|
20015
|
+
version: 4,
|
|
20016
|
+
name: "create_meta_table",
|
|
20017
|
+
sql: `
|
|
20018
|
+
CREATE TABLE IF NOT EXISTS _meta (
|
|
20019
|
+
key TEXT PRIMARY KEY,
|
|
20020
|
+
value TEXT NOT NULL
|
|
20021
|
+
);
|
|
20022
|
+
`
|
|
20023
|
+
},
|
|
20024
|
+
{
|
|
20025
|
+
version: 5,
|
|
20026
|
+
name: "create_recall_usage_timestamp_index",
|
|
20027
|
+
sql: `
|
|
20028
|
+
CREATE INDEX IF NOT EXISTS idx_memory_recall_usage_timestamp
|
|
20029
|
+
ON memory_recall_usage(timestamp DESC);
|
|
20030
|
+
`
|
|
20007
20031
|
}
|
|
20008
20032
|
];
|
|
20009
20033
|
|
|
@@ -20018,6 +20042,8 @@ class SQLiteMemoryProvider {
|
|
|
20018
20042
|
memories = new Map;
|
|
20019
20043
|
proposals = new Map;
|
|
20020
20044
|
lastAutomaticJsonlMigration = null;
|
|
20045
|
+
recallCountSinceLastCompaction = 0;
|
|
20046
|
+
isCompacting = false;
|
|
20021
20047
|
constructor(rootDirectory, config = {}) {
|
|
20022
20048
|
this.rootDirectory = rootDirectory;
|
|
20023
20049
|
this.config = {
|
|
@@ -20075,6 +20101,7 @@ class SQLiteMemoryProvider {
|
|
|
20075
20101
|
this.db.run(`PRAGMA busy_timeout = ${busyTimeoutMs};`);
|
|
20076
20102
|
this.db.run("PRAGMA foreign_keys = ON;");
|
|
20077
20103
|
this.runMigrations();
|
|
20104
|
+
this.backfillScopeKeys();
|
|
20078
20105
|
this.ftsAvailable = this.initializeFtsIndex();
|
|
20079
20106
|
this.lastAutomaticJsonlMigration = null;
|
|
20080
20107
|
await this.migrateLegacyJsonlIfNeeded();
|
|
@@ -20137,7 +20164,8 @@ class SQLiteMemoryProvider {
|
|
|
20137
20164
|
const scopedRecords = await this.list({
|
|
20138
20165
|
scopes: request.scopes,
|
|
20139
20166
|
kinds: request.kinds,
|
|
20140
|
-
includeExpired: request.includeExpired
|
|
20167
|
+
includeExpired: request.includeExpired,
|
|
20168
|
+
limit: RECALL_CANDIDATE_LIMIT
|
|
20141
20169
|
});
|
|
20142
20170
|
const candidates = this.selectRecallCandidates(request, scopedRecords);
|
|
20143
20171
|
const result = scoreMemoryRecordsWithDiagnostics(candidates.records, request);
|
|
@@ -20158,7 +20186,29 @@ class SQLiteMemoryProvider {
|
|
|
20158
20186
|
timestamp,
|
|
20159
20187
|
usage_json
|
|
20160
20188
|
) VALUES (?, ?, ?, ?)`, [randomUUID6(), event.bundleId, event.timestamp, JSON.stringify(event)]);
|
|
20161
|
-
|
|
20189
|
+
this.recallCountSinceLastCompaction++;
|
|
20190
|
+
const threshold = this.config.maintenance?.autoCompactEveryNRecalls ?? 50;
|
|
20191
|
+
if (threshold > 0 && this.recallCountSinceLastCompaction >= threshold && !this.isCompacting) {
|
|
20192
|
+
this.recallCountSinceLastCompaction = 0;
|
|
20193
|
+
this.isCompacting = true;
|
|
20194
|
+
this.compactMaintenance({ dryRun: false }).then((result) => {
|
|
20195
|
+
const rowsInspected = result.remaining + result.removedDeleted + result.removedSuperseded + result.removedExpiredScratch;
|
|
20196
|
+
const rowsPurged = result.removedDeleted + result.removedSuperseded + result.removedExpiredScratch;
|
|
20197
|
+
return this.insertEvent("compact_triggered", "memory_items", "auto compaction triggered", JSON.stringify({
|
|
20198
|
+
trigger: "auto",
|
|
20199
|
+
threshold,
|
|
20200
|
+
rowsInspected,
|
|
20201
|
+
rowsPurged,
|
|
20202
|
+
timestamp: new Date().toISOString()
|
|
20203
|
+
}));
|
|
20204
|
+
}).catch((err) => {
|
|
20205
|
+
if (process.env.OPENCODE_SWARM_DEBUG === "1") {
|
|
20206
|
+
console.debug(`[memory] auto-compaction failed: ${err}`);
|
|
20207
|
+
}
|
|
20208
|
+
}).finally(() => {
|
|
20209
|
+
this.isCompacting = false;
|
|
20210
|
+
});
|
|
20211
|
+
}
|
|
20162
20212
|
}
|
|
20163
20213
|
async listRecallUsage(filter = {}) {
|
|
20164
20214
|
await this.initialize();
|
|
@@ -20182,12 +20232,46 @@ class SQLiteMemoryProvider {
|
|
|
20182
20232
|
}
|
|
20183
20233
|
async list(filter = {}) {
|
|
20184
20234
|
await this.initialize();
|
|
20185
|
-
|
|
20235
|
+
const db = this.requireDb();
|
|
20236
|
+
const conditions = [];
|
|
20237
|
+
const params = [];
|
|
20186
20238
|
if (filter.scopes && filter.scopes.length > 0) {
|
|
20187
|
-
|
|
20239
|
+
const scopeKeys = filter.scopes.map((scope) => stableScopeKey(scope));
|
|
20240
|
+
const placeholders = scopeKeys.map(() => "?").join(", ");
|
|
20241
|
+
conditions.push(`scope_key IN (${placeholders})`);
|
|
20242
|
+
params.push(...scopeKeys);
|
|
20188
20243
|
}
|
|
20189
20244
|
if (filter.kinds && filter.kinds.length > 0) {
|
|
20190
|
-
|
|
20245
|
+
if (filter.kinds.length === 1) {
|
|
20246
|
+
conditions.push("kind = ?");
|
|
20247
|
+
params.push(filter.kinds[0]);
|
|
20248
|
+
} else {
|
|
20249
|
+
const placeholders = filter.kinds.map(() => "?").join(", ");
|
|
20250
|
+
conditions.push(`kind IN (${placeholders})`);
|
|
20251
|
+
params.push(...filter.kinds);
|
|
20252
|
+
}
|
|
20253
|
+
}
|
|
20254
|
+
if (!filter.includeInactive) {
|
|
20255
|
+
conditions.push("superseded_by IS NULL");
|
|
20256
|
+
conditions.push("deleted = 0");
|
|
20257
|
+
}
|
|
20258
|
+
if (!filter.includeExpired) {
|
|
20259
|
+
const nowIso = new Date().toISOString();
|
|
20260
|
+
conditions.push("(expires_at IS NULL OR expires_at > ?)");
|
|
20261
|
+
params.push(nowIso);
|
|
20262
|
+
}
|
|
20263
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
20264
|
+
let sql = `SELECT id, record_json FROM memory_items ${whereClause} ORDER BY updated_at DESC`;
|
|
20265
|
+
if (typeof filter.limit === "number") {
|
|
20266
|
+
sql += " LIMIT ?";
|
|
20267
|
+
params.push(Math.trunc(filter.limit));
|
|
20268
|
+
}
|
|
20269
|
+
const rows = db.query(sql).all(...params);
|
|
20270
|
+
let records = [];
|
|
20271
|
+
for (const row of rows) {
|
|
20272
|
+
const parsed = this.parseMemoryRow(row);
|
|
20273
|
+
if (parsed)
|
|
20274
|
+
records.push(parsed);
|
|
20191
20275
|
}
|
|
20192
20276
|
if (!filter.includeExpired) {
|
|
20193
20277
|
const now = Date.now();
|
|
@@ -20198,11 +20282,7 @@ class SQLiteMemoryProvider {
|
|
|
20198
20282
|
return !Number.isFinite(expires) || expires > now;
|
|
20199
20283
|
});
|
|
20200
20284
|
}
|
|
20201
|
-
|
|
20202
|
-
records = records.filter((record) => !record.supersededBy && record.metadata.deleted !== true);
|
|
20203
|
-
}
|
|
20204
|
-
records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
20205
|
-
return records.slice(0, filter.limit ?? records.length);
|
|
20285
|
+
return records;
|
|
20206
20286
|
}
|
|
20207
20287
|
async createProposal(proposal) {
|
|
20208
20288
|
await this.initialize();
|
|
@@ -20392,6 +20472,31 @@ class SQLiteMemoryProvider {
|
|
|
20392
20472
|
apply();
|
|
20393
20473
|
}
|
|
20394
20474
|
}
|
|
20475
|
+
backfillScopeKeys() {
|
|
20476
|
+
const db = this.requireDb();
|
|
20477
|
+
const metaRow = db.query("SELECT value FROM _meta WHERE key = 'scope_key_backfilled'").get("scope_key_backfilled");
|
|
20478
|
+
if (metaRow?.value === "1")
|
|
20479
|
+
return;
|
|
20480
|
+
const rows = db.query("SELECT id, record_json, scope_key FROM memory_items").all();
|
|
20481
|
+
let backfillCount = 0;
|
|
20482
|
+
for (const row of rows) {
|
|
20483
|
+
try {
|
|
20484
|
+
const record = JSON.parse(row.record_json);
|
|
20485
|
+
const canonicalKey = stableScopeKey(record.scope);
|
|
20486
|
+
if (row.scope_key !== canonicalKey) {
|
|
20487
|
+
db.run("UPDATE memory_items SET scope_key = ? WHERE id = ?", [
|
|
20488
|
+
canonicalKey,
|
|
20489
|
+
row.id
|
|
20490
|
+
]);
|
|
20491
|
+
backfillCount++;
|
|
20492
|
+
}
|
|
20493
|
+
} catch {}
|
|
20494
|
+
}
|
|
20495
|
+
if (backfillCount > 0) {
|
|
20496
|
+
this.insertEvent("migration", "backfill_scope_keys", `${backfillCount} memory item(s) scope_key backfilled to canonical form`);
|
|
20497
|
+
}
|
|
20498
|
+
db.run("INSERT OR REPLACE INTO _meta (key, value) VALUES ('scope_key_backfilled', '1')");
|
|
20499
|
+
}
|
|
20395
20500
|
initializeFtsIndex() {
|
|
20396
20501
|
const db = this.requireDb();
|
|
20397
20502
|
try {
|
|
@@ -20502,7 +20607,7 @@ class SQLiteMemoryProvider {
|
|
|
20502
20607
|
record_json
|
|
20503
20608
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
20504
20609
|
record.id,
|
|
20505
|
-
|
|
20610
|
+
stableScopeKey(record.scope),
|
|
20506
20611
|
record.kind,
|
|
20507
20612
|
record.updatedAt,
|
|
20508
20613
|
record.expiresAt ?? null,
|
|
@@ -20878,14 +20983,203 @@ function rerankWithFts(items, ftsOrder) {
|
|
|
20878
20983
|
}).sort((a, b) => b.score - a.score || a.record.id.localeCompare(b.record.id));
|
|
20879
20984
|
}
|
|
20880
20985
|
|
|
20986
|
+
// src/memory/provider-pool.ts
|
|
20987
|
+
var MAX_POOL_SIZE = 16;
|
|
20988
|
+
var POOLED_MARKER = Symbol("opencode-swarm-pooled-provider");
|
|
20989
|
+
var REAL_CLOSE = Symbol("opencode-swarm-real-close");
|
|
20990
|
+
var head = null;
|
|
20991
|
+
var tail = null;
|
|
20992
|
+
var entriesByKey = new Map;
|
|
20993
|
+
var deferredEntries = new Set;
|
|
20994
|
+
function markAsPooled(provider) {
|
|
20995
|
+
const originalClose = provider.close;
|
|
20996
|
+
provider.close = () => {
|
|
20997
|
+
releaseProvider(provider);
|
|
20998
|
+
return Promise.resolve();
|
|
20999
|
+
};
|
|
21000
|
+
provider[POOLED_MARKER] = true;
|
|
21001
|
+
if (originalClose) {
|
|
21002
|
+
provider[REAL_CLOSE] = originalClose;
|
|
21003
|
+
}
|
|
21004
|
+
}
|
|
21005
|
+
function callRealClose(provider) {
|
|
21006
|
+
const realClose = provider[REAL_CLOSE];
|
|
21007
|
+
try {
|
|
21008
|
+
realClose?.call(provider);
|
|
21009
|
+
} catch (err) {
|
|
21010
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
21011
|
+
if (process.env.OPENCODE_SWARM_DEBUG === "1") {
|
|
21012
|
+
console.debug(`[provider-pool] real close failed: ${msg}`);
|
|
21013
|
+
}
|
|
21014
|
+
}
|
|
21015
|
+
}
|
|
21016
|
+
function isPooledProvider(provider) {
|
|
21017
|
+
return POOLED_MARKER in provider;
|
|
21018
|
+
}
|
|
21019
|
+
function getOrCreateProvider(directory, config) {
|
|
21020
|
+
const key = resolvePoolKey(directory);
|
|
21021
|
+
const existing = entriesByKey.get(key);
|
|
21022
|
+
if (existing) {
|
|
21023
|
+
moveToHead(existing);
|
|
21024
|
+
existing.refCount++;
|
|
21025
|
+
return existing.provider;
|
|
21026
|
+
}
|
|
21027
|
+
for (const deferred of deferredEntries) {
|
|
21028
|
+
if (deferred.key === key) {
|
|
21029
|
+
deferredEntries.delete(deferred);
|
|
21030
|
+
if (entriesByKey.size >= MAX_POOL_SIZE) {
|
|
21031
|
+
evictLru();
|
|
21032
|
+
}
|
|
21033
|
+
deferred.prev = null;
|
|
21034
|
+
deferred.next = head;
|
|
21035
|
+
if (head)
|
|
21036
|
+
head.prev = deferred;
|
|
21037
|
+
head = deferred;
|
|
21038
|
+
if (!tail)
|
|
21039
|
+
tail = deferred;
|
|
21040
|
+
entriesByKey.set(key, deferred);
|
|
21041
|
+
deferred.refCount++;
|
|
21042
|
+
return deferred.provider;
|
|
21043
|
+
}
|
|
21044
|
+
}
|
|
21045
|
+
const provider = new SQLiteMemoryProvider(directory, config);
|
|
21046
|
+
markAsPooled(provider);
|
|
21047
|
+
if (entriesByKey.size >= MAX_POOL_SIZE) {
|
|
21048
|
+
evictLru();
|
|
21049
|
+
}
|
|
21050
|
+
const entry = {
|
|
21051
|
+
key,
|
|
21052
|
+
provider,
|
|
21053
|
+
refCount: 1,
|
|
21054
|
+
prev: null,
|
|
21055
|
+
next: head
|
|
21056
|
+
};
|
|
21057
|
+
if (head)
|
|
21058
|
+
head.prev = entry;
|
|
21059
|
+
head = entry;
|
|
21060
|
+
if (!tail)
|
|
21061
|
+
tail = entry;
|
|
21062
|
+
entriesByKey.set(key, entry);
|
|
21063
|
+
return provider;
|
|
21064
|
+
}
|
|
21065
|
+
function releaseProvider(provider) {
|
|
21066
|
+
for (const [_key, entry] of entriesByKey) {
|
|
21067
|
+
if (entry.provider === provider) {
|
|
21068
|
+
entry.refCount = Math.max(0, entry.refCount - 1);
|
|
21069
|
+
return;
|
|
21070
|
+
}
|
|
21071
|
+
}
|
|
21072
|
+
for (const entry of deferredEntries) {
|
|
21073
|
+
if (entry.provider === provider) {
|
|
21074
|
+
entry.refCount--;
|
|
21075
|
+
if (entry.refCount <= 0) {
|
|
21076
|
+
deferredEntries.delete(entry);
|
|
21077
|
+
callRealClose(provider);
|
|
21078
|
+
}
|
|
21079
|
+
return;
|
|
21080
|
+
}
|
|
21081
|
+
}
|
|
21082
|
+
if (isPooledProvider(provider)) {
|
|
21083
|
+
callRealClose(provider);
|
|
21084
|
+
}
|
|
21085
|
+
}
|
|
21086
|
+
function evictLru() {
|
|
21087
|
+
if (!tail)
|
|
21088
|
+
return;
|
|
21089
|
+
const evicted = tail;
|
|
21090
|
+
entriesByKey.delete(evicted.key);
|
|
21091
|
+
unlinkEntry(evicted);
|
|
21092
|
+
if (evicted.refCount > 0) {
|
|
21093
|
+
deferredEntries.add(evicted);
|
|
21094
|
+
} else {
|
|
21095
|
+
callRealClose(evicted.provider);
|
|
21096
|
+
}
|
|
21097
|
+
}
|
|
21098
|
+
function moveToHead(entry) {
|
|
21099
|
+
if (head === entry)
|
|
21100
|
+
return;
|
|
21101
|
+
unlinkEntry(entry);
|
|
21102
|
+
entry.prev = null;
|
|
21103
|
+
entry.next = head;
|
|
21104
|
+
if (head)
|
|
21105
|
+
head.prev = entry;
|
|
21106
|
+
head = entry;
|
|
21107
|
+
if (!tail)
|
|
21108
|
+
tail = entry;
|
|
21109
|
+
}
|
|
21110
|
+
function unlinkEntry(entry) {
|
|
21111
|
+
if (entry.prev)
|
|
21112
|
+
entry.prev.next = entry.next;
|
|
21113
|
+
if (entry.next)
|
|
21114
|
+
entry.next.prev = entry.prev;
|
|
21115
|
+
if (head === entry)
|
|
21116
|
+
head = entry.next;
|
|
21117
|
+
if (tail === entry)
|
|
21118
|
+
tail = entry.prev;
|
|
21119
|
+
}
|
|
21120
|
+
function resolvePoolKey(directory) {
|
|
21121
|
+
try {
|
|
21122
|
+
return realpathSync2(directory);
|
|
21123
|
+
} catch {
|
|
21124
|
+
return path41.resolve(directory);
|
|
21125
|
+
}
|
|
21126
|
+
}
|
|
21127
|
+
|
|
20881
21128
|
// src/memory/gateway.ts
|
|
20882
21129
|
function createConfiguredMemoryProvider(directory, config) {
|
|
20883
21130
|
if (config.provider === "sqlite") {
|
|
20884
|
-
return
|
|
21131
|
+
return getOrCreateProvider(directory, config);
|
|
20885
21132
|
}
|
|
20886
21133
|
return new LocalJsonlMemoryProvider(directory, config);
|
|
20887
21134
|
}
|
|
20888
21135
|
var gitRemoteUrlCache = new Map;
|
|
21136
|
+
var RESERVED_IDENTIFIERS = new Set([
|
|
21137
|
+
"const",
|
|
21138
|
+
"let",
|
|
21139
|
+
"var",
|
|
21140
|
+
"function",
|
|
21141
|
+
"class",
|
|
21142
|
+
"interface",
|
|
21143
|
+
"type",
|
|
21144
|
+
"async",
|
|
21145
|
+
"await",
|
|
21146
|
+
"return",
|
|
21147
|
+
"if",
|
|
21148
|
+
"else",
|
|
21149
|
+
"for",
|
|
21150
|
+
"while",
|
|
21151
|
+
"do",
|
|
21152
|
+
"switch",
|
|
21153
|
+
"case",
|
|
21154
|
+
"break",
|
|
21155
|
+
"continue",
|
|
21156
|
+
"new",
|
|
21157
|
+
"this",
|
|
21158
|
+
"super",
|
|
21159
|
+
"extends",
|
|
21160
|
+
"implements",
|
|
21161
|
+
"import",
|
|
21162
|
+
"export",
|
|
21163
|
+
"from",
|
|
21164
|
+
"default",
|
|
21165
|
+
"try",
|
|
21166
|
+
"catch",
|
|
21167
|
+
"finally",
|
|
21168
|
+
"throw",
|
|
21169
|
+
"typeof",
|
|
21170
|
+
"instanceof",
|
|
21171
|
+
"in",
|
|
21172
|
+
"of",
|
|
21173
|
+
"as",
|
|
21174
|
+
"yield",
|
|
21175
|
+
"static",
|
|
21176
|
+
"get",
|
|
21177
|
+
"set",
|
|
21178
|
+
"readonly",
|
|
21179
|
+
"public",
|
|
21180
|
+
"private",
|
|
21181
|
+
"protected"
|
|
21182
|
+
]);
|
|
20889
21183
|
|
|
20890
21184
|
// src/memory/evaluation.ts
|
|
20891
21185
|
var DEFAULT_PROVIDERS = [
|
|
@@ -20899,7 +21193,7 @@ var DEFAULT_MODES = [
|
|
|
20899
21193
|
];
|
|
20900
21194
|
var DEFAULT_TIMESTAMP = "2026-05-26T12:00:00.000Z";
|
|
20901
21195
|
async function evaluateMemoryRecallFixtures(options) {
|
|
20902
|
-
const fixtureDirectory =
|
|
21196
|
+
const fixtureDirectory = path42.resolve(options.fixtureDirectory);
|
|
20903
21197
|
const providers = options.providers ?? DEFAULT_PROVIDERS;
|
|
20904
21198
|
const modes = options.modes ?? DEFAULT_MODES;
|
|
20905
21199
|
const generatedAt = new Date().toISOString();
|
|
@@ -20908,7 +21202,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
20908
21202
|
for (const fixture of fixtures) {
|
|
20909
21203
|
const materialized = materializeFixture(fixture);
|
|
20910
21204
|
for (const providerName of providers) {
|
|
20911
|
-
const tempRoot = await fs17.realpath(await fs17.mkdtemp(
|
|
21205
|
+
const tempRoot = await fs17.realpath(await fs17.mkdtemp(path42.join(os9.tmpdir(), "swarm-memory-eval-")));
|
|
20912
21206
|
const provider = createEvaluationProvider(providerName, tempRoot);
|
|
20913
21207
|
try {
|
|
20914
21208
|
await provider.initialize?.();
|
|
@@ -20952,7 +21246,7 @@ async function loadRecallEvaluationFixtures(fixtureDirectory) {
|
|
|
20952
21246
|
const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
20953
21247
|
const fixtures = [];
|
|
20954
21248
|
for (const file of files) {
|
|
20955
|
-
const raw = await fs17.readFile(
|
|
21249
|
+
const raw = await fs17.readFile(path42.join(fixtureDirectory, file), "utf-8");
|
|
20956
21250
|
fixtures.push(validateFixture(JSON.parse(raw), file));
|
|
20957
21251
|
}
|
|
20958
21252
|
return fixtures;
|
|
@@ -21228,7 +21522,7 @@ var CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
|
21228
21522
|
curatorMemoryDecisions: exports_external.array(CuratorMemoryDecisionSchema).max(20).optional()
|
|
21229
21523
|
}).passthrough();
|
|
21230
21524
|
// src/commands/memory.ts
|
|
21231
|
-
var PACKAGE_ROOT =
|
|
21525
|
+
var PACKAGE_ROOT = path43.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
|
|
21232
21526
|
async function handleMemoryCommand(_directory, _args) {
|
|
21233
21527
|
return [
|
|
21234
21528
|
"## Swarm Memory",
|
|
@@ -21497,7 +21791,7 @@ function resolveCommandMemoryConfig(directory) {
|
|
|
21497
21791
|
}
|
|
21498
21792
|
function parseEvaluateArgs(directory, args) {
|
|
21499
21793
|
let json = false;
|
|
21500
|
-
let fixtureDirectory =
|
|
21794
|
+
let fixtureDirectory = path43.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
|
|
21501
21795
|
for (let i = 0;i < args.length; i++) {
|
|
21502
21796
|
const arg = args[i];
|
|
21503
21797
|
if (arg === "--json") {
|
|
@@ -21511,10 +21805,10 @@ function parseEvaluateArgs(directory, args) {
|
|
|
21511
21805
|
error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
|
|
21512
21806
|
};
|
|
21513
21807
|
}
|
|
21514
|
-
const resolvedFixtures =
|
|
21515
|
-
const canonical =
|
|
21516
|
-
const allowedRootA =
|
|
21517
|
-
const allowedRootB =
|
|
21808
|
+
const resolvedFixtures = path43.resolve(directory, next);
|
|
21809
|
+
const canonical = path43.normalize(resolvedFixtures) + path43.sep;
|
|
21810
|
+
const allowedRootA = path43.normalize(directory) + path43.sep;
|
|
21811
|
+
const allowedRootB = path43.normalize(path43.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path43.sep;
|
|
21518
21812
|
if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
|
|
21519
21813
|
return {
|
|
21520
21814
|
error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
|
|
@@ -21553,15 +21847,15 @@ function parseMaintenanceArgs(args, options) {
|
|
|
21553
21847
|
return { limit, confirm };
|
|
21554
21848
|
}
|
|
21555
21849
|
function resolvePackageRootFromModule(modulePath) {
|
|
21556
|
-
const moduleDir =
|
|
21557
|
-
const leaf =
|
|
21850
|
+
const moduleDir = path43.dirname(modulePath);
|
|
21851
|
+
const leaf = path43.basename(moduleDir);
|
|
21558
21852
|
if (leaf === "commands" || leaf === "cli") {
|
|
21559
|
-
return
|
|
21853
|
+
return path43.resolve(moduleDir, "..", "..");
|
|
21560
21854
|
}
|
|
21561
21855
|
if (leaf === "dist") {
|
|
21562
|
-
return
|
|
21856
|
+
return path43.resolve(moduleDir, "..");
|
|
21563
21857
|
}
|
|
21564
|
-
return
|
|
21858
|
+
return path43.resolve(moduleDir, "..");
|
|
21565
21859
|
}
|
|
21566
21860
|
function formatMigrationResult(label, report) {
|
|
21567
21861
|
if (!report) {
|
|
@@ -22000,31 +22294,35 @@ var _internals34 = {
|
|
|
22000
22294
|
formatRelativeTime,
|
|
22001
22295
|
listActive
|
|
22002
22296
|
};
|
|
22003
|
-
async function handlePrMonitorStatusCommand(directory, _args, sessionID) {
|
|
22297
|
+
async function handlePrMonitorStatusCommand(directory, _args, sessionID, source) {
|
|
22004
22298
|
const allActive = await _internals34.listActive(directory);
|
|
22005
|
-
const
|
|
22006
|
-
|
|
22007
|
-
|
|
22299
|
+
const allSessions = source === "cli";
|
|
22300
|
+
const subs = allSessions ? allActive : allActive.filter((record) => record.sessionID === sessionID);
|
|
22301
|
+
if (subs.length === 0) {
|
|
22302
|
+
return allSessions ? "No active PR subscriptions." : "No active PR subscriptions for this session.";
|
|
22008
22303
|
}
|
|
22009
22304
|
const lines = [];
|
|
22010
|
-
lines.push(`PR Monitor Status \u2014 Session: ${sessionID}`);
|
|
22305
|
+
lines.push(allSessions ? "PR Monitor Status \u2014 all sessions" : `PR Monitor Status \u2014 Session: ${sessionID}`);
|
|
22011
22306
|
lines.push("");
|
|
22012
22307
|
const totalActive = allActive.length;
|
|
22013
|
-
lines.push(`Active subscriptions (${
|
|
22014
|
-
for (let i = 0;i <
|
|
22015
|
-
const sub =
|
|
22308
|
+
lines.push(`Active subscriptions (${subs.length}):`);
|
|
22309
|
+
for (let i = 0;i < subs.length; i++) {
|
|
22310
|
+
const sub = subs[i];
|
|
22016
22311
|
const index = i + 1;
|
|
22017
22312
|
lines.push(` ${index}. ${sub.repoFullName}#${sub.prNumber}`);
|
|
22018
22313
|
lines.push(` URL: ${sub.prUrl}`);
|
|
22314
|
+
if (allSessions) {
|
|
22315
|
+
lines.push(` Session: ${sub.sessionID}`);
|
|
22316
|
+
}
|
|
22019
22317
|
lines.push(` Last checked: ${formatRelativeTime(sub.lastCheckedAt)}`);
|
|
22020
22318
|
lines.push(` Watching: ${sub.isWatching ? "yes" : "no"}`);
|
|
22021
22319
|
lines.push(` Errors: ${sub.errorCount}`);
|
|
22022
|
-
if (i <
|
|
22320
|
+
if (i < subs.length - 1) {
|
|
22023
22321
|
lines.push("");
|
|
22024
22322
|
}
|
|
22025
22323
|
}
|
|
22026
22324
|
lines.push("");
|
|
22027
|
-
if (totalActive !==
|
|
22325
|
+
if (!allSessions && totalActive !== subs.length) {
|
|
22028
22326
|
lines.push(`Total active across all sessions: ${totalActive}`);
|
|
22029
22327
|
}
|
|
22030
22328
|
return lines.join(`
|
|
@@ -22121,6 +22419,15 @@ async function handlePrSubscribeCommand(directory, args, sessionID) {
|
|
|
22121
22419
|
"Expected: full GitHub URL, owner/repo#N shorthand,",
|
|
22122
22420
|
"or a bare PR number (resolved against origin)."
|
|
22123
22421
|
].join(`
|
|
22422
|
+
`);
|
|
22423
|
+
}
|
|
22424
|
+
if (!sessionID || sessionID.trim() === "") {
|
|
22425
|
+
return [
|
|
22426
|
+
"Error: Cannot subscribe \u2014 no active session.",
|
|
22427
|
+
"",
|
|
22428
|
+
"PR subscriptions are session-scoped and require a live OpenCode session.",
|
|
22429
|
+
"Subscribe from inside OpenCode; the bunx CLI has no session context."
|
|
22430
|
+
].join(`
|
|
22124
22431
|
`);
|
|
22125
22432
|
}
|
|
22126
22433
|
const repoFullName = `${prInfo.owner}/${prInfo.repo}`;
|
|
@@ -22243,11 +22550,11 @@ var _internals36 = {
|
|
|
22243
22550
|
|
|
22244
22551
|
// src/services/preflight-service.ts
|
|
22245
22552
|
import * as fs24 from "fs";
|
|
22246
|
-
import * as
|
|
22553
|
+
import * as path50 from "path";
|
|
22247
22554
|
|
|
22248
22555
|
// src/tools/lint.ts
|
|
22249
22556
|
import * as fs18 from "fs";
|
|
22250
|
-
import * as
|
|
22557
|
+
import * as path44 from "path";
|
|
22251
22558
|
|
|
22252
22559
|
// src/utils/path-security.ts
|
|
22253
22560
|
function containsPathTraversal(str) {
|
|
@@ -22303,9 +22610,9 @@ function validateArgs(args) {
|
|
|
22303
22610
|
}
|
|
22304
22611
|
function getLinterCommand(linter, mode, projectDir) {
|
|
22305
22612
|
const isWindows = process.platform === "win32";
|
|
22306
|
-
const binDir =
|
|
22307
|
-
const biomeBin = isWindows ?
|
|
22308
|
-
const eslintBin = isWindows ?
|
|
22613
|
+
const binDir = path44.join(projectDir, "node_modules", ".bin");
|
|
22614
|
+
const biomeBin = isWindows ? path44.join(binDir, "biome.EXE") : path44.join(binDir, "biome");
|
|
22615
|
+
const eslintBin = isWindows ? path44.join(binDir, "eslint.cmd") : path44.join(binDir, "eslint");
|
|
22309
22616
|
switch (linter) {
|
|
22310
22617
|
case "biome":
|
|
22311
22618
|
if (mode === "fix") {
|
|
@@ -22321,7 +22628,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
22321
22628
|
}
|
|
22322
22629
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
22323
22630
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
22324
|
-
const gradlew = fs18.existsSync(
|
|
22631
|
+
const gradlew = fs18.existsSync(path44.join(cwd, gradlewName)) ? path44.join(cwd, gradlewName) : null;
|
|
22325
22632
|
switch (linter) {
|
|
22326
22633
|
case "ruff":
|
|
22327
22634
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -22355,10 +22662,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
22355
22662
|
}
|
|
22356
22663
|
}
|
|
22357
22664
|
function detectRuff(cwd) {
|
|
22358
|
-
if (fs18.existsSync(
|
|
22665
|
+
if (fs18.existsSync(path44.join(cwd, "ruff.toml")))
|
|
22359
22666
|
return isCommandAvailable("ruff");
|
|
22360
22667
|
try {
|
|
22361
|
-
const pyproject =
|
|
22668
|
+
const pyproject = path44.join(cwd, "pyproject.toml");
|
|
22362
22669
|
if (fs18.existsSync(pyproject)) {
|
|
22363
22670
|
const content = fs18.readFileSync(pyproject, "utf-8");
|
|
22364
22671
|
if (content.includes("[tool.ruff]"))
|
|
@@ -22368,19 +22675,19 @@ function detectRuff(cwd) {
|
|
|
22368
22675
|
return false;
|
|
22369
22676
|
}
|
|
22370
22677
|
function detectClippy(cwd) {
|
|
22371
|
-
return fs18.existsSync(
|
|
22678
|
+
return fs18.existsSync(path44.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
22372
22679
|
}
|
|
22373
22680
|
function detectGolangciLint(cwd) {
|
|
22374
|
-
return fs18.existsSync(
|
|
22681
|
+
return fs18.existsSync(path44.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
22375
22682
|
}
|
|
22376
22683
|
function detectCheckstyle(cwd) {
|
|
22377
|
-
const hasMaven = fs18.existsSync(
|
|
22378
|
-
const hasGradle = fs18.existsSync(
|
|
22379
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(
|
|
22684
|
+
const hasMaven = fs18.existsSync(path44.join(cwd, "pom.xml"));
|
|
22685
|
+
const hasGradle = fs18.existsSync(path44.join(cwd, "build.gradle")) || fs18.existsSync(path44.join(cwd, "build.gradle.kts"));
|
|
22686
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(path44.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
22380
22687
|
return (hasMaven || hasGradle) && hasBinary;
|
|
22381
22688
|
}
|
|
22382
22689
|
function detectKtlint(cwd) {
|
|
22383
|
-
const hasKotlin = fs18.existsSync(
|
|
22690
|
+
const hasKotlin = fs18.existsSync(path44.join(cwd, "build.gradle.kts")) || fs18.existsSync(path44.join(cwd, "build.gradle")) || (() => {
|
|
22384
22691
|
try {
|
|
22385
22692
|
return fs18.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
22386
22693
|
} catch {
|
|
@@ -22399,11 +22706,11 @@ function detectDotnetFormat(cwd) {
|
|
|
22399
22706
|
}
|
|
22400
22707
|
}
|
|
22401
22708
|
function detectCppcheck(cwd) {
|
|
22402
|
-
if (fs18.existsSync(
|
|
22709
|
+
if (fs18.existsSync(path44.join(cwd, "CMakeLists.txt"))) {
|
|
22403
22710
|
return isCommandAvailable("cppcheck");
|
|
22404
22711
|
}
|
|
22405
22712
|
try {
|
|
22406
|
-
const dirsToCheck = [cwd,
|
|
22713
|
+
const dirsToCheck = [cwd, path44.join(cwd, "src")];
|
|
22407
22714
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
22408
22715
|
try {
|
|
22409
22716
|
return fs18.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -22417,13 +22724,13 @@ function detectCppcheck(cwd) {
|
|
|
22417
22724
|
}
|
|
22418
22725
|
}
|
|
22419
22726
|
function detectSwiftlint(cwd) {
|
|
22420
|
-
return fs18.existsSync(
|
|
22727
|
+
return fs18.existsSync(path44.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
22421
22728
|
}
|
|
22422
22729
|
function detectDartAnalyze(cwd) {
|
|
22423
|
-
return fs18.existsSync(
|
|
22730
|
+
return fs18.existsSync(path44.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
22424
22731
|
}
|
|
22425
22732
|
function detectRubocop(cwd) {
|
|
22426
|
-
return (fs18.existsSync(
|
|
22733
|
+
return (fs18.existsSync(path44.join(cwd, "Gemfile")) || fs18.existsSync(path44.join(cwd, "gems.rb")) || fs18.existsSync(path44.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
22427
22734
|
}
|
|
22428
22735
|
function detectAdditionalLinter(cwd) {
|
|
22429
22736
|
if (detectRuff(cwd))
|
|
@@ -22451,10 +22758,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
22451
22758
|
function findBinInAncestors(startDir, binName) {
|
|
22452
22759
|
let dir = startDir;
|
|
22453
22760
|
while (true) {
|
|
22454
|
-
const candidate =
|
|
22761
|
+
const candidate = path44.join(dir, "node_modules", ".bin", binName);
|
|
22455
22762
|
if (fs18.existsSync(candidate))
|
|
22456
22763
|
return candidate;
|
|
22457
|
-
const parent =
|
|
22764
|
+
const parent = path44.dirname(dir);
|
|
22458
22765
|
if (parent === dir)
|
|
22459
22766
|
break;
|
|
22460
22767
|
dir = parent;
|
|
@@ -22463,10 +22770,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
22463
22770
|
}
|
|
22464
22771
|
function findBinInEnvPath(binName) {
|
|
22465
22772
|
const searchPath = process.env.PATH ?? "";
|
|
22466
|
-
for (const dir of searchPath.split(
|
|
22773
|
+
for (const dir of searchPath.split(path44.delimiter)) {
|
|
22467
22774
|
if (!dir)
|
|
22468
22775
|
continue;
|
|
22469
|
-
const candidate =
|
|
22776
|
+
const candidate = path44.join(dir, binName);
|
|
22470
22777
|
if (fs18.existsSync(candidate))
|
|
22471
22778
|
return candidate;
|
|
22472
22779
|
}
|
|
@@ -22479,13 +22786,13 @@ async function detectAvailableLinter(directory) {
|
|
|
22479
22786
|
return null;
|
|
22480
22787
|
const projectDir = directory;
|
|
22481
22788
|
const isWindows = process.platform === "win32";
|
|
22482
|
-
const biomeBin = isWindows ?
|
|
22483
|
-
const eslintBin = isWindows ?
|
|
22789
|
+
const biomeBin = isWindows ? path44.join(projectDir, "node_modules", ".bin", "biome.EXE") : path44.join(projectDir, "node_modules", ".bin", "biome");
|
|
22790
|
+
const eslintBin = isWindows ? path44.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path44.join(projectDir, "node_modules", ".bin", "eslint");
|
|
22484
22791
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
22485
22792
|
if (localResult)
|
|
22486
22793
|
return localResult;
|
|
22487
|
-
const biomeAncestor = findBinInAncestors(
|
|
22488
|
-
const eslintAncestor = findBinInAncestors(
|
|
22794
|
+
const biomeAncestor = findBinInAncestors(path44.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
22795
|
+
const eslintAncestor = findBinInAncestors(path44.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
22489
22796
|
if (biomeAncestor || eslintAncestor) {
|
|
22490
22797
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
22491
22798
|
}
|
|
@@ -22504,7 +22811,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
22504
22811
|
stderr: "pipe"
|
|
22505
22812
|
});
|
|
22506
22813
|
const biomeExit = biomeProc.exited;
|
|
22507
|
-
const timeout = new Promise((
|
|
22814
|
+
const timeout = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), DETECT_TIMEOUT));
|
|
22508
22815
|
const result = await Promise.race([biomeExit, timeout]);
|
|
22509
22816
|
if (result === "timeout") {
|
|
22510
22817
|
biomeProc.kill();
|
|
@@ -22518,7 +22825,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
22518
22825
|
stderr: "pipe"
|
|
22519
22826
|
});
|
|
22520
22827
|
const eslintExit = eslintProc.exited;
|
|
22521
|
-
const timeout = new Promise((
|
|
22828
|
+
const timeout = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), DETECT_TIMEOUT));
|
|
22522
22829
|
const result = await Promise.race([eslintExit, timeout]);
|
|
22523
22830
|
if (result === "timeout") {
|
|
22524
22831
|
eslintProc.kill();
|
|
@@ -22699,7 +23006,7 @@ var _internals37 = {
|
|
|
22699
23006
|
|
|
22700
23007
|
// src/tools/secretscan.ts
|
|
22701
23008
|
import * as fs19 from "fs";
|
|
22702
|
-
import * as
|
|
23009
|
+
import * as path45 from "path";
|
|
22703
23010
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
22704
23011
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
22705
23012
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -22926,7 +23233,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
22926
23233
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
22927
23234
|
}
|
|
22928
23235
|
function loadSecretScanIgnore(scanDir) {
|
|
22929
|
-
const ignorePath =
|
|
23236
|
+
const ignorePath = path45.join(scanDir, ".secretscanignore");
|
|
22930
23237
|
try {
|
|
22931
23238
|
if (!fs19.existsSync(ignorePath))
|
|
22932
23239
|
return [];
|
|
@@ -22949,7 +23256,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
22949
23256
|
if (exactNames.has(entry))
|
|
22950
23257
|
return true;
|
|
22951
23258
|
for (const pattern of globPatterns) {
|
|
22952
|
-
if (
|
|
23259
|
+
if (path45.matchesGlob(relPath, pattern))
|
|
22953
23260
|
return true;
|
|
22954
23261
|
}
|
|
22955
23262
|
return false;
|
|
@@ -22970,7 +23277,7 @@ function validateDirectoryInput(dir) {
|
|
|
22970
23277
|
return null;
|
|
22971
23278
|
}
|
|
22972
23279
|
function isBinaryFile(filePath, buffer) {
|
|
22973
|
-
const ext =
|
|
23280
|
+
const ext = path45.extname(filePath).toLowerCase();
|
|
22974
23281
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
22975
23282
|
return true;
|
|
22976
23283
|
}
|
|
@@ -23107,9 +23414,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
23107
23414
|
return false;
|
|
23108
23415
|
}
|
|
23109
23416
|
function isPathWithinScope(realPath, scanDir) {
|
|
23110
|
-
const resolvedScanDir =
|
|
23111
|
-
const resolvedRealPath =
|
|
23112
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
23417
|
+
const resolvedScanDir = path45.resolve(scanDir);
|
|
23418
|
+
const resolvedRealPath = path45.resolve(realPath);
|
|
23419
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path45.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
23113
23420
|
}
|
|
23114
23421
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
23115
23422
|
skippedDirs: 0,
|
|
@@ -23135,8 +23442,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
23135
23442
|
return a.localeCompare(b);
|
|
23136
23443
|
});
|
|
23137
23444
|
for (const entry of entries) {
|
|
23138
|
-
const fullPath =
|
|
23139
|
-
const relPath =
|
|
23445
|
+
const fullPath = path45.join(dir, entry);
|
|
23446
|
+
const relPath = path45.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
23140
23447
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
23141
23448
|
stats.skippedDirs++;
|
|
23142
23449
|
continue;
|
|
@@ -23171,7 +23478,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
23171
23478
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
23172
23479
|
files.push(...subFiles);
|
|
23173
23480
|
} else if (lstat2.isFile()) {
|
|
23174
|
-
const ext =
|
|
23481
|
+
const ext = path45.extname(fullPath).toLowerCase();
|
|
23175
23482
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
23176
23483
|
files.push(fullPath);
|
|
23177
23484
|
} else {
|
|
@@ -23237,7 +23544,7 @@ var secretscan = createSwarmTool({
|
|
|
23237
23544
|
}
|
|
23238
23545
|
}
|
|
23239
23546
|
try {
|
|
23240
|
-
const _scanDirRaw =
|
|
23547
|
+
const _scanDirRaw = path45.resolve(directory);
|
|
23241
23548
|
const scanDir = (() => {
|
|
23242
23549
|
try {
|
|
23243
23550
|
return fs19.realpathSync(_scanDirRaw);
|
|
@@ -23400,11 +23707,11 @@ var _internals38 = {
|
|
|
23400
23707
|
|
|
23401
23708
|
// src/tools/test-runner.ts
|
|
23402
23709
|
import * as fs23 from "fs";
|
|
23403
|
-
import * as
|
|
23710
|
+
import * as path49 from "path";
|
|
23404
23711
|
|
|
23405
23712
|
// src/test-impact/analyzer.ts
|
|
23406
23713
|
import fs20 from "fs";
|
|
23407
|
-
import
|
|
23714
|
+
import path46 from "path";
|
|
23408
23715
|
var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
23409
23716
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
23410
23717
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -23445,8 +23752,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
23445
23752
|
if (!importPath.startsWith(".")) {
|
|
23446
23753
|
return null;
|
|
23447
23754
|
}
|
|
23448
|
-
const resolved =
|
|
23449
|
-
if (
|
|
23755
|
+
const resolved = path46.resolve(fromDir, importPath);
|
|
23756
|
+
if (path46.extname(resolved)) {
|
|
23450
23757
|
if (fs20.existsSync(resolved) && fs20.statSync(resolved).isFile()) {
|
|
23451
23758
|
return normalizePath2(resolved);
|
|
23452
23759
|
}
|
|
@@ -23466,20 +23773,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
23466
23773
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
23467
23774
|
let baseDir = fromDir;
|
|
23468
23775
|
for (let i = 1;i < leadingDots; i++) {
|
|
23469
|
-
baseDir =
|
|
23776
|
+
baseDir = path46.dirname(baseDir);
|
|
23470
23777
|
}
|
|
23471
23778
|
const rest = module.slice(leadingDots);
|
|
23472
23779
|
if (rest.length === 0) {
|
|
23473
|
-
const initPath =
|
|
23780
|
+
const initPath = path46.join(baseDir, "__init__.py");
|
|
23474
23781
|
if (fs20.existsSync(initPath) && fs20.statSync(initPath).isFile()) {
|
|
23475
23782
|
return normalizePath2(initPath);
|
|
23476
23783
|
}
|
|
23477
23784
|
return null;
|
|
23478
23785
|
}
|
|
23479
|
-
const subpath = rest.replace(/\./g,
|
|
23786
|
+
const subpath = rest.replace(/\./g, path46.sep);
|
|
23480
23787
|
const candidates = [
|
|
23481
|
-
`${
|
|
23482
|
-
|
|
23788
|
+
`${path46.join(baseDir, subpath)}.py`,
|
|
23789
|
+
path46.join(baseDir, subpath, "__init__.py")
|
|
23483
23790
|
];
|
|
23484
23791
|
for (const c of candidates) {
|
|
23485
23792
|
if (fs20.existsSync(c) && fs20.statSync(c).isFile())
|
|
@@ -23489,7 +23796,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
23489
23796
|
}
|
|
23490
23797
|
var goModuleCache = new Map;
|
|
23491
23798
|
function findGoModule(fromDir) {
|
|
23492
|
-
const resolved =
|
|
23799
|
+
const resolved = path46.resolve(fromDir);
|
|
23493
23800
|
let cur = resolved;
|
|
23494
23801
|
const walked = [];
|
|
23495
23802
|
for (let i = 0;i < 16; i++) {
|
|
@@ -23501,7 +23808,7 @@ function findGoModule(fromDir) {
|
|
|
23501
23808
|
}
|
|
23502
23809
|
walked.push(cur);
|
|
23503
23810
|
try {
|
|
23504
|
-
const goMod =
|
|
23811
|
+
const goMod = path46.join(cur, "go.mod");
|
|
23505
23812
|
const content = fs20.readFileSync(goMod, "utf-8");
|
|
23506
23813
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
23507
23814
|
if (moduleMatch) {
|
|
@@ -23512,10 +23819,10 @@ function findGoModule(fromDir) {
|
|
|
23512
23819
|
}
|
|
23513
23820
|
} catch {}
|
|
23514
23821
|
try {
|
|
23515
|
-
fs20.accessSync(
|
|
23822
|
+
fs20.accessSync(path46.join(cur, ".git"));
|
|
23516
23823
|
break;
|
|
23517
23824
|
} catch {}
|
|
23518
|
-
const parent =
|
|
23825
|
+
const parent = path46.dirname(cur);
|
|
23519
23826
|
if (parent === cur)
|
|
23520
23827
|
break;
|
|
23521
23828
|
cur = parent;
|
|
@@ -23527,12 +23834,12 @@ function findGoModule(fromDir) {
|
|
|
23527
23834
|
function resolveGoImport(fromDir, importPath) {
|
|
23528
23835
|
let dir = null;
|
|
23529
23836
|
if (importPath.startsWith(".")) {
|
|
23530
|
-
dir =
|
|
23837
|
+
dir = path46.resolve(fromDir, importPath);
|
|
23531
23838
|
} else {
|
|
23532
23839
|
const mod = findGoModule(fromDir);
|
|
23533
23840
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
23534
23841
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
23535
|
-
dir =
|
|
23842
|
+
dir = path46.join(mod.moduleRoot, subpath);
|
|
23536
23843
|
}
|
|
23537
23844
|
}
|
|
23538
23845
|
if (dir === null)
|
|
@@ -23540,7 +23847,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
23540
23847
|
if (!fs20.existsSync(dir) || !fs20.statSync(dir).isDirectory())
|
|
23541
23848
|
return [];
|
|
23542
23849
|
try {
|
|
23543
|
-
return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(
|
|
23850
|
+
return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path46.join(dir, f)));
|
|
23544
23851
|
} catch {
|
|
23545
23852
|
return [];
|
|
23546
23853
|
}
|
|
@@ -23579,15 +23886,15 @@ function findTestFilesSync(cwd) {
|
|
|
23579
23886
|
for (const entry of entries) {
|
|
23580
23887
|
if (entry.isDirectory()) {
|
|
23581
23888
|
if (!skipDirs.has(entry.name)) {
|
|
23582
|
-
walk(
|
|
23889
|
+
walk(path46.join(dir, entry.name), visitedInodes);
|
|
23583
23890
|
}
|
|
23584
23891
|
} else if (entry.isFile()) {
|
|
23585
23892
|
const name = entry.name;
|
|
23586
23893
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
23587
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
23894
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path46.sep}tests${path46.sep}`) && name.endsWith(".py");
|
|
23588
23895
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
23589
23896
|
if (isTsTest || isPyTest || isGoTest) {
|
|
23590
|
-
testFiles.push(normalizePath2(
|
|
23897
|
+
testFiles.push(normalizePath2(path46.join(dir, entry.name)));
|
|
23591
23898
|
}
|
|
23592
23899
|
}
|
|
23593
23900
|
}
|
|
@@ -23612,8 +23919,8 @@ function extractImports(content) {
|
|
|
23612
23919
|
];
|
|
23613
23920
|
}
|
|
23614
23921
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
23615
|
-
const ext =
|
|
23616
|
-
const testDir =
|
|
23922
|
+
const ext = path46.extname(testFile).toLowerCase();
|
|
23923
|
+
const testDir = path46.dirname(testFile);
|
|
23617
23924
|
function addEdge(source) {
|
|
23618
23925
|
if (!impactMap[source])
|
|
23619
23926
|
impactMap[source] = [];
|
|
@@ -23686,7 +23993,7 @@ async function buildImpactMap(cwd) {
|
|
|
23686
23993
|
return impactMap;
|
|
23687
23994
|
}
|
|
23688
23995
|
async function loadImpactMap(cwd, options) {
|
|
23689
|
-
const cachePath =
|
|
23996
|
+
const cachePath = path46.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
23690
23997
|
if (fs20.existsSync(cachePath)) {
|
|
23691
23998
|
try {
|
|
23692
23999
|
const content = fs20.readFileSync(cachePath, "utf-8");
|
|
@@ -23719,12 +24026,12 @@ async function loadImpactMap(cwd, options) {
|
|
|
23719
24026
|
return _internals39.buildImpactMap(cwd);
|
|
23720
24027
|
}
|
|
23721
24028
|
async function saveImpactMap(cwd, impactMap) {
|
|
23722
|
-
if (!
|
|
24029
|
+
if (!path46.isAbsolute(cwd)) {
|
|
23723
24030
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
23724
24031
|
}
|
|
23725
24032
|
_internals39.validateProjectRoot(cwd);
|
|
23726
|
-
const cacheDir2 =
|
|
23727
|
-
const cachePath =
|
|
24033
|
+
const cacheDir2 = path46.join(cwd, ".swarm", "cache");
|
|
24034
|
+
const cachePath = path46.join(cacheDir2, "impact-map.json");
|
|
23728
24035
|
if (!fs20.existsSync(cacheDir2)) {
|
|
23729
24036
|
fs20.mkdirSync(cacheDir2, { recursive: true });
|
|
23730
24037
|
}
|
|
@@ -23756,7 +24063,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
23756
24063
|
budgetExceeded = true;
|
|
23757
24064
|
break;
|
|
23758
24065
|
}
|
|
23759
|
-
const normalizedChanged = normalizePath2(
|
|
24066
|
+
const normalizedChanged = normalizePath2(path46.resolve(changedFile));
|
|
23760
24067
|
const tests = impactMap[normalizedChanged];
|
|
23761
24068
|
if (tests && tests.length > 0) {
|
|
23762
24069
|
for (const test of tests) {
|
|
@@ -23770,13 +24077,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
23770
24077
|
if (budgetExceeded)
|
|
23771
24078
|
break;
|
|
23772
24079
|
} else {
|
|
23773
|
-
const changedDir = normalizePath2(
|
|
23774
|
-
const changedInputDir = normalizePath2(
|
|
24080
|
+
const changedDir = normalizePath2(path46.dirname(normalizedChanged));
|
|
24081
|
+
const changedInputDir = normalizePath2(path46.dirname(changedFile));
|
|
23775
24082
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
23776
24083
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
23777
24084
|
}).sort(([sourceA], [sourceB]) => {
|
|
23778
|
-
const sourceDirA = normalizePath2(
|
|
23779
|
-
const sourceDirB = normalizePath2(
|
|
24085
|
+
const sourceDirA = normalizePath2(path46.dirname(sourceA));
|
|
24086
|
+
const sourceDirB = normalizePath2(path46.dirname(sourceB));
|
|
23780
24087
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
23781
24088
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
23782
24089
|
if (exactA !== exactB)
|
|
@@ -24103,7 +24410,7 @@ function detectFlakyTests(allHistory) {
|
|
|
24103
24410
|
|
|
24104
24411
|
// src/test-impact/history-store.ts
|
|
24105
24412
|
import fs21 from "fs";
|
|
24106
|
-
import
|
|
24413
|
+
import path47 from "path";
|
|
24107
24414
|
var MAX_HISTORY_PER_TEST = 20;
|
|
24108
24415
|
var MAX_ERROR_LENGTH = 500;
|
|
24109
24416
|
var MAX_STACK_LENGTH = 200;
|
|
@@ -24115,10 +24422,10 @@ function getHistoryPath(workingDir) {
|
|
|
24115
24422
|
if (!workingDir) {
|
|
24116
24423
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
24117
24424
|
}
|
|
24118
|
-
if (!
|
|
24425
|
+
if (!path47.isAbsolute(workingDir)) {
|
|
24119
24426
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
24120
24427
|
}
|
|
24121
|
-
return
|
|
24428
|
+
return path47.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
24122
24429
|
}
|
|
24123
24430
|
function sanitizeErrorMessage(errorMessage) {
|
|
24124
24431
|
if (errorMessage === undefined) {
|
|
@@ -24210,7 +24517,7 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
24210
24517
|
}
|
|
24211
24518
|
}
|
|
24212
24519
|
const historyPath = getHistoryPath(workingDir);
|
|
24213
|
-
const historyDir =
|
|
24520
|
+
const historyDir = path47.dirname(historyPath);
|
|
24214
24521
|
_internals40.validateProjectRoot(workingDir);
|
|
24215
24522
|
if (!fs21.existsSync(historyDir)) {
|
|
24216
24523
|
fs21.mkdirSync(historyDir, { recursive: true });
|
|
@@ -24340,7 +24647,7 @@ var _internals40 = {
|
|
|
24340
24647
|
|
|
24341
24648
|
// src/tools/resolve-working-directory.ts
|
|
24342
24649
|
import * as fs22 from "fs";
|
|
24343
|
-
import * as
|
|
24650
|
+
import * as path48 from "path";
|
|
24344
24651
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
24345
24652
|
if (workingDirectory == null || workingDirectory === "") {
|
|
24346
24653
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -24372,15 +24679,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24372
24679
|
};
|
|
24373
24680
|
}
|
|
24374
24681
|
}
|
|
24375
|
-
const rawPathParts = workingDirectory.split(
|
|
24682
|
+
const rawPathParts = workingDirectory.split(path48.sep);
|
|
24376
24683
|
if (rawPathParts.includes("..")) {
|
|
24377
24684
|
return {
|
|
24378
24685
|
success: false,
|
|
24379
24686
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
24380
24687
|
};
|
|
24381
24688
|
}
|
|
24382
|
-
const normalizedDir =
|
|
24383
|
-
const resolvedDir =
|
|
24689
|
+
const normalizedDir = path48.normalize(workingDirectory);
|
|
24690
|
+
const resolvedDir = path48.resolve(normalizedDir);
|
|
24384
24691
|
let statResult;
|
|
24385
24692
|
try {
|
|
24386
24693
|
statResult = fs22.statSync(resolvedDir);
|
|
@@ -24399,7 +24706,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24399
24706
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
24400
24707
|
return { success: true, directory: resolvedDir };
|
|
24401
24708
|
}
|
|
24402
|
-
const resolvedFallback =
|
|
24709
|
+
const resolvedFallback = path48.resolve(fallbackDirectory);
|
|
24403
24710
|
let fallbackExists = false;
|
|
24404
24711
|
try {
|
|
24405
24712
|
fs22.statSync(resolvedFallback);
|
|
@@ -24408,7 +24715,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24408
24715
|
fallbackExists = false;
|
|
24409
24716
|
}
|
|
24410
24717
|
if (fallbackExists) {
|
|
24411
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
24718
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path48.sep);
|
|
24412
24719
|
if (isSubdirectory) {
|
|
24413
24720
|
return {
|
|
24414
24721
|
success: false,
|
|
@@ -24431,7 +24738,7 @@ async function estimateFanOut(sourceFiles, cwd) {
|
|
|
24431
24738
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
24432
24739
|
const uniqueTestFiles = new Set;
|
|
24433
24740
|
for (const sourceFile of sourceFiles) {
|
|
24434
|
-
const resolvedPath =
|
|
24741
|
+
const resolvedPath = path49.resolve(cwd, sourceFile);
|
|
24435
24742
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
24436
24743
|
const testFiles = impactMap[normalizedPath];
|
|
24437
24744
|
if (testFiles) {
|
|
@@ -24516,14 +24823,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
24516
24823
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
24517
24824
|
}
|
|
24518
24825
|
function detectGoTest(cwd) {
|
|
24519
|
-
return fs23.existsSync(
|
|
24826
|
+
return fs23.existsSync(path49.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
24520
24827
|
}
|
|
24521
24828
|
function detectJavaMaven(cwd) {
|
|
24522
|
-
return fs23.existsSync(
|
|
24829
|
+
return fs23.existsSync(path49.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
24523
24830
|
}
|
|
24524
24831
|
function detectGradle(cwd) {
|
|
24525
|
-
const hasBuildFile = fs23.existsSync(
|
|
24526
|
-
const hasGradlew = fs23.existsSync(
|
|
24832
|
+
const hasBuildFile = fs23.existsSync(path49.join(cwd, "build.gradle")) || fs23.existsSync(path49.join(cwd, "build.gradle.kts"));
|
|
24833
|
+
const hasGradlew = fs23.existsSync(path49.join(cwd, "gradlew")) || fs23.existsSync(path49.join(cwd, "gradlew.bat"));
|
|
24527
24834
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
24528
24835
|
}
|
|
24529
24836
|
function detectDotnetTest(cwd) {
|
|
@@ -24536,25 +24843,25 @@ function detectDotnetTest(cwd) {
|
|
|
24536
24843
|
}
|
|
24537
24844
|
}
|
|
24538
24845
|
function detectCTest(cwd) {
|
|
24539
|
-
const hasSource = fs23.existsSync(
|
|
24540
|
-
const hasBuildCache = fs23.existsSync(
|
|
24846
|
+
const hasSource = fs23.existsSync(path49.join(cwd, "CMakeLists.txt"));
|
|
24847
|
+
const hasBuildCache = fs23.existsSync(path49.join(cwd, "CMakeCache.txt")) || fs23.existsSync(path49.join(cwd, "build", "CMakeCache.txt"));
|
|
24541
24848
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
24542
24849
|
}
|
|
24543
24850
|
function detectSwiftTest(cwd) {
|
|
24544
|
-
return fs23.existsSync(
|
|
24851
|
+
return fs23.existsSync(path49.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
24545
24852
|
}
|
|
24546
24853
|
function detectDartTest(cwd) {
|
|
24547
|
-
return fs23.existsSync(
|
|
24854
|
+
return fs23.existsSync(path49.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
24548
24855
|
}
|
|
24549
24856
|
function detectRSpec(cwd) {
|
|
24550
|
-
const hasRSpecFile = fs23.existsSync(
|
|
24551
|
-
const hasGemfile = fs23.existsSync(
|
|
24552
|
-
const hasSpecDir = fs23.existsSync(
|
|
24857
|
+
const hasRSpecFile = fs23.existsSync(path49.join(cwd, ".rspec"));
|
|
24858
|
+
const hasGemfile = fs23.existsSync(path49.join(cwd, "Gemfile"));
|
|
24859
|
+
const hasSpecDir = fs23.existsSync(path49.join(cwd, "spec"));
|
|
24553
24860
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
24554
24861
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
24555
24862
|
}
|
|
24556
24863
|
function detectMinitest(cwd) {
|
|
24557
|
-
return fs23.existsSync(
|
|
24864
|
+
return fs23.existsSync(path49.join(cwd, "test")) && (fs23.existsSync(path49.join(cwd, "Gemfile")) || fs23.existsSync(path49.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
24558
24865
|
}
|
|
24559
24866
|
var DISPATCH_FRAMEWORK_MAP = {
|
|
24560
24867
|
bun: "bun",
|
|
@@ -24639,7 +24946,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
24639
24946
|
async function detectTestFramework(cwd) {
|
|
24640
24947
|
const baseDir = cwd;
|
|
24641
24948
|
try {
|
|
24642
|
-
const packageJsonPath =
|
|
24949
|
+
const packageJsonPath = path49.join(baseDir, "package.json");
|
|
24643
24950
|
if (fs23.existsSync(packageJsonPath)) {
|
|
24644
24951
|
const content = fs23.readFileSync(packageJsonPath, "utf-8");
|
|
24645
24952
|
const pkg = JSON.parse(content);
|
|
@@ -24660,16 +24967,16 @@ async function detectTestFramework(cwd) {
|
|
|
24660
24967
|
return "jest";
|
|
24661
24968
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
24662
24969
|
return "mocha";
|
|
24663
|
-
if (fs23.existsSync(
|
|
24970
|
+
if (fs23.existsSync(path49.join(baseDir, "bun.lockb")) || fs23.existsSync(path49.join(baseDir, "bun.lock"))) {
|
|
24664
24971
|
if (scripts.test?.includes("bun"))
|
|
24665
24972
|
return "bun";
|
|
24666
24973
|
}
|
|
24667
24974
|
}
|
|
24668
24975
|
} catch {}
|
|
24669
24976
|
try {
|
|
24670
|
-
const pyprojectTomlPath =
|
|
24671
|
-
const setupCfgPath =
|
|
24672
|
-
const requirementsTxtPath =
|
|
24977
|
+
const pyprojectTomlPath = path49.join(baseDir, "pyproject.toml");
|
|
24978
|
+
const setupCfgPath = path49.join(baseDir, "setup.cfg");
|
|
24979
|
+
const requirementsTxtPath = path49.join(baseDir, "requirements.txt");
|
|
24673
24980
|
if (fs23.existsSync(pyprojectTomlPath)) {
|
|
24674
24981
|
const content = fs23.readFileSync(pyprojectTomlPath, "utf-8");
|
|
24675
24982
|
if (content.includes("[tool.pytest"))
|
|
@@ -24689,7 +24996,7 @@ async function detectTestFramework(cwd) {
|
|
|
24689
24996
|
}
|
|
24690
24997
|
} catch {}
|
|
24691
24998
|
try {
|
|
24692
|
-
const cargoTomlPath =
|
|
24999
|
+
const cargoTomlPath = path49.join(baseDir, "Cargo.toml");
|
|
24693
25000
|
if (fs23.existsSync(cargoTomlPath)) {
|
|
24694
25001
|
const content = fs23.readFileSync(cargoTomlPath, "utf-8");
|
|
24695
25002
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -24700,9 +25007,9 @@ async function detectTestFramework(cwd) {
|
|
|
24700
25007
|
}
|
|
24701
25008
|
} catch {}
|
|
24702
25009
|
try {
|
|
24703
|
-
const pesterConfigPath =
|
|
24704
|
-
const pesterConfigJsonPath =
|
|
24705
|
-
const pesterPs1Path =
|
|
25010
|
+
const pesterConfigPath = path49.join(baseDir, "pester.config.ps1");
|
|
25011
|
+
const pesterConfigJsonPath = path49.join(baseDir, "pester.config.ps1.json");
|
|
25012
|
+
const pesterPs1Path = path49.join(baseDir, "tests.ps1");
|
|
24706
25013
|
if (fs23.existsSync(pesterConfigPath) || fs23.existsSync(pesterConfigJsonPath) || fs23.existsSync(pesterPs1Path)) {
|
|
24707
25014
|
return "pester";
|
|
24708
25015
|
}
|
|
@@ -24745,12 +25052,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
24745
25052
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
24746
25053
|
}
|
|
24747
25054
|
function resolveWorkspacePath(file, workingDir) {
|
|
24748
|
-
return
|
|
25055
|
+
return path49.isAbsolute(file) ? path49.resolve(file) : path49.resolve(workingDir, file);
|
|
24749
25056
|
}
|
|
24750
25057
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
24751
25058
|
if (!preferRelative)
|
|
24752
25059
|
return absolutePath;
|
|
24753
|
-
return
|
|
25060
|
+
return path49.relative(workingDir, absolutePath);
|
|
24754
25061
|
}
|
|
24755
25062
|
function dedupePush(target, value) {
|
|
24756
25063
|
if (!target.includes(value)) {
|
|
@@ -24787,18 +25094,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
24787
25094
|
}
|
|
24788
25095
|
}
|
|
24789
25096
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
24790
|
-
const relativeDir =
|
|
25097
|
+
const relativeDir = path49.dirname(relativePath);
|
|
24791
25098
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
24792
25099
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
24793
|
-
const rootDir =
|
|
24794
|
-
return nestedRelativeDir ? [rootDir,
|
|
25100
|
+
const rootDir = path49.join(workingDir, dirName);
|
|
25101
|
+
return nestedRelativeDir ? [rootDir, path49.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
24795
25102
|
});
|
|
24796
25103
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
24797
25104
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
24798
|
-
directories.push(
|
|
25105
|
+
directories.push(path49.join(workingDir, "src/test/java", path49.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
24799
25106
|
}
|
|
24800
25107
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
24801
|
-
directories.push(
|
|
25108
|
+
directories.push(path49.join(workingDir, "src/test/kotlin", path49.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
24802
25109
|
}
|
|
24803
25110
|
return [...new Set(directories)];
|
|
24804
25111
|
}
|
|
@@ -24826,23 +25133,23 @@ function isLanguageSpecificTestFile(basename9) {
|
|
|
24826
25133
|
}
|
|
24827
25134
|
function isConventionTestFilePath(filePath) {
|
|
24828
25135
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
24829
|
-
const basename9 =
|
|
25136
|
+
const basename9 = path49.basename(filePath);
|
|
24830
25137
|
return hasCompoundTestExtension(basename9) || basename9.includes(".spec.") || basename9.includes(".test.") || isLanguageSpecificTestFile(basename9) || isTestDirectoryPath(normalizedPath);
|
|
24831
25138
|
}
|
|
24832
25139
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
24833
25140
|
const testFiles = [];
|
|
24834
25141
|
for (const file of sourceFiles) {
|
|
24835
25142
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
24836
|
-
const relativeFile =
|
|
24837
|
-
const basename9 =
|
|
24838
|
-
const dirname23 =
|
|
24839
|
-
const preferRelativeOutput = !
|
|
25143
|
+
const relativeFile = path49.relative(workingDir, absoluteFile);
|
|
25144
|
+
const basename9 = path49.basename(absoluteFile);
|
|
25145
|
+
const dirname23 = path49.dirname(absoluteFile);
|
|
25146
|
+
const preferRelativeOutput = !path49.isAbsolute(file);
|
|
24840
25147
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
24841
25148
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
24842
25149
|
continue;
|
|
24843
25150
|
}
|
|
24844
25151
|
const nameWithoutExt = basename9.replace(/\.[^.]+$/, "");
|
|
24845
|
-
const ext =
|
|
25152
|
+
const ext = path49.extname(basename9);
|
|
24846
25153
|
const genericTestNames = [
|
|
24847
25154
|
`${nameWithoutExt}.spec${ext}`,
|
|
24848
25155
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -24851,7 +25158,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
24851
25158
|
const colocatedCandidates = [
|
|
24852
25159
|
...genericTestNames,
|
|
24853
25160
|
...languageSpecificTestNames
|
|
24854
|
-
].map((candidateName) =>
|
|
25161
|
+
].map((candidateName) => path49.join(dirname23, candidateName));
|
|
24855
25162
|
const testDirectoryNames = [
|
|
24856
25163
|
basename9,
|
|
24857
25164
|
...genericTestNames,
|
|
@@ -24860,8 +25167,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
24860
25167
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
24861
25168
|
const possibleTestFiles = [
|
|
24862
25169
|
...colocatedCandidates,
|
|
24863
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
24864
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
25170
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path49.join(dirname23, dirName, candidateName))),
|
|
25171
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path49.join(candidateDir, candidateName)))
|
|
24865
25172
|
];
|
|
24866
25173
|
for (const testFile of possibleTestFiles) {
|
|
24867
25174
|
if (fs23.existsSync(testFile)) {
|
|
@@ -24882,7 +25189,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
24882
25189
|
try {
|
|
24883
25190
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
24884
25191
|
const content = fs23.readFileSync(absoluteTestFile, "utf-8");
|
|
24885
|
-
const testDir =
|
|
25192
|
+
const testDir = path49.dirname(absoluteTestFile);
|
|
24886
25193
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
24887
25194
|
let match;
|
|
24888
25195
|
match = importRegex.exec(content);
|
|
@@ -24890,8 +25197,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
24890
25197
|
const importPath = match[1];
|
|
24891
25198
|
let resolvedImport;
|
|
24892
25199
|
if (importPath.startsWith(".")) {
|
|
24893
|
-
resolvedImport =
|
|
24894
|
-
const existingExt =
|
|
25200
|
+
resolvedImport = path49.resolve(testDir, importPath);
|
|
25201
|
+
const existingExt = path49.extname(resolvedImport);
|
|
24895
25202
|
if (!existingExt) {
|
|
24896
25203
|
for (const extToTry of [
|
|
24897
25204
|
".ts",
|
|
@@ -24911,12 +25218,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
24911
25218
|
} else {
|
|
24912
25219
|
continue;
|
|
24913
25220
|
}
|
|
24914
|
-
const importBasename =
|
|
24915
|
-
const importDir =
|
|
25221
|
+
const importBasename = path49.basename(resolvedImport, path49.extname(resolvedImport));
|
|
25222
|
+
const importDir = path49.dirname(resolvedImport);
|
|
24916
25223
|
for (const sourceFile of absoluteSourceFiles) {
|
|
24917
|
-
const sourceDir =
|
|
24918
|
-
const sourceBasename =
|
|
24919
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
25224
|
+
const sourceDir = path49.dirname(sourceFile);
|
|
25225
|
+
const sourceBasename = path49.basename(sourceFile, path49.extname(sourceFile));
|
|
25226
|
+
const isRelatedDir = importDir === sourceDir || importDir === path49.join(sourceDir, "__tests__") || importDir === path49.join(sourceDir, "tests") || importDir === path49.join(sourceDir, "test") || importDir === path49.join(sourceDir, "spec");
|
|
24920
25227
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
24921
25228
|
dedupePush(testFiles, testFile);
|
|
24922
25229
|
break;
|
|
@@ -24929,8 +25236,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
24929
25236
|
while (match !== null) {
|
|
24930
25237
|
const importPath = match[1];
|
|
24931
25238
|
if (importPath.startsWith(".")) {
|
|
24932
|
-
let resolvedImport =
|
|
24933
|
-
const existingExt =
|
|
25239
|
+
let resolvedImport = path49.resolve(testDir, importPath);
|
|
25240
|
+
const existingExt = path49.extname(resolvedImport);
|
|
24934
25241
|
if (!existingExt) {
|
|
24935
25242
|
for (const extToTry of [
|
|
24936
25243
|
".ts",
|
|
@@ -24947,12 +25254,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
24947
25254
|
}
|
|
24948
25255
|
}
|
|
24949
25256
|
}
|
|
24950
|
-
const importDir =
|
|
24951
|
-
const importBasename =
|
|
25257
|
+
const importDir = path49.dirname(resolvedImport);
|
|
25258
|
+
const importBasename = path49.basename(resolvedImport, path49.extname(resolvedImport));
|
|
24952
25259
|
for (const sourceFile of absoluteSourceFiles) {
|
|
24953
|
-
const sourceDir =
|
|
24954
|
-
const sourceBasename =
|
|
24955
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
25260
|
+
const sourceDir = path49.dirname(sourceFile);
|
|
25261
|
+
const sourceBasename = path49.basename(sourceFile, path49.extname(sourceFile));
|
|
25262
|
+
const isRelatedDir = importDir === sourceDir || importDir === path49.join(sourceDir, "__tests__") || importDir === path49.join(sourceDir, "tests") || importDir === path49.join(sourceDir, "test") || importDir === path49.join(sourceDir, "spec");
|
|
24956
25263
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
24957
25264
|
dedupePush(testFiles, testFile);
|
|
24958
25265
|
break;
|
|
@@ -25072,8 +25379,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
25072
25379
|
return ["mvn", "test"];
|
|
25073
25380
|
case "gradle": {
|
|
25074
25381
|
const isWindows = process.platform === "win32";
|
|
25075
|
-
const hasGradlewBat = fs23.existsSync(
|
|
25076
|
-
const hasGradlew = fs23.existsSync(
|
|
25382
|
+
const hasGradlewBat = fs23.existsSync(path49.join(baseDir, "gradlew.bat"));
|
|
25383
|
+
const hasGradlew = fs23.existsSync(path49.join(baseDir, "gradlew"));
|
|
25077
25384
|
if (hasGradlewBat && isWindows)
|
|
25078
25385
|
return ["gradlew.bat", "test"];
|
|
25079
25386
|
if (hasGradlew)
|
|
@@ -25090,7 +25397,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
25090
25397
|
"cmake-build-release",
|
|
25091
25398
|
"out"
|
|
25092
25399
|
];
|
|
25093
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(
|
|
25400
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(path49.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
25094
25401
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
25095
25402
|
}
|
|
25096
25403
|
case "swift-test":
|
|
@@ -25524,11 +25831,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
25524
25831
|
};
|
|
25525
25832
|
}
|
|
25526
25833
|
const startTime = Date.now();
|
|
25527
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
25834
|
+
const vitestJsonOutputPath = framework === "vitest" ? path49.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
25528
25835
|
try {
|
|
25529
25836
|
if (vitestJsonOutputPath) {
|
|
25530
25837
|
try {
|
|
25531
|
-
fs23.mkdirSync(
|
|
25838
|
+
fs23.mkdirSync(path49.dirname(vitestJsonOutputPath), { recursive: true });
|
|
25532
25839
|
if (fs23.existsSync(vitestJsonOutputPath)) {
|
|
25533
25840
|
fs23.unlinkSync(vitestJsonOutputPath);
|
|
25534
25841
|
}
|
|
@@ -25539,9 +25846,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
25539
25846
|
stderr: "pipe",
|
|
25540
25847
|
cwd
|
|
25541
25848
|
});
|
|
25542
|
-
const timeoutPromise = new Promise((
|
|
25849
|
+
const timeoutPromise = new Promise((resolve16) => setTimeout(() => {
|
|
25543
25850
|
proc.kill();
|
|
25544
|
-
|
|
25851
|
+
resolve16(-1);
|
|
25545
25852
|
}, timeout_ms));
|
|
25546
25853
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
25547
25854
|
Promise.race([proc.exited, timeoutPromise]),
|
|
@@ -25696,10 +26003,10 @@ var SKIP_DIRECTORIES = new Set([
|
|
|
25696
26003
|
]);
|
|
25697
26004
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
25698
26005
|
const normalized = testFile.replace(/\\/g, "/");
|
|
25699
|
-
if (!
|
|
26006
|
+
if (!path49.isAbsolute(testFile))
|
|
25700
26007
|
return normalized;
|
|
25701
|
-
const relative8 =
|
|
25702
|
-
if (relative8.startsWith("..") ||
|
|
26008
|
+
const relative8 = path49.relative(workingDir, testFile);
|
|
26009
|
+
if (relative8.startsWith("..") || path49.isAbsolute(relative8)) {
|
|
25703
26010
|
return normalized;
|
|
25704
26011
|
}
|
|
25705
26012
|
return relative8.replace(/\\/g, "/");
|
|
@@ -25938,7 +26245,7 @@ var test_runner = createSwarmTool({
|
|
|
25938
26245
|
const sourceFiles = args.files.filter((file) => {
|
|
25939
26246
|
if (directTestFiles.includes(file))
|
|
25940
26247
|
return false;
|
|
25941
|
-
const ext =
|
|
26248
|
+
const ext = path49.extname(file).toLowerCase();
|
|
25942
26249
|
return SOURCE_EXTENSIONS.has(ext);
|
|
25943
26250
|
});
|
|
25944
26251
|
const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
|
|
@@ -25984,7 +26291,7 @@ var test_runner = createSwarmTool({
|
|
|
25984
26291
|
if (isConventionTestFilePath(f)) {
|
|
25985
26292
|
return false;
|
|
25986
26293
|
}
|
|
25987
|
-
const ext =
|
|
26294
|
+
const ext = path49.extname(f).toLowerCase();
|
|
25988
26295
|
return SOURCE_EXTENSIONS.has(ext);
|
|
25989
26296
|
});
|
|
25990
26297
|
if (sourceFiles.length === 0) {
|
|
@@ -26034,7 +26341,7 @@ var test_runner = createSwarmTool({
|
|
|
26034
26341
|
if (isConventionTestFilePath(f)) {
|
|
26035
26342
|
return false;
|
|
26036
26343
|
}
|
|
26037
|
-
const ext =
|
|
26344
|
+
const ext = path49.extname(f).toLowerCase();
|
|
26038
26345
|
return SOURCE_EXTENSIONS.has(ext);
|
|
26039
26346
|
});
|
|
26040
26347
|
if (sourceFiles.length === 0) {
|
|
@@ -26086,8 +26393,8 @@ var test_runner = createSwarmTool({
|
|
|
26086
26393
|
}
|
|
26087
26394
|
if (impactResult.impactedTests.length > 0) {
|
|
26088
26395
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
26089
|
-
const relativePath =
|
|
26090
|
-
return
|
|
26396
|
+
const relativePath = path49.relative(workingDir, absPath);
|
|
26397
|
+
return path49.isAbsolute(relativePath) ? absPath : relativePath;
|
|
26091
26398
|
});
|
|
26092
26399
|
} else {
|
|
26093
26400
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -26182,8 +26489,8 @@ function validateDirectoryPath(dir) {
|
|
|
26182
26489
|
if (dir.includes("..")) {
|
|
26183
26490
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
26184
26491
|
}
|
|
26185
|
-
const normalized =
|
|
26186
|
-
const absolutePath =
|
|
26492
|
+
const normalized = path50.normalize(dir);
|
|
26493
|
+
const absolutePath = path50.isAbsolute(normalized) ? normalized : path50.resolve(normalized);
|
|
26187
26494
|
return absolutePath;
|
|
26188
26495
|
}
|
|
26189
26496
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -26206,7 +26513,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
26206
26513
|
}
|
|
26207
26514
|
function getPackageVersion(dir) {
|
|
26208
26515
|
try {
|
|
26209
|
-
const packagePath =
|
|
26516
|
+
const packagePath = path50.join(dir, "package.json");
|
|
26210
26517
|
if (fs24.existsSync(packagePath)) {
|
|
26211
26518
|
const content = fs24.readFileSync(packagePath, "utf-8");
|
|
26212
26519
|
const pkg = JSON.parse(content);
|
|
@@ -26217,7 +26524,7 @@ function getPackageVersion(dir) {
|
|
|
26217
26524
|
}
|
|
26218
26525
|
function getChangelogVersion(dir) {
|
|
26219
26526
|
try {
|
|
26220
|
-
const changelogPath =
|
|
26527
|
+
const changelogPath = path50.join(dir, "CHANGELOG.md");
|
|
26221
26528
|
if (fs24.existsSync(changelogPath)) {
|
|
26222
26529
|
const content = fs24.readFileSync(changelogPath, "utf-8");
|
|
26223
26530
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -26231,7 +26538,7 @@ function getChangelogVersion(dir) {
|
|
|
26231
26538
|
function getVersionFileVersion(dir) {
|
|
26232
26539
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
26233
26540
|
for (const file of possibleFiles) {
|
|
26234
|
-
const filePath =
|
|
26541
|
+
const filePath = path50.join(dir, file);
|
|
26235
26542
|
if (fs24.existsSync(filePath)) {
|
|
26236
26543
|
try {
|
|
26237
26544
|
const content = fs24.readFileSync(filePath, "utf-8").trim();
|
|
@@ -26969,7 +27276,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
26969
27276
|
|
|
26970
27277
|
// src/commands/reset.ts
|
|
26971
27278
|
import * as fs25 from "fs";
|
|
26972
|
-
import * as
|
|
27279
|
+
import * as path51 from "path";
|
|
26973
27280
|
|
|
26974
27281
|
// src/background/circuit-breaker.ts
|
|
26975
27282
|
class CircuitBreaker {
|
|
@@ -27021,13 +27328,13 @@ class CircuitBreaker {
|
|
|
27021
27328
|
if (this.config.callTimeoutMs <= 0) {
|
|
27022
27329
|
return fn();
|
|
27023
27330
|
}
|
|
27024
|
-
return new Promise((
|
|
27331
|
+
return new Promise((resolve17, reject) => {
|
|
27025
27332
|
const timeout = setTimeout(() => {
|
|
27026
27333
|
reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
|
|
27027
27334
|
}, this.config.callTimeoutMs);
|
|
27028
27335
|
fn().then((result) => {
|
|
27029
27336
|
clearTimeout(timeout);
|
|
27030
|
-
|
|
27337
|
+
resolve17(result);
|
|
27031
27338
|
}).catch((error2) => {
|
|
27032
27339
|
clearTimeout(timeout);
|
|
27033
27340
|
reject(error2);
|
|
@@ -27311,7 +27618,7 @@ class AutomationQueue {
|
|
|
27311
27618
|
|
|
27312
27619
|
// src/background/worker.ts
|
|
27313
27620
|
function sleep(ms) {
|
|
27314
|
-
return new Promise((
|
|
27621
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
27315
27622
|
}
|
|
27316
27623
|
|
|
27317
27624
|
class WorkerManager {
|
|
@@ -27686,7 +27993,7 @@ async function handleResetCommand(directory, args) {
|
|
|
27686
27993
|
}
|
|
27687
27994
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
27688
27995
|
try {
|
|
27689
|
-
const rootPath =
|
|
27996
|
+
const rootPath = path51.join(directory, filename);
|
|
27690
27997
|
if (fs25.existsSync(rootPath)) {
|
|
27691
27998
|
fs25.unlinkSync(rootPath);
|
|
27692
27999
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -27724,7 +28031,7 @@ async function handleResetCommand(directory, args) {
|
|
|
27724
28031
|
|
|
27725
28032
|
// src/commands/reset-session.ts
|
|
27726
28033
|
import * as fs27 from "fs";
|
|
27727
|
-
import * as
|
|
28034
|
+
import * as path53 from "path";
|
|
27728
28035
|
|
|
27729
28036
|
// src/hooks/trajectory-logger.ts
|
|
27730
28037
|
var callStartTimes = new Map;
|
|
@@ -28131,16 +28438,16 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
|
|
|
28131
28438
|
}
|
|
28132
28439
|
// src/prm/replay.ts
|
|
28133
28440
|
import { promises as fs26 } from "fs";
|
|
28134
|
-
import
|
|
28441
|
+
import path52 from "path";
|
|
28135
28442
|
function isPathSafe(targetPath, basePath) {
|
|
28136
|
-
const resolvedTarget =
|
|
28137
|
-
const resolvedBase =
|
|
28138
|
-
const rel =
|
|
28139
|
-
return !rel.startsWith("..") && !
|
|
28443
|
+
const resolvedTarget = path52.resolve(targetPath);
|
|
28444
|
+
const resolvedBase = path52.resolve(basePath);
|
|
28445
|
+
const rel = path52.relative(resolvedBase, resolvedTarget);
|
|
28446
|
+
return !rel.startsWith("..") && !path52.isAbsolute(rel);
|
|
28140
28447
|
}
|
|
28141
28448
|
function isWithinReplaysDir(targetPath) {
|
|
28142
|
-
const resolved =
|
|
28143
|
-
const parts = resolved.split(
|
|
28449
|
+
const resolved = path52.resolve(targetPath);
|
|
28450
|
+
const parts = resolved.split(path52.sep);
|
|
28144
28451
|
for (let i = 0;i < parts.length - 1; i++) {
|
|
28145
28452
|
if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
|
|
28146
28453
|
return true;
|
|
@@ -28153,10 +28460,10 @@ function sanitizeFilename(input) {
|
|
|
28153
28460
|
}
|
|
28154
28461
|
async function startReplayRecording(sessionID, directory) {
|
|
28155
28462
|
try {
|
|
28156
|
-
const replayDir =
|
|
28463
|
+
const replayDir = path52.join(directory, ".swarm", "replays");
|
|
28157
28464
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
28158
28465
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
28159
|
-
const filepath =
|
|
28466
|
+
const filepath = path52.join(replayDir, filename);
|
|
28160
28467
|
if (!isPathSafe(filepath, replayDir)) {
|
|
28161
28468
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
28162
28469
|
return null;
|
|
@@ -28234,7 +28541,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28234
28541
|
} catch {
|
|
28235
28542
|
results.push("\u274C Failed to delete state.json");
|
|
28236
28543
|
}
|
|
28237
|
-
const sessionDir =
|
|
28544
|
+
const sessionDir = path53.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
28238
28545
|
let sessionFiles = [];
|
|
28239
28546
|
if (fs27.existsSync(sessionDir)) {
|
|
28240
28547
|
try {
|
|
@@ -28246,7 +28553,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28246
28553
|
for (const file of sessionFiles) {
|
|
28247
28554
|
if (file === "state.json")
|
|
28248
28555
|
continue;
|
|
28249
|
-
const filePath =
|
|
28556
|
+
const filePath = path53.join(sessionDir, file);
|
|
28250
28557
|
try {
|
|
28251
28558
|
if (!fs27.existsSync(filePath))
|
|
28252
28559
|
continue;
|
|
@@ -28281,7 +28588,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28281
28588
|
}
|
|
28282
28589
|
|
|
28283
28590
|
// src/summaries/manager.ts
|
|
28284
|
-
import * as
|
|
28591
|
+
import * as path54 from "path";
|
|
28285
28592
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
28286
28593
|
function sanitizeSummaryId(id) {
|
|
28287
28594
|
if (!id || id.length === 0) {
|
|
@@ -28305,7 +28612,7 @@ function sanitizeSummaryId(id) {
|
|
|
28305
28612
|
}
|
|
28306
28613
|
async function loadFullOutput(directory, id) {
|
|
28307
28614
|
const sanitizedId = sanitizeSummaryId(id);
|
|
28308
|
-
const relativePath =
|
|
28615
|
+
const relativePath = path54.join("summaries", `${sanitizedId}.json`);
|
|
28309
28616
|
validateSwarmPath(directory, relativePath);
|
|
28310
28617
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
28311
28618
|
if (content === null) {
|
|
@@ -28358,7 +28665,7 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
|
28358
28665
|
|
|
28359
28666
|
// src/commands/rollback.ts
|
|
28360
28667
|
import * as fs28 from "fs";
|
|
28361
|
-
import * as
|
|
28668
|
+
import * as path55 from "path";
|
|
28362
28669
|
async function handleRollbackCommand(directory, args) {
|
|
28363
28670
|
const phaseArg = args[0];
|
|
28364
28671
|
if (!phaseArg) {
|
|
@@ -28424,8 +28731,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28424
28731
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
28425
28732
|
continue;
|
|
28426
28733
|
}
|
|
28427
|
-
const src =
|
|
28428
|
-
const dest =
|
|
28734
|
+
const src = path55.join(checkpointDir, file);
|
|
28735
|
+
const dest = path55.join(swarmDir, file);
|
|
28429
28736
|
try {
|
|
28430
28737
|
fs28.cpSync(src, dest, { recursive: true, force: true });
|
|
28431
28738
|
successes.push(file);
|
|
@@ -28444,7 +28751,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28444
28751
|
].join(`
|
|
28445
28752
|
`);
|
|
28446
28753
|
}
|
|
28447
|
-
const existingLedgerPath =
|
|
28754
|
+
const existingLedgerPath = path55.join(swarmDir, "plan-ledger.jsonl");
|
|
28448
28755
|
let ledgerDeletionFailed = false;
|
|
28449
28756
|
if (fs28.existsSync(existingLedgerPath)) {
|
|
28450
28757
|
try {
|
|
@@ -28457,7 +28764,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28457
28764
|
}
|
|
28458
28765
|
if (!ledgerDeletionFailed) {
|
|
28459
28766
|
try {
|
|
28460
|
-
const planJsonPath =
|
|
28767
|
+
const planJsonPath = path55.join(swarmDir, "plan.json");
|
|
28461
28768
|
if (fs28.existsSync(planJsonPath)) {
|
|
28462
28769
|
const planRaw = fs28.readFileSync(planJsonPath, "utf-8");
|
|
28463
28770
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -28718,10 +29025,10 @@ Ensure this is a git repository with commit history.`;
|
|
|
28718
29025
|
`);
|
|
28719
29026
|
try {
|
|
28720
29027
|
const fs29 = await import("fs/promises");
|
|
28721
|
-
const
|
|
28722
|
-
const reportPath =
|
|
28723
|
-
await fs29.mkdir(
|
|
28724
|
-
const reportTempPath =
|
|
29028
|
+
const path56 = await import("path");
|
|
29029
|
+
const reportPath = path56.join(directory, ".swarm", "simulate-report.md");
|
|
29030
|
+
await fs29.mkdir(path56.dirname(reportPath), { recursive: true });
|
|
29031
|
+
const reportTempPath = path56.join(path56.dirname(reportPath), `${path56.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
28725
29032
|
try {
|
|
28726
29033
|
await fs29.writeFile(reportTempPath, report, "utf-8");
|
|
28727
29034
|
renameSync11(reportTempPath, reportPath);
|
|
@@ -28750,18 +29057,18 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
28750
29057
|
// src/services/status-service.ts
|
|
28751
29058
|
import * as fsSync3 from "fs";
|
|
28752
29059
|
import { readFile as readFile15 } from "fs/promises";
|
|
28753
|
-
import * as
|
|
29060
|
+
import * as path57 from "path";
|
|
28754
29061
|
|
|
28755
29062
|
// src/turbo/lean/state.ts
|
|
28756
29063
|
init_logger();
|
|
28757
29064
|
import * as fs29 from "fs";
|
|
28758
|
-
import * as
|
|
29065
|
+
import * as path56 from "path";
|
|
28759
29066
|
var STATE_FILE3 = "turbo-state.json";
|
|
28760
29067
|
function nowISO3() {
|
|
28761
29068
|
return new Date().toISOString();
|
|
28762
29069
|
}
|
|
28763
29070
|
function ensureSwarmDir2(directory) {
|
|
28764
|
-
const swarmDir =
|
|
29071
|
+
const swarmDir = path56.resolve(directory, ".swarm");
|
|
28765
29072
|
if (!fs29.existsSync(swarmDir)) {
|
|
28766
29073
|
fs29.mkdirSync(swarmDir, { recursive: true });
|
|
28767
29074
|
}
|
|
@@ -28806,7 +29113,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
28806
29113
|
}
|
|
28807
29114
|
function readPersisted2(directory) {
|
|
28808
29115
|
try {
|
|
28809
|
-
const filePath =
|
|
29116
|
+
const filePath = path56.join(directory, ".swarm", STATE_FILE3);
|
|
28810
29117
|
if (!fs29.existsSync(filePath)) {
|
|
28811
29118
|
const seed = emptyPersisted2();
|
|
28812
29119
|
try {
|
|
@@ -28842,7 +29149,7 @@ function writePersisted2(directory, persisted) {
|
|
|
28842
29149
|
let payload;
|
|
28843
29150
|
try {
|
|
28844
29151
|
ensureSwarmDir2(directory);
|
|
28845
|
-
filePath =
|
|
29152
|
+
filePath = path56.join(directory, ".swarm", STATE_FILE3);
|
|
28846
29153
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
28847
29154
|
persisted.updatedAt = nowISO3();
|
|
28848
29155
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -28960,7 +29267,7 @@ var _internals43 = {
|
|
|
28960
29267
|
};
|
|
28961
29268
|
function readSpecStalenessSnapshot(directory) {
|
|
28962
29269
|
try {
|
|
28963
|
-
const p =
|
|
29270
|
+
const p = path57.join(directory, ".swarm", "spec-staleness.json");
|
|
28964
29271
|
if (!fsSync3.existsSync(p))
|
|
28965
29272
|
return { stale: false };
|
|
28966
29273
|
const raw = fsSync3.readFileSync(p, "utf-8");
|
|
@@ -29627,7 +29934,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
29627
29934
|
async function handleHelpCommand(ctx) {
|
|
29628
29935
|
const targetCommand = ctx.args.join(" ");
|
|
29629
29936
|
if (!targetCommand) {
|
|
29630
|
-
const { buildHelpText } = await import("./index-
|
|
29937
|
+
const { buildHelpText } = await import("./index-tjr1m8wf.js");
|
|
29631
29938
|
return buildHelpText();
|
|
29632
29939
|
}
|
|
29633
29940
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -29636,7 +29943,7 @@ async function handleHelpCommand(ctx) {
|
|
|
29636
29943
|
return _internals45.buildDetailedHelp(resolved.key, resolved.entry);
|
|
29637
29944
|
}
|
|
29638
29945
|
const similar = _internals45.findSimilarCommands(targetCommand);
|
|
29639
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
29946
|
+
const { buildHelpText: fullHelp } = await import("./index-tjr1m8wf.js");
|
|
29640
29947
|
if (similar.length > 0) {
|
|
29641
29948
|
return `Command '/swarm ${targetCommand}' not found.
|
|
29642
29949
|
|
|
@@ -29769,7 +30076,7 @@ var COMMAND_REGISTRY = {
|
|
|
29769
30076
|
},
|
|
29770
30077
|
"guardrail explain": {
|
|
29771
30078
|
handler: async (ctx) => {
|
|
29772
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
30079
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-qd243wrm.js");
|
|
29773
30080
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
29774
30081
|
},
|
|
29775
30082
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -30142,7 +30449,7 @@ Subcommands:
|
|
|
30142
30449
|
deprecated: true
|
|
30143
30450
|
},
|
|
30144
30451
|
"pr status": {
|
|
30145
|
-
handler: (ctx) => handlePrMonitorStatusCommand(ctx.directory, ctx.args, ctx.sessionID),
|
|
30452
|
+
handler: (ctx) => handlePrMonitorStatusCommand(ctx.directory, ctx.args, ctx.sessionID, ctx.source),
|
|
30146
30453
|
description: "Show PR monitor subscription status for the current session",
|
|
30147
30454
|
args: "",
|
|
30148
30455
|
details: "Displays all active PR subscriptions for the current session. Shows PR URL, last checked time, watching status, and error count per subscription. Also shows total active subscriptions across all sessions.",
|
|
@@ -30151,7 +30458,7 @@ Subcommands:
|
|
|
30151
30458
|
toolNoArgs: true
|
|
30152
30459
|
},
|
|
30153
30460
|
"pr-status": {
|
|
30154
|
-
handler: (ctx) => handlePrMonitorStatusCommand(ctx.directory, ctx.args, ctx.sessionID),
|
|
30461
|
+
handler: (ctx) => handlePrMonitorStatusCommand(ctx.directory, ctx.args, ctx.sessionID, ctx.source),
|
|
30155
30462
|
description: "Show PR monitor subscription status for the current session",
|
|
30156
30463
|
aliasOf: "pr status",
|
|
30157
30464
|
deprecated: true
|
|
@@ -30509,24 +30816,24 @@ function validateAliases() {
|
|
|
30509
30816
|
}
|
|
30510
30817
|
aliasTargets.get(target).push(name);
|
|
30511
30818
|
const visited = new Set;
|
|
30512
|
-
const
|
|
30819
|
+
const path58 = [];
|
|
30513
30820
|
let current = target;
|
|
30514
30821
|
while (current) {
|
|
30515
30822
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
30516
30823
|
if (!currentEntry)
|
|
30517
30824
|
break;
|
|
30518
30825
|
if (visited.has(current)) {
|
|
30519
|
-
const cycleStart =
|
|
30826
|
+
const cycleStart = path58.indexOf(current);
|
|
30520
30827
|
const fullChain = [
|
|
30521
30828
|
name,
|
|
30522
|
-
...
|
|
30829
|
+
...path58.slice(0, cycleStart > 0 ? cycleStart : path58.length),
|
|
30523
30830
|
current
|
|
30524
30831
|
].join(" \u2192 ");
|
|
30525
30832
|
errors.push(`Circular alias detected: ${fullChain}`);
|
|
30526
30833
|
break;
|
|
30527
30834
|
}
|
|
30528
30835
|
visited.add(current);
|
|
30529
|
-
|
|
30836
|
+
path58.push(current);
|
|
30530
30837
|
current = currentEntry.aliasOf || "";
|
|
30531
30838
|
}
|
|
30532
30839
|
}
|