@super-one/cli 0.50.2-alpha → 0.50.4-alpha

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/MANIFEST.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@super-one/cli",
3
- "version": "0.50.2-alpha",
3
+ "version": "0.50.4-alpha",
4
4
  "kind": "npm",
5
5
  "minNodeMajor": 20,
6
- "builtAt": "2026-08-06T17:30:12.368Z"
6
+ "builtAt": "2026-08-07T04:11:13.179Z"
7
7
  }
package/lib/cli.mjs CHANGED
@@ -170,7 +170,7 @@ var init_host_action_superone_descriptors = __esm({
170
170
  HOST_ACTION_SUPERONE_TOOL_DESCRIPTORS = [
171
171
  {
172
172
  "name": "session_collab_list_agents",
173
- "description": "List the built-in agent profiles (harness + config) available for user-approved child sessions. Each profile includes defaultConfig with the model/effort inherited when a request omits them. Call this before session_collab_request. The same profile may be requested more than once.",
173
+ "description": "List the agent profiles available for user-approved child sessions. Inspect each profile's harness and defaultConfig before session_collab_request. You may reuse one agentId for multiple launches.",
174
174
  "inputSchema": {
175
175
  "type": "object",
176
176
  "properties": {},
@@ -179,7 +179,7 @@ var init_host_action_superone_descriptors = __esm({
179
179
  },
180
180
  {
181
181
  "name": "session_collab_request",
182
- "description": 'Request approval for one or more child-agent launches. Repeat an agentId to launch multiple sessions from one profile. Every launch must include name (an agent-chosen human label, not the harness name) and role (for example, Reviewer or Implementer). config is optional; omitted model/effort fields inherit the selected profile defaultConfig, while explicit values override it. Session title becomes "Name - Role". The user reviews and may edit model/effort/AI provider/permission/sandbox (task, name, role, agent profile, cwd, worktree stay as requested). On approval each launch returns a bearer credential. Each credential can create exactly one session and must be kept private.',
182
+ "description": 'Request user approval for one or more child sessions. Call session_collab_list_agents first; repeat an agentId to reuse a profile. Invent a human-friendly name and a task-specific role for every launch. Omitted config fields inherit profile defaults. Before setting config.cwd or config.worktree, call read_manual({ domain: "product", topic: "collaboration" }); same-repo isolation belongs in config.worktree, not a worktree-leaf cwd. The user may edit model, effort, provider, permission, and sandbox settings. Each approved launch returns a private one-shot credential for session_collab_start.',
183
183
  "inputSchema": {
184
184
  "type": "object",
185
185
  "properties": {
@@ -251,10 +251,12 @@ var init_host_action_superone_descriptors = __esm({
251
251
  ]
252
252
  },
253
253
  "cwd": {
254
- "type": "string"
254
+ "type": "string",
255
+ "description": 'Set only to a genuinely different project root. Omit for the current project. Never pass ~/.worktrees/... or another same-repo worktree leaf; use config.worktree for same-repo isolation. See read_manual({ domain: "product", topic: "collaboration" }).'
255
256
  },
256
257
  "worktree": {
257
258
  "type": "object",
259
+ "description": 'Request a host-managed worktree for same-repo isolation while cwd stays omitted or at the project root. Set enabled, baseBranch, and mode; use a unique branchName with branch. See read_manual({ domain: "product", topic: "collaboration" }) for implementer and reviewer recipes.',
258
260
  "properties": {
259
261
  "enabled": {
260
262
  "type": "boolean"
@@ -272,7 +274,7 @@ var init_host_action_superone_descriptors = __esm({
272
274
  },
273
275
  "branchName": {
274
276
  "type": "string",
275
- "description": "Branch to create for this worktree. Must be unique across launches \u2014 git cannot check out one branch in two worktrees."
277
+ "description": 'With mode "branch", create this unique branch. Git cannot check out one branch in two worktrees.'
276
278
  },
277
279
  "carryLocalChanges": {
278
280
  "type": "boolean"
@@ -310,7 +312,7 @@ var init_host_action_superone_descriptors = __esm({
310
312
  },
311
313
  {
312
314
  "name": "session_collab_start",
313
- "description": "Create the real, user-visible collaboration child session authorized by one credential and deliver the approved launch task. Returns as soon as the child agent begins replying (does not wait for the full first turn). A credential creates at most one session; repeated calls are idempotent and return the same session id. The child then works asynchronously \u2014 start every child you need back to back, and never block on one before starting the next.",
315
+ "description": "Start the approved child session for one credential and deliver its task. The call returns when the child begins replying, not when its first turn finishes. A credential starts at most one session; retries return the same session id. Start all approved children back-to-back, then continue other work while they run asynchronously.",
314
316
  "inputSchema": {
315
317
  "type": "object",
316
318
  "properties": {
@@ -326,7 +328,7 @@ var init_host_action_superone_descriptors = __esm({
326
328
  },
327
329
  {
328
330
  "name": "session_collab_send",
329
- "description": "Send a persistent mailbox message between the parent and child sessions authorized by a credential. Direction is derived from the calling session. Write content as Markdown (headings, lists, code fences, emphasis, tables when useful) so peer agents and the SuperOne UI can render a structured handoff. Use clientMessageId for retry-safe idempotency. Delivery is push-based both ways: the peer is woken by a task notification (even mid-turn), and when it replies the host wakes you the same way \u2014 a fresh turn starts, telling you to call session_collab_retrieve. So after sending, move on to other work or end your turn; ending the turn IS how you wait here, and no reply is missed. Never sleep, re-send, or poll session_collab_retrieve while waiting.",
331
+ "description": "Send a persistent Markdown message through one parent-child mailbox. Use clientMessageId for retry-safe delivery. The host wakes the peer and later wakes you when it replies. After sending, continue other work or end your turn. Never sleep, resend, or poll session_collab_retrieve while waiting.",
330
332
  "inputSchema": {
331
333
  "type": "object",
332
334
  "properties": {
@@ -351,7 +353,7 @@ var init_host_action_superone_descriptors = __esm({
351
353
  },
352
354
  {
353
355
  "name": "session_collab_retrieve",
354
- "description": 'Retrieve persistent mailbox messages addressed to this session. Non-blocking single read: returns the messages already waiting (status "messages") or nothing (status "empty"). Each message content is Markdown written by the peer \u2014 parse structure (headings, lists, code) rather than treating it as plain text. Pass multiple credentials to drain several parent/child mailboxes in one call. Returned messages advance only this agent endpoint cursor. Call it when a collaboration wake notification arrives, or once to drain the inbox before you act on peer input. Status "empty" means no peer has replied yet \u2014 it is NOT a retry signal: do not call again, do not sleep, do not spin. End your turn and the wake notification will start a new one the moment a message actually arrives.',
356
+ "description": 'Retrieve queued Markdown messages for this session from one or more parent-child mailboxes. Call after a collaboration wake, or once before acting on peer input. This is a non-blocking read: status "empty" is not a retry signal. Do not sleep or poll; end your turn and wait for the next wake.',
355
357
  "inputSchema": {
356
358
  "type": "object",
357
359
  "properties": {
@@ -372,7 +374,7 @@ var init_host_action_superone_descriptors = __esm({
372
374
  },
373
375
  {
374
376
  "name": "read_manual",
375
- "description": "Read bundled SuperOne manuals. Omit domain to list all domains; pass domain to list its topics; pass domain with topic to read one topic. For widget, pass either topic or modules, never both. Use product/debug for support and runtime paths, miniapp/overview before mini-app development, and media/overview before provider-specific options. Use config_read for live settings and widget_list_templates for saved widgets.",
377
+ "description": "Read bundled SuperOne manuals. Omit domain to list all domains; pass domain to list its topics; pass domain with topic to read one topic. For widget, pass either topic or modules, never both. Use product/contribute for GitHub issues and PRs (issue-first, optional red\u2013green), product/debug for support and runtime paths, miniapp/overview before mini-app development, and media/overview before provider-specific options. Use config_read for live settings and widget_list_templates for saved widgets.",
376
378
  "inputSchema": {
377
379
  "type": "object",
378
380
  "properties": {
@@ -3268,7 +3270,13 @@ var init_auth = __esm({
3268
3270
  /** WebSocket ticket: 30 seconds, single /ws upgrade. */
3269
3271
  wsTicketMs: 30 * 1e3,
3270
3272
  /** Refresh family expires after 90 days of inactivity. */
3271
- refreshInactivityMs: 90 * 24 * 60 * 60 * 1e3
3273
+ refreshInactivityMs: 90 * 24 * 60 * 60 * 1e3,
3274
+ /**
3275
+ * Immediately-previous refresh token remains redeemable this long after
3276
+ * rotation. Mitigates lost-response / concurrent-refresh races without
3277
+ * disabling reuse detection for older generations (RFC 6819 §5.2.2.3).
3278
+ */
3279
+ refreshReuseGraceMs: 60 * 1e3
3272
3280
  };
3273
3281
  OPERATION_SCOPES = {
3274
3282
  readEnvironment: ["environment:read"],
@@ -18260,6 +18268,26 @@ function consumerForHarness(harness) {
18260
18268
  if (harness === "codex") return "chat:codex";
18261
18269
  return null;
18262
18270
  }
18271
+ function listHarnessApiProviders(store, harness) {
18272
+ const consumer = consumerForHarness(harness);
18273
+ if (!consumer) return [];
18274
+ const platforms = platformsForNode(store);
18275
+ const out = [];
18276
+ for (const cred of store.listCredentials()) {
18277
+ const platform2 = findPlatform(platforms, cred.platformId);
18278
+ const plan = findPlan(platform2, cred.planId);
18279
+ if (!platform2 || !plan) continue;
18280
+ const endpoints = effectiveEndpoints(platform2, plan, cred);
18281
+ if (!selectEndpoint(plan, consumer, void 0, cred, endpoints)) continue;
18282
+ out.push({
18283
+ id: cred.id,
18284
+ name: platform2.name ?? cred.name,
18285
+ ...platform2.brand ? { brand: platform2.brand } : {},
18286
+ ...cred.name ? { keyName: cred.name } : {}
18287
+ });
18288
+ }
18289
+ return out;
18290
+ }
18263
18291
  function buildHarnessEnv(harness, resolved) {
18264
18292
  if (!resolved) return {};
18265
18293
  const env = { ...resolved.extraEnv ?? {} };
@@ -40947,6 +40975,7 @@ function createXaiCorrelationState() {
40947
40975
  workflowToolByRunId: /* @__PURE__ */ new Map(),
40948
40976
  workflowRevision: /* @__PURE__ */ new Map(),
40949
40977
  workflowStarted: /* @__PURE__ */ new Set(),
40978
+ workflowOwnedSubagents: /* @__PURE__ */ new Set(),
40950
40979
  subagentToolById: /* @__PURE__ */ new Map(),
40951
40980
  subagentStarted: /* @__PURE__ */ new Set(),
40952
40981
  bgTaskById: /* @__PURE__ */ new Map(),
@@ -41237,15 +41266,16 @@ function mapWorkflowUpdated(u, state) {
41237
41266
  }
41238
41267
  if (WORKFLOW_TERMINAL.has(status)) {
41239
41268
  const taskStatus = status === "complete" || status === "completed" ? "completed" : status === "cancelled" || status === "canceled" ? "stopped" : "failed";
41269
+ const resultText = resultSummary || pauseMessage || lastEventDetail || void 0;
41240
41270
  events.push({
41241
41271
  type: "task_notification",
41242
41272
  taskId: runId,
41243
41273
  ...toolUseId ? { toolUseId } : {},
41244
41274
  taskStatus,
41245
41275
  outputFile: "",
41246
- summary: phaseLine || resultSummary || status,
41276
+ summary: resultSummary || phaseLine || pauseMessage || status,
41247
41277
  usage: usage2,
41248
- ...resultSummary ? { resultText: resultSummary } : {},
41278
+ ...resultText ? { resultText } : {},
41249
41279
  ...phaseFields
41250
41280
  });
41251
41281
  return events;
@@ -41255,9 +41285,9 @@ function mapWorkflowUpdated(u, state) {
41255
41285
  taskId: runId,
41256
41286
  ...toolUseId ? { toolUseId } : {},
41257
41287
  description,
41258
- summary: phaseLine || status,
41288
+ summary: phaseLine || pauseMessage || status,
41259
41289
  usage: usage2,
41260
- ...lastEventDetail || lastEvent ? { activityText: lastEventDetail ?? lastEvent } : {},
41290
+ ...lastEventDetail || lastEvent || pauseMessage ? { activityText: pauseMessage ?? lastEventDetail ?? lastEvent } : {},
41261
41291
  ...phaseFields
41262
41292
  });
41263
41293
  return events;
@@ -41327,16 +41357,16 @@ function mapSubagentSpawned(u, state) {
41327
41357
  state.subagentStarted.add(id);
41328
41358
  const description = strField(u, "description") ?? id;
41329
41359
  const subagentType = strField(u, "subagent_type", "subagentType");
41330
- const toolUseId = state.subagentToolById.get(id);
41331
41360
  const workflowRunId = strField(u, "workflow_run_id", "workflowRunId");
41332
- if (workflowRunId && !toolUseId) {
41333
- const wfTool = state.workflowToolByRunId.get(workflowRunId);
41334
- if (wfTool) state.subagentToolById.set(id, wfTool);
41361
+ if (workflowRunId) {
41362
+ state.workflowOwnedSubagents.add(id);
41363
+ state.subagentToolById.delete(id);
41335
41364
  }
41365
+ const toolUseId = workflowRunId ? void 0 : state.subagentToolById.get(id);
41336
41366
  return [{
41337
41367
  type: "task_started",
41338
41368
  taskId: id,
41339
- ...state.subagentToolById.get(id) ? { toolUseId: state.subagentToolById.get(id) } : {},
41369
+ ...toolUseId ? { toolUseId } : {},
41340
41370
  description,
41341
41371
  ...subagentType ? { taskType: subagentType } : {}
41342
41372
  }];
@@ -41344,6 +41374,7 @@ function mapSubagentSpawned(u, state) {
41344
41374
  function mapSubagentProgress(u, state) {
41345
41375
  const id = strField(u, "subagent_id", "subagentId");
41346
41376
  if (!id) return [];
41377
+ if (state.workflowOwnedSubagents.has(id)) return [];
41347
41378
  const events = [];
41348
41379
  if (!state.subagentStarted.has(id)) {
41349
41380
  state.subagentStarted.add(id);
@@ -41373,6 +41404,7 @@ function mapSubagentProgress(u, state) {
41373
41404
  function mapSubagentFinished(u, state) {
41374
41405
  const id = strField(u, "subagent_id", "subagentId");
41375
41406
  if (!id) return [];
41407
+ if (state.workflowOwnedSubagents.has(id)) return [];
41376
41408
  const status = (strField(u, "status") ?? "completed").toLowerCase();
41377
41409
  const taskStatus = status === "completed" || status === "complete" ? "completed" : status === "cancelled" || status === "canceled" ? "stopped" : "failed";
41378
41410
  const toolUseId = state.subagentToolById.get(id);
@@ -57155,8 +57187,8 @@ import { fileURLToPath } from "node:url";
57155
57187
  function resolveCliReleaseVersion() {
57156
57188
  const fromEnv = process.env.SUPERONE_CLI_VERSION?.trim();
57157
57189
  if (fromEnv) return fromEnv;
57158
- if ("0.50.2-alpha".trim()) {
57159
- return "0.50.2-alpha".trim();
57190
+ if ("0.50.4-alpha".trim()) {
57191
+ return "0.50.4-alpha".trim();
57160
57192
  }
57161
57193
  const fromDist = readDistManifestVersion();
57162
57194
  if (fromDist) return fromDist;
@@ -57501,26 +57533,52 @@ var AuthService = class {
57501
57533
  return exchange();
57502
57534
  }
57503
57535
  /**
57504
- * Rotate refresh credential; reuse of an old refresh hash revokes the family.
57505
- * Requires proof signature over `proofPayload` with the registered device key
57506
- * (caller validates signature separately or passes already-verified flag).
57536
+ * Rotate refresh credential.
57537
+ *
57538
+ * Reuse of a rotated refresh hash outside
57539
+ * {@link AUTH_CREDENTIAL_LIFETIMES.refreshReuseGraceMs} is treated as theft
57540
+ * and permanently revokes the family. Inside the grace window, presenting any
57541
+ * previously rotated hash re-rotates the *current* session and returns a fresh
57542
+ * pair (lost-response / concurrent-refresh races — RFC 6819 §5.2.2.3 style).
57543
+ *
57544
+ * Requires proof signature over `proofPayload` with the registered device key.
57507
57545
  */
57508
57546
  refreshAccess(input) {
57509
57547
  const refreshHash = this.hashSecret(input.refreshToken);
57510
57548
  const now = Date.now();
57511
- const row = this.db.prepare(
57549
+ const loadByHash = (hash2) => this.db.prepare(
57512
57550
  `SELECT client_session_id, device_public_key_pem, device_public_key_fingerprint,
57513
- scopes_json, refresh_family_id, refresh_hash, refresh_expires_at, revoked_at
57514
- FROM client_sessions WHERE refresh_hash = ?`
57515
- ).get(refreshHash);
57551
+ scopes_json, refresh_family_id, refresh_hash, refresh_expires_at, revoked_at
57552
+ FROM client_sessions WHERE refresh_hash = ?`
57553
+ ).get(hash2);
57554
+ const loadBySessionId = (clientSessionId) => this.db.prepare(
57555
+ `SELECT client_session_id, device_public_key_pem, device_public_key_fingerprint,
57556
+ scopes_json, refresh_family_id, refresh_hash, refresh_expires_at, revoked_at
57557
+ FROM client_sessions WHERE client_session_id = ?`
57558
+ ).get(clientSessionId);
57559
+ let row = loadByHash(refreshHash);
57516
57560
  if (!row) {
57517
- const reused = this.db.prepare("SELECT client_session_id FROM refresh_reuse_log WHERE refresh_hash = ?").get(refreshHash);
57518
- if (reused) {
57519
- this.db.prepare("UPDATE client_sessions SET revoked_at = ? WHERE client_session_id = ? AND revoked_at IS NULL").run(now, reused.client_session_id);
57561
+ const reused = this.db.prepare(
57562
+ `SELECT client_session_id, seen_at FROM refresh_reuse_log WHERE refresh_hash = ?`
57563
+ ).get(refreshHash);
57564
+ if (!reused) {
57565
+ throw Object.assign(new Error("invalid refresh token"), { code: "unauthorized" });
57566
+ }
57567
+ const withinGrace = now - reused.seen_at <= AUTH_CREDENTIAL_LIFETIMES.refreshReuseGraceMs;
57568
+ if (withinGrace) {
57569
+ row = loadBySessionId(reused.client_session_id);
57570
+ if (!row) {
57571
+ throw Object.assign(new Error("invalid refresh token"), { code: "unauthorized" });
57572
+ }
57573
+ } else {
57574
+ this.db.prepare(
57575
+ "UPDATE client_sessions SET revoked_at = ? WHERE client_session_id = ? AND revoked_at IS NULL"
57576
+ ).run(now, reused.client_session_id);
57520
57577
  this.onRevoke?.(reused.client_session_id);
57521
- throw Object.assign(new Error("refresh token reuse detected; session revoked"), { code: "unauthorized" });
57578
+ throw Object.assign(new Error("refresh token reuse detected; session revoked"), {
57579
+ code: "unauthorized"
57580
+ });
57522
57581
  }
57523
- throw Object.assign(new Error("invalid refresh token"), { code: "unauthorized" });
57524
57582
  }
57525
57583
  if (row.revoked_at) throw Object.assign(new Error("client session revoked"), { code: "unauthorized" });
57526
57584
  if (row.refresh_expires_at < now) {
@@ -57542,20 +57600,21 @@ var AuthService = class {
57542
57600
  if (!Number.isFinite(proofTs) || Math.abs(now - proofTs) > 12e4) {
57543
57601
  throw Object.assign(new Error("proof timestamp out of window"), { code: "unauthorized" });
57544
57602
  }
57603
+ const session = row;
57545
57604
  return this.db.transaction(() => {
57546
- const scopes = parseScopes(row.scopes_json);
57605
+ const scopes = parseScopes(session.scopes_json);
57547
57606
  const newRefresh = randomToken(32);
57548
57607
  const newRefreshHash = this.hashSecret(newRefresh);
57549
57608
  const refreshExpiresAt = now + AUTH_CREDENTIAL_LIFETIMES.refreshInactivityMs;
57550
57609
  this.db.prepare(
57551
57610
  `INSERT OR IGNORE INTO refresh_reuse_log (refresh_hash, client_session_id, seen_at)
57552
57611
  VALUES (?, ?, ?)`
57553
- ).run(row.refresh_hash, row.client_session_id, now);
57612
+ ).run(session.refresh_hash, session.client_session_id, now);
57554
57613
  const updated = this.db.prepare(
57555
57614
  `UPDATE client_sessions
57556
57615
  SET refresh_hash = ?, refresh_expires_at = ?, last_used_at = ?
57557
57616
  WHERE client_session_id = ? AND refresh_hash = ? AND revoked_at IS NULL`
57558
- ).run(newRefreshHash, refreshExpiresAt, now, row.client_session_id, row.refresh_hash);
57617
+ ).run(newRefreshHash, refreshExpiresAt, now, session.client_session_id, session.refresh_hash);
57559
57618
  if (updated.changes !== 1) {
57560
57619
  throw Object.assign(new Error("refresh race; retry"), { code: "conflict" });
57561
57620
  }
@@ -57565,15 +57624,15 @@ var AuthService = class {
57565
57624
  aud: "superone",
57566
57625
  exp: expiresAt,
57567
57626
  iat: now,
57568
- clientSessionId: row.client_session_id,
57627
+ clientSessionId: session.client_session_id,
57569
57628
  scopes,
57570
- proofKeyThumbprint: row.device_public_key_fingerprint
57629
+ proofKeyThumbprint: session.device_public_key_fingerprint
57571
57630
  });
57572
57631
  return {
57573
57632
  accessToken,
57574
57633
  expiresAt,
57575
57634
  scopes,
57576
- clientSessionId: row.client_session_id,
57635
+ clientSessionId: session.client_session_id,
57577
57636
  refreshToken: newRefresh
57578
57637
  };
57579
57638
  })();
@@ -61171,7 +61230,12 @@ function defaultProbeModels(ctx) {
61171
61230
  return async (harnessId, cwd) => {
61172
61231
  if (harnessId !== "claude") return [];
61173
61232
  const binaryPath = resolveClaudeBinaryPath({ harnesses: ctx.harnesses });
61174
- if (!binaryPath) return [];
61233
+ if (!binaryPath) {
61234
+ console.warn(
61235
+ "[harness.resources] claude model probe skipped: no Agent SDK binary on this node (reinstall the optional platform package or set SUPERONE_CLAUDE_BINARY)"
61236
+ );
61237
+ return [];
61238
+ }
61175
61239
  return getNodeClaudeModelCatalog({ cwd, binaryPath });
61176
61240
  };
61177
61241
  }
@@ -61209,6 +61273,9 @@ async function handleHarnessResources(payload, ctx) {
61209
61273
  const probe = ctx.probeModels ?? defaultProbeModels(ctx);
61210
61274
  const probed = await probe(hid, project.path);
61211
61275
  if (probed.length > 0) return probed;
61276
+ console.warn(
61277
+ `[harness.resources] ${hid} probe returned no models; serving the built-in fallback table`
61278
+ );
61212
61279
  return listHarnessModels(ctx.providers, hid, apiProviderId ?? null);
61213
61280
  };
61214
61281
  const bundle = await collectHarnessResources({
@@ -65643,7 +65710,7 @@ var CollaborationService = class {
65643
65710
  },
65644
65711
  models: models.length > 0 ? models : [{ id: "default", name: "Default" }],
65645
65712
  efforts: [...efforts],
65646
- apiProviders: []
65713
+ apiProviders: listHarnessApiProviders(providers, harnessId)
65647
65714
  });
65648
65715
  };
65649
65716
  if (sessionProviders) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@super-one/cli",
3
- "version": "0.50.2-alpha",
3
+ "version": "0.50.4-alpha",
4
4
  "description": "SuperOne headless node CLI — remote execution environment (RPC, workspaces, sessions).",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",