svamp-cli 0.2.165 → 0.2.166

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.
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from 'node:fs';
2
- import { connectAndGetMachine, resolveSessionId, createWorktree, connectAndResolveSession } from './commands-D2Zpi3G8.mjs';
2
+ import { connectAndGetMachine, resolveSessionId, createWorktree, connectAndResolveSession } from './commands-DbEd_EMK.mjs';
3
3
  import { execSync } from 'node:child_process';
4
- import { m as shortId } from './run-KCqpMQJZ.mjs';
4
+ import { u as updateIssue, p as addComment, v as addIssue, w as shortId } from './run-DEfioSLJ.mjs';
5
5
  import 'node:path';
6
6
  import 'node:os';
7
7
  import 'os';
@@ -191,6 +191,36 @@ async function featureStart(brief, opts = {}) {
191
191
  process.exit(1);
192
192
  }
193
193
  const childId = result.sessionId;
194
+ try {
195
+ let linkedId = opts.issueId;
196
+ if (linkedId) {
197
+ const u = updateIssue(projectRoot, linkedId, { disposition: "crew", session: childId, branch: wt.branch, status: "in_progress" });
198
+ if (!u) {
199
+ console.warn(`Note: issue ${linkedId} not found \u2014 creating a new crew issue instead.`);
200
+ linkedId = void 0;
201
+ } else {
202
+ addComment(projectRoot, u.id, `Delegated to crew child ${childId.slice(0, 8)} on \`${wt.branch}\` (base \`${base}\`).`);
203
+ linkedId = u.id;
204
+ }
205
+ }
206
+ if (!linkedId) {
207
+ const created = addIssue(projectRoot, {
208
+ title: brief.trim().split("\n")[0].slice(0, 80),
209
+ status: "in_progress",
210
+ disposition: "crew",
211
+ triaged: true,
212
+ session: childId,
213
+ scope: "project",
214
+ ...opts.oracle?.trim() ? { verify: { type: "command", text: opts.oracle.trim() } } : {},
215
+ body: brief.trim()
216
+ });
217
+ updateIssue(projectRoot, created.id, { branch: wt.branch });
218
+ linkedId = created.id;
219
+ }
220
+ console.log(` issue: #${linkedId} (crew, child ${childId.slice(0, 8)})`);
221
+ } catch (e) {
222
+ console.warn(`Note: could not link a crew issue (${e.message}).`);
223
+ }
194
224
  if (!lead.metadata?.crew) {
195
225
  try {
196
226
  await rpc(machine, lead.sessionId, "updateConfig", { patch: { crew: { role: "lead" } } });
@@ -470,7 +500,7 @@ async function crewCommand(args) {
470
500
  return;
471
501
  }
472
502
  if (sub === "start") {
473
- const valueFlags = ["--oracle", "--base", "--action", "--max", "--dir", "-d", "--lead", "-m", "--machine"];
503
+ const valueFlags = ["--oracle", "--base", "--action", "--max", "--dir", "-d", "--lead", "-m", "--machine", "--issue"];
474
504
  const brief = positionals(rest, valueFlags).join(" ");
475
505
  const maxStr = flag(rest, "--max");
476
506
  const action = flag(rest, "--action");
@@ -480,6 +510,7 @@ async function crewCommand(args) {
480
510
  directory: flag(rest, "--dir", "-d"),
481
511
  oracle: flag(rest, "--oracle"),
482
512
  baseBranch: flag(rest, "--base"),
513
+ issueId: flag(rest, "--issue"),
483
514
  action: action === "block" ? "block" : action === "nudge" ? "nudge" : void 0,
484
515
  maxRounds: maxStr ? parseInt(maxStr, 10) : void 0
485
516
  });
@@ -1,7 +1,7 @@
1
1
  import { execSync, execFileSync } from 'node:child_process';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { createServer } from 'node:http';
4
- import { E as readChecklist, F as compileChecklist, G as RoutineStore, H as RoutineRunner } from './run-KCqpMQJZ.mjs';
4
+ import { M as readChecklist, N as compileChecklist, O as RoutineStore, P as RoutineRunner } from './run-DEfioSLJ.mjs';
5
5
  import 'os';
6
6
  import 'fs/promises';
7
7
  import 'fs';
@@ -104,7 +104,7 @@ Criteria: ${res.criteria || "(none)"}
104
104
  urgency: "normal",
105
105
  hopCount: 1
106
106
  };
107
- const { connectAndGetMachine } = await import('./commands-D2Zpi3G8.mjs');
107
+ const { connectAndGetMachine } = await import('./commands-DbEd_EMK.mjs');
108
108
  const { server, machine } = await connectAndGetMachine();
109
109
  try {
110
110
  await machine.sessionRPC(reportTo, "sendInboxMessage", { message });
@@ -1,8 +1,26 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import { r as resolveProjectRoot } from './store-BQxdRyuI.mjs';
2
+ import { m as resolveProjectRoot } from './run-DEfioSLJ.mjs';
3
3
  import { existsSync, unlinkSync, readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
5
  import { parse, stringify } from 'yaml';
6
+ import 'os';
7
+ import 'fs/promises';
8
+ import 'fs';
9
+ import 'path';
10
+ import 'url';
11
+ import 'child_process';
12
+ import 'crypto';
13
+ import 'node:crypto';
14
+ import 'util';
15
+ import 'node:events';
16
+ import 'node:os';
17
+ import '@agentclientprotocol/sdk';
18
+ import '@modelcontextprotocol/sdk/client/index.js';
19
+ import '@modelcontextprotocol/sdk/client/stdio.js';
20
+ import '@modelcontextprotocol/sdk/types.js';
21
+ import 'zod';
22
+ import 'node:fs/promises';
23
+ import 'node:util';
6
24
 
7
25
  function workflowsDir(projectRoot) {
8
26
  return join(projectRoot, ".svamp", "workflows");
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import os from 'node:os';
4
- import { c as connectToHypha } from './run-KCqpMQJZ.mjs';
4
+ import { c as connectToHypha } from './run-DEfioSLJ.mjs';
5
5
  import { PINNED_CLAUDE_CODE_VERSION } from './pinnedClaudeCode-HydRNEt7.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
@@ -4,7 +4,7 @@ import { mkdirSync, writeFileSync, unlinkSync, existsSync, chmodSync, readFileSy
4
4
  import { join } from 'path';
5
5
  import { homedir, platform, arch } from 'os';
6
6
  import { randomUUID, createHash } from 'crypto';
7
- import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-KCqpMQJZ.mjs';
7
+ import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-DEfioSLJ.mjs';
8
8
  import 'fs/promises';
9
9
  import 'url';
10
10
  import 'node:crypto';
@@ -1,5 +1,5 @@
1
- import { D as resolveModel, Y as describeMisconfiguration, Z as buildMachineDeps } from './run-KCqpMQJZ.mjs';
2
- import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-XblR5fr5.mjs';
1
+ import { L as resolveModel, a4 as describeMisconfiguration, a5 as buildMachineDeps } from './run-DEfioSLJ.mjs';
2
+ import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-BuMjm0m2.mjs';
3
3
  import { WebSocket } from 'ws';
4
4
  import { execSync, spawn } from 'child_process';
5
5
  import 'os';
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { c as connectToHypha, a as createSessionStore, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, s as startDaemon, b as stopDaemon } from './run-KCqpMQJZ.mjs';
1
+ export { c as connectToHypha, a as createSessionStore, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, s as startDaemon, b as stopDaemon } from './run-DEfioSLJ.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -1,5 +1,5 @@
1
1
  var name = "svamp-cli";
2
- var version = "0.2.165";
2
+ var version = "0.2.166";
3
3
  var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
4
4
  var author = "Amun AI AB";
5
5
  var license = "SEE LICENSE IN LICENSE";
@@ -19,7 +19,7 @@ var exports$1 = {
19
19
  var scripts = {
20
20
  build: "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && cp -r ../../skills/loop bin/skills/loop && cp -r ../../skills/crew bin/skills/crew && tsc --noEmit && pkgroll",
21
21
  typecheck: "tsc --noEmit",
22
- test: "npx tsx test/test-context-window.mjs && npx tsx test/test-ratelimit-retry.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-loop-activation.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-inbox-cross-machine.mjs && npx tsx test/test-checklist.mjs && npx tsx test/test-checklist-cli.mjs && npx tsx test/test-issue-store.mjs && npx tsx test/test-issue-close-gate.mjs && npx tsx test/test-workflow-store.mjs && npx tsx test/test-serve-link-subdomain.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-routine.mjs && npx tsx test/test-routine-rpc.mjs && npx tsx test/test-checklist-watchdog.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-shared-session-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs",
22
+ test: "npx tsx test/test-context-window.mjs && npx tsx test/test-ratelimit-retry.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-loop-activation.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-inbox-cross-machine.mjs && npx tsx test/test-checklist.mjs && npx tsx test/test-checklist-cli.mjs && npx tsx test/test-issue-store.mjs && npx tsx test/test-issue-close-gate.mjs && npx tsx test/test-workflow-store.mjs && npx tsx test/test-serve-link-subdomain.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-routine.mjs && npx tsx test/test-routine-rpc.mjs && npx tsx test/test-checklist-watchdog.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-shared-session-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs && npx tsx test/test-crew-verdict-routing.mjs",
23
23
  "test:hypha": "node --no-warnings test/test-hypha-service.mjs",
24
24
  dev: "tsx src/cli.ts",
25
25
  "dev:daemon": "tsx src/cli.ts daemon start-sync",
@@ -1,4 +1,4 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { _ as composeSessionId, $ as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, a0 as generateHookSettings } from './run-KCqpMQJZ.mjs';
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { a6 as composeSessionId, a7 as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, a8 as generateHookSettings } from './run-DEfioSLJ.mjs';
2
2
  import os from 'node:os';
3
3
  import { resolve, join } from 'node:path';
4
4
  import { existsSync, readFileSync, watch } from 'node:fs';
@@ -2772,7 +2772,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
2772
2772
  const tunnels = handlers.tunnels;
2773
2773
  if (!tunnels) throw new Error("Tunnel management not available");
2774
2774
  if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
2775
- const { FrpcTunnel } = await import('./frpc-BbpARLqP.mjs');
2775
+ const { FrpcTunnel } = await import('./frpc-B6KtYbVe.mjs');
2776
2776
  const tunnel = new FrpcTunnel({
2777
2777
  name: params.name,
2778
2778
  ports: params.ports,
@@ -3213,7 +3213,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3213
3213
  }
3214
3214
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
3215
3215
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
3216
- const { toolsForRole } = await import('./sideband-XblR5fr5.mjs');
3216
+ const { toolsForRole } = await import('./sideband-BuMjm0m2.mjs');
3217
3217
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
3218
3218
  return fmt(r2);
3219
3219
  }
@@ -3312,7 +3312,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3312
3312
  if (r.error || !r.sender) return { error: r.error || "unauthorized" };
3313
3313
  const callId = "call_" + Math.random().toString(16).slice(2, 12);
3314
3314
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
3315
- const { queryCore } = await import('./commands-D2Zpi3G8.mjs');
3315
+ const { queryCore } = await import('./commands-DbEd_EMK.mjs');
3316
3316
  const timeout = c.reply?.timeout_sec || 120;
3317
3317
  let result;
3318
3318
  try {
@@ -5415,7 +5415,7 @@ function classifyInbound(message, now = Date.now()) {
5415
5415
  return { action: "wake", reason: "urgent", breakerTripped: tripped };
5416
5416
  }
5417
5417
 
5418
- function resolveProjectRoot(directory) {
5418
+ function resolveProjectRoot$1(directory) {
5419
5419
  try {
5420
5420
  const top = execSync("git rev-parse --show-toplevel", {
5421
5421
  cwd: directory,
@@ -5427,10 +5427,10 @@ function resolveProjectRoot(directory) {
5427
5427
  return directory.replace(/[/\\]+$/, "") || directory;
5428
5428
  }
5429
5429
  function projectInfoPath(directory) {
5430
- return join(resolveProjectRoot(directory), ".svamp", "project.json");
5430
+ return join(resolveProjectRoot$1(directory), ".svamp", "project.json");
5431
5431
  }
5432
5432
  function projectName(directory) {
5433
- return basename(resolveProjectRoot(directory).replace(/[/\\]+$/, "")) || "project";
5433
+ return basename(resolveProjectRoot$1(directory).replace(/[/\\]+$/, "")) || "project";
5434
5434
  }
5435
5435
  function readProjectInfo(directory) {
5436
5436
  try {
@@ -5457,7 +5457,7 @@ function sanitizeDescription(raw, maxLen = 240) {
5457
5457
  return t || null;
5458
5458
  }
5459
5459
  function extractDescriptionFromDocs(directory) {
5460
- const root = resolveProjectRoot(directory);
5460
+ const root = resolveProjectRoot$1(directory);
5461
5461
  const candidates = [
5462
5462
  [join(root, "CLAUDE.md"), "claude.md"],
5463
5463
  [join(root, "README.md"), "readme"],
@@ -5501,7 +5501,7 @@ var projectInfo = /*#__PURE__*/Object.freeze({
5501
5501
  projectInfoPath: projectInfoPath,
5502
5502
  projectName: projectName,
5503
5503
  readProjectInfo: readProjectInfo,
5504
- resolveProjectRoot: resolveProjectRoot,
5504
+ resolveProjectRoot: resolveProjectRoot$1,
5505
5505
  sanitizeDescription: sanitizeDescription,
5506
5506
  writeProjectInfo: writeProjectInfo
5507
5507
  });
@@ -10127,7 +10127,7 @@ function renderCriteria(items) {
10127
10127
  }
10128
10128
  return `- [${STATUS_TO_MARKER[it.status] ?? " "}] ${it.text}${tag}${how}`;
10129
10129
  });
10130
- const { done, total } = summarize(items);
10130
+ const { done, total } = summarize$1(items);
10131
10131
  return `Success criteria \u2014 drive this checklist to all-done (${done}/${total}):
10132
10132
  ${lines.join("\n")}`;
10133
10133
  }
@@ -10137,22 +10137,6 @@ function compileChecklist(items) {
10137
10137
  const oracle = oracleItem && oracleItem.eval?.type === "oracle" ? oracleItem.eval.cmd : void 0;
10138
10138
  return { criteria, ...oracle ? { oracle } : {} };
10139
10139
  }
10140
- function routeVerdictToChecklist(items, v) {
10141
- let matched = false;
10142
- const next = items.map((it) => {
10143
- if (it.child?.sessionId && it.child.sessionId === v.sessionId) {
10144
- matched = true;
10145
- return applyVerdict(it, v);
10146
- }
10147
- return it;
10148
- });
10149
- return { items: next, matched };
10150
- }
10151
- function applyVerdict(item, v) {
10152
- const lastVerdict = { verdict: v.verdict, ...v.guidance ? { guidance: v.guidance } : {}, round: v.round, ts: v.ts };
10153
- if (v.verdict === "approved") return { ...item, status: "done", doneAt: Date.parse(v.ts) || item.createdAt, lastVerdict };
10154
- return { ...item, status: "rework", lastVerdict };
10155
- }
10156
10140
  const VALID_STATUS = /* @__PURE__ */ new Set(["todo", "active", "verifying", "awaiting_review", "rework", "blocked", "done"]);
10157
10141
  function validateChecklist(items) {
10158
10142
  const errs = [];
@@ -10168,7 +10152,7 @@ function validateChecklist(items) {
10168
10152
  }
10169
10153
  return errs;
10170
10154
  }
10171
- function summarize(items) {
10155
+ function summarize$1(items) {
10172
10156
  const by = (s) => items.filter((i) => i.status === s).length;
10173
10157
  const done = by("done");
10174
10158
  return {
@@ -10229,11 +10213,196 @@ function clearChecklist(projectRoot, sessionId) {
10229
10213
  } catch {
10230
10214
  }
10231
10215
  }
10232
- function mutateChecklist(projectRoot, sessionId, fn) {
10233
- const next = fn(readChecklist(projectRoot, sessionId));
10234
- writeChecklist(projectRoot, sessionId, next);
10216
+
10217
+ const FIELD_ORDER = ["id", "title", "status", "scope", "labels", "verify", "disposition", "triaged", "branch", "session", "original", "created", "closed"];
10218
+ function resolveProjectRoot(start = process.cwd()) {
10219
+ let dir = start;
10220
+ for (let i = 0; i < 40; i++) {
10221
+ if (existsSync(join(dir, ".git")) || existsSync(join(dir, ".svamp"))) return dir;
10222
+ const parent = dirname(dir);
10223
+ if (parent === dir) break;
10224
+ dir = parent;
10225
+ }
10226
+ return start;
10227
+ }
10228
+ function issuesDir(projectRoot) {
10229
+ return join(projectRoot, ".svamp", "issues");
10230
+ }
10231
+ function archiveDir(projectRoot) {
10232
+ return join(issuesDir(projectRoot), "archive");
10233
+ }
10234
+ function issuePath(projectRoot, id, archived = false) {
10235
+ return join(archived ? archiveDir(projectRoot) : issuesDir(projectRoot), `${id}.md`);
10236
+ }
10237
+ function serializeIssue(issue) {
10238
+ const lines = ["---"];
10239
+ for (const k of FIELD_ORDER) {
10240
+ const v = issue[k];
10241
+ if (v === void 0) continue;
10242
+ lines.push(`${k}: ${JSON.stringify(v)}`);
10243
+ }
10244
+ lines.push("---", "");
10245
+ return lines.join("\n") + (issue.body ? issue.body.replace(/\s+$/, "") + "\n" : "");
10246
+ }
10247
+ function parseIssue(content) {
10248
+ const m = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
10249
+ if (!m) return null;
10250
+ const fm = {};
10251
+ for (const line of m[1].split("\n")) {
10252
+ const idx = line.indexOf(": ");
10253
+ if (idx === -1) continue;
10254
+ const key = line.slice(0, idx).trim();
10255
+ const raw = line.slice(idx + 2).trim();
10256
+ try {
10257
+ fm[key] = JSON.parse(raw);
10258
+ } catch {
10259
+ fm[key] = raw;
10260
+ }
10261
+ }
10262
+ if (!fm.id) return null;
10263
+ return {
10264
+ id: String(fm.id),
10265
+ title: String(fm.title ?? ""),
10266
+ status: fm.status ?? "backlog",
10267
+ scope: fm.scope ?? "session",
10268
+ labels: Array.isArray(fm.labels) ? fm.labels.map(String) : [],
10269
+ verify: fm.verify ?? null,
10270
+ disposition: fm.disposition === "crew" ? "crew" : "inline",
10271
+ triaged: fm.triaged === true,
10272
+ branch: fm.branch ?? null,
10273
+ session: fm.session ?? null,
10274
+ original: fm.original ?? null,
10275
+ created: String(fm.created ?? (/* @__PURE__ */ new Date()).toISOString()),
10276
+ closed: fm.closed ?? null,
10277
+ body: (m[2] || "").trim() || void 0
10278
+ };
10279
+ }
10280
+ function readDir(dir) {
10281
+ if (!existsSync(dir)) return [];
10282
+ const out = [];
10283
+ for (const name of readdirSync(dir)) {
10284
+ if (!name.endsWith(".md")) continue;
10285
+ try {
10286
+ const issue = parseIssue(readFileSync(join(dir, name), "utf-8"));
10287
+ if (issue) out.push(issue);
10288
+ } catch {
10289
+ }
10290
+ }
10291
+ return out;
10292
+ }
10293
+ function listIssues(projectRoot, opts = {}) {
10294
+ let items = readDir(issuesDir(projectRoot));
10295
+ if (opts.includeArchived) items = items.concat(readDir(archiveDir(projectRoot)));
10296
+ if (opts.status) items = items.filter((i) => i.status === opts.status);
10297
+ if (opts.label) items = items.filter((i) => i.labels.includes(opts.label));
10298
+ if (opts.scope) items = items.filter((i) => i.scope === opts.scope);
10299
+ return items.sort((a, b) => Number(a.id) - Number(b.id));
10300
+ }
10301
+ function getIssue(projectRoot, id) {
10302
+ const padded = /^\d+$/.test(id) ? id.padStart(4, "0") : id;
10303
+ for (const p of [issuePath(projectRoot, padded), issuePath(projectRoot, padded, true)]) {
10304
+ if (existsSync(p)) {
10305
+ try {
10306
+ return parseIssue(readFileSync(p, "utf-8"));
10307
+ } catch {
10308
+ return null;
10309
+ }
10310
+ }
10311
+ }
10312
+ return null;
10313
+ }
10314
+ function atomicWrite(path, content) {
10315
+ mkdirSync(dirname(path), { recursive: true });
10316
+ const tmp = `${path}.tmp-${process.pid}`;
10317
+ writeFileSync(tmp, content);
10318
+ renameSync(tmp, path);
10319
+ }
10320
+ function nextId(projectRoot) {
10321
+ const all = listIssues(projectRoot, { includeArchived: true });
10322
+ const max = all.reduce((acc, i) => Math.max(acc, Number(i.id) || 0), 0);
10323
+ return String(max + 1).padStart(4, "0");
10324
+ }
10325
+ function addIssue(projectRoot, fields) {
10326
+ const issue = {
10327
+ id: nextId(projectRoot),
10328
+ title: fields.title.trim(),
10329
+ status: fields.status ?? "backlog",
10330
+ scope: fields.scope ?? "session",
10331
+ labels: fields.labels ?? [],
10332
+ verify: fields.verify ?? null,
10333
+ disposition: fields.disposition ?? "inline",
10334
+ triaged: fields.triaged ?? false,
10335
+ branch: null,
10336
+ session: fields.session ?? null,
10337
+ original: fields.original ?? null,
10338
+ created: (/* @__PURE__ */ new Date()).toISOString(),
10339
+ closed: null,
10340
+ body: fields.body
10341
+ };
10342
+ atomicWrite(issuePath(projectRoot, issue.id), serializeIssue(issue));
10343
+ return issue;
10344
+ }
10345
+ function updateIssue(projectRoot, id, patch) {
10346
+ const cur = getIssue(projectRoot, id);
10347
+ if (!cur) return null;
10348
+ const wasArchived = cur.status === "archived";
10349
+ const next = { ...cur, ...patch, id: cur.id };
10350
+ const nowArchived = next.status === "archived";
10351
+ if ((next.status === "done" || nowArchived) && !next.closed) next.closed = (/* @__PURE__ */ new Date()).toISOString();
10352
+ if (next.status !== "done" && !nowArchived) next.closed = null;
10353
+ atomicWrite(issuePath(projectRoot, next.id, nowArchived), serializeIssue(next));
10354
+ if (wasArchived !== nowArchived) {
10355
+ const oldPath = issuePath(projectRoot, cur.id, wasArchived);
10356
+ try {
10357
+ if (existsSync(oldPath)) unlinkSync(oldPath);
10358
+ } catch {
10359
+ }
10360
+ }
10235
10361
  return next;
10236
10362
  }
10363
+ function addComment(projectRoot, id, text) {
10364
+ const cur = getIssue(projectRoot, id);
10365
+ if (!cur || !text.trim()) return cur;
10366
+ const entry = `
10367
+
10368
+ ---
10369
+ **Follow-up \xB7 ${(/* @__PURE__ */ new Date()).toISOString()}**
10370
+
10371
+ ${text.trim()}`;
10372
+ const body = (cur.body ? cur.body.replace(/\s+$/, "") : "") + entry;
10373
+ return updateIssue(projectRoot, id, { body });
10374
+ }
10375
+ function routeCrewVerdict(projectRoot, childSessionId, v) {
10376
+ const linked = listIssues(projectRoot, { includeArchived: true }).find((i) => i.disposition === "crew" && i.session === childSessionId);
10377
+ if (!linked) return null;
10378
+ const meta = [v.round != null ? `round ${v.round}` : "", v.judge ? `judge:${v.judge}` : ""].filter(Boolean).join(", ");
10379
+ addComment(projectRoot, linked.id, `Crew child ${childSessionId.slice(0, 8)} \u2192 ${v.verdict}${meta ? ` (${meta})` : ""}.${v.guidance ? " " + v.guidance : ""}`);
10380
+ return v.verdict === "approved" ? updateIssue(projectRoot, linked.id, { status: "done" }) ?? null : getIssue(projectRoot, linked.id);
10381
+ }
10382
+ function searchIssues(projectRoot, query) {
10383
+ const q = query.trim();
10384
+ if (!q) return [];
10385
+ try {
10386
+ const out = execFileSync("rg", ["-l", "-i", "--no-messages", q, issuesDir(projectRoot)], { encoding: "utf-8" });
10387
+ const files = out.split("\n").filter(Boolean);
10388
+ const issues = [];
10389
+ for (const f of files) {
10390
+ try {
10391
+ const i = parseIssue(readFileSync(f, "utf-8"));
10392
+ if (i) issues.push(i);
10393
+ } catch {
10394
+ }
10395
+ }
10396
+ return issues.sort((a, b) => Number(a.id) - Number(b.id));
10397
+ } catch {
10398
+ const ql = q.toLowerCase();
10399
+ return listIssues(projectRoot, { includeArchived: true }).filter((i) => i.title.toLowerCase().includes(ql) || (i.body || "").toLowerCase().includes(ql) || i.labels.some((l) => l.toLowerCase().includes(ql)));
10400
+ }
10401
+ }
10402
+ function summarize(issues) {
10403
+ const by = (s) => issues.filter((i) => i.status === s).length;
10404
+ return { total: issues.length, backlog: by("backlog"), ready: by("ready"), in_progress: by("in_progress"), done: by("done"), archived: by("archived") };
10405
+ }
10237
10406
 
10238
10407
  const OAUTH_TOKEN_ENDPOINT = "https://platform.claude.com/v1/oauth/token";
10239
10408
  const OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
@@ -11366,7 +11535,7 @@ Or verify and finish \u2014 an independent Stop gate re-checks before you can st
11366
11535
  const evaluator = ccfg.evaluator !== false;
11367
11536
  const budget = parseLoopBudget(ccfg.budget);
11368
11537
  const ok = initLoop(directory, { task, criteria, oracle, maxIterations, evaluator, budget, sessionId });
11369
- const s = summarize(items);
11538
+ const s = summarize$1(items);
11370
11539
  if (ok) {
11371
11540
  const idle = getMetadata().lifecycleState === "idle";
11372
11541
  if (idle) {
@@ -11816,7 +11985,7 @@ async function startDaemon(options) {
11816
11985
  saveExposedTunnels(list);
11817
11986
  }
11818
11987
  async function createExposedTunnel(spec) {
11819
- const { FrpcTunnel } = await import('./frpc-BbpARLqP.mjs');
11988
+ const { FrpcTunnel } = await import('./frpc-B6KtYbVe.mjs');
11820
11989
  const tunnel = new FrpcTunnel({
11821
11990
  name: spec.name,
11822
11991
  ports: spec.ports,
@@ -11836,7 +12005,7 @@ async function startDaemon(options) {
11836
12005
  return tunnel;
11837
12006
  }
11838
12007
  const tunnelRecreateState = /* @__PURE__ */ new Map();
11839
- const { ServeManager } = await import('./serveManager-fwaBwmlm.mjs');
12008
+ const { ServeManager } = await import('./serveManager-BH7mQRkn.mjs');
11840
12009
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
11841
12010
  ensureAutoInstalledSkills(logger).catch(() => {
11842
12011
  });
@@ -11898,9 +12067,13 @@ ${v.guidance ? v.guidance + "\n" : ""}Criteria: ${v.criteria || "(none)"}
11898
12067
  })).catch(() => {
11899
12068
  });
11900
12069
  try {
11901
- if (parent?.directory) {
11902
- const res = mutateChecklist(parent.directory, parentId, (items) => routeVerdictToChecklist(items, { sessionId: v.sessionId, verdict: v.verdict, guidance: v.guidance, round: v.round, ts: v.ts }).items);
11903
- if (res.some((i) => i.child?.sessionId === v.sessionId)) logger.log(`[supervision] reflected '${v.verdict}' onto parent ${parentId.slice(0, 8)} checklist`);
12070
+ if (parent?.directory && (v.verdict === "approved" || v.verdict === "rework")) {
12071
+ const linked = routeCrewVerdict(
12072
+ parent.directory,
12073
+ v.sessionId,
12074
+ { verdict: v.verdict, guidance: v.guidance, round: v.round, judge: v.judge }
12075
+ );
12076
+ if (linked) logger.log(`[supervision] routed '${v.verdict}' onto parent ${parentId.slice(0, 8)} issue #${linked.id}`);
11904
12077
  }
11905
12078
  } catch {
11906
12079
  }
@@ -15440,4 +15613,4 @@ var run = /*#__PURE__*/Object.freeze({
15440
15613
  writeStopMarker: writeStopMarker
15441
15614
  });
15442
15615
 
15443
- export { generateFriendlyName as $, buildMachineInstructions as A, machineToolsForRole as B, buildMachineTools as C, resolveModel as D, readChecklist as E, compileChecklist as F, RoutineStore as G, RoutineRunner as H, formatHandle as I, normalizeAllowedUser as J, loadSecurityContextConfig as K, resolveSecurityContext as L, buildSecurityContextFromFlags as M, mergeSecurityContexts as N, buildSessionShareUrl as O, validateChecklist as P, computeOutboundHop as Q, READ_ONLY_TOOLS as R, ServeAuth as S, buildMachineShareUrl as T, summarize as U, newItem as V, parseHandle as W, handleMatchesMetadata as X, describeMisconfiguration as Y, buildMachineDeps as Z, composeSessionId as _, createSessionStore as a, generateHookSettings as a0, projectInfo as a1, DefaultTransport$1 as a2, acpBackend as a3, acpAgentConfig as a4, codexMcpBackend as a5, GeminiTransport$1 as a6, claudeAuth as a7, instanceConfig as a8, api as a9, run as aa, stopDaemon as b, connectToHypha as c, daemonStatus as d, clearStopMarker as e, stopMarkerExists as f, getHyphaServerUrl$1 as g, getFrpsSubdomainHost as h, getFrpsServerPort as i, getFrpsServerAddr as j, getHyphaServerUrl as k, hasCookieToken as l, shortId as m, getSkillsServer as n, getSkillsWorkspaceName as o, parseFrontmatter as p, getSkillsCollectionName as q, registerMachineService as r, startDaemon as s, fetchWithTimeout as t, searchSkills as u, SKILLS_DIR as v, getSkillInfo as w, downloadSkillFile as x, listSkillFiles as y, loadMachineContext as z };
15616
+ export { buildMachineShareUrl as $, getSkillsCollectionName as A, fetchWithTimeout as B, searchSkills as C, SKILLS_DIR as D, getSkillInfo as E, downloadSkillFile as F, listSkillFiles as G, loadMachineContext as H, buildMachineInstructions as I, machineToolsForRole as J, buildMachineTools as K, resolveModel as L, readChecklist as M, compileChecklist as N, RoutineStore as O, RoutineRunner as P, formatHandle as Q, READ_ONLY_TOOLS as R, ServeAuth as S, normalizeAllowedUser as T, loadSecurityContextConfig as U, resolveSecurityContext as V, buildSecurityContextFromFlags as W, mergeSecurityContexts as X, buildSessionShareUrl as Y, validateChecklist as Z, computeOutboundHop as _, createSessionStore as a, summarize$1 as a0, newItem as a1, parseHandle as a2, handleMatchesMetadata as a3, describeMisconfiguration as a4, buildMachineDeps as a5, composeSessionId as a6, generateFriendlyName as a7, generateHookSettings as a8, projectInfo as a9, DefaultTransport$1 as aa, acpBackend as ab, acpAgentConfig as ac, codexMcpBackend as ad, GeminiTransport$1 as ae, claudeAuth as af, instanceConfig as ag, api as ah, run as ai, stopDaemon as b, connectToHypha as c, daemonStatus as d, clearStopMarker as e, stopMarkerExists as f, getHyphaServerUrl$1 as g, getFrpsSubdomainHost as h, getFrpsServerPort as i, getFrpsServerAddr as j, getHyphaServerUrl as k, hasCookieToken as l, resolveProjectRoot as m, searchIssues as n, listIssues as o, addComment as p, getIssue as q, registerMachineService as r, startDaemon as s, summarize as t, updateIssue as u, addIssue as v, shortId as w, parseFrontmatter as x, getSkillsServer as y, getSkillsWorkspaceName as z };
@@ -54,7 +54,7 @@ async function handleServeCommand() {
54
54
  }
55
55
  }
56
56
  async function serveAdd(args, machineId) {
57
- const { connectAndGetMachine } = await import('./commands-D2Zpi3G8.mjs');
57
+ const { connectAndGetMachine } = await import('./commands-DbEd_EMK.mjs');
58
58
  const pos = positionalArgs(args);
59
59
  const name = pos[0];
60
60
  if (!name) {
@@ -93,7 +93,7 @@ async function serveAdd(args, machineId) {
93
93
  }
94
94
  }
95
95
  async function serveApply(args, machineId) {
96
- const { connectAndGetMachine } = await import('./commands-D2Zpi3G8.mjs');
96
+ const { connectAndGetMachine } = await import('./commands-DbEd_EMK.mjs');
97
97
  const fs = await import('fs');
98
98
  const yaml = await import('yaml');
99
99
  const file = positionalArgs(args)[0];
@@ -182,7 +182,7 @@ async function serveApply(args, machineId) {
182
182
  }
183
183
  }
184
184
  async function serveRemove(args, machineId) {
185
- const { connectAndGetMachine } = await import('./commands-D2Zpi3G8.mjs');
185
+ const { connectAndGetMachine } = await import('./commands-DbEd_EMK.mjs');
186
186
  const pos = positionalArgs(args);
187
187
  const name = pos[0];
188
188
  if (!name) {
@@ -202,7 +202,7 @@ async function serveRemove(args, machineId) {
202
202
  }
203
203
  }
204
204
  async function serveList(args, machineId) {
205
- const { connectAndGetMachine } = await import('./commands-D2Zpi3G8.mjs');
205
+ const { connectAndGetMachine } = await import('./commands-DbEd_EMK.mjs');
206
206
  const all = hasFlag(args, "--all", "-a");
207
207
  const json = hasFlag(args, "--json");
208
208
  const sessionId = getFlag(args, "--session");
@@ -235,7 +235,7 @@ async function serveList(args, machineId) {
235
235
  }
236
236
  }
237
237
  async function serveInfo(machineId) {
238
- const { connectAndGetMachine } = await import('./commands-D2Zpi3G8.mjs');
238
+ const { connectAndGetMachine } = await import('./commands-DbEd_EMK.mjs');
239
239
  const { machine, server } = await connectAndGetMachine(machineId);
240
240
  try {
241
241
  const info = await machine.serveInfo();
@@ -4,7 +4,7 @@ import * as fs from 'fs';
4
4
  import * as http from 'http';
5
5
  import * as net from 'net';
6
6
  import * as path from 'path';
7
- import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-KCqpMQJZ.mjs';
7
+ import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-DEfioSLJ.mjs';
8
8
  import 'os';
9
9
  import 'fs/promises';
10
10
  import 'url';
@@ -733,7 +733,7 @@ class ServeManager {
733
733
  const mount = this.mounts.get(mountName);
734
734
  const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, buildLinkSubdomain(subdomainSafe, mount.linkToken)]]) : void 0;
735
735
  try {
736
- const { FrpcTunnel } = await import('./frpc-BbpARLqP.mjs');
736
+ const { FrpcTunnel } = await import('./frpc-B6KtYbVe.mjs');
737
737
  let tunnel;
738
738
  tunnel = new FrpcTunnel({
739
739
  name: tunnelName,
@@ -1,4 +1,4 @@
1
- import { R as READ_ONLY_TOOLS, z as loadMachineContext, A as buildMachineInstructions, B as machineToolsForRole, C as buildMachineTools } from './run-KCqpMQJZ.mjs';
1
+ import { R as READ_ONLY_TOOLS, H as loadMachineContext, I as buildMachineInstructions, J as machineToolsForRole, K as buildMachineTools } from './run-DEfioSLJ.mjs';
2
2
  import 'node:child_process';
3
3
  import 'os';
4
4
  import 'fs/promises';