svamp-cli 0.2.106 → 0.2.108

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.
Files changed (26) hide show
  1. package/bin/skills/loop/bin/inject-loop.mjs +20 -6
  2. package/bin/skills/loop/bin/loop-init.mjs +21 -8
  3. package/bin/skills/loop/bin/loop-status.mjs +17 -4
  4. package/bin/skills/loop/bin/precompact.mjs +5 -2
  5. package/bin/skills/loop/bin/state-fp.mjs +5 -7
  6. package/bin/skills/loop/bin/stop-gate.mjs +17 -4
  7. package/bin/skills/loop/test/test-loop-gate.mjs +55 -18
  8. package/dist/{agentCommands-V14aFkLp.mjs → agentCommands-Cpq_Yk3h.mjs} +2 -2
  9. package/dist/{auth-CuCvqsTH.mjs → auth-DBKbI5IE.mjs} +1 -1
  10. package/dist/cli.mjs +50 -50
  11. package/dist/{commands-BGO8YrVj.mjs → commands-4JPwWmBF.mjs} +2 -2
  12. package/dist/{commands-CyVLITvL.mjs → commands-B7z0Yoi7.mjs} +1 -1
  13. package/dist/{commands-CmnRHJ_u.mjs → commands-CjuVNGG4.mjs} +3 -3
  14. package/dist/{commands-Dd1kqgBk.mjs → commands-D38_YkF9.mjs} +5 -5
  15. package/dist/{commands-Cectk2JF.mjs → commands-DOsK9QRw.mjs} +24 -8
  16. package/dist/{fleet-D7A8whbP.mjs → fleet-D-YD8lYU.mjs} +1 -1
  17. package/dist/{frpc-D9HsqQ7e.mjs → frpc-C5Bhpsdw.mjs} +1 -1
  18. package/dist/{headlessCli-Bli0HPzi.mjs → headlessCli-Cwqhpbm1.mjs} +2 -2
  19. package/dist/index.mjs +1 -1
  20. package/dist/{package-1Infuho2.mjs → package-D7tAsMPM.mjs} +1 -1
  21. package/dist/{run-9j9_wlx5.mjs → run-LyzVTe3J.mjs} +59 -34
  22. package/dist/{run-Cysre19E.mjs → run-TjecLji1.mjs} +1 -1
  23. package/dist/{serveCommands-JHbRf6Vz.mjs → serveCommands-XlqflmVF.mjs} +5 -5
  24. package/dist/{serveManager-ClBIhxJK.mjs → serveManager-QZxNxQq0.mjs} +2 -2
  25. package/dist/{sideband-CnnaC4xC.mjs → sideband-CgiHKPJo.mjs} +1 -1
  26. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import os$1, { homedir as homedir$1 } from 'os';
2
2
  import fs, { mkdir as mkdir$1, readdir as readdir$1, readFile, writeFile as writeFile$1, rename, unlink } from 'fs/promises';
3
- import { readFileSync as readFileSync$1, mkdirSync as mkdirSync$1, writeFileSync as writeFileSync$1, renameSync as renameSync$1, existsSync as existsSync$1, rmSync as rmSync$1, unlinkSync as unlinkSync$1, copyFileSync, watch, rmdirSync, readdirSync as readdirSync$1 } from 'fs';
3
+ import { readFileSync as readFileSync$1, mkdirSync as mkdirSync$1, writeFileSync as writeFileSync$1, renameSync as renameSync$1, existsSync as existsSync$1, rmSync as rmSync$1, unlinkSync as unlinkSync$1, copyFileSync, readdirSync as readdirSync$1, watch, rmdirSync } from 'fs';
4
4
  import path__default, { join as join$1, dirname, basename, resolve } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { execFile, spawn as spawn$1, execSync as execSync$1, spawnSync } from 'child_process';
@@ -2527,7 +2527,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
2527
2527
  const tunnels = handlers.tunnels;
2528
2528
  if (!tunnels) throw new Error("Tunnel management not available");
2529
2529
  if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
2530
- const { FrpcTunnel } = await import('./frpc-D9HsqQ7e.mjs');
2530
+ const { FrpcTunnel } = await import('./frpc-C5Bhpsdw.mjs');
2531
2531
  const tunnel = new FrpcTunnel({
2532
2532
  name: params.name,
2533
2533
  ports: params.ports,
@@ -2788,7 +2788,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
2788
2788
  }
2789
2789
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
2790
2790
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
2791
- const { toolsForRole } = await import('./sideband-CnnaC4xC.mjs');
2791
+ const { toolsForRole } = await import('./sideband-CgiHKPJo.mjs');
2792
2792
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
2793
2793
  return fmt(r2);
2794
2794
  }
@@ -2887,7 +2887,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
2887
2887
  if (r.error || !r.sender) return { error: r.error || "unauthorized" };
2888
2888
  const callId = "call_" + Math.random().toString(16).slice(2, 12);
2889
2889
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
2890
- const { queryCore } = await import('./commands-Cectk2JF.mjs');
2890
+ const { queryCore } = await import('./commands-DOsK9QRw.mjs');
2891
2891
  const timeout = c.reply?.timeout_sec || 120;
2892
2892
  let result;
2893
2893
  try {
@@ -3130,17 +3130,24 @@ class RoutineRunner {
3130
3130
  }
3131
3131
  const resolved = this.resolveAction(routine, payload);
3132
3132
  let outcome = "delivered";
3133
+ const refundDailyCap = () => {
3134
+ if (!routine.daily_cap) return;
3135
+ const rb = this.store.get(routine.id);
3136
+ if (rb?.daily?.date === today && rb.daily.n > 0) {
3137
+ rb.daily.n -= 1;
3138
+ this.store.save(rb);
3139
+ }
3140
+ };
3133
3141
  try {
3134
- await this.deliver({ routine, action: routine.action, resolved, payload, via });
3142
+ const res = await this.deliver({ routine, action: routine.action, resolved, payload, via });
3143
+ if (res && res.skipped) {
3144
+ outcome = `skipped (${res.skipped})`;
3145
+ this.log(`[routine] ${routine.id || routine.name}: ${outcome}`);
3146
+ refundDailyCap();
3147
+ }
3135
3148
  } catch (e) {
3136
3149
  outcome = "error: " + (e?.message || e);
3137
- if (routine.daily_cap) {
3138
- const rb = this.store.get(routine.id);
3139
- if (rb?.daily?.date === today && rb.daily.n > 0) {
3140
- rb.daily.n -= 1;
3141
- this.store.save(rb);
3142
- }
3143
- }
3150
+ refundDailyCap();
3144
3151
  } finally {
3145
3152
  this.active.delete(routine.id);
3146
3153
  }
@@ -9691,29 +9698,36 @@ function writeSvampConfig(configPath, config) {
9691
9698
  renameSync$1(tmpPath, configPath);
9692
9699
  return content;
9693
9700
  }
9694
- function getLoopDir(directory) {
9701
+ function getLoopDir(directory, sessionId) {
9702
+ if (sessionId) {
9703
+ const scoped = join$1(directory, ".svamp", sessionId, "loop");
9704
+ if (existsSync$1(join$1(scoped, "loop-state.json"))) return scoped;
9705
+ const legacy = join$1(directory, ".claude", "loop");
9706
+ if (existsSync$1(join$1(legacy, "loop-state.json"))) return legacy;
9707
+ return scoped;
9708
+ }
9695
9709
  return join$1(directory, ".claude", "loop");
9696
9710
  }
9697
- function readLoopState(directory) {
9711
+ function readLoopState(directory, sessionId) {
9698
9712
  try {
9699
- const p = join$1(getLoopDir(directory), "loop-state.json");
9713
+ const p = join$1(getLoopDir(directory, sessionId), "loop-state.json");
9700
9714
  if (!existsSync$1(p)) return null;
9701
9715
  return JSON.parse(readFileSync$1(p, "utf-8"));
9702
9716
  } catch {
9703
9717
  return null;
9704
9718
  }
9705
9719
  }
9706
- function isLoopActive(directory) {
9707
- const s = readLoopState(directory);
9720
+ function isLoopActive(directory, sessionId) {
9721
+ const s = readLoopState(directory, sessionId);
9708
9722
  return !!s && s.active !== false && s.phase !== "done" && s.phase !== "gave_up" && s.phase !== "cancelled";
9709
9723
  }
9710
- function loopOwnerSession(directory) {
9711
- const s = readLoopState(directory);
9724
+ function loopOwnerSession(directory, sessionId) {
9725
+ const s = readLoopState(directory, sessionId);
9712
9726
  if (!s || s.active === false || s.phase === "done" || s.phase === "gave_up" || s.phase === "cancelled") return null;
9713
9727
  return typeof s.session_id === "string" ? s.session_id : null;
9714
9728
  }
9715
9729
  function isLoopActiveForSession(directory, sessionId) {
9716
- const s = readLoopState(directory);
9730
+ const s = readLoopState(directory, sessionId);
9717
9731
  if (!s || s.active === false || s.phase === "done" || s.phase === "gave_up" || s.phase === "cancelled") return false;
9718
9732
  if (typeof s.session_id !== "string") return true;
9719
9733
  return s.session_id === sessionId;
@@ -9739,9 +9753,9 @@ function initLoop(directory, cfg) {
9739
9753
  const res = spawnSync(process.execPath, args, { encoding: "utf-8", timeout: 3e4 });
9740
9754
  return res.status === 0;
9741
9755
  }
9742
- function deactivateLoop(directory) {
9756
+ function deactivateLoop(directory, sessionId) {
9743
9757
  try {
9744
- const p = join$1(getLoopDir(directory), "loop-state.json");
9758
+ const p = join$1(getLoopDir(directory, sessionId), "loop-state.json");
9745
9759
  if (!existsSync$1(p)) return;
9746
9760
  const s = JSON.parse(readFileSync$1(p, "utf-8"));
9747
9761
  s.active = false;
@@ -9866,7 +9880,7 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
9866
9880
  logger.log(`[svampConfig] Loop init failed \u2014 loop-init.mjs not found`);
9867
9881
  }
9868
9882
  } else {
9869
- deactivateLoop(directory);
9883
+ deactivateLoop(directory, sessionId);
9870
9884
  sessionService.pushMessage({ type: "message", message: "Loop cancelled." }, "event");
9871
9885
  logger.log(`[svampConfig] Loop cancelled`);
9872
9886
  }
@@ -10300,7 +10314,7 @@ async function startDaemon(options) {
10300
10314
  const list = loadExposedTunnels().filter((t) => t.name !== name);
10301
10315
  saveExposedTunnels(list);
10302
10316
  }
10303
- const { ServeManager } = await import('./serveManager-ClBIhxJK.mjs');
10317
+ const { ServeManager } = await import('./serveManager-QZxNxQq0.mjs');
10304
10318
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
10305
10319
  ensureAutoInstalledSkills(logger).catch(() => {
10306
10320
  });
@@ -10539,7 +10553,7 @@ async function startDaemon(options) {
10539
10553
  stuckWatchdogTimer = setInterval(() => {
10540
10554
  if (!claudeProcess || claudeProcess.exitCode !== null) return;
10541
10555
  if (!sessionWasProcessing) return;
10542
- if (!isLoopActive(directory)) return;
10556
+ if (!isLoopActive(directory, sessionId)) return;
10543
10557
  if (claudeProcess.pid && hasActiveChildren(claudeProcess.pid)) {
10544
10558
  lastOutputTime = Date.now();
10545
10559
  return;
@@ -10553,7 +10567,7 @@ async function startDaemon(options) {
10553
10567
  );
10554
10568
  claudeProcess.kill("SIGTERM");
10555
10569
  setTimeout(() => {
10556
- if (!trackedSession.stopped && isLoopActive(directory)) {
10570
+ if (!trackedSession.stopped && isLoopActive(directory, sessionId)) {
10557
10571
  logger.log(`[Session ${sessionId}] Stuck watchdog: nudging loop to resume`);
10558
10572
  enqueueLoopContinue();
10559
10573
  processMessageQueueRef?.();
@@ -10661,7 +10675,7 @@ async function startDaemon(options) {
10661
10675
  if (options2.forceIsolation || sessionMetadata.sharing?.enabled) {
10662
10676
  rawPermissionMode = rawPermissionMode === "default" ? "auto-approve-all" : rawPermissionMode;
10663
10677
  }
10664
- if (isLoopActive(directory)) {
10678
+ if (isLoopActiveForSession(directory, sessionId)) {
10665
10679
  rawPermissionMode = "bypassPermissions";
10666
10680
  }
10667
10681
  const permissionMode = toClaudePermissionMode(rawPermissionMode);
@@ -10934,7 +10948,7 @@ async function startDaemon(options) {
10934
10948
  }
10935
10949
  }
10936
10950
  if (msg.type === "result") {
10937
- const loopActive = isLoopActive(directory);
10951
+ const loopActive = isLoopActiveForSession(directory, sessionId);
10938
10952
  if (!turnInitiatedByUser && !loopActive) {
10939
10953
  logger.log(`[Session ${sessionId}] Skipping stale result from SDK-initiated turn`);
10940
10954
  const hasBackgroundTasks = backgroundTaskCount > 0;
@@ -12457,7 +12471,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
12457
12471
  const wasInMemory = teardownTrackedSession(sessionId);
12458
12472
  const markedArchived = markSessionAsArchived(sessionId);
12459
12473
  if (loopDir && isLoopActiveForSession(loopDir, sessionId)) {
12460
- deactivateLoop(loopDir);
12474
+ deactivateLoop(loopDir, sessionId);
12461
12475
  logger.log(`Deactivated loop for archived session ${sessionId}`);
12462
12476
  }
12463
12477
  if (wasInMemory || markedArchived) {
@@ -12514,7 +12528,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
12514
12528
  teardownTrackedSession(sessionId);
12515
12529
  deletePersistedSession(sessionId);
12516
12530
  if (loopDir && isLoopActiveForSession(loopDir, sessionId)) {
12517
- deactivateLoop(loopDir);
12531
+ deactivateLoop(loopDir, sessionId);
12518
12532
  }
12519
12533
  logger.log(`Session ${sessionId} deleted`);
12520
12534
  return true;
@@ -12662,7 +12676,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
12662
12676
  const specs = loadExposedTunnels();
12663
12677
  if (specs.length === 0) return;
12664
12678
  logger.log(`[exposed-tunnels] Restoring ${specs.length} tunnel(s) from ${EXPOSED_TUNNELS_FILE}`);
12665
- const { FrpcTunnel } = await import('./frpc-D9HsqQ7e.mjs');
12679
+ const { FrpcTunnel } = await import('./frpc-C5Bhpsdw.mjs');
12666
12680
  for (const spec of specs) {
12667
12681
  if (tunnels.has(spec.name)) continue;
12668
12682
  try {
@@ -12750,10 +12764,21 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
12750
12764
  for (const p of persistedSessions) {
12751
12765
  if (sweptDirs.has(p.directory)) continue;
12752
12766
  sweptDirs.add(p.directory);
12753
- const owner = loopOwnerSession(p.directory);
12754
- if (owner && !knownSessionIds.has(owner)) {
12767
+ try {
12768
+ for (const ent of readdirSync$1(join$1(p.directory, ".svamp"), { withFileTypes: true })) {
12769
+ if (!ent.isDirectory() || knownSessionIds.has(ent.name)) continue;
12770
+ const owner = loopOwnerSession(p.directory, ent.name);
12771
+ if (owner && !knownSessionIds.has(owner)) {
12772
+ deactivateLoop(p.directory, ent.name);
12773
+ logger.log(`[loop] Deactivated stale loop-state for ${ent.name} in ${p.directory} (owner no longer known)`);
12774
+ }
12775
+ }
12776
+ } catch {
12777
+ }
12778
+ const legacyOwner = loopOwnerSession(p.directory);
12779
+ if (legacyOwner && !knownSessionIds.has(legacyOwner)) {
12755
12780
  deactivateLoop(p.directory);
12756
- logger.log(`[loop] Deactivated stale loop-state in ${p.directory} (owner session ${owner} no longer known)`);
12781
+ logger.log(`[loop] Deactivated stale legacy loop-state in ${p.directory} (owner session ${legacyOwner} no longer known)`);
12757
12782
  }
12758
12783
  }
12759
12784
  }
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
2
2
  import os from 'node:os';
3
3
  import { resolve, join } from 'node:path';
4
4
  import { existsSync, readFileSync, watch } from 'node:fs';
5
- import { c as connectToHypha, a as createSessionStore, r as registerMachineService, P as generateHookSettings } from './run-9j9_wlx5.mjs';
5
+ import { c as connectToHypha, a as createSessionStore, r as registerMachineService, P as generateHookSettings } from './run-LyzVTe3J.mjs';
6
6
  import { createServer } from 'node:http';
7
7
  import { spawn } from 'node:child_process';
8
8
  import { createInterface } from 'node:readline';
@@ -54,7 +54,7 @@ async function handleServeCommand() {
54
54
  }
55
55
  }
56
56
  async function serveAdd(args, machineId) {
57
- const { connectAndGetMachine } = await import('./commands-Cectk2JF.mjs');
57
+ const { connectAndGetMachine } = await import('./commands-DOsK9QRw.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-Cectk2JF.mjs');
96
+ const { connectAndGetMachine } = await import('./commands-DOsK9QRw.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-Cectk2JF.mjs');
185
+ const { connectAndGetMachine } = await import('./commands-DOsK9QRw.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-Cectk2JF.mjs');
205
+ const { connectAndGetMachine } = await import('./commands-DOsK9QRw.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-Cectk2JF.mjs');
238
+ const { connectAndGetMachine } = await import('./commands-DOsK9QRw.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-9j9_wlx5.mjs';
7
+ import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-LyzVTe3J.mjs';
8
8
  import 'os';
9
9
  import 'fs/promises';
10
10
  import 'url';
@@ -713,7 +713,7 @@ class ServeManager {
713
713
  const mount = this.mounts.get(mountName);
714
714
  const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, `static-${subdomainSafe}-${mount.linkToken}`]]) : void 0;
715
715
  try {
716
- const { FrpcTunnel } = await import('./frpc-D9HsqQ7e.mjs');
716
+ const { FrpcTunnel } = await import('./frpc-C5Bhpsdw.mjs');
717
717
  let tunnel;
718
718
  tunnel = new FrpcTunnel({
719
719
  name: tunnelName,
@@ -1,4 +1,4 @@
1
- import { z as READ_ONLY_TOOLS, A as loadMachineContext, B as buildMachineInstructions, C as machineToolsForRole, D as buildMachineTools } from './run-9j9_wlx5.mjs';
1
+ import { z as READ_ONLY_TOOLS, A as loadMachineContext, B as buildMachineInstructions, C as machineToolsForRole, D as buildMachineTools } from './run-LyzVTe3J.mjs';
2
2
  import 'node:child_process';
3
3
  import 'os';
4
4
  import 'fs/promises';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.106",
3
+ "version": "0.2.108",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",