opencode-swarm 6.39.0 → 6.40.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/dist/cli/index.js +205 -54
- 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 +2815 -2383
- 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/quality/index.d.ts +1 -1
- package/dist/quality/metrics.d.ts +5 -0
- package/dist/services/compaction-service.d.ts +2 -2
- package/dist/session/snapshot-reader.d.ts +8 -0
- package/dist/session/snapshot-writer.d.ts +4 -3
- 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"),
|
|
@@ -16652,13 +16671,21 @@ function createConfigBackup(directory) {
|
|
|
16652
16671
|
if (fs4.existsSync(projectConfigPath)) {
|
|
16653
16672
|
try {
|
|
16654
16673
|
content = fs4.readFileSync(projectConfigPath, "utf-8");
|
|
16655
|
-
} catch {
|
|
16674
|
+
} catch (error93) {
|
|
16675
|
+
log("[ConfigDoctor] project config read failed", {
|
|
16676
|
+
error: error93 instanceof Error ? error93.message : String(error93)
|
|
16677
|
+
});
|
|
16678
|
+
}
|
|
16656
16679
|
}
|
|
16657
16680
|
if (content === null && fs4.existsSync(userConfigPath)) {
|
|
16658
16681
|
configPath = userConfigPath;
|
|
16659
16682
|
try {
|
|
16660
16683
|
content = fs4.readFileSync(userConfigPath, "utf-8");
|
|
16661
|
-
} catch {
|
|
16684
|
+
} catch (error93) {
|
|
16685
|
+
log("[ConfigDoctor] user config read failed", {
|
|
16686
|
+
error: error93 instanceof Error ? error93.message : String(error93)
|
|
16687
|
+
});
|
|
16688
|
+
}
|
|
16662
16689
|
}
|
|
16663
16690
|
if (content === null) {
|
|
16664
16691
|
return null;
|
|
@@ -17209,6 +17236,7 @@ async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
|
|
|
17209
17236
|
}
|
|
17210
17237
|
var VALID_CONFIG_PATTERNS, DANGEROUS_PATH_SEGMENTS;
|
|
17211
17238
|
var init_config_doctor = __esm(() => {
|
|
17239
|
+
init_utils();
|
|
17212
17240
|
VALID_CONFIG_PATTERNS = [
|
|
17213
17241
|
/^\.config[\\/]opencode[\\/]opencode-swarm\.json$/,
|
|
17214
17242
|
/\.opencode[\\/]opencode-swarm\.json$/
|
|
@@ -17301,8 +17329,8 @@ function getTaskBlockers(task, summary, status) {
|
|
|
17301
17329
|
}
|
|
17302
17330
|
return blockers;
|
|
17303
17331
|
}
|
|
17304
|
-
async function buildTaskSummary(task, taskId) {
|
|
17305
|
-
const result = await loadEvidence(
|
|
17332
|
+
async function buildTaskSummary(directory, task, taskId) {
|
|
17333
|
+
const result = await loadEvidence(directory, taskId);
|
|
17306
17334
|
const bundle = result.status === "found" ? result.bundle : null;
|
|
17307
17335
|
const phase = task?.phase ?? 0;
|
|
17308
17336
|
const status = getTaskStatus(task, bundle);
|
|
@@ -17331,18 +17359,18 @@ async function buildTaskSummary(task, taskId) {
|
|
|
17331
17359
|
lastEvidenceTimestamp: lastTimestamp
|
|
17332
17360
|
};
|
|
17333
17361
|
}
|
|
17334
|
-
async function buildPhaseSummary(phase) {
|
|
17335
|
-
const taskIds = await listEvidenceTaskIds(
|
|
17362
|
+
async function buildPhaseSummary(directory, phase) {
|
|
17363
|
+
const taskIds = await listEvidenceTaskIds(directory);
|
|
17336
17364
|
const phaseTaskIds = new Set(phase.tasks.map((t) => t.id));
|
|
17337
17365
|
const taskSummaries = [];
|
|
17338
17366
|
const _taskMap = new Map(phase.tasks.map((t) => [t.id, t]));
|
|
17339
17367
|
for (const task of phase.tasks) {
|
|
17340
|
-
const summary = await buildTaskSummary(task, task.id);
|
|
17368
|
+
const summary = await buildTaskSummary(directory, task, task.id);
|
|
17341
17369
|
taskSummaries.push(summary);
|
|
17342
17370
|
}
|
|
17343
17371
|
const extraTaskIds = taskIds.filter((id) => !phaseTaskIds.has(id));
|
|
17344
17372
|
for (const taskId of extraTaskIds) {
|
|
17345
|
-
const summary = await buildTaskSummary(undefined, taskId);
|
|
17373
|
+
const summary = await buildTaskSummary(directory, undefined, taskId);
|
|
17346
17374
|
if (summary.phase === phase.id) {
|
|
17347
17375
|
taskSummaries.push(summary);
|
|
17348
17376
|
}
|
|
@@ -17443,7 +17471,7 @@ async function buildEvidenceSummary(directory, currentPhase) {
|
|
|
17443
17471
|
let totalTasks = 0;
|
|
17444
17472
|
let completedTasks = 0;
|
|
17445
17473
|
for (const phase of phasesToProcess) {
|
|
17446
|
-
const summary = await buildPhaseSummary(phase);
|
|
17474
|
+
const summary = await buildPhaseSummary(directory, phase);
|
|
17447
17475
|
phaseSummaries.push(summary);
|
|
17448
17476
|
totalTasks += summary.totalTasks;
|
|
17449
17477
|
completedTasks += summary.completedTasks;
|
|
@@ -18161,8 +18189,8 @@ var PlanCursorConfigSchema = exports_external.object({
|
|
|
18161
18189
|
});
|
|
18162
18190
|
var CheckpointConfigSchema = exports_external.object({
|
|
18163
18191
|
enabled: exports_external.boolean().default(true),
|
|
18164
|
-
auto_checkpoint_threshold: exports_external.number().min(1).max(20).default(3)
|
|
18165
|
-
});
|
|
18192
|
+
auto_checkpoint_threshold: exports_external.number().int().min(1).max(20).default(3)
|
|
18193
|
+
}).strict();
|
|
18166
18194
|
var AutomationModeSchema = exports_external.enum(["manual", "hybrid", "auto"]);
|
|
18167
18195
|
var AutomationCapabilitiesSchema = exports_external.object({
|
|
18168
18196
|
plan_sync: exports_external.boolean().default(true),
|
|
@@ -18282,7 +18310,8 @@ var PluginConfigSchema = exports_external.object({
|
|
|
18282
18310
|
block_on_threshold: exports_external.boolean().default(false).describe("If true, block phase completion when threshold exceeded. Default: advisory only.")
|
|
18283
18311
|
}).optional(),
|
|
18284
18312
|
incremental_verify: IncrementalVerifyConfigSchema.optional(),
|
|
18285
|
-
compaction_service: CompactionConfigSchema.optional()
|
|
18313
|
+
compaction_service: CompactionConfigSchema.optional(),
|
|
18314
|
+
turbo_mode: exports_external.boolean().default(false).optional()
|
|
18286
18315
|
});
|
|
18287
18316
|
|
|
18288
18317
|
// src/config/loader.ts
|
|
@@ -18385,6 +18414,15 @@ function loadPluginConfig(directory) {
|
|
|
18385
18414
|
}
|
|
18386
18415
|
return result.data;
|
|
18387
18416
|
}
|
|
18417
|
+
function loadPluginConfigWithMeta(directory) {
|
|
18418
|
+
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
18419
|
+
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
18420
|
+
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
18421
|
+
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
18422
|
+
const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
|
|
18423
|
+
const config2 = loadPluginConfig(directory);
|
|
18424
|
+
return { config: config2, loadedFromFile };
|
|
18425
|
+
}
|
|
18388
18426
|
|
|
18389
18427
|
// src/commands/archive.ts
|
|
18390
18428
|
init_manager();
|
|
@@ -18807,6 +18845,9 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
18807
18845
|
`);
|
|
18808
18846
|
}
|
|
18809
18847
|
|
|
18848
|
+
// src/commands/checkpoint.ts
|
|
18849
|
+
init_zod();
|
|
18850
|
+
|
|
18810
18851
|
// src/tools/checkpoint.ts
|
|
18811
18852
|
import { spawnSync } from "child_process";
|
|
18812
18853
|
import * as fs3 from "fs";
|
|
@@ -31132,6 +31173,10 @@ function tool(input) {
|
|
|
31132
31173
|
return input;
|
|
31133
31174
|
}
|
|
31134
31175
|
tool.schema = exports_external2;
|
|
31176
|
+
|
|
31177
|
+
// src/config/index.ts
|
|
31178
|
+
init_evidence_schema();
|
|
31179
|
+
init_plan_schema();
|
|
31135
31180
|
// src/tools/create-tool.ts
|
|
31136
31181
|
function createSwarmTool(opts) {
|
|
31137
31182
|
return tool({
|
|
@@ -31256,6 +31301,11 @@ function isGitRepo() {
|
|
|
31256
31301
|
}
|
|
31257
31302
|
function handleSave(label, directory) {
|
|
31258
31303
|
try {
|
|
31304
|
+
let maxCheckpoints = 20;
|
|
31305
|
+
try {
|
|
31306
|
+
const { config: config3 } = loadPluginConfigWithMeta(directory);
|
|
31307
|
+
maxCheckpoints = config3.checkpoint?.auto_checkpoint_threshold ?? maxCheckpoints;
|
|
31308
|
+
} catch {}
|
|
31259
31309
|
const log2 = readCheckpointLog(directory);
|
|
31260
31310
|
const existingCheckpoint = log2.checkpoints.find((c) => c.label === label);
|
|
31261
31311
|
if (existingCheckpoint) {
|
|
@@ -31375,7 +31425,7 @@ var checkpoint = createSwarmTool({
|
|
|
31375
31425
|
let label;
|
|
31376
31426
|
try {
|
|
31377
31427
|
action = String(args.action);
|
|
31378
|
-
label = args.label !== undefined ? String(args.label) : undefined;
|
|
31428
|
+
label = args.label !== undefined && args.label !== null ? String(args.label) : undefined;
|
|
31379
31429
|
} catch {
|
|
31380
31430
|
return JSON.stringify({
|
|
31381
31431
|
action: "unknown",
|
|
@@ -31428,6 +31478,22 @@ var checkpoint = createSwarmTool({
|
|
|
31428
31478
|
});
|
|
31429
31479
|
|
|
31430
31480
|
// src/commands/checkpoint.ts
|
|
31481
|
+
var CheckpointResultSchema = exports_external.object({
|
|
31482
|
+
action: exports_external.string().optional(),
|
|
31483
|
+
success: exports_external.boolean(),
|
|
31484
|
+
error: exports_external.string().optional(),
|
|
31485
|
+
checkpoints: exports_external.array(exports_external.unknown()).optional()
|
|
31486
|
+
}).passthrough();
|
|
31487
|
+
function safeParseResult(result) {
|
|
31488
|
+
const parsed = CheckpointResultSchema.safeParse(JSON.parse(result));
|
|
31489
|
+
if (!parsed.success) {
|
|
31490
|
+
return {
|
|
31491
|
+
success: false,
|
|
31492
|
+
error: `Invalid response: ${parsed.error.message}`
|
|
31493
|
+
};
|
|
31494
|
+
}
|
|
31495
|
+
return parsed.data;
|
|
31496
|
+
}
|
|
31431
31497
|
async function handleCheckpointCommand(directory, args) {
|
|
31432
31498
|
const subcommand = args[0] || "list";
|
|
31433
31499
|
const label = args[1];
|
|
@@ -31450,7 +31516,7 @@ async function handleSave2(directory, label) {
|
|
|
31450
31516
|
const result = await checkpoint.execute({ action: "save", label }, {
|
|
31451
31517
|
directory
|
|
31452
31518
|
});
|
|
31453
|
-
const parsed =
|
|
31519
|
+
const parsed = safeParseResult(result);
|
|
31454
31520
|
if (parsed.success) {
|
|
31455
31521
|
return `\u2713 Checkpoint saved: "${label}"`;
|
|
31456
31522
|
} else {
|
|
@@ -31469,7 +31535,7 @@ async function handleRestore2(directory, label) {
|
|
|
31469
31535
|
const result = await checkpoint.execute({ action: "restore", label }, {
|
|
31470
31536
|
directory
|
|
31471
31537
|
});
|
|
31472
|
-
const parsed =
|
|
31538
|
+
const parsed = safeParseResult(result);
|
|
31473
31539
|
if (parsed.success) {
|
|
31474
31540
|
return `\u2713 Restored to checkpoint: "${label}"`;
|
|
31475
31541
|
} else {
|
|
@@ -31488,7 +31554,7 @@ async function handleDelete2(directory, label) {
|
|
|
31488
31554
|
const result = await checkpoint.execute({ action: "delete", label }, {
|
|
31489
31555
|
directory
|
|
31490
31556
|
});
|
|
31491
|
-
const parsed =
|
|
31557
|
+
const parsed = safeParseResult(result);
|
|
31492
31558
|
if (parsed.success) {
|
|
31493
31559
|
return `\u2713 Checkpoint deleted: "${label}"`;
|
|
31494
31560
|
} else {
|
|
@@ -31504,7 +31570,7 @@ async function handleList2(directory) {
|
|
|
31504
31570
|
const result = await checkpoint.execute({ action: "list" }, {
|
|
31505
31571
|
directory
|
|
31506
31572
|
});
|
|
31507
|
-
const parsed =
|
|
31573
|
+
const parsed = safeParseResult(result);
|
|
31508
31574
|
if (!parsed.success) {
|
|
31509
31575
|
return `Error: ${parsed.error || "Failed to list checkpoints"}`;
|
|
31510
31576
|
}
|
|
@@ -33713,6 +33779,7 @@ import { renameSync as renameSync4 } from "fs";
|
|
|
33713
33779
|
// src/services/handoff-service.ts
|
|
33714
33780
|
init_utils2();
|
|
33715
33781
|
init_manager2();
|
|
33782
|
+
init_utils();
|
|
33716
33783
|
var RTL_OVERRIDE_PATTERN = /[\u202e\u202d\u202c\u200f]/g;
|
|
33717
33784
|
var MAX_TASK_ID_LENGTH = 100;
|
|
33718
33785
|
var MAX_DECISION_LENGTH = 500;
|
|
@@ -33829,7 +33896,10 @@ function parseSessionState(content) {
|
|
|
33829
33896
|
}
|
|
33830
33897
|
}
|
|
33831
33898
|
return { activeAgent, delegationState, pendingQA };
|
|
33832
|
-
} catch {
|
|
33899
|
+
} catch (error93) {
|
|
33900
|
+
log("[HandoffService] state extraction failed", {
|
|
33901
|
+
error: error93 instanceof Error ? error93.message : String(error93)
|
|
33902
|
+
});
|
|
33833
33903
|
return null;
|
|
33834
33904
|
}
|
|
33835
33905
|
}
|
|
@@ -34011,8 +34081,8 @@ function formatHandoffMarkdown(data) {
|
|
|
34011
34081
|
init_utils2();
|
|
34012
34082
|
import { mkdirSync as mkdirSync4, renameSync as renameSync3 } from "fs";
|
|
34013
34083
|
import * as path14 from "path";
|
|
34014
|
-
|
|
34015
|
-
var
|
|
34084
|
+
init_utils();
|
|
34085
|
+
var _writeInFlight = Promise.resolve();
|
|
34016
34086
|
function serializeAgentSession(s) {
|
|
34017
34087
|
const gateLog = {};
|
|
34018
34088
|
const rawGateLog = s.gateLog ?? new Map;
|
|
@@ -34102,19 +34172,14 @@ async function writeSnapshot(directory, state) {
|
|
|
34102
34172
|
await Bun.write(tempPath, content);
|
|
34103
34173
|
renameSync3(tempPath, resolvedPath);
|
|
34104
34174
|
} catch (error93) {
|
|
34105
|
-
|
|
34106
|
-
|
|
34107
|
-
}
|
|
34175
|
+
log("[snapshot-writer] write failed", {
|
|
34176
|
+
error: error93 instanceof Error ? error93.message : String(error93)
|
|
34177
|
+
});
|
|
34108
34178
|
}
|
|
34109
34179
|
}
|
|
34110
34180
|
async function flushPendingSnapshot(directory) {
|
|
34111
|
-
|
|
34112
|
-
|
|
34113
|
-
pendingWrite = null;
|
|
34114
|
-
await writeSnapshot(directory, swarmState).catch(() => {});
|
|
34115
|
-
} else {
|
|
34116
|
-
await lastWritePromise;
|
|
34117
|
-
}
|
|
34181
|
+
_writeInFlight = _writeInFlight.then(() => writeSnapshot(directory, swarmState), () => writeSnapshot(directory, swarmState));
|
|
34182
|
+
await _writeInFlight;
|
|
34118
34183
|
}
|
|
34119
34184
|
|
|
34120
34185
|
// src/commands/handoff.ts
|
|
@@ -34202,7 +34267,8 @@ async function extractFromLegacy(directory) {
|
|
|
34202
34267
|
mappedStatus = "complete";
|
|
34203
34268
|
else if (status === "IN PROGRESS")
|
|
34204
34269
|
mappedStatus = "in_progress";
|
|
34205
|
-
const headerLineIndex =
|
|
34270
|
+
const headerLineIndex = planContent.substring(0, match.index).split(`
|
|
34271
|
+
`).length - 1;
|
|
34206
34272
|
let completed = 0;
|
|
34207
34273
|
let total = 0;
|
|
34208
34274
|
if (headerLineIndex !== -1) {
|
|
@@ -34597,9 +34663,9 @@ async function getPlanData(directory, phaseArg) {
|
|
|
34597
34663
|
return {
|
|
34598
34664
|
hasPlan: true,
|
|
34599
34665
|
fullMarkdown,
|
|
34600
|
-
requestedPhase:
|
|
34666
|
+
requestedPhase: null,
|
|
34601
34667
|
phaseMarkdown: null,
|
|
34602
|
-
errorMessage:
|
|
34668
|
+
errorMessage: `Invalid phase number: "${phaseArg}"`,
|
|
34603
34669
|
isLegacy: false
|
|
34604
34670
|
};
|
|
34605
34671
|
}
|
|
@@ -34650,9 +34716,9 @@ async function getPlanData(directory, phaseArg) {
|
|
|
34650
34716
|
return {
|
|
34651
34717
|
hasPlan: true,
|
|
34652
34718
|
fullMarkdown: planContent,
|
|
34653
|
-
requestedPhase:
|
|
34719
|
+
requestedPhase: null,
|
|
34654
34720
|
phaseMarkdown: null,
|
|
34655
|
-
errorMessage:
|
|
34721
|
+
errorMessage: `Invalid phase number: "${phaseArg}"`,
|
|
34656
34722
|
isLegacy: true
|
|
34657
34723
|
};
|
|
34658
34724
|
}
|
|
@@ -35591,6 +35657,59 @@ LANGUAGE_REGISTRY.register({
|
|
|
35591
35657
|
]
|
|
35592
35658
|
}
|
|
35593
35659
|
});
|
|
35660
|
+
LANGUAGE_REGISTRY.register({
|
|
35661
|
+
id: "php",
|
|
35662
|
+
displayName: "PHP",
|
|
35663
|
+
tier: 3,
|
|
35664
|
+
extensions: [".php", ".phtml"],
|
|
35665
|
+
treeSitter: { grammarId: "php", wasmFile: "tree-sitter-php.wasm" },
|
|
35666
|
+
build: {
|
|
35667
|
+
detectFiles: ["composer.json"],
|
|
35668
|
+
commands: []
|
|
35669
|
+
},
|
|
35670
|
+
test: {
|
|
35671
|
+
detectFiles: ["phpunit.xml", "phpunit.xml.dist"],
|
|
35672
|
+
frameworks: [
|
|
35673
|
+
{
|
|
35674
|
+
name: "PHPUnit",
|
|
35675
|
+
detect: "phpunit.xml",
|
|
35676
|
+
cmd: "vendor/bin/phpunit",
|
|
35677
|
+
priority: 1
|
|
35678
|
+
}
|
|
35679
|
+
]
|
|
35680
|
+
},
|
|
35681
|
+
lint: {
|
|
35682
|
+
detectFiles: [".php-cs-fixer.php", "phpcs.xml"],
|
|
35683
|
+
linters: [
|
|
35684
|
+
{
|
|
35685
|
+
name: "PHP-CS-Fixer",
|
|
35686
|
+
detect: ".php-cs-fixer.php",
|
|
35687
|
+
cmd: "vendor/bin/php-cs-fixer fix --dry-run --diff",
|
|
35688
|
+
priority: 1
|
|
35689
|
+
}
|
|
35690
|
+
]
|
|
35691
|
+
},
|
|
35692
|
+
audit: {
|
|
35693
|
+
detectFiles: ["composer.lock"],
|
|
35694
|
+
command: "composer audit --format=json",
|
|
35695
|
+
outputFormat: "json"
|
|
35696
|
+
},
|
|
35697
|
+
sast: { nativeRuleSet: "php", semgrepSupport: "ga" },
|
|
35698
|
+
prompts: {
|
|
35699
|
+
coderConstraints: [
|
|
35700
|
+
"Follow PSR-12 coding standards",
|
|
35701
|
+
"Use strict types declaration: declare(strict_types=1)",
|
|
35702
|
+
"Prefer type hints and return type declarations on all functions",
|
|
35703
|
+
"Use dependency injection over static methods and singletons"
|
|
35704
|
+
],
|
|
35705
|
+
reviewerChecklist: [
|
|
35706
|
+
"Verify no user input reaches SQL queries without parameterised binding",
|
|
35707
|
+
"Check for XSS \u2014 all output must be escaped with htmlspecialchars()",
|
|
35708
|
+
"Confirm no eval(), exec(), or shell_exec() with user-controlled input",
|
|
35709
|
+
"Validate proper error handling \u2014 no bare catch blocks that swallow errors"
|
|
35710
|
+
]
|
|
35711
|
+
}
|
|
35712
|
+
});
|
|
35594
35713
|
|
|
35595
35714
|
// src/lang/detector.ts
|
|
35596
35715
|
async function detectProjectLanguages(projectDir) {
|
|
@@ -36174,7 +36293,7 @@ async function detectAvailableLinter(directory) {
|
|
|
36174
36293
|
async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
36175
36294
|
const DETECT_TIMEOUT = 2000;
|
|
36176
36295
|
try {
|
|
36177
|
-
const biomeProc = Bun.spawn([
|
|
36296
|
+
const biomeProc = Bun.spawn([biomeBin, "--version"], {
|
|
36178
36297
|
stdout: "pipe",
|
|
36179
36298
|
stderr: "pipe"
|
|
36180
36299
|
});
|
|
@@ -36188,7 +36307,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
36188
36307
|
}
|
|
36189
36308
|
} catch {}
|
|
36190
36309
|
try {
|
|
36191
|
-
const eslintProc = Bun.spawn([
|
|
36310
|
+
const eslintProc = Bun.spawn([eslintBin, "--version"], {
|
|
36192
36311
|
stdout: "pipe",
|
|
36193
36312
|
stderr: "pipe"
|
|
36194
36313
|
});
|
|
@@ -38205,12 +38324,13 @@ async function runLintCheck(dir, linter, timeoutMs) {
|
|
|
38205
38324
|
const startTime = Date.now();
|
|
38206
38325
|
try {
|
|
38207
38326
|
const lintPromise = runLint(linter, "check", dir);
|
|
38327
|
+
let timeoutId;
|
|
38208
38328
|
const timeoutPromise = new Promise((_, reject) => {
|
|
38209
|
-
setTimeout(() => {
|
|
38329
|
+
timeoutId = setTimeout(() => {
|
|
38210
38330
|
reject(new Error(`Lint check timed out after ${timeoutMs}ms`));
|
|
38211
38331
|
}, timeoutMs);
|
|
38212
38332
|
});
|
|
38213
|
-
const result = await Promise.race([lintPromise, timeoutPromise]);
|
|
38333
|
+
const result = await Promise.race([lintPromise, timeoutPromise]).finally(() => clearTimeout(timeoutId));
|
|
38214
38334
|
if (!result.success) {
|
|
38215
38335
|
return {
|
|
38216
38336
|
type: "lint",
|
|
@@ -38774,17 +38894,19 @@ class CircuitBreaker {
|
|
|
38774
38894
|
this.successCount = 0;
|
|
38775
38895
|
this.onStateChange?.("closed", {
|
|
38776
38896
|
timestamp: Date.now(),
|
|
38777
|
-
successCount: 0
|
|
38897
|
+
successCount: 0,
|
|
38898
|
+
oldState
|
|
38778
38899
|
});
|
|
38779
38900
|
} else if (newState === "open") {
|
|
38780
38901
|
this.successCount = 0;
|
|
38781
38902
|
this.onStateChange?.("opened", {
|
|
38782
38903
|
timestamp: Date.now(),
|
|
38783
|
-
failureCount: this.failureCount
|
|
38904
|
+
failureCount: this.failureCount,
|
|
38905
|
+
oldState
|
|
38784
38906
|
});
|
|
38785
38907
|
} else if (newState === "half-open") {
|
|
38786
38908
|
this.successCount = 0;
|
|
38787
|
-
this.onStateChange?.("half-open", { timestamp: Date.now() });
|
|
38909
|
+
this.onStateChange?.("half-open", { timestamp: Date.now(), oldState });
|
|
38788
38910
|
}
|
|
38789
38911
|
}
|
|
38790
38912
|
reset() {
|
|
@@ -39720,12 +39842,32 @@ function makeInitialState() {
|
|
|
39720
39842
|
lastSnapshotAt: null
|
|
39721
39843
|
};
|
|
39722
39844
|
}
|
|
39723
|
-
var
|
|
39724
|
-
function
|
|
39725
|
-
|
|
39726
|
-
|
|
39727
|
-
|
|
39728
|
-
|
|
39845
|
+
var sessionStates = new Map;
|
|
39846
|
+
function getSessionState(sessionId) {
|
|
39847
|
+
let state = sessionStates.get(sessionId);
|
|
39848
|
+
if (!state) {
|
|
39849
|
+
state = makeInitialState();
|
|
39850
|
+
sessionStates.set(sessionId, state);
|
|
39851
|
+
}
|
|
39852
|
+
return state;
|
|
39853
|
+
}
|
|
39854
|
+
function getCompactionMetrics(sessionId) {
|
|
39855
|
+
if (sessionId) {
|
|
39856
|
+
const state = getSessionState(sessionId);
|
|
39857
|
+
return {
|
|
39858
|
+
compactionCount: state.observationCount + state.reflectionCount + state.emergencyCount,
|
|
39859
|
+
lastSnapshotAt: state.lastSnapshotAt
|
|
39860
|
+
};
|
|
39861
|
+
}
|
|
39862
|
+
let total = 0;
|
|
39863
|
+
let lastSnapshot = null;
|
|
39864
|
+
for (const state of sessionStates.values()) {
|
|
39865
|
+
total += state.observationCount + state.reflectionCount + state.emergencyCount;
|
|
39866
|
+
if (state.lastSnapshotAt && (!lastSnapshot || state.lastSnapshotAt > lastSnapshot)) {
|
|
39867
|
+
lastSnapshot = state.lastSnapshotAt;
|
|
39868
|
+
}
|
|
39869
|
+
}
|
|
39870
|
+
return { compactionCount: total, lastSnapshotAt: lastSnapshot };
|
|
39729
39871
|
}
|
|
39730
39872
|
|
|
39731
39873
|
// src/services/context-budget-service.ts
|
|
@@ -39888,6 +40030,7 @@ async function handleTurboCommand(_directory, args, sessionID) {
|
|
|
39888
40030
|
}
|
|
39889
40031
|
|
|
39890
40032
|
// src/tools/write-retro.ts
|
|
40033
|
+
init_evidence_schema();
|
|
39891
40034
|
init_manager();
|
|
39892
40035
|
async function executeWriteRetro(args, directory) {
|
|
39893
40036
|
const phase = args.phase;
|
|
@@ -40121,8 +40264,9 @@ async function executeWriteRetro(args, directory) {
|
|
|
40121
40264
|
};
|
|
40122
40265
|
const taxonomy = [];
|
|
40123
40266
|
try {
|
|
40124
|
-
|
|
40125
|
-
|
|
40267
|
+
const allTaskIds = await listEvidenceTaskIds(directory);
|
|
40268
|
+
const phaseTaskIds = allTaskIds.filter((id) => id.startsWith(`${phase}.`));
|
|
40269
|
+
for (const phaseTaskId of phaseTaskIds) {
|
|
40126
40270
|
const result = await loadEvidence(directory, phaseTaskId);
|
|
40127
40271
|
if (result.status !== "found")
|
|
40128
40272
|
continue;
|
|
@@ -40156,6 +40300,13 @@ async function executeWriteRetro(args, directory) {
|
|
|
40156
40300
|
}
|
|
40157
40301
|
} catch {}
|
|
40158
40302
|
retroEntry.error_taxonomy = [...new Set(taxonomy)];
|
|
40303
|
+
const validationResult = RetrospectiveEvidenceSchema.safeParse(retroEntry);
|
|
40304
|
+
if (!validationResult.success) {
|
|
40305
|
+
return JSON.stringify({
|
|
40306
|
+
success: false,
|
|
40307
|
+
error: `Retrospective entry failed validation: ${validationResult.error.message}`
|
|
40308
|
+
}, null, 2);
|
|
40309
|
+
}
|
|
40159
40310
|
try {
|
|
40160
40311
|
await saveEvidence(directory, taskId, retroEntry);
|
|
40161
40312
|
return JSON.stringify({
|
|
@@ -40220,7 +40371,7 @@ var write_retro = createSwarmTool({
|
|
|
40220
40371
|
}
|
|
40221
40372
|
});
|
|
40222
40373
|
|
|
40223
|
-
// src/commands/
|
|
40374
|
+
// src/commands/write-retro.ts
|
|
40224
40375
|
async function handleWriteRetroCommand(directory, args) {
|
|
40225
40376
|
if (args.length === 0 || !args[0] || args[0].trim() === "") {
|
|
40226
40377
|
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';
|