@vendian/cli 0.0.10 → 0.0.12

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/cli-wrapper.mjs +618 -89
  2. package/package.json +1 -1
package/cli-wrapper.mjs CHANGED
@@ -24765,10 +24765,10 @@ var require_react_reconciler_development = __commonJS({
24765
24765
  var setErrorHandler = null;
24766
24766
  var setSuspenseHandler = null;
24767
24767
  {
24768
- var copyWithDeleteImpl = function(obj, path7, index2) {
24769
- var key = path7[index2];
24768
+ var copyWithDeleteImpl = function(obj, path8, index2) {
24769
+ var key = path8[index2];
24770
24770
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
24771
- if (index2 + 1 === path7.length) {
24771
+ if (index2 + 1 === path8.length) {
24772
24772
  if (isArray(updated)) {
24773
24773
  updated.splice(key, 1);
24774
24774
  } else {
@@ -24776,11 +24776,11 @@ var require_react_reconciler_development = __commonJS({
24776
24776
  }
24777
24777
  return updated;
24778
24778
  }
24779
- updated[key] = copyWithDeleteImpl(obj[key], path7, index2 + 1);
24779
+ updated[key] = copyWithDeleteImpl(obj[key], path8, index2 + 1);
24780
24780
  return updated;
24781
24781
  };
24782
- var copyWithDelete = function(obj, path7) {
24783
- return copyWithDeleteImpl(obj, path7, 0);
24782
+ var copyWithDelete = function(obj, path8) {
24783
+ return copyWithDeleteImpl(obj, path8, 0);
24784
24784
  };
24785
24785
  var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
24786
24786
  var oldKey = oldPath[index2];
@@ -24818,17 +24818,17 @@ var require_react_reconciler_development = __commonJS({
24818
24818
  }
24819
24819
  return copyWithRenameImpl(obj, oldPath, newPath, 0);
24820
24820
  };
24821
- var copyWithSetImpl = function(obj, path7, index2, value) {
24822
- if (index2 >= path7.length) {
24821
+ var copyWithSetImpl = function(obj, path8, index2, value) {
24822
+ if (index2 >= path8.length) {
24823
24823
  return value;
24824
24824
  }
24825
- var key = path7[index2];
24825
+ var key = path8[index2];
24826
24826
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
24827
- updated[key] = copyWithSetImpl(obj[key], path7, index2 + 1, value);
24827
+ updated[key] = copyWithSetImpl(obj[key], path8, index2 + 1, value);
24828
24828
  return updated;
24829
24829
  };
24830
- var copyWithSet = function(obj, path7, value) {
24831
- return copyWithSetImpl(obj, path7, 0, value);
24830
+ var copyWithSet = function(obj, path8, value) {
24831
+ return copyWithSetImpl(obj, path8, 0, value);
24832
24832
  };
24833
24833
  var findHook = function(fiber, id) {
24834
24834
  var currentHook2 = fiber.memoizedState;
@@ -24838,10 +24838,10 @@ var require_react_reconciler_development = __commonJS({
24838
24838
  }
24839
24839
  return currentHook2;
24840
24840
  };
24841
- overrideHookState = function(fiber, id, path7, value) {
24841
+ overrideHookState = function(fiber, id, path8, value) {
24842
24842
  var hook = findHook(fiber, id);
24843
24843
  if (hook !== null) {
24844
- var newState = copyWithSet(hook.memoizedState, path7, value);
24844
+ var newState = copyWithSet(hook.memoizedState, path8, value);
24845
24845
  hook.memoizedState = newState;
24846
24846
  hook.baseState = newState;
24847
24847
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -24851,10 +24851,10 @@ var require_react_reconciler_development = __commonJS({
24851
24851
  }
24852
24852
  }
24853
24853
  };
24854
- overrideHookStateDeletePath = function(fiber, id, path7) {
24854
+ overrideHookStateDeletePath = function(fiber, id, path8) {
24855
24855
  var hook = findHook(fiber, id);
24856
24856
  if (hook !== null) {
24857
- var newState = copyWithDelete(hook.memoizedState, path7);
24857
+ var newState = copyWithDelete(hook.memoizedState, path8);
24858
24858
  hook.memoizedState = newState;
24859
24859
  hook.baseState = newState;
24860
24860
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -24877,8 +24877,8 @@ var require_react_reconciler_development = __commonJS({
24877
24877
  }
24878
24878
  }
24879
24879
  };
24880
- overrideProps = function(fiber, path7, value) {
24881
- fiber.pendingProps = copyWithSet(fiber.memoizedProps, path7, value);
24880
+ overrideProps = function(fiber, path8, value) {
24881
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path8, value);
24882
24882
  if (fiber.alternate) {
24883
24883
  fiber.alternate.pendingProps = fiber.pendingProps;
24884
24884
  }
@@ -24887,8 +24887,8 @@ var require_react_reconciler_development = __commonJS({
24887
24887
  scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
24888
24888
  }
24889
24889
  };
24890
- overridePropsDeletePath = function(fiber, path7) {
24891
- fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path7);
24890
+ overridePropsDeletePath = function(fiber, path8) {
24891
+ fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path8);
24892
24892
  if (fiber.alternate) {
24893
24893
  fiber.alternate.pendingProps = fiber.pendingProps;
24894
24894
  }
@@ -32281,7 +32281,7 @@ var init_Text = __esm({
32281
32281
  });
32282
32282
 
32283
32283
  // node_modules/ink/build/components/ErrorOverview.js
32284
- import * as fs10 from "node:fs";
32284
+ import * as fs11 from "node:fs";
32285
32285
  import { cwd } from "node:process";
32286
32286
  function ErrorOverview({ error }) {
32287
32287
  const stack = error.stack ? error.stack.split("\n").slice(1) : void 0;
@@ -32289,8 +32289,8 @@ function ErrorOverview({ error }) {
32289
32289
  const filePath = cleanupPath(origin?.file);
32290
32290
  let excerpt;
32291
32291
  let lineWidth = 0;
32292
- if (filePath && origin?.line && fs10.existsSync(filePath)) {
32293
- const sourceCode = fs10.readFileSync(filePath, "utf8");
32292
+ if (filePath && origin?.line && fs11.existsSync(filePath)) {
32293
+ const sourceCode = fs11.readFileSync(filePath, "utf8");
32294
32294
  excerpt = dist_default3(sourceCode, origin.line);
32295
32295
  if (excerpt) {
32296
32296
  for (const { line } of excerpt) {
@@ -32385,8 +32385,8 @@ var init_ErrorOverview = __esm({
32385
32385
  init_dist3();
32386
32386
  init_Box();
32387
32387
  init_Text();
32388
- cleanupPath = (path7) => {
32389
- return path7?.replace(`file://${cwd()}/`, "");
32388
+ cleanupPath = (path8) => {
32389
+ return path8?.replace(`file://${cwd()}/`, "");
32390
32390
  };
32391
32391
  stackUtils = new import_stack_utils.default({
32392
32392
  cwd: cwd(),
@@ -36304,6 +36304,38 @@ function activeCloudAuthStatus({ env: env3 = process.env, platform: platform2 =
36304
36304
  profiles
36305
36305
  };
36306
36306
  }
36307
+ function activateCloudProfile({ backend, apiUrl, env: env3 = process.env, platform: platform2 = process.platform } = {}) {
36308
+ const targetApiUrl = resolveApiUrl({ backend, apiUrl, env: env3 });
36309
+ const config = loadCloudConfig(env3, platform2);
36310
+ const profiles = config.profiles && typeof config.profiles === "object" ? config.profiles : {};
36311
+ const profile = profiles[targetApiUrl];
36312
+ if (!profile || typeof profile !== "object" || !profile.access_token) {
36313
+ return {
36314
+ apiUrl: targetApiUrl,
36315
+ activeApiUrl: typeof config.active_api_url === "string" ? config.active_api_url : void 0,
36316
+ authenticated: false,
36317
+ activated: false,
36318
+ profiles
36319
+ };
36320
+ }
36321
+ const next = {
36322
+ ...config,
36323
+ version: config.version || 2,
36324
+ profiles,
36325
+ active_api_url: targetApiUrl
36326
+ };
36327
+ writeCloudConfig(next, { env: env3, platform: platform2 });
36328
+ return {
36329
+ apiUrl: targetApiUrl,
36330
+ activeApiUrl: targetApiUrl,
36331
+ profile,
36332
+ authenticated: true,
36333
+ activated: true,
36334
+ email: typeof profile.email === "string" ? profile.email : void 0,
36335
+ expiresAt: typeof profile.expires_at === "string" ? profile.expires_at : void 0,
36336
+ profiles
36337
+ };
36338
+ }
36307
36339
  async function getOAuthConfig(apiUrl, redirectUri) {
36308
36340
  const url = new URL(`${apiUrl}/api/v1/cli/auth/oauth/config`);
36309
36341
  url.searchParams.set("redirectUri", redirectUri);
@@ -36452,18 +36484,18 @@ function cloudConfigPath(env3 = process.env, platform2 = process.platform) {
36452
36484
  return path5.posix.join(root, "vendian", "cloud-auth.json");
36453
36485
  }
36454
36486
  function saveCloudToken(token, { env: env3 = process.env, platform: platform2 = process.platform } = {}) {
36455
- const file = cloudConfigPath(env3, platform2);
36487
+ const tokenApiUrl = String(token.apiUrl || "").replace(/\/$/, "");
36456
36488
  let raw = { version: 2, profiles: {}, active_api_url: token.apiUrl };
36457
36489
  try {
36458
- const existing = JSON.parse(fs6.readFileSync(file, "utf8"));
36490
+ const existing = loadCloudConfig(env3, platform2);
36459
36491
  if (existing && typeof existing === "object" && existing.profiles && typeof existing.profiles === "object") {
36460
36492
  raw.profiles = existing.profiles;
36461
36493
  }
36462
36494
  } catch {
36463
36495
  }
36464
- raw.active_api_url = token.apiUrl;
36465
- raw.profiles[token.apiUrl] = {
36466
- api_url: token.apiUrl,
36496
+ raw.active_api_url = tokenApiUrl;
36497
+ raw.profiles[tokenApiUrl] = {
36498
+ api_url: tokenApiUrl,
36467
36499
  access_token: token.accessToken,
36468
36500
  user_id: token.userId,
36469
36501
  email: token.email,
@@ -36471,6 +36503,10 @@ function saveCloudToken(token, { env: env3 = process.env, platform: platform2 =
36471
36503
  scopes: token.scopes,
36472
36504
  tooling_eligible: token.toolingEligible
36473
36505
  };
36506
+ return writeCloudConfig(raw, { env: env3, platform: platform2 });
36507
+ }
36508
+ function writeCloudConfig(raw, { env: env3 = process.env, platform: platform2 = process.platform } = {}) {
36509
+ const file = cloudConfigPath(env3, platform2);
36474
36510
  fs6.mkdirSync(path5.dirname(file), { recursive: true });
36475
36511
  fs6.writeFileSync(file, `${JSON.stringify(raw, null, 2)}
36476
36512
  `, { encoding: "utf8", mode: 384 });
@@ -36519,6 +36555,7 @@ async function setup({
36519
36555
  savePackageCredentials(next, packageCredentials, { platform: platform2 });
36520
36556
  }
36521
36557
  } else if (auth.authenticated) {
36558
+ activateCloudProfile({ backend, apiUrl, env: env3, platform: platform2 });
36522
36559
  console.log(`Cloud authentication already saved for ${auth.apiUrl}${auth.email ? ` (${auth.email})` : ""}.`);
36523
36560
  const refreshed = await refreshPackageAccessFromCloudAuth({ config: next, auth, env: env3, platform: platform2 });
36524
36561
  Object.assign(next, refreshed.config);
@@ -36738,11 +36775,11 @@ function maybeAutoUpdateManagedEnv({
36738
36775
  }
36739
36776
 
36740
36777
  // src/tui.js
36741
- import fs11 from "node:fs";
36778
+ import fs12 from "node:fs";
36742
36779
  import readlinePromises from "node:readline/promises";
36743
36780
 
36744
36781
  // src/version.js
36745
- var CLI_VERSION = true ? "0.0.10" : process.env.npm_package_version || "0.0.0-dev";
36782
+ var CLI_VERSION = true ? "0.0.12" : process.env.npm_package_version || "0.0.0-dev";
36746
36783
 
36747
36784
  // src/npm-update.js
36748
36785
  var NPM_CHECK_INTERVAL_MS = 30 * 60 * 1e3;
@@ -37094,6 +37131,7 @@ function initialServeState() {
37094
37131
  logs: [],
37095
37132
  agentLogs: {},
37096
37133
  // per-agent logs keyed by relativePath
37134
+ agentRunState: {},
37097
37135
  newAgents: [],
37098
37136
  stopped: false,
37099
37137
  jobsRun: 0
@@ -37147,9 +37185,15 @@ function applyServeEvent(state, event) {
37147
37185
  return { ...next, activity: `Preparing ${agentLabel(event)}` };
37148
37186
  }
37149
37187
  if (event.type === "agent_prepare_completed") {
37188
+ const runState = event.status === "error" ? setAgentRunState(state.agentRunState, agentLabel(event), {
37189
+ status: "error",
37190
+ lastEventAt: event.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
37191
+ errorMessage: stringValue(event.error || event.errorMessage || "Agent setup failed")
37192
+ }) : state.agentRunState;
37150
37193
  return {
37151
37194
  ...next,
37152
37195
  activity: `${agentLabel(event)} ${event.status === "error" ? "needs setup" : "ready"}`,
37196
+ agentRunState: runState,
37153
37197
  errors: event.error ? appendError(state.errors, agentLabel(event), event.error) : state.errors
37154
37198
  };
37155
37199
  }
@@ -37160,19 +37204,47 @@ function applyServeEvent(state, event) {
37160
37204
  ...next,
37161
37205
  agents,
37162
37206
  newAgents,
37207
+ agentRunState: reconcileInventoryRunState(state.agentRunState, agents, event.timestamp),
37163
37208
  activity: newAgents.length ? `${newAgents.length} new agent${newAgents.length === 1 ? "" : "s"} synced` : `Inventory synced (${Number(event.agentCount ?? agents.length ?? 0)} agent(s))`
37164
37209
  };
37165
37210
  }
37166
37211
  if (event.type === "job_started") {
37212
+ const relativePath = agentLabel(event);
37213
+ const timestamp = event.timestamp || (/* @__PURE__ */ new Date()).toISOString();
37167
37214
  return {
37168
37215
  ...next,
37216
+ agentLogs: appendAgentLog(state.agentLogs, event),
37217
+ agentRunState: setAgentRunState(state.agentRunState, relativePath, {
37218
+ status: "running",
37219
+ runId: stringValue(event.runId || event.deployRequestId),
37220
+ jobType: stringValue(event.jobType || "run"),
37221
+ startedAt: timestamp,
37222
+ completedAt: null,
37223
+ lastEventAt: timestamp,
37224
+ errorMessage: null
37225
+ }),
37169
37226
  currentJob: event,
37170
37227
  activity: `Running ${jobLabel(event)}`
37171
37228
  };
37172
37229
  }
37173
37230
  if (event.type === "job_completed") {
37231
+ const relativePath = agentLabel(event);
37232
+ const timestamp = event.timestamp || (/* @__PURE__ */ new Date()).toISOString();
37233
+ const success = event.success !== false;
37234
+ const runId = stringValue(event.runId || event.deployRequestId);
37235
+ const previous = (state.agentRunState || {})[relativePath];
37236
+ const effectiveSuccess = success && !(previous?.status === "error" && previous?.runId === runId);
37174
37237
  return {
37175
37238
  ...next,
37239
+ agentLogs: appendAgentLog(state.agentLogs, event),
37240
+ agentRunState: setAgentRunState(state.agentRunState, relativePath, {
37241
+ status: effectiveSuccess ? "completed" : "error",
37242
+ runId,
37243
+ jobType: stringValue(event.jobType || "run"),
37244
+ completedAt: timestamp,
37245
+ lastEventAt: timestamp,
37246
+ errorMessage: effectiveSuccess ? null : previous?.errorMessage || stringValue(event.error || "Job failed")
37247
+ }),
37176
37248
  jobsRun: state.jobsRun + 1,
37177
37249
  currentJob: null,
37178
37250
  activity: `${jobLabel(event)} completed`
@@ -37188,8 +37260,20 @@ function applyServeEvent(state, event) {
37188
37260
  return { ...next, retry: event, activity: `Retrying ${stringValue(event.activity)} in ${formatSeconds(event.delaySeconds)}` };
37189
37261
  }
37190
37262
  if (event.type === "error") {
37263
+ const relativePath = event.relativePath || event.path ? agentLabel(event) : "";
37264
+ const timestamp = event.timestamp || (/* @__PURE__ */ new Date()).toISOString();
37265
+ const hasAgentScope = Boolean(relativePath);
37191
37266
  return {
37192
37267
  ...next,
37268
+ agentLogs: hasAgentScope ? appendAgentLog(state.agentLogs, event) : state.agentLogs,
37269
+ agentRunState: hasAgentScope ? setAgentRunState(state.agentRunState, relativePath, {
37270
+ status: "error",
37271
+ runId: stringValue(event.runId || event.deployRequestId),
37272
+ jobType: stringValue(event.jobType || "run"),
37273
+ completedAt: timestamp,
37274
+ lastEventAt: timestamp,
37275
+ errorMessage: stringValue(event.error || event.code || "Unknown error")
37276
+ }) : state.agentRunState,
37193
37277
  activity: "Error",
37194
37278
  errors: appendError(state.errors, jobLabel(event), event.error || event.code || "Unknown error")
37195
37279
  };
@@ -37205,9 +37289,21 @@ function applyServeEvent(state, event) {
37205
37289
  };
37206
37290
  }
37207
37291
  if (event.type === "run_log") {
37292
+ const entry = serveEventAgentLogEntry(event);
37293
+ const nextRunState = entry && entry.entry.eventType === "completion" ? setAgentRunState(state.agentRunState, entry.relativePath, {
37294
+ status: entry.entry.success === false ? "error" : "completed",
37295
+ runId: entry.entry.runId,
37296
+ completedAt: entry.entry.timestamp,
37297
+ lastEventAt: entry.entry.timestamp,
37298
+ errorMessage: entry.entry.success === false ? formatErrorMessage(entry.entry.error) : null
37299
+ }) : entry ? setAgentRunState(state.agentRunState, entry.relativePath, {
37300
+ runId: entry.entry.runId,
37301
+ lastEventAt: entry.entry.timestamp
37302
+ }) : state.agentRunState;
37208
37303
  return {
37209
37304
  ...next,
37210
- agentLogs: appendAgentLog(state.agentLogs, event)
37305
+ agentLogs: appendAgentLog(state.agentLogs, event),
37306
+ agentRunState: nextRunState
37211
37307
  };
37212
37308
  }
37213
37309
  return next;
@@ -37232,31 +37328,240 @@ function appendLog(logs, event) {
37232
37328
  return [...logs, event].slice(-200);
37233
37329
  }
37234
37330
  function appendAgentLog(agentLogs, event) {
37235
- const key = stringValue(event.relativePath || ".");
37331
+ const normalized = serveEventAgentLogEntry(event);
37332
+ if (!normalized) {
37333
+ return agentLogs || {};
37334
+ }
37335
+ const key = normalized.relativePath;
37236
37336
  const existing = agentLogs[key] || [];
37237
- const entry = {
37238
- timestamp: event.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
37239
- runId: stringValue(event.runId),
37240
- eventType: stringValue(event.eventType),
37241
- level: stringValue(event.level || "info"),
37242
- message: stringValue(event.message),
37243
- stepId: event.stepId ? stringValue(event.stepId) : null,
37244
- current: event.current ?? null,
37245
- total: event.total ?? null,
37246
- success: event.success ?? null,
37247
- error: event.error ?? null
37248
- };
37249
37337
  return {
37250
37338
  ...agentLogs,
37251
- [key]: [...existing, entry].slice(-100)
37339
+ [key]: [...existing, normalized.entry].slice(-5e3)
37252
37340
  };
37253
37341
  }
37254
37342
  function agentLogEntries(agentLogs, relativePath) {
37255
37343
  return (agentLogs || {})[relativePath] || [];
37256
37344
  }
37345
+ function mergeAgentLogRecords(agentLogs, records = []) {
37346
+ let next = agentLogs || {};
37347
+ for (const record of records) {
37348
+ if (!record || typeof record !== "object") continue;
37349
+ const relativePath = stringValue(record.relativePath || ".");
37350
+ const entry = record.entry && typeof record.entry === "object" ? record.entry : record;
37351
+ const existing = next[relativePath] || [];
37352
+ next = {
37353
+ ...next,
37354
+ [relativePath]: [...existing, normalizeStoredAgentLogEntry(entry)].slice(-5e3)
37355
+ };
37356
+ }
37357
+ return next;
37358
+ }
37359
+ function agentRunStateFromLogs(agentLogs, { includeRunning = true } = {}) {
37360
+ let next = {};
37361
+ for (const [relativePath, entries] of Object.entries(agentLogs || {})) {
37362
+ for (const entry of entries || []) {
37363
+ const timestamp = entry.timestamp || (/* @__PURE__ */ new Date()).toISOString();
37364
+ const runId = stringValue(entry.runId);
37365
+ const current = next[relativePath] || {};
37366
+ if (entry.eventType === "job_started") {
37367
+ next = setAgentRunState(next, relativePath, {
37368
+ status: includeRunning ? "running" : current.status,
37369
+ runId,
37370
+ jobType: entry.jobType ? stringValue(entry.jobType) : current.jobType,
37371
+ startedAt: timestamp,
37372
+ lastEventAt: timestamp
37373
+ });
37374
+ continue;
37375
+ }
37376
+ if (entry.eventType === "completion" || entry.eventType === "job_completed") {
37377
+ const failed = entry.success === false || current.status === "error" && current.runId === runId;
37378
+ next = setAgentRunState(next, relativePath, {
37379
+ status: failed ? "error" : "completed",
37380
+ runId,
37381
+ jobType: entry.jobType ? stringValue(entry.jobType) : current.jobType,
37382
+ completedAt: timestamp,
37383
+ lastEventAt: timestamp,
37384
+ errorMessage: failed ? formatErrorMessage(entry.error) || current.errorMessage || stringValue(entry.message || "Job failed") : null
37385
+ });
37386
+ continue;
37387
+ }
37388
+ if (entry.eventType === "error" || entry.level === "error" && entry.success === false) {
37389
+ next = setAgentRunState(next, relativePath, {
37390
+ status: "error",
37391
+ runId,
37392
+ jobType: entry.jobType ? stringValue(entry.jobType) : current.jobType,
37393
+ completedAt: timestamp,
37394
+ lastEventAt: timestamp,
37395
+ errorMessage: formatErrorMessage(entry.error) || stringValue(entry.message || "Job failed")
37396
+ });
37397
+ continue;
37398
+ }
37399
+ if (runId || timestamp) {
37400
+ next = setAgentRunState(next, relativePath, {
37401
+ runId: runId || current.runId,
37402
+ lastEventAt: timestamp
37403
+ });
37404
+ }
37405
+ }
37406
+ }
37407
+ return next;
37408
+ }
37409
+ function serveEventAgentLogEntry(event) {
37410
+ if (!event || typeof event !== "object") {
37411
+ return null;
37412
+ }
37413
+ const type = stringValue(event.type);
37414
+ const relativePath = stringValue(event.relativePath || event.path || ".");
37415
+ const timestamp = event.timestamp || (/* @__PURE__ */ new Date()).toISOString();
37416
+ if (type === "run_log") {
37417
+ return {
37418
+ relativePath,
37419
+ entry: {
37420
+ timestamp,
37421
+ runId: stringValue(event.runId),
37422
+ eventType: stringValue(event.eventType || "log"),
37423
+ level: stringValue(event.level || "info"),
37424
+ message: stringValue(event.message),
37425
+ stepId: event.stepId ? stringValue(event.stepId) : null,
37426
+ current: event.current ?? null,
37427
+ total: event.total ?? null,
37428
+ success: event.success ?? null,
37429
+ error: event.error ?? null,
37430
+ jobType: event.jobType ? stringValue(event.jobType) : null
37431
+ }
37432
+ };
37433
+ }
37434
+ if (type === "job_started") {
37435
+ const jobType = stringValue(event.jobType || "run");
37436
+ return {
37437
+ relativePath,
37438
+ entry: {
37439
+ timestamp,
37440
+ runId: stringValue(event.runId || event.deployRequestId),
37441
+ eventType: "job_started",
37442
+ level: "info",
37443
+ message: `Started ${jobType}`,
37444
+ stepId: null,
37445
+ current: null,
37446
+ total: null,
37447
+ success: null,
37448
+ error: null,
37449
+ jobType
37450
+ }
37451
+ };
37452
+ }
37453
+ if (type === "job_completed") {
37454
+ const success = event.success !== false;
37455
+ const jobType = stringValue(event.jobType || "run");
37456
+ return {
37457
+ relativePath,
37458
+ entry: {
37459
+ timestamp,
37460
+ runId: stringValue(event.runId || event.deployRequestId),
37461
+ eventType: "job_completed",
37462
+ level: success ? "info" : "error",
37463
+ message: success ? "Completed successfully" : stringValue(event.error || "Failed"),
37464
+ stepId: null,
37465
+ current: null,
37466
+ total: null,
37467
+ success,
37468
+ error: event.error ?? null,
37469
+ jobType
37470
+ }
37471
+ };
37472
+ }
37473
+ if (type === "error" && (event.relativePath || event.path)) {
37474
+ return {
37475
+ relativePath,
37476
+ entry: {
37477
+ timestamp,
37478
+ runId: stringValue(event.runId || event.deployRequestId),
37479
+ eventType: "error",
37480
+ level: "error",
37481
+ message: stringValue(event.error || event.code || "Unknown error"),
37482
+ stepId: null,
37483
+ current: null,
37484
+ total: null,
37485
+ success: false,
37486
+ error: event.error ?? event.code ?? null,
37487
+ jobType: event.jobType ? stringValue(event.jobType) : null
37488
+ }
37489
+ };
37490
+ }
37491
+ return null;
37492
+ }
37493
+ function agentRuntimeStatus(agent, agentRunState = {}) {
37494
+ const path8 = stringValue(agent?.relativePath || ".");
37495
+ const run2 = (agentRunState || {})[path8];
37496
+ const inventoryStatus = stringValue(agent?.status);
37497
+ if (run2?.status === "running") {
37498
+ return { status: "running", label: "running", run: run2 };
37499
+ }
37500
+ if (run2?.status === "error" || inventoryStatus === "error") {
37501
+ return { status: "error", label: "error", run: run2 };
37502
+ }
37503
+ if (inventoryStatus === "online") {
37504
+ return { status: run2?.status === "completed" ? "completed" : "ready", label: "ready", run: run2 };
37505
+ }
37506
+ if (run2?.status === "completed") {
37507
+ return { status: "completed", label: "ready", run: run2 };
37508
+ }
37509
+ return { status: inventoryStatus || "unknown", label: inventoryStatus || "unknown", run: run2 };
37510
+ }
37257
37511
  function appendError(errors, scope, message) {
37258
37512
  return [...errors, { scope, message: stringValue(message) }].slice(-20);
37259
37513
  }
37514
+ function setAgentRunState(agentRunState, relativePath, patch) {
37515
+ const key = stringValue(relativePath || ".");
37516
+ return {
37517
+ ...agentRunState || {},
37518
+ [key]: {
37519
+ ...(agentRunState || {})[key] || {},
37520
+ ...patch
37521
+ }
37522
+ };
37523
+ }
37524
+ function reconcileInventoryRunState(agentRunState, agents, timestamp) {
37525
+ let next = agentRunState || {};
37526
+ for (const agent of agents || []) {
37527
+ const path8 = stringValue(agent?.relativePath || ".");
37528
+ const current = next[path8];
37529
+ if (agent?.status === "error") {
37530
+ next = setAgentRunState(next, path8, {
37531
+ status: "error",
37532
+ lastEventAt: timestamp || (/* @__PURE__ */ new Date()).toISOString(),
37533
+ errorMessage: stringValue(agent.errorMessage || agent.error || "Agent setup failed")
37534
+ });
37535
+ } else if (agent?.status === "online" && current?.status === "error" && !current?.runId) {
37536
+ next = setAgentRunState(next, path8, {
37537
+ status: "ready",
37538
+ lastEventAt: timestamp || (/* @__PURE__ */ new Date()).toISOString(),
37539
+ errorMessage: null
37540
+ });
37541
+ }
37542
+ }
37543
+ return next;
37544
+ }
37545
+ function normalizeStoredAgentLogEntry(entry) {
37546
+ return {
37547
+ timestamp: entry.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
37548
+ runId: stringValue(entry.runId),
37549
+ eventType: stringValue(entry.eventType || "log"),
37550
+ level: stringValue(entry.level || "info"),
37551
+ message: stringValue(entry.message),
37552
+ stepId: entry.stepId ? stringValue(entry.stepId) : null,
37553
+ current: entry.current ?? null,
37554
+ total: entry.total ?? null,
37555
+ success: entry.success ?? null,
37556
+ error: entry.error ?? null,
37557
+ jobType: entry.jobType ? stringValue(entry.jobType) : null
37558
+ };
37559
+ }
37560
+ function formatErrorMessage(error) {
37561
+ if (!error) return null;
37562
+ if (typeof error === "object") return stringValue(error.message || "error");
37563
+ return stringValue(error);
37564
+ }
37260
37565
  function findNewAgents(previous, next) {
37261
37566
  const seen = new Set(previous.map(agentKey).filter(Boolean));
37262
37567
  return next.filter((agent) => {
@@ -37314,6 +37619,114 @@ function buildLocalServeEventStreamArgs({ agentsDir = "./agents", collectionId =
37314
37619
  return args;
37315
37620
  }
37316
37621
 
37622
+ // src/serve-log-store.js
37623
+ import crypto2 from "node:crypto";
37624
+ import fs10 from "node:fs";
37625
+ import path7 from "node:path";
37626
+ var MAX_EVENTS = 5e3;
37627
+ var MAX_RUNS = 50;
37628
+ function createServeLogStore({
37629
+ agentsDir = "./agents",
37630
+ collectionId = "",
37631
+ env: env3 = process.env,
37632
+ platform: platform2 = process.platform
37633
+ } = {}) {
37634
+ const file = serveLogFilePath({ agentsDir, collectionId, env: env3, platform: platform2 });
37635
+ let appendCount = 0;
37636
+ return {
37637
+ file,
37638
+ load() {
37639
+ return readServeLogRecords(file);
37640
+ },
37641
+ append(event) {
37642
+ const normalized = serveEventAgentLogEntry(event);
37643
+ if (!normalized) {
37644
+ return false;
37645
+ }
37646
+ fs10.mkdirSync(path7.dirname(file), { recursive: true });
37647
+ const record = {
37648
+ version: 1,
37649
+ collectionId: collectionId || "",
37650
+ agentsDir: String(agentsDir || "./agents"),
37651
+ relativePath: normalized.relativePath,
37652
+ entry: normalized.entry
37653
+ };
37654
+ fs10.appendFileSync(file, `${JSON.stringify(record)}
37655
+ `, "utf8");
37656
+ appendCount += 1;
37657
+ if (appendCount % 50 === 0) {
37658
+ compactServeLogFile(file);
37659
+ }
37660
+ return true;
37661
+ },
37662
+ compact() {
37663
+ compactServeLogFile(file);
37664
+ }
37665
+ };
37666
+ }
37667
+ function serveLogFilePath({
37668
+ agentsDir = "./agents",
37669
+ collectionId = "",
37670
+ env: env3 = process.env,
37671
+ platform: platform2 = process.platform
37672
+ } = {}) {
37673
+ const root = vendianHome(env3, platform2);
37674
+ const resolvedAgentsDir = path7.resolve(String(agentsDir || "./agents"));
37675
+ const hash = crypto2.createHash("sha256").update(`${collectionId || "default"}\0${resolvedAgentsDir}`).digest("hex").slice(0, 16);
37676
+ return path7.join(root, "serve-logs", `${safePathPart(collectionId || "default")}-${hash}.jsonl`);
37677
+ }
37678
+ function readServeLogRecords(file) {
37679
+ if (!file || !fs10.existsSync(file)) {
37680
+ return [];
37681
+ }
37682
+ const records = [];
37683
+ const lines = fs10.readFileSync(file, "utf8").split(/\r?\n/);
37684
+ for (const line of lines) {
37685
+ const value = line.trim();
37686
+ if (!value) continue;
37687
+ try {
37688
+ const record = JSON.parse(value);
37689
+ if (record && typeof record === "object" && record.entry && record.relativePath) {
37690
+ records.push({ relativePath: String(record.relativePath), entry: record.entry });
37691
+ }
37692
+ } catch {
37693
+ }
37694
+ }
37695
+ return trimServeLogRecords(records);
37696
+ }
37697
+ function compactServeLogFile(file) {
37698
+ if (!file || !fs10.existsSync(file)) {
37699
+ return;
37700
+ }
37701
+ const records = readServeLogRecords(file);
37702
+ const tmp = `${file}.tmp`;
37703
+ fs10.writeFileSync(
37704
+ tmp,
37705
+ records.map((record) => JSON.stringify({ version: 1, ...record })).join("\n") + (records.length ? "\n" : ""),
37706
+ "utf8"
37707
+ );
37708
+ fs10.renameSync(tmp, file);
37709
+ }
37710
+ function trimServeLogRecords(records) {
37711
+ const runIds = [];
37712
+ const seen = /* @__PURE__ */ new Set();
37713
+ for (const record of records) {
37714
+ const runId = String(record.entry?.runId || "");
37715
+ if (runId && !seen.has(runId)) {
37716
+ seen.add(runId);
37717
+ runIds.push(runId);
37718
+ }
37719
+ }
37720
+ const keepRuns = new Set(runIds.slice(-MAX_RUNS));
37721
+ return records.filter((record) => {
37722
+ const runId = String(record.entry?.runId || "");
37723
+ return !runId || keepRuns.has(runId);
37724
+ }).slice(-MAX_EVENTS);
37725
+ }
37726
+ function safePathPart(value) {
37727
+ return String(value || "default").replace(/[^a-zA-Z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "default";
37728
+ }
37729
+
37317
37730
  // src/workspaces.js
37318
37731
  async function listCloudWorkspaces({
37319
37732
  env: env3 = process.env,
@@ -37554,11 +37967,40 @@ function endpointRows({ env: env3 = process.env, platform: platform2 = process.p
37554
37967
  };
37555
37968
  });
37556
37969
  }
37970
+ async function switchOrLoginEndpoint({
37971
+ backend,
37972
+ apiUrl,
37973
+ env: env3 = process.env,
37974
+ platform: platform2 = process.platform,
37975
+ setupFn = setup,
37976
+ activateFn = activateCloudProfile
37977
+ } = {}) {
37978
+ const status = cloudAuthStatus({ backend, apiUrl, env: env3, platform: platform2 });
37979
+ if (status.authenticated) {
37980
+ const activated = activateFn({ backend, apiUrl, env: env3, platform: platform2 });
37981
+ return { apiUrl: status.apiUrl, reused: true, activated: Boolean(activated?.activated) };
37982
+ }
37983
+ await setupFn({ backend, apiUrl, forceAuth: true, env: env3, platform: platform2 });
37984
+ return { apiUrl: status.apiUrl, reused: false, activated: true };
37985
+ }
37986
+ function endpointErrorStatus(error) {
37987
+ const message = error && typeof error.message === "string" ? error.message : String(error || "Connection failed");
37988
+ return `${fig.cross} ${message}`;
37989
+ }
37990
+ function endpointStatusColor(status) {
37991
+ if (status.includes(fig.check)) {
37992
+ return colors.success;
37993
+ }
37994
+ if (status.includes(fig.cross)) {
37995
+ return colors.error;
37996
+ }
37997
+ return colors.muted;
37998
+ }
37557
37999
  function runtimeSummary({ env: env3 = process.env, platform: platform2 = process.platform, now = Date.now() } = {}) {
37558
38000
  const config = loadConfig(env3, platform2);
37559
38001
  const venvPath = managedVenvPath(env3, platform2);
37560
38002
  const vendianPath = venvVendian(venvPath, platform2);
37561
- const installed = fs11.existsSync(vendianPath);
38003
+ const installed = fs12.existsSync(vendianPath);
37562
38004
  const lastUpdate = Date.parse(config.lastManagedUpdateAt || "");
37563
38005
  const stale = !Number.isFinite(lastUpdate) || now - lastUpdate > 24 * 60 * 60 * 1e3;
37564
38006
  return {
@@ -37793,8 +38235,12 @@ function ConnectScreen({ env: env3, platform: platform2, onBack }) {
37793
38235
  return;
37794
38236
  }
37795
38237
  setStatus(`Connecting to ${value}...`);
37796
- await setup({ backend: value, forceAuth: true, env: env3, platform: platform2 });
37797
- setStatus(`${fig.check} Connected`);
38238
+ try {
38239
+ await switchOrLoginEndpoint({ backend: value, env: env3, platform: platform2 });
38240
+ setStatus(`${fig.check} Connected`);
38241
+ } catch (error) {
38242
+ setStatus(endpointErrorStatus(error));
38243
+ }
37798
38244
  }
37799
38245
  if (mode === "custom") {
37800
38246
  return h(
@@ -37809,11 +38255,15 @@ function ConnectScreen({ env: env3, platform: platform2, onBack }) {
37809
38255
  onSubmit: async (value) => {
37810
38256
  if (!value) return;
37811
38257
  setStatus("Connecting...");
37812
- await setup({ apiUrl: value, forceAuth: true, env: env3, platform: platform2 });
37813
- setStatus(`${fig.check} Connected`);
38258
+ try {
38259
+ await switchOrLoginEndpoint({ apiUrl: value, env: env3, platform: platform2 });
38260
+ setStatus(`${fig.check} Connected`);
38261
+ } catch (error) {
38262
+ setStatus(endpointErrorStatus(error));
38263
+ }
37814
38264
  }
37815
38265
  }),
37816
- status && h(Text2, { color: status.includes(fig.check) ? colors.success : colors.muted }, ` ${status}`),
38266
+ status && h(Text2, { color: endpointStatusColor(status) }, ` ${status}`),
37817
38267
  h(Text2, null, ""),
37818
38268
  h(FooterBar, { items: [{ key: "\u23CE", label: "Submit" }, { key: "esc", label: "Back" }] }),
37819
38269
  h(BackHint, { onBack })
@@ -37825,7 +38275,7 @@ function ConnectScreen({ env: env3, platform: platform2, onBack }) {
37825
38275
  h(Text2, { bold: true }, " Select environment:"),
37826
38276
  h(Text2, null, ""),
37827
38277
  h(SelectInput2, { items, onSelect: (item) => connect(item.value) }),
37828
- status && h(Text2, { color: status.includes(fig.check) ? colors.success : colors.muted }, ` ${status}`),
38278
+ status && h(Text2, { color: endpointStatusColor(status) }, ` ${status}`),
37829
38279
  h(Text2, null, ""),
37830
38280
  h(FooterBar, { items: [{ key: "\u2191\u2193", label: "Navigate" }, { key: "\u23CE", label: "Select" }, { key: "esc", label: "Back" }] })
37831
38281
  );
@@ -37969,11 +38419,26 @@ function ServeScreen({ env: env3, platform: platform2, input, onBack, onState, o
37969
38419
  setStarted(true);
37970
38420
  setStartupError("");
37971
38421
  try {
38422
+ const logStore = createServeLogStore({ agentsDir: serveRoot, collectionId, env: env3, platform: platform2 });
38423
+ const historicalLogs = logStore.load();
38424
+ if (historicalLogs.length > 0) {
38425
+ setState((current) => {
38426
+ const agentLogs = mergeAgentLogRecords(current.agentLogs, historicalLogs);
38427
+ return {
38428
+ ...current,
38429
+ agentLogs,
38430
+ agentRunState: {
38431
+ ...agentRunStateFromLogs(agentLogs, { includeRunning: false }),
38432
+ ...current.agentRunState
38433
+ }
38434
+ };
38435
+ });
38436
+ }
37972
38437
  const nextChild = await spawnLocalServeEventStream({ agentsDir: serveRoot, collectionId, env: env3, platform: platform2 });
37973
38438
  setChild(nextChild);
37974
38439
  attachServeChild(nextChild, setState, setStartupError, ({ message } = {}) => {
37975
38440
  setState((current) => current.stopped ? current : { ...current, stopped: true, activity: message ? "Runtime update required" : "Process exited" });
37976
- });
38441
+ }, logStore);
37977
38442
  } catch (error) {
37978
38443
  setStartupError(errorMessage2(error));
37979
38444
  }
@@ -38089,8 +38554,9 @@ function ServeScreen({ env: env3, platform: platform2, input, onBack, onState, o
38089
38554
  h(AgentLogViewer, {
38090
38555
  agents: state.agents,
38091
38556
  agentLogs: state.agentLogs,
38557
+ agentRunState: state.agentRunState,
38092
38558
  logMode,
38093
- onSelectAgent: (path7) => setLogMode(path7),
38559
+ onSelectAgent: (path8) => setLogMode(path8),
38094
38560
  onBack: () => {
38095
38561
  if (logMode === "picker") {
38096
38562
  setLogMode(null);
@@ -38127,7 +38593,7 @@ function ServeScreen({ env: env3, platform: platform2, input, onBack, onState, o
38127
38593
  { color: colors.success },
38128
38594
  ` ${fig.check} New agents synced automatically: ${state.newAgents.map((agent) => agent.relativePath || agent.manifestName || agent.path || "agent").join(", ")}`
38129
38595
  ),
38130
- h(AgentTable, { agents: state.agents }),
38596
+ h(AgentTable, { agents: state.agents, agentRunState: state.agentRunState }),
38131
38597
  state.retry && h(Text2, { color: colors.warning }, ` ${fig.warning} Retry: ${state.retry.activity} in ${Number(state.retry.delaySeconds || 0).toFixed(1)}s`),
38132
38598
  state.errors.length > 0 && h(
38133
38599
  Box2,
@@ -38150,7 +38616,7 @@ function ServeScreen({ env: env3, platform: platform2, input, onBack, onState, o
38150
38616
  exitArmed && h(Text2, { color: colors.warning, bold: true }, " Press Ctrl+C again to exit.")
38151
38617
  );
38152
38618
  }
38153
- function AgentTable({ agents }) {
38619
+ function AgentTable({ agents, agentRunState = {} }) {
38154
38620
  if (!agents.length) {
38155
38621
  return h(Text2, { color: colors.muted }, ` ${fig.dotEmpty} No agents discovered yet.`);
38156
38622
  }
@@ -38162,17 +38628,18 @@ function AgentTable({ agents }) {
38162
38628
  const headerLine = ` ${"Path".padEnd(pathW)} ${"Name".padEnd(nameW)} ${"Creds".padEnd(credW)} ${"Status".padEnd(statusW)}`;
38163
38629
  const separator = ` ${fig.horizontal.repeat(pathW + nameW + credW + statusW + 3)}`;
38164
38630
  const rows = agents.slice(0, 16).map((agent) => {
38165
- const path7 = clip(agent.relativePath || ".", pathW);
38631
+ const path8 = clip(agent.relativePath || ".", pathW);
38166
38632
  const name = clip(agent.manifestName || agent.manifest?.name || "-", nameW);
38167
38633
  const creds = credentialLabel(agent);
38168
- const status = String(agent.status || "-");
38169
- const statusColor = status === "online" ? colors.success : status === "error" ? colors.error : colors.warning;
38170
- const statusIcon = status === "online" ? fig.dot : status === "error" ? fig.cross : fig.dotEmpty;
38634
+ const runtime = agentRuntimeStatus(agent, agentRunState);
38635
+ const status = runtime.label || "-";
38636
+ const statusColor = runtimeStatusColor(runtime.status);
38637
+ const statusIcon = runtimeStatusIcon(runtime.status);
38171
38638
  return h(
38172
38639
  Text2,
38173
38640
  { key: agent.localAgentId || agent.relativePath },
38174
38641
  h(Text2, { color: colors.muted }, " "),
38175
- h(Text2, null, path7.padEnd(pathW)),
38642
+ h(Text2, null, path8.padEnd(pathW)),
38176
38643
  h(Text2, null, " "),
38177
38644
  h(Text2, null, name.padEnd(nameW)),
38178
38645
  h(Text2, null, " "),
@@ -38191,6 +38658,18 @@ function AgentTable({ agents }) {
38191
38658
  hiddenCount > 0 && h(Text2, { color: colors.muted }, ` ${fig.ellipsis} and ${hiddenCount} more`)
38192
38659
  );
38193
38660
  }
38661
+ function runtimeStatusColor(status) {
38662
+ if (status === "running") return colors.accent;
38663
+ if (status === "ready" || status === "completed") return colors.success;
38664
+ if (status === "error") return colors.error;
38665
+ return colors.warning;
38666
+ }
38667
+ function runtimeStatusIcon(status) {
38668
+ if (status === "running") return fig.arrow;
38669
+ if (status === "ready" || status === "completed") return fig.dot;
38670
+ if (status === "error") return fig.cross;
38671
+ return fig.dotEmpty;
38672
+ }
38194
38673
  function FooterBar({ items }) {
38195
38674
  if (!items || !items.length) return null;
38196
38675
  return h(
@@ -38204,39 +38683,39 @@ function FooterBar({ items }) {
38204
38683
  ]).flat().filter(Boolean)
38205
38684
  );
38206
38685
  }
38207
- function AgentLogViewer({ agents, agentLogs, logMode, onSelectAgent, onBack }) {
38686
+ function AgentLogViewer({ agents, agentLogs, agentRunState, logMode, onSelectAgent, onBack }) {
38208
38687
  if (logMode === "picker") {
38209
- return h(AgentLogPicker, { agents, agentLogs, onSelectAgent, onBack });
38688
+ return h(AgentLogPicker, { agents, agentLogs, agentRunState, onSelectAgent, onBack });
38210
38689
  }
38211
- return h(AgentLogDetail, { relativePath: logMode, agentLogs, agents, onBack });
38690
+ return h(AgentLogDetail, { relativePath: logMode, agentLogs, agentRunState, agents, onBack });
38212
38691
  }
38213
- function AgentLogPicker({ agents, agentLogs, onSelectAgent, onBack }) {
38692
+ function AgentLogPicker({ agents, agentLogs, agentRunState = {}, onSelectAgent, onBack }) {
38214
38693
  const [selectedIndex, setSelectedIndex] = useState5(0);
38215
38694
  const agentList = agents.map((agent) => {
38216
- const path7 = agent.relativePath || ".";
38217
- const logs = agentLogEntries(agentLogs, path7);
38695
+ const path8 = agent.relativePath || ".";
38696
+ const logs = agentLogEntries(agentLogs, path8);
38218
38697
  const lastLog = logs.length > 0 ? logs[logs.length - 1] : null;
38219
38698
  const hasErrors = logs.some((l) => l.level === "error" || l.eventType === "completion" && l.success === false);
38220
38699
  return {
38221
- path: path7,
38222
- name: agent.manifestName || agent.manifest?.name || path7,
38700
+ path: path8,
38701
+ name: agent.manifestName || agent.manifest?.name || path8,
38223
38702
  logCount: logs.length,
38224
38703
  lastLog,
38225
38704
  hasErrors,
38226
- status: agent.status || "-"
38705
+ status: agentRuntimeStatus(agent, agentRunState)
38227
38706
  };
38228
38707
  });
38229
38708
  const inventoryPaths = new Set(agentList.map((a) => a.path));
38230
- for (const path7 of Object.keys(agentLogs || {})) {
38231
- if (!inventoryPaths.has(path7)) {
38232
- const logs = agentLogEntries(agentLogs, path7);
38709
+ for (const path8 of Object.keys(agentLogs || {})) {
38710
+ if (!inventoryPaths.has(path8)) {
38711
+ const logs = agentLogEntries(agentLogs, path8);
38233
38712
  agentList.push({
38234
- path: path7,
38235
- name: path7,
38713
+ path: path8,
38714
+ name: path8,
38236
38715
  logCount: logs.length,
38237
38716
  lastLog: logs.length > 0 ? logs[logs.length - 1] : null,
38238
38717
  hasErrors: logs.some((l) => l.level === "error"),
38239
- status: "offline"
38718
+ status: { status: "unknown", label: "offline" }
38240
38719
  });
38241
38720
  }
38242
38721
  }
@@ -38265,14 +38744,15 @@ function AgentLogPicker({ agents, agentLogs, onSelectAgent, onBack }) {
38265
38744
  );
38266
38745
  }
38267
38746
  const pathW = 24;
38268
- const nameW = 26;
38747
+ const nameW = 24;
38748
+ const statusW = 10;
38269
38749
  return h(
38270
38750
  Box2,
38271
38751
  { flexDirection: "column" },
38272
38752
  h(Text2, { bold: true, color: colors.brand }, ` ${fig.horizontal.repeat(3)} Agent Logs ${fig.horizontal.repeat(20)}`),
38273
38753
  h(Text2, null, ""),
38274
- h(Text2, { color: colors.muted }, ` ${"Agent".padEnd(nameW)} ${"Logs".padEnd(6)} ${"Last event"}`),
38275
- h(Text2, { color: colors.muted }, ` ${fig.horizontal.repeat(nameW + 6 + 30)}`),
38754
+ h(Text2, { color: colors.muted }, ` ${"Agent".padEnd(nameW)} ${"Status".padEnd(statusW)} ${"Logs".padEnd(6)} ${"Last event"}`),
38755
+ h(Text2, { color: colors.muted }, ` ${fig.horizontal.repeat(nameW + statusW + 6 + 32)}`),
38276
38756
  ...agentList.map((agent, i) => {
38277
38757
  const isActive = i === selectedIndex;
38278
38758
  const logCountColor = agent.hasErrors ? colors.error : agent.logCount > 0 ? colors.success : colors.muted;
@@ -38282,6 +38762,7 @@ function AgentLogPicker({ agents, agentLogs, onSelectAgent, onBack }) {
38282
38762
  { key: agent.path },
38283
38763
  h(Text2, { color: isActive ? colors.accent : colors.muted }, isActive ? ` ${fig.arrow} ` : " "),
38284
38764
  h(Text2, { bold: isActive }, clip(agent.name, nameW - 2).padEnd(nameW)),
38765
+ h(Text2, { color: runtimeStatusColor(agent.status.status) }, `${runtimeStatusIcon(agent.status.status)} ${agent.status.label}`.padEnd(statusW)),
38285
38766
  h(Text2, { color: logCountColor }, String(agent.logCount).padEnd(6)),
38286
38767
  h(Text2, { color: colors.muted }, clip(lastEvent, 36))
38287
38768
  );
@@ -38294,10 +38775,11 @@ function AgentLogPicker({ agents, agentLogs, onSelectAgent, onBack }) {
38294
38775
  ] })
38295
38776
  );
38296
38777
  }
38297
- function AgentLogDetail({ relativePath, agentLogs, agents, onBack }) {
38778
+ function AgentLogDetail({ relativePath, agentLogs, agentRunState = {}, agents, onBack }) {
38298
38779
  const logs = agentLogEntries(agentLogs, relativePath);
38299
38780
  const agent = agents.find((a) => (a.relativePath || ".") === relativePath);
38300
38781
  const agentName = agent?.manifestName || agent?.manifest?.name || relativePath;
38782
+ const runtime = agent ? agentRuntimeStatus(agent, agentRunState) : { status: agentRunState?.[relativePath]?.status || "unknown", label: agentRunState?.[relativePath]?.status || "offline" };
38301
38783
  const [scrollOffset, setScrollOffset] = useState5(0);
38302
38784
  const visibleCount = Math.min(20, Math.max(8, (process.stdout.rows || 24) - 10));
38303
38785
  useInput2((input, key) => {
@@ -38315,29 +38797,44 @@ function AgentLogDetail({ relativePath, agentLogs, agents, onBack }) {
38315
38797
  });
38316
38798
  const effectiveOffset = logs.length <= visibleCount ? 0 : scrollOffset >= logs.length - visibleCount - 2 ? Math.max(0, logs.length - visibleCount) : scrollOffset;
38317
38799
  const visibleLogs = logs.slice(effectiveOffset, effectiveOffset + visibleCount);
38800
+ const visibleRows = groupedLogRows(visibleLogs, logs[effectiveOffset - 1]);
38801
+ const messageWidth = Math.max(50, Math.min((process.stdout.columns || 80) - 18, 120));
38318
38802
  return h(
38319
38803
  Box2,
38320
38804
  { flexDirection: "column" },
38321
38805
  h(Text2, { bold: true, color: colors.brand }, ` ${fig.horizontal.repeat(3)} ${agentName}`),
38322
- h(Text2, { color: colors.muted }, ` ${relativePath} ${fig.dash} ${logs.length} log entries`),
38806
+ h(
38807
+ Text2,
38808
+ null,
38809
+ h(Text2, { color: colors.muted }, ` ${relativePath} ${fig.dash} ${logs.length} log entries ${fig.dash} `),
38810
+ h(Text2, { color: runtimeStatusColor(runtime.status) }, `${runtimeStatusIcon(runtime.status)} ${runtime.label}`)
38811
+ ),
38323
38812
  h(Text2, null, ""),
38324
38813
  logs.length === 0 ? h(Text2, { color: colors.muted }, " No logs recorded yet for this agent. Logs appear during runs.") : h(
38325
38814
  Box2,
38326
38815
  { flexDirection: "column" },
38327
- ...visibleLogs.map((entry, i) => {
38816
+ ...visibleRows.map((row, i) => {
38817
+ if (row.type === "divider") {
38818
+ return h(
38819
+ Text2,
38820
+ { key: `divider-${effectiveOffset}-${i}`, color: colors.dim },
38821
+ ` ${fig.horizontal.repeat(3)} run ${clip(row.runId, 24)} ${fig.horizontal.repeat(12)}`
38822
+ );
38823
+ }
38824
+ const entry = row.entry;
38328
38825
  const levelColor = entry.level === "error" ? colors.error : entry.level === "warning" ? colors.warning : entry.level === "debug" ? colors.dim : colors.muted;
38329
38826
  const timeStr = formatLogTime(entry.timestamp);
38330
- const icon = entry.eventType === "completion" ? entry.success ? fig.check : fig.cross : entry.eventType === "step_event" ? fig.arrow : entry.eventType === "progress" ? fig.dotEmpty : entry.level === "error" ? fig.cross : fig.dash;
38331
- const iconColor = entry.eventType === "completion" ? entry.success ? colors.success : colors.error : levelColor;
38827
+ const icon = entry.eventType === "completion" ? entry.success ? fig.check : fig.cross : entry.eventType === "job_started" ? fig.arrow : entry.eventType === "job_completed" ? entry.success === false ? fig.cross : fig.check : entry.eventType === "step_event" ? fig.arrow : entry.eventType === "progress" ? fig.dotEmpty : entry.eventType === "error" || entry.level === "error" ? fig.cross : fig.dash;
38828
+ const iconColor = entry.eventType === "completion" ? entry.success ? colors.success : colors.error : entry.eventType === "job_started" ? colors.accent : entry.eventType === "job_completed" ? entry.success === false ? colors.error : colors.success : levelColor;
38332
38829
  return h(
38333
38830
  Text2,
38334
- { key: `${effectiveOffset + i}` },
38831
+ { key: `entry-${effectiveOffset}-${i}` },
38335
38832
  h(Text2, { color: colors.dim }, ` ${timeStr} `),
38336
38833
  h(Text2, { color: iconColor }, `${icon} `),
38337
38834
  h(
38338
38835
  Text2,
38339
38836
  { color: entry.level === "error" ? colors.error : colors.text },
38340
- clip(formatAgentLogEntry(entry), 60)
38837
+ clip(formatAgentLogEntry(entry), messageWidth)
38341
38838
  )
38342
38839
  );
38343
38840
  }),
@@ -38359,6 +38856,12 @@ function formatAgentLogEntry(entry) {
38359
38856
  if (!entry) return "";
38360
38857
  const type = entry.eventType || "";
38361
38858
  switch (type) {
38859
+ case "job_started":
38860
+ return entry.message || `Started ${entry.jobType || "run"}`;
38861
+ case "job_completed":
38862
+ return entry.success === false ? `Failed: ${formatEntryError(entry.error) || entry.message || "error"}` : entry.message || "Completed successfully";
38863
+ case "error":
38864
+ return `Error: ${entry.message || formatEntryError(entry.error) || "unknown error"}`;
38362
38865
  case "log":
38363
38866
  return entry.message || "";
38364
38867
  case "progress": {
@@ -38381,6 +38884,24 @@ function formatAgentLogEntry(entry) {
38381
38884
  return entry.message || type || "event";
38382
38885
  }
38383
38886
  }
38887
+ function groupedLogRows(logs, previousEntry) {
38888
+ const rows = [];
38889
+ let currentRunId = previousEntry?.runId || "";
38890
+ for (const entry of logs) {
38891
+ const runId = entry.runId || "";
38892
+ if (runId && runId !== currentRunId) {
38893
+ rows.push({ type: "divider", runId });
38894
+ currentRunId = runId;
38895
+ }
38896
+ rows.push({ type: "entry", entry });
38897
+ }
38898
+ return rows;
38899
+ }
38900
+ function formatEntryError(error) {
38901
+ if (!error) return "";
38902
+ if (typeof error === "object") return error.message || "error";
38903
+ return String(error);
38904
+ }
38384
38905
  function formatLogTime(timestamp) {
38385
38906
  if (!timestamp) return " ";
38386
38907
  try {
@@ -38526,7 +39047,7 @@ function BackHint({ onBack }) {
38526
39047
  });
38527
39048
  return null;
38528
39049
  }
38529
- function attachServeChild(child, setState, setStartupError, onExit) {
39050
+ function attachServeChild(child, setState, setStartupError, onExit, logStore = null) {
38530
39051
  let buffer = "";
38531
39052
  const stderrChunks = [];
38532
39053
  child.stdout.setEncoding("utf8");
@@ -38538,6 +39059,10 @@ function attachServeChild(child, setState, setStartupError, onExit) {
38538
39059
  try {
38539
39060
  const event = parseServeEventLine(line);
38540
39061
  if (event) {
39062
+ try {
39063
+ logStore?.append(event);
39064
+ } catch {
39065
+ }
38541
39066
  setState((current) => applyServeEvent(current, event));
38542
39067
  }
38543
39068
  } catch (error) {
@@ -38558,6 +39083,10 @@ function attachServeChild(child, setState, setStartupError, onExit) {
38558
39083
  });
38559
39084
  child.on("error", (error) => setStartupError(errorMessage2(error)));
38560
39085
  child.on("exit", (code, signal) => {
39086
+ try {
39087
+ logStore?.compact();
39088
+ } catch {
39089
+ }
38561
39090
  const message = serveProcessExitMessage({ stderr: stderrChunks.join("\n"), code, signal });
38562
39091
  if (message) {
38563
39092
  setStartupError(message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vendian/cli",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Public Vendian CLI bootstrapper and launcher",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,