@standardagents/code 0.3.1 → 0.4.0

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/dist/index.js CHANGED
@@ -1988,6 +1988,9 @@ var Tui = class _Tui {
1988
1988
  workingStart = 0;
1989
1989
  spinnerTimer = null;
1990
1990
  bgCount = 0;
1991
+ // The `[⚙ n bg]` prompt badge can be selected with ← from the start of the
1992
+ // input (rendered inverted); Enter then opens the background-process panel.
1993
+ bgBadgeSelected = false;
1991
1994
  queuedCount = 0;
1992
1995
  subagents = [];
1993
1996
  // active subagents (one line each)
@@ -2069,6 +2072,9 @@ var Tui = class _Tui {
2069
2072
  /** Up on the top row: return true to consume it (e.g. pull a queued message)
2070
2073
  * before history recall gets a chance. */
2071
2074
  onUpArrow = () => false;
2075
+ /** Enter while the `[⚙ n bg]` badge is selected — opens the bg process panel. */
2076
+ onBgBadge = () => {
2077
+ };
2072
2078
  onQuit = () => process.exit(0);
2073
2079
  levelListeners = [];
2074
2080
  get colors() {
@@ -2146,6 +2152,21 @@ var Tui = class _Tui {
2146
2152
  return;
2147
2153
  }
2148
2154
  if (!key) return;
2155
+ if (this.bgBadgeSelected) {
2156
+ if (key.name === "return" || key.name === "enter") {
2157
+ this.bgBadgeSelected = false;
2158
+ this.renderBottom();
2159
+ this.onBgBadge();
2160
+ return;
2161
+ }
2162
+ if (key.name === "left") return;
2163
+ this.bgBadgeSelected = false;
2164
+ if (key.name === "right" || key.name === "escape") {
2165
+ this.renderBottom();
2166
+ return;
2167
+ }
2168
+ this.renderBottom();
2169
+ }
2149
2170
  if (this.paletteOpen()) {
2150
2171
  const matches = this.filteredCommands();
2151
2172
  const cur = matches.length ? Math.min(this.slashIdx, matches.length - 1) : 0;
@@ -2196,6 +2217,9 @@ var Tui = class _Tui {
2196
2217
  if (this.cursorPos > 0) {
2197
2218
  this.cursorPos--;
2198
2219
  this.renderBottom();
2220
+ } else if (this.bgCount > 0) {
2221
+ this.bgBadgeSelected = true;
2222
+ this.renderBottom();
2199
2223
  }
2200
2224
  return;
2201
2225
  }
@@ -2570,7 +2594,8 @@ var Tui = class _Tui {
2570
2594
  /** The prompt line prefix (with ANSI colour) that precedes the typed text. */
2571
2595
  promptPrefix() {
2572
2596
  const q = this.queuedCount > 0 ? `${C.yellow}[\u23F3 ${this.queuedCount} queued]${C.reset} ` : "";
2573
- const bg = this.bgCount > 0 ? `${C.cyan}[\u2699 ${this.bgCount} bg]${C.reset} ` : "";
2597
+ const bgText = `[\u2699 ${this.bgCount} bg]`;
2598
+ const bg = this.bgCount > 0 ? this.bgBadgeSelected ? `${C.cyan}\x1B[7m${bgText}\x1B[27m${C.reset} ` : `${C.cyan}${bgText}${C.reset} ` : "";
2574
2599
  return `${q}${bg}${this.levelColor()}\u276F${C.reset} `;
2575
2600
  }
2576
2601
  visibleWidth(s) {
@@ -3003,6 +3028,7 @@ var Tui = class _Tui {
3003
3028
  }
3004
3029
  setBackgroundCount(n) {
3005
3030
  this.bgCount = n;
3031
+ if (n === 0) this.bgBadgeSelected = false;
3006
3032
  this.renderBottom();
3007
3033
  }
3008
3034
  setQueuedCount(n) {
@@ -3047,6 +3073,7 @@ var Tui = class _Tui {
3047
3073
  }
3048
3074
  // ─── takeover helpers (approval / menus) ───────────────────────────────────
3049
3075
  beginTakeover() {
3076
+ this.bgBadgeSelected = false;
3050
3077
  this.clearBottom();
3051
3078
  process.stdout.write("\r\x1B[K");
3052
3079
  process.stdout.write("\x1B[?25l");
@@ -3839,6 +3866,16 @@ function saveCredential(cred, options = {}) {
3839
3866
  } catch {
3840
3867
  }
3841
3868
  }
3869
+ function deleteCredential(endpoint) {
3870
+ const creds = loadCredentials();
3871
+ delete creds.instances[normalizeEndpoint(endpoint)];
3872
+ fs4.mkdirSync(DIR, { recursive: true });
3873
+ fs4.writeFileSync(FILE, JSON.stringify(creds, null, 2), { mode: 384 });
3874
+ try {
3875
+ fs4.chmodSync(FILE, 384);
3876
+ } catch {
3877
+ }
3878
+ }
3842
3879
  function defaultEndpoint() {
3843
3880
  return loadCredentials().default_endpoint ?? null;
3844
3881
  }
@@ -4230,7 +4267,12 @@ ${c.dim}Press Control-C again to exit${c.reset}
4230
4267
  } else {
4231
4268
  threadId = await api.createThread(AGENT_ID, tags);
4232
4269
  }
4233
- await runInteractive(tui, api, threadId, projectDir, machine, resumed, historySeed);
4270
+ for (; ; ) {
4271
+ await runInteractive(tui, api, threadId, projectDir, machine, resumed, historySeed);
4272
+ historySeed = threadId;
4273
+ threadId = await api.createThread(AGENT_ID, tags);
4274
+ resumed = false;
4275
+ }
4234
4276
  }
4235
4277
  async function summarizeThreads(api, threads) {
4236
4278
  return Promise.all(
@@ -4502,27 +4544,30 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
4502
4544
  if (activeSubagents.size > 0) scheduleReconcile();
4503
4545
  }, 5e3);
4504
4546
  heartbeatPoll.unref();
4547
+ let endSession;
4548
+ const sessionEnded = new Promise((r) => endSession = r);
4505
4549
  const quit = async () => {
4506
4550
  tui.end();
4507
- const stopped = api.stop(threadId).catch(() => {
4551
+ const stopped2 = api.stop(threadId).catch(() => {
4508
4552
  });
4509
- const procsStopped = host.stopAllLocalProcesses().catch(() => 0);
4553
+ const procsStopped2 = host.stopAllLocalProcesses().catch(() => 0);
4510
4554
  bridge.close();
4511
4555
  stream.close();
4512
4556
  events.close();
4513
4557
  mcp.closeAll();
4514
- const [, killed] = await Promise.race([
4515
- Promise.all([stopped, procsStopped]),
4558
+ const [, killed2] = await Promise.race([
4559
+ Promise.all([stopped2, procsStopped2]),
4516
4560
  new Promise((r) => setTimeout(() => r([void 0, 0]), 1500))
4517
4561
  ]);
4518
- farewell(killed);
4562
+ farewell(killed2);
4519
4563
  process.exit(0);
4520
4564
  };
4521
4565
  tui.setQuitHandler(quit);
4522
- const viewThread = () => {
4523
- const url = `${api.origin}/threads/${threadId}`;
4524
- openUrl(url);
4525
- tui.print(`${c.gray}opened ${c.cyan}${url}${c.reset}`);
4566
+ const logout = async () => {
4567
+ deleteCredential(api.origin);
4568
+ const instanceHost = api.origin.replace(/^https?:\/\//, "");
4569
+ tui.print(`${c.gray}Signed out \u2014 removed the saved token for ${c.teal}${instanceHost}${c.reset}${c.gray}. Run standardcode to sign in again.${c.reset}`);
4570
+ await quit();
4526
4571
  };
4527
4572
  const bgMgr = {
4528
4573
  list: () => registry.list(),
@@ -4612,6 +4657,12 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
4612
4657
  }
4613
4658
  };
4614
4659
  tui.setCommands([
4660
+ {
4661
+ name: "clear",
4662
+ label: "Clear conversation",
4663
+ hint: "start a fresh session",
4664
+ run: () => endSession()
4665
+ },
4615
4666
  {
4616
4667
  name: "compact",
4617
4668
  label: "Compact conversation now",
@@ -4644,8 +4695,8 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
4644
4695
  run: () => runSkillsMenu(tui, skillsCtl)
4645
4696
  },
4646
4697
  { name: "background", label: "Background processes", hint: "list / stop", run: () => runProcessMenu(tui, bgMgr) },
4647
- { name: "view", label: "View thread in AgentBuilder", run: () => viewThread() },
4648
4698
  { name: "keybindings", label: "Keyboard shortcuts", run: () => showKeybindings(tui) },
4699
+ { name: "logout", label: "Sign out", hint: "delete the saved token & quit", run: () => logout() },
4649
4700
  { name: "quit", label: "Quit", run: () => quit() }
4650
4701
  ]);
4651
4702
  const history = await loadHistory(api, threadId, historySeedThreadId);
@@ -4684,6 +4735,10 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
4684
4735
  });
4685
4736
  }
4686
4737
  };
4738
+ tui.onBgBadge = () => {
4739
+ void runProcessMenu(tui, bgMgr).catch(() => {
4740
+ });
4741
+ };
4687
4742
  tui.onUpArrow = () => {
4688
4743
  if (tui.getInput().trim() || queued.length === 0) return false;
4689
4744
  const q = queued.pop();
@@ -4783,18 +4838,45 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
4783
4838
  } catch {
4784
4839
  }
4785
4840
  const COMPACTION_TRIGGER_FRACTION = 0.5;
4841
+ const COMPACTION_TRIGGER_CAP = 5e4;
4786
4842
  try {
4787
4843
  const cu = await api.kvGet(threadId, "context_usage");
4788
4844
  const used = Number(cu?.inputTokens) || 0;
4789
- const max = (Number(cu?.maxContextTokens) || 0) * COMPACTION_TRIGGER_FRACTION;
4845
+ const max = Math.min(
4846
+ (Number(cu?.maxContextTokens) || 0) * COMPACTION_TRIGGER_FRACTION || Infinity,
4847
+ COMPACTION_TRIGGER_CAP
4848
+ );
4790
4849
  tui.setContextPct(max > 0 && used > 0 ? used / max * 100 : null);
4791
4850
  } catch {
4792
4851
  }
4793
4852
  };
4794
- setInterval(() => void poll().catch(() => {
4853
+ const pollTimer = setInterval(() => void poll().catch(() => {
4795
4854
  }), 1200);
4796
- await new Promise(() => {
4855
+ await sessionEnded;
4856
+ clearInterval(pollTimer);
4857
+ clearInterval(heartbeatPoll);
4858
+ const stopped = api.stop(threadId).catch(() => {
4797
4859
  });
4860
+ const procsStopped = host.stopAllLocalProcesses().catch(() => 0);
4861
+ bridge.close();
4862
+ stream.close();
4863
+ events.close();
4864
+ mcp.closeAll();
4865
+ const [, killed] = await Promise.race([
4866
+ Promise.all([stopped, procsStopped]),
4867
+ new Promise((r) => setTimeout(() => r([void 0, 0]), 1500))
4868
+ ]);
4869
+ tui.setWorking(false);
4870
+ tui.setSubagents([]);
4871
+ tui.setGoal(null);
4872
+ tui.setQueuedCount(0);
4873
+ tui.setContextPct(null);
4874
+ tui.setStep(null, 0);
4875
+ tui.setBackgroundCount(0);
4876
+ if (killed > 0) {
4877
+ tui.print(`${c.cyan}\u2699${c.reset} Stopped ${killed} background process${killed === 1 ? "" : "es"}.`);
4878
+ }
4879
+ tui.print(`${c.dim}\u2500\u2500 conversation cleared \u2014 starting a fresh session \u2500\u2500${c.reset}`);
4798
4880
  }
4799
4881
  async function runSkillsMenu(tui, skills) {
4800
4882
  let list;
@@ -4866,6 +4948,7 @@ function showKeybindings(tui) {
4866
4948
  tui.print(`${c.gray} /${c.reset} open the command palette (type to filter)`);
4867
4949
  tui.print(`${c.gray} ctrl-v${c.reset} paste an image from the clipboard ([#Image 1])`);
4868
4950
  tui.print(`${c.gray} \u2191 / \u2193${c.reset} cycle past messages (on the input's top line)`);
4951
+ tui.print(`${c.gray} \u2190${c.reset} from the start of the input: select the [\u2699 n bg] badge (enter opens it)`);
4869
4952
  tui.print(`${c.gray} ctrl-c${c.reset} quit`);
4870
4953
  }
4871
4954
  async function runProcessMenu(tui, bg) {