@standardagents/code 0.5.0 → 0.6.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 +319 -17
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import os6 from 'os';
|
|
2
|
+
import os6, { homedir } from 'os';
|
|
3
3
|
import fs4 from 'fs';
|
|
4
4
|
import path3 from 'path';
|
|
5
5
|
import readline2 from 'readline/promises';
|
|
@@ -8,6 +8,7 @@ import { stdout, stdin } from 'process';
|
|
|
8
8
|
import fsp from 'fs/promises';
|
|
9
9
|
import crypto from 'crypto';
|
|
10
10
|
import readline from 'readline';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
11
12
|
|
|
12
13
|
// src/api.ts
|
|
13
14
|
function classifyConnectError(err, endpoint) {
|
|
@@ -2105,6 +2106,19 @@ var SUBAGENT_COLORS = [
|
|
|
2105
2106
|
];
|
|
2106
2107
|
var COMPACTION_COLOR = "\x1B[38;5;208m";
|
|
2107
2108
|
var COMPACTION_AGENT = "compaction_agent";
|
|
2109
|
+
function isWideCodePoint(cp) {
|
|
2110
|
+
return cp >= 4352 && cp <= 4447 || // Hangul Jamo
|
|
2111
|
+
cp >= 11904 && cp <= 42191 || // CJK radicals … Yi
|
|
2112
|
+
cp >= 44032 && cp <= 55203 || // Hangul syllables
|
|
2113
|
+
cp >= 63744 && cp <= 64255 || // CJK compatibility ideographs
|
|
2114
|
+
cp >= 65072 && cp <= 65103 || // CJK compatibility forms
|
|
2115
|
+
cp >= 65280 && cp <= 65376 || // fullwidth forms
|
|
2116
|
+
cp >= 65504 && cp <= 65510 || cp >= 127744 && cp <= 129791 || // emoji
|
|
2117
|
+
cp >= 131072;
|
|
2118
|
+
}
|
|
2119
|
+
function sanitizeHudRow(s) {
|
|
2120
|
+
return s.replace(/\x1b(?!\[)/g, "").replace(/[\x00-\x1a\x1c-\x1f\x7f]/g, " ");
|
|
2121
|
+
}
|
|
2108
2122
|
var Tui = class _Tui {
|
|
2109
2123
|
constructor(level = 1) {
|
|
2110
2124
|
this.level = level;
|
|
@@ -2741,7 +2755,50 @@ var Tui = class _Tui {
|
|
|
2741
2755
|
return `${q}${bg}${this.levelColor()}\u276F${C.reset} `;
|
|
2742
2756
|
}
|
|
2743
2757
|
visibleWidth(s) {
|
|
2744
|
-
|
|
2758
|
+
let w = 0;
|
|
2759
|
+
for (const ch of s.replace(/\x1b\[[0-9;]*m/g, "")) {
|
|
2760
|
+
w += isWideCodePoint(ch.codePointAt(0)) ? 2 : 1;
|
|
2761
|
+
}
|
|
2762
|
+
return w;
|
|
2763
|
+
}
|
|
2764
|
+
/**
|
|
2765
|
+
* Truncate a styled string to at most `max` VISIBLE columns, copying ANSI
|
|
2766
|
+
* escape sequences through without counting them and appending a reset if it
|
|
2767
|
+
* cut mid-style. The redraw's whole height math assumes every HUD row is
|
|
2768
|
+
* exactly ONE physical terminal row — true only while each row's visible
|
|
2769
|
+
* width is strictly less than `cols`. A row of width == cols hits the
|
|
2770
|
+
* terminal's auto-wrap boundary: many terminals push the cursor to the next
|
|
2771
|
+
* line, so the following CR/LF yields an EXTRA physical row we didn't count,
|
|
2772
|
+
* and the region marches down the screen leaving a trail on every tick. Every
|
|
2773
|
+
* HUD row is clamped through here to keep that invariant no matter what any
|
|
2774
|
+
* individual line builder produces.
|
|
2775
|
+
*/
|
|
2776
|
+
clampVisible(s, max) {
|
|
2777
|
+
let out = "";
|
|
2778
|
+
let width = 0;
|
|
2779
|
+
let i = 0;
|
|
2780
|
+
let truncated = false;
|
|
2781
|
+
while (i < s.length) {
|
|
2782
|
+
if (s[i] === "\x1B" && s[i + 1] === "[") {
|
|
2783
|
+
let j = i + 2;
|
|
2784
|
+
while (j < s.length && !/[a-zA-Z]/.test(s[j])) j++;
|
|
2785
|
+
out += s.slice(i, j + 1);
|
|
2786
|
+
i = j + 1;
|
|
2787
|
+
continue;
|
|
2788
|
+
}
|
|
2789
|
+
const cp = s.codePointAt(i);
|
|
2790
|
+
const chLen = cp > 65535 ? 2 : 1;
|
|
2791
|
+
const chWidth = isWideCodePoint(cp) ? 2 : 1;
|
|
2792
|
+
if (width + chWidth > max) {
|
|
2793
|
+
truncated = true;
|
|
2794
|
+
break;
|
|
2795
|
+
}
|
|
2796
|
+
out += s.slice(i, i + chLen);
|
|
2797
|
+
width += chWidth;
|
|
2798
|
+
i += chLen;
|
|
2799
|
+
}
|
|
2800
|
+
if (truncated) out += C.reset;
|
|
2801
|
+
return out;
|
|
2745
2802
|
}
|
|
2746
2803
|
/**
|
|
2747
2804
|
* The slash-palette block rendered BELOW the input. While the palette is open
|
|
@@ -2754,7 +2811,7 @@ var Tui = class _Tui {
|
|
|
2754
2811
|
*/
|
|
2755
2812
|
paletteBlockLines(cols2) {
|
|
2756
2813
|
if (!this.paletteOpen()) return [];
|
|
2757
|
-
const rows = this.paletteLines(cols2);
|
|
2814
|
+
const rows = this.paletteLines(cols2).map((r) => this.clampVisible(r, Math.max(1, cols2 - 1)));
|
|
2758
2815
|
const reserved = Math.max(this.commands.length, rows.length);
|
|
2759
2816
|
while (rows.length < reserved) rows.push("");
|
|
2760
2817
|
return rows;
|
|
@@ -2823,11 +2880,13 @@ var Tui = class _Tui {
|
|
|
2823
2880
|
if (!this.started || this.takeoverHandler) return;
|
|
2824
2881
|
const cols2 = process.stdout.columns || 80;
|
|
2825
2882
|
this.moveToRegionTop();
|
|
2826
|
-
process.stdout.write("\x1B[J");
|
|
2827
2883
|
const hudWidths = [];
|
|
2884
|
+
const hudRows = [];
|
|
2885
|
+
const rowCap = Math.max(1, cols2 - 1);
|
|
2828
2886
|
const writeHudRow = (line) => {
|
|
2829
|
-
|
|
2830
|
-
|
|
2887
|
+
const row = this.clampVisible(sanitizeHudRow(line), rowCap);
|
|
2888
|
+
hudWidths.push(this.visibleWidth(row));
|
|
2889
|
+
hudRows.push(row);
|
|
2831
2890
|
};
|
|
2832
2891
|
const previewLines = this.streamPreviewLines(cols2);
|
|
2833
2892
|
for (const line of previewLines) writeHudRow(line);
|
|
@@ -2858,8 +2917,8 @@ var Tui = class _Tui {
|
|
|
2858
2917
|
const prefix = this.promptPrefix();
|
|
2859
2918
|
const pw = this.visibleWidth(prefix);
|
|
2860
2919
|
const lines = this.inputBuffer.split("\n");
|
|
2861
|
-
|
|
2862
|
-
for (let i = 1; i < lines.length; i++)
|
|
2920
|
+
const tail = [prefix + lines[0]];
|
|
2921
|
+
for (let i = 1; i < lines.length; i++) tail.push("\r\n" + lines[i]);
|
|
2863
2922
|
const rowsOf = (len, lead) => Math.max(1, Math.ceil((lead + len) / cols2));
|
|
2864
2923
|
const lineRows = lines.map((l, i) => rowsOf(l.length, i === 0 ? pw : 0));
|
|
2865
2924
|
const inputRows = lineRows.reduce((a, b) => a + b, 0);
|
|
@@ -2874,18 +2933,18 @@ var Tui = class _Tui {
|
|
|
2874
2933
|
for (let i = 0; i < caretLine; i++) caretRow += lineRows[i];
|
|
2875
2934
|
const caretCol = caretCell % cols2;
|
|
2876
2935
|
const paletteBlock = this.paletteBlockLines(cols2);
|
|
2877
|
-
for (const line of paletteBlock)
|
|
2936
|
+
for (const line of paletteBlock) tail.push("\r\n" + line);
|
|
2878
2937
|
if (paletteBlock.length > 0) {
|
|
2879
|
-
|
|
2938
|
+
tail.push("\r");
|
|
2880
2939
|
const up = inputRows - 1 + paletteBlock.length - caretRow;
|
|
2881
|
-
if (up > 0)
|
|
2882
|
-
if (caretCol > 0)
|
|
2940
|
+
if (up > 0) tail.push(`\x1B[${up}A`);
|
|
2941
|
+
if (caretCol > 0) tail.push(`\x1B[${caretCol}C`);
|
|
2883
2942
|
this.lastCursorRow = aboveRows + caretRow;
|
|
2884
2943
|
} else if (this.cursorPos < this.inputBuffer.length) {
|
|
2885
|
-
|
|
2944
|
+
tail.push("\r");
|
|
2886
2945
|
const up = inputRows - 1 - caretRow;
|
|
2887
|
-
if (up > 0)
|
|
2888
|
-
if (caretCol > 0)
|
|
2946
|
+
if (up > 0) tail.push(`\x1B[${up}A`);
|
|
2947
|
+
if (caretCol > 0) tail.push(`\x1B[${caretCol}C`);
|
|
2889
2948
|
this.lastCursorRow = aboveRows + caretRow;
|
|
2890
2949
|
} else {
|
|
2891
2950
|
this.lastCursorRow = aboveRows + (inputRows - 1);
|
|
@@ -2893,6 +2952,8 @@ var Tui = class _Tui {
|
|
|
2893
2952
|
this.drawnHudWidths = hudWidths;
|
|
2894
2953
|
this.lastDrawnCols = cols2;
|
|
2895
2954
|
this.bottomDrawn = true;
|
|
2955
|
+
const out = "\x1B[J" + hudRows.join("\r\n") + "\r\n" + tail.join("");
|
|
2956
|
+
process.stdout.write(out);
|
|
2896
2957
|
}
|
|
2897
2958
|
clearBottom() {
|
|
2898
2959
|
if (!this.bottomDrawn) return;
|
|
@@ -3206,7 +3267,7 @@ var Tui = class _Tui {
|
|
|
3206
3267
|
* resets whenever the label changes.
|
|
3207
3268
|
*/
|
|
3208
3269
|
setStep(label, outTokens) {
|
|
3209
|
-
const next = label && label.trim() ? label.trim() : null;
|
|
3270
|
+
const next = label && label.trim() ? label.replace(/\s+/g, " ").trim() : null;
|
|
3210
3271
|
if (next !== this.step) {
|
|
3211
3272
|
this.step = next;
|
|
3212
3273
|
this.stepStart = Date.now();
|
|
@@ -4032,6 +4093,172 @@ function saveDefaultEndpoint(endpoint) {
|
|
|
4032
4093
|
} catch {
|
|
4033
4094
|
}
|
|
4034
4095
|
}
|
|
4096
|
+
var PKG_NAME = "@standardagents/code";
|
|
4097
|
+
var REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PKG_NAME)}`;
|
|
4098
|
+
var CACHE_REL_DIR = ".config/standardagents-cli";
|
|
4099
|
+
var CACHE_FILE = "update-check.json";
|
|
4100
|
+
var STATE_FILE = "auto-update.json";
|
|
4101
|
+
var CACHE_TTL_MS = 1e3 * 60 * 60 * 24;
|
|
4102
|
+
var CHECK_TIMEOUT_MS = 4e3;
|
|
4103
|
+
var IN_FLIGHT_TTL_MS = 15 * 60 * 1e3;
|
|
4104
|
+
function cacheDir() {
|
|
4105
|
+
return path3.join(homedir(), CACHE_REL_DIR);
|
|
4106
|
+
}
|
|
4107
|
+
function cachePath() {
|
|
4108
|
+
return path3.join(cacheDir(), CACHE_FILE);
|
|
4109
|
+
}
|
|
4110
|
+
function readCache() {
|
|
4111
|
+
try {
|
|
4112
|
+
const raw = fs4.readFileSync(cachePath(), "utf-8");
|
|
4113
|
+
return JSON.parse(raw);
|
|
4114
|
+
} catch {
|
|
4115
|
+
return null;
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
function writeCache(latest) {
|
|
4119
|
+
try {
|
|
4120
|
+
const dir = cacheDir();
|
|
4121
|
+
if (!fs4.existsSync(dir)) fs4.mkdirSync(dir, { recursive: true });
|
|
4122
|
+
fs4.writeFileSync(cachePath(), JSON.stringify({ latest, timestamp: Date.now() }));
|
|
4123
|
+
} catch {
|
|
4124
|
+
}
|
|
4125
|
+
}
|
|
4126
|
+
function readAutoUpdateState(dir = cacheDir()) {
|
|
4127
|
+
try {
|
|
4128
|
+
const raw = fs4.readFileSync(path3.join(dir, STATE_FILE), "utf-8");
|
|
4129
|
+
const state = JSON.parse(raw);
|
|
4130
|
+
return typeof state?.version === "string" ? state : null;
|
|
4131
|
+
} catch {
|
|
4132
|
+
return null;
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
4135
|
+
function writeAutoUpdateState(state, dir = cacheDir()) {
|
|
4136
|
+
try {
|
|
4137
|
+
if (!fs4.existsSync(dir)) fs4.mkdirSync(dir, { recursive: true });
|
|
4138
|
+
fs4.writeFileSync(path3.join(dir, STATE_FILE), JSON.stringify(state));
|
|
4139
|
+
} catch {
|
|
4140
|
+
}
|
|
4141
|
+
}
|
|
4142
|
+
function clearAutoUpdateState(dir = cacheDir()) {
|
|
4143
|
+
try {
|
|
4144
|
+
fs4.unlinkSync(path3.join(dir, STATE_FILE));
|
|
4145
|
+
} catch {
|
|
4146
|
+
}
|
|
4147
|
+
}
|
|
4148
|
+
function detectPackageManager(selfPath = fileURLToPath(import.meta.url), env = process.env) {
|
|
4149
|
+
const norm = selfPath.split(/[\\/]/).join("/");
|
|
4150
|
+
if (!norm.includes("node_modules/@standardagents/code")) return null;
|
|
4151
|
+
const pnpmHome = (env.PNPM_HOME || "").split(/[\\/]/).join("/");
|
|
4152
|
+
if (pnpmHome && norm.startsWith(pnpmHome)) return "pnpm";
|
|
4153
|
+
if (norm.includes("/.pnpm/") || /\/pnpm\/global\//.test(norm)) return "pnpm";
|
|
4154
|
+
if (norm.includes("/.bun/")) return "bun";
|
|
4155
|
+
if (norm.includes("/.config/yarn/") || norm.includes("/.yarn/")) return "yarn";
|
|
4156
|
+
return "npm";
|
|
4157
|
+
}
|
|
4158
|
+
function updateCommand(pm) {
|
|
4159
|
+
switch (pm) {
|
|
4160
|
+
case "pnpm":
|
|
4161
|
+
return { cmd: "pnpm", args: ["add", "-g", `${PKG_NAME}@latest`], display: `pnpm add -g ${PKG_NAME}@latest` };
|
|
4162
|
+
case "yarn":
|
|
4163
|
+
return { cmd: "yarn", args: ["global", "add", `${PKG_NAME}@latest`], display: `yarn global add ${PKG_NAME}@latest` };
|
|
4164
|
+
case "bun":
|
|
4165
|
+
return { cmd: "bun", args: ["add", "-g", `${PKG_NAME}@latest`], display: `bun add -g ${PKG_NAME}@latest` };
|
|
4166
|
+
default:
|
|
4167
|
+
return { cmd: "npm", args: ["i", "-g", `${PKG_NAME}@latest`], display: `npm i -g ${PKG_NAME}@latest` };
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
function decideAutoUpdate(info, opts) {
|
|
4171
|
+
const env = opts.env ?? process.env;
|
|
4172
|
+
if (env.STANDARD_CODE_NO_AUTO_UPDATE) return "disabled";
|
|
4173
|
+
if (!opts.pm) return "dev_checkout";
|
|
4174
|
+
const state = opts.state;
|
|
4175
|
+
if (state && state.version === info.latest) {
|
|
4176
|
+
if (state.exitCode === null) {
|
|
4177
|
+
const now = opts.now ?? Date.now();
|
|
4178
|
+
return now - state.startedAt < IN_FLIGHT_TTL_MS ? "in_flight" : "start";
|
|
4179
|
+
}
|
|
4180
|
+
return state.exitCode === 0 ? "path_shadowed" : "already_failed";
|
|
4181
|
+
}
|
|
4182
|
+
return "start";
|
|
4183
|
+
}
|
|
4184
|
+
function startBackgroundUpdate(latest, pm, dir = cacheDir()) {
|
|
4185
|
+
const startedAt = Date.now();
|
|
4186
|
+
writeAutoUpdateState({ version: latest, startedAt, exitCode: null }, dir);
|
|
4187
|
+
const stateFile = path3.join(dir, STATE_FILE);
|
|
4188
|
+
const { cmd, args } = updateCommand(pm);
|
|
4189
|
+
const script = `const cp=require('child_process');const fs=require('fs');const r=cp.spawnSync(${JSON.stringify(cmd)},${JSON.stringify(args)},{shell:process.platform==='win32',encoding:'utf8'});const out=((r.stdout||'')+(r.stderr||'')).slice(-2000);fs.writeFileSync(${JSON.stringify(stateFile)},JSON.stringify({version:${JSON.stringify(latest)},startedAt:${startedAt},exitCode:r.status==null?-1:r.status,finishedAt:Date.now(),output:out}));`;
|
|
4190
|
+
try {
|
|
4191
|
+
const child = spawn(process.execPath, ["-e", script], { detached: true, stdio: "ignore" });
|
|
4192
|
+
child.unref();
|
|
4193
|
+
return true;
|
|
4194
|
+
} catch {
|
|
4195
|
+
writeAutoUpdateState({ version: latest, startedAt, exitCode: -1, finishedAt: Date.now() }, dir);
|
|
4196
|
+
return false;
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4199
|
+
function consumeAppliedUpdate(currentVersion, dir = cacheDir()) {
|
|
4200
|
+
const state = readAutoUpdateState(dir);
|
|
4201
|
+
if (!state || state.version !== currentVersion) return null;
|
|
4202
|
+
clearAutoUpdateState(dir);
|
|
4203
|
+
return state.exitCode === 0 ? state : null;
|
|
4204
|
+
}
|
|
4205
|
+
async function fetchLatest(currentVersion) {
|
|
4206
|
+
const controller = new AbortController();
|
|
4207
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
|
|
4208
|
+
try {
|
|
4209
|
+
const res = await fetch(REGISTRY_URL, {
|
|
4210
|
+
signal: controller.signal,
|
|
4211
|
+
headers: {
|
|
4212
|
+
Accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*",
|
|
4213
|
+
"User-Agent": `${PKG_NAME}/${currentVersion}`
|
|
4214
|
+
}
|
|
4215
|
+
});
|
|
4216
|
+
if (!res.ok) return null;
|
|
4217
|
+
const data = await res.json();
|
|
4218
|
+
return data["dist-tags"]?.latest ?? null;
|
|
4219
|
+
} catch {
|
|
4220
|
+
return null;
|
|
4221
|
+
} finally {
|
|
4222
|
+
clearTimeout(timeout);
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
async function checkForUpdate(currentVersion) {
|
|
4226
|
+
if (!currentVersion) return null;
|
|
4227
|
+
if (process.env.NO_UPDATE_NOTIFIER || process.env.CI) return null;
|
|
4228
|
+
const cached = readCache();
|
|
4229
|
+
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
|
4230
|
+
if (cached.latest !== currentVersion) {
|
|
4231
|
+
return { current: currentVersion, latest: cached.latest };
|
|
4232
|
+
}
|
|
4233
|
+
return null;
|
|
4234
|
+
}
|
|
4235
|
+
const latest = await fetchLatest(currentVersion);
|
|
4236
|
+
if (!latest) return null;
|
|
4237
|
+
writeCache(latest);
|
|
4238
|
+
return latest !== currentVersion ? { current: currentVersion, latest } : null;
|
|
4239
|
+
}
|
|
4240
|
+
async function forceCheckForUpdate(currentVersion) {
|
|
4241
|
+
if (!currentVersion) return null;
|
|
4242
|
+
if (process.env.NO_UPDATE_NOTIFIER || process.env.CI) return null;
|
|
4243
|
+
const latest = await fetchLatest(currentVersion);
|
|
4244
|
+
if (!latest) return null;
|
|
4245
|
+
writeCache(latest);
|
|
4246
|
+
return latest !== currentVersion ? { current: currentVersion, latest } : null;
|
|
4247
|
+
}
|
|
4248
|
+
function runUpdate(pm) {
|
|
4249
|
+
return new Promise((resolve) => {
|
|
4250
|
+
const { cmd, args } = updateCommand(pm);
|
|
4251
|
+
const child = spawn(cmd, args, {
|
|
4252
|
+
shell: process.platform === "win32",
|
|
4253
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4254
|
+
});
|
|
4255
|
+
let out = "";
|
|
4256
|
+
child.stdout?.on("data", (d) => out += d);
|
|
4257
|
+
child.stderr?.on("data", (d) => out += d);
|
|
4258
|
+
child.on("close", (code) => resolve({ ok: code === 0, output: out }));
|
|
4259
|
+
child.on("error", (err) => resolve({ ok: false, output: String(err) }));
|
|
4260
|
+
});
|
|
4261
|
+
}
|
|
4035
4262
|
|
|
4036
4263
|
// src/index.ts
|
|
4037
4264
|
var AGENT_ID = "standard_code_agent";
|
|
@@ -4316,6 +4543,44 @@ ${c.dim}Press Control-C again to exit${c.reset}
|
|
|
4316
4543
|
|
|
4317
4544
|
`);
|
|
4318
4545
|
}
|
|
4546
|
+
const version = readVersion();
|
|
4547
|
+
let updateAvailable = null;
|
|
4548
|
+
{
|
|
4549
|
+
const loading = startLoader("Checking for updates");
|
|
4550
|
+
updateAvailable = await checkForUpdate(version);
|
|
4551
|
+
loading.stop();
|
|
4552
|
+
const applied = consumeAppliedUpdate(version);
|
|
4553
|
+
if (applied) {
|
|
4554
|
+
stdout.write(` ${c.green}\u2713${c.reset} ${c.dim}Standard Code updated to v${version}.${c.reset}
|
|
4555
|
+
|
|
4556
|
+
`);
|
|
4557
|
+
}
|
|
4558
|
+
if (updateAvailable) {
|
|
4559
|
+
const pm = detectPackageManager();
|
|
4560
|
+
const decision = decideAutoUpdate(updateAvailable, { state: readAutoUpdateState(), pm });
|
|
4561
|
+
if (decision === "start" && pm && startBackgroundUpdate(updateAvailable.latest, pm)) {
|
|
4562
|
+
stdout.write(
|
|
4563
|
+
` ${c.teal}\u27F3${c.reset} ${c.dim}Standard Code ${c.reset}${c.bold}v${updateAvailable.latest}${c.reset}${c.dim} is installing in the background \u2014 it applies on your next launch.${c.reset}
|
|
4564
|
+
|
|
4565
|
+
`
|
|
4566
|
+
);
|
|
4567
|
+
} else if (decision === "in_flight") {
|
|
4568
|
+
stdout.write(
|
|
4569
|
+
` ${c.teal}\u27F3${c.reset} ${c.dim}Standard Code v${updateAvailable.latest} is still installing in the background.${c.reset}
|
|
4570
|
+
|
|
4571
|
+
`
|
|
4572
|
+
);
|
|
4573
|
+
} else {
|
|
4574
|
+
const display = updateCommand(pm ?? "npm").display;
|
|
4575
|
+
stdout.write(
|
|
4576
|
+
` ${c.teal}\u25C7${c.reset} ${c.dim}Update available:${c.reset} ${c.dim}v${updateAvailable.current}${c.reset} \u2192 ${c.bold}v${updateAvailable.latest}${c.reset}
|
|
4577
|
+
${c.dim}Run ${c.reset}${c.bold}${display}${c.reset}${c.dim} to update${c.reset}
|
|
4578
|
+
|
|
4579
|
+
`
|
|
4580
|
+
);
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4319
4584
|
const stored = getCredential(endpoint);
|
|
4320
4585
|
let api = stored ? new ApiClient(endpoint, stored.access_token) : null;
|
|
4321
4586
|
let storedCheck = null;
|
|
@@ -4675,7 +4940,8 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
|
|
|
4675
4940
|
for (const s of subs) {
|
|
4676
4941
|
const status = (s.status || "").trim();
|
|
4677
4942
|
if (status === "idle" || status === "terminated") continue;
|
|
4678
|
-
const
|
|
4943
|
+
const oneLineStatus = status.replace(/\s+/g, " ");
|
|
4944
|
+
const detail = oneLineStatus && oneLineStatus !== "running" ? ` \u2014 ${oneLineStatus.slice(0, 80)}` : "";
|
|
4679
4945
|
activeSubagents.set(s.id, {
|
|
4680
4946
|
label: `${subagentLabel(s, agentTitles)}${detail}`,
|
|
4681
4947
|
agentName: s.agent_name ?? void 0
|
|
@@ -4871,6 +5137,7 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
|
|
|
4871
5137
|
},
|
|
4872
5138
|
{ name: "background", label: "Background processes", hint: "list / stop", run: () => runProcessMenu(tui, bgMgr) },
|
|
4873
5139
|
{ name: "keybindings", label: "Keyboard shortcuts", run: () => showKeybindings(tui) },
|
|
5140
|
+
{ name: "update", label: "Check for updates", hint: "check for a newer version", run: () => runUpdateCommand(tui) },
|
|
4874
5141
|
{ name: "logout", label: "Sign out", hint: "delete the saved token & quit", run: () => logout() },
|
|
4875
5142
|
{ name: "quit", label: "Quit", run: () => quit() }
|
|
4876
5143
|
]);
|
|
@@ -5127,6 +5394,41 @@ function showKeybindings(tui) {
|
|
|
5127
5394
|
tui.print(`${c.gray} \u2190${c.reset} from the start of the input: select the [\u2699 n bg] badge (enter opens it)`);
|
|
5128
5395
|
tui.print(`${c.gray} ctrl-c${c.reset} quit`);
|
|
5129
5396
|
}
|
|
5397
|
+
async function runUpdateCommand(tui) {
|
|
5398
|
+
const version = readVersion();
|
|
5399
|
+
const result = await forceCheckForUpdate(version);
|
|
5400
|
+
if (!result) {
|
|
5401
|
+
tui.print(`${c.green}\u2713${c.reset} ${c.gray}@standardagents/code${c.reset} is up to date (v${version})`);
|
|
5402
|
+
return;
|
|
5403
|
+
}
|
|
5404
|
+
const { latest } = result;
|
|
5405
|
+
tui.print(`
|
|
5406
|
+
${c.yellow}\u27F3${c.reset} Update available: ${c.gray}v${version}${c.reset} \u2192 ${c.green}v${latest}${c.reset}`);
|
|
5407
|
+
const pm = detectPackageManager();
|
|
5408
|
+
if (!pm) {
|
|
5409
|
+
tui.print(` ${c.gray}This is a source checkout \u2014 pull the repo to update.${c.reset}`);
|
|
5410
|
+
return;
|
|
5411
|
+
}
|
|
5412
|
+
const { display } = updateCommand(pm);
|
|
5413
|
+
const choice = await tui.select(`Update now with \`${display}\`?`, [
|
|
5414
|
+
{ label: "Yes, update now", value: "yes" },
|
|
5415
|
+
{ label: "No, skip", value: "no" }
|
|
5416
|
+
]);
|
|
5417
|
+
if (choice === "yes") {
|
|
5418
|
+
tui.print(` ${c.gray}Running ${display}\u2026${c.reset}`);
|
|
5419
|
+
const { ok, output: pmOutput } = await runUpdate(pm);
|
|
5420
|
+
if (ok) {
|
|
5421
|
+
tui.print(` ${c.green}\u2713${c.reset} Updated to v${latest}. Restart to use the new version.`);
|
|
5422
|
+
} else {
|
|
5423
|
+
tui.print(` ${c.red}\u2717${c.reset} Update failed:`);
|
|
5424
|
+
for (const line of pmOutput.trim().split("\n").slice(-6)) {
|
|
5425
|
+
tui.print(` ${c.dim}${line}${c.reset}`);
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
} else {
|
|
5429
|
+
tui.print(` ${c.gray}Skipped. Run /update later.${c.reset}`);
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5130
5432
|
async function runProcessMenu(tui, bg) {
|
|
5131
5433
|
const procs = await bg.list();
|
|
5132
5434
|
if (!procs.length) {
|