@standardagents/code 0.9.2 → 0.9.3
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 +97 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5060,7 +5060,7 @@ function loadMachineIdentity() {
|
|
|
5060
5060
|
try {
|
|
5061
5061
|
const parsed = JSON.parse(fs4.readFileSync(file(), "utf8"));
|
|
5062
5062
|
if (typeof parsed.machine_id === "string" && parsed.machine_id.length > 0) {
|
|
5063
|
-
return parsed;
|
|
5063
|
+
return { machine_id: parsed.machine_id, created_at: parsed.created_at ?? Date.now() };
|
|
5064
5064
|
}
|
|
5065
5065
|
} catch {
|
|
5066
5066
|
}
|
|
@@ -5075,15 +5075,6 @@ function saveMachineIdentity(identity) {
|
|
|
5075
5075
|
fs4.mkdirSync(dir(), { recursive: true });
|
|
5076
5076
|
fs4.writeFileSync(file(), JSON.stringify(identity, null, 2), { mode: 384 });
|
|
5077
5077
|
}
|
|
5078
|
-
function setMachineName(name) {
|
|
5079
|
-
const identity = loadMachineIdentity();
|
|
5080
|
-
identity.name = name.trim() || void 0;
|
|
5081
|
-
saveMachineIdentity(identity);
|
|
5082
|
-
return identity;
|
|
5083
|
-
}
|
|
5084
|
-
function machineDisplayName(identity) {
|
|
5085
|
-
return identity.name?.trim() || os9.hostname();
|
|
5086
|
-
}
|
|
5087
5078
|
function daemonClientId(identity) {
|
|
5088
5079
|
return `daemon:${identity.machine_id}`;
|
|
5089
5080
|
}
|
|
@@ -5096,6 +5087,7 @@ function machineIdFromDaemonClientId(clientId) {
|
|
|
5096
5087
|
}
|
|
5097
5088
|
var KEY_PREFIX = "standardcode.machine.";
|
|
5098
5089
|
var CMD_SUFFIX = ".cmd";
|
|
5090
|
+
var NAME_SUFFIX = ".name";
|
|
5099
5091
|
var DAEMON_ONLINE_WINDOW_MS = 90 * 1e3;
|
|
5100
5092
|
function machineKey(machineId) {
|
|
5101
5093
|
return `${KEY_PREFIX}${machineId}`;
|
|
@@ -5103,6 +5095,20 @@ function machineKey(machineId) {
|
|
|
5103
5095
|
function commandKey(machineId) {
|
|
5104
5096
|
return `${KEY_PREFIX}${machineId}${CMD_SUFFIX}`;
|
|
5105
5097
|
}
|
|
5098
|
+
function nameKey(machineId) {
|
|
5099
|
+
return `${KEY_PREFIX}${machineId}${NAME_SUFFIX}`;
|
|
5100
|
+
}
|
|
5101
|
+
function machineDisplayName(record) {
|
|
5102
|
+
return record.name?.trim() || "" || (record.hostname || "") || (record.id || "") || "machine";
|
|
5103
|
+
}
|
|
5104
|
+
async function getMachineName(api, machineId) {
|
|
5105
|
+
const v = await api.userKvGet(nameKey(machineId));
|
|
5106
|
+
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
5107
|
+
}
|
|
5108
|
+
async function setMachineName(api, machineId, name) {
|
|
5109
|
+
const trimmed = name.trim();
|
|
5110
|
+
await api.userKvSet(nameKey(machineId), trimmed || null);
|
|
5111
|
+
}
|
|
5106
5112
|
function parseMachineRecord(value) {
|
|
5107
5113
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
5108
5114
|
const r = value;
|
|
@@ -5120,12 +5126,36 @@ function parseMachineRecord(value) {
|
|
|
5120
5126
|
updated_at: typeof r.updated_at === "number" ? r.updated_at : 0
|
|
5121
5127
|
};
|
|
5122
5128
|
}
|
|
5129
|
+
async function loadRawMachine(api, machineId) {
|
|
5130
|
+
return parseMachineRecord(await api.userKvGet(machineKey(machineId)));
|
|
5131
|
+
}
|
|
5123
5132
|
async function loadMachines(api) {
|
|
5124
5133
|
const entries = await api.userKvList(KEY_PREFIX);
|
|
5125
|
-
|
|
5134
|
+
const records = [];
|
|
5135
|
+
const names = /* @__PURE__ */ new Map();
|
|
5136
|
+
for (const e of entries) {
|
|
5137
|
+
const rest = e.key.slice(KEY_PREFIX.length);
|
|
5138
|
+
if (rest.endsWith(CMD_SUFFIX)) continue;
|
|
5139
|
+
if (rest.endsWith(NAME_SUFFIX)) {
|
|
5140
|
+
const id = rest.slice(0, -NAME_SUFFIX.length);
|
|
5141
|
+
if (typeof e.value === "string" && e.value.trim()) names.set(id, e.value.trim());
|
|
5142
|
+
continue;
|
|
5143
|
+
}
|
|
5144
|
+
const rec = parseMachineRecord(e.value);
|
|
5145
|
+
if (rec) records.push(rec);
|
|
5146
|
+
}
|
|
5147
|
+
for (const rec of records) {
|
|
5148
|
+
const override = names.get(rec.id);
|
|
5149
|
+
if (override) rec.name = override;
|
|
5150
|
+
}
|
|
5151
|
+
return records;
|
|
5126
5152
|
}
|
|
5127
5153
|
async function loadMachine(api, machineId) {
|
|
5128
|
-
|
|
5154
|
+
const rec = await loadRawMachine(api, machineId);
|
|
5155
|
+
if (!rec) return null;
|
|
5156
|
+
const override = await getMachineName(api, machineId);
|
|
5157
|
+
if (override) rec.name = override;
|
|
5158
|
+
return rec;
|
|
5129
5159
|
}
|
|
5130
5160
|
function daemonOnline(record, now = Date.now()) {
|
|
5131
5161
|
return !!record.daemon && now - record.daemon.last_seen_at < DAEMON_ONLINE_WINDOW_MS;
|
|
@@ -5134,7 +5164,7 @@ function newRecord(identity) {
|
|
|
5134
5164
|
const now = Date.now();
|
|
5135
5165
|
return {
|
|
5136
5166
|
id: identity.machine_id,
|
|
5137
|
-
name:
|
|
5167
|
+
name: os9.hostname(),
|
|
5138
5168
|
hostname: os9.hostname(),
|
|
5139
5169
|
platform: process.platform,
|
|
5140
5170
|
arch: process.arch,
|
|
@@ -5146,9 +5176,8 @@ function newRecord(identity) {
|
|
|
5146
5176
|
};
|
|
5147
5177
|
}
|
|
5148
5178
|
async function updateOwnMachineRecord(api, identity, mutate) {
|
|
5149
|
-
const existing = await
|
|
5179
|
+
const existing = await loadRawMachine(api, identity.machine_id);
|
|
5150
5180
|
const record = existing ?? newRecord(identity);
|
|
5151
|
-
record.name = machineDisplayName(loadMachineIdentity());
|
|
5152
5181
|
record.hostname = os9.hostname();
|
|
5153
5182
|
record.platform = process.platform;
|
|
5154
5183
|
record.arch = process.arch;
|
|
@@ -5233,13 +5262,6 @@ async function clearMachineCommands(api, machineId, appliedIds) {
|
|
|
5233
5262
|
}
|
|
5234
5263
|
async function applyMachineCommand(api, identity, cmd) {
|
|
5235
5264
|
switch (cmd.kind) {
|
|
5236
|
-
case "rename": {
|
|
5237
|
-
const name = typeof cmd.args?.name === "string" ? cmd.args.name.trim() : "";
|
|
5238
|
-
if (!name) return "rename: ignored (empty name)";
|
|
5239
|
-
setMachineName(name);
|
|
5240
|
-
await updateOwnMachineRecord(api, identity);
|
|
5241
|
-
return `renamed to "${name}"`;
|
|
5242
|
-
}
|
|
5243
5265
|
case "add_project": {
|
|
5244
5266
|
const path12 = typeof cmd.args?.path === "string" ? cmd.args.path : "";
|
|
5245
5267
|
if (!path12) return "add_project: ignored (no path)";
|
|
@@ -5519,11 +5541,10 @@ function pathFromTags(tags) {
|
|
|
5519
5541
|
return raw.replace(/^~(?=\/|$)/, os9.homedir());
|
|
5520
5542
|
}
|
|
5521
5543
|
var ThreadWorker = class {
|
|
5522
|
-
constructor(api, identity, threadId, projectDir, createdAt) {
|
|
5544
|
+
constructor(api, identity, machineName, threadId, projectDir, createdAt) {
|
|
5523
5545
|
this.threadId = threadId;
|
|
5524
5546
|
this.projectDir = projectDir;
|
|
5525
5547
|
this.createdAt = createdAt;
|
|
5526
|
-
const machineName = machineDisplayName(identity);
|
|
5527
5548
|
this.perm = { level: 1, alwaysAllow: /* @__PURE__ */ new Set(), allowRisk: /* @__PURE__ */ new Set() };
|
|
5528
5549
|
this.session = new ExecutionSession({
|
|
5529
5550
|
api,
|
|
@@ -5648,9 +5669,13 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
|
|
|
5648
5669
|
`);
|
|
5649
5670
|
process.exit(1);
|
|
5650
5671
|
}
|
|
5672
|
+
let displayName = machineDisplayName(await loadMachine(api, identity.machine_id).catch(() => null) ?? {
|
|
5673
|
+
hostname: os9.hostname(),
|
|
5674
|
+
id: identity.machine_id
|
|
5675
|
+
});
|
|
5651
5676
|
const applied = consumeAppliedUpdate(version);
|
|
5652
5677
|
daemonLog(
|
|
5653
|
-
`daemon starting \u2014 v${version}${applied ? " (freshly auto-updated)" : ""}, machine ${identity.machine_id} (${
|
|
5678
|
+
`daemon starting \u2014 v${version}${applied ? " (freshly auto-updated)" : ""}, machine ${identity.machine_id} (${displayName}), endpoint ${endpoint}`
|
|
5654
5679
|
);
|
|
5655
5680
|
process.on("uncaughtException", (err) => {
|
|
5656
5681
|
daemonLog(`FATAL uncaughtException: ${err?.stack || err}`);
|
|
@@ -5677,7 +5702,7 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
|
|
|
5677
5702
|
daemonLog(`cannot prepare project dir ${projectDir}: ${e instanceof Error ? e.message : String(e)}`);
|
|
5678
5703
|
return;
|
|
5679
5704
|
}
|
|
5680
|
-
const worker = new ThreadWorker(api, identity, threadId, projectDir, createdAt || Date.now());
|
|
5705
|
+
const worker = new ThreadWorker(api, identity, displayName, threadId, projectDir, createdAt || Date.now());
|
|
5681
5706
|
worker.onEvicted = (id) => detach(id);
|
|
5682
5707
|
workers.set(threadId, worker);
|
|
5683
5708
|
daemonLog(`attached ${threadId.slice(0, 8)} \u2192 ${projectDir}`);
|
|
@@ -5722,6 +5747,10 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
|
|
|
5722
5747
|
const heartbeat = setInterval(() => {
|
|
5723
5748
|
void touchDaemon(api, identity, version).catch(() => {
|
|
5724
5749
|
});
|
|
5750
|
+
void getMachineName(api, identity.machine_id).then((n) => {
|
|
5751
|
+
if (n) displayName = n;
|
|
5752
|
+
}).catch(() => {
|
|
5753
|
+
});
|
|
5725
5754
|
}, HEARTBEAT_MS);
|
|
5726
5755
|
const reclaim = setInterval(() => {
|
|
5727
5756
|
for (const worker of workers.values()) {
|
|
@@ -6089,15 +6118,16 @@ async function installCommand(endpointFlag) {
|
|
|
6089
6118
|
const endpoint = resolveEndpoint(endpointFlag);
|
|
6090
6119
|
const api = await ensureSignedIn(endpoint);
|
|
6091
6120
|
const identity = loadMachineIdentity();
|
|
6121
|
+
const existing = await loadMachine(api, identity.machine_id).catch(() => null);
|
|
6122
|
+
const suggested = machineDisplayName(existing ?? { hostname: os9.hostname(), id: identity.machine_id });
|
|
6092
6123
|
const rl = readline2.createInterface({ input: stdin, output: stdout });
|
|
6093
|
-
const suggested = machineDisplayName(identity);
|
|
6094
6124
|
const answer = (await rl.question(
|
|
6095
6125
|
`${c2.bold}Machine name${c2.reset} ${c2.dim}(shown in the session picker)${c2.reset} [${suggested}]: `
|
|
6096
6126
|
)).trim();
|
|
6097
6127
|
rl.close();
|
|
6098
|
-
if (answer) setMachineName(answer);
|
|
6099
|
-
|
|
6100
|
-
|
|
6128
|
+
if (answer) await setMachineName(api, identity.machine_id, answer);
|
|
6129
|
+
await updateOwnMachineRecord(api, identity);
|
|
6130
|
+
const displayName = answer || suggested;
|
|
6101
6131
|
stdout.write(`${c2.dim}Installing the always-on service\u2026${c2.reset}
|
|
6102
6132
|
`);
|
|
6103
6133
|
const extra = endpointFlag ? ["--endpoint", endpoint] : [];
|
|
@@ -6117,7 +6147,7 @@ async function installCommand(endpointFlag) {
|
|
|
6117
6147
|
let alive = false;
|
|
6118
6148
|
while (Date.now() < deadline) {
|
|
6119
6149
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
6120
|
-
const record = await loadMachine(api,
|
|
6150
|
+
const record = await loadMachine(api, identity.machine_id);
|
|
6121
6151
|
if (record && daemonOnline(record)) {
|
|
6122
6152
|
alive = true;
|
|
6123
6153
|
break;
|
|
@@ -6125,7 +6155,7 @@ async function installCommand(endpointFlag) {
|
|
|
6125
6155
|
}
|
|
6126
6156
|
if (alive) {
|
|
6127
6157
|
stdout.write(
|
|
6128
|
-
`${c2.green}\u2713${c2.reset} ${c2.bold}${
|
|
6158
|
+
`${c2.green}\u2713${c2.reset} ${c2.bold}${displayName}${c2.reset} is online.
|
|
6129
6159
|
|
|
6130
6160
|
Sessions started elsewhere can now run on this machine.
|
|
6131
6161
|
${c2.dim}Projects register automatically when you run standardcode in a directory here,
|
|
@@ -6144,12 +6174,14 @@ async function statusCommand() {
|
|
|
6144
6174
|
const status = serviceStatus();
|
|
6145
6175
|
const identity = loadMachineIdentity();
|
|
6146
6176
|
stdout.write(`${c2.bold}Service:${c2.reset} ${status.detail}
|
|
6147
|
-
`);
|
|
6148
|
-
stdout.write(`${c2.bold}Machine:${c2.reset} ${machineDisplayName(identity)} ${c2.dim}(${identity.machine_id})${c2.reset}
|
|
6149
6177
|
`);
|
|
6150
6178
|
const endpoint = resolveEndpoint();
|
|
6151
6179
|
const cred = getCredential(endpoint);
|
|
6152
6180
|
if (!cred) {
|
|
6181
|
+
stdout.write(
|
|
6182
|
+
`${c2.bold}Machine:${c2.reset} ${os9.hostname()} ${c2.dim}(${identity.machine_id})${c2.reset}
|
|
6183
|
+
`
|
|
6184
|
+
);
|
|
6153
6185
|
stdout.write(`${c2.bold}Account:${c2.reset} ${c2.yellow}not signed in to ${endpoint}${c2.reset}
|
|
6154
6186
|
`);
|
|
6155
6187
|
return;
|
|
@@ -6157,6 +6189,10 @@ async function statusCommand() {
|
|
|
6157
6189
|
relaxTlsForLocalEndpoint(endpoint);
|
|
6158
6190
|
const api = new ApiClient(endpoint, cred.access_token);
|
|
6159
6191
|
const record = await loadMachine(api, identity.machine_id).catch(() => null);
|
|
6192
|
+
stdout.write(
|
|
6193
|
+
`${c2.bold}Machine:${c2.reset} ${machineDisplayName(record ?? { hostname: os9.hostname(), id: identity.machine_id })} ${c2.dim}(${identity.machine_id})${c2.reset}
|
|
6194
|
+
`
|
|
6195
|
+
);
|
|
6160
6196
|
if (!record) {
|
|
6161
6197
|
stdout.write(`${c2.bold}Registry:${c2.reset} not registered yet
|
|
6162
6198
|
`);
|
|
@@ -6187,9 +6223,11 @@ async function projectCommand(action, target) {
|
|
|
6187
6223
|
const endpoint = resolveEndpoint();
|
|
6188
6224
|
const api = await ensureSignedIn(endpoint);
|
|
6189
6225
|
const identity = loadMachineIdentity();
|
|
6226
|
+
const record = await loadMachine(api, identity.machine_id).catch(() => null);
|
|
6227
|
+
const displayName = machineDisplayName(record ?? { hostname: os9.hostname(), id: identity.machine_id });
|
|
6190
6228
|
if (action === "add") {
|
|
6191
6229
|
await registerProject(api, identity, dir2);
|
|
6192
|
-
stdout.write(`${c2.green}\u2713${c2.reset} Registered ${dir2} for remote sessions on ${
|
|
6230
|
+
stdout.write(`${c2.green}\u2713${c2.reset} Registered ${dir2} for remote sessions on ${displayName}.
|
|
6193
6231
|
`);
|
|
6194
6232
|
} else {
|
|
6195
6233
|
await unregisterProject(api, identity, dir2);
|
|
@@ -6907,6 +6945,12 @@ async function runInteractive(tui, api, threadId, projectDir, machine, resumed,
|
|
|
6907
6945
|
if (ownerDaemonMachine === session.identity.machine_id) claim = "takeover";
|
|
6908
6946
|
}
|
|
6909
6947
|
if (!remote) {
|
|
6948
|
+
const localDisplayName = machineDisplayName(
|
|
6949
|
+
await loadMachine(api, session.identity.machine_id).catch(() => null) ?? {
|
|
6950
|
+
hostname: machine,
|
|
6951
|
+
id: session.identity.machine_id
|
|
6952
|
+
}
|
|
6953
|
+
);
|
|
6910
6954
|
exec = new ExecutionSession({
|
|
6911
6955
|
api,
|
|
6912
6956
|
threadId,
|
|
@@ -6915,7 +6959,7 @@ async function runInteractive(tui, api, threadId, projectDir, machine, resumed,
|
|
|
6915
6959
|
perm,
|
|
6916
6960
|
identity: {
|
|
6917
6961
|
clientId: interactiveClientId(session.identity),
|
|
6918
|
-
clientName: `${
|
|
6962
|
+
clientName: `${localDisplayName} (terminal)`,
|
|
6919
6963
|
clientKind: "interactive",
|
|
6920
6964
|
claim
|
|
6921
6965
|
},
|
|
@@ -7726,24 +7770,27 @@ async function runMachinesMenu(tui, api, self) {
|
|
|
7726
7770
|
async function manageMachine(tui, api, self, machine) {
|
|
7727
7771
|
const isSelf = machine.id === self.machine_id;
|
|
7728
7772
|
const online = daemonOnline(machine);
|
|
7729
|
-
const
|
|
7773
|
+
const canRunCommands = isSelf || !!machine.daemon;
|
|
7774
|
+
const options = [
|
|
7775
|
+
{ label: "Rename", value: "rename" }
|
|
7776
|
+
];
|
|
7777
|
+
if (canRunCommands) {
|
|
7778
|
+
options.push(
|
|
7779
|
+
{ label: "Update standardcode", hint: `v${machine.version ?? "?"} \u2192 latest`, value: "update" },
|
|
7780
|
+
{ label: "Manage projects", hint: `${Object.keys(machine.projects).length}`, value: "projects" }
|
|
7781
|
+
);
|
|
7782
|
+
}
|
|
7783
|
+
options.push({ label: "Back", value: "back" });
|
|
7730
7784
|
if (!isSelf && !machine.daemon) {
|
|
7731
7785
|
tui.print(
|
|
7732
|
-
`${c3.
|
|
7786
|
+
`${c3.dim}${machine.name} has no daemon \u2014 you can rename it here; update and project changes need its daemon installed.${c3.reset}`
|
|
7733
7787
|
);
|
|
7734
|
-
|
|
7735
|
-
}
|
|
7736
|
-
if (remoteReachable && !online) {
|
|
7788
|
+
} else if (!isSelf && machine.daemon && !online) {
|
|
7737
7789
|
tui.print(
|
|
7738
7790
|
`${c3.dim}${machine.name}'s daemon is offline \u2014 queued changes apply when it next comes online.${c3.reset}`
|
|
7739
7791
|
);
|
|
7740
7792
|
}
|
|
7741
|
-
const action = await tui.select(`${c3.bold}${machine.name}${c3.reset}`,
|
|
7742
|
-
{ label: "Rename", value: "rename" },
|
|
7743
|
-
{ label: "Update standardcode", hint: `v${machine.version ?? "?"} \u2192 latest`, value: "update" },
|
|
7744
|
-
{ label: "Manage projects", hint: `${Object.keys(machine.projects).length}`, value: "projects" },
|
|
7745
|
-
{ label: "Back", value: "back" }
|
|
7746
|
-
]);
|
|
7793
|
+
const action = await tui.select(`${c3.bold}${machine.name}${c3.reset}`, options);
|
|
7747
7794
|
if (!action || action === "back") return;
|
|
7748
7795
|
const dispatch = async (kind, args) => {
|
|
7749
7796
|
if (isSelf) {
|
|
@@ -7755,9 +7802,9 @@ async function manageMachine(tui, api, self, machine) {
|
|
|
7755
7802
|
const applyNote = isSelf ? "applied" : `queued \u2014 ${machine.name}'s daemon will apply it within ~10s`;
|
|
7756
7803
|
if (action === "rename") {
|
|
7757
7804
|
const name = await tui.prompt(`New name for ${machine.name}`, machine.name);
|
|
7758
|
-
if (
|
|
7759
|
-
await
|
|
7760
|
-
tui.print(`${c3.green}\u2713${c3.reset}
|
|
7805
|
+
if (name === null || !name.trim()) return;
|
|
7806
|
+
await setMachineName(api, machine.id, name.trim());
|
|
7807
|
+
tui.print(`${c3.green}\u2713${c3.reset} Renamed ${c3.bold}${machine.name}${c3.reset} \u2192 ${c3.bold}${name.trim()}${c3.reset}.`);
|
|
7761
7808
|
} else if (action === "update") {
|
|
7762
7809
|
if (isSelf) {
|
|
7763
7810
|
await runUpdateCommand(tui);
|