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/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.33.1",
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("local-jsonl"),
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 fileArray = Array.from(files).sort();
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 path29 from "path";
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 = path29.join(projectDir, "node_modules", ".bin");
45665
- const biomeBin = isWindows ? path29.join(binDir, "biome.EXE") : path29.join(binDir, "biome");
45666
- const eslintBin = isWindows ? path29.join(binDir, "eslint.cmd") : path29.join(binDir, "eslint");
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(path29.join(cwd, gradlewName)) ? path29.join(cwd, gradlewName) : null;
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(path29.join(cwd, "ruff.toml")))
47317
+ if (fs12.existsSync(path32.join(cwd, "ruff.toml")))
45717
47318
  return isCommandAvailable("ruff");
45718
47319
  try {
45719
- const pyproject = path29.join(cwd, "pyproject.toml");
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(path29.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
47330
+ return fs12.existsSync(path32.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
45730
47331
  }
45731
47332
  function detectGolangciLint(cwd) {
45732
- return fs12.existsSync(path29.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
47333
+ return fs12.existsSync(path32.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
45733
47334
  }
45734
47335
  function detectCheckstyle(cwd) {
45735
- const hasMaven = fs12.existsSync(path29.join(cwd, "pom.xml"));
45736
- const hasGradle = fs12.existsSync(path29.join(cwd, "build.gradle")) || fs12.existsSync(path29.join(cwd, "build.gradle.kts"));
45737
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path29.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
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(path29.join(cwd, "build.gradle.kts")) || fs12.existsSync(path29.join(cwd, "build.gradle")) || (() => {
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(path29.join(cwd, "CMakeLists.txt"))) {
47361
+ if (fs12.existsSync(path32.join(cwd, "CMakeLists.txt"))) {
45761
47362
  return isCommandAvailable("cppcheck");
45762
47363
  }
45763
47364
  try {
45764
- const dirsToCheck = [cwd, path29.join(cwd, "src")];
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(path29.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
47379
+ return fs12.existsSync(path32.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
45779
47380
  }
45780
47381
  function detectDartAnalyze(cwd) {
45781
- return fs12.existsSync(path29.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
47382
+ return fs12.existsSync(path32.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
45782
47383
  }
45783
47384
  function detectRubocop(cwd) {
45784
- return (fs12.existsSync(path29.join(cwd, "Gemfile")) || fs12.existsSync(path29.join(cwd, "gems.rb")) || fs12.existsSync(path29.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
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 = path29.join(dir, "node_modules", ".bin", binName);
47413
+ const candidate = path32.join(dir, "node_modules", ".bin", binName);
45813
47414
  if (fs12.existsSync(candidate))
45814
47415
  return candidate;
45815
- const parent = path29.dirname(dir);
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(path29.delimiter)) {
47425
+ for (const dir of searchPath.split(path32.delimiter)) {
45825
47426
  if (!dir)
45826
47427
  continue;
45827
- const candidate = path29.join(dir, binName);
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 ? path29.join(projectDir, "node_modules", ".bin", "biome.EXE") : path29.join(projectDir, "node_modules", ".bin", "biome");
45841
- const eslintBin = isWindows ? path29.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path29.join(projectDir, "node_modules", ".bin", "eslint");
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(path29.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
45846
- const eslintAncestor = findBinInAncestors(path29.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
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 path30 from "path";
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 = path30.join(scanDir, ".secretscanignore");
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 (path30.matchesGlob(relPath, pattern))
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 = path30.extname(filePath).toLowerCase();
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 SECRET_PATTERNS) {
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 = path30.resolve(scanDir);
46298
- const resolvedRealPath = path30.resolve(realPath);
46299
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path30.sep) || resolvedRealPath.startsWith(`${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 = path30.join(dir, entry);
46326
- const relPath = path30.relative(scanDir, fullPath).replace(/\\/g, "/");
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 = path30.extname(fullPath).toLowerCase();
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, SECRET_PATTERNS, O_NOFOLLOW, secretscan, _internals20;
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
- SECRET_PATTERNS = [
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 = path30.resolve(directory);
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 stat3 = fs13.statSync(filePath);
46692
- if (stat3.size > MAX_FILE_SIZE_BYTES) {
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 path31 from "path";
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(path31.join(dir, pattern));
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(path31.join(dir, "gradlew.bat"));
46909
- const hasGradlew = fs14.existsSync(path31.join(dir, "gradlew"));
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(path31.join(dir, d, "CMakeCache.txt"))) ?? "build";
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 = path31.extname(sourceFile);
48814
+ const ext = path34.extname(sourceFile);
47214
48815
  if (!profile.extensions.includes(ext))
47215
48816
  return [];
47216
- const base = path31.basename(sourceFile, ext);
47217
- const rel = path31.relative(dir, sourceFile);
47218
- const relDir = path31.dirname(rel);
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(path31.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
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 path32 from "path";
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(path32.join(dir, "go.mod"), "utf-8");
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(path32.join(dir, "main.go"));
48912
+ fs15.accessSync(path35.join(dir, "main.go"));
47312
48913
  points.push("main.go");
47313
48914
  } catch {}
47314
48915
  try {
47315
- const cmdDir = path32.join(dir, "cmd");
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 = path32.join("cmd", sub.name, "main.go");
48919
+ const main = path35.join("cmd", sub.name, "main.go");
47319
48920
  try {
47320
- fs15.accessSync(path32.join(dir, main));
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 path33 from "path";
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(path33.join(dir, candidate), "utf-8");
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(path33.join(dir, "pyproject.toml"), "utf-8");
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(path33.join(dir, name));
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 path34 from "path";
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 stat3 = fs17.statSync(sourcePath);
47477
- if (stat3.mtimeMs > generatedAtMs) {
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 = path34.resolve(fromDir, importPath);
47491
- if (path34.extname(resolved)) {
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 = path34.dirname(baseDir);
49112
+ baseDir = path37.dirname(baseDir);
47512
49113
  }
47513
49114
  const rest = module.slice(leadingDots);
47514
49115
  if (rest.length === 0) {
47515
- const initPath = path34.join(baseDir, "__init__.py");
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, path34.sep);
49122
+ const subpath = rest.replace(/\./g, path37.sep);
47522
49123
  const candidates = [
47523
- `${path34.join(baseDir, subpath)}.py`,
47524
- path34.join(baseDir, subpath, "__init__.py")
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 = path34.resolve(fromDir);
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 = path34.join(cur, "go.mod");
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(path34.join(cur, ".git"));
49157
+ fs17.accessSync(path37.join(cur, ".git"));
47557
49158
  break;
47558
49159
  } catch {}
47559
- const parent = path34.dirname(cur);
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 = path34.resolve(fromDir, importPath);
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 = path34.join(mod.moduleRoot, subpath);
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(path34.join(dir, f)));
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(path34.join(dir, entry.name), visitedInodes);
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(`${path34.sep}tests${path34.sep}`) && name.endsWith(".py");
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(path34.join(dir, entry.name)));
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 = path34.extname(testFile).toLowerCase();
47657
- const testDir = path34.dirname(testFile);
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 = path34.join(cwd, ".swarm", "cache", "impact-map.json");
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 (!path34.isAbsolute(cwd)) {
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 = path34.join(cwd, ".swarm", "cache");
47754
- const cachePath = path34.join(cacheDir2, "impact-map.json");
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(path34.resolve(changedFile));
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 path35 from "path";
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 (!path35.isAbsolute(workingDir)) {
49685
+ if (!path38.isAbsolute(workingDir)) {
48085
49686
  throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
48086
49687
  }
48087
- return path35.join(workingDir, ".swarm", "cache", "test-history.jsonl");
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 = path35.dirname(historyPath);
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 path36 from "path";
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 = path36.normalize(workingDirectory);
48291
- const pathParts = normalizedDir.split(path36.sep);
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 = path36.resolve(normalizedDir);
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 = path36.resolve(fallbackDirectory);
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 + path36.sep);
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 path37 from "path";
49980
+ import * as path40 from "path";
48380
49981
  function readPackageJsonRaw(dir) {
48381
49982
  try {
48382
- const content = fs20.readFileSync(path37.join(dir, "package.json"), "utf-8");
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 path38 from "path";
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 stat3 = fs21.statSync(path38.join(dir, name));
48620
- parts.push(`${name}:${stat3.size}:${stat3.mtimeMs}:${stat3.ino}`);
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 = path38.resolve(start);
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 = path38.dirname(cur);
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 path39 from "path";
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 = path39.resolve(cwd, sourceFile);
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(path39.join(cwd, "go.mod")) && isCommandAvailable("go");
50440
+ return fs22.existsSync(path42.join(cwd, "go.mod")) && isCommandAvailable("go");
48840
50441
  }
48841
50442
  function detectJavaMaven(cwd) {
48842
- return fs22.existsSync(path39.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
50443
+ return fs22.existsSync(path42.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
48843
50444
  }
48844
50445
  function detectGradle(cwd) {
48845
- const hasBuildFile = fs22.existsSync(path39.join(cwd, "build.gradle")) || fs22.existsSync(path39.join(cwd, "build.gradle.kts"));
48846
- const hasGradlew = fs22.existsSync(path39.join(cwd, "gradlew")) || fs22.existsSync(path39.join(cwd, "gradlew.bat"));
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(path39.join(cwd, "CMakeLists.txt"));
48860
- const hasBuildCache = fs22.existsSync(path39.join(cwd, "CMakeCache.txt")) || fs22.existsSync(path39.join(cwd, "build", "CMakeCache.txt"));
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(path39.join(cwd, "Package.swift")) && isCommandAvailable("swift");
50465
+ return fs22.existsSync(path42.join(cwd, "Package.swift")) && isCommandAvailable("swift");
48865
50466
  }
48866
50467
  function detectDartTest(cwd) {
48867
- return fs22.existsSync(path39.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
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(path39.join(cwd, ".rspec"));
48871
- const hasGemfile = fs22.existsSync(path39.join(cwd, "Gemfile"));
48872
- const hasSpecDir = fs22.existsSync(path39.join(cwd, "spec"));
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(path39.join(cwd, "test")) && (fs22.existsSync(path39.join(cwd, "Gemfile")) || fs22.existsSync(path39.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
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 = path39.join(baseDir, "package.json");
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(path39.join(baseDir, "bun.lockb")) || fs22.existsSync(path39.join(baseDir, "bun.lock"))) {
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 = path39.join(baseDir, "pyproject.toml");
48968
- const setupCfgPath = path39.join(baseDir, "setup.cfg");
48969
- const requirementsTxtPath = path39.join(baseDir, "requirements.txt");
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 = path39.join(baseDir, "Cargo.toml");
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 = path39.join(baseDir, "pester.config.ps1");
49001
- const pesterConfigJsonPath = path39.join(baseDir, "pester.config.ps1.json");
49002
- const pesterPs1Path = path39.join(baseDir, "tests.ps1");
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 path39.isAbsolute(file3) ? path39.resolve(file3) : path39.resolve(workingDir, file3);
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 path39.relative(workingDir, absolutePath);
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 = path39.dirname(relativePath);
50674
+ const relativeDir = path42.dirname(relativePath);
49074
50675
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
49075
50676
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
49076
- const rootDir = path39.join(workingDir, dirName);
49077
- return nestedRelativeDir ? [rootDir, path39.join(rootDir, 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(path39.join(workingDir, "src/test/java", path39.dirname(normalizedRelativePath.slice("src/main/java/".length))));
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(path39.join(workingDir, "src/test/kotlin", path39.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
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 = path39.basename(filePath);
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 = path39.relative(workingDir, absoluteFile);
49120
- const basename6 = path39.basename(absoluteFile);
49121
- const dirname17 = path39.dirname(absoluteFile);
49122
- const preferRelativeOutput = !path39.isAbsolute(file3);
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 = path39.extname(basename6);
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) => path39.join(dirname17, 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) => path39.join(dirname17, dirName, candidateName))),
49147
- ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path39.join(candidateDir, 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 = path39.dirname(absoluteTestFile);
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 = path39.resolve(testDir, importPath);
49177
- const existingExt = path39.extname(resolvedImport);
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 = path39.basename(resolvedImport, path39.extname(resolvedImport));
49198
- const importDir = path39.dirname(resolvedImport);
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 = path39.dirname(sourceFile);
49201
- const sourceBasename = path39.basename(sourceFile, path39.extname(sourceFile));
49202
- const isRelatedDir = importDir === sourceDir || importDir === path39.join(sourceDir, "__tests__") || importDir === path39.join(sourceDir, "tests") || importDir === path39.join(sourceDir, "test") || importDir === path39.join(sourceDir, "spec");
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 = path39.resolve(testDir, importPath);
49216
- const existingExt = path39.extname(resolvedImport);
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 = path39.dirname(resolvedImport);
49234
- const importBasename = path39.basename(resolvedImport, path39.extname(resolvedImport));
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 = path39.dirname(sourceFile);
49237
- const sourceBasename = path39.basename(sourceFile, path39.extname(sourceFile));
49238
- const isRelatedDir = importDir === sourceDir || importDir === path39.join(sourceDir, "__tests__") || importDir === path39.join(sourceDir, "tests") || importDir === path39.join(sourceDir, "test") || importDir === path39.join(sourceDir, "spec");
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(path39.join(baseDir, "gradlew.bat"));
49349
- const hasGradlew = fs22.existsSync(path39.join(baseDir, "gradlew"));
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(path39.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
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" ? path39.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
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(path39.dirname(vitestJsonOutputPath), { recursive: true });
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 (!path39.isAbsolute(testFile))
51519
+ if (!path42.isAbsolute(testFile))
49919
51520
  return normalized;
49920
- const relative9 = path39.relative(workingDir, testFile);
49921
- if (relative9.startsWith("..") || path39.isAbsolute(relative9)) {
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 = path39.extname(file3).toLowerCase();
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 = path39.extname(f).toLowerCase();
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 = path39.extname(f).toLowerCase();
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 = path39.relative(workingDir, absPath);
50408
- return path39.isAbsolute(relativePath) ? absPath : relativePath;
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 path40 from "path";
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 = path40.normalize(dir);
50493
- const absolutePath = path40.isAbsolute(normalized) ? normalized : path40.resolve(normalized);
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 = path40.join(dir, "package.json");
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 = path40.join(dir, "CHANGELOG.md");
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 = path40.join(dir, file3);
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 = path40.join(dir, ".swarm", "spec.md");
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 path41 from "path";
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 = path41.join(directory, filename);
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 path42 from "path";
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 = path42.dirname(validateSwarmPath(directory, "session/state.json"));
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 = path42.join(sessionDir, file3);
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 path43 from "path";
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 = path43.join("summaries", `${sanitizedId}.json`);
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 path44 from "path";
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 = path44.join(checkpointDir, file3);
52286
- const dest = path44.join(swarmDir, file3);
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 = path44.join(swarmDir, "plan-ledger.jsonl");
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 = path44.join(swarmDir, "plan.json");
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 path45 = await import("path");
52402
- const reportPath = path45.join(directory, ".swarm", "simulate-report.md");
52403
- await fs27.mkdir(path45.dirname(reportPath), { recursive: true });
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 path45 from "path";
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 = path45.resolve(directory, ".swarm");
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 = path45.join(directory, ".swarm", STATE_FILE2);
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 = path45.join(directory, ".swarm", STATE_FILE2);
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 path46 from "path";
54240
+ import * as path49 from "path";
52640
54241
  function readSpecStalenessSnapshot(directory) {
52641
54242
  try {
52642
- const p = path46.join(directory, ".swarm", "spec-staleness.json");
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 path47 from "path";
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 = path47.join(directory, ".swarm", ".first-run-complete");
54805
+ const sentinelPath = path50.join(directory, ".swarm", ".first-run-complete");
53205
54806
  try {
53206
- const swarmDir = path47.join(directory, ".swarm");
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 knowledge state. ` + "Run the CLI command directly after confirming the intended state change."
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 path48 = [];
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 = path48.indexOf(current);
55523
+ const cycleStart = path51.indexOf(current);
53896
55524
  const fullChain = [
53897
55525
  name,
53898
- ...path48.slice(0, cycleStart > 0 ? cycleStart : path48.length),
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
- path48.push(current);
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 path48 from "path";
56078
+ import * as path51 from "path";
54417
56079
  var { version: version4 } = package_default;
54418
56080
  var CONFIG_DIR = getPluginConfigDir();
54419
- var OPENCODE_CONFIG_PATH = path48.join(CONFIG_DIR, "opencode.json");
54420
- var PLUGIN_CONFIG_PATH = path48.join(CONFIG_DIR, "opencode-swarm.json");
54421
- var PROMPTS_DIR = path48.join(CONFIG_DIR, "opencode-swarm");
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 = path48.resolve(p);
54426
- const home = path48.resolve(os7.homedir());
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(path48.sep).filter((s) => s.length > 0);
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 = path48.basename(resolved);
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 = path48.basename(path48.dirname(resolved));
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 = path48.basename(path48.dirname(path48.dirname(resolved)));
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 = path48.resolve(p);
54450
- const home = path48.resolve(os7.homedir());
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(path48.sep).filter((s) => s.length > 0);
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 = path48.basename(resolved);
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 = path48.basename(path48.dirname(resolved));
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 = path48.join(cwd, ".opencode");
54489
- const projectConfigPath = path48.join(opencodeDir, "opencode-swarm.json");
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 = path48.join(CONFIG_DIR, "config.json");
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);