opencode-swarm 6.39.0 → 6.40.1
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/LICENSE +21 -21
- package/README.md +1 -1
- package/dist/cli/index.js +177 -36
- package/dist/commands/index.d.ts +1 -1
- package/dist/config/plan-schema.d.ts +2 -0
- package/dist/config/schema.d.ts +3 -2
- package/dist/index.js +559 -150
- package/dist/lang/grammars/tree-sitter-bash.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-c-sharp.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-cpp.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-css.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-go.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-ini.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-java.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-javascript.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-php.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-powershell.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-python.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-regex.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-ruby.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-rust.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/lang/grammars/tree-sitter.wasm +0 -0
- package/dist/services/compaction-service.d.ts +2 -2
- package/dist/session/snapshot-reader.d.ts +8 -0
- package/dist/tools/save-plan.d.ts +1 -0
- package/package.json +4 -1
- /package/dist/commands/{write_retro.d.ts → write-retro.d.ts} +0 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Most AI coding tools let one model write code and ask that same model whether th
|
|
|
27
27
|
### Key Features
|
|
28
28
|
|
|
29
29
|
- 🏗️ **11 specialized agents** — architect, coder, reviewer, test engineer, critic, critic_sounding_board, critic_drift_verifier, explorer, SME, docs, designer
|
|
30
|
-
- 🔒 **Gated pipeline** — code never ships without reviewer + test engineer approval
|
|
30
|
+
- 🔒 **Gated pipeline** — code never ships without reviewer + test engineer approval (bypassed in turbo mode)
|
|
31
31
|
- 🔄 **Phase completion gates** — completion-verify and drift verifier gates enforced before phase completion (bypassed in turbo mode)
|
|
32
32
|
- 🔁 **Resumable sessions** — all state saved to `.swarm/`; pick up any project any day
|
|
33
33
|
- 🌐 **11 languages** — TypeScript, Python, Go, Rust, Java, Kotlin, C#, C/C++, Swift, Dart, Ruby
|
package/dist/cli/index.js
CHANGED
|
@@ -5,25 +5,43 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
8
13
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
9
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
22
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
23
|
for (let key of __getOwnPropNames(mod))
|
|
12
24
|
if (!__hasOwnProp.call(to, key))
|
|
13
25
|
__defProp(to, key, {
|
|
14
|
-
get: (
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
15
27
|
enumerable: true
|
|
16
28
|
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
17
31
|
return to;
|
|
18
32
|
};
|
|
19
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
+
var __returnValue = (v) => v;
|
|
35
|
+
function __exportSetter(name, newValue) {
|
|
36
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
+
}
|
|
20
38
|
var __export = (target, all) => {
|
|
21
39
|
for (var name in all)
|
|
22
40
|
__defProp(target, name, {
|
|
23
41
|
get: all[name],
|
|
24
42
|
enumerable: true,
|
|
25
43
|
configurable: true,
|
|
26
|
-
set: (
|
|
44
|
+
set: __exportSetter.bind(all, name)
|
|
27
45
|
});
|
|
28
46
|
};
|
|
29
47
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -14572,7 +14590,8 @@ var init_plan_schema = __esm(() => {
|
|
|
14572
14590
|
id: exports_external.number().int().min(1),
|
|
14573
14591
|
name: exports_external.string().min(1),
|
|
14574
14592
|
status: PhaseStatusSchema.default("pending"),
|
|
14575
|
-
tasks: exports_external.array(TaskSchema).default([])
|
|
14593
|
+
tasks: exports_external.array(TaskSchema).default([]),
|
|
14594
|
+
required_agents: exports_external.array(exports_external.string()).optional()
|
|
14576
14595
|
});
|
|
14577
14596
|
PlanSchema = exports_external.object({
|
|
14578
14597
|
schema_version: exports_external.literal("1.0.0"),
|
|
@@ -17301,8 +17320,8 @@ function getTaskBlockers(task, summary, status) {
|
|
|
17301
17320
|
}
|
|
17302
17321
|
return blockers;
|
|
17303
17322
|
}
|
|
17304
|
-
async function buildTaskSummary(task, taskId) {
|
|
17305
|
-
const result = await loadEvidence(
|
|
17323
|
+
async function buildTaskSummary(directory, task, taskId) {
|
|
17324
|
+
const result = await loadEvidence(directory, taskId);
|
|
17306
17325
|
const bundle = result.status === "found" ? result.bundle : null;
|
|
17307
17326
|
const phase = task?.phase ?? 0;
|
|
17308
17327
|
const status = getTaskStatus(task, bundle);
|
|
@@ -17331,18 +17350,18 @@ async function buildTaskSummary(task, taskId) {
|
|
|
17331
17350
|
lastEvidenceTimestamp: lastTimestamp
|
|
17332
17351
|
};
|
|
17333
17352
|
}
|
|
17334
|
-
async function buildPhaseSummary(phase) {
|
|
17335
|
-
const taskIds = await listEvidenceTaskIds(
|
|
17353
|
+
async function buildPhaseSummary(directory, phase) {
|
|
17354
|
+
const taskIds = await listEvidenceTaskIds(directory);
|
|
17336
17355
|
const phaseTaskIds = new Set(phase.tasks.map((t) => t.id));
|
|
17337
17356
|
const taskSummaries = [];
|
|
17338
17357
|
const _taskMap = new Map(phase.tasks.map((t) => [t.id, t]));
|
|
17339
17358
|
for (const task of phase.tasks) {
|
|
17340
|
-
const summary = await buildTaskSummary(task, task.id);
|
|
17359
|
+
const summary = await buildTaskSummary(directory, task, task.id);
|
|
17341
17360
|
taskSummaries.push(summary);
|
|
17342
17361
|
}
|
|
17343
17362
|
const extraTaskIds = taskIds.filter((id) => !phaseTaskIds.has(id));
|
|
17344
17363
|
for (const taskId of extraTaskIds) {
|
|
17345
|
-
const summary = await buildTaskSummary(undefined, taskId);
|
|
17364
|
+
const summary = await buildTaskSummary(directory, undefined, taskId);
|
|
17346
17365
|
if (summary.phase === phase.id) {
|
|
17347
17366
|
taskSummaries.push(summary);
|
|
17348
17367
|
}
|
|
@@ -17443,7 +17462,7 @@ async function buildEvidenceSummary(directory, currentPhase) {
|
|
|
17443
17462
|
let totalTasks = 0;
|
|
17444
17463
|
let completedTasks = 0;
|
|
17445
17464
|
for (const phase of phasesToProcess) {
|
|
17446
|
-
const summary = await buildPhaseSummary(phase);
|
|
17465
|
+
const summary = await buildPhaseSummary(directory, phase);
|
|
17447
17466
|
phaseSummaries.push(summary);
|
|
17448
17467
|
totalTasks += summary.totalTasks;
|
|
17449
17468
|
completedTasks += summary.completedTasks;
|
|
@@ -18161,8 +18180,8 @@ var PlanCursorConfigSchema = exports_external.object({
|
|
|
18161
18180
|
});
|
|
18162
18181
|
var CheckpointConfigSchema = exports_external.object({
|
|
18163
18182
|
enabled: exports_external.boolean().default(true),
|
|
18164
|
-
auto_checkpoint_threshold: exports_external.number().min(1).max(20).default(3)
|
|
18165
|
-
});
|
|
18183
|
+
auto_checkpoint_threshold: exports_external.number().int().min(1).max(20).default(3)
|
|
18184
|
+
}).strict();
|
|
18166
18185
|
var AutomationModeSchema = exports_external.enum(["manual", "hybrid", "auto"]);
|
|
18167
18186
|
var AutomationCapabilitiesSchema = exports_external.object({
|
|
18168
18187
|
plan_sync: exports_external.boolean().default(true),
|
|
@@ -18282,7 +18301,8 @@ var PluginConfigSchema = exports_external.object({
|
|
|
18282
18301
|
block_on_threshold: exports_external.boolean().default(false).describe("If true, block phase completion when threshold exceeded. Default: advisory only.")
|
|
18283
18302
|
}).optional(),
|
|
18284
18303
|
incremental_verify: IncrementalVerifyConfigSchema.optional(),
|
|
18285
|
-
compaction_service: CompactionConfigSchema.optional()
|
|
18304
|
+
compaction_service: CompactionConfigSchema.optional(),
|
|
18305
|
+
turbo_mode: exports_external.boolean().default(false).optional()
|
|
18286
18306
|
});
|
|
18287
18307
|
|
|
18288
18308
|
// src/config/loader.ts
|
|
@@ -18385,6 +18405,15 @@ function loadPluginConfig(directory) {
|
|
|
18385
18405
|
}
|
|
18386
18406
|
return result.data;
|
|
18387
18407
|
}
|
|
18408
|
+
function loadPluginConfigWithMeta(directory) {
|
|
18409
|
+
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
18410
|
+
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
18411
|
+
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
18412
|
+
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
18413
|
+
const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
|
|
18414
|
+
const config2 = loadPluginConfig(directory);
|
|
18415
|
+
return { config: config2, loadedFromFile };
|
|
18416
|
+
}
|
|
18388
18417
|
|
|
18389
18418
|
// src/commands/archive.ts
|
|
18390
18419
|
init_manager();
|
|
@@ -18807,6 +18836,9 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
18807
18836
|
`);
|
|
18808
18837
|
}
|
|
18809
18838
|
|
|
18839
|
+
// src/commands/checkpoint.ts
|
|
18840
|
+
init_zod();
|
|
18841
|
+
|
|
18810
18842
|
// src/tools/checkpoint.ts
|
|
18811
18843
|
import { spawnSync } from "child_process";
|
|
18812
18844
|
import * as fs3 from "fs";
|
|
@@ -31132,6 +31164,10 @@ function tool(input) {
|
|
|
31132
31164
|
return input;
|
|
31133
31165
|
}
|
|
31134
31166
|
tool.schema = exports_external2;
|
|
31167
|
+
|
|
31168
|
+
// src/config/index.ts
|
|
31169
|
+
init_evidence_schema();
|
|
31170
|
+
init_plan_schema();
|
|
31135
31171
|
// src/tools/create-tool.ts
|
|
31136
31172
|
function createSwarmTool(opts) {
|
|
31137
31173
|
return tool({
|
|
@@ -31256,6 +31292,11 @@ function isGitRepo() {
|
|
|
31256
31292
|
}
|
|
31257
31293
|
function handleSave(label, directory) {
|
|
31258
31294
|
try {
|
|
31295
|
+
let maxCheckpoints = 20;
|
|
31296
|
+
try {
|
|
31297
|
+
const { config: config3 } = loadPluginConfigWithMeta(directory);
|
|
31298
|
+
maxCheckpoints = config3.checkpoint?.auto_checkpoint_threshold ?? maxCheckpoints;
|
|
31299
|
+
} catch {}
|
|
31259
31300
|
const log2 = readCheckpointLog(directory);
|
|
31260
31301
|
const existingCheckpoint = log2.checkpoints.find((c) => c.label === label);
|
|
31261
31302
|
if (existingCheckpoint) {
|
|
@@ -31375,7 +31416,7 @@ var checkpoint = createSwarmTool({
|
|
|
31375
31416
|
let label;
|
|
31376
31417
|
try {
|
|
31377
31418
|
action = String(args.action);
|
|
31378
|
-
label = args.label !== undefined ? String(args.label) : undefined;
|
|
31419
|
+
label = args.label !== undefined && args.label !== null ? String(args.label) : undefined;
|
|
31379
31420
|
} catch {
|
|
31380
31421
|
return JSON.stringify({
|
|
31381
31422
|
action: "unknown",
|
|
@@ -31428,6 +31469,22 @@ var checkpoint = createSwarmTool({
|
|
|
31428
31469
|
});
|
|
31429
31470
|
|
|
31430
31471
|
// src/commands/checkpoint.ts
|
|
31472
|
+
var CheckpointResultSchema = exports_external.object({
|
|
31473
|
+
action: exports_external.string().optional(),
|
|
31474
|
+
success: exports_external.boolean(),
|
|
31475
|
+
error: exports_external.string().optional(),
|
|
31476
|
+
checkpoints: exports_external.array(exports_external.unknown()).optional()
|
|
31477
|
+
}).passthrough();
|
|
31478
|
+
function safeParseResult(result) {
|
|
31479
|
+
const parsed = CheckpointResultSchema.safeParse(JSON.parse(result));
|
|
31480
|
+
if (!parsed.success) {
|
|
31481
|
+
return {
|
|
31482
|
+
success: false,
|
|
31483
|
+
error: `Invalid response: ${parsed.error.message}`
|
|
31484
|
+
};
|
|
31485
|
+
}
|
|
31486
|
+
return parsed.data;
|
|
31487
|
+
}
|
|
31431
31488
|
async function handleCheckpointCommand(directory, args) {
|
|
31432
31489
|
const subcommand = args[0] || "list";
|
|
31433
31490
|
const label = args[1];
|
|
@@ -31450,7 +31507,7 @@ async function handleSave2(directory, label) {
|
|
|
31450
31507
|
const result = await checkpoint.execute({ action: "save", label }, {
|
|
31451
31508
|
directory
|
|
31452
31509
|
});
|
|
31453
|
-
const parsed =
|
|
31510
|
+
const parsed = safeParseResult(result);
|
|
31454
31511
|
if (parsed.success) {
|
|
31455
31512
|
return `\u2713 Checkpoint saved: "${label}"`;
|
|
31456
31513
|
} else {
|
|
@@ -31469,7 +31526,7 @@ async function handleRestore2(directory, label) {
|
|
|
31469
31526
|
const result = await checkpoint.execute({ action: "restore", label }, {
|
|
31470
31527
|
directory
|
|
31471
31528
|
});
|
|
31472
|
-
const parsed =
|
|
31529
|
+
const parsed = safeParseResult(result);
|
|
31473
31530
|
if (parsed.success) {
|
|
31474
31531
|
return `\u2713 Restored to checkpoint: "${label}"`;
|
|
31475
31532
|
} else {
|
|
@@ -31488,7 +31545,7 @@ async function handleDelete2(directory, label) {
|
|
|
31488
31545
|
const result = await checkpoint.execute({ action: "delete", label }, {
|
|
31489
31546
|
directory
|
|
31490
31547
|
});
|
|
31491
|
-
const parsed =
|
|
31548
|
+
const parsed = safeParseResult(result);
|
|
31492
31549
|
if (parsed.success) {
|
|
31493
31550
|
return `\u2713 Checkpoint deleted: "${label}"`;
|
|
31494
31551
|
} else {
|
|
@@ -31504,7 +31561,7 @@ async function handleList2(directory) {
|
|
|
31504
31561
|
const result = await checkpoint.execute({ action: "list" }, {
|
|
31505
31562
|
directory
|
|
31506
31563
|
});
|
|
31507
|
-
const parsed =
|
|
31564
|
+
const parsed = safeParseResult(result);
|
|
31508
31565
|
if (!parsed.success) {
|
|
31509
31566
|
return `Error: ${parsed.error || "Failed to list checkpoints"}`;
|
|
31510
31567
|
}
|
|
@@ -34202,7 +34259,8 @@ async function extractFromLegacy(directory) {
|
|
|
34202
34259
|
mappedStatus = "complete";
|
|
34203
34260
|
else if (status === "IN PROGRESS")
|
|
34204
34261
|
mappedStatus = "in_progress";
|
|
34205
|
-
const headerLineIndex =
|
|
34262
|
+
const headerLineIndex = planContent.substring(0, match.index).split(`
|
|
34263
|
+
`).length - 1;
|
|
34206
34264
|
let completed = 0;
|
|
34207
34265
|
let total = 0;
|
|
34208
34266
|
if (headerLineIndex !== -1) {
|
|
@@ -34597,9 +34655,9 @@ async function getPlanData(directory, phaseArg) {
|
|
|
34597
34655
|
return {
|
|
34598
34656
|
hasPlan: true,
|
|
34599
34657
|
fullMarkdown,
|
|
34600
|
-
requestedPhase:
|
|
34658
|
+
requestedPhase: null,
|
|
34601
34659
|
phaseMarkdown: null,
|
|
34602
|
-
errorMessage:
|
|
34660
|
+
errorMessage: `Invalid phase number: "${phaseArg}"`,
|
|
34603
34661
|
isLegacy: false
|
|
34604
34662
|
};
|
|
34605
34663
|
}
|
|
@@ -34650,9 +34708,9 @@ async function getPlanData(directory, phaseArg) {
|
|
|
34650
34708
|
return {
|
|
34651
34709
|
hasPlan: true,
|
|
34652
34710
|
fullMarkdown: planContent,
|
|
34653
|
-
requestedPhase:
|
|
34711
|
+
requestedPhase: null,
|
|
34654
34712
|
phaseMarkdown: null,
|
|
34655
|
-
errorMessage:
|
|
34713
|
+
errorMessage: `Invalid phase number: "${phaseArg}"`,
|
|
34656
34714
|
isLegacy: true
|
|
34657
34715
|
};
|
|
34658
34716
|
}
|
|
@@ -35591,6 +35649,59 @@ LANGUAGE_REGISTRY.register({
|
|
|
35591
35649
|
]
|
|
35592
35650
|
}
|
|
35593
35651
|
});
|
|
35652
|
+
LANGUAGE_REGISTRY.register({
|
|
35653
|
+
id: "php",
|
|
35654
|
+
displayName: "PHP",
|
|
35655
|
+
tier: 3,
|
|
35656
|
+
extensions: [".php", ".phtml"],
|
|
35657
|
+
treeSitter: { grammarId: "php", wasmFile: "tree-sitter-php.wasm" },
|
|
35658
|
+
build: {
|
|
35659
|
+
detectFiles: ["composer.json"],
|
|
35660
|
+
commands: []
|
|
35661
|
+
},
|
|
35662
|
+
test: {
|
|
35663
|
+
detectFiles: ["phpunit.xml", "phpunit.xml.dist"],
|
|
35664
|
+
frameworks: [
|
|
35665
|
+
{
|
|
35666
|
+
name: "PHPUnit",
|
|
35667
|
+
detect: "phpunit.xml",
|
|
35668
|
+
cmd: "vendor/bin/phpunit",
|
|
35669
|
+
priority: 1
|
|
35670
|
+
}
|
|
35671
|
+
]
|
|
35672
|
+
},
|
|
35673
|
+
lint: {
|
|
35674
|
+
detectFiles: [".php-cs-fixer.php", "phpcs.xml"],
|
|
35675
|
+
linters: [
|
|
35676
|
+
{
|
|
35677
|
+
name: "PHP-CS-Fixer",
|
|
35678
|
+
detect: ".php-cs-fixer.php",
|
|
35679
|
+
cmd: "vendor/bin/php-cs-fixer fix --dry-run --diff",
|
|
35680
|
+
priority: 1
|
|
35681
|
+
}
|
|
35682
|
+
]
|
|
35683
|
+
},
|
|
35684
|
+
audit: {
|
|
35685
|
+
detectFiles: ["composer.lock"],
|
|
35686
|
+
command: "composer audit --format=json",
|
|
35687
|
+
outputFormat: "json"
|
|
35688
|
+
},
|
|
35689
|
+
sast: { nativeRuleSet: "php", semgrepSupport: "ga" },
|
|
35690
|
+
prompts: {
|
|
35691
|
+
coderConstraints: [
|
|
35692
|
+
"Follow PSR-12 coding standards",
|
|
35693
|
+
"Use strict types declaration: declare(strict_types=1)",
|
|
35694
|
+
"Prefer type hints and return type declarations on all functions",
|
|
35695
|
+
"Use dependency injection over static methods and singletons"
|
|
35696
|
+
],
|
|
35697
|
+
reviewerChecklist: [
|
|
35698
|
+
"Verify no user input reaches SQL queries without parameterised binding",
|
|
35699
|
+
"Check for XSS \u2014 all output must be escaped with htmlspecialchars()",
|
|
35700
|
+
"Confirm no eval(), exec(), or shell_exec() with user-controlled input",
|
|
35701
|
+
"Validate proper error handling \u2014 no bare catch blocks that swallow errors"
|
|
35702
|
+
]
|
|
35703
|
+
}
|
|
35704
|
+
});
|
|
35594
35705
|
|
|
35595
35706
|
// src/lang/detector.ts
|
|
35596
35707
|
async function detectProjectLanguages(projectDir) {
|
|
@@ -36174,7 +36285,7 @@ async function detectAvailableLinter(directory) {
|
|
|
36174
36285
|
async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
36175
36286
|
const DETECT_TIMEOUT = 2000;
|
|
36176
36287
|
try {
|
|
36177
|
-
const biomeProc = Bun.spawn([
|
|
36288
|
+
const biomeProc = Bun.spawn([biomeBin, "--version"], {
|
|
36178
36289
|
stdout: "pipe",
|
|
36179
36290
|
stderr: "pipe"
|
|
36180
36291
|
});
|
|
@@ -36188,7 +36299,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
36188
36299
|
}
|
|
36189
36300
|
} catch {}
|
|
36190
36301
|
try {
|
|
36191
|
-
const eslintProc = Bun.spawn([
|
|
36302
|
+
const eslintProc = Bun.spawn([eslintBin, "--version"], {
|
|
36192
36303
|
stdout: "pipe",
|
|
36193
36304
|
stderr: "pipe"
|
|
36194
36305
|
});
|
|
@@ -38205,12 +38316,13 @@ async function runLintCheck(dir, linter, timeoutMs) {
|
|
|
38205
38316
|
const startTime = Date.now();
|
|
38206
38317
|
try {
|
|
38207
38318
|
const lintPromise = runLint(linter, "check", dir);
|
|
38319
|
+
let timeoutId;
|
|
38208
38320
|
const timeoutPromise = new Promise((_, reject) => {
|
|
38209
|
-
setTimeout(() => {
|
|
38321
|
+
timeoutId = setTimeout(() => {
|
|
38210
38322
|
reject(new Error(`Lint check timed out after ${timeoutMs}ms`));
|
|
38211
38323
|
}, timeoutMs);
|
|
38212
38324
|
});
|
|
38213
|
-
const result = await Promise.race([lintPromise, timeoutPromise]);
|
|
38325
|
+
const result = await Promise.race([lintPromise, timeoutPromise]).finally(() => clearTimeout(timeoutId));
|
|
38214
38326
|
if (!result.success) {
|
|
38215
38327
|
return {
|
|
38216
38328
|
type: "lint",
|
|
@@ -39720,12 +39832,32 @@ function makeInitialState() {
|
|
|
39720
39832
|
lastSnapshotAt: null
|
|
39721
39833
|
};
|
|
39722
39834
|
}
|
|
39723
|
-
var
|
|
39724
|
-
function
|
|
39725
|
-
|
|
39726
|
-
|
|
39727
|
-
|
|
39728
|
-
|
|
39835
|
+
var sessionStates = new Map;
|
|
39836
|
+
function getSessionState(sessionId) {
|
|
39837
|
+
let state = sessionStates.get(sessionId);
|
|
39838
|
+
if (!state) {
|
|
39839
|
+
state = makeInitialState();
|
|
39840
|
+
sessionStates.set(sessionId, state);
|
|
39841
|
+
}
|
|
39842
|
+
return state;
|
|
39843
|
+
}
|
|
39844
|
+
function getCompactionMetrics(sessionId) {
|
|
39845
|
+
if (sessionId) {
|
|
39846
|
+
const state = getSessionState(sessionId);
|
|
39847
|
+
return {
|
|
39848
|
+
compactionCount: state.observationCount + state.reflectionCount + state.emergencyCount,
|
|
39849
|
+
lastSnapshotAt: state.lastSnapshotAt
|
|
39850
|
+
};
|
|
39851
|
+
}
|
|
39852
|
+
let total = 0;
|
|
39853
|
+
let lastSnapshot = null;
|
|
39854
|
+
for (const state of sessionStates.values()) {
|
|
39855
|
+
total += state.observationCount + state.reflectionCount + state.emergencyCount;
|
|
39856
|
+
if (state.lastSnapshotAt && (!lastSnapshot || state.lastSnapshotAt > lastSnapshot)) {
|
|
39857
|
+
lastSnapshot = state.lastSnapshotAt;
|
|
39858
|
+
}
|
|
39859
|
+
}
|
|
39860
|
+
return { compactionCount: total, lastSnapshotAt: lastSnapshot };
|
|
39729
39861
|
}
|
|
39730
39862
|
|
|
39731
39863
|
// src/services/context-budget-service.ts
|
|
@@ -39888,6 +40020,7 @@ async function handleTurboCommand(_directory, args, sessionID) {
|
|
|
39888
40020
|
}
|
|
39889
40021
|
|
|
39890
40022
|
// src/tools/write-retro.ts
|
|
40023
|
+
init_evidence_schema();
|
|
39891
40024
|
init_manager();
|
|
39892
40025
|
async function executeWriteRetro(args, directory) {
|
|
39893
40026
|
const phase = args.phase;
|
|
@@ -40121,8 +40254,9 @@ async function executeWriteRetro(args, directory) {
|
|
|
40121
40254
|
};
|
|
40122
40255
|
const taxonomy = [];
|
|
40123
40256
|
try {
|
|
40124
|
-
|
|
40125
|
-
|
|
40257
|
+
const allTaskIds = await listEvidenceTaskIds(directory);
|
|
40258
|
+
const phaseTaskIds = allTaskIds.filter((id) => id.startsWith(`${phase}.`));
|
|
40259
|
+
for (const phaseTaskId of phaseTaskIds) {
|
|
40126
40260
|
const result = await loadEvidence(directory, phaseTaskId);
|
|
40127
40261
|
if (result.status !== "found")
|
|
40128
40262
|
continue;
|
|
@@ -40156,6 +40290,13 @@ async function executeWriteRetro(args, directory) {
|
|
|
40156
40290
|
}
|
|
40157
40291
|
} catch {}
|
|
40158
40292
|
retroEntry.error_taxonomy = [...new Set(taxonomy)];
|
|
40293
|
+
const validationResult = RetrospectiveEvidenceSchema.safeParse(retroEntry);
|
|
40294
|
+
if (!validationResult.success) {
|
|
40295
|
+
return JSON.stringify({
|
|
40296
|
+
success: false,
|
|
40297
|
+
error: `Retrospective entry failed validation: ${validationResult.error.message}`
|
|
40298
|
+
}, null, 2);
|
|
40299
|
+
}
|
|
40159
40300
|
try {
|
|
40160
40301
|
await saveEvidence(directory, taskId, retroEntry);
|
|
40161
40302
|
return JSON.stringify({
|
|
@@ -40220,7 +40361,7 @@ var write_retro = createSwarmTool({
|
|
|
40220
40361
|
}
|
|
40221
40362
|
});
|
|
40222
40363
|
|
|
40223
|
-
// src/commands/
|
|
40364
|
+
// src/commands/write-retro.ts
|
|
40224
40365
|
async function handleWriteRetroCommand(directory, args) {
|
|
40225
40366
|
if (args.length === 0 || !args[0] || args[0].trim() === "") {
|
|
40226
40367
|
return `## Usage: /swarm write-retro <json>
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export { handleSpecifyCommand } from './specify';
|
|
|
29
29
|
export { handleStatusCommand } from './status';
|
|
30
30
|
export { handleSyncPlanCommand } from './sync-plan';
|
|
31
31
|
export { handleTurboCommand } from './turbo';
|
|
32
|
-
export { handleWriteRetroCommand } from './
|
|
32
|
+
export { handleWriteRetroCommand } from './write-retro';
|
|
33
33
|
/**
|
|
34
34
|
* Creates a command.execute.before handler for /swarm commands.
|
|
35
35
|
* Uses factory pattern to close over directory and agents.
|
|
@@ -91,6 +91,7 @@ export declare const PhaseSchema: z.ZodObject<{
|
|
|
91
91
|
evidence_path: z.ZodOptional<z.ZodString>;
|
|
92
92
|
blocked_reason: z.ZodOptional<z.ZodString>;
|
|
93
93
|
}, z.core.$strip>>>;
|
|
94
|
+
required_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
94
95
|
}, z.core.$strip>;
|
|
95
96
|
export type Phase = z.infer<typeof PhaseSchema>;
|
|
96
97
|
export declare const PlanSchema: z.ZodObject<{
|
|
@@ -129,6 +130,7 @@ export declare const PlanSchema: z.ZodObject<{
|
|
|
129
130
|
evidence_path: z.ZodOptional<z.ZodString>;
|
|
130
131
|
blocked_reason: z.ZodOptional<z.ZodString>;
|
|
131
132
|
}, z.core.$strip>>>;
|
|
133
|
+
required_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
132
134
|
}, z.core.$strip>>;
|
|
133
135
|
migration_status: z.ZodOptional<z.ZodEnum<{
|
|
134
136
|
native: "native";
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -375,7 +375,7 @@ export type PlanCursorConfig = z.infer<typeof PlanCursorConfigSchema>;
|
|
|
375
375
|
export declare const CheckpointConfigSchema: z.ZodObject<{
|
|
376
376
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
377
377
|
auto_checkpoint_threshold: z.ZodDefault<z.ZodNumber>;
|
|
378
|
-
}, z.core.$
|
|
378
|
+
}, z.core.$strict>;
|
|
379
379
|
export type CheckpointConfig = z.infer<typeof CheckpointConfigSchema>;
|
|
380
380
|
export declare const AutomationModeSchema: z.ZodEnum<{
|
|
381
381
|
auto: "auto";
|
|
@@ -699,7 +699,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
699
699
|
checkpoint: z.ZodOptional<z.ZodObject<{
|
|
700
700
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
701
701
|
auto_checkpoint_threshold: z.ZodDefault<z.ZodNumber>;
|
|
702
|
-
}, z.core.$
|
|
702
|
+
}, z.core.$strict>>;
|
|
703
703
|
automation: z.ZodOptional<z.ZodType<{
|
|
704
704
|
mode: "auto" | "manual" | "hybrid";
|
|
705
705
|
capabilities: {
|
|
@@ -785,6 +785,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
785
785
|
emergencyThreshold: z.ZodDefault<z.ZodNumber>;
|
|
786
786
|
preserveLastNTurns: z.ZodDefault<z.ZodNumber>;
|
|
787
787
|
}, z.core.$strip>>;
|
|
788
|
+
turbo_mode: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
788
789
|
}, z.core.$strip>;
|
|
789
790
|
export type PluginConfig = z.infer<typeof PluginConfigSchema>;
|
|
790
791
|
export type { AgentName, PipelineAgentName, QAAgentName, } from './constants';
|