opencode-swarm 6.53.3 → 6.53.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +376 -50
- package/dist/commands/close.d.ts +6 -2
- package/dist/commands/full-auto-config-guard.test.d.ts +7 -0
- package/dist/commands/full-auto-discoverability.test.d.ts +8 -0
- package/dist/hooks/full-auto-intercept.d.ts +1 -1
- package/dist/index.js +462 -71
- package/dist/services/handoff-service.d.ts +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31389,7 +31389,7 @@ var init_ledger = __esm(() => {
|
|
|
31389
31389
|
});
|
|
31390
31390
|
|
|
31391
31391
|
// src/plan/manager.ts
|
|
31392
|
-
import { existsSync as existsSync7, renameSync as renameSync4, unlinkSync } from "fs";
|
|
31392
|
+
import { copyFileSync, existsSync as existsSync7, renameSync as renameSync4, unlinkSync } from "fs";
|
|
31393
31393
|
import * as path11 from "path";
|
|
31394
31394
|
async function loadPlanJsonOnly(directory) {
|
|
31395
31395
|
const planJsonContent = await readSwarmFileAsync(directory, "plan.json");
|
|
@@ -31647,17 +31647,60 @@ async function savePlan(directory, plan, options) {
|
|
|
31647
31647
|
if (existingEvents.length > 0 && existingEvents[0].plan_id !== planId) {
|
|
31648
31648
|
const swarmDir2 = path11.resolve(directory, ".swarm");
|
|
31649
31649
|
const oldLedgerPath = path11.join(swarmDir2, "plan-ledger.jsonl");
|
|
31650
|
-
const
|
|
31650
|
+
const oldLedgerBackupPath = path11.join(swarmDir2, `plan-ledger.backup-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
|
|
31651
|
+
let backupExists = false;
|
|
31651
31652
|
if (existsSync7(oldLedgerPath)) {
|
|
31652
|
-
|
|
31653
|
-
|
|
31653
|
+
try {
|
|
31654
|
+
renameSync4(oldLedgerPath, oldLedgerBackupPath);
|
|
31655
|
+
backupExists = true;
|
|
31656
|
+
} catch (renameErr) {
|
|
31657
|
+
throw new Error(`[savePlan] Cannot reinitialize ledger: could not move old ledger aside (rename failed: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}). The existing ledger has plan_id="${existingEvents[0].plan_id}" which does not match the current plan="${planId}". To proceed, close any programs that may have the ledger file open, or run /swarm reset-session to clear the ledger.`);
|
|
31658
|
+
}
|
|
31654
31659
|
}
|
|
31655
|
-
|
|
31656
|
-
|
|
31657
|
-
|
|
31658
|
-
|
|
31659
|
-
|
|
31660
|
+
let initSucceeded = false;
|
|
31661
|
+
if (backupExists) {
|
|
31662
|
+
try {
|
|
31663
|
+
await initLedger(directory, planId, planHashForInit);
|
|
31664
|
+
initSucceeded = true;
|
|
31665
|
+
} catch (initErr) {
|
|
31666
|
+
const errorMessage = String(initErr);
|
|
31667
|
+
if (errorMessage.includes("already initialized")) {
|
|
31668
|
+
try {
|
|
31669
|
+
if (existsSync7(oldLedgerBackupPath))
|
|
31670
|
+
unlinkSync(oldLedgerBackupPath);
|
|
31671
|
+
} catch {}
|
|
31672
|
+
} else {
|
|
31673
|
+
if (existsSync7(oldLedgerBackupPath)) {
|
|
31674
|
+
try {
|
|
31675
|
+
renameSync4(oldLedgerBackupPath, oldLedgerPath);
|
|
31676
|
+
} catch {
|
|
31677
|
+
copyFileSync(oldLedgerBackupPath, oldLedgerPath);
|
|
31678
|
+
try {
|
|
31679
|
+
unlinkSync(oldLedgerBackupPath);
|
|
31680
|
+
} catch {}
|
|
31681
|
+
}
|
|
31682
|
+
}
|
|
31683
|
+
throw initErr;
|
|
31684
|
+
}
|
|
31685
|
+
}
|
|
31686
|
+
}
|
|
31687
|
+
if (initSucceeded && backupExists) {
|
|
31688
|
+
const archivePath = path11.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
|
|
31689
|
+
try {
|
|
31690
|
+
renameSync4(oldLedgerBackupPath, archivePath);
|
|
31691
|
+
warn(`[savePlan] Ledger identity mismatch (was "${existingEvents[0].plan_id}", now "${planId}") \u2014 archived old ledger to ${archivePath} and reinitializing.`);
|
|
31692
|
+
} catch (renameErr) {
|
|
31693
|
+
warn(`[savePlan] Could not archive old ledger (rename failed: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}). Old ledger may still exist at ${oldLedgerBackupPath}.`);
|
|
31694
|
+
try {
|
|
31695
|
+
if (existsSync7(oldLedgerBackupPath))
|
|
31696
|
+
unlinkSync(oldLedgerBackupPath);
|
|
31697
|
+
} catch {}
|
|
31660
31698
|
}
|
|
31699
|
+
} else if (!initSucceeded && backupExists) {
|
|
31700
|
+
try {
|
|
31701
|
+
if (existsSync7(oldLedgerBackupPath))
|
|
31702
|
+
unlinkSync(oldLedgerBackupPath);
|
|
31703
|
+
} catch {}
|
|
31661
31704
|
}
|
|
31662
31705
|
}
|
|
31663
31706
|
}
|
|
@@ -32167,13 +32210,13 @@ __export(exports_co_change_analyzer, {
|
|
|
32167
32210
|
co_change_analyzer: () => co_change_analyzer,
|
|
32168
32211
|
buildCoChangeMatrix: () => buildCoChangeMatrix
|
|
32169
32212
|
});
|
|
32170
|
-
import * as
|
|
32213
|
+
import * as child_process3 from "child_process";
|
|
32171
32214
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
32172
32215
|
import { readdir as readdir2, readFile as readFile4, stat } from "fs/promises";
|
|
32173
32216
|
import * as path17 from "path";
|
|
32174
32217
|
import { promisify } from "util";
|
|
32175
32218
|
function getExecFileAsync() {
|
|
32176
|
-
return promisify(
|
|
32219
|
+
return promisify(child_process3.execFile);
|
|
32177
32220
|
}
|
|
32178
32221
|
async function parseGitLog(directory, maxCommits) {
|
|
32179
32222
|
const commitMap = new Map;
|
|
@@ -43290,6 +43333,52 @@ import { execFileSync } from "child_process";
|
|
|
43290
43333
|
import { promises as fs9 } from "fs";
|
|
43291
43334
|
import path14 from "path";
|
|
43292
43335
|
|
|
43336
|
+
// src/git/branch.ts
|
|
43337
|
+
init_logger();
|
|
43338
|
+
import * as child_process2 from "child_process";
|
|
43339
|
+
var GIT_TIMEOUT_MS2 = 30000;
|
|
43340
|
+
function gitExec2(args2, cwd) {
|
|
43341
|
+
const result = child_process2.spawnSync("git", args2, {
|
|
43342
|
+
cwd,
|
|
43343
|
+
encoding: "utf-8",
|
|
43344
|
+
timeout: GIT_TIMEOUT_MS2,
|
|
43345
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
43346
|
+
});
|
|
43347
|
+
if (result.status !== 0) {
|
|
43348
|
+
throw new Error(result.stderr || `git exited with ${result.status}`);
|
|
43349
|
+
}
|
|
43350
|
+
return result.stdout;
|
|
43351
|
+
}
|
|
43352
|
+
function isGitRepo2(cwd) {
|
|
43353
|
+
try {
|
|
43354
|
+
gitExec2(["rev-parse", "--git-dir"], cwd);
|
|
43355
|
+
return true;
|
|
43356
|
+
} catch {
|
|
43357
|
+
return false;
|
|
43358
|
+
}
|
|
43359
|
+
}
|
|
43360
|
+
function getCurrentBranch(cwd) {
|
|
43361
|
+
const output = gitExec2(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
|
|
43362
|
+
return output.trim();
|
|
43363
|
+
}
|
|
43364
|
+
function getDefaultBaseBranch(cwd) {
|
|
43365
|
+
try {
|
|
43366
|
+
gitExec2(["rev-parse", "--verify", "origin/main"], cwd);
|
|
43367
|
+
return "origin/main";
|
|
43368
|
+
} catch {
|
|
43369
|
+
try {
|
|
43370
|
+
gitExec2(["rev-parse", "--verify", "origin/master"], cwd);
|
|
43371
|
+
return "origin/master";
|
|
43372
|
+
} catch {
|
|
43373
|
+
return "origin/main";
|
|
43374
|
+
}
|
|
43375
|
+
}
|
|
43376
|
+
}
|
|
43377
|
+
function hasUncommittedChanges(cwd) {
|
|
43378
|
+
const status = gitExec2(["status", "--porcelain"], cwd);
|
|
43379
|
+
return status.trim().length > 0;
|
|
43380
|
+
}
|
|
43381
|
+
|
|
43293
43382
|
// src/hooks/knowledge-reader.ts
|
|
43294
43383
|
init_knowledge_store();
|
|
43295
43384
|
import { existsSync as existsSync5 } from "fs";
|
|
@@ -44681,8 +44770,28 @@ var write_retro = createSwarmTool({
|
|
|
44681
44770
|
});
|
|
44682
44771
|
|
|
44683
44772
|
// src/commands/close.ts
|
|
44773
|
+
var ARCHIVE_ARTIFACTS = [
|
|
44774
|
+
"plan.json",
|
|
44775
|
+
"plan.md",
|
|
44776
|
+
"context.md",
|
|
44777
|
+
"events.jsonl",
|
|
44778
|
+
"handoff.md",
|
|
44779
|
+
"handoff-prompt.md",
|
|
44780
|
+
"handoff-consumed.md",
|
|
44781
|
+
"escalation-report.md",
|
|
44782
|
+
"close-lessons.md"
|
|
44783
|
+
];
|
|
44784
|
+
var ACTIVE_STATE_TO_CLEAN = [
|
|
44785
|
+
"plan.md",
|
|
44786
|
+
"events.jsonl",
|
|
44787
|
+
"handoff.md",
|
|
44788
|
+
"handoff-prompt.md",
|
|
44789
|
+
"handoff-consumed.md",
|
|
44790
|
+
"escalation-report.md"
|
|
44791
|
+
];
|
|
44684
44792
|
async function handleCloseCommand(directory, args2) {
|
|
44685
44793
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
44794
|
+
const swarmDir = path14.join(directory, ".swarm");
|
|
44686
44795
|
let planExists = false;
|
|
44687
44796
|
let planData = {
|
|
44688
44797
|
title: path14.basename(directory) || "Ad-hoc session",
|
|
@@ -44696,13 +44805,14 @@ async function handleCloseCommand(directory, args2) {
|
|
|
44696
44805
|
if (error93?.code !== "ENOENT") {
|
|
44697
44806
|
return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
44698
44807
|
}
|
|
44699
|
-
const swarmDirExists = await fs9.access(
|
|
44808
|
+
const swarmDirExists = await fs9.access(swarmDir).then(() => true).catch(() => false);
|
|
44700
44809
|
if (!swarmDirExists) {
|
|
44701
44810
|
return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
|
|
44702
44811
|
}
|
|
44703
44812
|
}
|
|
44704
44813
|
const phases = planData.phases ?? [];
|
|
44705
44814
|
const inProgressPhases = phases.filter((p) => p.status === "in_progress");
|
|
44815
|
+
const isForced = args2.includes("--force");
|
|
44706
44816
|
let planAlreadyDone = false;
|
|
44707
44817
|
if (planExists) {
|
|
44708
44818
|
planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
|
|
@@ -44719,7 +44829,7 @@ async function handleCloseCommand(directory, args2) {
|
|
|
44719
44829
|
try {
|
|
44720
44830
|
retroResult = await executeWriteRetro({
|
|
44721
44831
|
phase: phase.id,
|
|
44722
|
-
summary:
|
|
44832
|
+
summary: isForced ? `Phase force-closed via /swarm close --force` : `Phase closed via /swarm close`,
|
|
44723
44833
|
task_count: Math.max(1, (phase.tasks ?? []).length),
|
|
44724
44834
|
task_complexity: "simple",
|
|
44725
44835
|
total_tool_calls: 0,
|
|
@@ -44747,7 +44857,7 @@ async function handleCloseCommand(directory, args2) {
|
|
|
44747
44857
|
}
|
|
44748
44858
|
}
|
|
44749
44859
|
}
|
|
44750
|
-
const lessonsFilePath = path14.join(
|
|
44860
|
+
const lessonsFilePath = path14.join(swarmDir, "close-lessons.md");
|
|
44751
44861
|
let explicitLessons = [];
|
|
44752
44862
|
try {
|
|
44753
44863
|
const lessonsText = await fs9.readFile(lessonsFilePath, "utf-8");
|
|
@@ -44787,13 +44897,83 @@ async function handleCloseCommand(directory, args2) {
|
|
|
44787
44897
|
console.warn("[close-command] Failed to write plan.json:", error93);
|
|
44788
44898
|
}
|
|
44789
44899
|
}
|
|
44900
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
44901
|
+
const archiveDir = path14.join(swarmDir, "archive", `swarm-${timestamp}`);
|
|
44902
|
+
let archiveResult = "";
|
|
44903
|
+
let archivedFileCount = 0;
|
|
44904
|
+
const archivedActiveStateFiles = new Set;
|
|
44905
|
+
try {
|
|
44906
|
+
await fs9.mkdir(archiveDir, { recursive: true });
|
|
44907
|
+
for (const artifact of ARCHIVE_ARTIFACTS) {
|
|
44908
|
+
const srcPath = path14.join(swarmDir, artifact);
|
|
44909
|
+
const destPath = path14.join(archiveDir, artifact);
|
|
44910
|
+
try {
|
|
44911
|
+
await fs9.copyFile(srcPath, destPath);
|
|
44912
|
+
archivedFileCount++;
|
|
44913
|
+
if (ACTIVE_STATE_TO_CLEAN.includes(artifact)) {
|
|
44914
|
+
archivedActiveStateFiles.add(artifact);
|
|
44915
|
+
}
|
|
44916
|
+
} catch {}
|
|
44917
|
+
}
|
|
44918
|
+
const evidenceDir = path14.join(swarmDir, "evidence");
|
|
44919
|
+
const archiveEvidenceDir = path14.join(archiveDir, "evidence");
|
|
44920
|
+
try {
|
|
44921
|
+
const evidenceEntries = await fs9.readdir(evidenceDir);
|
|
44922
|
+
if (evidenceEntries.length > 0) {
|
|
44923
|
+
await fs9.mkdir(archiveEvidenceDir, { recursive: true });
|
|
44924
|
+
for (const entry of evidenceEntries) {
|
|
44925
|
+
const srcEntry = path14.join(evidenceDir, entry);
|
|
44926
|
+
const destEntry = path14.join(archiveEvidenceDir, entry);
|
|
44927
|
+
try {
|
|
44928
|
+
const stat = await fs9.stat(srcEntry);
|
|
44929
|
+
if (stat.isDirectory()) {
|
|
44930
|
+
await fs9.mkdir(destEntry, { recursive: true });
|
|
44931
|
+
const subEntries = await fs9.readdir(srcEntry);
|
|
44932
|
+
for (const sub of subEntries) {
|
|
44933
|
+
await fs9.copyFile(path14.join(srcEntry, sub), path14.join(destEntry, sub)).catch(() => {});
|
|
44934
|
+
}
|
|
44935
|
+
} else {
|
|
44936
|
+
await fs9.copyFile(srcEntry, destEntry);
|
|
44937
|
+
}
|
|
44938
|
+
archivedFileCount++;
|
|
44939
|
+
} catch {}
|
|
44940
|
+
}
|
|
44941
|
+
}
|
|
44942
|
+
} catch {}
|
|
44943
|
+
const sessionStatePath = path14.join(swarmDir, "session", "state.json");
|
|
44944
|
+
try {
|
|
44945
|
+
const archiveSessionDir = path14.join(archiveDir, "session");
|
|
44946
|
+
await fs9.mkdir(archiveSessionDir, { recursive: true });
|
|
44947
|
+
await fs9.copyFile(sessionStatePath, path14.join(archiveSessionDir, "state.json"));
|
|
44948
|
+
archivedFileCount++;
|
|
44949
|
+
} catch {}
|
|
44950
|
+
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
|
|
44951
|
+
} catch (archiveError) {
|
|
44952
|
+
warnings.push(`Archive creation failed: ${archiveError instanceof Error ? archiveError.message : String(archiveError)}`);
|
|
44953
|
+
archiveResult = "Archive creation failed (see warnings)";
|
|
44954
|
+
}
|
|
44790
44955
|
try {
|
|
44791
44956
|
await archiveEvidence(directory, 30, 10);
|
|
44792
44957
|
} catch (error93) {
|
|
44793
44958
|
console.warn("[close-command] archiveEvidence error:", error93);
|
|
44794
44959
|
}
|
|
44795
|
-
const swarmDir = path14.join(directory, ".swarm");
|
|
44796
44960
|
let configBackupsRemoved = 0;
|
|
44961
|
+
const cleanedFiles = [];
|
|
44962
|
+
if (archivedActiveStateFiles.size > 0) {
|
|
44963
|
+
for (const artifact of ACTIVE_STATE_TO_CLEAN) {
|
|
44964
|
+
if (!archivedActiveStateFiles.has(artifact)) {
|
|
44965
|
+
warnings.push(`Preserved ${artifact} because it was not successfully archived.`);
|
|
44966
|
+
continue;
|
|
44967
|
+
}
|
|
44968
|
+
const filePath = path14.join(swarmDir, artifact);
|
|
44969
|
+
try {
|
|
44970
|
+
await fs9.unlink(filePath);
|
|
44971
|
+
cleanedFiles.push(artifact);
|
|
44972
|
+
} catch {}
|
|
44973
|
+
}
|
|
44974
|
+
} else {
|
|
44975
|
+
warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");
|
|
44976
|
+
}
|
|
44797
44977
|
try {
|
|
44798
44978
|
const swarmFiles = await fs9.readdir(swarmDir);
|
|
44799
44979
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
@@ -44804,13 +44984,14 @@ async function handleCloseCommand(directory, args2) {
|
|
|
44804
44984
|
} catch {}
|
|
44805
44985
|
}
|
|
44806
44986
|
} catch {}
|
|
44807
|
-
const contextPath = path14.join(
|
|
44987
|
+
const contextPath = path14.join(swarmDir, "context.md");
|
|
44808
44988
|
const contextContent = [
|
|
44809
44989
|
"# Context",
|
|
44810
44990
|
"",
|
|
44811
44991
|
"## Status",
|
|
44812
44992
|
`Session closed after: ${projectName}`,
|
|
44813
44993
|
`Closed: ${new Date().toISOString()}`,
|
|
44994
|
+
`Finalization: ${isForced ? "forced" : planAlreadyDone ? "plan-already-done" : "normal"}`,
|
|
44814
44995
|
"No active plan. Next session starts fresh.",
|
|
44815
44996
|
""
|
|
44816
44997
|
].join(`
|
|
@@ -44823,46 +45004,112 @@ async function handleCloseCommand(directory, args2) {
|
|
|
44823
45004
|
const pruneBranches = args2.includes("--prune-branches");
|
|
44824
45005
|
const prunedBranches = [];
|
|
44825
45006
|
const pruneErrors = [];
|
|
44826
|
-
|
|
45007
|
+
let gitAlignResult = "";
|
|
45008
|
+
const isGit = isGitRepo2(directory);
|
|
45009
|
+
if (isGit) {
|
|
44827
45010
|
try {
|
|
44828
|
-
const
|
|
44829
|
-
|
|
44830
|
-
|
|
44831
|
-
|
|
44832
|
-
})
|
|
44833
|
-
|
|
44834
|
-
|
|
44835
|
-
|
|
44836
|
-
|
|
44837
|
-
|
|
44838
|
-
|
|
44839
|
-
|
|
44840
|
-
|
|
44841
|
-
|
|
44842
|
-
|
|
44843
|
-
|
|
44844
|
-
|
|
45011
|
+
const currentBranch = getCurrentBranch(directory);
|
|
45012
|
+
if (currentBranch === "HEAD") {
|
|
45013
|
+
gitAlignResult = "Skipped git alignment: detached HEAD state";
|
|
45014
|
+
warnings.push("Repo is in detached HEAD state. Checkout a branch before starting a new swarm.");
|
|
45015
|
+
} else if (hasUncommittedChanges(directory)) {
|
|
45016
|
+
gitAlignResult = "Skipped git alignment: uncommitted changes in worktree";
|
|
45017
|
+
warnings.push("Uncommitted changes detected. Commit or stash before aligning to main.");
|
|
45018
|
+
} else {
|
|
45019
|
+
const baseBranch = getDefaultBaseBranch(directory);
|
|
45020
|
+
const localBase = baseBranch.replace(/^origin\//, "");
|
|
45021
|
+
if (currentBranch === localBase) {
|
|
45022
|
+
try {
|
|
45023
|
+
execFileSync("git", ["fetch", "origin", localBase], {
|
|
45024
|
+
cwd: directory,
|
|
45025
|
+
encoding: "utf-8",
|
|
45026
|
+
timeout: 30000,
|
|
45027
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
45028
|
+
});
|
|
45029
|
+
const mergeBase = execFileSync("git", ["merge-base", "HEAD", baseBranch], {
|
|
45030
|
+
cwd: directory,
|
|
45031
|
+
encoding: "utf-8",
|
|
45032
|
+
timeout: 1e4,
|
|
45033
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
45034
|
+
}).trim();
|
|
45035
|
+
const headSha = execFileSync("git", ["rev-parse", "HEAD"], {
|
|
45036
|
+
cwd: directory,
|
|
45037
|
+
encoding: "utf-8",
|
|
45038
|
+
timeout: 1e4,
|
|
45039
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
45040
|
+
}).trim();
|
|
45041
|
+
if (mergeBase === headSha) {
|
|
45042
|
+
execFileSync("git", ["merge", "--ff-only", baseBranch], {
|
|
45043
|
+
cwd: directory,
|
|
45044
|
+
encoding: "utf-8",
|
|
45045
|
+
timeout: 30000,
|
|
45046
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
45047
|
+
});
|
|
45048
|
+
gitAlignResult = `Aligned to ${baseBranch} (fast-forward)`;
|
|
45049
|
+
} else {
|
|
45050
|
+
gitAlignResult = `On ${localBase} but cannot fast-forward to ${baseBranch} (diverged)`;
|
|
45051
|
+
warnings.push(`Local ${localBase} has diverged from ${baseBranch}. Manual merge/rebase needed.`);
|
|
45052
|
+
}
|
|
45053
|
+
} catch (fetchErr) {
|
|
45054
|
+
gitAlignResult = `Fetch from origin/${localBase} failed \u2014 remote may be unavailable`;
|
|
45055
|
+
warnings.push(`Git fetch failed: ${fetchErr instanceof Error ? fetchErr.message : String(fetchErr)}`);
|
|
45056
|
+
}
|
|
45057
|
+
} else {
|
|
45058
|
+
gitAlignResult = `On branch ${currentBranch}. Switch to ${localBase} manually when ready for a new swarm.`;
|
|
44845
45059
|
}
|
|
44846
45060
|
}
|
|
44847
|
-
} catch {
|
|
45061
|
+
} catch (gitError) {
|
|
45062
|
+
gitAlignResult = `Git alignment error: ${gitError instanceof Error ? gitError.message : String(gitError)}`;
|
|
45063
|
+
}
|
|
45064
|
+
if (pruneBranches) {
|
|
45065
|
+
try {
|
|
45066
|
+
const branchOutput = execFileSync("git", ["branch", "-vv"], {
|
|
45067
|
+
cwd: directory,
|
|
45068
|
+
encoding: "utf-8",
|
|
45069
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
45070
|
+
});
|
|
45071
|
+
const goneBranches = branchOutput.split(`
|
|
45072
|
+
`).filter((line) => line.includes(": gone]")).map((line) => line.trim().replace(/^[*+]\s+/, "").split(/\s+/)[0]).filter(Boolean);
|
|
45073
|
+
for (const branch of goneBranches) {
|
|
45074
|
+
try {
|
|
45075
|
+
execFileSync("git", ["branch", "-d", branch], {
|
|
45076
|
+
cwd: directory,
|
|
45077
|
+
encoding: "utf-8",
|
|
45078
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
45079
|
+
});
|
|
45080
|
+
prunedBranches.push(branch);
|
|
45081
|
+
} catch {
|
|
45082
|
+
pruneErrors.push(branch);
|
|
45083
|
+
}
|
|
45084
|
+
}
|
|
45085
|
+
} catch {}
|
|
45086
|
+
}
|
|
45087
|
+
} else {
|
|
45088
|
+
gitAlignResult = "Not a git repository \u2014 skipped git alignment";
|
|
44848
45089
|
}
|
|
44849
45090
|
const closeSummaryPath = validateSwarmPath(directory, "close-summary.md");
|
|
45091
|
+
const finalizationType = isForced ? "Forced closure" : planAlreadyDone ? "Plan already terminal \u2014 cleanup only" : "Normal finalization";
|
|
44850
45092
|
const actionsPerformed = [
|
|
44851
45093
|
...!planAlreadyDone && inProgressPhases.length > 0 ? ["- Wrote retrospectives for in-progress phases"] : [],
|
|
44852
|
-
|
|
45094
|
+
`- ${archiveResult}`,
|
|
45095
|
+
...cleanedFiles.length > 0 ? [
|
|
45096
|
+
`- Cleaned ${cleanedFiles.length} active-state file(s): ${cleanedFiles.join(", ")}`
|
|
45097
|
+
] : [],
|
|
44853
45098
|
"- Reset context.md for next session",
|
|
44854
45099
|
...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
|
|
44855
45100
|
...prunedBranches.length > 0 ? [
|
|
44856
45101
|
`- Pruned ${prunedBranches.length} stale local git branch(es): ${prunedBranches.join(", ")}`
|
|
44857
45102
|
] : [],
|
|
44858
45103
|
"- Cleared agent sessions and delegation chains",
|
|
44859
|
-
...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : []
|
|
45104
|
+
...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : [],
|
|
45105
|
+
...gitAlignResult ? [`- Git: ${gitAlignResult}`] : []
|
|
44860
45106
|
];
|
|
44861
45107
|
const summaryContent = [
|
|
44862
45108
|
"# Swarm Close Summary",
|
|
44863
45109
|
"",
|
|
44864
45110
|
`**Project:** ${projectName}`,
|
|
44865
45111
|
`**Closed:** ${new Date().toISOString()}`,
|
|
45112
|
+
`**Finalization:** ${finalizationType}`,
|
|
44866
45113
|
"",
|
|
44867
45114
|
`## Phases Closed: ${closedPhases.length}`,
|
|
44868
45115
|
!planExists ? "_No plan \u2014 ad-hoc session_" : closedPhases.length > 0 ? closedPhases.map((id) => `- Phase ${id}`).join(`
|
|
@@ -44873,7 +45120,9 @@ async function handleCloseCommand(directory, args2) {
|
|
|
44873
45120
|
`) : "_No incomplete tasks_",
|
|
44874
45121
|
"",
|
|
44875
45122
|
"## Actions Performed",
|
|
44876
|
-
...actionsPerformed
|
|
45123
|
+
...actionsPerformed,
|
|
45124
|
+
"",
|
|
45125
|
+
...warnings.length > 0 ? ["## Warnings", ...warnings.map((w) => `- ${w}`), ""] : []
|
|
44877
45126
|
].join(`
|
|
44878
45127
|
`);
|
|
44879
45128
|
try {
|
|
@@ -44892,11 +45141,21 @@ async function handleCloseCommand(directory, args2) {
|
|
|
44892
45141
|
if (pruneErrors.length > 0) {
|
|
44893
45142
|
warnings.push(`Could not prune ${pruneErrors.length} branch(es) (unmerged or checked out): ${pruneErrors.join(", ")}`);
|
|
44894
45143
|
}
|
|
44895
|
-
const warningMsg = warnings.length > 0 ? `
|
|
45144
|
+
const warningMsg = warnings.length > 0 ? `
|
|
45145
|
+
|
|
45146
|
+
**Warnings:**
|
|
45147
|
+
${warnings.map((w) => `- ${w}`).join(`
|
|
45148
|
+
`)}` : "";
|
|
44896
45149
|
if (planAlreadyDone) {
|
|
44897
|
-
return `\u2705 Session
|
|
45150
|
+
return `\u2705 Session finalized. Plan was already in a terminal state \u2014 cleanup and archive applied.
|
|
45151
|
+
|
|
45152
|
+
**Archive:** ${archiveResult}
|
|
45153
|
+
**Git:** ${gitAlignResult}${warningMsg}`;
|
|
44898
45154
|
}
|
|
44899
|
-
return `\u2705 Swarm
|
|
45155
|
+
return `\u2705 Swarm finalized. ${closedPhases.length} phase(s) closed, ${closedTasks.length} incomplete task(s) marked closed.
|
|
45156
|
+
|
|
45157
|
+
**Archive:** ${archiveResult}
|
|
45158
|
+
**Git:** ${gitAlignResult}${warningMsg}`;
|
|
44900
45159
|
}
|
|
44901
45160
|
|
|
44902
45161
|
// src/commands/config.ts
|
|
@@ -46051,7 +46310,7 @@ init_loader();
|
|
|
46051
46310
|
init_manager();
|
|
46052
46311
|
init_utils2();
|
|
46053
46312
|
init_manager2();
|
|
46054
|
-
import * as
|
|
46313
|
+
import * as child_process4 from "child_process";
|
|
46055
46314
|
import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
46056
46315
|
import path19 from "path";
|
|
46057
46316
|
import { fileURLToPath } from "url";
|
|
@@ -46293,7 +46552,7 @@ async function checkGitRepository(directory) {
|
|
|
46293
46552
|
detail: "Invalid directory \u2014 cannot check git status"
|
|
46294
46553
|
};
|
|
46295
46554
|
}
|
|
46296
|
-
|
|
46555
|
+
child_process4.execSync("git rev-parse --git-dir", {
|
|
46297
46556
|
cwd: directory,
|
|
46298
46557
|
stdio: "pipe"
|
|
46299
46558
|
});
|
|
@@ -47177,7 +47436,7 @@ async function handleExportCommand(directory, _args) {
|
|
|
47177
47436
|
init_state();
|
|
47178
47437
|
async function handleFullAutoCommand(_directory, args2, sessionID) {
|
|
47179
47438
|
if (!sessionID || sessionID.trim() === "") {
|
|
47180
|
-
return "Error: No active session context. Full-Auto Mode requires an active session. Use /swarm
|
|
47439
|
+
return "Error: No active session context. Full-Auto Mode requires an active session. Use /swarm-full-auto from within an OpenCode session, or start a session first.";
|
|
47181
47440
|
}
|
|
47182
47441
|
const session = getAgentSession(sessionID);
|
|
47183
47442
|
if (!session) {
|
|
@@ -47185,16 +47444,15 @@ async function handleFullAutoCommand(_directory, args2, sessionID) {
|
|
|
47185
47444
|
}
|
|
47186
47445
|
const arg = args2[0]?.toLowerCase();
|
|
47187
47446
|
let newFullAutoMode;
|
|
47188
|
-
let feedback;
|
|
47189
47447
|
if (arg === "on") {
|
|
47190
47448
|
newFullAutoMode = true;
|
|
47191
|
-
feedback = "Full-Auto Mode enabled";
|
|
47192
47449
|
} else if (arg === "off") {
|
|
47193
47450
|
newFullAutoMode = false;
|
|
47194
|
-
feedback = "Full-Auto Mode disabled";
|
|
47195
47451
|
} else {
|
|
47196
47452
|
newFullAutoMode = !session.fullAutoMode;
|
|
47197
|
-
|
|
47453
|
+
}
|
|
47454
|
+
if (newFullAutoMode && !swarmState.fullAutoEnabledInConfig) {
|
|
47455
|
+
return "Error: Full-Auto Mode cannot be enabled because full_auto.enabled is not set to true in the swarm plugin config. The autonomous oversight hook is inactive without config-level enablement. Set full_auto.enabled = true in your opencode-swarm config and restart.";
|
|
47198
47456
|
}
|
|
47199
47457
|
session.fullAutoMode = newFullAutoMode;
|
|
47200
47458
|
if (!newFullAutoMode) {
|
|
@@ -47202,7 +47460,7 @@ async function handleFullAutoCommand(_directory, args2, sessionID) {
|
|
|
47202
47460
|
session.fullAutoDeadlockCount = 0;
|
|
47203
47461
|
session.fullAutoLastQuestionHash = null;
|
|
47204
47462
|
}
|
|
47205
|
-
return
|
|
47463
|
+
return newFullAutoMode ? "Full-Auto Mode enabled" : "Full-Auto Mode disabled";
|
|
47206
47464
|
}
|
|
47207
47465
|
|
|
47208
47466
|
// src/commands/handoff.ts
|
|
@@ -47510,6 +47768,64 @@ function formatHandoffMarkdown(data) {
|
|
|
47510
47768
|
return lines.join(`
|
|
47511
47769
|
`);
|
|
47512
47770
|
}
|
|
47771
|
+
function formatContinuationPrompt(data) {
|
|
47772
|
+
const lines = [];
|
|
47773
|
+
lines.push("## Resume Swarm");
|
|
47774
|
+
lines.push("");
|
|
47775
|
+
if (data.currentPhase) {
|
|
47776
|
+
lines.push(`**Phase**: ${data.currentPhase}`);
|
|
47777
|
+
}
|
|
47778
|
+
if (data.currentTask) {
|
|
47779
|
+
lines.push(`**Current Task**: ${data.currentTask}`);
|
|
47780
|
+
}
|
|
47781
|
+
let nextTask;
|
|
47782
|
+
if (data.incompleteTasks.length > 0) {
|
|
47783
|
+
nextTask = data.incompleteTasks.find((t) => t !== data.currentTask);
|
|
47784
|
+
if (nextTask) {
|
|
47785
|
+
lines.push(`**Next Task**: ${nextTask}`);
|
|
47786
|
+
}
|
|
47787
|
+
}
|
|
47788
|
+
if (data.pendingQA) {
|
|
47789
|
+
lines.push("");
|
|
47790
|
+
lines.push(`**Pending QA Blocker**: ${data.pendingQA.taskId}`);
|
|
47791
|
+
if (data.pendingQA.lastFailure) {
|
|
47792
|
+
lines.push(` - Last failure: ${data.pendingQA.lastFailure}`);
|
|
47793
|
+
}
|
|
47794
|
+
}
|
|
47795
|
+
if (data.recentDecisions.length > 0) {
|
|
47796
|
+
const last3 = data.recentDecisions.slice(-3);
|
|
47797
|
+
lines.push("");
|
|
47798
|
+
lines.push("**Recent Decisions (do not revisit)**:");
|
|
47799
|
+
for (const decision of last3) {
|
|
47800
|
+
lines.push(`- ${decision}`);
|
|
47801
|
+
}
|
|
47802
|
+
}
|
|
47803
|
+
if (data.incompleteTasks.length > 2) {
|
|
47804
|
+
const remaining = data.incompleteTasks.filter((t) => t !== data.currentTask && t !== nextTask);
|
|
47805
|
+
if (remaining.length > 0) {
|
|
47806
|
+
lines.push("");
|
|
47807
|
+
lines.push(`**Remaining Tasks**: ${remaining.slice(0, 8).join(", ")}${remaining.length > 8 ? ` (+${remaining.length - 8} more)` : ""}`);
|
|
47808
|
+
}
|
|
47809
|
+
}
|
|
47810
|
+
lines.push("");
|
|
47811
|
+
lines.push("**To resume**:");
|
|
47812
|
+
lines.push("1. Read `.swarm/handoff.md` for full context");
|
|
47813
|
+
lines.push("2. Use `knowledge_recall` to recall relevant lessons before starting");
|
|
47814
|
+
if (data.pendingQA) {
|
|
47815
|
+
lines.push(`3. Resolve QA blocker on task ${data.pendingQA.taskId} before continuing`);
|
|
47816
|
+
} else if (data.currentTask) {
|
|
47817
|
+
lines.push(`3. Continue work on task ${data.currentTask}`);
|
|
47818
|
+
} else if (nextTask) {
|
|
47819
|
+
lines.push(`3. Begin work on task ${nextTask}`);
|
|
47820
|
+
} else {
|
|
47821
|
+
lines.push("3. Review the plan and pick up the next incomplete task");
|
|
47822
|
+
}
|
|
47823
|
+
lines.push("4. Do not re-implement completed tasks or revisit settled decisions");
|
|
47824
|
+
return `\`\`\`markdown
|
|
47825
|
+
${lines.join(`
|
|
47826
|
+
`)}
|
|
47827
|
+
\`\`\``;
|
|
47828
|
+
}
|
|
47513
47829
|
|
|
47514
47830
|
// src/commands/handoff.ts
|
|
47515
47831
|
init_state();
|
|
@@ -47520,17 +47836,27 @@ async function handleHandoffCommand(directory, _args) {
|
|
|
47520
47836
|
const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
|
|
47521
47837
|
await Bun.write(tempPath, markdown);
|
|
47522
47838
|
renameSync7(tempPath, resolvedPath);
|
|
47839
|
+
const continuationPrompt = formatContinuationPrompt(handoffData);
|
|
47840
|
+
const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
|
|
47841
|
+
const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
|
|
47842
|
+
await Bun.write(promptTempPath, continuationPrompt);
|
|
47843
|
+
renameSync7(promptTempPath, promptPath);
|
|
47523
47844
|
await writeSnapshot(directory, swarmState);
|
|
47524
47845
|
await flushPendingSnapshot(directory);
|
|
47525
47846
|
return `## Handoff Brief Written
|
|
47526
47847
|
|
|
47527
47848
|
Brief written to \`.swarm/handoff.md\`.
|
|
47849
|
+
Continuation prompt written to \`.swarm/handoff-prompt.md\`.
|
|
47528
47850
|
|
|
47529
47851
|
${markdown}
|
|
47530
47852
|
|
|
47531
47853
|
---
|
|
47532
47854
|
|
|
47533
|
-
|
|
47855
|
+
## Continuation Prompt
|
|
47856
|
+
|
|
47857
|
+
Copy and paste the block below into your next session to resume cleanly:
|
|
47858
|
+
|
|
47859
|
+
${continuationPrompt}`;
|
|
47534
47860
|
}
|
|
47535
47861
|
|
|
47536
47862
|
// src/services/history-service.ts
|
|
@@ -56161,12 +56487,23 @@ init_state();
|
|
|
56161
56487
|
init_telemetry();
|
|
56162
56488
|
init_utils2();
|
|
56163
56489
|
var END_OF_SENTENCE_QUESTION_PATTERN = /\?\s*$/;
|
|
56164
|
-
var
|
|
56165
|
-
/Ready for Phase (?:\d+|\[?N\+1\]?)
|
|
56490
|
+
var PHASE_COMPLETION_PATTERNS = [
|
|
56491
|
+
/Ready for Phase (?:\d+|\[?N\+1\]?)\??/i,
|
|
56492
|
+
/phase.{0,20}(?:complete|finish|done|wrap)/i,
|
|
56493
|
+
/move(?:d?)?\s+(?:on\s+)?to\s+(?:the\s+)?(?:next\s+)?phase/i
|
|
56494
|
+
];
|
|
56495
|
+
var QUESTION_ESCALATION_PATTERNS = [
|
|
56166
56496
|
/escalat/i,
|
|
56167
56497
|
/What would you like/i,
|
|
56168
56498
|
/Should I proceed/i,
|
|
56169
|
-
/Do you want/i
|
|
56499
|
+
/Do you want/i,
|
|
56500
|
+
/Shall I/i,
|
|
56501
|
+
/Would you like/i,
|
|
56502
|
+
/Can I proceed/i,
|
|
56503
|
+
/May I proceed/i,
|
|
56504
|
+
/Awaiting (?:your |)(?:approval|confirmation|input|decision|direction)/i,
|
|
56505
|
+
/Please (?:confirm|approve|advise|let me know)/i,
|
|
56506
|
+
/How (?:would you like|should I)/i
|
|
56170
56507
|
];
|
|
56171
56508
|
var MID_SENTENCE_QUESTION_PATTERNS = [
|
|
56172
56509
|
/\b(v\d+\?)/i,
|
|
@@ -56203,11 +56540,16 @@ function resolveOversightAgentName(architectAgentName) {
|
|
|
56203
56540
|
return `${prefix}critic_oversight`;
|
|
56204
56541
|
}
|
|
56205
56542
|
function detectEscalation(text) {
|
|
56206
|
-
for (const pattern of
|
|
56543
|
+
for (const pattern of PHASE_COMPLETION_PATTERNS) {
|
|
56207
56544
|
if (pattern.test(text)) {
|
|
56208
56545
|
return "phase_completion";
|
|
56209
56546
|
}
|
|
56210
56547
|
}
|
|
56548
|
+
for (const pattern of QUESTION_ESCALATION_PATTERNS) {
|
|
56549
|
+
if (pattern.test(text)) {
|
|
56550
|
+
return "question";
|
|
56551
|
+
}
|
|
56552
|
+
}
|
|
56211
56553
|
if (END_OF_SENTENCE_QUESTION_PATTERN.test(text)) {
|
|
56212
56554
|
if (!isMidSentenceQuestion(text)) {
|
|
56213
56555
|
return "question";
|
|
@@ -56349,7 +56691,7 @@ async function writeAutoOversightEvent(directory, architectOutput, criticVerdict
|
|
|
56349
56691
|
}
|
|
56350
56692
|
}
|
|
56351
56693
|
}
|
|
56352
|
-
function injectVerdictIntoMessages(messages, architectIndex, criticResult,
|
|
56694
|
+
function injectVerdictIntoMessages(messages, architectIndex, criticResult, escalationType, oversightAgentName) {
|
|
56353
56695
|
if (criticResult.escalationNeeded || criticResult.verdict === "ESCALATE_TO_HUMAN") {
|
|
56354
56696
|
const verdictMessage2 = {
|
|
56355
56697
|
info: {
|
|
@@ -56386,6 +56728,19 @@ ${criticResult.reasoning}`
|
|
|
56386
56728
|
]
|
|
56387
56729
|
};
|
|
56388
56730
|
messages.splice(architectIndex + 1, 0, verdictMessage2);
|
|
56731
|
+
const continuationMessage = {
|
|
56732
|
+
info: {
|
|
56733
|
+
role: "user",
|
|
56734
|
+
agent: oversightAgentName
|
|
56735
|
+
},
|
|
56736
|
+
parts: [
|
|
56737
|
+
{
|
|
56738
|
+
type: "text",
|
|
56739
|
+
text: "[FULL-AUTO CONTINUATION] The critic has answered your question. Incorporate the answer above and continue executing the current plan. Do not ask follow-up questions about this answer \u2014 proceed with implementation."
|
|
56740
|
+
}
|
|
56741
|
+
]
|
|
56742
|
+
};
|
|
56743
|
+
messages.splice(architectIndex + 2, 0, continuationMessage);
|
|
56389
56744
|
return;
|
|
56390
56745
|
}
|
|
56391
56746
|
const verdictEmoji = criticResult.verdict === "APPROVED" ? "\u2705" : criticResult.verdict === "NEEDS_REVISION" ? "\uD83D\uDD04" : criticResult.verdict === "REJECTED" ? "\u274C" : criticResult.verdict === "BLOCKED" ? "\uD83D\uDEAB" : "\uD83D\uDCAC";
|
|
@@ -56404,6 +56759,35 @@ Critic reasoning: ${criticResult.reasoning}`
|
|
|
56404
56759
|
]
|
|
56405
56760
|
};
|
|
56406
56761
|
messages.splice(architectIndex + 1, 0, verdictMessage);
|
|
56762
|
+
if (criticResult.verdict === "APPROVED" && escalationType === "phase_completion") {
|
|
56763
|
+
const continuationMessage = {
|
|
56764
|
+
info: {
|
|
56765
|
+
role: "user",
|
|
56766
|
+
agent: oversightAgentName
|
|
56767
|
+
},
|
|
56768
|
+
parts: [
|
|
56769
|
+
{
|
|
56770
|
+
type: "text",
|
|
56771
|
+
text: "[FULL-AUTO CONTINUATION] Phase approved by autonomous oversight. Call `phase_complete` now to finalize this phase, then proceed to the next phase in the plan. Do not wait for further human input."
|
|
56772
|
+
}
|
|
56773
|
+
]
|
|
56774
|
+
};
|
|
56775
|
+
messages.splice(architectIndex + 2, 0, continuationMessage);
|
|
56776
|
+
} else if (criticResult.verdict === "APPROVED") {
|
|
56777
|
+
const continuationMessage = {
|
|
56778
|
+
info: {
|
|
56779
|
+
role: "user",
|
|
56780
|
+
agent: oversightAgentName
|
|
56781
|
+
},
|
|
56782
|
+
parts: [
|
|
56783
|
+
{
|
|
56784
|
+
type: "text",
|
|
56785
|
+
text: "[FULL-AUTO CONTINUATION] Approved by autonomous oversight. Continue executing the current task and plan. Do not wait for further human input."
|
|
56786
|
+
}
|
|
56787
|
+
]
|
|
56788
|
+
};
|
|
56789
|
+
messages.splice(architectIndex + 2, 0, continuationMessage);
|
|
56790
|
+
}
|
|
56407
56791
|
}
|
|
56408
56792
|
async function dispatchCriticAndWriteEvent(directory, architectOutput, criticContext, criticModel, escalationType, interactionCount, deadlockCount, oversightAgentName) {
|
|
56409
56793
|
const client = swarmState.opencodeClient;
|
|
@@ -57889,6 +58273,10 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
57889
58273
|
fs35.unlinkSync(consumedPath);
|
|
57890
58274
|
}
|
|
57891
58275
|
fs35.renameSync(handoffPath, consumedPath);
|
|
58276
|
+
try {
|
|
58277
|
+
const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
|
|
58278
|
+
fs35.unlinkSync(promptPath);
|
|
58279
|
+
} catch {}
|
|
57892
58280
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
57893
58281
|
The previous model's session ended. Here is your starting context:
|
|
57894
58282
|
|
|
@@ -59002,14 +59390,14 @@ import * as fs36 from "fs";
|
|
|
59002
59390
|
import * as path47 from "path";
|
|
59003
59391
|
|
|
59004
59392
|
// src/hooks/spawn-helper.ts
|
|
59005
|
-
import * as
|
|
59393
|
+
import * as child_process5 from "child_process";
|
|
59006
59394
|
var WIN32_CMD_BINARIES = new Set(["npm", "npx", "pnpm", "yarn"]);
|
|
59007
59395
|
function spawnAsync(command, cwd, timeoutMs) {
|
|
59008
59396
|
return new Promise((resolve15) => {
|
|
59009
59397
|
try {
|
|
59010
59398
|
const [rawCmd, ...args2] = command;
|
|
59011
59399
|
const cmd = process.platform === "win32" && WIN32_CMD_BINARIES.has(rawCmd) && !rawCmd.includes(".") ? `${rawCmd}.cmd` : rawCmd;
|
|
59012
|
-
const proc =
|
|
59400
|
+
const proc = child_process5.spawn(cmd, args2, {
|
|
59013
59401
|
cwd,
|
|
59014
59402
|
stdio: ["ignore", "pipe", "pipe"]
|
|
59015
59403
|
});
|
|
@@ -60017,6 +60405,9 @@ async function rehydrateState(snapshot) {
|
|
|
60017
60405
|
for (const field of TRANSIENT_SESSION_FIELDS) {
|
|
60018
60406
|
session[field.name] = field.resetValue;
|
|
60019
60407
|
}
|
|
60408
|
+
if (session.fullAutoMode && !swarmState.fullAutoEnabledInConfig) {
|
|
60409
|
+
session.fullAutoMode = false;
|
|
60410
|
+
}
|
|
60020
60411
|
swarmState.agentSessions.set(sessionId, session);
|
|
60021
60412
|
}
|
|
60022
60413
|
}
|
|
@@ -62418,7 +62809,7 @@ var declare_scope = createSwarmTool({
|
|
|
62418
62809
|
});
|
|
62419
62810
|
// src/tools/diff.ts
|
|
62420
62811
|
init_dist();
|
|
62421
|
-
import * as
|
|
62812
|
+
import * as child_process6 from "child_process";
|
|
62422
62813
|
|
|
62423
62814
|
// src/diff/ast-diff.ts
|
|
62424
62815
|
init_tree_sitter();
|
|
@@ -62786,13 +63177,13 @@ var diff = createSwarmTool({
|
|
|
62786
63177
|
numstatArgs.push("--", ...typedArgs.paths);
|
|
62787
63178
|
fullDiffArgs.push("--", ...typedArgs.paths);
|
|
62788
63179
|
}
|
|
62789
|
-
const numstatOutput =
|
|
63180
|
+
const numstatOutput = child_process6.execFileSync("git", numstatArgs, {
|
|
62790
63181
|
encoding: "utf-8",
|
|
62791
63182
|
timeout: DIFF_TIMEOUT_MS,
|
|
62792
63183
|
maxBuffer: MAX_BUFFER_BYTES,
|
|
62793
63184
|
cwd: directory
|
|
62794
63185
|
});
|
|
62795
|
-
const fullDiffOutput =
|
|
63186
|
+
const fullDiffOutput = child_process6.execFileSync("git", fullDiffArgs, {
|
|
62796
63187
|
encoding: "utf-8",
|
|
62797
63188
|
timeout: DIFF_TIMEOUT_MS,
|
|
62798
63189
|
maxBuffer: MAX_BUFFER_BYTES,
|
|
@@ -62841,23 +63232,23 @@ var diff = createSwarmTool({
|
|
|
62841
63232
|
let oldContent;
|
|
62842
63233
|
let newContent;
|
|
62843
63234
|
if (base === "staged") {
|
|
62844
|
-
oldContent =
|
|
63235
|
+
oldContent = child_process6.execFileSync("git", ["show", `HEAD:${file3.path}`], {
|
|
62845
63236
|
encoding: "utf-8",
|
|
62846
63237
|
timeout: 5000,
|
|
62847
63238
|
cwd: directory
|
|
62848
63239
|
});
|
|
62849
|
-
newContent =
|
|
63240
|
+
newContent = child_process6.execFileSync("git", ["show", `:${file3.path}`], {
|
|
62850
63241
|
encoding: "utf-8",
|
|
62851
63242
|
timeout: 5000,
|
|
62852
63243
|
cwd: directory
|
|
62853
63244
|
});
|
|
62854
63245
|
} else if (base === "unstaged") {
|
|
62855
|
-
oldContent =
|
|
63246
|
+
oldContent = child_process6.execFileSync("git", ["show", `:${file3.path}`], {
|
|
62856
63247
|
encoding: "utf-8",
|
|
62857
63248
|
timeout: 5000,
|
|
62858
63249
|
cwd: directory
|
|
62859
63250
|
});
|
|
62860
|
-
newContent =
|
|
63251
|
+
newContent = child_process6.execFileSync("git", ["show", `HEAD:${file3.path}`], {
|
|
62861
63252
|
encoding: "utf-8",
|
|
62862
63253
|
timeout: 5000,
|
|
62863
63254
|
cwd: directory
|
|
@@ -62866,12 +63257,12 @@ var diff = createSwarmTool({
|
|
|
62866
63257
|
const pathModule = await import("path");
|
|
62867
63258
|
newContent = fsModule.readFileSync(pathModule.join(directory, file3.path), "utf-8");
|
|
62868
63259
|
} else {
|
|
62869
|
-
oldContent =
|
|
63260
|
+
oldContent = child_process6.execFileSync("git", ["show", `${base}:${file3.path}`], {
|
|
62870
63261
|
encoding: "utf-8",
|
|
62871
63262
|
timeout: 5000,
|
|
62872
63263
|
cwd: directory
|
|
62873
63264
|
});
|
|
62874
|
-
newContent =
|
|
63265
|
+
newContent = child_process6.execFileSync("git", ["show", `HEAD:${file3.path}`], {
|
|
62875
63266
|
encoding: "utf-8",
|
|
62876
63267
|
timeout: 5000,
|
|
62877
63268
|
cwd: directory
|
|
@@ -67695,7 +68086,7 @@ function executeRulesSync(filePath, content, language) {
|
|
|
67695
68086
|
}
|
|
67696
68087
|
|
|
67697
68088
|
// src/sast/semgrep.ts
|
|
67698
|
-
import * as
|
|
68089
|
+
import * as child_process7 from "child_process";
|
|
67699
68090
|
var semgrepAvailableCache = null;
|
|
67700
68091
|
var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
|
|
67701
68092
|
var DEFAULT_TIMEOUT_MS3 = 30000;
|
|
@@ -67704,7 +68095,7 @@ function isSemgrepAvailable() {
|
|
|
67704
68095
|
return semgrepAvailableCache;
|
|
67705
68096
|
}
|
|
67706
68097
|
try {
|
|
67707
|
-
|
|
68098
|
+
child_process7.execFileSync("semgrep", ["--version"], {
|
|
67708
68099
|
encoding: "utf-8",
|
|
67709
68100
|
stdio: "pipe"
|
|
67710
68101
|
});
|
|
@@ -67763,7 +68154,7 @@ function mapSemgrepSeverity(severity) {
|
|
|
67763
68154
|
}
|
|
67764
68155
|
async function executeWithTimeout(command, args2, options) {
|
|
67765
68156
|
return new Promise((resolve24) => {
|
|
67766
|
-
const child =
|
|
68157
|
+
const child = child_process7.spawn(command, args2, {
|
|
67767
68158
|
shell: false,
|
|
67768
68159
|
cwd: options.cwd
|
|
67769
68160
|
});
|
|
@@ -72804,8 +73195,8 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
72804
73195
|
description: "Use /swarm turbo to enable turbo mode for faster execution"
|
|
72805
73196
|
},
|
|
72806
73197
|
"swarm-full-auto": {
|
|
72807
|
-
template: "/swarm
|
|
72808
|
-
description: "
|
|
73198
|
+
template: "/swarm-full-auto $ARGUMENTS",
|
|
73199
|
+
description: "Toggle Full-Auto Mode for the active session [on|off]"
|
|
72809
73200
|
},
|
|
72810
73201
|
"swarm-write-retro": {
|
|
72811
73202
|
template: "/swarm write-retro $ARGUMENTS",
|