opencode-swarm 7.33.1 → 7.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/cli/index.js +1898 -236
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/memory.d.ts +5 -0
- package/dist/commands/registry.d.ts +33 -0
- package/dist/commands/tool-policy.d.ts +1 -1
- package/dist/index.js +32129 -31529
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/jsonl-migration.d.ts +47 -0
- package/dist/memory/sqlite-provider.d.ts +21 -0
- package/dist/tools/co-change-analyzer.d.ts +2 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.
|
|
37
|
+
version: "7.34.0",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -17601,7 +17601,7 @@ var init_schema = __esm(() => {
|
|
|
17601
17601
|
});
|
|
17602
17602
|
MemoryConfigSchema = exports_external.object({
|
|
17603
17603
|
enabled: exports_external.boolean().default(false),
|
|
17604
|
-
provider: exports_external.enum(["local-jsonl", "sqlite"]).default("
|
|
17604
|
+
provider: exports_external.enum(["local-jsonl", "sqlite"]).default("sqlite"),
|
|
17605
17605
|
storageDir: exports_external.string().default(".swarm/memory"),
|
|
17606
17606
|
sqlite: exports_external.object({
|
|
17607
17607
|
path: exports_external.string().default(".swarm/memory/memory.db"),
|
|
@@ -39023,14 +39023,16 @@ async function parseGitLog(directory, maxCommits) {
|
|
|
39023
39023
|
}
|
|
39024
39024
|
return commitMap;
|
|
39025
39025
|
}
|
|
39026
|
-
function buildCoChangeMatrix(commitMap) {
|
|
39026
|
+
function buildCoChangeMatrix(commitMap, maxFilesPerCommit = 500) {
|
|
39027
39027
|
const matrix = new Map;
|
|
39028
39028
|
const fileCommitCount = new Map;
|
|
39029
39029
|
for (const files of commitMap.values()) {
|
|
39030
|
-
const
|
|
39031
|
-
for (const file3 of fileArray) {
|
|
39030
|
+
for (const file3 of files) {
|
|
39032
39031
|
fileCommitCount.set(file3, (fileCommitCount.get(file3) || 0) + 1);
|
|
39033
39032
|
}
|
|
39033
|
+
if (files.size > maxFilesPerCommit)
|
|
39034
|
+
continue;
|
|
39035
|
+
const fileArray = Array.from(files).sort();
|
|
39034
39036
|
for (let i = 0;i < fileArray.length; i++) {
|
|
39035
39037
|
for (let j = i + 1;j < fileArray.length; j++) {
|
|
39036
39038
|
const fileA = fileArray[i];
|
|
@@ -39193,6 +39195,7 @@ async function detectDarkMatter(directory, options) {
|
|
|
39193
39195
|
const minCoChanges = options?.minCoChanges ?? 3;
|
|
39194
39196
|
const npmiThreshold = options?.npmiThreshold ?? 0.5;
|
|
39195
39197
|
const maxCommitsToAnalyze = options?.maxCommitsToAnalyze ?? 500;
|
|
39198
|
+
const maxFilesPerCommit = options?.maxFilesPerCommit ?? 500;
|
|
39196
39199
|
try {
|
|
39197
39200
|
const { stdout } = await getExecFileAsync()("git", ["rev-list", "--count", "HEAD"], {
|
|
39198
39201
|
cwd: directory,
|
|
@@ -39206,7 +39209,7 @@ async function detectDarkMatter(directory, options) {
|
|
|
39206
39209
|
return [];
|
|
39207
39210
|
}
|
|
39208
39211
|
const commitMap = await _internals11.parseGitLog(directory, maxCommitsToAnalyze);
|
|
39209
|
-
const matrix = _internals11.buildCoChangeMatrix(commitMap);
|
|
39212
|
+
const matrix = _internals11.buildCoChangeMatrix(commitMap, maxFilesPerCommit);
|
|
39210
39213
|
const staticEdges = await _internals11.getStaticEdges(directory);
|
|
39211
39214
|
const results = [];
|
|
39212
39215
|
for (const entry of matrix.values()) {
|
|
@@ -45265,6 +45268,1604 @@ var init_knowledge = __esm(() => {
|
|
|
45265
45268
|
init_knowledge_validator();
|
|
45266
45269
|
});
|
|
45267
45270
|
|
|
45271
|
+
// src/memory/config.ts
|
|
45272
|
+
function resolveMemoryConfig(input) {
|
|
45273
|
+
return {
|
|
45274
|
+
...DEFAULT_MEMORY_CONFIG,
|
|
45275
|
+
...input ?? {},
|
|
45276
|
+
sqlite: {
|
|
45277
|
+
...DEFAULT_MEMORY_CONFIG.sqlite,
|
|
45278
|
+
...input?.sqlite ?? {}
|
|
45279
|
+
},
|
|
45280
|
+
recall: {
|
|
45281
|
+
...DEFAULT_MEMORY_CONFIG.recall,
|
|
45282
|
+
...input?.recall ?? {},
|
|
45283
|
+
injection: {
|
|
45284
|
+
...DEFAULT_MEMORY_CONFIG.recall.injection,
|
|
45285
|
+
...input?.recall?.injection ?? {}
|
|
45286
|
+
}
|
|
45287
|
+
},
|
|
45288
|
+
writes: {
|
|
45289
|
+
...DEFAULT_MEMORY_CONFIG.writes,
|
|
45290
|
+
...input?.writes ?? {}
|
|
45291
|
+
},
|
|
45292
|
+
redaction: {
|
|
45293
|
+
...DEFAULT_MEMORY_CONFIG.redaction,
|
|
45294
|
+
...input?.redaction ?? {}
|
|
45295
|
+
}
|
|
45296
|
+
};
|
|
45297
|
+
}
|
|
45298
|
+
var DEFAULT_MEMORY_CONFIG, DURABLE_MEMORY_KINDS, EVIDENCE_REQUIRED_KINDS;
|
|
45299
|
+
var init_config3 = __esm(() => {
|
|
45300
|
+
DEFAULT_MEMORY_CONFIG = {
|
|
45301
|
+
enabled: false,
|
|
45302
|
+
provider: "sqlite",
|
|
45303
|
+
storageDir: ".swarm/memory",
|
|
45304
|
+
sqlite: {
|
|
45305
|
+
path: ".swarm/memory/memory.db",
|
|
45306
|
+
busyTimeoutMs: 5000
|
|
45307
|
+
},
|
|
45308
|
+
recall: {
|
|
45309
|
+
defaultMaxItems: 8,
|
|
45310
|
+
defaultTokenBudget: 1200,
|
|
45311
|
+
minScore: 0.05,
|
|
45312
|
+
injection: {
|
|
45313
|
+
enabled: true,
|
|
45314
|
+
minScore: 0.25,
|
|
45315
|
+
requireQuerySignal: true,
|
|
45316
|
+
maxItems: 6,
|
|
45317
|
+
tokenBudget: 1000
|
|
45318
|
+
}
|
|
45319
|
+
},
|
|
45320
|
+
writes: {
|
|
45321
|
+
mode: "propose"
|
|
45322
|
+
},
|
|
45323
|
+
redaction: {
|
|
45324
|
+
rejectDurableSecrets: true
|
|
45325
|
+
},
|
|
45326
|
+
hardDelete: false
|
|
45327
|
+
};
|
|
45328
|
+
DURABLE_MEMORY_KINDS = new Set([
|
|
45329
|
+
"user_preference",
|
|
45330
|
+
"project_fact",
|
|
45331
|
+
"architecture_decision",
|
|
45332
|
+
"repo_convention",
|
|
45333
|
+
"code_pattern",
|
|
45334
|
+
"test_pattern",
|
|
45335
|
+
"failure_pattern",
|
|
45336
|
+
"security_note"
|
|
45337
|
+
]);
|
|
45338
|
+
EVIDENCE_REQUIRED_KINDS = new Set([
|
|
45339
|
+
"api_finding",
|
|
45340
|
+
"evidence",
|
|
45341
|
+
"security_note"
|
|
45342
|
+
]);
|
|
45343
|
+
});
|
|
45344
|
+
|
|
45345
|
+
// src/memory/errors.ts
|
|
45346
|
+
var MemoryValidationError;
|
|
45347
|
+
var init_errors6 = __esm(() => {
|
|
45348
|
+
MemoryValidationError = class MemoryValidationError extends Error {
|
|
45349
|
+
code;
|
|
45350
|
+
constructor(message, code = "memory_validation_error") {
|
|
45351
|
+
super(message);
|
|
45352
|
+
this.name = "MemoryValidationError";
|
|
45353
|
+
this.code = code;
|
|
45354
|
+
}
|
|
45355
|
+
};
|
|
45356
|
+
});
|
|
45357
|
+
|
|
45358
|
+
// src/memory/redaction.ts
|
|
45359
|
+
function findSecrets(text) {
|
|
45360
|
+
const findings = [];
|
|
45361
|
+
for (const { type, pattern } of SECRET_PATTERNS) {
|
|
45362
|
+
pattern.lastIndex = 0;
|
|
45363
|
+
for (const match of text.matchAll(pattern)) {
|
|
45364
|
+
if (match[0])
|
|
45365
|
+
findings.push({ type, match: match[0] });
|
|
45366
|
+
}
|
|
45367
|
+
}
|
|
45368
|
+
return findings;
|
|
45369
|
+
}
|
|
45370
|
+
function containsSecret(text) {
|
|
45371
|
+
return findSecrets(text).length > 0;
|
|
45372
|
+
}
|
|
45373
|
+
var SECRET_PATTERNS;
|
|
45374
|
+
var init_redaction = __esm(() => {
|
|
45375
|
+
SECRET_PATTERNS = [
|
|
45376
|
+
{ type: "openai_api_key", pattern: /\bsk-[A-Za-z0-9_-]{20,}\b/g },
|
|
45377
|
+
{
|
|
45378
|
+
type: "github_token",
|
|
45379
|
+
pattern: /\b(?:ghp|gho|ghu|ghs|ghr|github_pat)_[A-Za-z0-9_]{20,}\b/g
|
|
45380
|
+
},
|
|
45381
|
+
{ type: "aws_access_key_id", pattern: /\bAKIA[0-9A-Z]{16}\b/g },
|
|
45382
|
+
{
|
|
45383
|
+
type: "private_key_block",
|
|
45384
|
+
pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
|
|
45385
|
+
},
|
|
45386
|
+
{
|
|
45387
|
+
type: "authorization_bearer",
|
|
45388
|
+
pattern: /\bAuthorization\s*:\s*Bearer\s+[A-Za-z0-9._~+/=-]{12,}/gi
|
|
45389
|
+
},
|
|
45390
|
+
{
|
|
45391
|
+
type: "env_secret",
|
|
45392
|
+
pattern: /\b(?:[A-Z0-9]+_)*(?:KEY|TOKEN|SECRET|PASSWORD)\b\s*=\s*["']?[^\s"'`]{8,}["']?/gi
|
|
45393
|
+
}
|
|
45394
|
+
];
|
|
45395
|
+
});
|
|
45396
|
+
|
|
45397
|
+
// src/memory/schema.ts
|
|
45398
|
+
import { createHash as createHash5 } from "crypto";
|
|
45399
|
+
function normalizeMemoryText(text) {
|
|
45400
|
+
return text.replace(/\s+/g, " ").trim();
|
|
45401
|
+
}
|
|
45402
|
+
function stableScopeKey(scope) {
|
|
45403
|
+
const ordered = { type: scope.type };
|
|
45404
|
+
const keys = scope.type === "repository" ? ["repoId"] : [
|
|
45405
|
+
"userId",
|
|
45406
|
+
"workspaceId",
|
|
45407
|
+
"projectId",
|
|
45408
|
+
"repoId",
|
|
45409
|
+
"repoRoot",
|
|
45410
|
+
"runId",
|
|
45411
|
+
"agentId"
|
|
45412
|
+
];
|
|
45413
|
+
for (const key of keys) {
|
|
45414
|
+
const value = scope[key];
|
|
45415
|
+
if (value)
|
|
45416
|
+
ordered[key] = value;
|
|
45417
|
+
}
|
|
45418
|
+
return JSON.stringify(ordered);
|
|
45419
|
+
}
|
|
45420
|
+
function computeMemoryContentHash(recordLike) {
|
|
45421
|
+
const normalized = normalizeMemoryText(recordLike.text).toLowerCase();
|
|
45422
|
+
return createHash5("sha256").update(`${stableScopeKey(recordLike.scope)}
|
|
45423
|
+
${recordLike.kind}
|
|
45424
|
+
${normalized}`).digest("hex");
|
|
45425
|
+
}
|
|
45426
|
+
function createMemoryId(recordLike) {
|
|
45427
|
+
return `mem_${computeMemoryContentHash(recordLike).slice(0, 16)}`;
|
|
45428
|
+
}
|
|
45429
|
+
function isExpired(record3, now = new Date) {
|
|
45430
|
+
if (!record3.expiresAt)
|
|
45431
|
+
return false;
|
|
45432
|
+
const expires = Date.parse(record3.expiresAt);
|
|
45433
|
+
return Number.isFinite(expires) && expires <= now.getTime();
|
|
45434
|
+
}
|
|
45435
|
+
function hasEvidenceSource(record3) {
|
|
45436
|
+
return Boolean(record3.source.url || record3.source.filePath || record3.source.commitSha || record3.source.ref);
|
|
45437
|
+
}
|
|
45438
|
+
function validateMemoryRecordRules(record3, options) {
|
|
45439
|
+
const parsed = MemoryRecordSchema.parse(record3);
|
|
45440
|
+
const expectedHash = computeMemoryContentHash(parsed);
|
|
45441
|
+
const expectedId = createMemoryId(parsed);
|
|
45442
|
+
if (parsed.contentHash !== expectedHash) {
|
|
45443
|
+
throw new MemoryValidationError("contentHash does not match memory content");
|
|
45444
|
+
}
|
|
45445
|
+
if (parsed.id !== expectedId) {
|
|
45446
|
+
throw new MemoryValidationError("id does not match memory content");
|
|
45447
|
+
}
|
|
45448
|
+
if (parsed.stability === "durable" && (parsed.scope.type === "run" || parsed.scope.type === "agent")) {
|
|
45449
|
+
throw new MemoryValidationError("durable memories cannot use run or agent scope");
|
|
45450
|
+
}
|
|
45451
|
+
if (parsed.stability === "durable" && (DURABLE_MEMORY_KINDS.has(parsed.kind) || parsed.kind === "api_finding" || parsed.kind === "evidence") && !hasEvidenceSource(parsed)) {
|
|
45452
|
+
throw new MemoryValidationError("durable project, repository, API, evidence, and security memories require source evidence");
|
|
45453
|
+
}
|
|
45454
|
+
if (EVIDENCE_REQUIRED_KINDS.has(parsed.kind) && !hasEvidenceSource(parsed)) {
|
|
45455
|
+
throw new MemoryValidationError(`${parsed.kind} memories require source evidence`);
|
|
45456
|
+
}
|
|
45457
|
+
if (parsed.kind === "scratch" && (!parsed.expiresAt || Date.parse(parsed.expiresAt) - Date.parse(parsed.createdAt) > 7 * 24 * 60 * 60 * 1000)) {
|
|
45458
|
+
throw new MemoryValidationError("scratch memories must expire within 7 days");
|
|
45459
|
+
}
|
|
45460
|
+
if (options.rejectDurableSecrets && parsed.stability === "durable" && containsSecret(parsed.text)) {
|
|
45461
|
+
throw new MemoryValidationError("durable memory contains a likely secret");
|
|
45462
|
+
}
|
|
45463
|
+
return parsed;
|
|
45464
|
+
}
|
|
45465
|
+
function validateMemoryProposal(proposal) {
|
|
45466
|
+
return MemoryProposalSchema.parse(proposal);
|
|
45467
|
+
}
|
|
45468
|
+
var MemoryScopeTypeSchema, MemoryScopeRefSchema, MemoryKindSchema, MemorySourceSchema, MemoryRecordSchema, MemoryProposalSchema;
|
|
45469
|
+
var init_schema2 = __esm(() => {
|
|
45470
|
+
init_zod();
|
|
45471
|
+
init_config3();
|
|
45472
|
+
init_errors6();
|
|
45473
|
+
init_redaction();
|
|
45474
|
+
MemoryScopeTypeSchema = exports_external.enum([
|
|
45475
|
+
"global_user",
|
|
45476
|
+
"workspace",
|
|
45477
|
+
"project",
|
|
45478
|
+
"repository",
|
|
45479
|
+
"run",
|
|
45480
|
+
"agent"
|
|
45481
|
+
]);
|
|
45482
|
+
MemoryScopeRefSchema = exports_external.object({
|
|
45483
|
+
type: MemoryScopeTypeSchema,
|
|
45484
|
+
userId: exports_external.string().optional(),
|
|
45485
|
+
workspaceId: exports_external.string().optional(),
|
|
45486
|
+
projectId: exports_external.string().optional(),
|
|
45487
|
+
repoId: exports_external.string().optional(),
|
|
45488
|
+
repoRoot: exports_external.string().optional(),
|
|
45489
|
+
runId: exports_external.string().optional(),
|
|
45490
|
+
agentId: exports_external.string().optional()
|
|
45491
|
+
}).strict();
|
|
45492
|
+
MemoryKindSchema = exports_external.enum([
|
|
45493
|
+
"user_preference",
|
|
45494
|
+
"project_fact",
|
|
45495
|
+
"architecture_decision",
|
|
45496
|
+
"repo_convention",
|
|
45497
|
+
"api_finding",
|
|
45498
|
+
"code_pattern",
|
|
45499
|
+
"test_pattern",
|
|
45500
|
+
"failure_pattern",
|
|
45501
|
+
"security_note",
|
|
45502
|
+
"evidence",
|
|
45503
|
+
"todo",
|
|
45504
|
+
"scratch"
|
|
45505
|
+
]);
|
|
45506
|
+
MemorySourceSchema = exports_external.object({
|
|
45507
|
+
type: exports_external.enum([
|
|
45508
|
+
"user",
|
|
45509
|
+
"agent",
|
|
45510
|
+
"tool",
|
|
45511
|
+
"file",
|
|
45512
|
+
"repo",
|
|
45513
|
+
"commit",
|
|
45514
|
+
"test",
|
|
45515
|
+
"web",
|
|
45516
|
+
"manual"
|
|
45517
|
+
]),
|
|
45518
|
+
ref: exports_external.string().optional(),
|
|
45519
|
+
url: exports_external.string().optional(),
|
|
45520
|
+
filePath: exports_external.string().optional(),
|
|
45521
|
+
commitSha: exports_external.string().optional(),
|
|
45522
|
+
createdBy: exports_external.string().optional()
|
|
45523
|
+
}).strict();
|
|
45524
|
+
MemoryRecordSchema = exports_external.object({
|
|
45525
|
+
id: exports_external.string().regex(/^mem_[a-f0-9]{16}$/),
|
|
45526
|
+
scope: MemoryScopeRefSchema,
|
|
45527
|
+
kind: MemoryKindSchema,
|
|
45528
|
+
text: exports_external.string().min(1).max(2000),
|
|
45529
|
+
tags: exports_external.array(exports_external.string().min(1).max(64)).max(32),
|
|
45530
|
+
confidence: exports_external.number().min(0).max(1),
|
|
45531
|
+
stability: exports_external.enum(["ephemeral", "session", "durable"]),
|
|
45532
|
+
source: MemorySourceSchema,
|
|
45533
|
+
createdAt: exports_external.string().datetime(),
|
|
45534
|
+
updatedAt: exports_external.string().datetime(),
|
|
45535
|
+
lastAccessedAt: exports_external.string().datetime().optional(),
|
|
45536
|
+
expiresAt: exports_external.string().datetime().optional(),
|
|
45537
|
+
supersedes: exports_external.array(exports_external.string()).optional(),
|
|
45538
|
+
supersededBy: exports_external.string().optional(),
|
|
45539
|
+
contentHash: exports_external.string().regex(/^[a-f0-9]{64}$/),
|
|
45540
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown())
|
|
45541
|
+
}).strict();
|
|
45542
|
+
MemoryProposalSchema = exports_external.object({
|
|
45543
|
+
id: exports_external.string().regex(/^prop_[a-f0-9]{16}$/),
|
|
45544
|
+
operation: exports_external.enum([
|
|
45545
|
+
"add",
|
|
45546
|
+
"update",
|
|
45547
|
+
"delete",
|
|
45548
|
+
"ignore",
|
|
45549
|
+
"merge",
|
|
45550
|
+
"supersede"
|
|
45551
|
+
]),
|
|
45552
|
+
proposedRecord: MemoryRecordSchema.optional(),
|
|
45553
|
+
targetMemoryId: exports_external.string().optional(),
|
|
45554
|
+
relatedMemoryIds: exports_external.array(exports_external.string()).optional(),
|
|
45555
|
+
proposedBy: exports_external.object({
|
|
45556
|
+
agentRole: exports_external.string().optional(),
|
|
45557
|
+
agentId: exports_external.string().optional(),
|
|
45558
|
+
runId: exports_external.string().optional()
|
|
45559
|
+
}).strict(),
|
|
45560
|
+
rationale: exports_external.string().min(1).max(2000),
|
|
45561
|
+
evidenceRefs: exports_external.array(exports_external.string().min(1).max(500)).max(20),
|
|
45562
|
+
status: exports_external.enum([
|
|
45563
|
+
"pending",
|
|
45564
|
+
"approved",
|
|
45565
|
+
"rejected",
|
|
45566
|
+
"superseded",
|
|
45567
|
+
"applied"
|
|
45568
|
+
]),
|
|
45569
|
+
reviewer: exports_external.enum(["user", "controller", "curator_agent", "auto_policy"]).optional(),
|
|
45570
|
+
reviewedAt: exports_external.string().datetime().optional(),
|
|
45571
|
+
rejectionReason: exports_external.string().optional(),
|
|
45572
|
+
createdAt: exports_external.string().datetime(),
|
|
45573
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown())
|
|
45574
|
+
}).strict();
|
|
45575
|
+
});
|
|
45576
|
+
|
|
45577
|
+
// src/memory/scoring.ts
|
|
45578
|
+
function tokenize(text) {
|
|
45579
|
+
return new Set(text.toLowerCase().replace(/[^\w\s-]/g, " ").split(/\s+/).map((token) => token.trim()).filter(Boolean));
|
|
45580
|
+
}
|
|
45581
|
+
function normalizeKindText(kind) {
|
|
45582
|
+
return kind.replace(/_/g, " ");
|
|
45583
|
+
}
|
|
45584
|
+
function collectMetadataStrings(metadata, keys) {
|
|
45585
|
+
const values = [];
|
|
45586
|
+
for (const key of keys) {
|
|
45587
|
+
const value = metadata[key];
|
|
45588
|
+
if (typeof value === "string")
|
|
45589
|
+
values.push(value);
|
|
45590
|
+
if (Array.isArray(value)) {
|
|
45591
|
+
for (const item of value) {
|
|
45592
|
+
if (typeof item === "string")
|
|
45593
|
+
values.push(item);
|
|
45594
|
+
}
|
|
45595
|
+
}
|
|
45596
|
+
}
|
|
45597
|
+
return values;
|
|
45598
|
+
}
|
|
45599
|
+
function overlap(a, b) {
|
|
45600
|
+
if (a.size === 0 || b.size === 0)
|
|
45601
|
+
return 0;
|
|
45602
|
+
let hits = 0;
|
|
45603
|
+
for (const token of a) {
|
|
45604
|
+
if (b.has(token))
|
|
45605
|
+
hits++;
|
|
45606
|
+
}
|
|
45607
|
+
return hits / Math.max(a.size, 1);
|
|
45608
|
+
}
|
|
45609
|
+
function scopeSpecificityBoost(scope) {
|
|
45610
|
+
switch (scope.type) {
|
|
45611
|
+
case "agent":
|
|
45612
|
+
return 1;
|
|
45613
|
+
case "run":
|
|
45614
|
+
return 0.9;
|
|
45615
|
+
case "repository":
|
|
45616
|
+
return 0.8;
|
|
45617
|
+
case "project":
|
|
45618
|
+
return 0.65;
|
|
45619
|
+
case "workspace":
|
|
45620
|
+
return 0.45;
|
|
45621
|
+
case "global_user":
|
|
45622
|
+
return 0.3;
|
|
45623
|
+
}
|
|
45624
|
+
}
|
|
45625
|
+
function kindProfileBoost(kind, request) {
|
|
45626
|
+
if (!request.kinds || request.kinds.length === 0)
|
|
45627
|
+
return 0.5;
|
|
45628
|
+
return request.kinds.includes(kind) ? 1 : 0;
|
|
45629
|
+
}
|
|
45630
|
+
function sameScope(a, b) {
|
|
45631
|
+
return stableScopeKey(a) === stableScopeKey(b);
|
|
45632
|
+
}
|
|
45633
|
+
function scopeAllowed(recordScope, allowedScopes) {
|
|
45634
|
+
return allowedScopes.some((scope) => sameScope(recordScope, scope));
|
|
45635
|
+
}
|
|
45636
|
+
function scoreMemoryRecordDetailed(record3, request) {
|
|
45637
|
+
if (!request.includeExpired && isExpired(record3)) {
|
|
45638
|
+
return { item: null, skipReason: "filtered" };
|
|
45639
|
+
}
|
|
45640
|
+
if (record3.supersededBy)
|
|
45641
|
+
return { item: null, skipReason: "filtered" };
|
|
45642
|
+
if (record3.metadata.deleted === true) {
|
|
45643
|
+
return { item: null, skipReason: "filtered" };
|
|
45644
|
+
}
|
|
45645
|
+
if (!scopeAllowed(record3.scope, request.scopes)) {
|
|
45646
|
+
return { item: null, skipReason: "filtered" };
|
|
45647
|
+
}
|
|
45648
|
+
if (request.kinds && !request.kinds.includes(record3.kind)) {
|
|
45649
|
+
return { item: null, skipReason: "filtered" };
|
|
45650
|
+
}
|
|
45651
|
+
const queryTokens = request.mode === "injection" && request.task ? tokenize(request.task) : tokenize(request.query);
|
|
45652
|
+
const textTokens = tokenize(record3.text);
|
|
45653
|
+
const tagTokens = tokenize(record3.tags.join(" "));
|
|
45654
|
+
const fileTokens = tokenize([
|
|
45655
|
+
record3.source.filePath,
|
|
45656
|
+
...collectMetadataStrings(record3.metadata, [
|
|
45657
|
+
"file",
|
|
45658
|
+
"filePath",
|
|
45659
|
+
"files",
|
|
45660
|
+
"touchedFiles"
|
|
45661
|
+
])
|
|
45662
|
+
].filter((value) => typeof value === "string").join(" "));
|
|
45663
|
+
const symbolTokens = tokenize(collectMetadataStrings(record3.metadata, ["symbol", "symbols"]).join(" "));
|
|
45664
|
+
const kindQueryOverlap = overlap(queryTokens, tokenize(normalizeKindText(record3.kind)));
|
|
45665
|
+
const textOverlap = overlap(queryTokens, textTokens);
|
|
45666
|
+
const tagOverlap = overlap(queryTokens, tagTokens);
|
|
45667
|
+
const fileOverlap = overlap(queryTokens, fileTokens);
|
|
45668
|
+
const symbolOverlap = overlap(queryTokens, symbolTokens);
|
|
45669
|
+
const kindMatch = request.kinds?.includes(record3.kind) ?? false;
|
|
45670
|
+
const scopeMatch = scopeAllowed(record3.scope, request.scopes);
|
|
45671
|
+
const hasQuerySignal = textOverlap > 0 || tagOverlap > 0 || fileOverlap > 0 || symbolOverlap > 0 || kindQueryOverlap > 0;
|
|
45672
|
+
if (request.mode === "injection" && request.requireQuerySignal !== false && !hasQuerySignal) {
|
|
45673
|
+
return { item: null, skipReason: "no_signal" };
|
|
45674
|
+
}
|
|
45675
|
+
const score = textOverlap * 0.45 + tagOverlap * 0.2 + fileOverlap * 0.05 + symbolOverlap * 0.05 + scopeSpecificityBoost(record3.scope) * 0.15 + kindProfileBoost(record3.kind, request) * 0.1 + record3.confidence * 0.1;
|
|
45676
|
+
const reasonParts = [
|
|
45677
|
+
textOverlap > 0 ? `text_overlap=${textOverlap.toFixed(2)}` : null,
|
|
45678
|
+
tagOverlap > 0 ? `tag_overlap=${tagOverlap.toFixed(2)}` : null,
|
|
45679
|
+
fileOverlap > 0 ? `file_overlap=${fileOverlap.toFixed(2)}` : null,
|
|
45680
|
+
symbolOverlap > 0 ? `symbol_overlap=${symbolOverlap.toFixed(2)}` : null,
|
|
45681
|
+
kindQueryOverlap > 0 ? `kind_query=${kindQueryOverlap.toFixed(2)}` : null,
|
|
45682
|
+
`scope=${record3.scope.type}`,
|
|
45683
|
+
`confidence=${record3.confidence.toFixed(2)}`
|
|
45684
|
+
].filter(Boolean);
|
|
45685
|
+
return {
|
|
45686
|
+
item: {
|
|
45687
|
+
record: record3,
|
|
45688
|
+
score,
|
|
45689
|
+
reason: reasonParts.join(", "),
|
|
45690
|
+
signals: {
|
|
45691
|
+
textOverlap,
|
|
45692
|
+
tagOverlap,
|
|
45693
|
+
fileOverlap,
|
|
45694
|
+
symbolOverlap,
|
|
45695
|
+
kindMatch,
|
|
45696
|
+
scopeMatch
|
|
45697
|
+
}
|
|
45698
|
+
}
|
|
45699
|
+
};
|
|
45700
|
+
}
|
|
45701
|
+
function scoreMemoryRecordsWithDiagnostics(records, request) {
|
|
45702
|
+
const minScore = request.minScore ?? 0;
|
|
45703
|
+
const diagnostics = {
|
|
45704
|
+
candidateCount: records.length,
|
|
45705
|
+
preScoredFilteredCount: 0,
|
|
45706
|
+
scoredCount: 0,
|
|
45707
|
+
returnedCount: 0,
|
|
45708
|
+
noSignalCount: 0,
|
|
45709
|
+
belowThresholdCount: 0
|
|
45710
|
+
};
|
|
45711
|
+
const items = [];
|
|
45712
|
+
for (const record3 of records) {
|
|
45713
|
+
const result = scoreMemoryRecordDetailed(record3, request);
|
|
45714
|
+
if (!result.item) {
|
|
45715
|
+
if (result.skipReason === "filtered")
|
|
45716
|
+
diagnostics.preScoredFilteredCount++;
|
|
45717
|
+
if (result.skipReason === "no_signal")
|
|
45718
|
+
diagnostics.noSignalCount++;
|
|
45719
|
+
continue;
|
|
45720
|
+
}
|
|
45721
|
+
diagnostics.scoredCount++;
|
|
45722
|
+
if (result.item.score < minScore) {
|
|
45723
|
+
diagnostics.belowThresholdCount++;
|
|
45724
|
+
continue;
|
|
45725
|
+
}
|
|
45726
|
+
items.push(result.item);
|
|
45727
|
+
}
|
|
45728
|
+
items.sort((a, b) => b.score - a.score || a.record.id.localeCompare(b.record.id));
|
|
45729
|
+
diagnostics.returnedCount = items.length;
|
|
45730
|
+
return { items, diagnostics };
|
|
45731
|
+
}
|
|
45732
|
+
var init_scoring = __esm(() => {
|
|
45733
|
+
init_schema2();
|
|
45734
|
+
});
|
|
45735
|
+
|
|
45736
|
+
// src/memory/local-jsonl-provider.ts
|
|
45737
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
45738
|
+
import { existsSync as existsSync18 } from "fs";
|
|
45739
|
+
import {
|
|
45740
|
+
appendFile as appendFile4,
|
|
45741
|
+
mkdir as mkdir8,
|
|
45742
|
+
readFile as readFile8,
|
|
45743
|
+
rename as rename6,
|
|
45744
|
+
writeFile as writeFile9
|
|
45745
|
+
} from "fs/promises";
|
|
45746
|
+
import * as path29 from "path";
|
|
45747
|
+
|
|
45748
|
+
class LocalJsonlMemoryProvider {
|
|
45749
|
+
name = "local-jsonl";
|
|
45750
|
+
rootDirectory;
|
|
45751
|
+
config;
|
|
45752
|
+
initialized = false;
|
|
45753
|
+
memories = new Map;
|
|
45754
|
+
proposals = new Map;
|
|
45755
|
+
constructor(rootDirectory, config3 = {}) {
|
|
45756
|
+
this.rootDirectory = rootDirectory;
|
|
45757
|
+
this.config = { ...DEFAULT_MEMORY_CONFIG, ...config3 };
|
|
45758
|
+
}
|
|
45759
|
+
pathFor(file3) {
|
|
45760
|
+
const storageDir = this.config.storageDir.replace(/^\.swarm[/\\]?/, "");
|
|
45761
|
+
const filename = file3 === "memories" ? "memories.jsonl" : file3 === "proposals" ? "proposals.jsonl" : "audit.jsonl";
|
|
45762
|
+
return validateSwarmPath(this.rootDirectory, path29.join(storageDir, filename));
|
|
45763
|
+
}
|
|
45764
|
+
async initialize() {
|
|
45765
|
+
if (this.initialized)
|
|
45766
|
+
return;
|
|
45767
|
+
const memoryPath = this.pathFor("memories");
|
|
45768
|
+
const proposalPath2 = this.pathFor("proposals");
|
|
45769
|
+
const memoryLoad = validateLoadedMemories(await readJsonl(memoryPath), this.config);
|
|
45770
|
+
const proposalLoad = validateLoadedProposals(await readJsonl(proposalPath2), this.config);
|
|
45771
|
+
this.memories = new Map(memoryLoad.records.map((record3) => [record3.id, record3]));
|
|
45772
|
+
this.proposals = new Map(proposalLoad.records.map((proposal) => [proposal.id, proposal]));
|
|
45773
|
+
this.initialized = true;
|
|
45774
|
+
if (memoryLoad.invalidCount > 0) {
|
|
45775
|
+
await this.audit("invalid_load", "memories", `${memoryLoad.invalidCount} invalid memory JSONL row(s) skipped`);
|
|
45776
|
+
}
|
|
45777
|
+
if (proposalLoad.invalidCount > 0) {
|
|
45778
|
+
await this.audit("invalid_load", "proposals", `${proposalLoad.invalidCount} invalid proposal JSONL row(s) skipped`);
|
|
45779
|
+
}
|
|
45780
|
+
}
|
|
45781
|
+
async upsert(record3) {
|
|
45782
|
+
await this.initialize();
|
|
45783
|
+
const existing = this.memories.get(record3.id);
|
|
45784
|
+
if (existing?.metadata.deleted === true) {
|
|
45785
|
+
throw new MemoryValidationError("memory is tombstoned and cannot be upserted");
|
|
45786
|
+
}
|
|
45787
|
+
const next = validateMemoryRecordRules({
|
|
45788
|
+
...record3,
|
|
45789
|
+
createdAt: existing?.createdAt ?? record3.createdAt
|
|
45790
|
+
}, { rejectDurableSecrets: this.config.redaction.rejectDurableSecrets });
|
|
45791
|
+
this.memories.set(next.id, next);
|
|
45792
|
+
await appendJsonl(this.pathFor("memories"), next);
|
|
45793
|
+
await this.audit("upsert", next.id);
|
|
45794
|
+
return next;
|
|
45795
|
+
}
|
|
45796
|
+
async get(id) {
|
|
45797
|
+
await this.initialize();
|
|
45798
|
+
return this.memories.get(id) ?? null;
|
|
45799
|
+
}
|
|
45800
|
+
async delete(id, reason) {
|
|
45801
|
+
await this.initialize();
|
|
45802
|
+
const existing = this.memories.get(id);
|
|
45803
|
+
if (!existing)
|
|
45804
|
+
return;
|
|
45805
|
+
if (this.config.hardDelete) {
|
|
45806
|
+
this.memories.delete(id);
|
|
45807
|
+
await this.compact();
|
|
45808
|
+
} else {
|
|
45809
|
+
const tombstone = {
|
|
45810
|
+
...existing,
|
|
45811
|
+
updatedAt: new Date().toISOString(),
|
|
45812
|
+
metadata: { ...existing.metadata, deleted: true, deleteReason: reason }
|
|
45813
|
+
};
|
|
45814
|
+
this.memories.set(id, tombstone);
|
|
45815
|
+
await appendJsonl(this.pathFor("memories"), tombstone);
|
|
45816
|
+
}
|
|
45817
|
+
await this.audit("delete", id, reason);
|
|
45818
|
+
}
|
|
45819
|
+
async recall(request) {
|
|
45820
|
+
return (await this.recallWithDiagnostics(request)).items;
|
|
45821
|
+
}
|
|
45822
|
+
async recallWithDiagnostics(request) {
|
|
45823
|
+
await this.initialize();
|
|
45824
|
+
const records = await this.list({
|
|
45825
|
+
scopes: request.scopes,
|
|
45826
|
+
kinds: request.kinds,
|
|
45827
|
+
includeExpired: request.includeExpired
|
|
45828
|
+
});
|
|
45829
|
+
const result = scoreMemoryRecordsWithDiagnostics(records, request);
|
|
45830
|
+
return {
|
|
45831
|
+
items: result.items.slice(0, request.maxItems),
|
|
45832
|
+
diagnostics: {
|
|
45833
|
+
...result.diagnostics,
|
|
45834
|
+
returnedCount: Math.min(result.diagnostics.returnedCount, request.maxItems)
|
|
45835
|
+
}
|
|
45836
|
+
};
|
|
45837
|
+
}
|
|
45838
|
+
async recordRecallUsage(event) {
|
|
45839
|
+
await this.initialize();
|
|
45840
|
+
await this.audit("recall", event.bundleId, JSON.stringify({
|
|
45841
|
+
query: event.query,
|
|
45842
|
+
scopes: event.scopes,
|
|
45843
|
+
kinds: event.kinds,
|
|
45844
|
+
memoryIds: event.memoryIds,
|
|
45845
|
+
scores: event.scores,
|
|
45846
|
+
tokenEstimate: event.tokenEstimate,
|
|
45847
|
+
agentRole: event.agentRole,
|
|
45848
|
+
runId: event.runId
|
|
45849
|
+
}));
|
|
45850
|
+
}
|
|
45851
|
+
async list(filter = {}) {
|
|
45852
|
+
await this.initialize();
|
|
45853
|
+
let records = Array.from(this.memories.values());
|
|
45854
|
+
if (filter.scopes && filter.scopes.length > 0) {
|
|
45855
|
+
records = records.filter((record3) => scopeAllowed(record3.scope, filter.scopes ?? []));
|
|
45856
|
+
}
|
|
45857
|
+
if (filter.kinds && filter.kinds.length > 0) {
|
|
45858
|
+
records = records.filter((record3) => filter.kinds?.includes(record3.kind));
|
|
45859
|
+
}
|
|
45860
|
+
if (!filter.includeExpired) {
|
|
45861
|
+
const now = Date.now();
|
|
45862
|
+
records = records.filter((record3) => {
|
|
45863
|
+
if (!record3.expiresAt)
|
|
45864
|
+
return true;
|
|
45865
|
+
const expires = Date.parse(record3.expiresAt);
|
|
45866
|
+
return !Number.isFinite(expires) || expires > now;
|
|
45867
|
+
});
|
|
45868
|
+
}
|
|
45869
|
+
records = records.filter((record3) => !record3.supersededBy && record3.metadata.deleted !== true);
|
|
45870
|
+
records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
45871
|
+
return records.slice(0, filter.limit ?? records.length);
|
|
45872
|
+
}
|
|
45873
|
+
async createProposal(proposal) {
|
|
45874
|
+
await this.initialize();
|
|
45875
|
+
const next = validateMemoryProposal(proposal);
|
|
45876
|
+
this.proposals.set(next.id, next);
|
|
45877
|
+
await appendJsonl(this.pathFor("proposals"), next);
|
|
45878
|
+
await this.audit("proposal", next.id);
|
|
45879
|
+
return next;
|
|
45880
|
+
}
|
|
45881
|
+
async listProposals(filter = {}) {
|
|
45882
|
+
await this.initialize();
|
|
45883
|
+
let proposals = Array.from(this.proposals.values());
|
|
45884
|
+
if (filter.status) {
|
|
45885
|
+
proposals = proposals.filter((proposal) => proposal.status === filter.status);
|
|
45886
|
+
}
|
|
45887
|
+
proposals.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
45888
|
+
return proposals.slice(0, filter.limit ?? proposals.length);
|
|
45889
|
+
}
|
|
45890
|
+
async compact() {
|
|
45891
|
+
await this.initialize();
|
|
45892
|
+
await writeJsonlAtomic(this.pathFor("memories"), Array.from(this.memories.values()));
|
|
45893
|
+
await this.audit("compact", "memories");
|
|
45894
|
+
}
|
|
45895
|
+
async audit(operation, targetId, reason) {
|
|
45896
|
+
const event = {
|
|
45897
|
+
id: randomUUID3(),
|
|
45898
|
+
operation,
|
|
45899
|
+
targetId,
|
|
45900
|
+
reason,
|
|
45901
|
+
timestamp: new Date().toISOString()
|
|
45902
|
+
};
|
|
45903
|
+
await appendJsonl(this.pathFor("audit"), event);
|
|
45904
|
+
}
|
|
45905
|
+
}
|
|
45906
|
+
function validateLoadedMemories(values, config3) {
|
|
45907
|
+
const records = [];
|
|
45908
|
+
let invalidCount = 0;
|
|
45909
|
+
for (const value of values) {
|
|
45910
|
+
try {
|
|
45911
|
+
records.push(validateMemoryRecordRules(value, {
|
|
45912
|
+
rejectDurableSecrets: config3.redaction.rejectDurableSecrets
|
|
45913
|
+
}));
|
|
45914
|
+
} catch {
|
|
45915
|
+
invalidCount++;
|
|
45916
|
+
}
|
|
45917
|
+
}
|
|
45918
|
+
return { records, invalidCount };
|
|
45919
|
+
}
|
|
45920
|
+
function validateLoadedProposals(values, config3) {
|
|
45921
|
+
const records = [];
|
|
45922
|
+
let invalidCount = 0;
|
|
45923
|
+
for (const value of values) {
|
|
45924
|
+
try {
|
|
45925
|
+
const proposal = validateMemoryProposal(value);
|
|
45926
|
+
if (proposal.proposedRecord) {
|
|
45927
|
+
validateMemoryRecordRules(proposal.proposedRecord, {
|
|
45928
|
+
rejectDurableSecrets: config3.redaction.rejectDurableSecrets
|
|
45929
|
+
});
|
|
45930
|
+
}
|
|
45931
|
+
records.push(proposal);
|
|
45932
|
+
} catch {
|
|
45933
|
+
invalidCount++;
|
|
45934
|
+
}
|
|
45935
|
+
}
|
|
45936
|
+
return { records, invalidCount };
|
|
45937
|
+
}
|
|
45938
|
+
async function readJsonl(filePath) {
|
|
45939
|
+
if (!existsSync18(filePath))
|
|
45940
|
+
return [];
|
|
45941
|
+
const content = await readFile8(filePath, "utf-8");
|
|
45942
|
+
const records = [];
|
|
45943
|
+
for (const line of content.split(`
|
|
45944
|
+
`)) {
|
|
45945
|
+
const trimmed = line.trim();
|
|
45946
|
+
if (!trimmed)
|
|
45947
|
+
continue;
|
|
45948
|
+
try {
|
|
45949
|
+
records.push(JSON.parse(trimmed));
|
|
45950
|
+
} catch {}
|
|
45951
|
+
}
|
|
45952
|
+
return records;
|
|
45953
|
+
}
|
|
45954
|
+
async function appendJsonl(filePath, value) {
|
|
45955
|
+
await mkdir8(path29.dirname(filePath), { recursive: true });
|
|
45956
|
+
await appendFile4(filePath, `${JSON.stringify(value)}
|
|
45957
|
+
`, "utf-8");
|
|
45958
|
+
}
|
|
45959
|
+
async function writeJsonlAtomic(filePath, values) {
|
|
45960
|
+
await mkdir8(path29.dirname(filePath), { recursive: true });
|
|
45961
|
+
const tmp = `${filePath}.tmp.${randomUUID3()}`;
|
|
45962
|
+
const content = values.map((value) => JSON.stringify(value)).join(`
|
|
45963
|
+
`) + (values.length > 0 ? `
|
|
45964
|
+
` : "");
|
|
45965
|
+
await writeFile9(tmp, content, "utf-8");
|
|
45966
|
+
await rename6(tmp, filePath);
|
|
45967
|
+
}
|
|
45968
|
+
var init_local_jsonl_provider = __esm(() => {
|
|
45969
|
+
init_utils2();
|
|
45970
|
+
init_config3();
|
|
45971
|
+
init_errors6();
|
|
45972
|
+
init_schema2();
|
|
45973
|
+
init_scoring();
|
|
45974
|
+
});
|
|
45975
|
+
|
|
45976
|
+
// src/memory/prompt-block.ts
|
|
45977
|
+
var init_prompt_block = __esm(() => {
|
|
45978
|
+
init_utils2();
|
|
45979
|
+
init_redaction();
|
|
45980
|
+
});
|
|
45981
|
+
|
|
45982
|
+
// src/memory/jsonl-migration.ts
|
|
45983
|
+
import { existsSync as existsSync19 } from "fs";
|
|
45984
|
+
import { copyFile, mkdir as mkdir9, readFile as readFile9, stat as stat3, writeFile as writeFile10 } from "fs/promises";
|
|
45985
|
+
import * as path30 from "path";
|
|
45986
|
+
function resolveMemoryStorageDir(rootDirectory, config3 = {}) {
|
|
45987
|
+
const resolved = resolveConfig(config3);
|
|
45988
|
+
const storageDir = resolved.storageDir.replace(/^\.swarm[/\\]?/, "");
|
|
45989
|
+
return validateSwarmPath(rootDirectory, storageDir);
|
|
45990
|
+
}
|
|
45991
|
+
function resolveSqliteDatabasePath(rootDirectory, config3 = {}) {
|
|
45992
|
+
const resolved = resolveConfig(config3);
|
|
45993
|
+
const relativePath = resolved.sqlite.path.replace(/^\.swarm[/\\]?/, "");
|
|
45994
|
+
return validateSwarmPath(rootDirectory, relativePath);
|
|
45995
|
+
}
|
|
45996
|
+
async function readLegacyJsonl(rootDirectory, config3 = {}) {
|
|
45997
|
+
const resolved = resolveConfig(config3);
|
|
45998
|
+
const storageDir = resolveMemoryStorageDir(rootDirectory, resolved);
|
|
45999
|
+
const memoryLoad = await readMemoryJsonl(path30.join(storageDir, "memories.jsonl"), resolved);
|
|
46000
|
+
const proposalLoad = await readProposalJsonl(path30.join(storageDir, "proposals.jsonl"), resolved);
|
|
46001
|
+
return {
|
|
46002
|
+
memories: memoryLoad.records,
|
|
46003
|
+
proposals: proposalLoad.records,
|
|
46004
|
+
invalidRows: [...memoryLoad.invalidRows, ...proposalLoad.invalidRows],
|
|
46005
|
+
totalRows: memoryLoad.totalRows + proposalLoad.totalRows
|
|
46006
|
+
};
|
|
46007
|
+
}
|
|
46008
|
+
async function backupLegacyJsonl(rootDirectory, config3 = {}) {
|
|
46009
|
+
const storageDir = resolveMemoryStorageDir(rootDirectory, config3);
|
|
46010
|
+
const backupDir = path30.join(storageDir, "backups");
|
|
46011
|
+
await mkdir9(backupDir, { recursive: true });
|
|
46012
|
+
const results = [];
|
|
46013
|
+
for (const filename of ["memories.jsonl", "proposals.jsonl"]) {
|
|
46014
|
+
const source = path30.join(storageDir, filename);
|
|
46015
|
+
if (!existsSync19(source))
|
|
46016
|
+
continue;
|
|
46017
|
+
const backup = path30.join(backupDir, `${filename}.pre-sqlite-migration`);
|
|
46018
|
+
if (existsSync19(backup)) {
|
|
46019
|
+
results.push({ source, backup, created: false });
|
|
46020
|
+
continue;
|
|
46021
|
+
}
|
|
46022
|
+
await copyFile(source, backup);
|
|
46023
|
+
results.push({ source, backup, created: true });
|
|
46024
|
+
}
|
|
46025
|
+
return results;
|
|
46026
|
+
}
|
|
46027
|
+
async function writeJsonlExport(rootDirectory, config3, memories, proposals) {
|
|
46028
|
+
const exportDir = path30.join(resolveMemoryStorageDir(rootDirectory, config3), "export");
|
|
46029
|
+
await mkdir9(exportDir, { recursive: true });
|
|
46030
|
+
const memoriesPath = path30.join(exportDir, "memories.jsonl");
|
|
46031
|
+
const proposalsPath = path30.join(exportDir, "proposals.jsonl");
|
|
46032
|
+
await writeFile10(memoriesPath, toJsonl(memories), "utf-8");
|
|
46033
|
+
await writeFile10(proposalsPath, toJsonl(proposals), "utf-8");
|
|
46034
|
+
return { directory: exportDir, memoriesPath, proposalsPath };
|
|
46035
|
+
}
|
|
46036
|
+
async function writeMigrationReport(rootDirectory, report, config3 = {}) {
|
|
46037
|
+
const reportPath = path30.join(resolveMemoryStorageDir(rootDirectory, config3), "migration-report.json");
|
|
46038
|
+
await mkdir9(path30.dirname(reportPath), { recursive: true });
|
|
46039
|
+
await writeFile10(reportPath, `${JSON.stringify(report, null, 2)}
|
|
46040
|
+
`, "utf-8");
|
|
46041
|
+
return reportPath;
|
|
46042
|
+
}
|
|
46043
|
+
async function readMigrationReport(rootDirectory, config3 = {}) {
|
|
46044
|
+
const reportPath = path30.join(resolveMemoryStorageDir(rootDirectory, config3), "migration-report.json");
|
|
46045
|
+
if (!existsSync19(reportPath))
|
|
46046
|
+
return null;
|
|
46047
|
+
try {
|
|
46048
|
+
return JSON.parse(await readFile9(reportPath, "utf-8"));
|
|
46049
|
+
} catch {
|
|
46050
|
+
return null;
|
|
46051
|
+
}
|
|
46052
|
+
}
|
|
46053
|
+
async function getLegacyJsonlFileStatus(rootDirectory, config3 = {}) {
|
|
46054
|
+
const storageDir = resolveMemoryStorageDir(rootDirectory, config3);
|
|
46055
|
+
const statuses = [];
|
|
46056
|
+
for (const file3 of ["memories.jsonl", "proposals.jsonl"]) {
|
|
46057
|
+
const filePath = path30.join(storageDir, file3);
|
|
46058
|
+
let sizeBytes = 0;
|
|
46059
|
+
if (existsSync19(filePath)) {
|
|
46060
|
+
sizeBytes = (await stat3(filePath)).size;
|
|
46061
|
+
}
|
|
46062
|
+
statuses.push({
|
|
46063
|
+
file: file3,
|
|
46064
|
+
path: filePath,
|
|
46065
|
+
exists: existsSync19(filePath),
|
|
46066
|
+
sizeBytes
|
|
46067
|
+
});
|
|
46068
|
+
}
|
|
46069
|
+
return statuses;
|
|
46070
|
+
}
|
|
46071
|
+
function resolveConfig(config3) {
|
|
46072
|
+
return {
|
|
46073
|
+
...DEFAULT_MEMORY_CONFIG,
|
|
46074
|
+
...config3,
|
|
46075
|
+
sqlite: {
|
|
46076
|
+
...DEFAULT_MEMORY_CONFIG.sqlite,
|
|
46077
|
+
...config3.sqlite ?? {}
|
|
46078
|
+
},
|
|
46079
|
+
recall: {
|
|
46080
|
+
...DEFAULT_MEMORY_CONFIG.recall,
|
|
46081
|
+
...config3.recall ?? {},
|
|
46082
|
+
injection: {
|
|
46083
|
+
...DEFAULT_MEMORY_CONFIG.recall.injection,
|
|
46084
|
+
...config3.recall?.injection ?? {}
|
|
46085
|
+
}
|
|
46086
|
+
},
|
|
46087
|
+
writes: {
|
|
46088
|
+
...DEFAULT_MEMORY_CONFIG.writes,
|
|
46089
|
+
...config3.writes ?? {}
|
|
46090
|
+
},
|
|
46091
|
+
redaction: {
|
|
46092
|
+
...DEFAULT_MEMORY_CONFIG.redaction,
|
|
46093
|
+
...config3.redaction ?? {}
|
|
46094
|
+
}
|
|
46095
|
+
};
|
|
46096
|
+
}
|
|
46097
|
+
async function readMemoryJsonl(filePath, config3) {
|
|
46098
|
+
const rows = await readJsonlRows(filePath);
|
|
46099
|
+
const records = [];
|
|
46100
|
+
const invalidRows = [];
|
|
46101
|
+
for (const row of rows.rows) {
|
|
46102
|
+
try {
|
|
46103
|
+
records.push(validateMemoryRecordRules(row.value, {
|
|
46104
|
+
rejectDurableSecrets: config3.redaction.rejectDurableSecrets
|
|
46105
|
+
}));
|
|
46106
|
+
} catch (err) {
|
|
46107
|
+
invalidRows.push({
|
|
46108
|
+
file: "memories.jsonl",
|
|
46109
|
+
line: row.line,
|
|
46110
|
+
error: err instanceof Error ? err.message : String(err)
|
|
46111
|
+
});
|
|
46112
|
+
}
|
|
46113
|
+
}
|
|
46114
|
+
for (const row of rows.invalidRows) {
|
|
46115
|
+
invalidRows.push({ file: "memories.jsonl", ...row });
|
|
46116
|
+
}
|
|
46117
|
+
return { records, invalidRows, totalRows: rows.totalRows };
|
|
46118
|
+
}
|
|
46119
|
+
async function readProposalJsonl(filePath, config3) {
|
|
46120
|
+
const rows = await readJsonlRows(filePath);
|
|
46121
|
+
const records = [];
|
|
46122
|
+
const invalidRows = [];
|
|
46123
|
+
for (const row of rows.rows) {
|
|
46124
|
+
try {
|
|
46125
|
+
const proposal = validateMemoryProposal(row.value);
|
|
46126
|
+
if (proposal.proposedRecord) {
|
|
46127
|
+
validateMemoryRecordRules(proposal.proposedRecord, {
|
|
46128
|
+
rejectDurableSecrets: config3.redaction.rejectDurableSecrets
|
|
46129
|
+
});
|
|
46130
|
+
}
|
|
46131
|
+
records.push(proposal);
|
|
46132
|
+
} catch (err) {
|
|
46133
|
+
invalidRows.push({
|
|
46134
|
+
file: "proposals.jsonl",
|
|
46135
|
+
line: row.line,
|
|
46136
|
+
error: err instanceof Error ? err.message : String(err)
|
|
46137
|
+
});
|
|
46138
|
+
}
|
|
46139
|
+
}
|
|
46140
|
+
for (const row of rows.invalidRows) {
|
|
46141
|
+
invalidRows.push({ file: "proposals.jsonl", ...row });
|
|
46142
|
+
}
|
|
46143
|
+
return { records, invalidRows, totalRows: rows.totalRows };
|
|
46144
|
+
}
|
|
46145
|
+
async function readJsonlRows(filePath) {
|
|
46146
|
+
if (!existsSync19(filePath)) {
|
|
46147
|
+
return { rows: [], invalidRows: [], totalRows: 0 };
|
|
46148
|
+
}
|
|
46149
|
+
const content = await readFile9(filePath, "utf-8");
|
|
46150
|
+
const rows = [];
|
|
46151
|
+
const invalidRows = [];
|
|
46152
|
+
let totalRows = 0;
|
|
46153
|
+
const lines = content.split(/\r?\n/);
|
|
46154
|
+
for (let index = 0;index < lines.length; index++) {
|
|
46155
|
+
const trimmed = lines[index].trim();
|
|
46156
|
+
if (!trimmed)
|
|
46157
|
+
continue;
|
|
46158
|
+
totalRows++;
|
|
46159
|
+
try {
|
|
46160
|
+
rows.push({ line: index + 1, value: JSON.parse(trimmed) });
|
|
46161
|
+
} catch (err) {
|
|
46162
|
+
invalidRows.push({
|
|
46163
|
+
line: index + 1,
|
|
46164
|
+
error: err instanceof Error ? err.message : String(err)
|
|
46165
|
+
});
|
|
46166
|
+
}
|
|
46167
|
+
}
|
|
46168
|
+
return { rows, invalidRows, totalRows };
|
|
46169
|
+
}
|
|
46170
|
+
function toJsonl(values) {
|
|
46171
|
+
return values.map((value) => JSON.stringify(value)).join(`
|
|
46172
|
+
`) + (values.length > 0 ? `
|
|
46173
|
+
` : "");
|
|
46174
|
+
}
|
|
46175
|
+
var LEGACY_JSONL_MIGRATION_VERSION = 2, LEGACY_JSONL_MIGRATION_NAME = "legacy_jsonl_import_complete";
|
|
46176
|
+
var init_jsonl_migration = __esm(() => {
|
|
46177
|
+
init_utils2();
|
|
46178
|
+
init_config3();
|
|
46179
|
+
init_schema2();
|
|
46180
|
+
});
|
|
46181
|
+
|
|
46182
|
+
// src/memory/sqlite-provider.ts
|
|
46183
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
46184
|
+
import { mkdirSync as mkdirSync12 } from "fs";
|
|
46185
|
+
import { createRequire as createRequire2 } from "module";
|
|
46186
|
+
import * as path31 from "path";
|
|
46187
|
+
function loadDatabaseCtor2() {
|
|
46188
|
+
if (_DatabaseCtor2)
|
|
46189
|
+
return _DatabaseCtor2;
|
|
46190
|
+
const req = createRequire2(import.meta.url);
|
|
46191
|
+
_DatabaseCtor2 = req("bun:sqlite").Database;
|
|
46192
|
+
return _DatabaseCtor2;
|
|
46193
|
+
}
|
|
46194
|
+
|
|
46195
|
+
class SQLiteMemoryProvider {
|
|
46196
|
+
name = "sqlite";
|
|
46197
|
+
rootDirectory;
|
|
46198
|
+
config;
|
|
46199
|
+
initialized = false;
|
|
46200
|
+
db = null;
|
|
46201
|
+
memories = new Map;
|
|
46202
|
+
proposals = new Map;
|
|
46203
|
+
lastAutomaticJsonlMigration = null;
|
|
46204
|
+
constructor(rootDirectory, config3 = {}) {
|
|
46205
|
+
this.rootDirectory = rootDirectory;
|
|
46206
|
+
this.config = {
|
|
46207
|
+
...DEFAULT_MEMORY_CONFIG,
|
|
46208
|
+
...config3,
|
|
46209
|
+
sqlite: {
|
|
46210
|
+
...DEFAULT_MEMORY_CONFIG.sqlite,
|
|
46211
|
+
...config3.sqlite ?? {}
|
|
46212
|
+
},
|
|
46213
|
+
recall: {
|
|
46214
|
+
...DEFAULT_MEMORY_CONFIG.recall,
|
|
46215
|
+
...config3.recall ?? {},
|
|
46216
|
+
injection: {
|
|
46217
|
+
...DEFAULT_MEMORY_CONFIG.recall.injection,
|
|
46218
|
+
...config3.recall?.injection ?? {}
|
|
46219
|
+
}
|
|
46220
|
+
},
|
|
46221
|
+
writes: {
|
|
46222
|
+
...DEFAULT_MEMORY_CONFIG.writes,
|
|
46223
|
+
...config3.writes ?? {}
|
|
46224
|
+
},
|
|
46225
|
+
redaction: {
|
|
46226
|
+
...DEFAULT_MEMORY_CONFIG.redaction,
|
|
46227
|
+
...config3.redaction ?? {}
|
|
46228
|
+
}
|
|
46229
|
+
};
|
|
46230
|
+
}
|
|
46231
|
+
databasePath() {
|
|
46232
|
+
const relativePath = this.config.sqlite.path.replace(/^\.swarm[/\\]?/, "");
|
|
46233
|
+
return validateSwarmPath(this.rootDirectory, relativePath);
|
|
46234
|
+
}
|
|
46235
|
+
async initialize() {
|
|
46236
|
+
if (this.initialized)
|
|
46237
|
+
return;
|
|
46238
|
+
const dbPath = this.databasePath();
|
|
46239
|
+
mkdirSync12(path31.dirname(dbPath), { recursive: true });
|
|
46240
|
+
const Db = loadDatabaseCtor2();
|
|
46241
|
+
this.db = new Db(dbPath);
|
|
46242
|
+
this.db.run("PRAGMA journal_mode = WAL;");
|
|
46243
|
+
this.db.run("PRAGMA synchronous = NORMAL;");
|
|
46244
|
+
const busyTimeoutMs = Math.min(60000, Math.max(0, Math.trunc(this.config.sqlite.busyTimeoutMs)));
|
|
46245
|
+
this.db.run(`PRAGMA busy_timeout = ${busyTimeoutMs};`);
|
|
46246
|
+
this.db.run("PRAGMA foreign_keys = ON;");
|
|
46247
|
+
this.runMigrations();
|
|
46248
|
+
this.lastAutomaticJsonlMigration = null;
|
|
46249
|
+
await this.migrateLegacyJsonlIfNeeded();
|
|
46250
|
+
const memoryLoad = this.loadMemories();
|
|
46251
|
+
const proposalLoad = this.loadProposals();
|
|
46252
|
+
this.memories = new Map(memoryLoad.records.map((record3) => [record3.id, record3]));
|
|
46253
|
+
this.proposals = new Map(proposalLoad.records.map((proposal) => [proposal.id, proposal]));
|
|
46254
|
+
this.initialized = true;
|
|
46255
|
+
if (memoryLoad.invalidCount > 0) {
|
|
46256
|
+
await this.event("invalid_load", "memory_items", `${memoryLoad.invalidCount} invalid SQLite memory row(s) skipped`);
|
|
46257
|
+
}
|
|
46258
|
+
if (proposalLoad.invalidCount > 0) {
|
|
46259
|
+
await this.event("invalid_load", "memory_proposals", `${proposalLoad.invalidCount} invalid SQLite proposal row(s) skipped`);
|
|
46260
|
+
}
|
|
46261
|
+
}
|
|
46262
|
+
async upsert(record3) {
|
|
46263
|
+
await this.initialize();
|
|
46264
|
+
const existing = this.memories.get(record3.id);
|
|
46265
|
+
if (existing?.metadata.deleted === true) {
|
|
46266
|
+
throw new MemoryValidationError("memory is tombstoned and cannot be upserted");
|
|
46267
|
+
}
|
|
46268
|
+
const next = validateMemoryRecordRules({
|
|
46269
|
+
...record3,
|
|
46270
|
+
createdAt: existing?.createdAt ?? record3.createdAt
|
|
46271
|
+
}, { rejectDurableSecrets: this.config.redaction.rejectDurableSecrets });
|
|
46272
|
+
this.memories.set(next.id, next);
|
|
46273
|
+
this.writeMemory(next);
|
|
46274
|
+
await this.event("upsert", next.id);
|
|
46275
|
+
return next;
|
|
46276
|
+
}
|
|
46277
|
+
async get(id) {
|
|
46278
|
+
await this.initialize();
|
|
46279
|
+
return this.memories.get(id) ?? null;
|
|
46280
|
+
}
|
|
46281
|
+
async delete(id, reason) {
|
|
46282
|
+
await this.initialize();
|
|
46283
|
+
const existing = this.memories.get(id);
|
|
46284
|
+
if (!existing)
|
|
46285
|
+
return;
|
|
46286
|
+
if (this.config.hardDelete) {
|
|
46287
|
+
this.memories.delete(id);
|
|
46288
|
+
this.requireDb().run("DELETE FROM memory_items WHERE id = ?", [id]);
|
|
46289
|
+
} else {
|
|
46290
|
+
const tombstone = {
|
|
46291
|
+
...existing,
|
|
46292
|
+
updatedAt: new Date().toISOString(),
|
|
46293
|
+
metadata: { ...existing.metadata, deleted: true, deleteReason: reason }
|
|
46294
|
+
};
|
|
46295
|
+
this.memories.set(id, tombstone);
|
|
46296
|
+
this.writeMemory(tombstone);
|
|
46297
|
+
}
|
|
46298
|
+
await this.event("delete", id, reason);
|
|
46299
|
+
}
|
|
46300
|
+
async recall(request) {
|
|
46301
|
+
return (await this.recallWithDiagnostics(request)).items;
|
|
46302
|
+
}
|
|
46303
|
+
async recallWithDiagnostics(request) {
|
|
46304
|
+
await this.initialize();
|
|
46305
|
+
const records = await this.list({
|
|
46306
|
+
scopes: request.scopes,
|
|
46307
|
+
kinds: request.kinds,
|
|
46308
|
+
includeExpired: request.includeExpired
|
|
46309
|
+
});
|
|
46310
|
+
const result = scoreMemoryRecordsWithDiagnostics(records, request);
|
|
46311
|
+
return {
|
|
46312
|
+
items: result.items.slice(0, request.maxItems),
|
|
46313
|
+
diagnostics: {
|
|
46314
|
+
...result.diagnostics,
|
|
46315
|
+
returnedCount: Math.min(result.diagnostics.returnedCount, request.maxItems)
|
|
46316
|
+
}
|
|
46317
|
+
};
|
|
46318
|
+
}
|
|
46319
|
+
async recordRecallUsage(event) {
|
|
46320
|
+
await this.initialize();
|
|
46321
|
+
this.requireDb().run(`INSERT INTO memory_recall_usage (
|
|
46322
|
+
id,
|
|
46323
|
+
bundle_id,
|
|
46324
|
+
timestamp,
|
|
46325
|
+
usage_json
|
|
46326
|
+
) VALUES (?, ?, ?, ?)`, [randomUUID4(), event.bundleId, event.timestamp, JSON.stringify(event)]);
|
|
46327
|
+
await this.event("recall", event.bundleId, JSON.stringify(event));
|
|
46328
|
+
}
|
|
46329
|
+
async list(filter = {}) {
|
|
46330
|
+
await this.initialize();
|
|
46331
|
+
let records = Array.from(this.memories.values());
|
|
46332
|
+
if (filter.scopes && filter.scopes.length > 0) {
|
|
46333
|
+
records = records.filter((record3) => scopeAllowed(record3.scope, filter.scopes ?? []));
|
|
46334
|
+
}
|
|
46335
|
+
if (filter.kinds && filter.kinds.length > 0) {
|
|
46336
|
+
records = records.filter((record3) => filter.kinds?.includes(record3.kind));
|
|
46337
|
+
}
|
|
46338
|
+
if (!filter.includeExpired) {
|
|
46339
|
+
const now = Date.now();
|
|
46340
|
+
records = records.filter((record3) => {
|
|
46341
|
+
if (!record3.expiresAt)
|
|
46342
|
+
return true;
|
|
46343
|
+
const expires = Date.parse(record3.expiresAt);
|
|
46344
|
+
return !Number.isFinite(expires) || expires > now;
|
|
46345
|
+
});
|
|
46346
|
+
}
|
|
46347
|
+
records = records.filter((record3) => !record3.supersededBy && record3.metadata.deleted !== true);
|
|
46348
|
+
records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
46349
|
+
return records.slice(0, filter.limit ?? records.length);
|
|
46350
|
+
}
|
|
46351
|
+
async createProposal(proposal) {
|
|
46352
|
+
await this.initialize();
|
|
46353
|
+
const next = validateMemoryProposal(proposal);
|
|
46354
|
+
if (next.proposedRecord) {
|
|
46355
|
+
validateMemoryRecordRules(next.proposedRecord, {
|
|
46356
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
46357
|
+
});
|
|
46358
|
+
}
|
|
46359
|
+
this.proposals.set(next.id, next);
|
|
46360
|
+
this.writeProposal(next);
|
|
46361
|
+
await this.event("proposal", next.id);
|
|
46362
|
+
return next;
|
|
46363
|
+
}
|
|
46364
|
+
async listProposals(filter = {}) {
|
|
46365
|
+
await this.initialize();
|
|
46366
|
+
let proposals = Array.from(this.proposals.values());
|
|
46367
|
+
if (filter.status) {
|
|
46368
|
+
proposals = proposals.filter((proposal) => proposal.status === filter.status);
|
|
46369
|
+
}
|
|
46370
|
+
proposals.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
46371
|
+
return proposals.slice(0, filter.limit ?? proposals.length);
|
|
46372
|
+
}
|
|
46373
|
+
close() {
|
|
46374
|
+
if (!this.db)
|
|
46375
|
+
return;
|
|
46376
|
+
this.db.close();
|
|
46377
|
+
this.db = null;
|
|
46378
|
+
this.initialized = false;
|
|
46379
|
+
this.lastAutomaticJsonlMigration = null;
|
|
46380
|
+
}
|
|
46381
|
+
async importJsonl() {
|
|
46382
|
+
const wasInitialized = this.initialized;
|
|
46383
|
+
await this.initialize();
|
|
46384
|
+
if (!wasInitialized && this.lastAutomaticJsonlMigration) {
|
|
46385
|
+
return this.lastAutomaticJsonlMigration;
|
|
46386
|
+
}
|
|
46387
|
+
return this.importLegacyJsonlRows();
|
|
46388
|
+
}
|
|
46389
|
+
async exportJsonl() {
|
|
46390
|
+
await this.initialize();
|
|
46391
|
+
const memories = await this.list({ includeExpired: true });
|
|
46392
|
+
const proposals = await this.listProposals();
|
|
46393
|
+
const output = await writeJsonlExport(this.rootDirectory, this.config, memories, proposals);
|
|
46394
|
+
return {
|
|
46395
|
+
...output,
|
|
46396
|
+
memories: memories.length,
|
|
46397
|
+
proposals: proposals.length
|
|
46398
|
+
};
|
|
46399
|
+
}
|
|
46400
|
+
hasMigration(name) {
|
|
46401
|
+
const row = this.requireDb().query("SELECT version, name FROM schema_migrations WHERE name = ? LIMIT 1").get(name);
|
|
46402
|
+
return Boolean(row);
|
|
46403
|
+
}
|
|
46404
|
+
markMigration(version4, name) {
|
|
46405
|
+
this.requireDb().run("INSERT OR IGNORE INTO schema_migrations (version, name) VALUES (?, ?)", [version4, name]);
|
|
46406
|
+
}
|
|
46407
|
+
runMigrations() {
|
|
46408
|
+
const db = this.requireDb();
|
|
46409
|
+
db.run(`CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
46410
|
+
version INTEGER PRIMARY KEY,
|
|
46411
|
+
name TEXT NOT NULL,
|
|
46412
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
46413
|
+
)`);
|
|
46414
|
+
const row = db.query("SELECT MAX(version) as version FROM schema_migrations").get();
|
|
46415
|
+
const currentVersion = row?.version ?? 0;
|
|
46416
|
+
for (const migration of MIGRATIONS2) {
|
|
46417
|
+
if (migration.version <= currentVersion)
|
|
46418
|
+
continue;
|
|
46419
|
+
const apply = db.transaction(() => {
|
|
46420
|
+
for (const statement of splitSql(migration.sql)) {
|
|
46421
|
+
db.run(statement);
|
|
46422
|
+
}
|
|
46423
|
+
db.run("INSERT INTO schema_migrations (version, name) VALUES (?, ?)", [
|
|
46424
|
+
migration.version,
|
|
46425
|
+
migration.name
|
|
46426
|
+
]);
|
|
46427
|
+
this.insertEvent("migration", String(migration.version), migration.name);
|
|
46428
|
+
});
|
|
46429
|
+
apply();
|
|
46430
|
+
}
|
|
46431
|
+
}
|
|
46432
|
+
loadMemories() {
|
|
46433
|
+
const rows = this.requireDb().query("SELECT id, record_json FROM memory_items ORDER BY updated_at ASC").all();
|
|
46434
|
+
const records = [];
|
|
46435
|
+
let invalidCount = 0;
|
|
46436
|
+
for (const row of rows) {
|
|
46437
|
+
try {
|
|
46438
|
+
records.push(validateMemoryRecordRules(JSON.parse(row.record_json), {
|
|
46439
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
46440
|
+
}));
|
|
46441
|
+
} catch {
|
|
46442
|
+
invalidCount++;
|
|
46443
|
+
}
|
|
46444
|
+
}
|
|
46445
|
+
return { records, invalidCount };
|
|
46446
|
+
}
|
|
46447
|
+
loadProposals() {
|
|
46448
|
+
const rows = this.requireDb().query("SELECT id, proposal_json FROM memory_proposals ORDER BY created_at ASC").all();
|
|
46449
|
+
const records = [];
|
|
46450
|
+
let invalidCount = 0;
|
|
46451
|
+
for (const row of rows) {
|
|
46452
|
+
try {
|
|
46453
|
+
const proposal = validateMemoryProposal(JSON.parse(row.proposal_json));
|
|
46454
|
+
if (proposal.proposedRecord) {
|
|
46455
|
+
validateMemoryRecordRules(proposal.proposedRecord, {
|
|
46456
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
46457
|
+
});
|
|
46458
|
+
}
|
|
46459
|
+
records.push(proposal);
|
|
46460
|
+
} catch {
|
|
46461
|
+
invalidCount++;
|
|
46462
|
+
}
|
|
46463
|
+
}
|
|
46464
|
+
return { records, invalidCount };
|
|
46465
|
+
}
|
|
46466
|
+
writeMemory(record3) {
|
|
46467
|
+
this.requireDb().run(`INSERT OR REPLACE INTO memory_items (
|
|
46468
|
+
id,
|
|
46469
|
+
scope_key,
|
|
46470
|
+
kind,
|
|
46471
|
+
updated_at,
|
|
46472
|
+
expires_at,
|
|
46473
|
+
superseded_by,
|
|
46474
|
+
deleted,
|
|
46475
|
+
record_json
|
|
46476
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
46477
|
+
record3.id,
|
|
46478
|
+
JSON.stringify(record3.scope),
|
|
46479
|
+
record3.kind,
|
|
46480
|
+
record3.updatedAt,
|
|
46481
|
+
record3.expiresAt ?? null,
|
|
46482
|
+
record3.supersededBy ?? null,
|
|
46483
|
+
record3.metadata.deleted === true ? 1 : 0,
|
|
46484
|
+
JSON.stringify(record3)
|
|
46485
|
+
]);
|
|
46486
|
+
}
|
|
46487
|
+
writeProposal(proposal) {
|
|
46488
|
+
this.requireDb().run(`INSERT OR REPLACE INTO memory_proposals (
|
|
46489
|
+
id,
|
|
46490
|
+
status,
|
|
46491
|
+
created_at,
|
|
46492
|
+
proposal_json
|
|
46493
|
+
) VALUES (?, ?, ?, ?)`, [
|
|
46494
|
+
proposal.id,
|
|
46495
|
+
proposal.status,
|
|
46496
|
+
proposal.createdAt,
|
|
46497
|
+
JSON.stringify(proposal)
|
|
46498
|
+
]);
|
|
46499
|
+
}
|
|
46500
|
+
async migrateLegacyJsonlIfNeeded() {
|
|
46501
|
+
if (this.hasMigration(LEGACY_JSONL_MIGRATION_NAME))
|
|
46502
|
+
return;
|
|
46503
|
+
const backups = await backupLegacyJsonl(this.rootDirectory, this.config);
|
|
46504
|
+
const result = await this.importLegacyJsonlRows();
|
|
46505
|
+
this.lastAutomaticJsonlMigration = result;
|
|
46506
|
+
this.markMigration(LEGACY_JSONL_MIGRATION_VERSION, LEGACY_JSONL_MIGRATION_NAME);
|
|
46507
|
+
const report = {
|
|
46508
|
+
migration: LEGACY_JSONL_MIGRATION_NAME,
|
|
46509
|
+
completedAt: new Date().toISOString(),
|
|
46510
|
+
skipped: false,
|
|
46511
|
+
importedMemories: result.importedMemories,
|
|
46512
|
+
importedProposals: result.importedProposals,
|
|
46513
|
+
invalidRows: result.invalidRows,
|
|
46514
|
+
backups
|
|
46515
|
+
};
|
|
46516
|
+
await writeMigrationReport(this.rootDirectory, report, this.config);
|
|
46517
|
+
this.insertEvent("migration", LEGACY_JSONL_MIGRATION_NAME, JSON.stringify({
|
|
46518
|
+
importedMemories: result.importedMemories,
|
|
46519
|
+
importedProposals: result.importedProposals,
|
|
46520
|
+
invalidRows: result.invalidRows.length
|
|
46521
|
+
}));
|
|
46522
|
+
}
|
|
46523
|
+
async importLegacyJsonlRows() {
|
|
46524
|
+
const payload = await readLegacyJsonl(this.rootDirectory, this.config);
|
|
46525
|
+
for (const record3 of payload.memories) {
|
|
46526
|
+
this.writeMemory(record3);
|
|
46527
|
+
}
|
|
46528
|
+
for (const proposal of payload.proposals) {
|
|
46529
|
+
this.writeProposal(proposal);
|
|
46530
|
+
}
|
|
46531
|
+
return {
|
|
46532
|
+
importedMemories: payload.memories.length,
|
|
46533
|
+
importedProposals: payload.proposals.length,
|
|
46534
|
+
invalidRows: payload.invalidRows,
|
|
46535
|
+
totalRows: payload.totalRows
|
|
46536
|
+
};
|
|
46537
|
+
}
|
|
46538
|
+
async event(operation, targetId, reason) {
|
|
46539
|
+
this.insertEvent(operation, targetId, reason);
|
|
46540
|
+
}
|
|
46541
|
+
insertEvent(operation, targetId, reason) {
|
|
46542
|
+
this.requireDb().run(`INSERT INTO memory_events (
|
|
46543
|
+
id,
|
|
46544
|
+
operation,
|
|
46545
|
+
target_id,
|
|
46546
|
+
reason,
|
|
46547
|
+
timestamp,
|
|
46548
|
+
event_json
|
|
46549
|
+
) VALUES (?, ?, ?, ?, ?, ?)`, [
|
|
46550
|
+
randomUUID4(),
|
|
46551
|
+
operation,
|
|
46552
|
+
targetId,
|
|
46553
|
+
reason ?? null,
|
|
46554
|
+
new Date().toISOString(),
|
|
46555
|
+
reason ? JSON.stringify({ reason }) : null
|
|
46556
|
+
]);
|
|
46557
|
+
}
|
|
46558
|
+
requireDb() {
|
|
46559
|
+
if (!this.db)
|
|
46560
|
+
throw new Error("SQLite memory provider is not initialized");
|
|
46561
|
+
return this.db;
|
|
46562
|
+
}
|
|
46563
|
+
}
|
|
46564
|
+
function splitSql(sql) {
|
|
46565
|
+
return sql.split(";").map((statement) => statement.trim()).filter(Boolean);
|
|
46566
|
+
}
|
|
46567
|
+
var _DatabaseCtor2 = null, MIGRATIONS2;
|
|
46568
|
+
var init_sqlite_provider = __esm(() => {
|
|
46569
|
+
init_utils2();
|
|
46570
|
+
init_config3();
|
|
46571
|
+
init_errors6();
|
|
46572
|
+
init_jsonl_migration();
|
|
46573
|
+
init_schema2();
|
|
46574
|
+
init_scoring();
|
|
46575
|
+
MIGRATIONS2 = [
|
|
46576
|
+
{
|
|
46577
|
+
version: 1,
|
|
46578
|
+
name: "create_memory_provider_tables",
|
|
46579
|
+
sql: `
|
|
46580
|
+
CREATE TABLE IF NOT EXISTS memory_items (
|
|
46581
|
+
id TEXT PRIMARY KEY,
|
|
46582
|
+
scope_key TEXT NOT NULL,
|
|
46583
|
+
kind TEXT NOT NULL,
|
|
46584
|
+
updated_at TEXT NOT NULL,
|
|
46585
|
+
expires_at TEXT,
|
|
46586
|
+
superseded_by TEXT,
|
|
46587
|
+
deleted INTEGER NOT NULL DEFAULT 0,
|
|
46588
|
+
record_json TEXT NOT NULL
|
|
46589
|
+
);
|
|
46590
|
+
CREATE INDEX IF NOT EXISTS idx_memory_items_scope_kind
|
|
46591
|
+
ON memory_items(scope_key, kind);
|
|
46592
|
+
CREATE INDEX IF NOT EXISTS idx_memory_items_updated_at
|
|
46593
|
+
ON memory_items(updated_at);
|
|
46594
|
+
|
|
46595
|
+
CREATE TABLE IF NOT EXISTS memory_proposals (
|
|
46596
|
+
id TEXT PRIMARY KEY,
|
|
46597
|
+
status TEXT NOT NULL,
|
|
46598
|
+
created_at TEXT NOT NULL,
|
|
46599
|
+
proposal_json TEXT NOT NULL
|
|
46600
|
+
);
|
|
46601
|
+
CREATE INDEX IF NOT EXISTS idx_memory_proposals_status_created
|
|
46602
|
+
ON memory_proposals(status, created_at);
|
|
46603
|
+
|
|
46604
|
+
CREATE TABLE IF NOT EXISTS memory_events (
|
|
46605
|
+
id TEXT PRIMARY KEY,
|
|
46606
|
+
operation TEXT NOT NULL,
|
|
46607
|
+
target_id TEXT NOT NULL,
|
|
46608
|
+
reason TEXT,
|
|
46609
|
+
timestamp TEXT NOT NULL,
|
|
46610
|
+
event_json TEXT
|
|
46611
|
+
);
|
|
46612
|
+
|
|
46613
|
+
CREATE TABLE IF NOT EXISTS memory_recall_usage (
|
|
46614
|
+
id TEXT PRIMARY KEY,
|
|
46615
|
+
bundle_id TEXT NOT NULL,
|
|
46616
|
+
timestamp TEXT NOT NULL,
|
|
46617
|
+
usage_json TEXT NOT NULL
|
|
46618
|
+
);
|
|
46619
|
+
CREATE INDEX IF NOT EXISTS idx_memory_recall_usage_bundle
|
|
46620
|
+
ON memory_recall_usage(bundle_id);
|
|
46621
|
+
`
|
|
46622
|
+
}
|
|
46623
|
+
];
|
|
46624
|
+
});
|
|
46625
|
+
|
|
46626
|
+
// src/memory/gateway.ts
|
|
46627
|
+
function createConfiguredMemoryProvider(directory, config3) {
|
|
46628
|
+
if (config3.provider === "sqlite") {
|
|
46629
|
+
return new SQLiteMemoryProvider(directory, config3);
|
|
46630
|
+
}
|
|
46631
|
+
return new LocalJsonlMemoryProvider(directory, config3);
|
|
46632
|
+
}
|
|
46633
|
+
var gitRemoteUrlCache;
|
|
46634
|
+
var init_gateway = __esm(() => {
|
|
46635
|
+
init_config3();
|
|
46636
|
+
init_errors6();
|
|
46637
|
+
init_local_jsonl_provider();
|
|
46638
|
+
init_prompt_block();
|
|
46639
|
+
init_redaction();
|
|
46640
|
+
init_schema2();
|
|
46641
|
+
init_sqlite_provider();
|
|
46642
|
+
gitRemoteUrlCache = new Map;
|
|
46643
|
+
});
|
|
46644
|
+
|
|
46645
|
+
// src/agents/agent-output-schema.ts
|
|
46646
|
+
var AgentMemoryProposalSchema, AgentOutputMemorySchema;
|
|
46647
|
+
var init_agent_output_schema = __esm(() => {
|
|
46648
|
+
init_zod();
|
|
46649
|
+
init_schema2();
|
|
46650
|
+
AgentMemoryProposalSchema = exports_external.object({
|
|
46651
|
+
operation: exports_external.enum([
|
|
46652
|
+
"add",
|
|
46653
|
+
"update",
|
|
46654
|
+
"delete",
|
|
46655
|
+
"ignore",
|
|
46656
|
+
"merge",
|
|
46657
|
+
"supersede"
|
|
46658
|
+
]),
|
|
46659
|
+
kind: MemoryKindSchema.optional(),
|
|
46660
|
+
text: exports_external.string().min(1).max(2000).optional(),
|
|
46661
|
+
targetMemoryId: exports_external.string().optional(),
|
|
46662
|
+
relatedMemoryIds: exports_external.array(exports_external.string()).optional(),
|
|
46663
|
+
rationale: exports_external.string().min(1).max(2000),
|
|
46664
|
+
evidenceRefs: exports_external.array(exports_external.string().min(1).max(500)).max(20).optional()
|
|
46665
|
+
}).strict();
|
|
46666
|
+
AgentOutputMemorySchema = exports_external.object({
|
|
46667
|
+
memoryProposals: exports_external.array(AgentMemoryProposalSchema).max(20).optional()
|
|
46668
|
+
}).passthrough();
|
|
46669
|
+
});
|
|
46670
|
+
|
|
46671
|
+
// src/memory/role-profiles.ts
|
|
46672
|
+
var init_role_profiles = __esm(() => {
|
|
46673
|
+
init_schema();
|
|
46674
|
+
});
|
|
46675
|
+
|
|
46676
|
+
// src/memory/recall-planner.ts
|
|
46677
|
+
var init_recall_planner = __esm(() => {
|
|
46678
|
+
init_role_profiles();
|
|
46679
|
+
});
|
|
46680
|
+
|
|
46681
|
+
// src/memory/run-log.ts
|
|
46682
|
+
var init_run_log = __esm(() => {
|
|
46683
|
+
init_utils2();
|
|
46684
|
+
});
|
|
46685
|
+
|
|
46686
|
+
// src/memory/injector.ts
|
|
46687
|
+
var init_injector = __esm(() => {
|
|
46688
|
+
init_agent_output_schema();
|
|
46689
|
+
init_schema();
|
|
46690
|
+
init_normalize_tool_name();
|
|
46691
|
+
init_config3();
|
|
46692
|
+
init_gateway();
|
|
46693
|
+
init_recall_planner();
|
|
46694
|
+
init_run_log();
|
|
46695
|
+
});
|
|
46696
|
+
|
|
46697
|
+
// src/memory/index.ts
|
|
46698
|
+
var init_memory = __esm(() => {
|
|
46699
|
+
init_config3();
|
|
46700
|
+
init_errors6();
|
|
46701
|
+
init_gateway();
|
|
46702
|
+
init_injector();
|
|
46703
|
+
init_jsonl_migration();
|
|
46704
|
+
init_local_jsonl_provider();
|
|
46705
|
+
init_prompt_block();
|
|
46706
|
+
init_recall_planner();
|
|
46707
|
+
init_redaction();
|
|
46708
|
+
init_role_profiles();
|
|
46709
|
+
init_run_log();
|
|
46710
|
+
init_schema2();
|
|
46711
|
+
init_sqlite_provider();
|
|
46712
|
+
});
|
|
46713
|
+
|
|
46714
|
+
// src/commands/memory.ts
|
|
46715
|
+
import { existsSync as existsSync20 } from "fs";
|
|
46716
|
+
async function handleMemoryCommand(_directory, _args) {
|
|
46717
|
+
return [
|
|
46718
|
+
"## Swarm Memory",
|
|
46719
|
+
"",
|
|
46720
|
+
"- `/swarm memory status` - show provider, SQLite path, JSONL files, and last migration report",
|
|
46721
|
+
"- `/swarm memory export` - export current memory and proposals to `.swarm/memory/export/*.jsonl`",
|
|
46722
|
+
"- `/swarm memory import` - import `.swarm/memory/{memories,proposals}.jsonl` into SQLite",
|
|
46723
|
+
"- `/swarm memory migrate` - run the one-time legacy JSONL to SQLite migration"
|
|
46724
|
+
].join(`
|
|
46725
|
+
`);
|
|
46726
|
+
}
|
|
46727
|
+
async function handleMemoryStatusCommand(directory, _args) {
|
|
46728
|
+
const config3 = resolveCommandMemoryConfig(directory);
|
|
46729
|
+
const storageDir = resolveMemoryStorageDir(directory, config3);
|
|
46730
|
+
const sqlitePath = resolveSqliteDatabasePath(directory, config3);
|
|
46731
|
+
const jsonlFiles = await getLegacyJsonlFileStatus(directory, config3);
|
|
46732
|
+
const report = await readMigrationReport(directory, config3);
|
|
46733
|
+
const lines = [
|
|
46734
|
+
"## Swarm Memory Status",
|
|
46735
|
+
"",
|
|
46736
|
+
`- Enabled: \`${config3.enabled}\``,
|
|
46737
|
+
`- Provider: \`${config3.provider}\``,
|
|
46738
|
+
`- Storage: \`${storageDir}\``,
|
|
46739
|
+
`- SQLite path: \`${sqlitePath}\``,
|
|
46740
|
+
`- SQLite database exists: \`${existsSync20(sqlitePath)}\``,
|
|
46741
|
+
"",
|
|
46742
|
+
"### Legacy JSONL"
|
|
46743
|
+
];
|
|
46744
|
+
for (const file3 of jsonlFiles) {
|
|
46745
|
+
lines.push(`- ${file3.file}: \`${file3.exists ? "present" : "missing"}\` (${file3.sizeBytes} bytes)`);
|
|
46746
|
+
}
|
|
46747
|
+
lines.push("", "### Migration");
|
|
46748
|
+
if (!report) {
|
|
46749
|
+
lines.push("- Last report: `none`");
|
|
46750
|
+
} else {
|
|
46751
|
+
lines.push(`- Completed at: \`${report.completedAt}\``, `- Imported memories: \`${report.importedMemories}\``, `- Imported proposals: \`${report.importedProposals}\``, `- Invalid rows: \`${report.invalidRows.length}\``, `- Backups: \`${report.backups.length}\``);
|
|
46752
|
+
if (report.invalidRows.length > 0) {
|
|
46753
|
+
lines.push("", "Invalid rows:");
|
|
46754
|
+
for (const row of report.invalidRows.slice(0, 20)) {
|
|
46755
|
+
lines.push(`- ${row.file}:${row.line} - ${row.error}`);
|
|
46756
|
+
}
|
|
46757
|
+
if (report.invalidRows.length > 20) {
|
|
46758
|
+
lines.push(`- ... ${report.invalidRows.length - 20} more`);
|
|
46759
|
+
}
|
|
46760
|
+
}
|
|
46761
|
+
}
|
|
46762
|
+
return lines.join(`
|
|
46763
|
+
`);
|
|
46764
|
+
}
|
|
46765
|
+
async function handleMemoryMigrateCommand(directory, _args) {
|
|
46766
|
+
const config3 = {
|
|
46767
|
+
...resolveCommandMemoryConfig(directory),
|
|
46768
|
+
provider: "sqlite"
|
|
46769
|
+
};
|
|
46770
|
+
const provider = new SQLiteMemoryProvider(directory, config3);
|
|
46771
|
+
try {
|
|
46772
|
+
await provider.initialize();
|
|
46773
|
+
const report = await readMigrationReport(directory, config3);
|
|
46774
|
+
return formatMigrationResult("migration", report);
|
|
46775
|
+
} finally {
|
|
46776
|
+
provider.close();
|
|
46777
|
+
}
|
|
46778
|
+
}
|
|
46779
|
+
async function handleMemoryImportCommand(directory, _args) {
|
|
46780
|
+
const config3 = {
|
|
46781
|
+
...resolveCommandMemoryConfig(directory),
|
|
46782
|
+
provider: "sqlite"
|
|
46783
|
+
};
|
|
46784
|
+
const provider = new SQLiteMemoryProvider(directory, config3);
|
|
46785
|
+
try {
|
|
46786
|
+
const result = await provider.importJsonl();
|
|
46787
|
+
const lines = [
|
|
46788
|
+
"## Swarm Memory Import",
|
|
46789
|
+
"",
|
|
46790
|
+
`- Imported memories: \`${result.importedMemories}\``,
|
|
46791
|
+
`- Imported proposals: \`${result.importedProposals}\``,
|
|
46792
|
+
`- Total JSONL rows scanned: \`${result.totalRows}\``,
|
|
46793
|
+
`- Invalid rows: \`${result.invalidRows.length}\``
|
|
46794
|
+
];
|
|
46795
|
+
appendInvalidRows(lines, result.invalidRows);
|
|
46796
|
+
return lines.join(`
|
|
46797
|
+
`);
|
|
46798
|
+
} finally {
|
|
46799
|
+
provider.close();
|
|
46800
|
+
}
|
|
46801
|
+
}
|
|
46802
|
+
async function handleMemoryExportCommand(directory, _args) {
|
|
46803
|
+
const config3 = resolveCommandMemoryConfig(directory);
|
|
46804
|
+
const provider = createConfiguredMemoryProvider(directory, config3);
|
|
46805
|
+
try {
|
|
46806
|
+
await provider.initialize?.();
|
|
46807
|
+
const memories = await provider.list({ includeExpired: true });
|
|
46808
|
+
const proposals = provider.listProposals ? await provider.listProposals() : [];
|
|
46809
|
+
const output = await writeJsonlExport(directory, config3, memories, proposals);
|
|
46810
|
+
return [
|
|
46811
|
+
"## Swarm Memory Export",
|
|
46812
|
+
"",
|
|
46813
|
+
`- Memories: \`${memories.length}\` -> \`${output.memoriesPath}\``,
|
|
46814
|
+
`- Proposals: \`${proposals.length}\` -> \`${output.proposalsPath}\``
|
|
46815
|
+
].join(`
|
|
46816
|
+
`);
|
|
46817
|
+
} finally {
|
|
46818
|
+
await provider.close?.();
|
|
46819
|
+
}
|
|
46820
|
+
}
|
|
46821
|
+
function resolveCommandMemoryConfig(directory) {
|
|
46822
|
+
const loaded = loadPluginConfig(directory).memory;
|
|
46823
|
+
return resolveMemoryConfig(loaded ?? DEFAULT_MEMORY_CONFIG);
|
|
46824
|
+
}
|
|
46825
|
+
function formatMigrationResult(label, report) {
|
|
46826
|
+
if (!report) {
|
|
46827
|
+
return [
|
|
46828
|
+
`## Swarm Memory ${label}`,
|
|
46829
|
+
"",
|
|
46830
|
+
"No migration report was written."
|
|
46831
|
+
].join(`
|
|
46832
|
+
`);
|
|
46833
|
+
}
|
|
46834
|
+
const lines = [
|
|
46835
|
+
`## Swarm Memory ${label}`,
|
|
46836
|
+
"",
|
|
46837
|
+
`- Completed at: \`${report.completedAt}\``,
|
|
46838
|
+
`- Imported memories: \`${report.importedMemories}\``,
|
|
46839
|
+
`- Imported proposals: \`${report.importedProposals}\``,
|
|
46840
|
+
`- Invalid rows: \`${report.invalidRows.length}\``,
|
|
46841
|
+
`- Backups: \`${report.backups.length}\``
|
|
46842
|
+
];
|
|
46843
|
+
if (report.backups.length > 0) {
|
|
46844
|
+
lines.push("", "Backups:");
|
|
46845
|
+
for (const backup of report.backups) {
|
|
46846
|
+
lines.push(`- \`${backup.backup}\` (${backup.created ? "created" : "already existed"})`);
|
|
46847
|
+
}
|
|
46848
|
+
}
|
|
46849
|
+
appendInvalidRows(lines, report.invalidRows);
|
|
46850
|
+
return lines.join(`
|
|
46851
|
+
`);
|
|
46852
|
+
}
|
|
46853
|
+
function appendInvalidRows(lines, invalidRows) {
|
|
46854
|
+
if (invalidRows.length === 0)
|
|
46855
|
+
return;
|
|
46856
|
+
lines.push("", "Invalid rows:");
|
|
46857
|
+
for (const row of invalidRows.slice(0, 20)) {
|
|
46858
|
+
lines.push(`- ${row.file}:${row.line} - ${row.error}`);
|
|
46859
|
+
}
|
|
46860
|
+
if (invalidRows.length > 20) {
|
|
46861
|
+
lines.push(`- ... ${invalidRows.length - 20} more`);
|
|
46862
|
+
}
|
|
46863
|
+
}
|
|
46864
|
+
var init_memory2 = __esm(() => {
|
|
46865
|
+
init_loader();
|
|
46866
|
+
init_memory();
|
|
46867
|
+
});
|
|
46868
|
+
|
|
45268
46869
|
// src/services/plan-service.ts
|
|
45269
46870
|
async function getPlanData(directory, phaseArg) {
|
|
45270
46871
|
const plan = await _internals18.loadPlanJsonOnly(directory);
|
|
@@ -45650,7 +47251,7 @@ var init_path_security = () => {};
|
|
|
45650
47251
|
|
|
45651
47252
|
// src/tools/lint.ts
|
|
45652
47253
|
import * as fs12 from "fs";
|
|
45653
|
-
import * as
|
|
47254
|
+
import * as path32 from "path";
|
|
45654
47255
|
function validateArgs(args) {
|
|
45655
47256
|
if (typeof args !== "object" || args === null)
|
|
45656
47257
|
return false;
|
|
@@ -45661,9 +47262,9 @@ function validateArgs(args) {
|
|
|
45661
47262
|
}
|
|
45662
47263
|
function getLinterCommand(linter, mode, projectDir) {
|
|
45663
47264
|
const isWindows = process.platform === "win32";
|
|
45664
|
-
const binDir =
|
|
45665
|
-
const biomeBin = isWindows ?
|
|
45666
|
-
const eslintBin = isWindows ?
|
|
47265
|
+
const binDir = path32.join(projectDir, "node_modules", ".bin");
|
|
47266
|
+
const biomeBin = isWindows ? path32.join(binDir, "biome.EXE") : path32.join(binDir, "biome");
|
|
47267
|
+
const eslintBin = isWindows ? path32.join(binDir, "eslint.cmd") : path32.join(binDir, "eslint");
|
|
45667
47268
|
switch (linter) {
|
|
45668
47269
|
case "biome":
|
|
45669
47270
|
if (mode === "fix") {
|
|
@@ -45679,7 +47280,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
45679
47280
|
}
|
|
45680
47281
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
45681
47282
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
45682
|
-
const gradlew = fs12.existsSync(
|
|
47283
|
+
const gradlew = fs12.existsSync(path32.join(cwd, gradlewName)) ? path32.join(cwd, gradlewName) : null;
|
|
45683
47284
|
switch (linter) {
|
|
45684
47285
|
case "ruff":
|
|
45685
47286
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -45713,10 +47314,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
45713
47314
|
}
|
|
45714
47315
|
}
|
|
45715
47316
|
function detectRuff(cwd) {
|
|
45716
|
-
if (fs12.existsSync(
|
|
47317
|
+
if (fs12.existsSync(path32.join(cwd, "ruff.toml")))
|
|
45717
47318
|
return isCommandAvailable("ruff");
|
|
45718
47319
|
try {
|
|
45719
|
-
const pyproject =
|
|
47320
|
+
const pyproject = path32.join(cwd, "pyproject.toml");
|
|
45720
47321
|
if (fs12.existsSync(pyproject)) {
|
|
45721
47322
|
const content = fs12.readFileSync(pyproject, "utf-8");
|
|
45722
47323
|
if (content.includes("[tool.ruff]"))
|
|
@@ -45726,19 +47327,19 @@ function detectRuff(cwd) {
|
|
|
45726
47327
|
return false;
|
|
45727
47328
|
}
|
|
45728
47329
|
function detectClippy(cwd) {
|
|
45729
|
-
return fs12.existsSync(
|
|
47330
|
+
return fs12.existsSync(path32.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
45730
47331
|
}
|
|
45731
47332
|
function detectGolangciLint(cwd) {
|
|
45732
|
-
return fs12.existsSync(
|
|
47333
|
+
return fs12.existsSync(path32.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
45733
47334
|
}
|
|
45734
47335
|
function detectCheckstyle(cwd) {
|
|
45735
|
-
const hasMaven = fs12.existsSync(
|
|
45736
|
-
const hasGradle = fs12.existsSync(
|
|
45737
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(
|
|
47336
|
+
const hasMaven = fs12.existsSync(path32.join(cwd, "pom.xml"));
|
|
47337
|
+
const hasGradle = fs12.existsSync(path32.join(cwd, "build.gradle")) || fs12.existsSync(path32.join(cwd, "build.gradle.kts"));
|
|
47338
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path32.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
45738
47339
|
return (hasMaven || hasGradle) && hasBinary;
|
|
45739
47340
|
}
|
|
45740
47341
|
function detectKtlint(cwd) {
|
|
45741
|
-
const hasKotlin = fs12.existsSync(
|
|
47342
|
+
const hasKotlin = fs12.existsSync(path32.join(cwd, "build.gradle.kts")) || fs12.existsSync(path32.join(cwd, "build.gradle")) || (() => {
|
|
45742
47343
|
try {
|
|
45743
47344
|
return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
45744
47345
|
} catch {
|
|
@@ -45757,11 +47358,11 @@ function detectDotnetFormat(cwd) {
|
|
|
45757
47358
|
}
|
|
45758
47359
|
}
|
|
45759
47360
|
function detectCppcheck(cwd) {
|
|
45760
|
-
if (fs12.existsSync(
|
|
47361
|
+
if (fs12.existsSync(path32.join(cwd, "CMakeLists.txt"))) {
|
|
45761
47362
|
return isCommandAvailable("cppcheck");
|
|
45762
47363
|
}
|
|
45763
47364
|
try {
|
|
45764
|
-
const dirsToCheck = [cwd,
|
|
47365
|
+
const dirsToCheck = [cwd, path32.join(cwd, "src")];
|
|
45765
47366
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
45766
47367
|
try {
|
|
45767
47368
|
return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -45775,13 +47376,13 @@ function detectCppcheck(cwd) {
|
|
|
45775
47376
|
}
|
|
45776
47377
|
}
|
|
45777
47378
|
function detectSwiftlint(cwd) {
|
|
45778
|
-
return fs12.existsSync(
|
|
47379
|
+
return fs12.existsSync(path32.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
45779
47380
|
}
|
|
45780
47381
|
function detectDartAnalyze(cwd) {
|
|
45781
|
-
return fs12.existsSync(
|
|
47382
|
+
return fs12.existsSync(path32.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
45782
47383
|
}
|
|
45783
47384
|
function detectRubocop(cwd) {
|
|
45784
|
-
return (fs12.existsSync(
|
|
47385
|
+
return (fs12.existsSync(path32.join(cwd, "Gemfile")) || fs12.existsSync(path32.join(cwd, "gems.rb")) || fs12.existsSync(path32.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
45785
47386
|
}
|
|
45786
47387
|
function detectAdditionalLinter(cwd) {
|
|
45787
47388
|
if (detectRuff(cwd))
|
|
@@ -45809,10 +47410,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
45809
47410
|
function findBinInAncestors(startDir, binName) {
|
|
45810
47411
|
let dir = startDir;
|
|
45811
47412
|
while (true) {
|
|
45812
|
-
const candidate =
|
|
47413
|
+
const candidate = path32.join(dir, "node_modules", ".bin", binName);
|
|
45813
47414
|
if (fs12.existsSync(candidate))
|
|
45814
47415
|
return candidate;
|
|
45815
|
-
const parent =
|
|
47416
|
+
const parent = path32.dirname(dir);
|
|
45816
47417
|
if (parent === dir)
|
|
45817
47418
|
break;
|
|
45818
47419
|
dir = parent;
|
|
@@ -45821,10 +47422,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
45821
47422
|
}
|
|
45822
47423
|
function findBinInEnvPath(binName) {
|
|
45823
47424
|
const searchPath = process.env.PATH ?? "";
|
|
45824
|
-
for (const dir of searchPath.split(
|
|
47425
|
+
for (const dir of searchPath.split(path32.delimiter)) {
|
|
45825
47426
|
if (!dir)
|
|
45826
47427
|
continue;
|
|
45827
|
-
const candidate =
|
|
47428
|
+
const candidate = path32.join(dir, binName);
|
|
45828
47429
|
if (fs12.existsSync(candidate))
|
|
45829
47430
|
return candidate;
|
|
45830
47431
|
}
|
|
@@ -45837,13 +47438,13 @@ async function detectAvailableLinter(directory) {
|
|
|
45837
47438
|
return null;
|
|
45838
47439
|
const projectDir = directory;
|
|
45839
47440
|
const isWindows = process.platform === "win32";
|
|
45840
|
-
const biomeBin = isWindows ?
|
|
45841
|
-
const eslintBin = isWindows ?
|
|
47441
|
+
const biomeBin = isWindows ? path32.join(projectDir, "node_modules", ".bin", "biome.EXE") : path32.join(projectDir, "node_modules", ".bin", "biome");
|
|
47442
|
+
const eslintBin = isWindows ? path32.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path32.join(projectDir, "node_modules", ".bin", "eslint");
|
|
45842
47443
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
45843
47444
|
if (localResult)
|
|
45844
47445
|
return localResult;
|
|
45845
|
-
const biomeAncestor = findBinInAncestors(
|
|
45846
|
-
const eslintAncestor = findBinInAncestors(
|
|
47446
|
+
const biomeAncestor = findBinInAncestors(path32.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
47447
|
+
const eslintAncestor = findBinInAncestors(path32.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
45847
47448
|
if (biomeAncestor || eslintAncestor) {
|
|
45848
47449
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
45849
47450
|
}
|
|
@@ -46066,7 +47667,7 @@ For Rust: rustup component add clippy`
|
|
|
46066
47667
|
|
|
46067
47668
|
// src/tools/secretscan.ts
|
|
46068
47669
|
import * as fs13 from "fs";
|
|
46069
|
-
import * as
|
|
47670
|
+
import * as path33 from "path";
|
|
46070
47671
|
function calculateShannonEntropy(str) {
|
|
46071
47672
|
if (str.length === 0)
|
|
46072
47673
|
return 0;
|
|
@@ -46114,7 +47715,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
46114
47715
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
46115
47716
|
}
|
|
46116
47717
|
function loadSecretScanIgnore(scanDir) {
|
|
46117
|
-
const ignorePath =
|
|
47718
|
+
const ignorePath = path33.join(scanDir, ".secretscanignore");
|
|
46118
47719
|
try {
|
|
46119
47720
|
if (!fs13.existsSync(ignorePath))
|
|
46120
47721
|
return [];
|
|
@@ -46137,7 +47738,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
46137
47738
|
if (exactNames.has(entry))
|
|
46138
47739
|
return true;
|
|
46139
47740
|
for (const pattern of globPatterns) {
|
|
46140
|
-
if (
|
|
47741
|
+
if (path33.matchesGlob(relPath, pattern))
|
|
46141
47742
|
return true;
|
|
46142
47743
|
}
|
|
46143
47744
|
return false;
|
|
@@ -46158,7 +47759,7 @@ function validateDirectoryInput(dir) {
|
|
|
46158
47759
|
return null;
|
|
46159
47760
|
}
|
|
46160
47761
|
function isBinaryFile(filePath, buffer) {
|
|
46161
|
-
const ext =
|
|
47762
|
+
const ext = path33.extname(filePath).toLowerCase();
|
|
46162
47763
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
46163
47764
|
return true;
|
|
46164
47765
|
}
|
|
@@ -46183,7 +47784,7 @@ function scanLineForSecrets(line, _lineNum) {
|
|
|
46183
47784
|
if (line.length > MAX_LINE_LENGTH) {
|
|
46184
47785
|
return results;
|
|
46185
47786
|
}
|
|
46186
|
-
for (const pattern of
|
|
47787
|
+
for (const pattern of SECRET_PATTERNS2) {
|
|
46187
47788
|
pattern.regex.lastIndex = 0;
|
|
46188
47789
|
for (let match = pattern.regex.exec(line);match !== null; match = pattern.regex.exec(line)) {
|
|
46189
47790
|
const fullMatch = match[0];
|
|
@@ -46294,9 +47895,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
46294
47895
|
return false;
|
|
46295
47896
|
}
|
|
46296
47897
|
function isPathWithinScope(realPath, scanDir) {
|
|
46297
|
-
const resolvedScanDir =
|
|
46298
|
-
const resolvedRealPath =
|
|
46299
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
47898
|
+
const resolvedScanDir = path33.resolve(scanDir);
|
|
47899
|
+
const resolvedRealPath = path33.resolve(realPath);
|
|
47900
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path33.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
46300
47901
|
}
|
|
46301
47902
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
46302
47903
|
skippedDirs: 0,
|
|
@@ -46322,8 +47923,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
46322
47923
|
return a.localeCompare(b);
|
|
46323
47924
|
});
|
|
46324
47925
|
for (const entry of entries) {
|
|
46325
|
-
const fullPath =
|
|
46326
|
-
const relPath =
|
|
47926
|
+
const fullPath = path33.join(dir, entry);
|
|
47927
|
+
const relPath = path33.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
46327
47928
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
46328
47929
|
stats.skippedDirs++;
|
|
46329
47930
|
continue;
|
|
@@ -46358,7 +47959,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
46358
47959
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
46359
47960
|
files.push(...subFiles);
|
|
46360
47961
|
} else if (lstat.isFile()) {
|
|
46361
|
-
const ext =
|
|
47962
|
+
const ext = path33.extname(fullPath).toLowerCase();
|
|
46362
47963
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
46363
47964
|
files.push(fullPath);
|
|
46364
47965
|
} else {
|
|
@@ -46385,7 +47986,7 @@ async function runSecretscan(directory) {
|
|
|
46385
47986
|
return errorResult;
|
|
46386
47987
|
}
|
|
46387
47988
|
}
|
|
46388
|
-
var MAX_FILE_PATH_LENGTH = 500, MAX_FILE_SIZE_BYTES, MAX_FILES_SCANNED = 1000, MAX_FINDINGS = 100, MAX_OUTPUT_BYTES2 = 512000, MAX_LINE_LENGTH = 1e4, MAX_CONTENT_BYTES, BINARY_SIGNATURES, BINARY_PREFIX_BYTES = 4, BINARY_NULL_CHECK_BYTES = 8192, BINARY_NULL_THRESHOLD = 0.1, DEFAULT_EXCLUDE_DIRS, DEFAULT_EXCLUDE_EXTENSIONS,
|
|
47989
|
+
var MAX_FILE_PATH_LENGTH = 500, MAX_FILE_SIZE_BYTES, MAX_FILES_SCANNED = 1000, MAX_FINDINGS = 100, MAX_OUTPUT_BYTES2 = 512000, MAX_LINE_LENGTH = 1e4, MAX_CONTENT_BYTES, BINARY_SIGNATURES, BINARY_PREFIX_BYTES = 4, BINARY_NULL_CHECK_BYTES = 8192, BINARY_NULL_THRESHOLD = 0.1, DEFAULT_EXCLUDE_DIRS, DEFAULT_EXCLUDE_EXTENSIONS, SECRET_PATTERNS2, O_NOFOLLOW, secretscan, _internals20;
|
|
46389
47990
|
var init_secretscan = __esm(() => {
|
|
46390
47991
|
init_zod();
|
|
46391
47992
|
init_path_security();
|
|
@@ -46448,7 +48049,7 @@ var init_secretscan = __esm(() => {
|
|
|
46448
48049
|
".log",
|
|
46449
48050
|
".md"
|
|
46450
48051
|
]);
|
|
46451
|
-
|
|
48052
|
+
SECRET_PATTERNS2 = [
|
|
46452
48053
|
{
|
|
46453
48054
|
type: "aws_access_key",
|
|
46454
48055
|
regex: /(?:AWS_ACCESS_KEY_ID|AWS_SECRET_ACCESS_KEY|aws_access_key_id|aws_secret_access_key)\s*[=:]\s*['"]?([A-Z0-9]{20})['"]?/gi,
|
|
@@ -46618,7 +48219,7 @@ var init_secretscan = __esm(() => {
|
|
|
46618
48219
|
}
|
|
46619
48220
|
}
|
|
46620
48221
|
try {
|
|
46621
|
-
const _scanDirRaw =
|
|
48222
|
+
const _scanDirRaw = path33.resolve(directory);
|
|
46622
48223
|
const scanDir = (() => {
|
|
46623
48224
|
try {
|
|
46624
48225
|
return fs13.realpathSync(_scanDirRaw);
|
|
@@ -46688,8 +48289,8 @@ var init_secretscan = __esm(() => {
|
|
|
46688
48289
|
break;
|
|
46689
48290
|
const fileFindings = scanFileForSecrets(filePath);
|
|
46690
48291
|
try {
|
|
46691
|
-
const
|
|
46692
|
-
if (
|
|
48292
|
+
const stat4 = fs13.statSync(filePath);
|
|
48293
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES) {
|
|
46693
48294
|
skippedFiles++;
|
|
46694
48295
|
continue;
|
|
46695
48296
|
}
|
|
@@ -46765,7 +48366,7 @@ var init_secretscan = __esm(() => {
|
|
|
46765
48366
|
|
|
46766
48367
|
// src/lang/default-backend.ts
|
|
46767
48368
|
import * as fs14 from "fs";
|
|
46768
|
-
import * as
|
|
48369
|
+
import * as path34 from "path";
|
|
46769
48370
|
function detectFileExists(dir, pattern) {
|
|
46770
48371
|
if (pattern.includes("*") || pattern.includes("?")) {
|
|
46771
48372
|
try {
|
|
@@ -46777,7 +48378,7 @@ function detectFileExists(dir, pattern) {
|
|
|
46777
48378
|
}
|
|
46778
48379
|
}
|
|
46779
48380
|
try {
|
|
46780
|
-
fs14.accessSync(
|
|
48381
|
+
fs14.accessSync(path34.join(dir, pattern));
|
|
46781
48382
|
return true;
|
|
46782
48383
|
} catch {
|
|
46783
48384
|
return false;
|
|
@@ -46905,8 +48506,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
46905
48506
|
return ["mvn", "test"];
|
|
46906
48507
|
case "gradle": {
|
|
46907
48508
|
const isWindows = process.platform === "win32";
|
|
46908
|
-
const hasGradlewBat = fs14.existsSync(
|
|
46909
|
-
const hasGradlew = fs14.existsSync(
|
|
48509
|
+
const hasGradlewBat = fs14.existsSync(path34.join(dir, "gradlew.bat"));
|
|
48510
|
+
const hasGradlew = fs14.existsSync(path34.join(dir, "gradlew"));
|
|
46910
48511
|
if (hasGradlewBat && isWindows)
|
|
46911
48512
|
return ["gradlew.bat", "test"];
|
|
46912
48513
|
if (hasGradlew)
|
|
@@ -46923,7 +48524,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
46923
48524
|
"cmake-build-release",
|
|
46924
48525
|
"out"
|
|
46925
48526
|
];
|
|
46926
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs14.existsSync(
|
|
48527
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs14.existsSync(path34.join(dir, d, "CMakeCache.txt"))) ?? "build";
|
|
46927
48528
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
46928
48529
|
}
|
|
46929
48530
|
case "swift-test":
|
|
@@ -47210,17 +48811,17 @@ async function defaultSelectBuildCommand(profile, dir) {
|
|
|
47210
48811
|
return null;
|
|
47211
48812
|
}
|
|
47212
48813
|
async function defaultTestFilesFor(profile, sourceFile, dir) {
|
|
47213
|
-
const ext =
|
|
48814
|
+
const ext = path34.extname(sourceFile);
|
|
47214
48815
|
if (!profile.extensions.includes(ext))
|
|
47215
48816
|
return [];
|
|
47216
|
-
const base =
|
|
47217
|
-
const rel =
|
|
47218
|
-
const relDir =
|
|
48817
|
+
const base = path34.basename(sourceFile, ext);
|
|
48818
|
+
const rel = path34.relative(dir, sourceFile);
|
|
48819
|
+
const relDir = path34.dirname(rel);
|
|
47219
48820
|
const stripSrc = relDir.replace(/^src(\/|\\)/, "");
|
|
47220
48821
|
const candidates = new Set;
|
|
47221
48822
|
for (const tDir of ["tests", "test", "__tests__", "spec"]) {
|
|
47222
48823
|
for (const suffix of ["", "_test", ".test", "_spec", ".spec"]) {
|
|
47223
|
-
candidates.add(
|
|
48824
|
+
candidates.add(path34.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
|
|
47224
48825
|
}
|
|
47225
48826
|
}
|
|
47226
48827
|
const existing = [];
|
|
@@ -47261,7 +48862,7 @@ var init_default_backend = __esm(() => {
|
|
|
47261
48862
|
|
|
47262
48863
|
// src/lang/backends/go.ts
|
|
47263
48864
|
import * as fs15 from "fs";
|
|
47264
|
-
import * as
|
|
48865
|
+
import * as path35 from "path";
|
|
47265
48866
|
function extractImports(_sourceFile, source) {
|
|
47266
48867
|
const out = new Set;
|
|
47267
48868
|
IMPORT_REGEX_SINGLE.lastIndex = 0;
|
|
@@ -47287,7 +48888,7 @@ function extractImports(_sourceFile, source) {
|
|
|
47287
48888
|
async function selectFramework(dir) {
|
|
47288
48889
|
let content;
|
|
47289
48890
|
try {
|
|
47290
|
-
content = fs15.readFileSync(
|
|
48891
|
+
content = fs15.readFileSync(path35.join(dir, "go.mod"), "utf-8");
|
|
47291
48892
|
} catch {
|
|
47292
48893
|
return null;
|
|
47293
48894
|
}
|
|
@@ -47308,16 +48909,16 @@ async function selectFramework(dir) {
|
|
|
47308
48909
|
async function selectEntryPoints(dir) {
|
|
47309
48910
|
const points = [];
|
|
47310
48911
|
try {
|
|
47311
|
-
fs15.accessSync(
|
|
48912
|
+
fs15.accessSync(path35.join(dir, "main.go"));
|
|
47312
48913
|
points.push("main.go");
|
|
47313
48914
|
} catch {}
|
|
47314
48915
|
try {
|
|
47315
|
-
const cmdDir =
|
|
48916
|
+
const cmdDir = path35.join(dir, "cmd");
|
|
47316
48917
|
const subdirs = fs15.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
47317
48918
|
for (const sub of subdirs) {
|
|
47318
|
-
const main =
|
|
48919
|
+
const main = path35.join("cmd", sub.name, "main.go");
|
|
47319
48920
|
try {
|
|
47320
|
-
fs15.accessSync(
|
|
48921
|
+
fs15.accessSync(path35.join(dir, main));
|
|
47321
48922
|
points.push(main);
|
|
47322
48923
|
} catch {}
|
|
47323
48924
|
}
|
|
@@ -47348,7 +48949,7 @@ var init_go = __esm(() => {
|
|
|
47348
48949
|
|
|
47349
48950
|
// src/lang/backends/python.ts
|
|
47350
48951
|
import * as fs16 from "fs";
|
|
47351
|
-
import * as
|
|
48952
|
+
import * as path36 from "path";
|
|
47352
48953
|
function parseImportTargets(rawTargets) {
|
|
47353
48954
|
const cleaned = rawTargets.replace(/[()]/g, "").split(`
|
|
47354
48955
|
`).map((line) => line.replace(/#.*$/, "").replace(/\\\s*$/, "")).join(" ");
|
|
@@ -47408,7 +49009,7 @@ async function selectFramework2(dir) {
|
|
|
47408
49009
|
];
|
|
47409
49010
|
for (const candidate of ["pyproject.toml", "requirements.txt", "setup.py"]) {
|
|
47410
49011
|
try {
|
|
47411
|
-
const content = fs16.readFileSync(
|
|
49012
|
+
const content = fs16.readFileSync(path36.join(dir, candidate), "utf-8");
|
|
47412
49013
|
const lower = content.toLowerCase();
|
|
47413
49014
|
for (const [pkg, name] of candidates) {
|
|
47414
49015
|
if (lower.includes(pkg)) {
|
|
@@ -47422,7 +49023,7 @@ async function selectFramework2(dir) {
|
|
|
47422
49023
|
async function selectEntryPoints2(dir) {
|
|
47423
49024
|
const points = new Set;
|
|
47424
49025
|
try {
|
|
47425
|
-
const content = fs16.readFileSync(
|
|
49026
|
+
const content = fs16.readFileSync(path36.join(dir, "pyproject.toml"), "utf-8");
|
|
47426
49027
|
const scriptsBlock = content.match(/\[project\.scripts\][\s\S]*?(?=\n\[|$)/);
|
|
47427
49028
|
if (scriptsBlock) {
|
|
47428
49029
|
for (const line of scriptsBlock[0].split(`
|
|
@@ -47437,7 +49038,7 @@ async function selectEntryPoints2(dir) {
|
|
|
47437
49038
|
} catch {}
|
|
47438
49039
|
for (const name of ["manage.py", "main.py", "app.py", "__main__.py"]) {
|
|
47439
49040
|
try {
|
|
47440
|
-
fs16.accessSync(
|
|
49041
|
+
fs16.accessSync(path36.join(dir, name));
|
|
47441
49042
|
points.add(name);
|
|
47442
49043
|
} catch {}
|
|
47443
49044
|
}
|
|
@@ -47466,15 +49067,15 @@ var init_python = __esm(() => {
|
|
|
47466
49067
|
|
|
47467
49068
|
// src/test-impact/analyzer.ts
|
|
47468
49069
|
import fs17 from "fs";
|
|
47469
|
-
import
|
|
49070
|
+
import path37 from "path";
|
|
47470
49071
|
function normalizePath(p) {
|
|
47471
49072
|
return p.replace(/\\/g, "/");
|
|
47472
49073
|
}
|
|
47473
49074
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
47474
49075
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
47475
49076
|
try {
|
|
47476
|
-
const
|
|
47477
|
-
if (
|
|
49077
|
+
const stat4 = fs17.statSync(sourcePath);
|
|
49078
|
+
if (stat4.mtimeMs > generatedAtMs) {
|
|
47478
49079
|
return true;
|
|
47479
49080
|
}
|
|
47480
49081
|
} catch {
|
|
@@ -47487,8 +49088,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
47487
49088
|
if (!importPath.startsWith(".")) {
|
|
47488
49089
|
return null;
|
|
47489
49090
|
}
|
|
47490
|
-
const resolved =
|
|
47491
|
-
if (
|
|
49091
|
+
const resolved = path37.resolve(fromDir, importPath);
|
|
49092
|
+
if (path37.extname(resolved)) {
|
|
47492
49093
|
if (fs17.existsSync(resolved) && fs17.statSync(resolved).isFile()) {
|
|
47493
49094
|
return normalizePath(resolved);
|
|
47494
49095
|
}
|
|
@@ -47508,20 +49109,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
47508
49109
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
47509
49110
|
let baseDir = fromDir;
|
|
47510
49111
|
for (let i = 1;i < leadingDots; i++) {
|
|
47511
|
-
baseDir =
|
|
49112
|
+
baseDir = path37.dirname(baseDir);
|
|
47512
49113
|
}
|
|
47513
49114
|
const rest = module.slice(leadingDots);
|
|
47514
49115
|
if (rest.length === 0) {
|
|
47515
|
-
const initPath =
|
|
49116
|
+
const initPath = path37.join(baseDir, "__init__.py");
|
|
47516
49117
|
if (fs17.existsSync(initPath) && fs17.statSync(initPath).isFile()) {
|
|
47517
49118
|
return normalizePath(initPath);
|
|
47518
49119
|
}
|
|
47519
49120
|
return null;
|
|
47520
49121
|
}
|
|
47521
|
-
const subpath = rest.replace(/\./g,
|
|
49122
|
+
const subpath = rest.replace(/\./g, path37.sep);
|
|
47522
49123
|
const candidates = [
|
|
47523
|
-
`${
|
|
47524
|
-
|
|
49124
|
+
`${path37.join(baseDir, subpath)}.py`,
|
|
49125
|
+
path37.join(baseDir, subpath, "__init__.py")
|
|
47525
49126
|
];
|
|
47526
49127
|
for (const c of candidates) {
|
|
47527
49128
|
if (fs17.existsSync(c) && fs17.statSync(c).isFile())
|
|
@@ -47530,7 +49131,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
47530
49131
|
return null;
|
|
47531
49132
|
}
|
|
47532
49133
|
function findGoModule(fromDir) {
|
|
47533
|
-
const resolved =
|
|
49134
|
+
const resolved = path37.resolve(fromDir);
|
|
47534
49135
|
let cur = resolved;
|
|
47535
49136
|
const walked = [];
|
|
47536
49137
|
for (let i = 0;i < 16; i++) {
|
|
@@ -47542,7 +49143,7 @@ function findGoModule(fromDir) {
|
|
|
47542
49143
|
}
|
|
47543
49144
|
walked.push(cur);
|
|
47544
49145
|
try {
|
|
47545
|
-
const goMod =
|
|
49146
|
+
const goMod = path37.join(cur, "go.mod");
|
|
47546
49147
|
const content = fs17.readFileSync(goMod, "utf-8");
|
|
47547
49148
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
47548
49149
|
if (moduleMatch) {
|
|
@@ -47553,10 +49154,10 @@ function findGoModule(fromDir) {
|
|
|
47553
49154
|
}
|
|
47554
49155
|
} catch {}
|
|
47555
49156
|
try {
|
|
47556
|
-
fs17.accessSync(
|
|
49157
|
+
fs17.accessSync(path37.join(cur, ".git"));
|
|
47557
49158
|
break;
|
|
47558
49159
|
} catch {}
|
|
47559
|
-
const parent =
|
|
49160
|
+
const parent = path37.dirname(cur);
|
|
47560
49161
|
if (parent === cur)
|
|
47561
49162
|
break;
|
|
47562
49163
|
cur = parent;
|
|
@@ -47568,12 +49169,12 @@ function findGoModule(fromDir) {
|
|
|
47568
49169
|
function resolveGoImport(fromDir, importPath) {
|
|
47569
49170
|
let dir = null;
|
|
47570
49171
|
if (importPath.startsWith(".")) {
|
|
47571
|
-
dir =
|
|
49172
|
+
dir = path37.resolve(fromDir, importPath);
|
|
47572
49173
|
} else {
|
|
47573
49174
|
const mod = findGoModule(fromDir);
|
|
47574
49175
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
47575
49176
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
47576
|
-
dir =
|
|
49177
|
+
dir = path37.join(mod.moduleRoot, subpath);
|
|
47577
49178
|
}
|
|
47578
49179
|
}
|
|
47579
49180
|
if (dir === null)
|
|
@@ -47581,7 +49182,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
47581
49182
|
if (!fs17.existsSync(dir) || !fs17.statSync(dir).isDirectory())
|
|
47582
49183
|
return [];
|
|
47583
49184
|
try {
|
|
47584
|
-
return fs17.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(
|
|
49185
|
+
return fs17.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(path37.join(dir, f)));
|
|
47585
49186
|
} catch {
|
|
47586
49187
|
return [];
|
|
47587
49188
|
}
|
|
@@ -47620,15 +49221,15 @@ function findTestFilesSync(cwd) {
|
|
|
47620
49221
|
for (const entry of entries) {
|
|
47621
49222
|
if (entry.isDirectory()) {
|
|
47622
49223
|
if (!skipDirs.has(entry.name)) {
|
|
47623
|
-
walk(
|
|
49224
|
+
walk(path37.join(dir, entry.name), visitedInodes);
|
|
47624
49225
|
}
|
|
47625
49226
|
} else if (entry.isFile()) {
|
|
47626
49227
|
const name = entry.name;
|
|
47627
49228
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
47628
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
49229
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path37.sep}tests${path37.sep}`) && name.endsWith(".py");
|
|
47629
49230
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
47630
49231
|
if (isTsTest || isPyTest || isGoTest) {
|
|
47631
|
-
testFiles.push(normalizePath(
|
|
49232
|
+
testFiles.push(normalizePath(path37.join(dir, entry.name)));
|
|
47632
49233
|
}
|
|
47633
49234
|
}
|
|
47634
49235
|
}
|
|
@@ -47653,8 +49254,8 @@ function extractImports3(content) {
|
|
|
47653
49254
|
];
|
|
47654
49255
|
}
|
|
47655
49256
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
47656
|
-
const ext =
|
|
47657
|
-
const testDir =
|
|
49257
|
+
const ext = path37.extname(testFile).toLowerCase();
|
|
49258
|
+
const testDir = path37.dirname(testFile);
|
|
47658
49259
|
function addEdge(source) {
|
|
47659
49260
|
if (!impactMap[source])
|
|
47660
49261
|
impactMap[source] = [];
|
|
@@ -47713,7 +49314,7 @@ async function buildImpactMap(cwd) {
|
|
|
47713
49314
|
return impactMap;
|
|
47714
49315
|
}
|
|
47715
49316
|
async function loadImpactMap(cwd, options) {
|
|
47716
|
-
const cachePath =
|
|
49317
|
+
const cachePath = path37.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
47717
49318
|
if (fs17.existsSync(cachePath)) {
|
|
47718
49319
|
try {
|
|
47719
49320
|
const content = fs17.readFileSync(cachePath, "utf-8");
|
|
@@ -47746,12 +49347,12 @@ async function loadImpactMap(cwd, options) {
|
|
|
47746
49347
|
return _internals23.buildImpactMap(cwd);
|
|
47747
49348
|
}
|
|
47748
49349
|
async function saveImpactMap(cwd, impactMap) {
|
|
47749
|
-
if (!
|
|
49350
|
+
if (!path37.isAbsolute(cwd)) {
|
|
47750
49351
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
47751
49352
|
}
|
|
47752
49353
|
_internals23.validateProjectRoot(cwd);
|
|
47753
|
-
const cacheDir2 =
|
|
47754
|
-
const cachePath =
|
|
49354
|
+
const cacheDir2 = path37.join(cwd, ".swarm", "cache");
|
|
49355
|
+
const cachePath = path37.join(cacheDir2, "impact-map.json");
|
|
47755
49356
|
if (!fs17.existsSync(cacheDir2)) {
|
|
47756
49357
|
fs17.mkdirSync(cacheDir2, { recursive: true });
|
|
47757
49358
|
}
|
|
@@ -47783,7 +49384,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
47783
49384
|
budgetExceeded = true;
|
|
47784
49385
|
break;
|
|
47785
49386
|
}
|
|
47786
|
-
const normalizedChanged = normalizePath(
|
|
49387
|
+
const normalizedChanged = normalizePath(path37.resolve(changedFile));
|
|
47787
49388
|
const tests = impactMap[normalizedChanged];
|
|
47788
49389
|
if (tests && tests.length > 0) {
|
|
47789
49390
|
for (const test of tests) {
|
|
@@ -48076,15 +49677,15 @@ var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
|
|
|
48076
49677
|
|
|
48077
49678
|
// src/test-impact/history-store.ts
|
|
48078
49679
|
import fs18 from "fs";
|
|
48079
|
-
import
|
|
49680
|
+
import path38 from "path";
|
|
48080
49681
|
function getHistoryPath(workingDir) {
|
|
48081
49682
|
if (!workingDir) {
|
|
48082
49683
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
48083
49684
|
}
|
|
48084
|
-
if (!
|
|
49685
|
+
if (!path38.isAbsolute(workingDir)) {
|
|
48085
49686
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
48086
49687
|
}
|
|
48087
|
-
return
|
|
49688
|
+
return path38.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
48088
49689
|
}
|
|
48089
49690
|
function sanitizeErrorMessage(errorMessage) {
|
|
48090
49691
|
if (errorMessage === undefined) {
|
|
@@ -48171,7 +49772,7 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
48171
49772
|
}
|
|
48172
49773
|
}
|
|
48173
49774
|
const historyPath = getHistoryPath(workingDir);
|
|
48174
|
-
const historyDir =
|
|
49775
|
+
const historyDir = path38.dirname(historyPath);
|
|
48175
49776
|
_internals24.validateProjectRoot(workingDir);
|
|
48176
49777
|
if (!fs18.existsSync(historyDir)) {
|
|
48177
49778
|
fs18.mkdirSync(historyDir, { recursive: true });
|
|
@@ -48267,7 +49868,7 @@ var init_history_store = __esm(() => {
|
|
|
48267
49868
|
|
|
48268
49869
|
// src/tools/resolve-working-directory.ts
|
|
48269
49870
|
import * as fs19 from "fs";
|
|
48270
|
-
import * as
|
|
49871
|
+
import * as path39 from "path";
|
|
48271
49872
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
48272
49873
|
if (workingDirectory == null || workingDirectory === "") {
|
|
48273
49874
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -48287,15 +49888,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
48287
49888
|
};
|
|
48288
49889
|
}
|
|
48289
49890
|
}
|
|
48290
|
-
const normalizedDir =
|
|
48291
|
-
const pathParts = normalizedDir.split(
|
|
49891
|
+
const normalizedDir = path39.normalize(workingDirectory);
|
|
49892
|
+
const pathParts = normalizedDir.split(path39.sep);
|
|
48292
49893
|
if (pathParts.includes("..")) {
|
|
48293
49894
|
return {
|
|
48294
49895
|
success: false,
|
|
48295
49896
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
48296
49897
|
};
|
|
48297
49898
|
}
|
|
48298
|
-
const resolvedDir =
|
|
49899
|
+
const resolvedDir = path39.resolve(normalizedDir);
|
|
48299
49900
|
let statResult;
|
|
48300
49901
|
try {
|
|
48301
49902
|
statResult = fs19.statSync(resolvedDir);
|
|
@@ -48311,7 +49912,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
48311
49912
|
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
48312
49913
|
};
|
|
48313
49914
|
}
|
|
48314
|
-
const resolvedFallback =
|
|
49915
|
+
const resolvedFallback = path39.resolve(fallbackDirectory);
|
|
48315
49916
|
let fallbackExists = false;
|
|
48316
49917
|
try {
|
|
48317
49918
|
fs19.statSync(resolvedFallback);
|
|
@@ -48321,7 +49922,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
48321
49922
|
}
|
|
48322
49923
|
if (workingDirectory != null && workingDirectory !== "") {
|
|
48323
49924
|
if (fallbackExists) {
|
|
48324
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
49925
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path39.sep);
|
|
48325
49926
|
if (isSubdirectory) {
|
|
48326
49927
|
return {
|
|
48327
49928
|
success: false,
|
|
@@ -48376,10 +49977,10 @@ var init_registry_backend = __esm(() => {
|
|
|
48376
49977
|
|
|
48377
49978
|
// src/lang/backends/typescript.ts
|
|
48378
49979
|
import * as fs20 from "fs";
|
|
48379
|
-
import * as
|
|
49980
|
+
import * as path40 from "path";
|
|
48380
49981
|
function readPackageJsonRaw(dir) {
|
|
48381
49982
|
try {
|
|
48382
|
-
const content = fs20.readFileSync(
|
|
49983
|
+
const content = fs20.readFileSync(path40.join(dir, "package.json"), "utf-8");
|
|
48383
49984
|
return JSON.parse(content);
|
|
48384
49985
|
} catch {
|
|
48385
49986
|
return null;
|
|
@@ -48599,7 +50200,7 @@ __export(exports_dispatch, {
|
|
|
48599
50200
|
_internals: () => _internals26
|
|
48600
50201
|
});
|
|
48601
50202
|
import * as fs21 from "fs";
|
|
48602
|
-
import * as
|
|
50203
|
+
import * as path41 from "path";
|
|
48603
50204
|
function safeReaddirSet(dir) {
|
|
48604
50205
|
try {
|
|
48605
50206
|
return new Set(fs21.readdirSync(dir));
|
|
@@ -48616,14 +50217,14 @@ function manifestHash(dir) {
|
|
|
48616
50217
|
if (!entries.has(name))
|
|
48617
50218
|
continue;
|
|
48618
50219
|
try {
|
|
48619
|
-
const
|
|
48620
|
-
parts.push(`${name}:${
|
|
50220
|
+
const stat4 = fs21.statSync(path41.join(dir, name));
|
|
50221
|
+
parts.push(`${name}:${stat4.size}:${stat4.mtimeMs}:${stat4.ino}`);
|
|
48621
50222
|
} catch {}
|
|
48622
50223
|
}
|
|
48623
50224
|
return parts.join("|");
|
|
48624
50225
|
}
|
|
48625
50226
|
function findManifestRoot(start) {
|
|
48626
|
-
const resolved =
|
|
50227
|
+
const resolved = path41.resolve(start);
|
|
48627
50228
|
const cached3 = manifestRootCache.get(resolved);
|
|
48628
50229
|
if (cached3 !== undefined)
|
|
48629
50230
|
return cached3;
|
|
@@ -48642,7 +50243,7 @@ function findManifestRoot(start) {
|
|
|
48642
50243
|
return cur;
|
|
48643
50244
|
}
|
|
48644
50245
|
}
|
|
48645
|
-
const parent =
|
|
50246
|
+
const parent = path41.dirname(cur);
|
|
48646
50247
|
if (parent === cur)
|
|
48647
50248
|
break;
|
|
48648
50249
|
cur = parent;
|
|
@@ -48752,13 +50353,13 @@ var init_dispatch = __esm(() => {
|
|
|
48752
50353
|
|
|
48753
50354
|
// src/tools/test-runner.ts
|
|
48754
50355
|
import * as fs22 from "fs";
|
|
48755
|
-
import * as
|
|
50356
|
+
import * as path42 from "path";
|
|
48756
50357
|
async function estimateFanOut(sourceFiles, cwd) {
|
|
48757
50358
|
try {
|
|
48758
50359
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
48759
50360
|
const uniqueTestFiles = new Set;
|
|
48760
50361
|
for (const sourceFile of sourceFiles) {
|
|
48761
|
-
const resolvedPath =
|
|
50362
|
+
const resolvedPath = path42.resolve(cwd, sourceFile);
|
|
48762
50363
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
48763
50364
|
const testFiles = impactMap[normalizedPath];
|
|
48764
50365
|
if (testFiles) {
|
|
@@ -48836,14 +50437,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
48836
50437
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
48837
50438
|
}
|
|
48838
50439
|
function detectGoTest(cwd) {
|
|
48839
|
-
return fs22.existsSync(
|
|
50440
|
+
return fs22.existsSync(path42.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
48840
50441
|
}
|
|
48841
50442
|
function detectJavaMaven(cwd) {
|
|
48842
|
-
return fs22.existsSync(
|
|
50443
|
+
return fs22.existsSync(path42.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
48843
50444
|
}
|
|
48844
50445
|
function detectGradle(cwd) {
|
|
48845
|
-
const hasBuildFile = fs22.existsSync(
|
|
48846
|
-
const hasGradlew = fs22.existsSync(
|
|
50446
|
+
const hasBuildFile = fs22.existsSync(path42.join(cwd, "build.gradle")) || fs22.existsSync(path42.join(cwd, "build.gradle.kts"));
|
|
50447
|
+
const hasGradlew = fs22.existsSync(path42.join(cwd, "gradlew")) || fs22.existsSync(path42.join(cwd, "gradlew.bat"));
|
|
48847
50448
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
48848
50449
|
}
|
|
48849
50450
|
function detectDotnetTest(cwd) {
|
|
@@ -48856,25 +50457,25 @@ function detectDotnetTest(cwd) {
|
|
|
48856
50457
|
}
|
|
48857
50458
|
}
|
|
48858
50459
|
function detectCTest(cwd) {
|
|
48859
|
-
const hasSource = fs22.existsSync(
|
|
48860
|
-
const hasBuildCache = fs22.existsSync(
|
|
50460
|
+
const hasSource = fs22.existsSync(path42.join(cwd, "CMakeLists.txt"));
|
|
50461
|
+
const hasBuildCache = fs22.existsSync(path42.join(cwd, "CMakeCache.txt")) || fs22.existsSync(path42.join(cwd, "build", "CMakeCache.txt"));
|
|
48861
50462
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
48862
50463
|
}
|
|
48863
50464
|
function detectSwiftTest(cwd) {
|
|
48864
|
-
return fs22.existsSync(
|
|
50465
|
+
return fs22.existsSync(path42.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
48865
50466
|
}
|
|
48866
50467
|
function detectDartTest(cwd) {
|
|
48867
|
-
return fs22.existsSync(
|
|
50468
|
+
return fs22.existsSync(path42.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
48868
50469
|
}
|
|
48869
50470
|
function detectRSpec(cwd) {
|
|
48870
|
-
const hasRSpecFile = fs22.existsSync(
|
|
48871
|
-
const hasGemfile = fs22.existsSync(
|
|
48872
|
-
const hasSpecDir = fs22.existsSync(
|
|
50471
|
+
const hasRSpecFile = fs22.existsSync(path42.join(cwd, ".rspec"));
|
|
50472
|
+
const hasGemfile = fs22.existsSync(path42.join(cwd, "Gemfile"));
|
|
50473
|
+
const hasSpecDir = fs22.existsSync(path42.join(cwd, "spec"));
|
|
48873
50474
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
48874
50475
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
48875
50476
|
}
|
|
48876
50477
|
function detectMinitest(cwd) {
|
|
48877
|
-
return fs22.existsSync(
|
|
50478
|
+
return fs22.existsSync(path42.join(cwd, "test")) && (fs22.existsSync(path42.join(cwd, "Gemfile")) || fs22.existsSync(path42.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
48878
50479
|
}
|
|
48879
50480
|
async function detectTestFrameworkViaDispatch(cwd) {
|
|
48880
50481
|
try {
|
|
@@ -48936,7 +50537,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
48936
50537
|
async function detectTestFramework(cwd) {
|
|
48937
50538
|
const baseDir = cwd;
|
|
48938
50539
|
try {
|
|
48939
|
-
const packageJsonPath =
|
|
50540
|
+
const packageJsonPath = path42.join(baseDir, "package.json");
|
|
48940
50541
|
if (fs22.existsSync(packageJsonPath)) {
|
|
48941
50542
|
const content = fs22.readFileSync(packageJsonPath, "utf-8");
|
|
48942
50543
|
const pkg = JSON.parse(content);
|
|
@@ -48957,16 +50558,16 @@ async function detectTestFramework(cwd) {
|
|
|
48957
50558
|
return "jest";
|
|
48958
50559
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
48959
50560
|
return "mocha";
|
|
48960
|
-
if (fs22.existsSync(
|
|
50561
|
+
if (fs22.existsSync(path42.join(baseDir, "bun.lockb")) || fs22.existsSync(path42.join(baseDir, "bun.lock"))) {
|
|
48961
50562
|
if (scripts.test?.includes("bun"))
|
|
48962
50563
|
return "bun";
|
|
48963
50564
|
}
|
|
48964
50565
|
}
|
|
48965
50566
|
} catch {}
|
|
48966
50567
|
try {
|
|
48967
|
-
const pyprojectTomlPath =
|
|
48968
|
-
const setupCfgPath =
|
|
48969
|
-
const requirementsTxtPath =
|
|
50568
|
+
const pyprojectTomlPath = path42.join(baseDir, "pyproject.toml");
|
|
50569
|
+
const setupCfgPath = path42.join(baseDir, "setup.cfg");
|
|
50570
|
+
const requirementsTxtPath = path42.join(baseDir, "requirements.txt");
|
|
48970
50571
|
if (fs22.existsSync(pyprojectTomlPath)) {
|
|
48971
50572
|
const content = fs22.readFileSync(pyprojectTomlPath, "utf-8");
|
|
48972
50573
|
if (content.includes("[tool.pytest"))
|
|
@@ -48986,7 +50587,7 @@ async function detectTestFramework(cwd) {
|
|
|
48986
50587
|
}
|
|
48987
50588
|
} catch {}
|
|
48988
50589
|
try {
|
|
48989
|
-
const cargoTomlPath =
|
|
50590
|
+
const cargoTomlPath = path42.join(baseDir, "Cargo.toml");
|
|
48990
50591
|
if (fs22.existsSync(cargoTomlPath)) {
|
|
48991
50592
|
const content = fs22.readFileSync(cargoTomlPath, "utf-8");
|
|
48992
50593
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -48997,9 +50598,9 @@ async function detectTestFramework(cwd) {
|
|
|
48997
50598
|
}
|
|
48998
50599
|
} catch {}
|
|
48999
50600
|
try {
|
|
49000
|
-
const pesterConfigPath =
|
|
49001
|
-
const pesterConfigJsonPath =
|
|
49002
|
-
const pesterPs1Path =
|
|
50601
|
+
const pesterConfigPath = path42.join(baseDir, "pester.config.ps1");
|
|
50602
|
+
const pesterConfigJsonPath = path42.join(baseDir, "pester.config.ps1.json");
|
|
50603
|
+
const pesterPs1Path = path42.join(baseDir, "tests.ps1");
|
|
49003
50604
|
if (fs22.existsSync(pesterConfigPath) || fs22.existsSync(pesterConfigJsonPath) || fs22.existsSync(pesterPs1Path)) {
|
|
49004
50605
|
return "pester";
|
|
49005
50606
|
}
|
|
@@ -49028,12 +50629,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
49028
50629
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
49029
50630
|
}
|
|
49030
50631
|
function resolveWorkspacePath(file3, workingDir) {
|
|
49031
|
-
return
|
|
50632
|
+
return path42.isAbsolute(file3) ? path42.resolve(file3) : path42.resolve(workingDir, file3);
|
|
49032
50633
|
}
|
|
49033
50634
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
49034
50635
|
if (!preferRelative)
|
|
49035
50636
|
return absolutePath;
|
|
49036
|
-
return
|
|
50637
|
+
return path42.relative(workingDir, absolutePath);
|
|
49037
50638
|
}
|
|
49038
50639
|
function dedupePush(target, value) {
|
|
49039
50640
|
if (!target.includes(value)) {
|
|
@@ -49070,18 +50671,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
49070
50671
|
}
|
|
49071
50672
|
}
|
|
49072
50673
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
49073
|
-
const relativeDir =
|
|
50674
|
+
const relativeDir = path42.dirname(relativePath);
|
|
49074
50675
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
49075
50676
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
49076
|
-
const rootDir =
|
|
49077
|
-
return nestedRelativeDir ? [rootDir,
|
|
50677
|
+
const rootDir = path42.join(workingDir, dirName);
|
|
50678
|
+
return nestedRelativeDir ? [rootDir, path42.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
49078
50679
|
});
|
|
49079
50680
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
49080
50681
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
49081
|
-
directories.push(
|
|
50682
|
+
directories.push(path42.join(workingDir, "src/test/java", path42.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
49082
50683
|
}
|
|
49083
50684
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
49084
|
-
directories.push(
|
|
50685
|
+
directories.push(path42.join(workingDir, "src/test/kotlin", path42.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
49085
50686
|
}
|
|
49086
50687
|
return [...new Set(directories)];
|
|
49087
50688
|
}
|
|
@@ -49109,23 +50710,23 @@ function isLanguageSpecificTestFile(basename6) {
|
|
|
49109
50710
|
}
|
|
49110
50711
|
function isConventionTestFilePath(filePath) {
|
|
49111
50712
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
49112
|
-
const basename6 =
|
|
50713
|
+
const basename6 = path42.basename(filePath);
|
|
49113
50714
|
return hasCompoundTestExtension(basename6) || basename6.includes(".spec.") || basename6.includes(".test.") || isLanguageSpecificTestFile(basename6) || isTestDirectoryPath(normalizedPath);
|
|
49114
50715
|
}
|
|
49115
50716
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
49116
50717
|
const testFiles = [];
|
|
49117
50718
|
for (const file3 of sourceFiles) {
|
|
49118
50719
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
49119
|
-
const relativeFile =
|
|
49120
|
-
const basename6 =
|
|
49121
|
-
const
|
|
49122
|
-
const preferRelativeOutput = !
|
|
50720
|
+
const relativeFile = path42.relative(workingDir, absoluteFile);
|
|
50721
|
+
const basename6 = path42.basename(absoluteFile);
|
|
50722
|
+
const dirname20 = path42.dirname(absoluteFile);
|
|
50723
|
+
const preferRelativeOutput = !path42.isAbsolute(file3);
|
|
49123
50724
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
49124
50725
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
49125
50726
|
continue;
|
|
49126
50727
|
}
|
|
49127
50728
|
const nameWithoutExt = basename6.replace(/\.[^.]+$/, "");
|
|
49128
|
-
const ext =
|
|
50729
|
+
const ext = path42.extname(basename6);
|
|
49129
50730
|
const genericTestNames = [
|
|
49130
50731
|
`${nameWithoutExt}.spec${ext}`,
|
|
49131
50732
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -49134,7 +50735,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
49134
50735
|
const colocatedCandidates = [
|
|
49135
50736
|
...genericTestNames,
|
|
49136
50737
|
...languageSpecificTestNames
|
|
49137
|
-
].map((candidateName) =>
|
|
50738
|
+
].map((candidateName) => path42.join(dirname20, candidateName));
|
|
49138
50739
|
const testDirectoryNames = [
|
|
49139
50740
|
basename6,
|
|
49140
50741
|
...genericTestNames,
|
|
@@ -49143,8 +50744,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
49143
50744
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
49144
50745
|
const possibleTestFiles = [
|
|
49145
50746
|
...colocatedCandidates,
|
|
49146
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
49147
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
50747
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path42.join(dirname20, dirName, candidateName))),
|
|
50748
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path42.join(candidateDir, candidateName)))
|
|
49148
50749
|
];
|
|
49149
50750
|
for (const testFile of possibleTestFiles) {
|
|
49150
50751
|
if (fs22.existsSync(testFile)) {
|
|
@@ -49165,7 +50766,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49165
50766
|
try {
|
|
49166
50767
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
49167
50768
|
const content = fs22.readFileSync(absoluteTestFile, "utf-8");
|
|
49168
|
-
const testDir =
|
|
50769
|
+
const testDir = path42.dirname(absoluteTestFile);
|
|
49169
50770
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
49170
50771
|
let match;
|
|
49171
50772
|
match = importRegex.exec(content);
|
|
@@ -49173,8 +50774,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49173
50774
|
const importPath = match[1];
|
|
49174
50775
|
let resolvedImport;
|
|
49175
50776
|
if (importPath.startsWith(".")) {
|
|
49176
|
-
resolvedImport =
|
|
49177
|
-
const existingExt =
|
|
50777
|
+
resolvedImport = path42.resolve(testDir, importPath);
|
|
50778
|
+
const existingExt = path42.extname(resolvedImport);
|
|
49178
50779
|
if (!existingExt) {
|
|
49179
50780
|
for (const extToTry of [
|
|
49180
50781
|
".ts",
|
|
@@ -49194,12 +50795,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49194
50795
|
} else {
|
|
49195
50796
|
continue;
|
|
49196
50797
|
}
|
|
49197
|
-
const importBasename =
|
|
49198
|
-
const importDir =
|
|
50798
|
+
const importBasename = path42.basename(resolvedImport, path42.extname(resolvedImport));
|
|
50799
|
+
const importDir = path42.dirname(resolvedImport);
|
|
49199
50800
|
for (const sourceFile of absoluteSourceFiles) {
|
|
49200
|
-
const sourceDir =
|
|
49201
|
-
const sourceBasename =
|
|
49202
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
50801
|
+
const sourceDir = path42.dirname(sourceFile);
|
|
50802
|
+
const sourceBasename = path42.basename(sourceFile, path42.extname(sourceFile));
|
|
50803
|
+
const isRelatedDir = importDir === sourceDir || importDir === path42.join(sourceDir, "__tests__") || importDir === path42.join(sourceDir, "tests") || importDir === path42.join(sourceDir, "test") || importDir === path42.join(sourceDir, "spec");
|
|
49203
50804
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
49204
50805
|
dedupePush(testFiles, testFile);
|
|
49205
50806
|
break;
|
|
@@ -49212,8 +50813,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49212
50813
|
while (match !== null) {
|
|
49213
50814
|
const importPath = match[1];
|
|
49214
50815
|
if (importPath.startsWith(".")) {
|
|
49215
|
-
let resolvedImport =
|
|
49216
|
-
const existingExt =
|
|
50816
|
+
let resolvedImport = path42.resolve(testDir, importPath);
|
|
50817
|
+
const existingExt = path42.extname(resolvedImport);
|
|
49217
50818
|
if (!existingExt) {
|
|
49218
50819
|
for (const extToTry of [
|
|
49219
50820
|
".ts",
|
|
@@ -49230,12 +50831,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49230
50831
|
}
|
|
49231
50832
|
}
|
|
49232
50833
|
}
|
|
49233
|
-
const importDir =
|
|
49234
|
-
const importBasename =
|
|
50834
|
+
const importDir = path42.dirname(resolvedImport);
|
|
50835
|
+
const importBasename = path42.basename(resolvedImport, path42.extname(resolvedImport));
|
|
49235
50836
|
for (const sourceFile of absoluteSourceFiles) {
|
|
49236
|
-
const sourceDir =
|
|
49237
|
-
const sourceBasename =
|
|
49238
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
50837
|
+
const sourceDir = path42.dirname(sourceFile);
|
|
50838
|
+
const sourceBasename = path42.basename(sourceFile, path42.extname(sourceFile));
|
|
50839
|
+
const isRelatedDir = importDir === sourceDir || importDir === path42.join(sourceDir, "__tests__") || importDir === path42.join(sourceDir, "tests") || importDir === path42.join(sourceDir, "test") || importDir === path42.join(sourceDir, "spec");
|
|
49239
50840
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
49240
50841
|
dedupePush(testFiles, testFile);
|
|
49241
50842
|
break;
|
|
@@ -49345,8 +50946,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
|
49345
50946
|
return ["mvn", "test"];
|
|
49346
50947
|
case "gradle": {
|
|
49347
50948
|
const isWindows = process.platform === "win32";
|
|
49348
|
-
const hasGradlewBat = fs22.existsSync(
|
|
49349
|
-
const hasGradlew = fs22.existsSync(
|
|
50949
|
+
const hasGradlewBat = fs22.existsSync(path42.join(baseDir, "gradlew.bat"));
|
|
50950
|
+
const hasGradlew = fs22.existsSync(path42.join(baseDir, "gradlew"));
|
|
49350
50951
|
if (hasGradlewBat && isWindows)
|
|
49351
50952
|
return ["gradlew.bat", "test"];
|
|
49352
50953
|
if (hasGradlew)
|
|
@@ -49363,7 +50964,7 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
|
49363
50964
|
"cmake-build-release",
|
|
49364
50965
|
"out"
|
|
49365
50966
|
];
|
|
49366
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs22.existsSync(
|
|
50967
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs22.existsSync(path42.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
49367
50968
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
49368
50969
|
}
|
|
49369
50970
|
case "swift-test":
|
|
@@ -49795,11 +51396,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
49795
51396
|
};
|
|
49796
51397
|
}
|
|
49797
51398
|
const startTime = Date.now();
|
|
49798
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
51399
|
+
const vitestJsonOutputPath = framework === "vitest" ? path42.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
49799
51400
|
try {
|
|
49800
51401
|
if (vitestJsonOutputPath) {
|
|
49801
51402
|
try {
|
|
49802
|
-
fs22.mkdirSync(
|
|
51403
|
+
fs22.mkdirSync(path42.dirname(vitestJsonOutputPath), { recursive: true });
|
|
49803
51404
|
if (fs22.existsSync(vitestJsonOutputPath)) {
|
|
49804
51405
|
fs22.unlinkSync(vitestJsonOutputPath);
|
|
49805
51406
|
}
|
|
@@ -49915,10 +51516,10 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
49915
51516
|
}
|
|
49916
51517
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
49917
51518
|
const normalized = testFile.replace(/\\/g, "/");
|
|
49918
|
-
if (!
|
|
51519
|
+
if (!path42.isAbsolute(testFile))
|
|
49919
51520
|
return normalized;
|
|
49920
|
-
const relative9 =
|
|
49921
|
-
if (relative9.startsWith("..") ||
|
|
51521
|
+
const relative9 = path42.relative(workingDir, testFile);
|
|
51522
|
+
if (relative9.startsWith("..") || path42.isAbsolute(relative9)) {
|
|
49922
51523
|
return normalized;
|
|
49923
51524
|
}
|
|
49924
51525
|
return relative9.replace(/\\/g, "/");
|
|
@@ -50256,7 +51857,7 @@ var init_test_runner = __esm(() => {
|
|
|
50256
51857
|
const sourceFiles = args.files.filter((file3) => {
|
|
50257
51858
|
if (directTestFiles.includes(file3))
|
|
50258
51859
|
return false;
|
|
50259
|
-
const ext =
|
|
51860
|
+
const ext = path42.extname(file3).toLowerCase();
|
|
50260
51861
|
return SOURCE_EXTENSIONS.has(ext);
|
|
50261
51862
|
});
|
|
50262
51863
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -50302,7 +51903,7 @@ var init_test_runner = __esm(() => {
|
|
|
50302
51903
|
if (isConventionTestFilePath(f)) {
|
|
50303
51904
|
return false;
|
|
50304
51905
|
}
|
|
50305
|
-
const ext =
|
|
51906
|
+
const ext = path42.extname(f).toLowerCase();
|
|
50306
51907
|
return SOURCE_EXTENSIONS.has(ext);
|
|
50307
51908
|
});
|
|
50308
51909
|
if (sourceFiles.length === 0) {
|
|
@@ -50352,7 +51953,7 @@ var init_test_runner = __esm(() => {
|
|
|
50352
51953
|
if (isConventionTestFilePath(f)) {
|
|
50353
51954
|
return false;
|
|
50354
51955
|
}
|
|
50355
|
-
const ext =
|
|
51956
|
+
const ext = path42.extname(f).toLowerCase();
|
|
50356
51957
|
return SOURCE_EXTENSIONS.has(ext);
|
|
50357
51958
|
});
|
|
50358
51959
|
if (sourceFiles.length === 0) {
|
|
@@ -50404,8 +52005,8 @@ var init_test_runner = __esm(() => {
|
|
|
50404
52005
|
}
|
|
50405
52006
|
if (impactResult.impactedTests.length > 0) {
|
|
50406
52007
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
50407
|
-
const relativePath =
|
|
50408
|
-
return
|
|
52008
|
+
const relativePath = path42.relative(workingDir, absPath);
|
|
52009
|
+
return path42.isAbsolute(relativePath) ? absPath : relativePath;
|
|
50409
52010
|
});
|
|
50410
52011
|
} else {
|
|
50411
52012
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -50481,7 +52082,7 @@ var init_test_runner = __esm(() => {
|
|
|
50481
52082
|
|
|
50482
52083
|
// src/services/preflight-service.ts
|
|
50483
52084
|
import * as fs23 from "fs";
|
|
50484
|
-
import * as
|
|
52085
|
+
import * as path43 from "path";
|
|
50485
52086
|
function validateDirectoryPath(dir) {
|
|
50486
52087
|
if (!dir || typeof dir !== "string") {
|
|
50487
52088
|
throw new Error("Directory path is required");
|
|
@@ -50489,8 +52090,8 @@ function validateDirectoryPath(dir) {
|
|
|
50489
52090
|
if (dir.includes("..")) {
|
|
50490
52091
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
50491
52092
|
}
|
|
50492
|
-
const normalized =
|
|
50493
|
-
const absolutePath =
|
|
52093
|
+
const normalized = path43.normalize(dir);
|
|
52094
|
+
const absolutePath = path43.isAbsolute(normalized) ? normalized : path43.resolve(normalized);
|
|
50494
52095
|
return absolutePath;
|
|
50495
52096
|
}
|
|
50496
52097
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -50513,7 +52114,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
50513
52114
|
}
|
|
50514
52115
|
function getPackageVersion(dir) {
|
|
50515
52116
|
try {
|
|
50516
|
-
const packagePath =
|
|
52117
|
+
const packagePath = path43.join(dir, "package.json");
|
|
50517
52118
|
if (fs23.existsSync(packagePath)) {
|
|
50518
52119
|
const content = fs23.readFileSync(packagePath, "utf-8");
|
|
50519
52120
|
const pkg = JSON.parse(content);
|
|
@@ -50524,7 +52125,7 @@ function getPackageVersion(dir) {
|
|
|
50524
52125
|
}
|
|
50525
52126
|
function getChangelogVersion(dir) {
|
|
50526
52127
|
try {
|
|
50527
|
-
const changelogPath =
|
|
52128
|
+
const changelogPath = path43.join(dir, "CHANGELOG.md");
|
|
50528
52129
|
if (fs23.existsSync(changelogPath)) {
|
|
50529
52130
|
const content = fs23.readFileSync(changelogPath, "utf-8");
|
|
50530
52131
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -50538,7 +52139,7 @@ function getChangelogVersion(dir) {
|
|
|
50538
52139
|
function getVersionFileVersion(dir) {
|
|
50539
52140
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
50540
52141
|
for (const file3 of possibleFiles) {
|
|
50541
|
-
const filePath =
|
|
52142
|
+
const filePath = path43.join(dir, file3);
|
|
50542
52143
|
if (fs23.existsSync(filePath)) {
|
|
50543
52144
|
try {
|
|
50544
52145
|
const content = fs23.readFileSync(filePath, "utf-8").trim();
|
|
@@ -50880,7 +52481,7 @@ async function runEvidenceCheck(dir) {
|
|
|
50880
52481
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
50881
52482
|
const startTime = Date.now();
|
|
50882
52483
|
try {
|
|
50883
|
-
const specPath =
|
|
52484
|
+
const specPath = path43.join(dir, ".swarm", "spec.md");
|
|
50884
52485
|
if (!fs23.existsSync(specPath)) {
|
|
50885
52486
|
return {
|
|
50886
52487
|
type: "req_coverage",
|
|
@@ -51998,7 +53599,7 @@ var init_manager3 = __esm(() => {
|
|
|
51998
53599
|
|
|
51999
53600
|
// src/commands/reset.ts
|
|
52000
53601
|
import * as fs24 from "fs";
|
|
52001
|
-
import * as
|
|
53602
|
+
import * as path44 from "path";
|
|
52002
53603
|
async function handleResetCommand(directory, args) {
|
|
52003
53604
|
const hasConfirm = args.includes("--confirm");
|
|
52004
53605
|
if (!hasConfirm) {
|
|
@@ -52038,7 +53639,7 @@ async function handleResetCommand(directory, args) {
|
|
|
52038
53639
|
}
|
|
52039
53640
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
52040
53641
|
try {
|
|
52041
|
-
const rootPath =
|
|
53642
|
+
const rootPath = path44.join(directory, filename);
|
|
52042
53643
|
if (fs24.existsSync(rootPath)) {
|
|
52043
53644
|
fs24.unlinkSync(rootPath);
|
|
52044
53645
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -52078,7 +53679,7 @@ var init_reset = __esm(() => {
|
|
|
52078
53679
|
|
|
52079
53680
|
// src/commands/reset-session.ts
|
|
52080
53681
|
import * as fs25 from "fs";
|
|
52081
|
-
import * as
|
|
53682
|
+
import * as path45 from "path";
|
|
52082
53683
|
async function handleResetSessionCommand(directory, _args) {
|
|
52083
53684
|
const results = [];
|
|
52084
53685
|
try {
|
|
@@ -52093,13 +53694,13 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
52093
53694
|
results.push("\u274C Failed to delete state.json");
|
|
52094
53695
|
}
|
|
52095
53696
|
try {
|
|
52096
|
-
const sessionDir =
|
|
53697
|
+
const sessionDir = path45.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
52097
53698
|
if (fs25.existsSync(sessionDir)) {
|
|
52098
53699
|
const files = fs25.readdirSync(sessionDir);
|
|
52099
53700
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
52100
53701
|
let deletedCount = 0;
|
|
52101
53702
|
for (const file3 of otherFiles) {
|
|
52102
|
-
const filePath =
|
|
53703
|
+
const filePath = path45.join(sessionDir, file3);
|
|
52103
53704
|
if (fs25.lstatSync(filePath).isFile()) {
|
|
52104
53705
|
fs25.unlinkSync(filePath);
|
|
52105
53706
|
deletedCount++;
|
|
@@ -52131,7 +53732,7 @@ var init_reset_session = __esm(() => {
|
|
|
52131
53732
|
});
|
|
52132
53733
|
|
|
52133
53734
|
// src/summaries/manager.ts
|
|
52134
|
-
import * as
|
|
53735
|
+
import * as path46 from "path";
|
|
52135
53736
|
function sanitizeSummaryId(id) {
|
|
52136
53737
|
if (!id || id.length === 0) {
|
|
52137
53738
|
throw new Error("Invalid summary ID: empty string");
|
|
@@ -52154,7 +53755,7 @@ function sanitizeSummaryId(id) {
|
|
|
52154
53755
|
}
|
|
52155
53756
|
async function loadFullOutput(directory, id) {
|
|
52156
53757
|
const sanitizedId = sanitizeSummaryId(id);
|
|
52157
|
-
const relativePath =
|
|
53758
|
+
const relativePath = path46.join("summaries", `${sanitizedId}.json`);
|
|
52158
53759
|
validateSwarmPath(directory, relativePath);
|
|
52159
53760
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
52160
53761
|
if (content === null) {
|
|
@@ -52217,7 +53818,7 @@ var init_retrieve = __esm(() => {
|
|
|
52217
53818
|
|
|
52218
53819
|
// src/commands/rollback.ts
|
|
52219
53820
|
import * as fs26 from "fs";
|
|
52220
|
-
import * as
|
|
53821
|
+
import * as path47 from "path";
|
|
52221
53822
|
async function handleRollbackCommand(directory, args) {
|
|
52222
53823
|
const phaseArg = args[0];
|
|
52223
53824
|
if (!phaseArg) {
|
|
@@ -52282,8 +53883,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
52282
53883
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
52283
53884
|
continue;
|
|
52284
53885
|
}
|
|
52285
|
-
const src =
|
|
52286
|
-
const dest =
|
|
53886
|
+
const src = path47.join(checkpointDir, file3);
|
|
53887
|
+
const dest = path47.join(swarmDir, file3);
|
|
52287
53888
|
try {
|
|
52288
53889
|
fs26.cpSync(src, dest, { recursive: true, force: true });
|
|
52289
53890
|
successes.push(file3);
|
|
@@ -52302,12 +53903,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
52302
53903
|
].join(`
|
|
52303
53904
|
`);
|
|
52304
53905
|
}
|
|
52305
|
-
const existingLedgerPath =
|
|
53906
|
+
const existingLedgerPath = path47.join(swarmDir, "plan-ledger.jsonl");
|
|
52306
53907
|
if (fs26.existsSync(existingLedgerPath)) {
|
|
52307
53908
|
fs26.unlinkSync(existingLedgerPath);
|
|
52308
53909
|
}
|
|
52309
53910
|
try {
|
|
52310
|
-
const planJsonPath =
|
|
53911
|
+
const planJsonPath = path47.join(swarmDir, "plan.json");
|
|
52311
53912
|
if (fs26.existsSync(planJsonPath)) {
|
|
52312
53913
|
const planRaw = fs26.readFileSync(planJsonPath, "utf-8");
|
|
52313
53914
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -52398,9 +53999,9 @@ Ensure this is a git repository with commit history.`;
|
|
|
52398
53999
|
`);
|
|
52399
54000
|
try {
|
|
52400
54001
|
const fs27 = await import("fs/promises");
|
|
52401
|
-
const
|
|
52402
|
-
const reportPath =
|
|
52403
|
-
await fs27.mkdir(
|
|
54002
|
+
const path48 = await import("path");
|
|
54003
|
+
const reportPath = path48.join(directory, ".swarm", "simulate-report.md");
|
|
54004
|
+
await fs27.mkdir(path48.dirname(reportPath), { recursive: true });
|
|
52404
54005
|
await fs27.writeFile(reportPath, report, "utf-8");
|
|
52405
54006
|
} catch (err) {
|
|
52406
54007
|
const writeErr = err instanceof Error ? err.message : String(err);
|
|
@@ -52424,12 +54025,12 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
52424
54025
|
|
|
52425
54026
|
// src/turbo/lean/state.ts
|
|
52426
54027
|
import * as fs27 from "fs";
|
|
52427
|
-
import * as
|
|
54028
|
+
import * as path48 from "path";
|
|
52428
54029
|
function nowISO2() {
|
|
52429
54030
|
return new Date().toISOString();
|
|
52430
54031
|
}
|
|
52431
54032
|
function ensureSwarmDir2(directory) {
|
|
52432
|
-
const swarmDir =
|
|
54033
|
+
const swarmDir = path48.resolve(directory, ".swarm");
|
|
52433
54034
|
if (!fs27.existsSync(swarmDir)) {
|
|
52434
54035
|
fs27.mkdirSync(swarmDir, { recursive: true });
|
|
52435
54036
|
}
|
|
@@ -52473,7 +54074,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
52473
54074
|
}
|
|
52474
54075
|
function readPersisted2(directory) {
|
|
52475
54076
|
try {
|
|
52476
|
-
const filePath =
|
|
54077
|
+
const filePath = path48.join(directory, ".swarm", STATE_FILE2);
|
|
52477
54078
|
if (!fs27.existsSync(filePath)) {
|
|
52478
54079
|
const seed = emptyPersisted2();
|
|
52479
54080
|
try {
|
|
@@ -52509,7 +54110,7 @@ function writePersisted2(directory, persisted) {
|
|
|
52509
54110
|
let payload;
|
|
52510
54111
|
try {
|
|
52511
54112
|
ensureSwarmDir2(directory);
|
|
52512
|
-
filePath =
|
|
54113
|
+
filePath = path48.join(directory, ".swarm", STATE_FILE2);
|
|
52513
54114
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
52514
54115
|
persisted.updatedAt = nowISO2();
|
|
52515
54116
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -52636,10 +54237,10 @@ var init_context_budget_service = __esm(() => {
|
|
|
52636
54237
|
|
|
52637
54238
|
// src/services/status-service.ts
|
|
52638
54239
|
import * as fsSync2 from "fs";
|
|
52639
|
-
import * as
|
|
54240
|
+
import * as path49 from "path";
|
|
52640
54241
|
function readSpecStalenessSnapshot(directory) {
|
|
52641
54242
|
try {
|
|
52642
|
-
const p =
|
|
54243
|
+
const p = path49.join(directory, ".swarm", "spec-staleness.json");
|
|
52643
54244
|
if (!fsSync2.existsSync(p))
|
|
52644
54245
|
return { stale: false };
|
|
52645
54246
|
const raw = fsSync2.readFileSync(p, "utf-8");
|
|
@@ -53165,7 +54766,7 @@ var init_write_retro2 = __esm(() => {
|
|
|
53165
54766
|
|
|
53166
54767
|
// src/commands/command-dispatch.ts
|
|
53167
54768
|
import fs28 from "fs";
|
|
53168
|
-
import
|
|
54769
|
+
import path50 from "path";
|
|
53169
54770
|
function normalizeSwarmCommandInput(command, argumentText) {
|
|
53170
54771
|
if (command !== "swarm" && !command.startsWith("swarm-")) {
|
|
53171
54772
|
return { isSwarmCommand: false, tokens: [] };
|
|
@@ -53201,9 +54802,9 @@ ${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
|
|
|
53201
54802
|
`);
|
|
53202
54803
|
}
|
|
53203
54804
|
function maybeMarkFirstRun(directory) {
|
|
53204
|
-
const sentinelPath =
|
|
54805
|
+
const sentinelPath = path50.join(directory, ".swarm", ".first-run-complete");
|
|
53205
54806
|
try {
|
|
53206
|
-
const swarmDir =
|
|
54807
|
+
const swarmDir = path50.join(directory, ".swarm");
|
|
53207
54808
|
fs28.mkdirSync(swarmDir, { recursive: true });
|
|
53208
54809
|
fs28.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
|
|
53209
54810
|
`, { flag: "wx" });
|
|
@@ -53312,6 +54913,14 @@ function classifySwarmCommandToolUse(resolved) {
|
|
|
53312
54913
|
message: "Only `/swarm knowledge` and `/swarm knowledge list` are available through swarm_command. Knowledge migrate/quarantine/restore are intentionally excluded."
|
|
53313
54914
|
};
|
|
53314
54915
|
}
|
|
54916
|
+
if (canonicalKey === "memory") {
|
|
54917
|
+
if (args.length === 0)
|
|
54918
|
+
return { allowed: true };
|
|
54919
|
+
return {
|
|
54920
|
+
allowed: false,
|
|
54921
|
+
message: "Use `/swarm memory status` or `/swarm memory export` through swarm_command. Memory import and migrate are intentionally excluded from chat-tool execution."
|
|
54922
|
+
};
|
|
54923
|
+
}
|
|
53315
54924
|
if (canonicalKey === "retrieve") {
|
|
53316
54925
|
if (args.length !== 1 || !SUMMARY_ID_PATTERN.test(args[0])) {
|
|
53317
54926
|
return {
|
|
@@ -53363,10 +54972,10 @@ function classifySwarmCommandChatFallbackUse(resolved) {
|
|
|
53363
54972
|
message: "/swarm config doctor --fix is not available through chat fallback because it can modify configuration files. Run the CLI command directly when you intend to apply fixes."
|
|
53364
54973
|
};
|
|
53365
54974
|
}
|
|
53366
|
-
if (canonicalKey === "knowledge migrate" || canonicalKey === "knowledge quarantine" || canonicalKey === "knowledge restore") {
|
|
54975
|
+
if (canonicalKey === "knowledge migrate" || canonicalKey === "knowledge quarantine" || canonicalKey === "knowledge restore" || canonicalKey === "memory import" || canonicalKey === "memory migrate") {
|
|
53367
54976
|
return {
|
|
53368
54977
|
allowed: false,
|
|
53369
|
-
message: `/swarm ${canonicalKey} is not available through chat fallback because it mutates .swarm
|
|
54978
|
+
message: `/swarm ${canonicalKey} is not available through chat fallback because it mutates .swarm state. ` + "Run the CLI command directly after confirming the intended state change."
|
|
53370
54979
|
};
|
|
53371
54980
|
}
|
|
53372
54981
|
return { allowed: true };
|
|
@@ -53394,6 +55003,11 @@ var init_tool_policy = __esm(() => {
|
|
|
53394
55003
|
"preflight",
|
|
53395
55004
|
"benchmark",
|
|
53396
55005
|
"knowledge",
|
|
55006
|
+
"memory",
|
|
55007
|
+
"memory status",
|
|
55008
|
+
"memory export",
|
|
55009
|
+
"memory import",
|
|
55010
|
+
"memory migrate",
|
|
53397
55011
|
"sync-plan",
|
|
53398
55012
|
"export",
|
|
53399
55013
|
"list-agents"
|
|
@@ -53414,6 +55028,9 @@ var init_tool_policy = __esm(() => {
|
|
|
53414
55028
|
"preflight",
|
|
53415
55029
|
"benchmark",
|
|
53416
55030
|
"knowledge",
|
|
55031
|
+
"memory",
|
|
55032
|
+
"memory status",
|
|
55033
|
+
"memory export",
|
|
53417
55034
|
"sync-plan",
|
|
53418
55035
|
"export"
|
|
53419
55036
|
]);
|
|
@@ -53422,7 +55039,9 @@ var init_tool_policy = __esm(() => {
|
|
|
53422
55039
|
"reset",
|
|
53423
55040
|
"reset-session",
|
|
53424
55041
|
"rollback",
|
|
53425
|
-
"checkpoint"
|
|
55042
|
+
"checkpoint",
|
|
55043
|
+
"memory import",
|
|
55044
|
+
"memory migrate"
|
|
53426
55045
|
]);
|
|
53427
55046
|
NO_ARGS = new Set([
|
|
53428
55047
|
"agents",
|
|
@@ -53435,7 +55054,10 @@ var init_tool_policy = __esm(() => {
|
|
|
53435
55054
|
"diagnose",
|
|
53436
55055
|
"preflight",
|
|
53437
55056
|
"sync-plan",
|
|
53438
|
-
"export"
|
|
55057
|
+
"export",
|
|
55058
|
+
"memory",
|
|
55059
|
+
"memory status",
|
|
55060
|
+
"memory export"
|
|
53439
55061
|
]);
|
|
53440
55062
|
SUMMARY_ID_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
53441
55063
|
TASK_ID_PATTERN = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
@@ -53468,6 +55090,11 @@ __export(exports_commands, {
|
|
|
53468
55090
|
handlePromoteCommand: () => handlePromoteCommand,
|
|
53469
55091
|
handlePreflightCommand: () => handlePreflightCommand,
|
|
53470
55092
|
handlePlanCommand: () => handlePlanCommand,
|
|
55093
|
+
handleMemoryStatusCommand: () => handleMemoryStatusCommand,
|
|
55094
|
+
handleMemoryMigrateCommand: () => handleMemoryMigrateCommand,
|
|
55095
|
+
handleMemoryImportCommand: () => handleMemoryImportCommand,
|
|
55096
|
+
handleMemoryExportCommand: () => handleMemoryExportCommand,
|
|
55097
|
+
handleMemoryCommand: () => handleMemoryCommand,
|
|
53471
55098
|
handleKnowledgeRestoreCommand: () => handleKnowledgeRestoreCommand,
|
|
53472
55099
|
handleKnowledgeQuarantineCommand: () => handleKnowledgeQuarantineCommand,
|
|
53473
55100
|
handleKnowledgeMigrateCommand: () => handleKnowledgeMigrateCommand,
|
|
@@ -53745,6 +55372,7 @@ var init_commands = __esm(() => {
|
|
|
53745
55372
|
init_handoff();
|
|
53746
55373
|
init_history();
|
|
53747
55374
|
init_knowledge();
|
|
55375
|
+
init_memory2();
|
|
53748
55376
|
init_plan();
|
|
53749
55377
|
init_preflight();
|
|
53750
55378
|
init_promote();
|
|
@@ -53885,24 +55513,24 @@ function validateAliases() {
|
|
|
53885
55513
|
}
|
|
53886
55514
|
aliasTargets.get(target).push(name);
|
|
53887
55515
|
const visited = new Set;
|
|
53888
|
-
const
|
|
55516
|
+
const path51 = [];
|
|
53889
55517
|
let current = target;
|
|
53890
55518
|
while (current) {
|
|
53891
55519
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
53892
55520
|
if (!currentEntry)
|
|
53893
55521
|
break;
|
|
53894
55522
|
if (visited.has(current)) {
|
|
53895
|
-
const cycleStart =
|
|
55523
|
+
const cycleStart = path51.indexOf(current);
|
|
53896
55524
|
const fullChain = [
|
|
53897
55525
|
name,
|
|
53898
|
-
...
|
|
55526
|
+
...path51.slice(0, cycleStart > 0 ? cycleStart : path51.length),
|
|
53899
55527
|
current
|
|
53900
55528
|
].join(" \u2192 ");
|
|
53901
55529
|
errors5.push(`Circular alias detected: ${fullChain}`);
|
|
53902
55530
|
break;
|
|
53903
55531
|
}
|
|
53904
55532
|
visited.add(current);
|
|
53905
|
-
|
|
55533
|
+
path51.push(current);
|
|
53906
55534
|
current = currentEntry.aliasOf || "";
|
|
53907
55535
|
}
|
|
53908
55536
|
}
|
|
@@ -53965,6 +55593,7 @@ var init_registry = __esm(() => {
|
|
|
53965
55593
|
init_history();
|
|
53966
55594
|
init_issue();
|
|
53967
55595
|
init_knowledge();
|
|
55596
|
+
init_memory2();
|
|
53968
55597
|
init_plan();
|
|
53969
55598
|
init_pr_review();
|
|
53970
55599
|
init_preflight();
|
|
@@ -54375,6 +56004,39 @@ Subcommands:
|
|
|
54375
56004
|
description: "List knowledge entries",
|
|
54376
56005
|
category: "utility"
|
|
54377
56006
|
},
|
|
56007
|
+
memory: {
|
|
56008
|
+
handler: (ctx) => handleMemoryCommand(ctx.directory, ctx.args),
|
|
56009
|
+
description: "Show Swarm memory commands",
|
|
56010
|
+
category: "utility"
|
|
56011
|
+
},
|
|
56012
|
+
"memory status": {
|
|
56013
|
+
handler: (ctx) => handleMemoryStatusCommand(ctx.directory, ctx.args),
|
|
56014
|
+
description: "Show Swarm memory provider, JSONL, and migration status",
|
|
56015
|
+
subcommandOf: "memory",
|
|
56016
|
+
args: "",
|
|
56017
|
+
category: "diagnostics"
|
|
56018
|
+
},
|
|
56019
|
+
"memory export": {
|
|
56020
|
+
handler: (ctx) => handleMemoryExportCommand(ctx.directory, ctx.args),
|
|
56021
|
+
description: "Export current Swarm memory to JSONL files",
|
|
56022
|
+
subcommandOf: "memory",
|
|
56023
|
+
args: "",
|
|
56024
|
+
category: "utility"
|
|
56025
|
+
},
|
|
56026
|
+
"memory import": {
|
|
56027
|
+
handler: (ctx) => handleMemoryImportCommand(ctx.directory, ctx.args),
|
|
56028
|
+
description: "Import legacy JSONL memory into SQLite",
|
|
56029
|
+
subcommandOf: "memory",
|
|
56030
|
+
args: "",
|
|
56031
|
+
category: "utility"
|
|
56032
|
+
},
|
|
56033
|
+
"memory migrate": {
|
|
56034
|
+
handler: (ctx) => handleMemoryMigrateCommand(ctx.directory, ctx.args),
|
|
56035
|
+
description: "Run the one-time legacy JSONL to SQLite migration",
|
|
56036
|
+
subcommandOf: "memory",
|
|
56037
|
+
args: "",
|
|
56038
|
+
category: "utility"
|
|
56039
|
+
},
|
|
54378
56040
|
checkpoint: {
|
|
54379
56041
|
handler: (ctx) => handleCheckpointCommand(ctx.directory, ctx.args),
|
|
54380
56042
|
description: "Manage project checkpoints [save|restore|delete|list] <label>",
|
|
@@ -54413,53 +56075,53 @@ init_cache_paths();
|
|
|
54413
56075
|
init_constants();
|
|
54414
56076
|
import * as fs29 from "fs";
|
|
54415
56077
|
import * as os7 from "os";
|
|
54416
|
-
import * as
|
|
56078
|
+
import * as path51 from "path";
|
|
54417
56079
|
var { version: version4 } = package_default;
|
|
54418
56080
|
var CONFIG_DIR = getPluginConfigDir();
|
|
54419
|
-
var OPENCODE_CONFIG_PATH =
|
|
54420
|
-
var PLUGIN_CONFIG_PATH =
|
|
54421
|
-
var PROMPTS_DIR =
|
|
56081
|
+
var OPENCODE_CONFIG_PATH = path51.join(CONFIG_DIR, "opencode.json");
|
|
56082
|
+
var PLUGIN_CONFIG_PATH = path51.join(CONFIG_DIR, "opencode-swarm.json");
|
|
56083
|
+
var PROMPTS_DIR = path51.join(CONFIG_DIR, "opencode-swarm");
|
|
54422
56084
|
var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
54423
56085
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
54424
56086
|
function isSafeCachePath(p) {
|
|
54425
|
-
const resolved =
|
|
54426
|
-
const home =
|
|
56087
|
+
const resolved = path51.resolve(p);
|
|
56088
|
+
const home = path51.resolve(os7.homedir());
|
|
54427
56089
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
54428
56090
|
return false;
|
|
54429
56091
|
}
|
|
54430
|
-
const segments = resolved.split(
|
|
56092
|
+
const segments = resolved.split(path51.sep).filter((s) => s.length > 0);
|
|
54431
56093
|
if (segments.length < 4) {
|
|
54432
56094
|
return false;
|
|
54433
56095
|
}
|
|
54434
|
-
const leaf =
|
|
56096
|
+
const leaf = path51.basename(resolved);
|
|
54435
56097
|
if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
|
|
54436
56098
|
return false;
|
|
54437
56099
|
}
|
|
54438
|
-
const parent =
|
|
56100
|
+
const parent = path51.basename(path51.dirname(resolved));
|
|
54439
56101
|
if (parent !== "packages" && parent !== "node_modules") {
|
|
54440
56102
|
return false;
|
|
54441
56103
|
}
|
|
54442
|
-
const grandparent =
|
|
56104
|
+
const grandparent = path51.basename(path51.dirname(path51.dirname(resolved)));
|
|
54443
56105
|
if (grandparent !== "opencode") {
|
|
54444
56106
|
return false;
|
|
54445
56107
|
}
|
|
54446
56108
|
return true;
|
|
54447
56109
|
}
|
|
54448
56110
|
function isSafeLockFilePath(p) {
|
|
54449
|
-
const resolved =
|
|
54450
|
-
const home =
|
|
56111
|
+
const resolved = path51.resolve(p);
|
|
56112
|
+
const home = path51.resolve(os7.homedir());
|
|
54451
56113
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
54452
56114
|
return false;
|
|
54453
56115
|
}
|
|
54454
|
-
const segments = resolved.split(
|
|
56116
|
+
const segments = resolved.split(path51.sep).filter((s) => s.length > 0);
|
|
54455
56117
|
if (segments.length < 4) {
|
|
54456
56118
|
return false;
|
|
54457
56119
|
}
|
|
54458
|
-
const leaf =
|
|
56120
|
+
const leaf = path51.basename(resolved);
|
|
54459
56121
|
if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
|
|
54460
56122
|
return false;
|
|
54461
56123
|
}
|
|
54462
|
-
const parent =
|
|
56124
|
+
const parent = path51.basename(path51.dirname(resolved));
|
|
54463
56125
|
if (parent !== "opencode") {
|
|
54464
56126
|
return false;
|
|
54465
56127
|
}
|
|
@@ -54485,8 +56147,8 @@ function saveJson(filepath, data) {
|
|
|
54485
56147
|
}
|
|
54486
56148
|
function writeProjectConfigIfMissing(cwd) {
|
|
54487
56149
|
try {
|
|
54488
|
-
const opencodeDir =
|
|
54489
|
-
const projectConfigPath =
|
|
56150
|
+
const opencodeDir = path51.join(cwd, ".opencode");
|
|
56151
|
+
const projectConfigPath = path51.join(opencodeDir, "opencode-swarm.json");
|
|
54490
56152
|
if (fs29.existsSync(projectConfigPath)) {
|
|
54491
56153
|
return;
|
|
54492
56154
|
}
|
|
@@ -54503,7 +56165,7 @@ async function install() {
|
|
|
54503
56165
|
`);
|
|
54504
56166
|
ensureDir(CONFIG_DIR);
|
|
54505
56167
|
ensureDir(PROMPTS_DIR);
|
|
54506
|
-
const LEGACY_CONFIG_PATH =
|
|
56168
|
+
const LEGACY_CONFIG_PATH = path51.join(CONFIG_DIR, "config.json");
|
|
54507
56169
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
54508
56170
|
if (!opencodeConfig) {
|
|
54509
56171
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|