opencode-swarm 7.33.2 → 7.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/cli/index.js +1891 -232
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/memory.d.ts +5 -0
- package/dist/commands/registry.d.ts +33 -0
- package/dist/commands/tool-policy.d.ts +1 -1
- package/dist/index.js +32134 -31540
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/jsonl-migration.d.ts +47 -0
- package/dist/memory/sqlite-provider.d.ts +21 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.
|
|
37
|
+
version: "7.35.0",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -17601,7 +17601,7 @@ var init_schema = __esm(() => {
|
|
|
17601
17601
|
});
|
|
17602
17602
|
MemoryConfigSchema = exports_external.object({
|
|
17603
17603
|
enabled: exports_external.boolean().default(false),
|
|
17604
|
-
provider: exports_external.enum(["local-jsonl", "sqlite"]).default("
|
|
17604
|
+
provider: exports_external.enum(["local-jsonl", "sqlite"]).default("sqlite"),
|
|
17605
17605
|
storageDir: exports_external.string().default(".swarm/memory"),
|
|
17606
17606
|
sqlite: exports_external.object({
|
|
17607
17607
|
path: exports_external.string().default(".swarm/memory/memory.db"),
|
|
@@ -45268,6 +45268,1604 @@ var init_knowledge = __esm(() => {
|
|
|
45268
45268
|
init_knowledge_validator();
|
|
45269
45269
|
});
|
|
45270
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
|
+
|
|
45271
46869
|
// src/services/plan-service.ts
|
|
45272
46870
|
async function getPlanData(directory, phaseArg) {
|
|
45273
46871
|
const plan = await _internals18.loadPlanJsonOnly(directory);
|
|
@@ -45653,7 +47251,7 @@ var init_path_security = () => {};
|
|
|
45653
47251
|
|
|
45654
47252
|
// src/tools/lint.ts
|
|
45655
47253
|
import * as fs12 from "fs";
|
|
45656
|
-
import * as
|
|
47254
|
+
import * as path32 from "path";
|
|
45657
47255
|
function validateArgs(args) {
|
|
45658
47256
|
if (typeof args !== "object" || args === null)
|
|
45659
47257
|
return false;
|
|
@@ -45664,9 +47262,9 @@ function validateArgs(args) {
|
|
|
45664
47262
|
}
|
|
45665
47263
|
function getLinterCommand(linter, mode, projectDir) {
|
|
45666
47264
|
const isWindows = process.platform === "win32";
|
|
45667
|
-
const binDir =
|
|
45668
|
-
const biomeBin = isWindows ?
|
|
45669
|
-
const eslintBin = isWindows ?
|
|
47265
|
+
const binDir = path32.join(projectDir, "node_modules", ".bin");
|
|
47266
|
+
const biomeBin = isWindows ? path32.join(binDir, "biome.EXE") : path32.join(binDir, "biome");
|
|
47267
|
+
const eslintBin = isWindows ? path32.join(binDir, "eslint.cmd") : path32.join(binDir, "eslint");
|
|
45670
47268
|
switch (linter) {
|
|
45671
47269
|
case "biome":
|
|
45672
47270
|
if (mode === "fix") {
|
|
@@ -45682,7 +47280,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
45682
47280
|
}
|
|
45683
47281
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
45684
47282
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
45685
|
-
const gradlew = fs12.existsSync(
|
|
47283
|
+
const gradlew = fs12.existsSync(path32.join(cwd, gradlewName)) ? path32.join(cwd, gradlewName) : null;
|
|
45686
47284
|
switch (linter) {
|
|
45687
47285
|
case "ruff":
|
|
45688
47286
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -45716,10 +47314,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
45716
47314
|
}
|
|
45717
47315
|
}
|
|
45718
47316
|
function detectRuff(cwd) {
|
|
45719
|
-
if (fs12.existsSync(
|
|
47317
|
+
if (fs12.existsSync(path32.join(cwd, "ruff.toml")))
|
|
45720
47318
|
return isCommandAvailable("ruff");
|
|
45721
47319
|
try {
|
|
45722
|
-
const pyproject =
|
|
47320
|
+
const pyproject = path32.join(cwd, "pyproject.toml");
|
|
45723
47321
|
if (fs12.existsSync(pyproject)) {
|
|
45724
47322
|
const content = fs12.readFileSync(pyproject, "utf-8");
|
|
45725
47323
|
if (content.includes("[tool.ruff]"))
|
|
@@ -45729,19 +47327,19 @@ function detectRuff(cwd) {
|
|
|
45729
47327
|
return false;
|
|
45730
47328
|
}
|
|
45731
47329
|
function detectClippy(cwd) {
|
|
45732
|
-
return fs12.existsSync(
|
|
47330
|
+
return fs12.existsSync(path32.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
45733
47331
|
}
|
|
45734
47332
|
function detectGolangciLint(cwd) {
|
|
45735
|
-
return fs12.existsSync(
|
|
47333
|
+
return fs12.existsSync(path32.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
45736
47334
|
}
|
|
45737
47335
|
function detectCheckstyle(cwd) {
|
|
45738
|
-
const hasMaven = fs12.existsSync(
|
|
45739
|
-
const hasGradle = fs12.existsSync(
|
|
45740
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(
|
|
47336
|
+
const hasMaven = fs12.existsSync(path32.join(cwd, "pom.xml"));
|
|
47337
|
+
const hasGradle = fs12.existsSync(path32.join(cwd, "build.gradle")) || fs12.existsSync(path32.join(cwd, "build.gradle.kts"));
|
|
47338
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path32.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
45741
47339
|
return (hasMaven || hasGradle) && hasBinary;
|
|
45742
47340
|
}
|
|
45743
47341
|
function detectKtlint(cwd) {
|
|
45744
|
-
const hasKotlin = fs12.existsSync(
|
|
47342
|
+
const hasKotlin = fs12.existsSync(path32.join(cwd, "build.gradle.kts")) || fs12.existsSync(path32.join(cwd, "build.gradle")) || (() => {
|
|
45745
47343
|
try {
|
|
45746
47344
|
return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
45747
47345
|
} catch {
|
|
@@ -45760,11 +47358,11 @@ function detectDotnetFormat(cwd) {
|
|
|
45760
47358
|
}
|
|
45761
47359
|
}
|
|
45762
47360
|
function detectCppcheck(cwd) {
|
|
45763
|
-
if (fs12.existsSync(
|
|
47361
|
+
if (fs12.existsSync(path32.join(cwd, "CMakeLists.txt"))) {
|
|
45764
47362
|
return isCommandAvailable("cppcheck");
|
|
45765
47363
|
}
|
|
45766
47364
|
try {
|
|
45767
|
-
const dirsToCheck = [cwd,
|
|
47365
|
+
const dirsToCheck = [cwd, path32.join(cwd, "src")];
|
|
45768
47366
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
45769
47367
|
try {
|
|
45770
47368
|
return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -45778,13 +47376,13 @@ function detectCppcheck(cwd) {
|
|
|
45778
47376
|
}
|
|
45779
47377
|
}
|
|
45780
47378
|
function detectSwiftlint(cwd) {
|
|
45781
|
-
return fs12.existsSync(
|
|
47379
|
+
return fs12.existsSync(path32.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
45782
47380
|
}
|
|
45783
47381
|
function detectDartAnalyze(cwd) {
|
|
45784
|
-
return fs12.existsSync(
|
|
47382
|
+
return fs12.existsSync(path32.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
45785
47383
|
}
|
|
45786
47384
|
function detectRubocop(cwd) {
|
|
45787
|
-
return (fs12.existsSync(
|
|
47385
|
+
return (fs12.existsSync(path32.join(cwd, "Gemfile")) || fs12.existsSync(path32.join(cwd, "gems.rb")) || fs12.existsSync(path32.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
45788
47386
|
}
|
|
45789
47387
|
function detectAdditionalLinter(cwd) {
|
|
45790
47388
|
if (detectRuff(cwd))
|
|
@@ -45812,10 +47410,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
45812
47410
|
function findBinInAncestors(startDir, binName) {
|
|
45813
47411
|
let dir = startDir;
|
|
45814
47412
|
while (true) {
|
|
45815
|
-
const candidate =
|
|
47413
|
+
const candidate = path32.join(dir, "node_modules", ".bin", binName);
|
|
45816
47414
|
if (fs12.existsSync(candidate))
|
|
45817
47415
|
return candidate;
|
|
45818
|
-
const parent =
|
|
47416
|
+
const parent = path32.dirname(dir);
|
|
45819
47417
|
if (parent === dir)
|
|
45820
47418
|
break;
|
|
45821
47419
|
dir = parent;
|
|
@@ -45824,10 +47422,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
45824
47422
|
}
|
|
45825
47423
|
function findBinInEnvPath(binName) {
|
|
45826
47424
|
const searchPath = process.env.PATH ?? "";
|
|
45827
|
-
for (const dir of searchPath.split(
|
|
47425
|
+
for (const dir of searchPath.split(path32.delimiter)) {
|
|
45828
47426
|
if (!dir)
|
|
45829
47427
|
continue;
|
|
45830
|
-
const candidate =
|
|
47428
|
+
const candidate = path32.join(dir, binName);
|
|
45831
47429
|
if (fs12.existsSync(candidate))
|
|
45832
47430
|
return candidate;
|
|
45833
47431
|
}
|
|
@@ -45840,13 +47438,13 @@ async function detectAvailableLinter(directory) {
|
|
|
45840
47438
|
return null;
|
|
45841
47439
|
const projectDir = directory;
|
|
45842
47440
|
const isWindows = process.platform === "win32";
|
|
45843
|
-
const biomeBin = isWindows ?
|
|
45844
|
-
const eslintBin = isWindows ?
|
|
47441
|
+
const biomeBin = isWindows ? path32.join(projectDir, "node_modules", ".bin", "biome.EXE") : path32.join(projectDir, "node_modules", ".bin", "biome");
|
|
47442
|
+
const eslintBin = isWindows ? path32.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path32.join(projectDir, "node_modules", ".bin", "eslint");
|
|
45845
47443
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
45846
47444
|
if (localResult)
|
|
45847
47445
|
return localResult;
|
|
45848
|
-
const biomeAncestor = findBinInAncestors(
|
|
45849
|
-
const eslintAncestor = findBinInAncestors(
|
|
47446
|
+
const biomeAncestor = findBinInAncestors(path32.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
47447
|
+
const eslintAncestor = findBinInAncestors(path32.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
45850
47448
|
if (biomeAncestor || eslintAncestor) {
|
|
45851
47449
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
45852
47450
|
}
|
|
@@ -46069,7 +47667,7 @@ For Rust: rustup component add clippy`
|
|
|
46069
47667
|
|
|
46070
47668
|
// src/tools/secretscan.ts
|
|
46071
47669
|
import * as fs13 from "fs";
|
|
46072
|
-
import * as
|
|
47670
|
+
import * as path33 from "path";
|
|
46073
47671
|
function calculateShannonEntropy(str) {
|
|
46074
47672
|
if (str.length === 0)
|
|
46075
47673
|
return 0;
|
|
@@ -46117,7 +47715,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
46117
47715
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
46118
47716
|
}
|
|
46119
47717
|
function loadSecretScanIgnore(scanDir) {
|
|
46120
|
-
const ignorePath =
|
|
47718
|
+
const ignorePath = path33.join(scanDir, ".secretscanignore");
|
|
46121
47719
|
try {
|
|
46122
47720
|
if (!fs13.existsSync(ignorePath))
|
|
46123
47721
|
return [];
|
|
@@ -46140,7 +47738,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
46140
47738
|
if (exactNames.has(entry))
|
|
46141
47739
|
return true;
|
|
46142
47740
|
for (const pattern of globPatterns) {
|
|
46143
|
-
if (
|
|
47741
|
+
if (path33.matchesGlob(relPath, pattern))
|
|
46144
47742
|
return true;
|
|
46145
47743
|
}
|
|
46146
47744
|
return false;
|
|
@@ -46161,7 +47759,7 @@ function validateDirectoryInput(dir) {
|
|
|
46161
47759
|
return null;
|
|
46162
47760
|
}
|
|
46163
47761
|
function isBinaryFile(filePath, buffer) {
|
|
46164
|
-
const ext =
|
|
47762
|
+
const ext = path33.extname(filePath).toLowerCase();
|
|
46165
47763
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
46166
47764
|
return true;
|
|
46167
47765
|
}
|
|
@@ -46186,7 +47784,7 @@ function scanLineForSecrets(line, _lineNum) {
|
|
|
46186
47784
|
if (line.length > MAX_LINE_LENGTH) {
|
|
46187
47785
|
return results;
|
|
46188
47786
|
}
|
|
46189
|
-
for (const pattern of
|
|
47787
|
+
for (const pattern of SECRET_PATTERNS2) {
|
|
46190
47788
|
pattern.regex.lastIndex = 0;
|
|
46191
47789
|
for (let match = pattern.regex.exec(line);match !== null; match = pattern.regex.exec(line)) {
|
|
46192
47790
|
const fullMatch = match[0];
|
|
@@ -46297,9 +47895,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
46297
47895
|
return false;
|
|
46298
47896
|
}
|
|
46299
47897
|
function isPathWithinScope(realPath, scanDir) {
|
|
46300
|
-
const resolvedScanDir =
|
|
46301
|
-
const resolvedRealPath =
|
|
46302
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
47898
|
+
const resolvedScanDir = path33.resolve(scanDir);
|
|
47899
|
+
const resolvedRealPath = path33.resolve(realPath);
|
|
47900
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path33.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
46303
47901
|
}
|
|
46304
47902
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
46305
47903
|
skippedDirs: 0,
|
|
@@ -46325,8 +47923,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
46325
47923
|
return a.localeCompare(b);
|
|
46326
47924
|
});
|
|
46327
47925
|
for (const entry of entries) {
|
|
46328
|
-
const fullPath =
|
|
46329
|
-
const relPath =
|
|
47926
|
+
const fullPath = path33.join(dir, entry);
|
|
47927
|
+
const relPath = path33.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
46330
47928
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
46331
47929
|
stats.skippedDirs++;
|
|
46332
47930
|
continue;
|
|
@@ -46361,7 +47959,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
46361
47959
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
46362
47960
|
files.push(...subFiles);
|
|
46363
47961
|
} else if (lstat.isFile()) {
|
|
46364
|
-
const ext =
|
|
47962
|
+
const ext = path33.extname(fullPath).toLowerCase();
|
|
46365
47963
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
46366
47964
|
files.push(fullPath);
|
|
46367
47965
|
} else {
|
|
@@ -46388,7 +47986,7 @@ async function runSecretscan(directory) {
|
|
|
46388
47986
|
return errorResult;
|
|
46389
47987
|
}
|
|
46390
47988
|
}
|
|
46391
|
-
var MAX_FILE_PATH_LENGTH = 500, MAX_FILE_SIZE_BYTES, MAX_FILES_SCANNED = 1000, MAX_FINDINGS = 100, MAX_OUTPUT_BYTES2 = 512000, MAX_LINE_LENGTH = 1e4, MAX_CONTENT_BYTES, BINARY_SIGNATURES, BINARY_PREFIX_BYTES = 4, BINARY_NULL_CHECK_BYTES = 8192, BINARY_NULL_THRESHOLD = 0.1, DEFAULT_EXCLUDE_DIRS, DEFAULT_EXCLUDE_EXTENSIONS,
|
|
47989
|
+
var MAX_FILE_PATH_LENGTH = 500, MAX_FILE_SIZE_BYTES, MAX_FILES_SCANNED = 1000, MAX_FINDINGS = 100, MAX_OUTPUT_BYTES2 = 512000, MAX_LINE_LENGTH = 1e4, MAX_CONTENT_BYTES, BINARY_SIGNATURES, BINARY_PREFIX_BYTES = 4, BINARY_NULL_CHECK_BYTES = 8192, BINARY_NULL_THRESHOLD = 0.1, DEFAULT_EXCLUDE_DIRS, DEFAULT_EXCLUDE_EXTENSIONS, SECRET_PATTERNS2, O_NOFOLLOW, secretscan, _internals20;
|
|
46392
47990
|
var init_secretscan = __esm(() => {
|
|
46393
47991
|
init_zod();
|
|
46394
47992
|
init_path_security();
|
|
@@ -46451,7 +48049,7 @@ var init_secretscan = __esm(() => {
|
|
|
46451
48049
|
".log",
|
|
46452
48050
|
".md"
|
|
46453
48051
|
]);
|
|
46454
|
-
|
|
48052
|
+
SECRET_PATTERNS2 = [
|
|
46455
48053
|
{
|
|
46456
48054
|
type: "aws_access_key",
|
|
46457
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,
|
|
@@ -46621,7 +48219,7 @@ var init_secretscan = __esm(() => {
|
|
|
46621
48219
|
}
|
|
46622
48220
|
}
|
|
46623
48221
|
try {
|
|
46624
|
-
const _scanDirRaw =
|
|
48222
|
+
const _scanDirRaw = path33.resolve(directory);
|
|
46625
48223
|
const scanDir = (() => {
|
|
46626
48224
|
try {
|
|
46627
48225
|
return fs13.realpathSync(_scanDirRaw);
|
|
@@ -46691,8 +48289,8 @@ var init_secretscan = __esm(() => {
|
|
|
46691
48289
|
break;
|
|
46692
48290
|
const fileFindings = scanFileForSecrets(filePath);
|
|
46693
48291
|
try {
|
|
46694
|
-
const
|
|
46695
|
-
if (
|
|
48292
|
+
const stat4 = fs13.statSync(filePath);
|
|
48293
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES) {
|
|
46696
48294
|
skippedFiles++;
|
|
46697
48295
|
continue;
|
|
46698
48296
|
}
|
|
@@ -46768,7 +48366,7 @@ var init_secretscan = __esm(() => {
|
|
|
46768
48366
|
|
|
46769
48367
|
// src/lang/default-backend.ts
|
|
46770
48368
|
import * as fs14 from "fs";
|
|
46771
|
-
import * as
|
|
48369
|
+
import * as path34 from "path";
|
|
46772
48370
|
function detectFileExists(dir, pattern) {
|
|
46773
48371
|
if (pattern.includes("*") || pattern.includes("?")) {
|
|
46774
48372
|
try {
|
|
@@ -46780,7 +48378,7 @@ function detectFileExists(dir, pattern) {
|
|
|
46780
48378
|
}
|
|
46781
48379
|
}
|
|
46782
48380
|
try {
|
|
46783
|
-
fs14.accessSync(
|
|
48381
|
+
fs14.accessSync(path34.join(dir, pattern));
|
|
46784
48382
|
return true;
|
|
46785
48383
|
} catch {
|
|
46786
48384
|
return false;
|
|
@@ -46908,8 +48506,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
46908
48506
|
return ["mvn", "test"];
|
|
46909
48507
|
case "gradle": {
|
|
46910
48508
|
const isWindows = process.platform === "win32";
|
|
46911
|
-
const hasGradlewBat = fs14.existsSync(
|
|
46912
|
-
const hasGradlew = fs14.existsSync(
|
|
48509
|
+
const hasGradlewBat = fs14.existsSync(path34.join(dir, "gradlew.bat"));
|
|
48510
|
+
const hasGradlew = fs14.existsSync(path34.join(dir, "gradlew"));
|
|
46913
48511
|
if (hasGradlewBat && isWindows)
|
|
46914
48512
|
return ["gradlew.bat", "test"];
|
|
46915
48513
|
if (hasGradlew)
|
|
@@ -46926,7 +48524,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
46926
48524
|
"cmake-build-release",
|
|
46927
48525
|
"out"
|
|
46928
48526
|
];
|
|
46929
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs14.existsSync(
|
|
48527
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs14.existsSync(path34.join(dir, d, "CMakeCache.txt"))) ?? "build";
|
|
46930
48528
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
46931
48529
|
}
|
|
46932
48530
|
case "swift-test":
|
|
@@ -47213,17 +48811,17 @@ async function defaultSelectBuildCommand(profile, dir) {
|
|
|
47213
48811
|
return null;
|
|
47214
48812
|
}
|
|
47215
48813
|
async function defaultTestFilesFor(profile, sourceFile, dir) {
|
|
47216
|
-
const ext =
|
|
48814
|
+
const ext = path34.extname(sourceFile);
|
|
47217
48815
|
if (!profile.extensions.includes(ext))
|
|
47218
48816
|
return [];
|
|
47219
|
-
const base =
|
|
47220
|
-
const rel =
|
|
47221
|
-
const relDir =
|
|
48817
|
+
const base = path34.basename(sourceFile, ext);
|
|
48818
|
+
const rel = path34.relative(dir, sourceFile);
|
|
48819
|
+
const relDir = path34.dirname(rel);
|
|
47222
48820
|
const stripSrc = relDir.replace(/^src(\/|\\)/, "");
|
|
47223
48821
|
const candidates = new Set;
|
|
47224
48822
|
for (const tDir of ["tests", "test", "__tests__", "spec"]) {
|
|
47225
48823
|
for (const suffix of ["", "_test", ".test", "_spec", ".spec"]) {
|
|
47226
|
-
candidates.add(
|
|
48824
|
+
candidates.add(path34.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
|
|
47227
48825
|
}
|
|
47228
48826
|
}
|
|
47229
48827
|
const existing = [];
|
|
@@ -47264,7 +48862,7 @@ var init_default_backend = __esm(() => {
|
|
|
47264
48862
|
|
|
47265
48863
|
// src/lang/backends/go.ts
|
|
47266
48864
|
import * as fs15 from "fs";
|
|
47267
|
-
import * as
|
|
48865
|
+
import * as path35 from "path";
|
|
47268
48866
|
function extractImports(_sourceFile, source) {
|
|
47269
48867
|
const out = new Set;
|
|
47270
48868
|
IMPORT_REGEX_SINGLE.lastIndex = 0;
|
|
@@ -47290,7 +48888,7 @@ function extractImports(_sourceFile, source) {
|
|
|
47290
48888
|
async function selectFramework(dir) {
|
|
47291
48889
|
let content;
|
|
47292
48890
|
try {
|
|
47293
|
-
content = fs15.readFileSync(
|
|
48891
|
+
content = fs15.readFileSync(path35.join(dir, "go.mod"), "utf-8");
|
|
47294
48892
|
} catch {
|
|
47295
48893
|
return null;
|
|
47296
48894
|
}
|
|
@@ -47311,16 +48909,16 @@ async function selectFramework(dir) {
|
|
|
47311
48909
|
async function selectEntryPoints(dir) {
|
|
47312
48910
|
const points = [];
|
|
47313
48911
|
try {
|
|
47314
|
-
fs15.accessSync(
|
|
48912
|
+
fs15.accessSync(path35.join(dir, "main.go"));
|
|
47315
48913
|
points.push("main.go");
|
|
47316
48914
|
} catch {}
|
|
47317
48915
|
try {
|
|
47318
|
-
const cmdDir =
|
|
48916
|
+
const cmdDir = path35.join(dir, "cmd");
|
|
47319
48917
|
const subdirs = fs15.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
47320
48918
|
for (const sub of subdirs) {
|
|
47321
|
-
const main =
|
|
48919
|
+
const main = path35.join("cmd", sub.name, "main.go");
|
|
47322
48920
|
try {
|
|
47323
|
-
fs15.accessSync(
|
|
48921
|
+
fs15.accessSync(path35.join(dir, main));
|
|
47324
48922
|
points.push(main);
|
|
47325
48923
|
} catch {}
|
|
47326
48924
|
}
|
|
@@ -47351,7 +48949,7 @@ var init_go = __esm(() => {
|
|
|
47351
48949
|
|
|
47352
48950
|
// src/lang/backends/python.ts
|
|
47353
48951
|
import * as fs16 from "fs";
|
|
47354
|
-
import * as
|
|
48952
|
+
import * as path36 from "path";
|
|
47355
48953
|
function parseImportTargets(rawTargets) {
|
|
47356
48954
|
const cleaned = rawTargets.replace(/[()]/g, "").split(`
|
|
47357
48955
|
`).map((line) => line.replace(/#.*$/, "").replace(/\\\s*$/, "")).join(" ");
|
|
@@ -47411,7 +49009,7 @@ async function selectFramework2(dir) {
|
|
|
47411
49009
|
];
|
|
47412
49010
|
for (const candidate of ["pyproject.toml", "requirements.txt", "setup.py"]) {
|
|
47413
49011
|
try {
|
|
47414
|
-
const content = fs16.readFileSync(
|
|
49012
|
+
const content = fs16.readFileSync(path36.join(dir, candidate), "utf-8");
|
|
47415
49013
|
const lower = content.toLowerCase();
|
|
47416
49014
|
for (const [pkg, name] of candidates) {
|
|
47417
49015
|
if (lower.includes(pkg)) {
|
|
@@ -47425,7 +49023,7 @@ async function selectFramework2(dir) {
|
|
|
47425
49023
|
async function selectEntryPoints2(dir) {
|
|
47426
49024
|
const points = new Set;
|
|
47427
49025
|
try {
|
|
47428
|
-
const content = fs16.readFileSync(
|
|
49026
|
+
const content = fs16.readFileSync(path36.join(dir, "pyproject.toml"), "utf-8");
|
|
47429
49027
|
const scriptsBlock = content.match(/\[project\.scripts\][\s\S]*?(?=\n\[|$)/);
|
|
47430
49028
|
if (scriptsBlock) {
|
|
47431
49029
|
for (const line of scriptsBlock[0].split(`
|
|
@@ -47440,7 +49038,7 @@ async function selectEntryPoints2(dir) {
|
|
|
47440
49038
|
} catch {}
|
|
47441
49039
|
for (const name of ["manage.py", "main.py", "app.py", "__main__.py"]) {
|
|
47442
49040
|
try {
|
|
47443
|
-
fs16.accessSync(
|
|
49041
|
+
fs16.accessSync(path36.join(dir, name));
|
|
47444
49042
|
points.add(name);
|
|
47445
49043
|
} catch {}
|
|
47446
49044
|
}
|
|
@@ -47469,15 +49067,15 @@ var init_python = __esm(() => {
|
|
|
47469
49067
|
|
|
47470
49068
|
// src/test-impact/analyzer.ts
|
|
47471
49069
|
import fs17 from "fs";
|
|
47472
|
-
import
|
|
49070
|
+
import path37 from "path";
|
|
47473
49071
|
function normalizePath(p) {
|
|
47474
49072
|
return p.replace(/\\/g, "/");
|
|
47475
49073
|
}
|
|
47476
49074
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
47477
49075
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
47478
49076
|
try {
|
|
47479
|
-
const
|
|
47480
|
-
if (
|
|
49077
|
+
const stat4 = fs17.statSync(sourcePath);
|
|
49078
|
+
if (stat4.mtimeMs > generatedAtMs) {
|
|
47481
49079
|
return true;
|
|
47482
49080
|
}
|
|
47483
49081
|
} catch {
|
|
@@ -47490,8 +49088,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
47490
49088
|
if (!importPath.startsWith(".")) {
|
|
47491
49089
|
return null;
|
|
47492
49090
|
}
|
|
47493
|
-
const resolved =
|
|
47494
|
-
if (
|
|
49091
|
+
const resolved = path37.resolve(fromDir, importPath);
|
|
49092
|
+
if (path37.extname(resolved)) {
|
|
47495
49093
|
if (fs17.existsSync(resolved) && fs17.statSync(resolved).isFile()) {
|
|
47496
49094
|
return normalizePath(resolved);
|
|
47497
49095
|
}
|
|
@@ -47511,20 +49109,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
47511
49109
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
47512
49110
|
let baseDir = fromDir;
|
|
47513
49111
|
for (let i = 1;i < leadingDots; i++) {
|
|
47514
|
-
baseDir =
|
|
49112
|
+
baseDir = path37.dirname(baseDir);
|
|
47515
49113
|
}
|
|
47516
49114
|
const rest = module.slice(leadingDots);
|
|
47517
49115
|
if (rest.length === 0) {
|
|
47518
|
-
const initPath =
|
|
49116
|
+
const initPath = path37.join(baseDir, "__init__.py");
|
|
47519
49117
|
if (fs17.existsSync(initPath) && fs17.statSync(initPath).isFile()) {
|
|
47520
49118
|
return normalizePath(initPath);
|
|
47521
49119
|
}
|
|
47522
49120
|
return null;
|
|
47523
49121
|
}
|
|
47524
|
-
const subpath = rest.replace(/\./g,
|
|
49122
|
+
const subpath = rest.replace(/\./g, path37.sep);
|
|
47525
49123
|
const candidates = [
|
|
47526
|
-
`${
|
|
47527
|
-
|
|
49124
|
+
`${path37.join(baseDir, subpath)}.py`,
|
|
49125
|
+
path37.join(baseDir, subpath, "__init__.py")
|
|
47528
49126
|
];
|
|
47529
49127
|
for (const c of candidates) {
|
|
47530
49128
|
if (fs17.existsSync(c) && fs17.statSync(c).isFile())
|
|
@@ -47533,7 +49131,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
47533
49131
|
return null;
|
|
47534
49132
|
}
|
|
47535
49133
|
function findGoModule(fromDir) {
|
|
47536
|
-
const resolved =
|
|
49134
|
+
const resolved = path37.resolve(fromDir);
|
|
47537
49135
|
let cur = resolved;
|
|
47538
49136
|
const walked = [];
|
|
47539
49137
|
for (let i = 0;i < 16; i++) {
|
|
@@ -47545,7 +49143,7 @@ function findGoModule(fromDir) {
|
|
|
47545
49143
|
}
|
|
47546
49144
|
walked.push(cur);
|
|
47547
49145
|
try {
|
|
47548
|
-
const goMod =
|
|
49146
|
+
const goMod = path37.join(cur, "go.mod");
|
|
47549
49147
|
const content = fs17.readFileSync(goMod, "utf-8");
|
|
47550
49148
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
47551
49149
|
if (moduleMatch) {
|
|
@@ -47556,10 +49154,10 @@ function findGoModule(fromDir) {
|
|
|
47556
49154
|
}
|
|
47557
49155
|
} catch {}
|
|
47558
49156
|
try {
|
|
47559
|
-
fs17.accessSync(
|
|
49157
|
+
fs17.accessSync(path37.join(cur, ".git"));
|
|
47560
49158
|
break;
|
|
47561
49159
|
} catch {}
|
|
47562
|
-
const parent =
|
|
49160
|
+
const parent = path37.dirname(cur);
|
|
47563
49161
|
if (parent === cur)
|
|
47564
49162
|
break;
|
|
47565
49163
|
cur = parent;
|
|
@@ -47571,12 +49169,12 @@ function findGoModule(fromDir) {
|
|
|
47571
49169
|
function resolveGoImport(fromDir, importPath) {
|
|
47572
49170
|
let dir = null;
|
|
47573
49171
|
if (importPath.startsWith(".")) {
|
|
47574
|
-
dir =
|
|
49172
|
+
dir = path37.resolve(fromDir, importPath);
|
|
47575
49173
|
} else {
|
|
47576
49174
|
const mod = findGoModule(fromDir);
|
|
47577
49175
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
47578
49176
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
47579
|
-
dir =
|
|
49177
|
+
dir = path37.join(mod.moduleRoot, subpath);
|
|
47580
49178
|
}
|
|
47581
49179
|
}
|
|
47582
49180
|
if (dir === null)
|
|
@@ -47584,7 +49182,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
47584
49182
|
if (!fs17.existsSync(dir) || !fs17.statSync(dir).isDirectory())
|
|
47585
49183
|
return [];
|
|
47586
49184
|
try {
|
|
47587
|
-
return fs17.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(
|
|
49185
|
+
return fs17.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(path37.join(dir, f)));
|
|
47588
49186
|
} catch {
|
|
47589
49187
|
return [];
|
|
47590
49188
|
}
|
|
@@ -47623,15 +49221,15 @@ function findTestFilesSync(cwd) {
|
|
|
47623
49221
|
for (const entry of entries) {
|
|
47624
49222
|
if (entry.isDirectory()) {
|
|
47625
49223
|
if (!skipDirs.has(entry.name)) {
|
|
47626
|
-
walk(
|
|
49224
|
+
walk(path37.join(dir, entry.name), visitedInodes);
|
|
47627
49225
|
}
|
|
47628
49226
|
} else if (entry.isFile()) {
|
|
47629
49227
|
const name = entry.name;
|
|
47630
49228
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
47631
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
49229
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path37.sep}tests${path37.sep}`) && name.endsWith(".py");
|
|
47632
49230
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
47633
49231
|
if (isTsTest || isPyTest || isGoTest) {
|
|
47634
|
-
testFiles.push(normalizePath(
|
|
49232
|
+
testFiles.push(normalizePath(path37.join(dir, entry.name)));
|
|
47635
49233
|
}
|
|
47636
49234
|
}
|
|
47637
49235
|
}
|
|
@@ -47656,8 +49254,8 @@ function extractImports3(content) {
|
|
|
47656
49254
|
];
|
|
47657
49255
|
}
|
|
47658
49256
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
47659
|
-
const ext =
|
|
47660
|
-
const testDir =
|
|
49257
|
+
const ext = path37.extname(testFile).toLowerCase();
|
|
49258
|
+
const testDir = path37.dirname(testFile);
|
|
47661
49259
|
function addEdge(source) {
|
|
47662
49260
|
if (!impactMap[source])
|
|
47663
49261
|
impactMap[source] = [];
|
|
@@ -47716,7 +49314,7 @@ async function buildImpactMap(cwd) {
|
|
|
47716
49314
|
return impactMap;
|
|
47717
49315
|
}
|
|
47718
49316
|
async function loadImpactMap(cwd, options) {
|
|
47719
|
-
const cachePath =
|
|
49317
|
+
const cachePath = path37.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
47720
49318
|
if (fs17.existsSync(cachePath)) {
|
|
47721
49319
|
try {
|
|
47722
49320
|
const content = fs17.readFileSync(cachePath, "utf-8");
|
|
@@ -47749,12 +49347,12 @@ async function loadImpactMap(cwd, options) {
|
|
|
47749
49347
|
return _internals23.buildImpactMap(cwd);
|
|
47750
49348
|
}
|
|
47751
49349
|
async function saveImpactMap(cwd, impactMap) {
|
|
47752
|
-
if (!
|
|
49350
|
+
if (!path37.isAbsolute(cwd)) {
|
|
47753
49351
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
47754
49352
|
}
|
|
47755
49353
|
_internals23.validateProjectRoot(cwd);
|
|
47756
|
-
const cacheDir2 =
|
|
47757
|
-
const cachePath =
|
|
49354
|
+
const cacheDir2 = path37.join(cwd, ".swarm", "cache");
|
|
49355
|
+
const cachePath = path37.join(cacheDir2, "impact-map.json");
|
|
47758
49356
|
if (!fs17.existsSync(cacheDir2)) {
|
|
47759
49357
|
fs17.mkdirSync(cacheDir2, { recursive: true });
|
|
47760
49358
|
}
|
|
@@ -47786,7 +49384,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
47786
49384
|
budgetExceeded = true;
|
|
47787
49385
|
break;
|
|
47788
49386
|
}
|
|
47789
|
-
const normalizedChanged = normalizePath(
|
|
49387
|
+
const normalizedChanged = normalizePath(path37.resolve(changedFile));
|
|
47790
49388
|
const tests = impactMap[normalizedChanged];
|
|
47791
49389
|
if (tests && tests.length > 0) {
|
|
47792
49390
|
for (const test of tests) {
|
|
@@ -48079,15 +49677,15 @@ var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
|
|
|
48079
49677
|
|
|
48080
49678
|
// src/test-impact/history-store.ts
|
|
48081
49679
|
import fs18 from "fs";
|
|
48082
|
-
import
|
|
49680
|
+
import path38 from "path";
|
|
48083
49681
|
function getHistoryPath(workingDir) {
|
|
48084
49682
|
if (!workingDir) {
|
|
48085
49683
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
48086
49684
|
}
|
|
48087
|
-
if (!
|
|
49685
|
+
if (!path38.isAbsolute(workingDir)) {
|
|
48088
49686
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
48089
49687
|
}
|
|
48090
|
-
return
|
|
49688
|
+
return path38.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
48091
49689
|
}
|
|
48092
49690
|
function sanitizeErrorMessage(errorMessage) {
|
|
48093
49691
|
if (errorMessage === undefined) {
|
|
@@ -48174,7 +49772,7 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
48174
49772
|
}
|
|
48175
49773
|
}
|
|
48176
49774
|
const historyPath = getHistoryPath(workingDir);
|
|
48177
|
-
const historyDir =
|
|
49775
|
+
const historyDir = path38.dirname(historyPath);
|
|
48178
49776
|
_internals24.validateProjectRoot(workingDir);
|
|
48179
49777
|
if (!fs18.existsSync(historyDir)) {
|
|
48180
49778
|
fs18.mkdirSync(historyDir, { recursive: true });
|
|
@@ -48270,7 +49868,7 @@ var init_history_store = __esm(() => {
|
|
|
48270
49868
|
|
|
48271
49869
|
// src/tools/resolve-working-directory.ts
|
|
48272
49870
|
import * as fs19 from "fs";
|
|
48273
|
-
import * as
|
|
49871
|
+
import * as path39 from "path";
|
|
48274
49872
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
48275
49873
|
if (workingDirectory == null || workingDirectory === "") {
|
|
48276
49874
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -48290,15 +49888,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
48290
49888
|
};
|
|
48291
49889
|
}
|
|
48292
49890
|
}
|
|
48293
|
-
const normalizedDir =
|
|
48294
|
-
const pathParts = normalizedDir.split(
|
|
49891
|
+
const normalizedDir = path39.normalize(workingDirectory);
|
|
49892
|
+
const pathParts = normalizedDir.split(path39.sep);
|
|
48295
49893
|
if (pathParts.includes("..")) {
|
|
48296
49894
|
return {
|
|
48297
49895
|
success: false,
|
|
48298
49896
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
48299
49897
|
};
|
|
48300
49898
|
}
|
|
48301
|
-
const resolvedDir =
|
|
49899
|
+
const resolvedDir = path39.resolve(normalizedDir);
|
|
48302
49900
|
let statResult;
|
|
48303
49901
|
try {
|
|
48304
49902
|
statResult = fs19.statSync(resolvedDir);
|
|
@@ -48314,7 +49912,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
48314
49912
|
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
48315
49913
|
};
|
|
48316
49914
|
}
|
|
48317
|
-
const resolvedFallback =
|
|
49915
|
+
const resolvedFallback = path39.resolve(fallbackDirectory);
|
|
48318
49916
|
let fallbackExists = false;
|
|
48319
49917
|
try {
|
|
48320
49918
|
fs19.statSync(resolvedFallback);
|
|
@@ -48324,7 +49922,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
48324
49922
|
}
|
|
48325
49923
|
if (workingDirectory != null && workingDirectory !== "") {
|
|
48326
49924
|
if (fallbackExists) {
|
|
48327
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
49925
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path39.sep);
|
|
48328
49926
|
if (isSubdirectory) {
|
|
48329
49927
|
return {
|
|
48330
49928
|
success: false,
|
|
@@ -48379,10 +49977,10 @@ var init_registry_backend = __esm(() => {
|
|
|
48379
49977
|
|
|
48380
49978
|
// src/lang/backends/typescript.ts
|
|
48381
49979
|
import * as fs20 from "fs";
|
|
48382
|
-
import * as
|
|
49980
|
+
import * as path40 from "path";
|
|
48383
49981
|
function readPackageJsonRaw(dir) {
|
|
48384
49982
|
try {
|
|
48385
|
-
const content = fs20.readFileSync(
|
|
49983
|
+
const content = fs20.readFileSync(path40.join(dir, "package.json"), "utf-8");
|
|
48386
49984
|
return JSON.parse(content);
|
|
48387
49985
|
} catch {
|
|
48388
49986
|
return null;
|
|
@@ -48602,7 +50200,7 @@ __export(exports_dispatch, {
|
|
|
48602
50200
|
_internals: () => _internals26
|
|
48603
50201
|
});
|
|
48604
50202
|
import * as fs21 from "fs";
|
|
48605
|
-
import * as
|
|
50203
|
+
import * as path41 from "path";
|
|
48606
50204
|
function safeReaddirSet(dir) {
|
|
48607
50205
|
try {
|
|
48608
50206
|
return new Set(fs21.readdirSync(dir));
|
|
@@ -48619,14 +50217,14 @@ function manifestHash(dir) {
|
|
|
48619
50217
|
if (!entries.has(name))
|
|
48620
50218
|
continue;
|
|
48621
50219
|
try {
|
|
48622
|
-
const
|
|
48623
|
-
parts.push(`${name}:${
|
|
50220
|
+
const stat4 = fs21.statSync(path41.join(dir, name));
|
|
50221
|
+
parts.push(`${name}:${stat4.size}:${stat4.mtimeMs}:${stat4.ino}`);
|
|
48624
50222
|
} catch {}
|
|
48625
50223
|
}
|
|
48626
50224
|
return parts.join("|");
|
|
48627
50225
|
}
|
|
48628
50226
|
function findManifestRoot(start) {
|
|
48629
|
-
const resolved =
|
|
50227
|
+
const resolved = path41.resolve(start);
|
|
48630
50228
|
const cached3 = manifestRootCache.get(resolved);
|
|
48631
50229
|
if (cached3 !== undefined)
|
|
48632
50230
|
return cached3;
|
|
@@ -48645,7 +50243,7 @@ function findManifestRoot(start) {
|
|
|
48645
50243
|
return cur;
|
|
48646
50244
|
}
|
|
48647
50245
|
}
|
|
48648
|
-
const parent =
|
|
50246
|
+
const parent = path41.dirname(cur);
|
|
48649
50247
|
if (parent === cur)
|
|
48650
50248
|
break;
|
|
48651
50249
|
cur = parent;
|
|
@@ -48755,13 +50353,13 @@ var init_dispatch = __esm(() => {
|
|
|
48755
50353
|
|
|
48756
50354
|
// src/tools/test-runner.ts
|
|
48757
50355
|
import * as fs22 from "fs";
|
|
48758
|
-
import * as
|
|
50356
|
+
import * as path42 from "path";
|
|
48759
50357
|
async function estimateFanOut(sourceFiles, cwd) {
|
|
48760
50358
|
try {
|
|
48761
50359
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
48762
50360
|
const uniqueTestFiles = new Set;
|
|
48763
50361
|
for (const sourceFile of sourceFiles) {
|
|
48764
|
-
const resolvedPath =
|
|
50362
|
+
const resolvedPath = path42.resolve(cwd, sourceFile);
|
|
48765
50363
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
48766
50364
|
const testFiles = impactMap[normalizedPath];
|
|
48767
50365
|
if (testFiles) {
|
|
@@ -48839,14 +50437,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
48839
50437
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
48840
50438
|
}
|
|
48841
50439
|
function detectGoTest(cwd) {
|
|
48842
|
-
return fs22.existsSync(
|
|
50440
|
+
return fs22.existsSync(path42.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
48843
50441
|
}
|
|
48844
50442
|
function detectJavaMaven(cwd) {
|
|
48845
|
-
return fs22.existsSync(
|
|
50443
|
+
return fs22.existsSync(path42.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
48846
50444
|
}
|
|
48847
50445
|
function detectGradle(cwd) {
|
|
48848
|
-
const hasBuildFile = fs22.existsSync(
|
|
48849
|
-
const hasGradlew = fs22.existsSync(
|
|
50446
|
+
const hasBuildFile = fs22.existsSync(path42.join(cwd, "build.gradle")) || fs22.existsSync(path42.join(cwd, "build.gradle.kts"));
|
|
50447
|
+
const hasGradlew = fs22.existsSync(path42.join(cwd, "gradlew")) || fs22.existsSync(path42.join(cwd, "gradlew.bat"));
|
|
48850
50448
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
48851
50449
|
}
|
|
48852
50450
|
function detectDotnetTest(cwd) {
|
|
@@ -48859,25 +50457,25 @@ function detectDotnetTest(cwd) {
|
|
|
48859
50457
|
}
|
|
48860
50458
|
}
|
|
48861
50459
|
function detectCTest(cwd) {
|
|
48862
|
-
const hasSource = fs22.existsSync(
|
|
48863
|
-
const hasBuildCache = fs22.existsSync(
|
|
50460
|
+
const hasSource = fs22.existsSync(path42.join(cwd, "CMakeLists.txt"));
|
|
50461
|
+
const hasBuildCache = fs22.existsSync(path42.join(cwd, "CMakeCache.txt")) || fs22.existsSync(path42.join(cwd, "build", "CMakeCache.txt"));
|
|
48864
50462
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
48865
50463
|
}
|
|
48866
50464
|
function detectSwiftTest(cwd) {
|
|
48867
|
-
return fs22.existsSync(
|
|
50465
|
+
return fs22.existsSync(path42.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
48868
50466
|
}
|
|
48869
50467
|
function detectDartTest(cwd) {
|
|
48870
|
-
return fs22.existsSync(
|
|
50468
|
+
return fs22.existsSync(path42.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
48871
50469
|
}
|
|
48872
50470
|
function detectRSpec(cwd) {
|
|
48873
|
-
const hasRSpecFile = fs22.existsSync(
|
|
48874
|
-
const hasGemfile = fs22.existsSync(
|
|
48875
|
-
const hasSpecDir = fs22.existsSync(
|
|
50471
|
+
const hasRSpecFile = fs22.existsSync(path42.join(cwd, ".rspec"));
|
|
50472
|
+
const hasGemfile = fs22.existsSync(path42.join(cwd, "Gemfile"));
|
|
50473
|
+
const hasSpecDir = fs22.existsSync(path42.join(cwd, "spec"));
|
|
48876
50474
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
48877
50475
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
48878
50476
|
}
|
|
48879
50477
|
function detectMinitest(cwd) {
|
|
48880
|
-
return fs22.existsSync(
|
|
50478
|
+
return fs22.existsSync(path42.join(cwd, "test")) && (fs22.existsSync(path42.join(cwd, "Gemfile")) || fs22.existsSync(path42.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
48881
50479
|
}
|
|
48882
50480
|
async function detectTestFrameworkViaDispatch(cwd) {
|
|
48883
50481
|
try {
|
|
@@ -48939,7 +50537,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
48939
50537
|
async function detectTestFramework(cwd) {
|
|
48940
50538
|
const baseDir = cwd;
|
|
48941
50539
|
try {
|
|
48942
|
-
const packageJsonPath =
|
|
50540
|
+
const packageJsonPath = path42.join(baseDir, "package.json");
|
|
48943
50541
|
if (fs22.existsSync(packageJsonPath)) {
|
|
48944
50542
|
const content = fs22.readFileSync(packageJsonPath, "utf-8");
|
|
48945
50543
|
const pkg = JSON.parse(content);
|
|
@@ -48960,16 +50558,16 @@ async function detectTestFramework(cwd) {
|
|
|
48960
50558
|
return "jest";
|
|
48961
50559
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
48962
50560
|
return "mocha";
|
|
48963
|
-
if (fs22.existsSync(
|
|
50561
|
+
if (fs22.existsSync(path42.join(baseDir, "bun.lockb")) || fs22.existsSync(path42.join(baseDir, "bun.lock"))) {
|
|
48964
50562
|
if (scripts.test?.includes("bun"))
|
|
48965
50563
|
return "bun";
|
|
48966
50564
|
}
|
|
48967
50565
|
}
|
|
48968
50566
|
} catch {}
|
|
48969
50567
|
try {
|
|
48970
|
-
const pyprojectTomlPath =
|
|
48971
|
-
const setupCfgPath =
|
|
48972
|
-
const requirementsTxtPath =
|
|
50568
|
+
const pyprojectTomlPath = path42.join(baseDir, "pyproject.toml");
|
|
50569
|
+
const setupCfgPath = path42.join(baseDir, "setup.cfg");
|
|
50570
|
+
const requirementsTxtPath = path42.join(baseDir, "requirements.txt");
|
|
48973
50571
|
if (fs22.existsSync(pyprojectTomlPath)) {
|
|
48974
50572
|
const content = fs22.readFileSync(pyprojectTomlPath, "utf-8");
|
|
48975
50573
|
if (content.includes("[tool.pytest"))
|
|
@@ -48989,7 +50587,7 @@ async function detectTestFramework(cwd) {
|
|
|
48989
50587
|
}
|
|
48990
50588
|
} catch {}
|
|
48991
50589
|
try {
|
|
48992
|
-
const cargoTomlPath =
|
|
50590
|
+
const cargoTomlPath = path42.join(baseDir, "Cargo.toml");
|
|
48993
50591
|
if (fs22.existsSync(cargoTomlPath)) {
|
|
48994
50592
|
const content = fs22.readFileSync(cargoTomlPath, "utf-8");
|
|
48995
50593
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -49000,9 +50598,9 @@ async function detectTestFramework(cwd) {
|
|
|
49000
50598
|
}
|
|
49001
50599
|
} catch {}
|
|
49002
50600
|
try {
|
|
49003
|
-
const pesterConfigPath =
|
|
49004
|
-
const pesterConfigJsonPath =
|
|
49005
|
-
const pesterPs1Path =
|
|
50601
|
+
const pesterConfigPath = path42.join(baseDir, "pester.config.ps1");
|
|
50602
|
+
const pesterConfigJsonPath = path42.join(baseDir, "pester.config.ps1.json");
|
|
50603
|
+
const pesterPs1Path = path42.join(baseDir, "tests.ps1");
|
|
49006
50604
|
if (fs22.existsSync(pesterConfigPath) || fs22.existsSync(pesterConfigJsonPath) || fs22.existsSync(pesterPs1Path)) {
|
|
49007
50605
|
return "pester";
|
|
49008
50606
|
}
|
|
@@ -49031,12 +50629,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
49031
50629
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
49032
50630
|
}
|
|
49033
50631
|
function resolveWorkspacePath(file3, workingDir) {
|
|
49034
|
-
return
|
|
50632
|
+
return path42.isAbsolute(file3) ? path42.resolve(file3) : path42.resolve(workingDir, file3);
|
|
49035
50633
|
}
|
|
49036
50634
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
49037
50635
|
if (!preferRelative)
|
|
49038
50636
|
return absolutePath;
|
|
49039
|
-
return
|
|
50637
|
+
return path42.relative(workingDir, absolutePath);
|
|
49040
50638
|
}
|
|
49041
50639
|
function dedupePush(target, value) {
|
|
49042
50640
|
if (!target.includes(value)) {
|
|
@@ -49073,18 +50671,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
49073
50671
|
}
|
|
49074
50672
|
}
|
|
49075
50673
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
49076
|
-
const relativeDir =
|
|
50674
|
+
const relativeDir = path42.dirname(relativePath);
|
|
49077
50675
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
49078
50676
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
49079
|
-
const rootDir =
|
|
49080
|
-
return nestedRelativeDir ? [rootDir,
|
|
50677
|
+
const rootDir = path42.join(workingDir, dirName);
|
|
50678
|
+
return nestedRelativeDir ? [rootDir, path42.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
49081
50679
|
});
|
|
49082
50680
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
49083
50681
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
49084
|
-
directories.push(
|
|
50682
|
+
directories.push(path42.join(workingDir, "src/test/java", path42.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
49085
50683
|
}
|
|
49086
50684
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
49087
|
-
directories.push(
|
|
50685
|
+
directories.push(path42.join(workingDir, "src/test/kotlin", path42.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
49088
50686
|
}
|
|
49089
50687
|
return [...new Set(directories)];
|
|
49090
50688
|
}
|
|
@@ -49112,23 +50710,23 @@ function isLanguageSpecificTestFile(basename6) {
|
|
|
49112
50710
|
}
|
|
49113
50711
|
function isConventionTestFilePath(filePath) {
|
|
49114
50712
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
49115
|
-
const basename6 =
|
|
50713
|
+
const basename6 = path42.basename(filePath);
|
|
49116
50714
|
return hasCompoundTestExtension(basename6) || basename6.includes(".spec.") || basename6.includes(".test.") || isLanguageSpecificTestFile(basename6) || isTestDirectoryPath(normalizedPath);
|
|
49117
50715
|
}
|
|
49118
50716
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
49119
50717
|
const testFiles = [];
|
|
49120
50718
|
for (const file3 of sourceFiles) {
|
|
49121
50719
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
49122
|
-
const relativeFile =
|
|
49123
|
-
const basename6 =
|
|
49124
|
-
const
|
|
49125
|
-
const preferRelativeOutput = !
|
|
50720
|
+
const relativeFile = path42.relative(workingDir, absoluteFile);
|
|
50721
|
+
const basename6 = path42.basename(absoluteFile);
|
|
50722
|
+
const dirname20 = path42.dirname(absoluteFile);
|
|
50723
|
+
const preferRelativeOutput = !path42.isAbsolute(file3);
|
|
49126
50724
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
49127
50725
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
49128
50726
|
continue;
|
|
49129
50727
|
}
|
|
49130
50728
|
const nameWithoutExt = basename6.replace(/\.[^.]+$/, "");
|
|
49131
|
-
const ext =
|
|
50729
|
+
const ext = path42.extname(basename6);
|
|
49132
50730
|
const genericTestNames = [
|
|
49133
50731
|
`${nameWithoutExt}.spec${ext}`,
|
|
49134
50732
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -49137,7 +50735,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
49137
50735
|
const colocatedCandidates = [
|
|
49138
50736
|
...genericTestNames,
|
|
49139
50737
|
...languageSpecificTestNames
|
|
49140
|
-
].map((candidateName) =>
|
|
50738
|
+
].map((candidateName) => path42.join(dirname20, candidateName));
|
|
49141
50739
|
const testDirectoryNames = [
|
|
49142
50740
|
basename6,
|
|
49143
50741
|
...genericTestNames,
|
|
@@ -49146,8 +50744,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
49146
50744
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
49147
50745
|
const possibleTestFiles = [
|
|
49148
50746
|
...colocatedCandidates,
|
|
49149
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
49150
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
50747
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path42.join(dirname20, dirName, candidateName))),
|
|
50748
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path42.join(candidateDir, candidateName)))
|
|
49151
50749
|
];
|
|
49152
50750
|
for (const testFile of possibleTestFiles) {
|
|
49153
50751
|
if (fs22.existsSync(testFile)) {
|
|
@@ -49168,7 +50766,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49168
50766
|
try {
|
|
49169
50767
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
49170
50768
|
const content = fs22.readFileSync(absoluteTestFile, "utf-8");
|
|
49171
|
-
const testDir =
|
|
50769
|
+
const testDir = path42.dirname(absoluteTestFile);
|
|
49172
50770
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
49173
50771
|
let match;
|
|
49174
50772
|
match = importRegex.exec(content);
|
|
@@ -49176,8 +50774,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49176
50774
|
const importPath = match[1];
|
|
49177
50775
|
let resolvedImport;
|
|
49178
50776
|
if (importPath.startsWith(".")) {
|
|
49179
|
-
resolvedImport =
|
|
49180
|
-
const existingExt =
|
|
50777
|
+
resolvedImport = path42.resolve(testDir, importPath);
|
|
50778
|
+
const existingExt = path42.extname(resolvedImport);
|
|
49181
50779
|
if (!existingExt) {
|
|
49182
50780
|
for (const extToTry of [
|
|
49183
50781
|
".ts",
|
|
@@ -49197,12 +50795,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49197
50795
|
} else {
|
|
49198
50796
|
continue;
|
|
49199
50797
|
}
|
|
49200
|
-
const importBasename =
|
|
49201
|
-
const importDir =
|
|
50798
|
+
const importBasename = path42.basename(resolvedImport, path42.extname(resolvedImport));
|
|
50799
|
+
const importDir = path42.dirname(resolvedImport);
|
|
49202
50800
|
for (const sourceFile of absoluteSourceFiles) {
|
|
49203
|
-
const sourceDir =
|
|
49204
|
-
const sourceBasename =
|
|
49205
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
50801
|
+
const sourceDir = path42.dirname(sourceFile);
|
|
50802
|
+
const sourceBasename = path42.basename(sourceFile, path42.extname(sourceFile));
|
|
50803
|
+
const isRelatedDir = importDir === sourceDir || importDir === path42.join(sourceDir, "__tests__") || importDir === path42.join(sourceDir, "tests") || importDir === path42.join(sourceDir, "test") || importDir === path42.join(sourceDir, "spec");
|
|
49206
50804
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
49207
50805
|
dedupePush(testFiles, testFile);
|
|
49208
50806
|
break;
|
|
@@ -49215,8 +50813,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49215
50813
|
while (match !== null) {
|
|
49216
50814
|
const importPath = match[1];
|
|
49217
50815
|
if (importPath.startsWith(".")) {
|
|
49218
|
-
let resolvedImport =
|
|
49219
|
-
const existingExt =
|
|
50816
|
+
let resolvedImport = path42.resolve(testDir, importPath);
|
|
50817
|
+
const existingExt = path42.extname(resolvedImport);
|
|
49220
50818
|
if (!existingExt) {
|
|
49221
50819
|
for (const extToTry of [
|
|
49222
50820
|
".ts",
|
|
@@ -49233,12 +50831,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
49233
50831
|
}
|
|
49234
50832
|
}
|
|
49235
50833
|
}
|
|
49236
|
-
const importDir =
|
|
49237
|
-
const importBasename =
|
|
50834
|
+
const importDir = path42.dirname(resolvedImport);
|
|
50835
|
+
const importBasename = path42.basename(resolvedImport, path42.extname(resolvedImport));
|
|
49238
50836
|
for (const sourceFile of absoluteSourceFiles) {
|
|
49239
|
-
const sourceDir =
|
|
49240
|
-
const sourceBasename =
|
|
49241
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
50837
|
+
const sourceDir = path42.dirname(sourceFile);
|
|
50838
|
+
const sourceBasename = path42.basename(sourceFile, path42.extname(sourceFile));
|
|
50839
|
+
const isRelatedDir = importDir === sourceDir || importDir === path42.join(sourceDir, "__tests__") || importDir === path42.join(sourceDir, "tests") || importDir === path42.join(sourceDir, "test") || importDir === path42.join(sourceDir, "spec");
|
|
49242
50840
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
49243
50841
|
dedupePush(testFiles, testFile);
|
|
49244
50842
|
break;
|
|
@@ -49348,8 +50946,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
|
49348
50946
|
return ["mvn", "test"];
|
|
49349
50947
|
case "gradle": {
|
|
49350
50948
|
const isWindows = process.platform === "win32";
|
|
49351
|
-
const hasGradlewBat = fs22.existsSync(
|
|
49352
|
-
const hasGradlew = fs22.existsSync(
|
|
50949
|
+
const hasGradlewBat = fs22.existsSync(path42.join(baseDir, "gradlew.bat"));
|
|
50950
|
+
const hasGradlew = fs22.existsSync(path42.join(baseDir, "gradlew"));
|
|
49353
50951
|
if (hasGradlewBat && isWindows)
|
|
49354
50952
|
return ["gradlew.bat", "test"];
|
|
49355
50953
|
if (hasGradlew)
|
|
@@ -49366,7 +50964,7 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
|
49366
50964
|
"cmake-build-release",
|
|
49367
50965
|
"out"
|
|
49368
50966
|
];
|
|
49369
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs22.existsSync(
|
|
50967
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs22.existsSync(path42.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
49370
50968
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
49371
50969
|
}
|
|
49372
50970
|
case "swift-test":
|
|
@@ -49798,11 +51396,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
49798
51396
|
};
|
|
49799
51397
|
}
|
|
49800
51398
|
const startTime = Date.now();
|
|
49801
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
51399
|
+
const vitestJsonOutputPath = framework === "vitest" ? path42.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
49802
51400
|
try {
|
|
49803
51401
|
if (vitestJsonOutputPath) {
|
|
49804
51402
|
try {
|
|
49805
|
-
fs22.mkdirSync(
|
|
51403
|
+
fs22.mkdirSync(path42.dirname(vitestJsonOutputPath), { recursive: true });
|
|
49806
51404
|
if (fs22.existsSync(vitestJsonOutputPath)) {
|
|
49807
51405
|
fs22.unlinkSync(vitestJsonOutputPath);
|
|
49808
51406
|
}
|
|
@@ -49918,10 +51516,10 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
49918
51516
|
}
|
|
49919
51517
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
49920
51518
|
const normalized = testFile.replace(/\\/g, "/");
|
|
49921
|
-
if (!
|
|
51519
|
+
if (!path42.isAbsolute(testFile))
|
|
49922
51520
|
return normalized;
|
|
49923
|
-
const relative9 =
|
|
49924
|
-
if (relative9.startsWith("..") ||
|
|
51521
|
+
const relative9 = path42.relative(workingDir, testFile);
|
|
51522
|
+
if (relative9.startsWith("..") || path42.isAbsolute(relative9)) {
|
|
49925
51523
|
return normalized;
|
|
49926
51524
|
}
|
|
49927
51525
|
return relative9.replace(/\\/g, "/");
|
|
@@ -50259,7 +51857,7 @@ var init_test_runner = __esm(() => {
|
|
|
50259
51857
|
const sourceFiles = args.files.filter((file3) => {
|
|
50260
51858
|
if (directTestFiles.includes(file3))
|
|
50261
51859
|
return false;
|
|
50262
|
-
const ext =
|
|
51860
|
+
const ext = path42.extname(file3).toLowerCase();
|
|
50263
51861
|
return SOURCE_EXTENSIONS.has(ext);
|
|
50264
51862
|
});
|
|
50265
51863
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -50305,7 +51903,7 @@ var init_test_runner = __esm(() => {
|
|
|
50305
51903
|
if (isConventionTestFilePath(f)) {
|
|
50306
51904
|
return false;
|
|
50307
51905
|
}
|
|
50308
|
-
const ext =
|
|
51906
|
+
const ext = path42.extname(f).toLowerCase();
|
|
50309
51907
|
return SOURCE_EXTENSIONS.has(ext);
|
|
50310
51908
|
});
|
|
50311
51909
|
if (sourceFiles.length === 0) {
|
|
@@ -50355,7 +51953,7 @@ var init_test_runner = __esm(() => {
|
|
|
50355
51953
|
if (isConventionTestFilePath(f)) {
|
|
50356
51954
|
return false;
|
|
50357
51955
|
}
|
|
50358
|
-
const ext =
|
|
51956
|
+
const ext = path42.extname(f).toLowerCase();
|
|
50359
51957
|
return SOURCE_EXTENSIONS.has(ext);
|
|
50360
51958
|
});
|
|
50361
51959
|
if (sourceFiles.length === 0) {
|
|
@@ -50407,8 +52005,8 @@ var init_test_runner = __esm(() => {
|
|
|
50407
52005
|
}
|
|
50408
52006
|
if (impactResult.impactedTests.length > 0) {
|
|
50409
52007
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
50410
|
-
const relativePath =
|
|
50411
|
-
return
|
|
52008
|
+
const relativePath = path42.relative(workingDir, absPath);
|
|
52009
|
+
return path42.isAbsolute(relativePath) ? absPath : relativePath;
|
|
50412
52010
|
});
|
|
50413
52011
|
} else {
|
|
50414
52012
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -50484,7 +52082,7 @@ var init_test_runner = __esm(() => {
|
|
|
50484
52082
|
|
|
50485
52083
|
// src/services/preflight-service.ts
|
|
50486
52084
|
import * as fs23 from "fs";
|
|
50487
|
-
import * as
|
|
52085
|
+
import * as path43 from "path";
|
|
50488
52086
|
function validateDirectoryPath(dir) {
|
|
50489
52087
|
if (!dir || typeof dir !== "string") {
|
|
50490
52088
|
throw new Error("Directory path is required");
|
|
@@ -50492,8 +52090,8 @@ function validateDirectoryPath(dir) {
|
|
|
50492
52090
|
if (dir.includes("..")) {
|
|
50493
52091
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
50494
52092
|
}
|
|
50495
|
-
const normalized =
|
|
50496
|
-
const absolutePath =
|
|
52093
|
+
const normalized = path43.normalize(dir);
|
|
52094
|
+
const absolutePath = path43.isAbsolute(normalized) ? normalized : path43.resolve(normalized);
|
|
50497
52095
|
return absolutePath;
|
|
50498
52096
|
}
|
|
50499
52097
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -50516,7 +52114,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
50516
52114
|
}
|
|
50517
52115
|
function getPackageVersion(dir) {
|
|
50518
52116
|
try {
|
|
50519
|
-
const packagePath =
|
|
52117
|
+
const packagePath = path43.join(dir, "package.json");
|
|
50520
52118
|
if (fs23.existsSync(packagePath)) {
|
|
50521
52119
|
const content = fs23.readFileSync(packagePath, "utf-8");
|
|
50522
52120
|
const pkg = JSON.parse(content);
|
|
@@ -50527,7 +52125,7 @@ function getPackageVersion(dir) {
|
|
|
50527
52125
|
}
|
|
50528
52126
|
function getChangelogVersion(dir) {
|
|
50529
52127
|
try {
|
|
50530
|
-
const changelogPath =
|
|
52128
|
+
const changelogPath = path43.join(dir, "CHANGELOG.md");
|
|
50531
52129
|
if (fs23.existsSync(changelogPath)) {
|
|
50532
52130
|
const content = fs23.readFileSync(changelogPath, "utf-8");
|
|
50533
52131
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -50541,7 +52139,7 @@ function getChangelogVersion(dir) {
|
|
|
50541
52139
|
function getVersionFileVersion(dir) {
|
|
50542
52140
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
50543
52141
|
for (const file3 of possibleFiles) {
|
|
50544
|
-
const filePath =
|
|
52142
|
+
const filePath = path43.join(dir, file3);
|
|
50545
52143
|
if (fs23.existsSync(filePath)) {
|
|
50546
52144
|
try {
|
|
50547
52145
|
const content = fs23.readFileSync(filePath, "utf-8").trim();
|
|
@@ -50883,7 +52481,7 @@ async function runEvidenceCheck(dir) {
|
|
|
50883
52481
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
50884
52482
|
const startTime = Date.now();
|
|
50885
52483
|
try {
|
|
50886
|
-
const specPath =
|
|
52484
|
+
const specPath = path43.join(dir, ".swarm", "spec.md");
|
|
50887
52485
|
if (!fs23.existsSync(specPath)) {
|
|
50888
52486
|
return {
|
|
50889
52487
|
type: "req_coverage",
|
|
@@ -52001,7 +53599,7 @@ var init_manager3 = __esm(() => {
|
|
|
52001
53599
|
|
|
52002
53600
|
// src/commands/reset.ts
|
|
52003
53601
|
import * as fs24 from "fs";
|
|
52004
|
-
import * as
|
|
53602
|
+
import * as path44 from "path";
|
|
52005
53603
|
async function handleResetCommand(directory, args) {
|
|
52006
53604
|
const hasConfirm = args.includes("--confirm");
|
|
52007
53605
|
if (!hasConfirm) {
|
|
@@ -52041,7 +53639,7 @@ async function handleResetCommand(directory, args) {
|
|
|
52041
53639
|
}
|
|
52042
53640
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
52043
53641
|
try {
|
|
52044
|
-
const rootPath =
|
|
53642
|
+
const rootPath = path44.join(directory, filename);
|
|
52045
53643
|
if (fs24.existsSync(rootPath)) {
|
|
52046
53644
|
fs24.unlinkSync(rootPath);
|
|
52047
53645
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -52081,7 +53679,7 @@ var init_reset = __esm(() => {
|
|
|
52081
53679
|
|
|
52082
53680
|
// src/commands/reset-session.ts
|
|
52083
53681
|
import * as fs25 from "fs";
|
|
52084
|
-
import * as
|
|
53682
|
+
import * as path45 from "path";
|
|
52085
53683
|
async function handleResetSessionCommand(directory, _args) {
|
|
52086
53684
|
const results = [];
|
|
52087
53685
|
try {
|
|
@@ -52096,13 +53694,13 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
52096
53694
|
results.push("\u274C Failed to delete state.json");
|
|
52097
53695
|
}
|
|
52098
53696
|
try {
|
|
52099
|
-
const sessionDir =
|
|
53697
|
+
const sessionDir = path45.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
52100
53698
|
if (fs25.existsSync(sessionDir)) {
|
|
52101
53699
|
const files = fs25.readdirSync(sessionDir);
|
|
52102
53700
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
52103
53701
|
let deletedCount = 0;
|
|
52104
53702
|
for (const file3 of otherFiles) {
|
|
52105
|
-
const filePath =
|
|
53703
|
+
const filePath = path45.join(sessionDir, file3);
|
|
52106
53704
|
if (fs25.lstatSync(filePath).isFile()) {
|
|
52107
53705
|
fs25.unlinkSync(filePath);
|
|
52108
53706
|
deletedCount++;
|
|
@@ -52134,7 +53732,7 @@ var init_reset_session = __esm(() => {
|
|
|
52134
53732
|
});
|
|
52135
53733
|
|
|
52136
53734
|
// src/summaries/manager.ts
|
|
52137
|
-
import * as
|
|
53735
|
+
import * as path46 from "path";
|
|
52138
53736
|
function sanitizeSummaryId(id) {
|
|
52139
53737
|
if (!id || id.length === 0) {
|
|
52140
53738
|
throw new Error("Invalid summary ID: empty string");
|
|
@@ -52157,7 +53755,7 @@ function sanitizeSummaryId(id) {
|
|
|
52157
53755
|
}
|
|
52158
53756
|
async function loadFullOutput(directory, id) {
|
|
52159
53757
|
const sanitizedId = sanitizeSummaryId(id);
|
|
52160
|
-
const relativePath =
|
|
53758
|
+
const relativePath = path46.join("summaries", `${sanitizedId}.json`);
|
|
52161
53759
|
validateSwarmPath(directory, relativePath);
|
|
52162
53760
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
52163
53761
|
if (content === null) {
|
|
@@ -52220,7 +53818,7 @@ var init_retrieve = __esm(() => {
|
|
|
52220
53818
|
|
|
52221
53819
|
// src/commands/rollback.ts
|
|
52222
53820
|
import * as fs26 from "fs";
|
|
52223
|
-
import * as
|
|
53821
|
+
import * as path47 from "path";
|
|
52224
53822
|
async function handleRollbackCommand(directory, args) {
|
|
52225
53823
|
const phaseArg = args[0];
|
|
52226
53824
|
if (!phaseArg) {
|
|
@@ -52285,8 +53883,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
52285
53883
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
52286
53884
|
continue;
|
|
52287
53885
|
}
|
|
52288
|
-
const src =
|
|
52289
|
-
const dest =
|
|
53886
|
+
const src = path47.join(checkpointDir, file3);
|
|
53887
|
+
const dest = path47.join(swarmDir, file3);
|
|
52290
53888
|
try {
|
|
52291
53889
|
fs26.cpSync(src, dest, { recursive: true, force: true });
|
|
52292
53890
|
successes.push(file3);
|
|
@@ -52305,12 +53903,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
52305
53903
|
].join(`
|
|
52306
53904
|
`);
|
|
52307
53905
|
}
|
|
52308
|
-
const existingLedgerPath =
|
|
53906
|
+
const existingLedgerPath = path47.join(swarmDir, "plan-ledger.jsonl");
|
|
52309
53907
|
if (fs26.existsSync(existingLedgerPath)) {
|
|
52310
53908
|
fs26.unlinkSync(existingLedgerPath);
|
|
52311
53909
|
}
|
|
52312
53910
|
try {
|
|
52313
|
-
const planJsonPath =
|
|
53911
|
+
const planJsonPath = path47.join(swarmDir, "plan.json");
|
|
52314
53912
|
if (fs26.existsSync(planJsonPath)) {
|
|
52315
53913
|
const planRaw = fs26.readFileSync(planJsonPath, "utf-8");
|
|
52316
53914
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -52401,9 +53999,9 @@ Ensure this is a git repository with commit history.`;
|
|
|
52401
53999
|
`);
|
|
52402
54000
|
try {
|
|
52403
54001
|
const fs27 = await import("fs/promises");
|
|
52404
|
-
const
|
|
52405
|
-
const reportPath =
|
|
52406
|
-
await fs27.mkdir(
|
|
54002
|
+
const path48 = await import("path");
|
|
54003
|
+
const reportPath = path48.join(directory, ".swarm", "simulate-report.md");
|
|
54004
|
+
await fs27.mkdir(path48.dirname(reportPath), { recursive: true });
|
|
52407
54005
|
await fs27.writeFile(reportPath, report, "utf-8");
|
|
52408
54006
|
} catch (err) {
|
|
52409
54007
|
const writeErr = err instanceof Error ? err.message : String(err);
|
|
@@ -52427,12 +54025,12 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
52427
54025
|
|
|
52428
54026
|
// src/turbo/lean/state.ts
|
|
52429
54027
|
import * as fs27 from "fs";
|
|
52430
|
-
import * as
|
|
54028
|
+
import * as path48 from "path";
|
|
52431
54029
|
function nowISO2() {
|
|
52432
54030
|
return new Date().toISOString();
|
|
52433
54031
|
}
|
|
52434
54032
|
function ensureSwarmDir2(directory) {
|
|
52435
|
-
const swarmDir =
|
|
54033
|
+
const swarmDir = path48.resolve(directory, ".swarm");
|
|
52436
54034
|
if (!fs27.existsSync(swarmDir)) {
|
|
52437
54035
|
fs27.mkdirSync(swarmDir, { recursive: true });
|
|
52438
54036
|
}
|
|
@@ -52476,7 +54074,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
52476
54074
|
}
|
|
52477
54075
|
function readPersisted2(directory) {
|
|
52478
54076
|
try {
|
|
52479
|
-
const filePath =
|
|
54077
|
+
const filePath = path48.join(directory, ".swarm", STATE_FILE2);
|
|
52480
54078
|
if (!fs27.existsSync(filePath)) {
|
|
52481
54079
|
const seed = emptyPersisted2();
|
|
52482
54080
|
try {
|
|
@@ -52512,7 +54110,7 @@ function writePersisted2(directory, persisted) {
|
|
|
52512
54110
|
let payload;
|
|
52513
54111
|
try {
|
|
52514
54112
|
ensureSwarmDir2(directory);
|
|
52515
|
-
filePath =
|
|
54113
|
+
filePath = path48.join(directory, ".swarm", STATE_FILE2);
|
|
52516
54114
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
52517
54115
|
persisted.updatedAt = nowISO2();
|
|
52518
54116
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -52639,10 +54237,10 @@ var init_context_budget_service = __esm(() => {
|
|
|
52639
54237
|
|
|
52640
54238
|
// src/services/status-service.ts
|
|
52641
54239
|
import * as fsSync2 from "fs";
|
|
52642
|
-
import * as
|
|
54240
|
+
import * as path49 from "path";
|
|
52643
54241
|
function readSpecStalenessSnapshot(directory) {
|
|
52644
54242
|
try {
|
|
52645
|
-
const p =
|
|
54243
|
+
const p = path49.join(directory, ".swarm", "spec-staleness.json");
|
|
52646
54244
|
if (!fsSync2.existsSync(p))
|
|
52647
54245
|
return { stale: false };
|
|
52648
54246
|
const raw = fsSync2.readFileSync(p, "utf-8");
|
|
@@ -53168,7 +54766,7 @@ var init_write_retro2 = __esm(() => {
|
|
|
53168
54766
|
|
|
53169
54767
|
// src/commands/command-dispatch.ts
|
|
53170
54768
|
import fs28 from "fs";
|
|
53171
|
-
import
|
|
54769
|
+
import path50 from "path";
|
|
53172
54770
|
function normalizeSwarmCommandInput(command, argumentText) {
|
|
53173
54771
|
if (command !== "swarm" && !command.startsWith("swarm-")) {
|
|
53174
54772
|
return { isSwarmCommand: false, tokens: [] };
|
|
@@ -53204,9 +54802,9 @@ ${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
|
|
|
53204
54802
|
`);
|
|
53205
54803
|
}
|
|
53206
54804
|
function maybeMarkFirstRun(directory) {
|
|
53207
|
-
const sentinelPath =
|
|
54805
|
+
const sentinelPath = path50.join(directory, ".swarm", ".first-run-complete");
|
|
53208
54806
|
try {
|
|
53209
|
-
const swarmDir =
|
|
54807
|
+
const swarmDir = path50.join(directory, ".swarm");
|
|
53210
54808
|
fs28.mkdirSync(swarmDir, { recursive: true });
|
|
53211
54809
|
fs28.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
|
|
53212
54810
|
`, { flag: "wx" });
|
|
@@ -53315,6 +54913,14 @@ function classifySwarmCommandToolUse(resolved) {
|
|
|
53315
54913
|
message: "Only `/swarm knowledge` and `/swarm knowledge list` are available through swarm_command. Knowledge migrate/quarantine/restore are intentionally excluded."
|
|
53316
54914
|
};
|
|
53317
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
|
+
}
|
|
53318
54924
|
if (canonicalKey === "retrieve") {
|
|
53319
54925
|
if (args.length !== 1 || !SUMMARY_ID_PATTERN.test(args[0])) {
|
|
53320
54926
|
return {
|
|
@@ -53366,10 +54972,10 @@ function classifySwarmCommandChatFallbackUse(resolved) {
|
|
|
53366
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."
|
|
53367
54973
|
};
|
|
53368
54974
|
}
|
|
53369
|
-
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") {
|
|
53370
54976
|
return {
|
|
53371
54977
|
allowed: false,
|
|
53372
|
-
message: `/swarm ${canonicalKey} is not available through chat fallback because it mutates .swarm
|
|
54978
|
+
message: `/swarm ${canonicalKey} is not available through chat fallback because it mutates .swarm state. ` + "Run the CLI command directly after confirming the intended state change."
|
|
53373
54979
|
};
|
|
53374
54980
|
}
|
|
53375
54981
|
return { allowed: true };
|
|
@@ -53397,6 +55003,11 @@ var init_tool_policy = __esm(() => {
|
|
|
53397
55003
|
"preflight",
|
|
53398
55004
|
"benchmark",
|
|
53399
55005
|
"knowledge",
|
|
55006
|
+
"memory",
|
|
55007
|
+
"memory status",
|
|
55008
|
+
"memory export",
|
|
55009
|
+
"memory import",
|
|
55010
|
+
"memory migrate",
|
|
53400
55011
|
"sync-plan",
|
|
53401
55012
|
"export",
|
|
53402
55013
|
"list-agents"
|
|
@@ -53417,6 +55028,9 @@ var init_tool_policy = __esm(() => {
|
|
|
53417
55028
|
"preflight",
|
|
53418
55029
|
"benchmark",
|
|
53419
55030
|
"knowledge",
|
|
55031
|
+
"memory",
|
|
55032
|
+
"memory status",
|
|
55033
|
+
"memory export",
|
|
53420
55034
|
"sync-plan",
|
|
53421
55035
|
"export"
|
|
53422
55036
|
]);
|
|
@@ -53425,7 +55039,9 @@ var init_tool_policy = __esm(() => {
|
|
|
53425
55039
|
"reset",
|
|
53426
55040
|
"reset-session",
|
|
53427
55041
|
"rollback",
|
|
53428
|
-
"checkpoint"
|
|
55042
|
+
"checkpoint",
|
|
55043
|
+
"memory import",
|
|
55044
|
+
"memory migrate"
|
|
53429
55045
|
]);
|
|
53430
55046
|
NO_ARGS = new Set([
|
|
53431
55047
|
"agents",
|
|
@@ -53438,7 +55054,10 @@ var init_tool_policy = __esm(() => {
|
|
|
53438
55054
|
"diagnose",
|
|
53439
55055
|
"preflight",
|
|
53440
55056
|
"sync-plan",
|
|
53441
|
-
"export"
|
|
55057
|
+
"export",
|
|
55058
|
+
"memory",
|
|
55059
|
+
"memory status",
|
|
55060
|
+
"memory export"
|
|
53442
55061
|
]);
|
|
53443
55062
|
SUMMARY_ID_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
53444
55063
|
TASK_ID_PATTERN = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
@@ -53471,6 +55090,11 @@ __export(exports_commands, {
|
|
|
53471
55090
|
handlePromoteCommand: () => handlePromoteCommand,
|
|
53472
55091
|
handlePreflightCommand: () => handlePreflightCommand,
|
|
53473
55092
|
handlePlanCommand: () => handlePlanCommand,
|
|
55093
|
+
handleMemoryStatusCommand: () => handleMemoryStatusCommand,
|
|
55094
|
+
handleMemoryMigrateCommand: () => handleMemoryMigrateCommand,
|
|
55095
|
+
handleMemoryImportCommand: () => handleMemoryImportCommand,
|
|
55096
|
+
handleMemoryExportCommand: () => handleMemoryExportCommand,
|
|
55097
|
+
handleMemoryCommand: () => handleMemoryCommand,
|
|
53474
55098
|
handleKnowledgeRestoreCommand: () => handleKnowledgeRestoreCommand,
|
|
53475
55099
|
handleKnowledgeQuarantineCommand: () => handleKnowledgeQuarantineCommand,
|
|
53476
55100
|
handleKnowledgeMigrateCommand: () => handleKnowledgeMigrateCommand,
|
|
@@ -53748,6 +55372,7 @@ var init_commands = __esm(() => {
|
|
|
53748
55372
|
init_handoff();
|
|
53749
55373
|
init_history();
|
|
53750
55374
|
init_knowledge();
|
|
55375
|
+
init_memory2();
|
|
53751
55376
|
init_plan();
|
|
53752
55377
|
init_preflight();
|
|
53753
55378
|
init_promote();
|
|
@@ -53888,24 +55513,24 @@ function validateAliases() {
|
|
|
53888
55513
|
}
|
|
53889
55514
|
aliasTargets.get(target).push(name);
|
|
53890
55515
|
const visited = new Set;
|
|
53891
|
-
const
|
|
55516
|
+
const path51 = [];
|
|
53892
55517
|
let current = target;
|
|
53893
55518
|
while (current) {
|
|
53894
55519
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
53895
55520
|
if (!currentEntry)
|
|
53896
55521
|
break;
|
|
53897
55522
|
if (visited.has(current)) {
|
|
53898
|
-
const cycleStart =
|
|
55523
|
+
const cycleStart = path51.indexOf(current);
|
|
53899
55524
|
const fullChain = [
|
|
53900
55525
|
name,
|
|
53901
|
-
...
|
|
55526
|
+
...path51.slice(0, cycleStart > 0 ? cycleStart : path51.length),
|
|
53902
55527
|
current
|
|
53903
55528
|
].join(" \u2192 ");
|
|
53904
55529
|
errors5.push(`Circular alias detected: ${fullChain}`);
|
|
53905
55530
|
break;
|
|
53906
55531
|
}
|
|
53907
55532
|
visited.add(current);
|
|
53908
|
-
|
|
55533
|
+
path51.push(current);
|
|
53909
55534
|
current = currentEntry.aliasOf || "";
|
|
53910
55535
|
}
|
|
53911
55536
|
}
|
|
@@ -53968,6 +55593,7 @@ var init_registry = __esm(() => {
|
|
|
53968
55593
|
init_history();
|
|
53969
55594
|
init_issue();
|
|
53970
55595
|
init_knowledge();
|
|
55596
|
+
init_memory2();
|
|
53971
55597
|
init_plan();
|
|
53972
55598
|
init_pr_review();
|
|
53973
55599
|
init_preflight();
|
|
@@ -54378,6 +56004,39 @@ Subcommands:
|
|
|
54378
56004
|
description: "List knowledge entries",
|
|
54379
56005
|
category: "utility"
|
|
54380
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
|
+
},
|
|
54381
56040
|
checkpoint: {
|
|
54382
56041
|
handler: (ctx) => handleCheckpointCommand(ctx.directory, ctx.args),
|
|
54383
56042
|
description: "Manage project checkpoints [save|restore|delete|list] <label>",
|
|
@@ -54416,53 +56075,53 @@ init_cache_paths();
|
|
|
54416
56075
|
init_constants();
|
|
54417
56076
|
import * as fs29 from "fs";
|
|
54418
56077
|
import * as os7 from "os";
|
|
54419
|
-
import * as
|
|
56078
|
+
import * as path51 from "path";
|
|
54420
56079
|
var { version: version4 } = package_default;
|
|
54421
56080
|
var CONFIG_DIR = getPluginConfigDir();
|
|
54422
|
-
var OPENCODE_CONFIG_PATH =
|
|
54423
|
-
var PLUGIN_CONFIG_PATH =
|
|
54424
|
-
var PROMPTS_DIR =
|
|
56081
|
+
var OPENCODE_CONFIG_PATH = path51.join(CONFIG_DIR, "opencode.json");
|
|
56082
|
+
var PLUGIN_CONFIG_PATH = path51.join(CONFIG_DIR, "opencode-swarm.json");
|
|
56083
|
+
var PROMPTS_DIR = path51.join(CONFIG_DIR, "opencode-swarm");
|
|
54425
56084
|
var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
54426
56085
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
54427
56086
|
function isSafeCachePath(p) {
|
|
54428
|
-
const resolved =
|
|
54429
|
-
const home =
|
|
56087
|
+
const resolved = path51.resolve(p);
|
|
56088
|
+
const home = path51.resolve(os7.homedir());
|
|
54430
56089
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
54431
56090
|
return false;
|
|
54432
56091
|
}
|
|
54433
|
-
const segments = resolved.split(
|
|
56092
|
+
const segments = resolved.split(path51.sep).filter((s) => s.length > 0);
|
|
54434
56093
|
if (segments.length < 4) {
|
|
54435
56094
|
return false;
|
|
54436
56095
|
}
|
|
54437
|
-
const leaf =
|
|
56096
|
+
const leaf = path51.basename(resolved);
|
|
54438
56097
|
if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
|
|
54439
56098
|
return false;
|
|
54440
56099
|
}
|
|
54441
|
-
const parent =
|
|
56100
|
+
const parent = path51.basename(path51.dirname(resolved));
|
|
54442
56101
|
if (parent !== "packages" && parent !== "node_modules") {
|
|
54443
56102
|
return false;
|
|
54444
56103
|
}
|
|
54445
|
-
const grandparent =
|
|
56104
|
+
const grandparent = path51.basename(path51.dirname(path51.dirname(resolved)));
|
|
54446
56105
|
if (grandparent !== "opencode") {
|
|
54447
56106
|
return false;
|
|
54448
56107
|
}
|
|
54449
56108
|
return true;
|
|
54450
56109
|
}
|
|
54451
56110
|
function isSafeLockFilePath(p) {
|
|
54452
|
-
const resolved =
|
|
54453
|
-
const home =
|
|
56111
|
+
const resolved = path51.resolve(p);
|
|
56112
|
+
const home = path51.resolve(os7.homedir());
|
|
54454
56113
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
54455
56114
|
return false;
|
|
54456
56115
|
}
|
|
54457
|
-
const segments = resolved.split(
|
|
56116
|
+
const segments = resolved.split(path51.sep).filter((s) => s.length > 0);
|
|
54458
56117
|
if (segments.length < 4) {
|
|
54459
56118
|
return false;
|
|
54460
56119
|
}
|
|
54461
|
-
const leaf =
|
|
56120
|
+
const leaf = path51.basename(resolved);
|
|
54462
56121
|
if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
|
|
54463
56122
|
return false;
|
|
54464
56123
|
}
|
|
54465
|
-
const parent =
|
|
56124
|
+
const parent = path51.basename(path51.dirname(resolved));
|
|
54466
56125
|
if (parent !== "opencode") {
|
|
54467
56126
|
return false;
|
|
54468
56127
|
}
|
|
@@ -54488,8 +56147,8 @@ function saveJson(filepath, data) {
|
|
|
54488
56147
|
}
|
|
54489
56148
|
function writeProjectConfigIfMissing(cwd) {
|
|
54490
56149
|
try {
|
|
54491
|
-
const opencodeDir =
|
|
54492
|
-
const projectConfigPath =
|
|
56150
|
+
const opencodeDir = path51.join(cwd, ".opencode");
|
|
56151
|
+
const projectConfigPath = path51.join(opencodeDir, "opencode-swarm.json");
|
|
54493
56152
|
if (fs29.existsSync(projectConfigPath)) {
|
|
54494
56153
|
return;
|
|
54495
56154
|
}
|
|
@@ -54506,7 +56165,7 @@ async function install() {
|
|
|
54506
56165
|
`);
|
|
54507
56166
|
ensureDir(CONFIG_DIR);
|
|
54508
56167
|
ensureDir(PROMPTS_DIR);
|
|
54509
|
-
const LEGACY_CONFIG_PATH =
|
|
56168
|
+
const LEGACY_CONFIG_PATH = path51.join(CONFIG_DIR, "config.json");
|
|
54510
56169
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
54511
56170
|
if (!opencodeConfig) {
|
|
54512
56171
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|