svamp-cli 0.2.346 → 0.2.358

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 (33) hide show
  1. package/bin/skills/artifact/SKILL.md +19 -5
  2. package/bin/skills/crew/SKILL.md +42 -11
  3. package/dist/{acpBackend-BZ1MJhQV.mjs → acpBackend-UaBD4zL3.mjs} +3 -0
  4. package/dist/{agentCommands-B2Nl7Fof.mjs → agentCommands-C_KvvYFp.mjs} +5 -5
  5. package/dist/{claudeAuth-iAerdaMr.mjs → claudeAuth-DMDvPNhO.mjs} +55 -6
  6. package/dist/cli.mjs +164 -86
  7. package/dist/{commands-D69mnkYu.mjs → commands-B19lVZjm.mjs} +10 -3
  8. package/dist/{commands-BB1Kcyt-.mjs → commands-Bmoy6Rlw.mjs} +34 -4
  9. package/dist/{commands-CiRCwjkJ.mjs → commands-CFBKkfX8.mjs} +9 -9
  10. package/dist/{commands-D1pZq3d4.mjs → commands-CcdoQIkb.mjs} +126 -25
  11. package/dist/{commands-BOpoVBOM.mjs → commands-DH_YQrAP.mjs} +5 -21
  12. package/dist/{commands-H4PsTGn8.mjs → commands-DRxANaS5.mjs} +65 -19
  13. package/dist/{commands-C2aODeVc.mjs → commands-nkvTnUJj.mjs} +29 -13
  14. package/dist/{detectIsolation-CzoDCEnh.mjs → detectIsolation-CrV8IFDv.mjs} +36 -16
  15. package/dist/{fleet-DM_Q7w69.mjs → fleet-Ca-UjJNL.mjs} +40 -15
  16. package/dist/friendlyName-B-OEwt0t.mjs +341 -0
  17. package/dist/{headlessCli-C8HzQvis.mjs → headlessCli-BpTXz6FD.mjs} +24 -16
  18. package/dist/{hookSettings-DYMTUgVA.mjs → hookSettings-CvvUhwCK.mjs} +294 -55
  19. package/dist/{friendlyName-1UZcyDhu.mjs → inboxGuard-CDqmIypF.mjs} +32 -347
  20. package/dist/index.mjs +10 -9
  21. package/dist/{loopVerify-B47sSjxe.mjs → loopVerify-CxAKJB5a.mjs} +1 -1
  22. package/dist/{notifyCommands-D-IKIxiq.mjs → notifyCommands-CCUE18Q-.mjs} +1 -1
  23. package/dist/package-DTTWvJbp.mjs +64 -0
  24. package/dist/{rpc-Cf0grcru.mjs → rpc-CAlAHQAy.mjs} +8 -3
  25. package/dist/{rpc-BB6RF4-F.mjs → rpc-CacreLQ8.mjs} +13 -9
  26. package/dist/{run-ChdsgaSD.mjs → run-Bc81iurl.mjs} +27 -8
  27. package/dist/{run-DkjwF-zA.mjs → run-DKOND4dO.mjs} +222 -73
  28. package/dist/{scheduler-BY30ZrB9.mjs → scheduler-IyLWBF8T.mjs} +28 -10
  29. package/dist/{serveAuth-DbVLRCRR.mjs → serveAuth-4M0vwMyj.mjs} +53 -11
  30. package/dist/{serveCommands-CUHUiYnZ.mjs → serveCommands-B-Ym_QXc.mjs} +8 -8
  31. package/dist/{store-Bn0ByYev.mjs → store-D8dok6_d.mjs} +62 -14
  32. package/package.json +3 -3
  33. package/dist/package-DtuINqf5.mjs +0 -64
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: artifact
3
- version: 1.3.1
3
+ version: 1.3.2
4
4
  description: Embed a rendered HTML file or live URL inline in chat via a single self-closing `<artifact src="..." />` tag — the Svamp client renders it as a sandboxed iframe with modes for inline, card, bare, and immersive.
5
5
  tags:
6
6
  - svamp
@@ -134,16 +134,30 @@ This means you can iterate freely without polluting the chat with stale renders.
134
134
  To share with a colleague, run `svamp serve`:
135
135
 
136
136
  ```bash
137
- # Owner-only (defaultthey need to log in via Hypha)
137
+ # DEFAULT is the `link` tier a capability URL. NO login required:
138
+ # anyone who has the URL can read it. The hostname IS the secret.
138
139
  svamp serve dashboard ./outputs
139
140
 
140
- # Public link (anyone with the URL)
141
- svamp serve dashboard ./outputs --public
141
+ # Login-gated (only you, via Hypha) — opt IN to this
142
+ svamp serve dashboard ./outputs --access owner
142
143
 
143
- # Restrict to specific emails
144
+ # Restrict to specific emails (they log in via Hypha)
144
145
  svamp serve dashboard ./outputs --access alice@x.com,bob@y.com
146
+
147
+ # Listed publicly (anyone, no URL secrecy assumed)
148
+ svamp serve dashboard ./outputs --public
145
149
  ```
146
150
 
151
+ ⚠️ **Do not assume the default is login-gated.** It is not — `svamp serve` prints the tier back to
152
+ you as `link (capability URL — anyone with the URL can view)`. Before serving anything internal,
153
+ either pass `--access owner` or accept that possession of the URL is possession of the content.
154
+ Because the hostname is the secret, there is no way to revoke access to a `link` mount other than
155
+ `--regenerate-url`, which mints a new one; deleting the mount does not un-publish what was already
156
+ fetched.
157
+
158
+ Use the URL exactly as `serve`/`serve list` prints it — never compose it by hand, and never append a
159
+ path to it.
160
+
147
161
  Post the resulting URL as a normal markdown link. The svamp client doesn't manage shares — `svamp serve` is the dedicated tool.
148
162
 
149
163
  ## Rendering environment
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: crew
3
- version: 0.3.2
3
+ version: 0.3.4
4
4
  description: Coordinate work as a lead delegating features to managed worktree children — spawn a child per feature on its own branch, run it as a loop until done, and pull finished work back to the base branch with merge-and-close. Use when one session should run a project and farm out features instead of piling many sessions on one working tree.
5
5
  ---
6
6
 
@@ -13,10 +13,27 @@ the same working tree.
13
13
 
14
14
  A **crew** is emergent, not a heavy object: it is just plain sessions linked by
15
15
  `parentSessionId` + a `crew.role`. A **feature child** always (a) has the lead as its
16
- parent, (b) lives in its own `.dev/worktree/<n>` on its own branch, and (c) runs as a loop
17
- with `parent: <lead>` — i.e. **the lead is the judge** that decides when the child is done
18
- (this is the `parent`-routed case of the loop until gate; the loop engine is Claude Code's
19
- native `/goal`, driven from `svamp session loop`).
16
+ parent and (b) lives in its own `.dev/worktree/<n>` on its own branch.
17
+
18
+ > **⚠ Whether the child is GATED depends on how you started it (#1604).**
19
+ >
20
+ > | You ran | Gate |
21
+ > |---|---|
22
+ > | `crew start "<brief>"` (no `--oracle`) | **none** — the child works, then runs `feature done` when *it* decides it is complete. Nothing judges it. |
23
+ > | `crew start "<brief>" --oracle "<cmd>"` | a loop with `parent: <lead>` — the oracle gates each stop and **the lead is the judge** of done. |
24
+ >
25
+ > The CLI tells you which you got: it prints `gate: none — child runs 'feature done' when complete`
26
+ > on the ungated path. This is deliberate, not an oversight — `featureStart` attaches the loop only
27
+ > when there is an oracle, because a no-oracle child would otherwise fire `approved` on its very
28
+ > first stop, which is worse than no gate at all.
29
+ >
30
+ > **What this means for you as a lead:** if the feature has any objective success condition, pass
31
+ > `--oracle`. Without one you are the only thing standing between a child and a premature
32
+ > `feature done`, so read the merge request rather than trusting the verdict.
33
+ >
34
+ > This block used to claim every feature child runs as a loop with the lead as judge. It did not,
35
+ > and an agent that believed it would skip `--oracle`, skip checking on the child, and read "no
36
+ > verdict yet" as "still working" rather than "nothing will ever judge this".
20
37
 
21
38
  ## The verbs (these are your tools)
22
39
 
@@ -29,10 +46,17 @@ svamp feature start "<brief>" [--oracle "<test cmd>"] [--base <branch>] [--actio
29
46
  # nudge (default) = normal urgency, the lead sees it on its next idle turn;
30
47
  # block = urgent, which WAKES the lead. Use block for a child whose result
31
48
  # gates your next step; nudge for one you will collect when convenient.
32
- # --issue <id> links the child to an existing backlog issue: its verdict routes
33
- # ONTO that issue. This is the seam that joins crew to the backlog the loop
34
- # oracle (`svamp issue pending`) reads — without it the child's result is
35
- # invisible to the loop, so pass it whenever the feature came from an issue.
49
+ # --issue <id> links the child to an EXISTING backlog issue: its verdict routes
50
+ # ONTO that issue instead of onto a new one. This is the seam that joins crew
51
+ # to the backlog the loop oracle (`svamp issue pending`) reads.
52
+ # Pass it whenever the feature came from an issue, so the verdict lands on the
53
+ # item you are already tracking rather than creating a second one to reconcile.
54
+ # NOT passing it does NOT make the child invisible: `crew start` auto-creates a
55
+ # tracking issue at status `in_progress`, and `isPendingIssue` counts anything
56
+ # that is neither `archived` nor `paused` — so an unlinked child still holds the
57
+ # loop oracle RED until its issue is resolved. Do not treat an unlinked child as
58
+ # fire-and-forget; a lead waiting for `svamp issue pending` to empty will wait
59
+ # for it.
36
60
  # --max N bounds the child's loop iterations (a hard stop, unlike the soft
37
61
  # progress-based cap); --model <id> picks the child's model.
38
62
  svamp feature start "<brief>" --no-worktree --dir <folder>
@@ -81,8 +105,15 @@ You coordinate the project. Keep your own working tree (the base branch, e.g. `m
81
105
 
82
106
  ## If you are a FEATURE CHILD
83
107
 
84
- You own one feature in an isolated worktree on your own branch, reporting to your lead. Your
85
- brief (and your loop's "until" criteria) is injected each turn.
108
+ You own one feature in an isolated worktree on your own branch, reporting to your lead.
109
+
110
+ **Your brief arrives ONCE, as the first message of this session — it is not repeated (#1607).**
111
+ Nothing re-injects it, so keeping it in view is your job: re-read it before you decide you are done,
112
+ and restate it in your own words in `feature report` notes so drift is visible to your lead. (If your
113
+ lead started you *with* `--oracle`, the native `/goal` gate does restate the "until" criteria at each
114
+ turn-end — but on the default no-oracle path there is no loop at all. See the gate table above.)
115
+ This line previously promised per-turn injection of both; no such mechanism was ever built, and
116
+ `docs/crew-design.md` §7 already recorded those hooks as never shipped.
86
117
 
87
118
  - **Work in your worktree.** Implement the feature. Commit as you go. Keep the oracle/tests green.
88
119
  - **Report.** Use `svamp feature report "<note>"` for milestones and `--blocker` when stuck —
@@ -558,6 +558,9 @@ class AcpBackend {
558
558
  return { outcome: { outcome: "selected", optionId: "cancel" } };
559
559
  }
560
560
  }
561
+ if (!this.options.permissionHandler) {
562
+ return { outcome: { outcome: "cancelled" } };
563
+ }
561
564
  const proceedOnceOption = options.find(
562
565
  (opt) => opt.optionId === "proceed_once" || typeof opt.name === "string" && opt.name.toLowerCase().includes("once")
563
566
  );
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync } from '
2
2
  import { join, dirname } from 'node:path';
3
3
  import os from 'node:os';
4
4
  import { requireNotSandboxed } from './sandboxDetect-Cdzsj5TC.mjs';
5
- import { s as shortId } from './friendlyName-1UZcyDhu.mjs';
5
+ import { s as shortId } from './friendlyName-B-OEwt0t.mjs';
6
6
  import 'node:crypto';
7
7
 
8
8
  const SVAMP_HOME = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
@@ -79,7 +79,7 @@ async function sessionSetTitle(title) {
79
79
  }
80
80
  async function sessionSetProjectDescription(description) {
81
81
  const dir = process.cwd();
82
- const { projectName, writeProjectInfo, sanitizeDescription, projectInfoPath } = await import('./run-DkjwF-zA.mjs').then(function (n) { return n.p; });
82
+ const { projectName, writeProjectInfo, sanitizeDescription, projectInfoPath } = await import('./run-DKOND4dO.mjs').then(function (n) { return n.p; });
83
83
  const desc = sanitizeDescription(description, 240);
84
84
  if (!desc) {
85
85
  console.error("Project description is empty.");
@@ -382,7 +382,7 @@ async function sessionBroadcast(action, args) {
382
382
  console.log(`Broadcast sent: ${action}`);
383
383
  }
384
384
  async function connectToMachineService() {
385
- const { connectAndGetMachine } = await import('./commands-D1pZq3d4.mjs');
385
+ const { connectAndGetMachine } = await import('./commands-CcdoQIkb.mjs').then(function (n) { return n.d; });
386
386
  return connectAndGetMachine();
387
387
  }
388
388
  function buildInboxMessage(args) {
@@ -465,7 +465,7 @@ async function inboxSend(targetSessionId, opts) {
465
465
  console.error("Message body is required.");
466
466
  process.exit(1);
467
467
  }
468
- const { connectAndResolveSession } = await import('./commands-D1pZq3d4.mjs');
468
+ const { connectAndResolveSession } = await import('./commands-CcdoQIkb.mjs').then(function (n) { return n.d; });
469
469
  let server;
470
470
  try {
471
471
  const { targetId, messageId } = await inboxSendCore(
@@ -520,7 +520,7 @@ async function inboxReply(messageId, body, opts) {
520
520
  console.error("SVAMP_SESSION_ID not set. This command must be run inside a Svamp session.");
521
521
  process.exit(1);
522
522
  }
523
- const { connectAndResolveSession } = await import('./commands-D1pZq3d4.mjs');
523
+ const { connectAndResolveSession } = await import('./commands-CcdoQIkb.mjs').then(function (n) { return n.d; });
524
524
  const { server: localServer, machine: localMachine } = await connectToMachineService();
525
525
  let localDisconnected = false;
526
526
  const disconnectLocal = async () => {
@@ -182,12 +182,61 @@ function applyPromptCacheTtl(spawnEnv) {
182
182
  if (explicit1h === void 0) spawnEnv.ENABLE_PROMPT_CACHING_1H = "1";
183
183
  }
184
184
  const BETA_1M_TOKEN = "context-1m-2025-08-07";
185
+ let longContext1MEntitlement = "unknown";
186
+ function setLongContext1MEntitlement(state) {
187
+ longContext1MEntitlement = state;
188
+ }
189
+ function getLongContext1MEntitlement() {
190
+ return longContext1MEntitlement;
191
+ }
192
+ function isLongContextBetaUnavailableError(err) {
193
+ const text = typeof err === "string" ? err : err?.message ?? String(err ?? "");
194
+ return /long context beta is not (yet )?available/i.test(text);
195
+ }
196
+ const LONG_CONTEXT_ENTITLEMENT_RECHECK_MS = Number(process.env.SVAMP_1M_ENTITLEMENT_RECHECK_MS || 60 * 60 * 1e3);
197
+ async function probeLongContext1MEntitlement(baseUrl, apiKey, fetchImpl = fetch) {
198
+ if (!baseUrl || !apiKey) return longContext1MEntitlement;
199
+ try {
200
+ const resp = await fetchImpl(`${baseUrl.replace(/\/$/, "")}/v1/messages`, {
201
+ method: "POST",
202
+ headers: {
203
+ "content-type": "application/json",
204
+ authorization: `Bearer ${apiKey}`,
205
+ "anthropic-beta": BETA_1M_TOKEN
206
+ },
207
+ body: JSON.stringify({
208
+ model: "claude-haiku-4-5-20251001",
209
+ max_tokens: 1,
210
+ messages: [{ role: "user", content: "x" }]
211
+ }),
212
+ signal: AbortSignal.timeout(2e4)
213
+ });
214
+ if (resp.ok) {
215
+ setLongContext1MEntitlement("entitled");
216
+ return "entitled";
217
+ }
218
+ const text = await resp.text().catch(() => "");
219
+ if (isLongContextBetaUnavailableError(text)) {
220
+ setLongContext1MEntitlement("not-entitled");
221
+ return "not-entitled";
222
+ }
223
+ return longContext1MEntitlement;
224
+ } catch {
225
+ return longContext1MEntitlement;
226
+ }
227
+ }
185
228
  function applyLongContext1M(spawnEnv) {
186
- if (envFlagEnabled(spawnEnv.CLAUDE_CODE_DISABLE_1M_CONTEXT) || envFlagEnabled(process.env.CLAUDE_CODE_DISABLE_1M_CONTEXT)) return;
229
+ if (envFlagEnabled(spawnEnv.CLAUDE_CODE_DISABLE_1M_CONTEXT) || envFlagEnabled(process.env.CLAUDE_CODE_DISABLE_1M_CONTEXT)) return false;
230
+ if (longContext1MEntitlement !== "entitled") return false;
187
231
  const existing = spawnEnv.ANTHROPIC_BETAS ?? process.env.ANTHROPIC_BETAS ?? "";
188
232
  const betas = existing.split(",").map((b) => b.trim()).filter(Boolean);
189
233
  if (!betas.includes(BETA_1M_TOKEN)) betas.push(BETA_1M_TOKEN);
190
234
  spawnEnv.ANTHROPIC_BETAS = betas.join(",");
235
+ return true;
236
+ }
237
+ function describeContextWindow(injected) {
238
+ if (injected) return "1M context";
239
+ return `200K context (1M beta not sent \u2014 entitlement ${longContext1MEntitlement})`;
191
240
  }
192
241
  function applyTodoTools(spawnEnv) {
193
242
  const override = spawnEnv.CLAUDE_CODE_ENABLE_TODO_TOOLS ?? process.env.CLAUDE_CODE_ENABLE_TODO_TOOLS;
@@ -221,8 +270,8 @@ function applyClaudeProxyEnv(spawnEnv) {
221
270
  spawnEnv.ANTHROPIC_BASE_URL = proxyUrl;
222
271
  spawnEnv.ANTHROPIC_API_KEY = token;
223
272
  applyPromptCacheTtl(spawnEnv);
224
- applyLongContext1M(spawnEnv);
225
- return `hypha proxy (${proxyUrl}, 1h cache TTL, 1M context)`;
273
+ const oneM = applyLongContext1M(spawnEnv);
274
+ return `hypha proxy (${proxyUrl}, 1h cache TTL, ${describeContextWindow(oneM)})`;
226
275
  }
227
276
  if (mode === "custom") {
228
277
  const url = process.env.ANTHROPIC_BASE_URL;
@@ -235,8 +284,8 @@ function applyClaudeProxyEnv(spawnEnv) {
235
284
  spawnEnv.ANTHROPIC_BASE_URL = url;
236
285
  spawnEnv.ANTHROPIC_API_KEY = key;
237
286
  applyPromptCacheTtl(spawnEnv);
238
- applyLongContext1M(spawnEnv);
239
- return `custom proxy (${url}, 1h cache TTL, 1M context)`;
287
+ const oneM = applyLongContext1M(spawnEnv);
288
+ return `custom proxy (${url}, 1h cache TTL, ${describeContextWindow(oneM)})`;
240
289
  }
241
290
  delete spawnEnv.ANTHROPIC_BASE_URL;
242
291
  delete spawnEnv.ANTHROPIC_API_KEY;
@@ -244,4 +293,4 @@ function applyClaudeProxyEnv(spawnEnv) {
244
293
  }
245
294
  const MANAGED_ENV_KEYS = Array.from(MANAGED_KEYS);
246
295
 
247
- export { BETA_1M_TOKEN, EXAMPLE_HYPHA_PROXY_URL, MANAGED_ENV_KEYS, applyClaudeProxyEnv, getClaudeAuthStatus, normalizeProxyUrl, resolveHyphaProxyUrl, setClaudeAuthCustom, setClaudeAuthHyphaProxy, setClaudeAuthLogin, updateEnvFile };
296
+ export { BETA_1M_TOKEN, EXAMPLE_HYPHA_PROXY_URL, LONG_CONTEXT_ENTITLEMENT_RECHECK_MS, MANAGED_ENV_KEYS, applyClaudeProxyEnv, getClaudeAuthStatus, getLongContext1MEntitlement, isLongContextBetaUnavailableError, normalizeProxyUrl, probeLongContext1MEntitlement, resolveHyphaProxyUrl, setClaudeAuthCustom, setClaudeAuthHyphaProxy, setClaudeAuthLogin, setLongContext1MEntitlement, updateEnvFile };