@super-one/cli 0.69.0-alpha.2 → 0.70.0-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.69.0-alpha.2",
3
+ "version": "0.70.0-alpha",
4
4
  "kind": "npm",
5
5
  "minNodeMajor": 20,
6
- "builtAt": "2026-09-26T08:10:48.454Z"
6
+ "builtAt": "2026-09-29T20:49:23.769Z"
7
7
  }
package/README.md CHANGED
@@ -41,4 +41,4 @@ bun run pack:cli -- --dry-run # npm pack only
41
41
 
42
42
  - Local remote lab (host credentials, no Docker): [`docs/local-remote-lab.md`](./docs/local-remote-lab.md)
43
43
  - Docker SSH lab: [`docker/README.md`](./docker/README.md)
44
- - Design: `docs/design/remote-node-service.md` §15 (registry vs upload install)
44
+ - Design: `docs/architecture/remote-node-service.md` §15 (registry vs upload install)
package/lib/cli.mjs CHANGED
@@ -359,7 +359,7 @@ var init_interaction_memory = __esm({
359
359
  });
360
360
 
361
361
  // ../../packages/shared/src/superone-tool-descriptions.ts
362
- var MANUAL_READ_DESCRIPTION, SETUP_MINI_APP_DEV_DESCRIPTION, REGISTER_DEV_MINIAPP_DESCRIPTION, PACK_MINI_APP_DESCRIPTION, UPDATE_SUPERONE_TYPES_DESCRIPTION, RENAME_SESSION_DESCRIPTION, SESSION_TAG_DESCRIPTION, SESSION_TAG_LIST_DESCRIPTION, PROJECT_LIST_DESCRIPTION, SESSION_LIST_DESCRIPTION, SESSION_SEARCH_DESCRIPTION, SESSION_READ_DESCRIPTION, SESSION_TAGS_FILTER_DESCRIPTION, SESSION_TAG_MATCH_DESCRIPTION, SESSION_CLEANUP_DESCRIPTION, CONFIG_READ_DESCRIPTION, CONFIG_APPLY_DESCRIPTION, LIST_MEDIA_PROVIDERS_DESCRIPTION, GENERATE_IMAGE_DESCRIPTION, GENERATE_VIDEO_DESCRIPTION, VIDEO_STATUS_DESCRIPTION, SESSION_LIST_AGENTS_DESCRIPTION, SESSION_REQUEST_AGENTS_DESCRIPTION, LAUNCH_SUMMARY_DESCRIPTION, START_LAUNCH_ID_DESCRIPTION, LAUNCH_TASK_DESCRIPTION, LAUNCH_MODE_DESCRIPTION, LAUNCH_SESSION_ID_DESCRIPTION, LAUNCH_PERMISSION_MODE_DESCRIPTION, LAUNCH_CWD_DESCRIPTION, LAUNCH_WORKTREE_DESCRIPTION, LAUNCH_BRANCH_NAME_DESCRIPTION, SESSION_START_DESCRIPTION, SESSION_SEND_DESCRIPTION, SESSION_SEND_TO_DESCRIPTION, SESSION_SEND_CONTENT_DESCRIPTION, SESSION_RETRIEVE_DESCRIPTION, SESSION_RETRIEVE_FROM_DESCRIPTION, AUTOMATION_LIST_DESCRIPTION, AUTOMATION_APPLY_DESCRIPTION, AUTOMATION_DELETE_DESCRIPTION, TERMINAL_TABS_DESCRIPTION, TERMINAL_SNAPSHOT_DESCRIPTION, TERMINAL_ACT_DESCRIPTION, TERMINAL_WAIT_FOR_DESCRIPTION;
362
+ var MANUAL_READ_DESCRIPTION, SETUP_MINI_APP_DEV_DESCRIPTION, REGISTER_DEV_MINIAPP_DESCRIPTION, PACK_MINI_APP_DESCRIPTION, UPDATE_SUPERONE_TYPES_DESCRIPTION, MINIAPP_DEV_PREVIEW_DESCRIPTION, MINIAPP_DEV_RELOAD_DESCRIPTION, MINIAPP_DEV_PREVIEW_INPUT_SCHEMA, MINIAPP_DEV_RELOAD_INPUT_SCHEMA, RENAME_SESSION_DESCRIPTION, SESSION_TAG_DESCRIPTION, SESSION_TAG_LIST_DESCRIPTION, PROJECT_LIST_DESCRIPTION, SESSION_LIST_DESCRIPTION, SESSION_SEARCH_DESCRIPTION, SESSION_READ_DESCRIPTION, SESSION_TAGS_FILTER_DESCRIPTION, SESSION_TAG_MATCH_DESCRIPTION, SESSION_CLEANUP_DESCRIPTION, CONFIG_READ_DESCRIPTION, CONFIG_APPLY_DESCRIPTION, LIST_MEDIA_PROVIDERS_DESCRIPTION, GENERATE_IMAGE_DESCRIPTION, GENERATE_VIDEO_DESCRIPTION, VIDEO_STATUS_DESCRIPTION, SESSION_LIST_AGENTS_DESCRIPTION, SESSION_REQUEST_AGENTS_DESCRIPTION, LAUNCH_SUMMARY_DESCRIPTION, START_LAUNCH_ID_DESCRIPTION, LAUNCH_TASK_DESCRIPTION, LAUNCH_MODE_DESCRIPTION, LAUNCH_SESSION_ID_DESCRIPTION, LAUNCH_PERMISSION_MODE_DESCRIPTION, LAUNCH_CWD_DESCRIPTION, LAUNCH_WORKTREE_DESCRIPTION, LAUNCH_BRANCH_NAME_DESCRIPTION, SESSION_START_DESCRIPTION, SESSION_SEND_DESCRIPTION, SESSION_SEND_TO_DESCRIPTION, SESSION_SEND_CONTENT_DESCRIPTION, SESSION_RETRIEVE_DESCRIPTION, SESSION_RETRIEVE_FROM_DESCRIPTION, AUTOMATION_LIST_DESCRIPTION, AUTOMATION_APPLY_DESCRIPTION, AUTOMATION_DELETE_DESCRIPTION, TERMINAL_TABS_DESCRIPTION, TERMINAL_SNAPSHOT_DESCRIPTION, TERMINAL_ACT_DESCRIPTION, TERMINAL_WAIT_FOR_DESCRIPTION;
363
363
  var init_superone_tool_descriptions = __esm({
364
364
  "../../packages/shared/src/superone-tool-descriptions.ts"() {
365
365
  "use strict";
@@ -368,6 +368,30 @@ var init_superone_tool_descriptions = __esm({
368
368
  REGISTER_DEV_MINIAPP_DESCRIPTION = "Register an existing mini-app directory without modifying its source files. Reads manifest.json from the directory or dist, updates dev-registry.json in the variant-specific personal data root, and optionally writes a project- or user-scoped .s1-dev.json pointer.";
369
369
  PACK_MINI_APP_DESCRIPTION = "Package a mini-app directory into a .s1app file for distribution. The app directory must contain a valid manifest.json with a version field. Generates integrity checksums and creates a compressed archive.";
370
370
  UPDATE_SUPERONE_TYPES_DESCRIPTION = "Update the superone.d.ts type definitions in an existing mini-app project to the latest version. Use this when the mini-app needs access to newly added SuperOne APIs.";
371
+ MINIAPP_DEV_PREVIEW_DESCRIPTION = "Render a development mini-app tool's chat UI (intercept, result, or standalone template) from fixture input/result without running the tool. Returns a view id to pass as tab to browser_* tools for snapshots, clicks, screenshots, and console. Intercept submit/cancel and result close are logged as info console entries instead of executing. A new call replaces the app's previous preview. Workflow: read_manual miniapp/debugging.";
372
+ MINIAPP_DEV_RELOAD_DESCRIPTION = "Reload a development mini-app after editing it (build first if it has a build step): restarts its MiniApp Host so changed main code loads, refreshes manifest tools and templates, and reloads its open WebViews. Then inspect them with browser_* tools via miniapp: view ids.";
373
+ MINIAPP_DEV_PREVIEW_INPUT_SCHEMA = {
374
+ type: "object",
375
+ properties: {
376
+ appId: { type: "string", description: "Development mini-app id." },
377
+ tool: { type: "string", description: "Tool name from the manifest; it must declare a renderer." },
378
+ phase: { type: "string", enum: ["intercept", "result", "standalone"], description: "UI to render. Defaults to the result UI (standalone for standalone tools)." },
379
+ input: { type: "object", description: "Fixture tool input (intercept data and standalone args)." },
380
+ result: { description: "Fixture tool result for result and standalone UIs." },
381
+ running: { type: "boolean", description: "Standalone only: render the in-progress state (no result yet)." },
382
+ width: { type: "integer", minimum: 240, maximum: 1600, description: "Max width in px, to check narrow chat columns." }
383
+ },
384
+ required: ["appId", "tool"],
385
+ additionalProperties: false
386
+ };
387
+ MINIAPP_DEV_RELOAD_INPUT_SCHEMA = {
388
+ type: "object",
389
+ properties: {
390
+ appId: { type: "string", description: "Development mini-app id." }
391
+ },
392
+ required: ["appId"],
393
+ additionalProperties: false
394
+ };
371
395
  RENAME_SESSION_DESCRIPTION = "Rename the current chat session to a concise topic label shown in the sidebar. Always pass tags (set): 1\u20134 short kebab-case labels you choose so session_list/session_search can find this chat. Reuse names from session_tag_list when they fit; invent one when they don't. When the session fixes an issue, reviews a PR, or opens one, add a ref tag issue-N / pr-N on top of the labels. Top-level agent only \u2014 a Task/subagent worker does not own the user-facing title and must not call it.";
372
396
  SESSION_TAG_DESCRIPTION = "Tag SuperOne sessions so session_list/session_search can filter by tag. Default: current session. Pass sessionId for one other session, or sessionIds with add to tag many. Use add, remove, or set (exactly one). set: [] clears. Pick 1\u20134 short kebab-case labels; reuse names from session_tag_list when they fit, otherwise invent. Add pr-N as soon as the session opens a PR, and issue-N / pr-N when work turns out to target one. Only the top-level agent may call this; subagents must not. Not session_rename (titles) and not live collab.";
373
397
  SESSION_TAG_LIST_DESCRIPTION = "List session tags and counts. Default: current project; projectId or allProjects changes scope. kind: label (default) = topic labels to reuse; ref = issue-N / pr-N tracker references; all = both. Use query for a tag substring. Discover unknown label tags here before filtering session_list/session_search; reuse known tags, and a known ref tag (pr-456) needs no lookup. Filter with tagMatch any or all. Hidden sessions are omitted unless includeHidden.";
@@ -919,6 +943,16 @@ var init_host_action_setup_descriptors = __esm({
919
943
  ],
920
944
  "additionalProperties": false
921
945
  }
946
+ },
947
+ {
948
+ "name": "miniapp_dev_preview",
949
+ "description": MINIAPP_DEV_PREVIEW_DESCRIPTION,
950
+ "inputSchema": MINIAPP_DEV_PREVIEW_INPUT_SCHEMA
951
+ },
952
+ {
953
+ "name": "miniapp_dev_reload",
954
+ "description": MINIAPP_DEV_RELOAD_DESCRIPTION,
955
+ "inputSchema": MINIAPP_DEV_RELOAD_INPUT_SCHEMA
922
956
  }
923
957
  ];
924
958
  }
@@ -1517,7 +1551,7 @@ var init_host_action_browser_descriptors = __esm({
1517
1551
  "type": "object",
1518
1552
  "properties": {
1519
1553
  "tab": {
1520
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
1554
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
1521
1555
  "type": "string"
1522
1556
  }
1523
1557
  },
@@ -1531,7 +1565,7 @@ var init_host_action_browser_descriptors = __esm({
1531
1565
  "type": "object",
1532
1566
  "properties": {
1533
1567
  "tab": {
1534
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
1568
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
1535
1569
  "type": "string"
1536
1570
  },
1537
1571
  "description": {
@@ -1565,7 +1599,7 @@ var init_host_action_browser_descriptors = __esm({
1565
1599
  "type": "object",
1566
1600
  "properties": {
1567
1601
  "tab": {
1568
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
1602
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
1569
1603
  "type": "string"
1570
1604
  },
1571
1605
  "description": {
@@ -1660,7 +1694,7 @@ var init_host_action_browser_descriptors = __esm({
1660
1694
  "type": "object",
1661
1695
  "properties": {
1662
1696
  "tab": {
1663
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
1697
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
1664
1698
  "type": "string"
1665
1699
  },
1666
1700
  "description": {
@@ -1733,7 +1767,7 @@ var init_host_action_browser_descriptors = __esm({
1733
1767
  "type": "object",
1734
1768
  "properties": {
1735
1769
  "tab": {
1736
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
1770
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
1737
1771
  "type": "string"
1738
1772
  },
1739
1773
  "description": {
@@ -1773,7 +1807,7 @@ var init_host_action_browser_descriptors = __esm({
1773
1807
  "type": "object",
1774
1808
  "properties": {
1775
1809
  "tab": {
1776
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
1810
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
1777
1811
  "type": "string"
1778
1812
  },
1779
1813
  "description": {
@@ -1864,7 +1898,7 @@ var init_host_action_browser_descriptors = __esm({
1864
1898
  "type": "object",
1865
1899
  "properties": {
1866
1900
  "tab": {
1867
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
1901
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
1868
1902
  "type": "string"
1869
1903
  },
1870
1904
  "description": {
@@ -2055,7 +2089,7 @@ var init_host_action_browser_descriptors = __esm({
2055
2089
  "type": "object",
2056
2090
  "properties": {
2057
2091
  "tab": {
2058
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
2092
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
2059
2093
  "type": "string"
2060
2094
  },
2061
2095
  "description": {
@@ -4063,7 +4097,7 @@ var init_host_action_browser_perf_descriptors = __esm({
4063
4097
  "type": "object",
4064
4098
  "properties": {
4065
4099
  "tab": {
4066
- "description": "Browser view id. Omit to target the focused browser view (errors if multiple are open).",
4100
+ "description": "Browser view id, or a development mini-app view id: miniapp:<appId> for its panel, or one returned by miniapp_dev_preview or browser_tabs. Omit to target the focused browser view (errors if multiple are open).",
4067
4101
  "type": "string"
4068
4102
  },
4069
4103
  "description": {
@@ -7474,7 +7508,7 @@ var require_websocket = __commonJS({
7474
7508
  var http = __require("http");
7475
7509
  var net2 = __require("net");
7476
7510
  var tls = __require("tls");
7477
- var { randomBytes: randomBytes6, createHash: createHash12 } = __require("crypto");
7511
+ var { randomBytes: randomBytes6, createHash: createHash13 } = __require("crypto");
7478
7512
  var { Duplex, Readable: Readable4 } = __require("stream");
7479
7513
  var { URL: URL2 } = __require("url");
7480
7514
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -8142,7 +8176,7 @@ var require_websocket = __commonJS({
8142
8176
  abortHandshake(websocket, socket, "Invalid Upgrade header");
8143
8177
  return;
8144
8178
  }
8145
- const digest = createHash12("sha1").update(key + GUID).digest("base64");
8179
+ const digest = createHash13("sha1").update(key + GUID).digest("base64");
8146
8180
  if (res.headers["sec-websocket-accept"] !== digest) {
8147
8181
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
8148
8182
  return;
@@ -8511,7 +8545,7 @@ var require_websocket_server = __commonJS({
8511
8545
  var EventEmitter = __require("events");
8512
8546
  var http = __require("http");
8513
8547
  var { Duplex } = __require("stream");
8514
- var { createHash: createHash12 } = __require("crypto");
8548
+ var { createHash: createHash13 } = __require("crypto");
8515
8549
  var extension2 = require_extension();
8516
8550
  var PerMessageDeflate2 = require_permessage_deflate();
8517
8551
  var subprotocol2 = require_subprotocol();
@@ -8818,7 +8852,7 @@ var require_websocket_server = __commonJS({
8818
8852
  );
8819
8853
  }
8820
8854
  if (this._state > RUNNING) return abortHandshake(socket, 503);
8821
- const digest = createHash12("sha1").update(key + GUID).digest("base64");
8855
+ const digest = createHash13("sha1").update(key + GUID).digest("base64");
8822
8856
  const headers = [
8823
8857
  "HTTP/1.1 101 Switching Protocols",
8824
8858
  "Upgrade: websocket",
@@ -10801,6 +10835,115 @@ var init_app_server_client = __esm({
10801
10835
  }
10802
10836
  });
10803
10837
 
10838
+ // ../../packages/shared/src/subscription-usage.ts
10839
+ function sameUsageReset(a, b3) {
10840
+ return a === b3 || a != null && b3 != null && Math.abs(a - b3) * 1e3 <= USAGE_RESET_TOLERANCE_MS;
10841
+ }
10842
+ function usageRisk(window2, now = Date.now()) {
10843
+ const { forecast, resetsAt, usedPercent } = window2;
10844
+ if (resetsAt != null && resetsAt * 1e3 <= now) return "unknown";
10845
+ if (!forecast || now - forecast.sampledAt > USAGE_FRESH_MS || forecast.sampledAt > now + 6e4) return "unknown";
10846
+ if (usedPercent >= 100) return "exhausted";
10847
+ if (forecast.status !== "ready" || forecast.exhaustsAt == null || resetsAt == null) return "unknown";
10848
+ const untilReset = resetsAt * 1e3 - now;
10849
+ const untilEmpty = forecast.exhaustsAt - now;
10850
+ if (untilEmpty >= untilReset * 1.2) return "safe";
10851
+ if (untilEmpty >= untilReset * 0.8) return "watch";
10852
+ return untilEmpty <= 30 * 6e4 ? "critical" : "risk";
10853
+ }
10854
+ function forecastUsage(samples) {
10855
+ const last = samples.at(-1);
10856
+ const learning = { sampledAt: last?.at ?? 0, status: "learning", ratePerHour: null, exhaustsAt: null, confirmed: false };
10857
+ if (!last || samples.length < 4 || last.at - samples[0].at < 15 * 6e4) return learning;
10858
+ let weightedUsage = 0;
10859
+ let weightedHours = 0;
10860
+ let lastIncrease = samples[0].at;
10861
+ for (let i = 1; i < samples.length; i++) {
10862
+ const previous = samples[i - 1];
10863
+ const sample = samples[i];
10864
+ const delta = sample.usedPercent - previous.usedPercent;
10865
+ const hours = (sample.at - previous.at) / 36e5;
10866
+ if (hours <= 0 || delta < 0) return learning;
10867
+ if (delta > 0) lastIncrease = sample.at;
10868
+ const weight = Math.pow(0.5, (last.at - sample.at) / (20 * 6e4));
10869
+ weightedUsage += delta * weight;
10870
+ weightedHours += hours * weight;
10871
+ }
10872
+ if (last.at - lastIncrease >= 20 * 6e4) return { ...learning, status: "idle" };
10873
+ if (last.usedPercent - samples[0].usedPercent < 1 || weightedHours <= 0) return learning;
10874
+ const ratePerHour = weightedUsage / weightedHours;
10875
+ return {
10876
+ ...learning,
10877
+ status: "ready",
10878
+ ratePerHour,
10879
+ exhaustsAt: last.at + Math.max(0, 100 - last.usedPercent) / ratePerHour * 36e5
10880
+ };
10881
+ }
10882
+ var USAGE_POLL_MS, USAGE_FRESH_MS, USAGE_HISTORY_MS, USAGE_RESET_TOLERANCE_MS, SubscriptionUsageTracker;
10883
+ var init_subscription_usage = __esm({
10884
+ "../../packages/shared/src/subscription-usage.ts"() {
10885
+ "use strict";
10886
+ USAGE_POLL_MS = 5 * 6e4;
10887
+ USAGE_FRESH_MS = 10 * 6e4;
10888
+ USAGE_HISTORY_MS = 60 * 6e4;
10889
+ USAGE_RESET_TOLERANCE_MS = 6e4;
10890
+ SubscriptionUsageTracker = class {
10891
+ history = /* @__PURE__ */ new Map();
10892
+ observe(accountKey, window2, sampledAt) {
10893
+ const key = JSON.stringify([accountKey, window2.id ?? window2.label]);
10894
+ let entry = this.history.get(key);
10895
+ const last = entry?.samples.at(-1);
10896
+ if (!Number.isFinite(sampledAt) || !Number.isFinite(window2.usedPercent) || window2.usedPercent < 0 || window2.usedPercent > 100 || window2.resetsAt != null && !Number.isFinite(window2.resetsAt)) {
10897
+ this.history.delete(key);
10898
+ return { ...window2, forecast: { sampledAt, status: "learning", ratePerHour: null, exhaustsAt: null, confirmed: false } };
10899
+ }
10900
+ if (last && sampledAt <= last.at) return { ...window2, usedPercent: last.usedPercent, resetsAt: last.resetsAt, forecast: entry.forecast };
10901
+ const restarted = !last || !sameUsageReset(last.resetsAt, window2.resetsAt) || sampledAt - last.at > 15 * 6e4 || window2.usedPercent < last.usedPercent;
10902
+ if (restarted) entry = void 0;
10903
+ if (entry && last && sampledAt - last.at < 6e4) return { ...window2, forecast: window2.usedPercent === last.usedPercent ? entry.forecast : { sampledAt, status: "learning", ratePerHour: null, exhaustsAt: null, confirmed: false } };
10904
+ const samples = [...entry?.samples ?? [], { at: sampledAt, usedPercent: window2.usedPercent, resetsAt: window2.resetsAt }].filter((sample) => sampledAt - sample.at <= USAGE_HISTORY_MS).slice(-61);
10905
+ const forecast = forecastUsage(samples);
10906
+ const risk = usageRisk({ ...window2, forecast }, sampledAt);
10907
+ forecast.confirmed = risk !== "unknown" && entry?.risk === risk;
10908
+ this.history.delete(key);
10909
+ this.history.set(key, { samples, forecast, risk });
10910
+ for (const [id, value] of this.history) {
10911
+ if (sampledAt - value.forecast.sampledAt > USAGE_HISTORY_MS || this.history.size > 256) this.history.delete(id);
10912
+ }
10913
+ return { ...window2, forecast };
10914
+ }
10915
+ };
10916
+ }
10917
+ });
10918
+
10919
+ // ../../packages/codex/src/subscription-usage.ts
10920
+ import { createHash as createHash2 } from "node:crypto";
10921
+ function trackCodexSubscription(limits, account, scope) {
10922
+ const fetchedAt = Date.now();
10923
+ if (!account || typeof account.email !== "string") return { ...limits, fetchedAt };
10924
+ const quotaKey = `codex:${createHash2("sha256").update(JSON.stringify([
10925
+ scope,
10926
+ account.id ?? account.accountId ?? "",
10927
+ account.email,
10928
+ account.planType ?? limits.planType
10929
+ ])).digest("hex")}`;
10930
+ const track = (window2, slot) => {
10931
+ if (!window2) return null;
10932
+ const id = `${slot}:${window2.windowDurationMins ?? "unknown"}`;
10933
+ const observed = history.observe(quotaKey, { ...window2, id, label: id }, fetchedAt);
10934
+ return { ...window2, id, usedPercent: observed.usedPercent, resetsAt: observed.resetsAt, forecast: observed.forecast };
10935
+ };
10936
+ return { ...limits, quotaKey, fetchedAt, primary: track(limits.primary, "primary"), secondary: track(limits.secondary, "secondary") };
10937
+ }
10938
+ var history;
10939
+ var init_subscription_usage2 = __esm({
10940
+ "../../packages/codex/src/subscription-usage.ts"() {
10941
+ "use strict";
10942
+ init_subscription_usage();
10943
+ history = new SubscriptionUsageTracker();
10944
+ }
10945
+ });
10946
+
10804
10947
  // ../../packages/codex/src/codex-admin.ts
10805
10948
  import { randomUUID as randomUUID2 } from "node:crypto";
10806
10949
  function normalizeApiKey(value) {
@@ -11001,10 +11144,14 @@ function summarizeImportResults(raw) {
11001
11144
  }
11002
11145
  return { successCount, failureCount };
11003
11146
  }
11004
- async function readRateLimits(client3) {
11147
+ async function readRateLimits(client3, scope = "cli") {
11005
11148
  try {
11006
- const result = await client3.request("account/rateLimits/read");
11007
- return parseRateLimits(result);
11149
+ const [result, identity] = await Promise.all([
11150
+ client3.request("account/rateLimits/read"),
11151
+ client3.request("account/read", { refreshToken: false }).catch(() => null)
11152
+ ]);
11153
+ const limits = parseRateLimits(result);
11154
+ return limits ? trackCodexSubscription(limits, asRecord6(identity?.account), scope) : null;
11008
11155
  } catch (err) {
11009
11156
  throw safePublicError("account/rateLimits/read failed", err);
11010
11157
  }
@@ -11203,6 +11350,7 @@ var init_codex_admin = __esm({
11203
11350
  "../../packages/codex/src/codex-admin.ts"() {
11204
11351
  "use strict";
11205
11352
  init_app_server_client();
11353
+ init_subscription_usage2();
11206
11354
  }
11207
11355
  });
11208
11356
 
@@ -11359,24 +11507,53 @@ var init_account_manager = __esm({
11359
11507
  });
11360
11508
 
11361
11509
  // ../../packages/codex/src/fork-thread.ts
11510
+ async function resolveBeforeTurnId(request, threadId, drop) {
11511
+ let remaining = drop;
11512
+ let beforeTurnId;
11513
+ let cursor;
11514
+ const seenCursors = /* @__PURE__ */ new Set();
11515
+ do {
11516
+ const page2 = await request("thread/turns/list", {
11517
+ threadId,
11518
+ sortDirection: "desc",
11519
+ itemsView: "notLoaded",
11520
+ limit: Math.min(remaining, 100),
11521
+ ...cursor ? { cursor } : {}
11522
+ });
11523
+ const turns = Array.isArray(page2.data) ? page2.data : [];
11524
+ for (const turn of turns.slice(0, remaining)) {
11525
+ const id = turn?.id;
11526
+ if (typeof id !== "string" || !id) throw new Error("Codex fork boundary has no turn id");
11527
+ beforeTurnId = id;
11528
+ remaining -= 1;
11529
+ }
11530
+ cursor = typeof page2.nextCursor === "string" && page2.nextCursor ? page2.nextCursor : void 0;
11531
+ if (remaining > 0 && cursor) {
11532
+ if (!turns.length || seenCursors.has(cursor)) throw new Error("Codex fork boundary pagination did not advance");
11533
+ seenCursors.add(cursor);
11534
+ }
11535
+ } while (remaining > 0 && cursor);
11536
+ if (!beforeTurnId) throw new Error("Codex fork boundary could not be resolved from source history");
11537
+ return beforeTurnId;
11538
+ }
11362
11539
  async function forkCodexThread(input) {
11363
11540
  const threadId = input.threadId?.trim();
11364
11541
  if (!threadId) {
11365
11542
  throw new Error("Codex thread id is required to fork");
11366
11543
  }
11544
+ const drop = input.lastTurnId ? 0 : Math.max(0, input.dropTrailingTurns ?? 0);
11545
+ if (!Number.isSafeInteger(drop)) throw new Error("Codex trailing-turn count must be a finite integer");
11546
+ const beforeTurnId = drop > 0 ? await resolveBeforeTurnId(input.request, threadId, drop) : void 0;
11367
11547
  const forked = await input.request("thread/fork", {
11368
11548
  threadId,
11369
- ...input.lastTurnId ? { lastTurnId: input.lastTurnId } : {}
11549
+ ...input.lastTurnId ? { lastTurnId: input.lastTurnId } : {},
11550
+ ...beforeTurnId ? { beforeTurnId } : {}
11370
11551
  });
11371
11552
  const thread = forked.thread;
11372
11553
  const newThreadId = typeof thread?.id === "string" ? thread.id : null;
11373
11554
  if (!newThreadId) {
11374
11555
  throw new Error("Codex thread/fork did not return a thread id");
11375
11556
  }
11376
- const drop = input.lastTurnId ? 0 : Math.max(0, input.dropTrailingTurns ?? 0);
11377
- if (drop > 0) {
11378
- await input.request("thread/rollback", { threadId: newThreadId, numTurns: drop });
11379
- }
11380
11557
  return newThreadId;
11381
11558
  }
11382
11559
  var init_fork_thread = __esm({
@@ -11515,6 +11692,8 @@ var init_superone_host_owned_tools = __esm({
11515
11692
  "miniapp_dev_register",
11516
11693
  "miniapp_dev_pack",
11517
11694
  "miniapp_dev_update_types",
11695
+ "miniapp_dev_preview",
11696
+ "miniapp_dev_reload",
11518
11697
  "session_rename",
11519
11698
  "session_tag",
11520
11699
  "session_tag_list",
@@ -11862,7 +12041,7 @@ var init_harness_capabilities = __esm({
11862
12041
  displayName: "Cursor"
11863
12042
  },
11864
12043
  dsh: {
11865
- // In-process dsh Cordis tree (docs/draft/deepseek-harness-integration.md).
12044
+ // In-process dsh Cordis tree (docs/harness/dsh/deepseek-harness-integration.md).
11866
12045
  // Flags flip only when the corresponding event path is wired.
11867
12046
  // `supportsStreamingToolInput`: live `tool-call-delta` frames open the row
11868
12047
  // and stream its arguments before the durable `tool/call` completes it.
@@ -13405,6 +13584,9 @@ var init_claude_live_session = __esm({
13405
13584
  bridge = new MessageBridge();
13406
13585
  pending = [];
13407
13586
  active = null;
13587
+ ambient = null;
13588
+ backgroundTaskIds = /* @__PURE__ */ new Set();
13589
+ idleSystemMapper = null;
13408
13590
  sdkSessionId;
13409
13591
  closed = false;
13410
13592
  iterationDone;
@@ -13431,7 +13613,26 @@ var init_claude_live_session = __esm({
13431
13613
  return this.sdkSessionId;
13432
13614
  }
13433
13615
  get isBusy() {
13434
- return this.active != null;
13616
+ return this.active != null || this.ambient != null;
13617
+ }
13618
+ get hasActiveBackgroundTasks() {
13619
+ return this.backgroundTaskIds.size > 0;
13620
+ }
13621
+ trackBackgroundTasks(msg) {
13622
+ if (msg.type !== "system") return;
13623
+ const system = msg;
13624
+ if (system.subtype === "task_started" && system.task_id && system.ambient !== true) {
13625
+ this.backgroundTaskIds.add(system.task_id);
13626
+ } else if (system.subtype === "task_notification" && system.task_id) {
13627
+ this.backgroundTaskIds.delete(system.task_id);
13628
+ } else if (system.subtype === "task_updated" && system.task_id && (system.patch?.status === "completed" || system.patch?.status === "failed" || system.patch?.status === "killed")) {
13629
+ this.backgroundTaskIds.delete(system.task_id);
13630
+ } else if (system.subtype === "background_tasks_changed") {
13631
+ this.backgroundTaskIds.clear();
13632
+ for (const task of system.tasks ?? []) {
13633
+ if (task.task_id && task.ambient !== true) this.backgroundTaskIds.add(task.task_id);
13634
+ }
13635
+ }
13435
13636
  }
13436
13637
  /**
13437
13638
  * Send one user turn on the long-lived query.
@@ -13444,7 +13645,7 @@ var init_claude_live_session = __esm({
13444
13645
  }
13445
13646
  const tag = input.clientMessageId || randomUUID3();
13446
13647
  const sessionId = this.sdkSessionId || "";
13447
- const priorityNext = input.priorityNext !== false && this.active != null;
13648
+ const priorityNext = input.priorityNext !== false && this.isBusy;
13448
13649
  const msg = toUserMessage(input.content, sessionId, priorityNext);
13449
13650
  return new Promise((resolve17, reject) => {
13450
13651
  if (input.signal?.aborted) {
@@ -13466,7 +13667,7 @@ var init_claude_live_session = __esm({
13466
13667
  }
13467
13668
  };
13468
13669
  input.signal?.addEventListener("abort", onAbort, { once: true });
13469
- if (this.active) {
13670
+ if (this.isBusy) {
13470
13671
  this.pending.push({ tag, msg, input, resolve: resolve17, reject });
13471
13672
  return;
13472
13673
  }
@@ -13483,6 +13684,8 @@ var init_claude_live_session = __esm({
13483
13684
  this.active.reject(new Error("Claude live session disposed"));
13484
13685
  this.active = null;
13485
13686
  }
13687
+ this.ambient = null;
13688
+ this.backgroundTaskIds.clear();
13486
13689
  this.bridge.close();
13487
13690
  this.processAbort.abort();
13488
13691
  await this.iterationDone.catch(() => void 0);
@@ -13494,6 +13697,7 @@ var init_claude_live_session = __esm({
13494
13697
  this.planHandler = item.input.onPlan;
13495
13698
  this.active = {
13496
13699
  tag: item.tag,
13700
+ userUuid: item.msg.uuid ?? item.tag,
13497
13701
  messageId,
13498
13702
  input: item.input,
13499
13703
  resolve: item.resolve,
@@ -13509,7 +13713,7 @@ var init_claude_live_session = __esm({
13509
13713
  this.bridge.push(item.msg, item.tag);
13510
13714
  }
13511
13715
  flushPending() {
13512
- if (this.active || this.closed) return;
13716
+ if (this.isBusy || this.closed) return;
13513
13717
  const next = this.pending.shift();
13514
13718
  if (!next) return;
13515
13719
  this.startTurn(next);
@@ -13532,12 +13736,61 @@ var init_claude_live_session = __esm({
13532
13736
  }
13533
13737
  this.flushPending();
13534
13738
  }
13739
+ applyAmbientMessage(msg) {
13740
+ if (!this.ambient && ((msg.type === "assistant" || msg.type === "stream_event") && !msg.parent_tool_use_id)) {
13741
+ const messageId = `ambient-${randomUUID3()}`;
13742
+ this.opts.onAmbientEvent?.({
13743
+ type: "message_start",
13744
+ message: { id: messageId, role: "assistant", status: "streaming", content: [], createdAt: (/* @__PURE__ */ new Date()).toISOString(), providerId: "claude" }
13745
+ });
13746
+ this.opts.onAmbientEvent?.({ type: "status_change", status: "streaming" });
13747
+ this.ambient = {
13748
+ messageId,
13749
+ mapper: createClaudeAgentEventMapper({ messageId, emit: (event) => this.opts.onAmbientEvent?.(event) })
13750
+ };
13751
+ }
13752
+ if (!this.ambient) return;
13753
+ const applied = this.ambient.mapper.apply(msg);
13754
+ if (applied.sessionId) this.sdkSessionId = applied.sessionId;
13755
+ if (applied.isResult) {
13756
+ this.ambient = null;
13757
+ this.flushPending();
13758
+ }
13759
+ }
13760
+ failAmbient(error51) {
13761
+ const ambient = this.ambient;
13762
+ if (!ambient) return;
13763
+ this.ambient = null;
13764
+ this.opts.onAmbientEvent?.({ type: "message_error", messageId: ambient.messageId, error: error51 });
13765
+ }
13535
13766
  async iterate(q2) {
13536
13767
  try {
13537
13768
  for await (const msg of q2) {
13538
13769
  if (this.closed) break;
13770
+ this.trackBackgroundTasks(msg);
13539
13771
  const cur = this.active;
13540
- if (!cur) continue;
13772
+ if (!cur) {
13773
+ if (!this.ambient && msg.type === "system") {
13774
+ this.idleSystemMapper ??= createClaudeAgentEventMapper({
13775
+ messageId: "",
13776
+ emit: (event) => this.opts.onAmbientEvent?.(event)
13777
+ });
13778
+ this.idleSystemMapper.apply(msg);
13779
+ } else {
13780
+ this.applyAmbientMessage(msg);
13781
+ }
13782
+ continue;
13783
+ }
13784
+ const tagged = msg;
13785
+ const uuids = tagged.user_message_uuids ?? (tagged.user_message_uuid ? [tagged.user_message_uuid] : null);
13786
+ if (uuids && !uuids.includes(cur.userUuid) || this.ambient && !uuids) {
13787
+ this.applyAmbientMessage(msg);
13788
+ continue;
13789
+ }
13790
+ if (msg.type === "result") {
13791
+ const result = msg;
13792
+ if (!uuids && this.opts.sessionId && result.num_turns === 0 && result.is_error === false && !cur.sawResult && !cur.streamedText) continue;
13793
+ }
13541
13794
  if (cur.cancelled) {
13542
13795
  if (msg.type === "result") {
13543
13796
  this.active = null;
@@ -13593,6 +13846,7 @@ var init_claude_live_session = __esm({
13593
13846
  }
13594
13847
  }
13595
13848
  } catch (err) {
13849
+ this.failAmbient(err instanceof Error ? err.message : String(err));
13596
13850
  if (this.active) {
13597
13851
  if (!this.active.cancelled) {
13598
13852
  this.active.reject(err instanceof Error ? err : new Error(String(err)));
@@ -13603,6 +13857,12 @@ var init_claude_live_session = __esm({
13603
13857
  p3.reject(err instanceof Error ? err : new Error(String(err)));
13604
13858
  }
13605
13859
  } finally {
13860
+ if (!this.closed) {
13861
+ this.failAmbient("Claude SDK stream ended before the background turn completed");
13862
+ this.active?.reject(new Error("Claude SDK stream ended before the user turn completed"));
13863
+ this.active = null;
13864
+ for (const pending2 of this.pending.splice(0)) pending2.reject(new Error("Claude SDK stream ended before the queued turn started"));
13865
+ }
13606
13866
  this.closed = true;
13607
13867
  this.bridge.close();
13608
13868
  }
@@ -14986,12 +15246,12 @@ var init_host_wake = __esm({
14986
15246
  });
14987
15247
 
14988
15248
  // ../../packages/runtime/src/session/host-action-store.ts
14989
- import { createHash as createHash2, randomBytes as randomBytes2, randomUUID as randomUUID4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
15249
+ import { createHash as createHash3, randomBytes as randomBytes2, randomUUID as randomUUID4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
14990
15250
  function hashToken(token) {
14991
- return createHash2("sha256").update(token).digest("hex");
15251
+ return createHash3("sha256").update(token).digest("hex");
14992
15252
  }
14993
15253
  function payloadHash(outcome, result, error51) {
14994
- return createHash2("sha256").update(JSON.stringify({ outcome, result: result ?? null, error: error51 ?? null })).digest("hex");
15254
+ return createHash3("sha256").update(JSON.stringify({ outcome, result: result ?? null, error: error51 ?? null })).digest("hex");
14995
15255
  }
14996
15256
  function tokensEqual(a, b3) {
14997
15257
  const ba = Buffer.from(a, "utf8");
@@ -15904,6 +16164,7 @@ var init_session_runtime = __esm({
15904
16164
  deliveringArtifactNotifications = /* @__PURE__ */ new Map();
15905
16165
  /** In-flight runTurn count per session (for multi-turn live inject). */
15906
16166
  activeTurnCounts = /* @__PURE__ */ new Map();
16167
+ ambientTurns = /* @__PURE__ */ new Map();
15907
16168
  /**
15908
16169
  * Ephemeral system-prompt append (e.g. collaboration credential instructions).
15909
16170
  * Not durable in sessions table — reconstructed from grants on restart when needed.
@@ -16450,7 +16711,7 @@ var init_session_runtime = __esm({
16450
16711
  }
16451
16712
  /**
16452
16713
  * Deliver a host-built completion notification for finished artifact
16453
- * transfers (`docs/design/session-sync-zone.md` §4.1). Controller-bound like
16714
+ * transfers (`docs/architecture/session-sync-zone.md` §5.3). Controller-bound like
16454
16715
  * the Host Action channel, and idempotent by `notificationId` so a desktop
16455
16716
  * retry after a dropped ACK injects the turn once. The text is built on the
16456
16717
  * node from files it has confirmed — the desktop cannot inject arbitrary
@@ -16545,6 +16806,48 @@ var init_session_runtime = __esm({
16545
16806
  this.inFlightTurns.delete(turnPromise);
16546
16807
  });
16547
16808
  }
16809
+ handleAmbientEvent(sessionId, event) {
16810
+ const session = this.live.get(sessionId);
16811
+ if (!session || session.closed || this.disposing) return;
16812
+ const activeUsers = this.activeTurnCounts.get(sessionId) ?? 0;
16813
+ if (event.type === "status_change" && event.status === "idle" && activeUsers > 0) return;
16814
+ if (event.type === "message_start") {
16815
+ this.ambientTurns.set(sessionId, { messageId: event.message.id, text: "" });
16816
+ session.status = "streaming";
16817
+ if (activeUsers === 0) {
16818
+ this.events.appendSession({ sessionId, eventType: SESSION_DURABLE_EVENT.turnStarted, payload: { status: "streaming" } });
16819
+ }
16820
+ }
16821
+ const ambient = this.ambientTurns.get(sessionId);
16822
+ if (ambient && event.type === "content_delta" && event.messageId === ambient.messageId && event.delta.type === "text" && !event.delta.parentToolUseId) {
16823
+ ambient.text += event.delta.text;
16824
+ }
16825
+ this.events.appendSession({ sessionId, eventType: SESSION_DURABLE_EVENT.agentEvent, payload: { event } });
16826
+ if (ambient && event.type === "message_complete" && event.messageId === ambient.messageId) {
16827
+ const text2 = ambient.text || event.metadata?.resultText || "";
16828
+ session.transcript.push({ id: ambient.messageId, role: "assistant", text: text2, createdAt: Date.now() });
16829
+ this.events.appendSession({ sessionId, eventType: SESSION_DURABLE_EVENT.assistantMessage, payload: { blockId: ambient.messageId, text: text2 } });
16830
+ this.ambientTurns.delete(sessionId);
16831
+ if (activeUsers === 0) {
16832
+ session.status = "idle";
16833
+ this.events.appendSession({ sessionId, eventType: SESSION_DURABLE_EVENT.turnCompleted, payload: { status: "idle" } });
16834
+ this.cancelHostActionsForSession(sessionId, "turn_ended");
16835
+ }
16836
+ } else if (ambient && (event.type === "message_error" || event.type === "message_interrupted") && event.messageId === ambient.messageId) {
16837
+ this.ambientTurns.delete(sessionId);
16838
+ if (activeUsers === 0) {
16839
+ session.status = event.type === "message_error" ? "error" : "interrupted";
16840
+ this.events.appendSession({
16841
+ sessionId,
16842
+ eventType: event.type === "message_error" ? SESSION_DURABLE_EVENT.turnError : SESSION_DURABLE_EVENT.turnInterrupted,
16843
+ payload: event.type === "message_error" ? { message: event.error } : { reason: "ambient_interrupted" }
16844
+ });
16845
+ this.cancelHostActionsForSession(sessionId, "turn_ended");
16846
+ }
16847
+ }
16848
+ session.updatedAt = Date.now();
16849
+ this.persist(session);
16850
+ }
16548
16851
  async runTurn(session, opts, abort) {
16549
16852
  const assistantId = randomUUID5();
16550
16853
  let assistantText = "";
@@ -16593,6 +16896,7 @@ var init_session_runtime = __esm({
16593
16896
  causationRequestId: requestId
16594
16897
  });
16595
16898
  },
16899
+ onAmbientEvent: (event) => this.handleAmbientEvent(session.sessionId, event),
16596
16900
  onPermission: (interaction) => {
16597
16901
  if (permissionMode === "bypassPermissions" || permissionMode === "dontAsk" || permissionMode === "acceptEdits") {
16598
16902
  return Promise.resolve("allow");
@@ -16634,7 +16938,7 @@ var init_session_runtime = __esm({
16634
16938
  }
16635
16939
  const remainingPeers = Math.max(0, (this.activeTurnCounts.get(session.sessionId) ?? 1) - 1);
16636
16940
  const fifo = this.turnQueues.get(session.sessionId)?.length ?? 0;
16637
- if (remainingPeers > 0 || fifo > 0) {
16941
+ if (remainingPeers > 0 || fifo > 0 || this.ambientTurns.has(session.sessionId)) {
16638
16942
  session.status = "streaming";
16639
16943
  } else {
16640
16944
  session.status = "idle";
@@ -16671,7 +16975,7 @@ var init_session_runtime = __esm({
16671
16975
  const remainingAfter = Math.max(0, (this.activeTurnCounts.get(sid) ?? 1) - 1);
16672
16976
  if (remainingAfter <= 0) this.activeTurnCounts.delete(sid);
16673
16977
  else this.activeTurnCounts.set(sid, remainingAfter);
16674
- if (!session.closed && remainingAfter <= 0) {
16978
+ if (!session.closed && remainingAfter <= 0 && !this.ambientTurns.has(sid)) {
16675
16979
  this.cancelHostActionsForSession(sid, "turn_ended");
16676
16980
  }
16677
16981
  if (!session.closed) {
@@ -16710,6 +17014,7 @@ var init_session_runtime = __esm({
16710
17014
  const session = this.live.get(sessionId);
16711
17015
  if (!session) throw Object.assign(new Error("session not found"), { code: "not_found" });
16712
17016
  if (session.closed) return;
17017
+ this.ambientTurns.delete(sessionId);
16713
17018
  const aborts = this.aborts.get(sessionId);
16714
17019
  for (const abort of aborts ?? []) abort.abort();
16715
17020
  this.aborts.delete(sessionId);
@@ -22826,10 +23131,10 @@ var init_server = __esm({
22826
23131
  });
22827
23132
 
22828
23133
  // ../../packages/runtime/src/llm-proxy/manager.ts
22829
- import { createHash as createHash3 } from "node:crypto";
23134
+ import { createHash as createHash4 } from "node:crypto";
22830
23135
  import net from "node:net";
22831
23136
  function upstreamKey(u2) {
22832
- return createHash3("sha256").update(JSON.stringify(u2)).digest("hex").slice(0, 16);
23137
+ return createHash4("sha256").update(JSON.stringify(u2)).digest("hex").slice(0, 16);
22833
23138
  }
22834
23139
  async function getFreePort() {
22835
23140
  return new Promise((resolve17, reject) => {
@@ -33651,6 +33956,11 @@ function createNodeClaudeTurnRunner(opts) {
33651
33956
  } : void 0;
33652
33957
  const live = ClaudeLiveSession.open({
33653
33958
  cwd,
33959
+ onAmbientEvent: (event) => {
33960
+ const current = lives.get(sessionKey);
33961
+ if (current) current.lastActivityAt = Date.now();
33962
+ input.onAmbientEvent?.(event);
33963
+ },
33654
33964
  binaryPath: binary,
33655
33965
  sessionId: priorSession,
33656
33966
  model: input.model && input.model.trim() ? input.model.trim() : void 0,
@@ -33742,7 +34052,7 @@ function createNodeClaudeTurnRunner(opts) {
33742
34052
  runner.listActiveRuntimes = () => [...lives.entries()].map(([sessionId, entry]) => ({
33743
34053
  sessionId,
33744
34054
  lastActivityAt: entry.lastActivityAt,
33745
- busy: entry.busyCount > 0
34055
+ busy: entry.busyCount > 0 || entry.live.isBusy || entry.live.hasActiveBackgroundTasks
33746
34056
  }));
33747
34057
  return runner;
33748
34058
  }
@@ -64172,10 +64482,10 @@ var init_cursor_event_map = __esm({
64172
64482
  // ../../packages/cursor/src/cursor-store.ts
64173
64483
  import Database from "better-sqlite3";
64174
64484
  import { mkdirSync as mkdirSync11 } from "node:fs";
64175
- import { createHash as createHash4 } from "node:crypto";
64485
+ import { createHash as createHash5 } from "node:crypto";
64176
64486
  import { join as join23 } from "node:path";
64177
64487
  function workspaceHash(workspaceRef) {
64178
- return createHash4("md5").update(workspaceRef).digest("hex");
64488
+ return createHash5("md5").update(workspaceRef).digest("hex");
64179
64489
  }
64180
64490
  function page(items, limit, cursor, encode3, decode3, after) {
64181
64491
  let sorted = items;
@@ -66247,7 +66557,7 @@ var init_codex_admin_service = __esm({
66247
66557
  const auth = this.getProjectAuth(projectId);
66248
66558
  if (resolveMode(auth.mode, auth.apiKey) !== "chatgpt") return null;
66249
66559
  try {
66250
- return await this.withClient(projectId, apiProviderId, (client3) => readRateLimits(client3));
66560
+ return await this.withClient(projectId, apiProviderId, (client3) => readRateLimits(client3, apiProviderId ?? "cli"));
66251
66561
  } catch {
66252
66562
  return null;
66253
66563
  }
@@ -73443,8 +73753,8 @@ import { fileURLToPath } from "node:url";
73443
73753
  function resolveCliReleaseVersion() {
73444
73754
  const fromEnv = process.env.SUPERONE_CLI_VERSION?.trim();
73445
73755
  if (fromEnv) return fromEnv;
73446
- if ("0.69.0-alpha.2".trim()) {
73447
- return "0.69.0-alpha.2".trim();
73756
+ if ("0.70.0-alpha".trim()) {
73757
+ return "0.70.0-alpha".trim();
73448
73758
  }
73449
73759
  const fromDist = readDistManifestVersion();
73450
73760
  if (fromDist) return fromDist;
@@ -80630,7 +80940,7 @@ import {
80630
80940
  statSync as statSync8,
80631
80941
  writeFileSync as writeFileSync12
80632
80942
  } from "node:fs";
80633
- import { createHash as createHash5, randomBytes as randomBytes4 } from "node:crypto";
80943
+ import { createHash as createHash6, randomBytes as randomBytes4 } from "node:crypto";
80634
80944
  import { dirname as dirname13, join as join28, relative, resolve as resolve7, sep as sep3 } from "node:path";
80635
80945
  import { arch as osArch, platform as osPlatform } from "node:os";
80636
80946
  var releaseVersionProvider = null;
@@ -80797,7 +81107,7 @@ function selectArtifactPin(pin, platform2 = currentHostPlatform(), arch2 = curre
80797
81107
  }
80798
81108
  async function sha256File(path) {
80799
81109
  return new Promise((resolveHash, reject) => {
80800
- const hash2 = createHash5("sha256");
81110
+ const hash2 = createHash6("sha256");
80801
81111
  const stream = createReadStream(path);
80802
81112
  stream.on("data", (chunk) => hash2.update(chunk));
80803
81113
  stream.on("error", reject);
@@ -81038,8 +81348,8 @@ function requiredRuntimeVersion(harnessId, manifest) {
81038
81348
  import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync17, readdirSync as readdirSync11, statSync as statSync9, writeFileSync as writeFileSync13 } from "node:fs";
81039
81349
  import { arch as osArch2, platform as osPlatform2 } from "node:os";
81040
81350
  import { join as join29, resolve as resolve8 } from "node:path";
81041
- var OFFICIAL_CLAUDE_SDK_VERSION = "0.3.280";
81042
- var OFFICIAL_CODEX_NPM_VERSION = "0.155.1";
81351
+ var OFFICIAL_CLAUDE_SDK_VERSION = "0.3.285";
81352
+ var OFFICIAL_CODEX_NPM_VERSION = "0.159.0";
81043
81353
  var OFFICIAL_CODEX_PACKAGE = "@openai/codex";
81044
81354
  function codexPlatformPackageVersion(baseVersion = OFFICIAL_CODEX_NPM_VERSION) {
81045
81355
  const platform2 = process.platform;
@@ -81235,7 +81545,7 @@ async function fetchTarballWithFallback(opts) {
81235
81545
  }
81236
81546
 
81237
81547
  // ../../packages/runtime/src/harness/resumable-download.ts
81238
- import { createHash as createHash6 } from "node:crypto";
81548
+ import { createHash as createHash7 } from "node:crypto";
81239
81549
  import {
81240
81550
  appendFileSync,
81241
81551
  createReadStream as createReadStream2,
@@ -81273,8 +81583,8 @@ function parseContentRange(header) {
81273
81583
  };
81274
81584
  }
81275
81585
  async function seedHashesFromFile(path) {
81276
- const sha256 = createHash6("sha256");
81277
- const sha512 = createHash6("sha512");
81586
+ const sha256 = createHash7("sha256");
81587
+ const sha512 = createHash7("sha512");
81278
81588
  const size = statSync10(path).size;
81279
81589
  if (size === 0) return { sha256, sha512, size };
81280
81590
  await new Promise((resolve17, reject) => {
@@ -81324,8 +81634,8 @@ async function streamResponseToFile(res, destPath, onProgress, opts = {}) {
81324
81634
  received = resumeFrom;
81325
81635
  emit?.(received, total || received);
81326
81636
  } else {
81327
- sha256 = createHash6("sha256");
81328
- sha512 = createHash6("sha512");
81637
+ sha256 = createHash7("sha256");
81638
+ sha512 = createHash7("sha512");
81329
81639
  received = 0;
81330
81640
  }
81331
81641
  if (!res.body) {
@@ -85640,7 +85950,7 @@ var NodeTerminalManager = class {
85640
85950
  // ../../packages/runtime/src/workspace/project-registry.ts
85641
85951
  import { basename as basename2, resolve as resolve11 } from "node:path";
85642
85952
  import { existsSync as existsSync36, realpathSync as realpathSync4, statSync as statSync13 } from "node:fs";
85643
- import { createHash as createHash7 } from "node:crypto";
85953
+ import { createHash as createHash8 } from "node:crypto";
85644
85954
  import { execFileSync as execFileSync2 } from "node:child_process";
85645
85955
 
85646
85956
  // ../../packages/shared/src/project-extra-dirs.ts
@@ -85730,7 +86040,7 @@ var ProjectRegistry = class {
85730
86040
  this.db.prepare(`UPDATE projects SET last_active_at = ?, name = COALESCE(?, name) WHERE project_id = ?`).run(now, name ?? null, existing.projectId);
85731
86041
  return this.get(existing.projectId);
85732
86042
  }
85733
- const projectId = createHash7("sha256").update(abs).digest("hex").slice(0, 32);
86043
+ const projectId = createHash8("sha256").update(abs).digest("hex").slice(0, 32);
85734
86044
  const repoIdentity = detectRepoIdentity(abs);
85735
86045
  this.db.prepare(
85736
86046
  `INSERT INTO projects (project_id, path, name, repo_identity, opened_at, last_active_at)
@@ -85844,7 +86154,7 @@ import {
85844
86154
  writeFileSync as writeFileSync16
85845
86155
  } from "node:fs";
85846
86156
  import { dirname as dirname16, join as join31, relative as relative2 } from "node:path";
85847
- import { createHash as createHash8 } from "node:crypto";
86157
+ import { createHash as createHash9 } from "node:crypto";
85848
86158
  function normalizeRel(path) {
85849
86159
  return path.replace(/\\/g, "/").replace(/\/+$/, "") || ".";
85850
86160
  }
@@ -85951,7 +86261,7 @@ var WorkspaceFsService = class {
85951
86261
  const slice = Buffer.alloc(toRead);
85952
86262
  if (toRead > 0) readSync(fd, slice, 0, toRead, offset);
85953
86263
  const content = slice.toString("base64");
85954
- const hash2 = createHash8("sha256").update(slice).digest("hex");
86264
+ const hash2 = createHash9("sha256").update(slice).digest("hex");
85955
86265
  this.projects.touch(projectId);
85956
86266
  return { content, hash: hash2, encoding: "base64" };
85957
86267
  } finally {
@@ -86007,7 +86317,7 @@ var WorkspaceFsService = class {
86007
86317
  }
86008
86318
  }
86009
86319
  }
86010
- const hash2 = createHash8("sha256").update(data).digest("hex");
86320
+ const hash2 = createHash9("sha256").update(data).digest("hex");
86011
86321
  this.projects.touch(projectId);
86012
86322
  return { hash: hash2 };
86013
86323
  }
@@ -86195,7 +86505,7 @@ var WorkspaceFsService = class {
86195
86505
  function hashFileBounded(absolutePath, size) {
86196
86506
  const fd = openSync(absolutePath, "r");
86197
86507
  try {
86198
- const hash2 = createHash8("sha256");
86508
+ const hash2 = createHash9("sha256");
86199
86509
  const buf = Buffer.alloc(Math.min(64 * 1024, Math.max(1, size)));
86200
86510
  let offset = 0;
86201
86511
  while (offset < size) {
@@ -88583,7 +88893,7 @@ var WorkspaceTailWatchService = class {
88583
88893
  };
88584
88894
 
88585
88895
  // src/auth/idempotency.ts
88586
- import { createHash as createHash9 } from "node:crypto";
88896
+ import { createHash as createHash10 } from "node:crypto";
88587
88897
  var IdempotencyService = class {
88588
88898
  constructor(db) {
88589
88899
  this.db = db;
@@ -88591,7 +88901,7 @@ var IdempotencyService = class {
88591
88901
  db;
88592
88902
  inflight = /* @__PURE__ */ new Map();
88593
88903
  payloadHash(payload) {
88594
- return createHash9("sha256").update(JSON.stringify(payload ?? null)).digest("hex");
88904
+ return createHash10("sha256").update(JSON.stringify(payload ?? null)).digest("hex");
88595
88905
  }
88596
88906
  key(clientIdentity, operation, idempotencyKey) {
88597
88907
  return `${clientIdentity}\0${operation}\0${idempotencyKey}`;
@@ -92568,7 +92878,7 @@ init_interaction_memory();
92568
92878
  // ../../packages/runtime/src/fs/interaction-memory.ts
92569
92879
  init_superone_home();
92570
92880
  init_interaction_memory();
92571
- import { createHash as createHash10, randomUUID as randomUUID14 } from "node:crypto";
92881
+ import { createHash as createHash11, randomUUID as randomUUID14 } from "node:crypto";
92572
92882
  import { lstat, mkdir, open, readdir, rename, rm } from "node:fs/promises";
92573
92883
  import { constants as constants4 } from "node:fs";
92574
92884
  import { join as join34 } from "node:path";
@@ -92822,7 +93132,7 @@ var InteractionMemoryStore = class _InteractionMemoryStore {
92822
93132
  await file2.close();
92823
93133
  }
92824
93134
  const { meta: meta3, content } = parseNote(raw, { title: topic2, resource: target.resource });
92825
- return { ...meta3, topic: topic2, content, revision: createHash10("sha256").update(raw).digest("hex") };
93135
+ return { ...meta3, topic: topic2, content, revision: createHash11("sha256").update(raw).digest("hex") };
92826
93136
  } catch (err) {
92827
93137
  if (missing(err)) return null;
92828
93138
  throw new Error(`Cannot read personal memory ${target.label}/${topic2}: ${err instanceof Error ? err.message : String(err)}`);
@@ -92915,7 +93225,7 @@ var InteractionMemoryStore = class _InteractionMemoryStore {
92915
93225
  saved: true,
92916
93226
  created: !existing,
92917
93227
  ...target.identity,
92918
- ...summary({ ...meta3, topic: args.topic, content, revision: createHash10("sha256").update(raw).digest("hex") })
93228
+ ...summary({ ...meta3, topic: args.topic, content, revision: createHash11("sha256").update(raw).digest("hex") })
92919
93229
  };
92920
93230
  } finally {
92921
93231
  await rm(lock, { recursive: true, force: true });
@@ -102655,7 +102965,7 @@ ON CONFLICT(id) DO UPDATE SET
102655
102965
 
102656
102966
  // src/workspace/artifact-zone.ts
102657
102967
  init_environment();
102658
- import { createHash as createHash11 } from "node:crypto";
102968
+ import { createHash as createHash12 } from "node:crypto";
102659
102969
  import {
102660
102970
  closeSync as closeSync3,
102661
102971
  fstatSync as fstatSync3,
@@ -102977,7 +103287,7 @@ var ArtifactZoneService = class {
102977
103287
  written: 0,
102978
103288
  total: req.total,
102979
103289
  sha256: req.sha256,
102980
- hash: createHash11("sha256"),
103290
+ hash: createHash12("sha256"),
102981
103291
  lastActivityAt: Date.now()
102982
103292
  };
102983
103293
  this.transfers.set(transferId, transfer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@super-one/cli",
3
- "version": "0.69.0-alpha.2",
3
+ "version": "0.70.0-alpha",
4
4
  "description": "SuperOne headless node CLI — remote execution environment (RPC, workspaces, sessions).",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -25,20 +25,20 @@
25
25
  "directory": "apps/cli"
26
26
  },
27
27
  "dependencies": {
28
- "@anthropic-ai/claude-agent-sdk": "0.3.280",
28
+ "@anthropic-ai/claude-agent-sdk": "0.3.285",
29
29
  "@cursor/sdk": "1.0.30",
30
30
  "better-sqlite3": "^13.0.1",
31
31
  "node-pty": "^1.0.0"
32
32
  },
33
33
  "optionalDependencies": {
34
- "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.280",
35
- "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.280",
36
- "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.280",
37
- "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.280",
38
- "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.280",
39
- "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.280",
40
- "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.280",
41
- "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.280",
34
+ "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.285",
35
+ "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.285",
36
+ "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.285",
37
+ "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.285",
38
+ "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.285",
39
+ "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.285",
40
+ "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.285",
41
+ "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.285",
42
42
  "@cursor/sdk-darwin-arm64": "1.0.30",
43
43
  "@cursor/sdk-darwin-x64": "1.0.30",
44
44
  "@cursor/sdk-linux-arm64": "1.0.30",