@tryarcanist/cli 0.1.100 → 0.1.102

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 (2) hide show
  1. package/dist/index.js +49 -37
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -212,9 +212,6 @@ function getRuntimeOptions(command, options = {}) {
212
212
  function isJson(command, options = {}) {
213
213
  return getRuntimeOptions(command, options).json === true;
214
214
  }
215
- function isQuiet(command, options = {}) {
216
- return getRuntimeOptions(command, options).quiet === true;
217
- }
218
215
  function writeJson(value) {
219
216
  process.stdout.write(`${JSON.stringify(value)}
220
217
  `);
@@ -318,11 +315,6 @@ async function readHiddenPrompt(prompt) {
318
315
  stdin.on("error", onError);
319
316
  });
320
317
  }
321
- function printDeprecatedAlias(alias, replacement, command, options = {}) {
322
- if (isQuiet(command, options)) return;
323
- process.stderr.write(`Warning: \`arcanist ${alias}\` is deprecated; use \`arcanist ${replacement}\`.
324
- `);
325
- }
326
318
  function applyColorEnvironment(options) {
327
319
  if (options.noColor === true || !process.stdout.isTTY) {
328
320
  process.env.NO_COLOR = "1";
@@ -862,6 +854,22 @@ function noChangeOutcomeCopy(reason) {
862
854
  }
863
855
  }
864
856
 
857
+ // ../../shared/session/transient-disconnect.ts
858
+ var TRANSIENT_DISCONNECT_VISIBILITY_MS = 15e3;
859
+ function nextDisconnectMask(mask, previous, current, now) {
860
+ if (!current || current.sandboxSubstate !== "reconnecting") return null;
861
+ if (mask) return mask;
862
+ if (!previous || previous.sandboxSubstate === "reconnecting") return null;
863
+ return { since: now, heldPhase: previous.phase, heldSubstate: previous.sandboxSubstate ?? "none" };
864
+ }
865
+ function isDisconnectMaskActive(mask, now) {
866
+ return mask !== null && now - mask.since < TRANSIENT_DISCONNECT_VISIBILITY_MS;
867
+ }
868
+ function applyDisconnectMask(view, mask, now) {
869
+ if (!isDisconnectMaskActive(mask, now)) return view;
870
+ return { ...view, phase: mask.heldPhase, sandboxSubstate: mask.heldSubstate };
871
+ }
872
+
865
873
  // ../../shared/transcript/malformed-search.ts
866
874
  var MALFORMED_SEARCH_BLOCKED_TRANSCRIPT_PREFIX = "Arcanist blocked this malformed search command before execution.";
867
875
  var BASH_UNMATCHED_QUOTE_EOF_RE = /\/bin\/bash:\s+-c:\s+line\s+\d+:\s+unexpected EOF while looking for matching [`'"][`'"]?/i;
@@ -1244,6 +1252,24 @@ function projectRetryStatus(data, index) {
1244
1252
  ...typeof data?.retryAfterMs === "number" ? { retryAfterMs: data.retryAfterMs } : {}
1245
1253
  };
1246
1254
  }
1255
+ function projectPromptRetrying(data, index) {
1256
+ const attempt = typeof data?.attempt === "number" ? data.attempt : Number(data?.attempt ?? 0);
1257
+ const cap = typeof data?.cap === "number" ? data.cap : void 0;
1258
+ const retryPromptId = typeof data?.retryPromptId === "string" ? data.retryPromptId : resolvePromptId(data);
1259
+ return {
1260
+ type: "retry_status",
1261
+ // Key off retryPromptId (always present in the emitted payload, unique per
1262
+ // retry) rather than the index, so the id is stable across replays. The
1263
+ // event's `timestamp` lives at the top level, not inside `data`.
1264
+ id: `pr-retry-${retryPromptId ?? index}`,
1265
+ ...retryPromptId ? { promptId: retryPromptId } : {},
1266
+ attempt,
1267
+ message: "Sandbox dropped mid-task; retrying on a fresh sandbox",
1268
+ scope: "sandbox_disconnect",
1269
+ ...cap !== void 0 ? { maxAttempts: cap } : {},
1270
+ ...typeof data?.reason === "string" ? { reason: data.reason } : {}
1271
+ };
1272
+ }
1247
1273
  function projectBranchChanged(data, index) {
1248
1274
  return {
1249
1275
  type: "branch_changed",
@@ -1515,6 +1541,9 @@ function flattenSessionEvents(raw) {
1515
1541
  case "retry_status":
1516
1542
  pushEvent(state, projectRetryStatus(data, state.merged.length));
1517
1543
  break;
1544
+ case "prompt_retrying":
1545
+ pushEvent(state, projectPromptRetrying(data, state.merged.length));
1546
+ break;
1518
1547
  case "branch_changed":
1519
1548
  pushEvent(state, projectBranchChanged(data, state.merged.length));
1520
1549
  break;
@@ -2139,6 +2168,12 @@ function formatStatusLine(status) {
2139
2168
  if (status.spawnDurationMs != null) details.push(`spawn ${(status.spawnDurationMs / 1e3).toFixed(1)}s`);
2140
2169
  return details.length > 0 ? `[status] ${phaseLabel} | ${details.join(" | ")}` : `[status] ${phaseLabel}`;
2141
2170
  }
2171
+ function advanceStatusDisconnectMask(status, mask, lastView, now) {
2172
+ const view = status.phase ? { phase: status.phase, sandboxSubstate: status.sandboxSubstate } : null;
2173
+ const nextMask = nextDisconnectMask(mask, lastView, view, now);
2174
+ const displayStatus = view ? { ...status, ...applyDisconnectMask(view, nextMask, now) } : status;
2175
+ return { displayStatus, mask: nextMask, view };
2176
+ }
2142
2177
  async function printNoChangeOutcome(config, sessionId) {
2143
2178
  try {
2144
2179
  const data = await apiFetch(
@@ -2197,6 +2232,8 @@ async function watchCommand(sessionId, options, command) {
2197
2232
  let afterSequence = initialAfterSequence;
2198
2233
  let lastStatusLine = null;
2199
2234
  let textOpen = false;
2235
+ let disconnectMask = null;
2236
+ let lastStatusView = null;
2200
2237
  if (!json) console.log(`Watching session ${sessionId}...`);
2201
2238
  try {
2202
2239
  while (true) {
@@ -2208,7 +2245,10 @@ async function watchCommand(sessionId, options, command) {
2208
2245
  const parsed = parseSsePayload(payload);
2209
2246
  const receivedFullPage = parsed.events.length >= pageSize;
2210
2247
  if (!json && parsed.status) {
2211
- const nextStatusLine = formatStatusLine(parsed.status);
2248
+ const advanced = advanceStatusDisconnectMask(parsed.status, disconnectMask, lastStatusView, Date.now());
2249
+ disconnectMask = advanced.mask;
2250
+ lastStatusView = advanced.view;
2251
+ const nextStatusLine = formatStatusLine(advanced.displayStatus);
2212
2252
  if (nextStatusLine !== lastStatusLine) {
2213
2253
  if (textOpen) {
2214
2254
  process.stdout.write("\n");
@@ -2990,34 +3030,6 @@ Examples:
2990
3030
  `
2991
3031
  ).action((repo, name, options, command) => setTestCredentialCommand(repo, name, options, command));
2992
3032
  testCreds.command("delete").description("Delete a test credential").argument("<repo>", "Repository in 'owner/name' form").argument("<name>", "Credential name").requiredOption("--business <id>", "Business ID that owns the repo").option("--yes", "Confirm deletion without prompting").action((repo, name, options, command) => deleteTestCredentialCommand(repo, name, options, command));
2993
- program.command("login").description("Authenticate with a personal access token").option("--token-stdin", "Read token from stdin instead of interactive prompt").option("--api-url <url>", "Set custom API URL").action((options, command) => {
2994
- printDeprecatedAlias("login", "auth login", command);
2995
- return loginCommand(options, command);
2996
- });
2997
- addCreateOptions(program.command("create").description("Create a session and send a prompt")).action(
2998
- (repoUrl, prompt, options, command) => {
2999
- printDeprecatedAlias("create", "sessions create", command);
3000
- return createCommand(repoUrl, prompt, options, command);
3001
- }
3002
- );
3003
- addSendOptions(program.command("message").description("Send a message to an existing session")).action(
3004
- (sessionId, prompt, options, command) => {
3005
- printDeprecatedAlias("message", "sessions send", command);
3006
- return messageCommand(sessionId, prompt, options, command);
3007
- }
3008
- );
3009
- program.command("stop").description("Stop the active run for a session").argument("<session-id>", "Session ID").action((sessionId, options, command) => {
3010
- printDeprecatedAlias("stop", "sessions stop", command);
3011
- return stopCommand(sessionId, options, command);
3012
- });
3013
- program.command("transcript").description("Render a session transcript").argument("<session-id>", "Session ID").action((sessionId, options, command) => {
3014
- printDeprecatedAlias("transcript", "sessions transcript", command);
3015
- return transcriptCommand(sessionId, options, command);
3016
- });
3017
- program.command("watch").description("Watch session activity until it becomes idle").argument("<session-id>", "Session ID").option("--poll-interval <ms>", "Polling interval in milliseconds", String(DEFAULT_WATCH_POLL_INTERVAL_MS)).action((sessionId, options, command) => {
3018
- printDeprecatedAlias("watch", "sessions events --follow", command);
3019
- return watchCommand(sessionId, options, command);
3020
- });
3021
3033
  async function main() {
3022
3034
  try {
3023
3035
  await program.parseAsync(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.100",
3
+ "version": "0.1.102",
4
4
  "description": "CLI for Arcanist — create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {