svamp-cli 0.2.202 → 0.2.203
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/bin/skills/loop/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: loop
|
|
3
|
-
version: 0.4.
|
|
3
|
+
version: 0.4.2
|
|
4
4
|
description: Run a task as a reliable, self-verifying loop — iterate until objective exit conditions are met, with an independent evaluator instead of self-judging. Use when a task needs repeated iterations until "done" (fix until tests pass, refactor until clean, build until a spec is met, autonomous long-running work).
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -166,9 +166,25 @@ if (done) {
|
|
|
166
166
|
block(`The loop's exit conditions are met (oracle empty + evaluator done), but you have ${pending} UNHANDLED inbox message(s). Handle them first — read/reply/triage/merge each (\`svamp session inbox list\`), then finish your turn. (This guard fires at most once per loop, then allows stop, so a flood can't trap the loop.)`);
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
|
+
// #0128: NON-BLOCKING open-crew hint. The loop is about to STOP — surface any active crew children
|
|
170
|
+
// the lead hasn't merged/closed so an orphaned/forgotten crew is visible at the natural checkpoint.
|
|
171
|
+
// Purely informational: it NEVER blocks or affects the decision (the loop still stops). Computed
|
|
172
|
+
// lazily only here (not every iteration) to avoid a per-turn subprocess. Disable with
|
|
173
|
+
// `crew_hint: false` in loop.config.json.
|
|
174
|
+
let openCrew = '';
|
|
175
|
+
if (cfg.crew_hint !== false) {
|
|
176
|
+
try {
|
|
177
|
+
const out = execSync('svamp feature list', { cwd: PROJECT, stdio: 'pipe', encoding: 'utf-8',
|
|
178
|
+
timeout: 15000, env: { ...process.env, ...(SID ? { SVAMP_SESSION_ID: SID } : {}) } }).toString();
|
|
179
|
+
const active = out.split('\n').map((l) => l.trim()).filter((l) => /\bactive\b/.test(l))
|
|
180
|
+
.map((l) => { const id = l.split(/\s+/)[0]; const iss = (l.match(/#\d{2,}/) || [])[0]; return iss ? `${id} (${iss})` : id; });
|
|
181
|
+
if (active.length) openCrew = `Open crew not merged/closed: ${active.join(', ')} — review with \`svamp feature merge <id>\`.`;
|
|
182
|
+
} catch { /* fail-open: no daemon / no crew → no hint */ }
|
|
183
|
+
}
|
|
184
|
+
if (openCrew) process.stderr.write(`[loop] ${openCrew}\n`);
|
|
169
185
|
writeJSONAtomic(STATE, { ...state, active: false, phase: 'done', completed_at: now,
|
|
170
|
-
last_oracle: oracleDetail });
|
|
171
|
-
appendHistory({ ts: now, iteration: iterNum, decision: 'done', oracle: oraclePass, evaluator: evaluatorPass, detail: oracleDetail });
|
|
186
|
+
last_oracle: oracleDetail, ...(openCrew ? { open_crew: openCrew } : {}) });
|
|
187
|
+
appendHistory({ ts: now, iteration: iterNum, decision: 'done', oracle: oraclePass, evaluator: evaluatorPass, detail: oracleDetail, ...(openCrew ? { open_crew: openCrew } : {}) });
|
|
172
188
|
allow();
|
|
173
189
|
}
|
|
174
190
|
|
package/dist/cli.mjs
CHANGED
|
@@ -386,7 +386,7 @@ async function main() {
|
|
|
386
386
|
await handleWiseAgentCommand(args.slice(1));
|
|
387
387
|
process.exit(0);
|
|
388
388
|
} else if (subcommand === "feature" || subcommand === "crew") {
|
|
389
|
-
const { crewCommand } = await import('./commands-
|
|
389
|
+
const { crewCommand } = await import('./commands-CKY0GfUp.mjs');
|
|
390
390
|
await crewCommand(args.slice(1));
|
|
391
391
|
process.exit(0);
|
|
392
392
|
} else if (subcommand === "--help" || subcommand === "-h") {
|
|
@@ -394,7 +394,7 @@ async function main() {
|
|
|
394
394
|
} else if (!subcommand || subcommand === "start") {
|
|
395
395
|
await handleInteractiveCommand();
|
|
396
396
|
} else if (subcommand === "--version" || subcommand === "-v") {
|
|
397
|
-
const pkg = await import('./package-
|
|
397
|
+
const pkg = await import('./package-BAOTsiw2.mjs').catch(() => ({ default: { version: "unknown" } }));
|
|
398
398
|
console.log(`svamp version: ${pkg.default.version}`);
|
|
399
399
|
} else {
|
|
400
400
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -55,23 +55,23 @@ function mergeBack(input) {
|
|
|
55
55
|
if (!existsSync(projectRoot)) {
|
|
56
56
|
return { ok: false, stage: "verify", detail: `project root not found: ${projectRoot}` };
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
detail: `feature worktree has uncommitted changes \u2014 commit (or run \`feature done\`) first:
|
|
58
|
+
const worktreeGone = !existsSync(worktreePath);
|
|
59
|
+
if (!worktreeGone) {
|
|
60
|
+
let childStatus;
|
|
61
|
+
try {
|
|
62
|
+
childStatus = worktreeStatus(worktreePath);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
return { ok: false, stage: "verify", detail: `not a git worktree: ${worktreePath} (${e.message})` };
|
|
65
|
+
}
|
|
66
|
+
if (childStatus) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
stage: "verify",
|
|
70
|
+
rework: true,
|
|
71
|
+
detail: `feature worktree has uncommitted changes \u2014 commit (or run \`feature done\`) first:
|
|
73
72
|
${childStatus}`
|
|
74
|
-
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
75
|
}
|
|
76
76
|
const leadBranch = currentBranch(projectRoot);
|
|
77
77
|
if (leadBranch !== baseBranch) {
|
|
@@ -108,8 +108,19 @@ ${detail.trim()}` };
|
|
|
108
108
|
try {
|
|
109
109
|
git(projectRoot, `worktree remove --force ${worktreePath}`);
|
|
110
110
|
} catch (e) {
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
try {
|
|
112
|
+
git(projectRoot, "worktree prune");
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
let stillRegistered = false;
|
|
116
|
+
try {
|
|
117
|
+
stillRegistered = git(projectRoot, "worktree list --porcelain").includes(worktreePath);
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
if (stillRegistered) {
|
|
121
|
+
const detail = e.stderr?.toString() || "" || e.message;
|
|
122
|
+
return { ok: false, stage: "remove-worktree", detail: `merged OK but worktree removal failed: ${detail.trim()}` };
|
|
123
|
+
}
|
|
113
124
|
}
|
|
114
125
|
if (input.deleteBranch !== false) {
|
|
115
126
|
try {
|