@standardagents/code 0.14.1-issue.653.6647dc-linux-x64-gnu → 0.14.1-issue.658.a1599e-darwin-arm64

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 (29) hide show
  1. package/Standard Code Daemon.app/Contents/CodeResources +0 -0
  2. package/Standard Code Daemon.app/Contents/Helpers/tmux +0 -0
  3. package/Standard Code Daemon.app/Contents/Info.plist +42 -0
  4. package/Standard Code Daemon.app/Contents/MacOS/standardd +4 -0
  5. package/{lib/standard-plugin-runner/index.mjs → Standard Code Daemon.app/Contents/Resources/plugin-runner/index.mjs } +62 -30
  6. package/{lib/standard-plugin-runner/runtime.json → Standard Code Daemon.app/Contents/Resources/plugin-runner/runtime.json } +1 -1
  7. package/{lib/standard-plugin-runner/sdk.mjs → Standard Code Daemon.app/Contents/Resources/plugin-runner/sdk.mjs } +141 -77
  8. package/{lib/standard-plugin-runner/worker.mjs → Standard Code Daemon.app/Contents/Resources/plugin-runner/worker.mjs } +188 -86
  9. package/Standard Code Daemon.app/Contents/Resources/tmux/TMUX-ARTIFACT-MANIFEST.sha256 +6 -0
  10. package/Standard Code Daemon.app/Contents/Resources/tmux/TMUX-ARTIFACT-METADATA.txt +23 -0
  11. package/Standard Code Daemon.app/Contents/Resources/tmux/TMUX-BUILD-TOOLS.txt +11 -0
  12. package/Standard Code Daemon.app/Contents/Resources/tmux/TMUX-OTOOL-L.txt +4 -0
  13. package/Standard Code Daemon.app/Contents/Resources/tmux/TMUX-SIGNED-RUNTIME.sha256 +1 -0
  14. package/Standard Code Daemon.app/Contents/Resources/tmux/licenses/libevent.txt +99 -0
  15. package/Standard Code Daemon.app/Contents/Resources/tmux/licenses/tmux.txt +13 -0
  16. package/Standard Code Daemon.app/Contents/_CodeSignature/CodeResources +269 -0
  17. package/Standard Code.app/Contents/CodeResources +0 -0
  18. package/Standard Code.app/Contents/Info.plist +42 -0
  19. package/Standard Code.app/Contents/MacOS/standard +0 -0
  20. package/Standard Code.app/Contents/_CodeSignature/CodeResources +115 -0
  21. package/licenses/THIRD-PARTY.txt +0 -33
  22. package/manifest.json +1 -1
  23. package/manifest.sig +1 -1
  24. package/package.json +6 -9
  25. package/bin/standard +0 -4
  26. package/bin/standardd +0 -4
  27. package/bin/tmux +0 -0
  28. /package/{lib/standard-plugin-runner → Standard Code Daemon.app/Contents/Resources/plugin-runner}/THIRD-PARTY.txt +0 -0
  29. /package/{lib/standard-plugin-runner → Standard Code Daemon.app/Contents/Resources/plugin-runner}/loader.mjs +0 -0
@@ -0,0 +1,42 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDisplayName</key>
6
+ <string>Standard Code Daemon</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>standardd</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>ai.standardcode.standardd</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>Standard Code Daemon</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>APPL</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>0.14.1-issue.658.a1599e</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>1</string>
21
+ <key>LSBackgroundOnly</key>
22
+ <true/>
23
+ <key>LSMinimumSystemVersion</key>
24
+ <string>11.0</string>
25
+ <key>NSLocalNetworkUsageDescription</key>
26
+ <string>Standard Code uses your local network to establish faster, encrypted direct connections to your other devices.</string>
27
+ <key>StandardCodeChannel</key>
28
+ <string>team</string>
29
+ <key>StandardCodeCommit</key>
30
+ <string>a1599e20b8d4621a2b3bcd0fd9023a4cb66bb96e</string>
31
+ <key>StandardCodeComponent</key>
32
+ <string>standardd</string>
33
+ <key>StandardCodeRelease</key>
34
+ <string>npm-a1599e20b8d4</string>
35
+ <key>StandardCodeTmuxSHA256</key>
36
+ <string>2875498eaff99cdb5b422198ff74befc39381bdd869e8e0210a097f0dc61027c</string>
37
+ <key>StandardCodeUnixProtocol</key>
38
+ <integer>1</integer>
39
+ <key>StandardCodeVersion</key>
40
+ <string>0.14.1-issue.658.a1599e</string>
41
+ </dict>
42
+ </plist>
@@ -0,0 +1,4 @@
1
+ [diffend] Oversized file quarantined before diffing.
2
+ name: package/Standard Code Daemon.app/Contents/MacOS/standardd
3
+ size: 35828720 bytes
4
+ sha256: 3cb4cdc4699f5f13abbbf105f46dc37bcb66ae18dac1eefb0ff231db92f5ce9e
@@ -29,7 +29,22 @@ var SURFACE_KINDS = Object.freeze([
29
29
  "key",
30
30
  "link"
31
31
  ]);
32
- var PRESENTATIONS = Object.freeze(["popover", "column", "pane"]);
32
+ var PRESENTATIONS = Object.freeze(["popover", "column", "pane", "stage"]);
33
+ var MUX_EXPRESSIONS = Object.freeze([
34
+ "neutral",
35
+ "blink",
36
+ "happy",
37
+ "happy-smile",
38
+ "sad",
39
+ "grin",
40
+ "surprise",
41
+ "sleepy",
42
+ "angry",
43
+ "focus",
44
+ "question",
45
+ "exclaim",
46
+ "cross"
47
+ ]);
33
48
  var ANCHORS = Object.freeze([
34
49
  "plugins",
35
50
  "machine.before",
@@ -58,6 +73,7 @@ var LIMITS = Object.freeze({
58
73
  canvasColumns: 512,
59
74
  canvasRows: 256,
60
75
  canvasHoverBytes: 512,
76
+ canvasShapes: 256,
61
77
  stateKeys: 256,
62
78
  stateValueBytes: 64 * 1024
63
79
  });
@@ -71,13 +87,13 @@ var PluginError = class extends Error {
71
87
  function ensure(condition, code, message) {
72
88
  if (!condition) throw new PluginError(code, message);
73
89
  }
74
- function object(value) {
75
- return value !== null && typeof value === "object" && !Array.isArray(value);
90
+ function object(value2) {
91
+ return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
76
92
  }
77
- function identifier(value) {
78
- return typeof value === "string" && /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value);
93
+ function identifier(value2) {
94
+ return typeof value2 === "string" && /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value2);
79
95
  }
80
- function jsonBytes(value, limit = LIMITS.frameBytes) {
96
+ function jsonBytes(value2, limit = LIMITS.frameBytes) {
81
97
  const seen = /* @__PURE__ */ new Set();
82
98
  function visit(item, depth) {
83
99
  ensure(depth <= 32, "invalid_payload", "JSON nesting exceeds 32 levels");
@@ -93,21 +109,21 @@ function jsonBytes(value, limit = LIMITS.frameBytes) {
93
109
  for (const child of Object.values(item)) visit(child, depth + 1);
94
110
  seen.delete(item);
95
111
  }
96
- visit(value, 0);
97
- const text = JSON.stringify(value);
112
+ visit(value2, 0);
113
+ const text = JSON.stringify(value2);
98
114
  ensure(Buffer.byteLength(text) <= limit, "payload_too_large", `Payload exceeds ${limit} bytes`);
99
115
  return text;
100
116
  }
101
- function freeze(value) {
102
- if (value && typeof value === "object") {
103
- Object.values(value).forEach(freeze);
104
- Object.freeze(value);
117
+ function freeze(value2) {
118
+ if (value2 && typeof value2 === "object") {
119
+ Object.values(value2).forEach(freeze);
120
+ Object.freeze(value2);
105
121
  }
106
- return value;
122
+ return value2;
107
123
  }
108
- function validateManifest(value) {
109
- ensure(object(value), "invalid_manifest", "package.json must contain a standardPlugin object");
110
- jsonBytes(value, LIMITS.manifestBytes);
124
+ function validateManifest(value2) {
125
+ ensure(object(value2), "invalid_manifest", "package.json must contain a standardPlugin object");
126
+ jsonBytes(value2, LIMITS.manifestBytes);
111
127
  const allowed = [
112
128
  "apiVersion",
113
129
  "id",
@@ -121,8 +137,8 @@ function validateManifest(value) {
121
137
  "configSchema",
122
138
  "hookTimeoutMs"
123
139
  ];
124
- ensure(Object.keys(value).every((key) => allowed.includes(key)), "invalid_manifest", "Unknown manifest field");
125
- const manifest = structuredClone({ singleton: false, order: 0, capabilities: [], contributions: [], hookTimeoutMs: 5e3, ...value });
140
+ ensure(Object.keys(value2).every((key) => allowed.includes(key)), "invalid_manifest", "Unknown manifest field");
141
+ const manifest = structuredClone({ singleton: false, order: 0, capabilities: [], contributions: [], hookTimeoutMs: 5e3, ...value2 });
126
142
  ensure(manifest.apiVersion === 1, "incompatible_version", "Plugin requires a different SDK API version");
127
143
  ensure(identifier(manifest.id), "invalid_manifest", "Plugin id must be a stable identifier");
128
144
  ensure(
@@ -192,6 +208,11 @@ function validateManifest(value) {
192
208
  "Only panels, cards, and commands declare a presentation"
193
209
  );
194
210
  ensure(declaration.kind !== "card" || declaration.anchor === "plugins", "invalid_manifest", "Cards use the plugins anchor");
211
+ ensure(
212
+ declaration.presentation !== "stage" || declaration.kind !== "panel" || declaration.anchor === "account",
213
+ "invalid_manifest",
214
+ "Stage panels use the account anchor"
215
+ );
195
216
  }
196
217
  for (const declaration of manifest.contributions) {
197
218
  ensure(
@@ -346,11 +367,11 @@ var RpcPeer = class {
346
367
  const id = `${this.idPrefix}-${++this.nextId}`;
347
368
  return new Promise((resolve2, reject) => {
348
369
  let timer;
349
- const finish = (error, value) => {
370
+ const finish = (error, value2) => {
350
371
  if (!this.pending.delete(id)) return;
351
372
  this.clock.clearTimeout(timer);
352
373
  signal?.removeEventListener("abort", cancel);
353
- error ? reject(error) : resolve2(value);
374
+ error ? reject(error) : resolve2(value2);
354
375
  };
355
376
  const cancelWith = (code) => {
356
377
  finish(new PluginError(code, code === "timeout" ? "Request deadline elapsed" : "Request was cancelled"));
@@ -420,8 +441,8 @@ var RpcPeer = class {
420
441
  ensure(!controller.signal.aborted, "cancelled", "Request was cancelled");
421
442
  ensure(typeof this.onRequest === "function", "unsupported_operation", "No request handler");
422
443
  return this.onRequest(frame.operation, { signal: controller.signal, timeoutMs: frame.timeoutMs });
423
- }).then((value) => {
424
- if (!controller.signal.aborted) respond({ ok: true, value: value ?? null });
444
+ }).then((value2) => {
445
+ if (!controller.signal.aborted) respond({ ok: true, value: value2 ?? null });
425
446
  }, (error) => {
426
447
  if (!controller.signal.aborted) respond({ ok: false, error: wireError(error) });
427
448
  }).finally(() => {
@@ -456,14 +477,25 @@ var VIEW_LIMITS = Object.freeze({
456
477
  actionValueBytes: 512
457
478
  });
458
479
  var TONES = Object.freeze(["ok", "info", "warn", "error", "muted", "accent", "pending", "bright"]);
459
- function compact(value) {
460
- return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
480
+ function compact(value2) {
481
+ return Object.fromEntries(Object.entries(value2).filter(([, item]) => item !== void 0));
461
482
  }
462
483
  var node = (type, fields) => compact({ type, ...fields });
484
+ var clockTime = (at) => `${new Date(at).toISOString().slice(11, 16)} UTC`;
485
+ var timeSpan = (style, at, { text: fallback, tone, weight, mono } = {}) => compact({
486
+ text: fallback ?? (style === "duration" ? `since ${clockTime(at)}` : clockTime(at)),
487
+ tone,
488
+ weight,
489
+ mono,
490
+ time: { at: Math.max(0, Math.floor(at)), style }
491
+ });
492
+ var value = (content) => Array.isArray(content) ? { value: content.map((span) => span.text).join(""), valueSpans: content.map(compact) } : { value: content };
463
493
  var ui = Object.freeze({
464
494
  view: (root, { title } = {}) => compact({ kind: "view", root, title }),
465
- action: (actionId, { value, opens, agentPicker } = {}) => compact({ actionId, value, opens, agentPicker }),
466
- span: (value, { tone, weight, mono } = {}) => compact({ text: value, tone, weight, mono }),
495
+ action: (actionId, { value: value2, opens, agentPicker } = {}) => compact({ actionId, value: value2, opens, agentPicker }),
496
+ span: (content, { tone, weight, mono, time } = {}) => compact({ text: content, tone, weight, mono, time }),
497
+ elapsed: (since, options) => timeSpan("duration", since, options),
498
+ relativeTime: (at, options) => timeSpan("relative", at, options),
467
499
  stack: (items, { gap } = {}) => node("stack", { gap, children: items }),
468
500
  row: (items, { align } = {}) => node("row", { children: items, align }),
469
501
  divider: (label) => node("divider", { label }),
@@ -471,18 +503,18 @@ var ui = Object.freeze({
471
503
  text: (content, { tone, weight, mono } = {}) => node("text", { ...Array.isArray(content) ? { spans: content.map(compact) } : { text: content }, tone, weight, mono }),
472
504
  badge: (label, tone) => node("badge", { label, tone }),
473
505
  dot: (tone) => node("dot", { tone }),
474
- progress: (value, max, { tone, label } = {}) => node("progress", { value, max, tone, label }),
506
+ progress: (value2, max, { tone, label } = {}) => node("progress", { value: value2, max, tone, label }),
475
507
  segments: (items) => node("segments", { items: items.map(compact) }),
476
508
  card: (items, { title, tone, tags, action, externalAction, footer } = {}) => node("card", { title, tone, tags, action, externalAction, footer, children: items }),
477
- stat: (label, value, { tone, hint } = {}) => node("stat", { label, value, tone, hint }),
478
- kv: (items) => node("kv", { items: items.map(compact) }),
509
+ stat: (label, content, { tone, hint } = {}) => node("stat", { label, ...value(content), tone, hint }),
510
+ kv: (items) => node("kv", { items: items.map((item) => compact({ ...item, ...value(item.value) })) }),
479
511
  tabs: (id, items, { filters, action } = {}) => node("tabs", { id, items: items.map(compact), filters, action }),
480
512
  select: (id, label, options, { filters, action } = {}) => node("select", { id, label, options: options.map(compact), filters, action }),
481
513
  table: (id, columns, rows = []) => node("table", { id, columns: columns.map(compact), rows: rows.map(compact) }),
482
514
  log: (lines) => node("log", { lines }),
483
515
  /** `action` is an action object or an action id. */
484
516
  button: (label, action) => node("button", { label, action: typeof action === "string" ? { actionId: action } : action }),
485
- input: (id, value, action, { placeholder, maxLength } = {}) => node("input", { id, value, placeholder, maxLength, action: typeof action === "string" ? { actionId: action } : action })
517
+ input: (id, value2, action, { placeholder, maxLength } = {}) => node("input", { id, value: value2, placeholder, maxLength, action: typeof action === "string" ? { actionId: action } : action })
486
518
  });
487
519
 
488
520
  // ../plugin-sdk/src/runtime.mjs
@@ -1 +1 @@
1
- {"schema":1,"productVersion":"0.14.1-issue.653.6647dc","commit":"6647dc62cf91b02086fdfef2250843f06b65d042","protocolVersion":1,"sdkApiVersion":1,"minimumNodeMajor":20,"loader":{"typescript":"5.9.2"},"files":["index.mjs","worker.mjs","loader.mjs","sdk.mjs","runtime.json","THIRD-PARTY.txt"]}
1
+ {"schema":1,"productVersion":"0.14.1-issue.658.a1599e","commit":"a1599e20b8d4621a2b3bcd0fd9023a4cb66bb96e","protocolVersion":1,"sdkApiVersion":1,"minimumNodeMajor":20,"loader":{"typescript":"5.9.2"},"files":["index.mjs","worker.mjs","loader.mjs","sdk.mjs","runtime.json","THIRD-PARTY.txt"]}
@@ -25,7 +25,22 @@ var SURFACE_KINDS = Object.freeze([
25
25
  "key",
26
26
  "link"
27
27
  ]);
28
- var PRESENTATIONS = Object.freeze(["popover", "column", "pane"]);
28
+ var PRESENTATIONS = Object.freeze(["popover", "column", "pane", "stage"]);
29
+ var MUX_EXPRESSIONS = Object.freeze([
30
+ "neutral",
31
+ "blink",
32
+ "happy",
33
+ "happy-smile",
34
+ "sad",
35
+ "grin",
36
+ "surprise",
37
+ "sleepy",
38
+ "angry",
39
+ "focus",
40
+ "question",
41
+ "exclaim",
42
+ "cross"
43
+ ]);
29
44
  var ANCHORS = Object.freeze([
30
45
  "plugins",
31
46
  "machine.before",
@@ -54,6 +69,7 @@ var LIMITS = Object.freeze({
54
69
  canvasColumns: 512,
55
70
  canvasRows: 256,
56
71
  canvasHoverBytes: 512,
72
+ canvasShapes: 256,
57
73
  stateKeys: 256,
58
74
  stateValueBytes: 64 * 1024
59
75
  });
@@ -67,13 +83,13 @@ var PluginError = class extends Error {
67
83
  function ensure(condition, code, message) {
68
84
  if (!condition) throw new PluginError(code, message);
69
85
  }
70
- function object(value) {
71
- return value !== null && typeof value === "object" && !Array.isArray(value);
86
+ function object(value2) {
87
+ return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
72
88
  }
73
- function identifier(value) {
74
- return typeof value === "string" && /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value);
89
+ function identifier(value2) {
90
+ return typeof value2 === "string" && /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value2);
75
91
  }
76
- function jsonBytes(value, limit = LIMITS.frameBytes) {
92
+ function jsonBytes(value2, limit = LIMITS.frameBytes) {
77
93
  const seen = /* @__PURE__ */ new Set();
78
94
  function visit(item, depth) {
79
95
  ensure(depth <= 32, "invalid_payload", "JSON nesting exceeds 32 levels");
@@ -89,21 +105,21 @@ function jsonBytes(value, limit = LIMITS.frameBytes) {
89
105
  for (const child of Object.values(item)) visit(child, depth + 1);
90
106
  seen.delete(item);
91
107
  }
92
- visit(value, 0);
93
- const text2 = JSON.stringify(value);
108
+ visit(value2, 0);
109
+ const text2 = JSON.stringify(value2);
94
110
  ensure(Buffer.byteLength(text2) <= limit, "payload_too_large", `Payload exceeds ${limit} bytes`);
95
111
  return text2;
96
112
  }
97
- function freeze(value) {
98
- if (value && typeof value === "object") {
99
- Object.values(value).forEach(freeze);
100
- Object.freeze(value);
113
+ function freeze(value2) {
114
+ if (value2 && typeof value2 === "object") {
115
+ Object.values(value2).forEach(freeze);
116
+ Object.freeze(value2);
101
117
  }
102
- return value;
118
+ return value2;
103
119
  }
104
- function validateManifest(value) {
105
- ensure(object(value), "invalid_manifest", "package.json must contain a standardPlugin object");
106
- jsonBytes(value, LIMITS.manifestBytes);
120
+ function validateManifest(value2) {
121
+ ensure(object(value2), "invalid_manifest", "package.json must contain a standardPlugin object");
122
+ jsonBytes(value2, LIMITS.manifestBytes);
107
123
  const allowed = [
108
124
  "apiVersion",
109
125
  "id",
@@ -117,8 +133,8 @@ function validateManifest(value) {
117
133
  "configSchema",
118
134
  "hookTimeoutMs"
119
135
  ];
120
- ensure(Object.keys(value).every((key) => allowed.includes(key)), "invalid_manifest", "Unknown manifest field");
121
- const manifest = structuredClone({ singleton: false, order: 0, capabilities: [], contributions: [], hookTimeoutMs: 5e3, ...value });
136
+ ensure(Object.keys(value2).every((key) => allowed.includes(key)), "invalid_manifest", "Unknown manifest field");
137
+ const manifest = structuredClone({ singleton: false, order: 0, capabilities: [], contributions: [], hookTimeoutMs: 5e3, ...value2 });
122
138
  ensure(manifest.apiVersion === 1, "incompatible_version", "Plugin requires a different SDK API version");
123
139
  ensure(identifier(manifest.id), "invalid_manifest", "Plugin id must be a stable identifier");
124
140
  ensure(
@@ -188,6 +204,11 @@ function validateManifest(value) {
188
204
  "Only panels, cards, and commands declare a presentation"
189
205
  );
190
206
  ensure(declaration.kind !== "card" || declaration.anchor === "plugins", "invalid_manifest", "Cards use the plugins anchor");
207
+ ensure(
208
+ declaration.presentation !== "stage" || declaration.kind !== "panel" || declaration.anchor === "account",
209
+ "invalid_manifest",
210
+ "Stage panels use the account anchor"
211
+ );
191
212
  }
192
213
  for (const declaration of manifest.contributions) {
193
214
  ensure(
@@ -204,29 +225,29 @@ function validateManifest(value) {
204
225
  // ../plugin-sdk/src/collection.mjs
205
226
  var COLLECTION_FILE = "standard-plugins.json";
206
227
  var COLLECTION_LIMITS = Object.freeze({ entries: 256, pathLength: 512 });
207
- function relativePath(value) {
208
- return typeof value === "string" && value.length > 0 && value.length <= COLLECTION_LIMITS.pathLength && !/[\\]/.test(value) && !value.startsWith("/") && value.split("/").every((part) => part && part !== "." && part !== "..");
228
+ function relativePath(value2) {
229
+ return typeof value2 === "string" && value2.length > 0 && value2.length <= COLLECTION_LIMITS.pathLength && !/[\\]/.test(value2) && !value2.startsWith("/") && value2.split("/").every((part) => part && part !== "." && part !== "..");
209
230
  }
210
- function freeze2(value) {
211
- if (value && typeof value === "object") {
212
- Object.values(value).forEach(freeze2);
213
- Object.freeze(value);
231
+ function freeze2(value2) {
232
+ if (value2 && typeof value2 === "object") {
233
+ Object.values(value2).forEach(freeze2);
234
+ Object.freeze(value2);
214
235
  }
215
- return value;
236
+ return value2;
216
237
  }
217
- function validateCollection(value) {
218
- ensure(object(value), "invalid_collection", `${COLLECTION_FILE} must contain an object`);
219
- jsonBytes(value, LIMITS.manifestBytes);
220
- ensure(Object.keys(value).every((key) => ["schema", "plugins"].includes(key)), "invalid_collection", "Unknown collection field");
221
- ensure(value.schema === 1, "invalid_collection", "Collection schema must be 1");
238
+ function validateCollection(value2) {
239
+ ensure(object(value2), "invalid_collection", `${COLLECTION_FILE} must contain an object`);
240
+ jsonBytes(value2, LIMITS.manifestBytes);
241
+ ensure(Object.keys(value2).every((key) => ["schema", "plugins"].includes(key)), "invalid_collection", "Unknown collection field");
242
+ ensure(value2.schema === 1, "invalid_collection", "Collection schema must be 1");
222
243
  ensure(
223
- Array.isArray(value.plugins) && value.plugins.length >= 1 && value.plugins.length <= COLLECTION_LIMITS.entries,
244
+ Array.isArray(value2.plugins) && value2.plugins.length >= 1 && value2.plugins.length <= COLLECTION_LIMITS.entries,
224
245
  "invalid_collection",
225
246
  `Collection must list between 1 and ${COLLECTION_LIMITS.entries} plugins`
226
247
  );
227
248
  const ids = /* @__PURE__ */ new Set();
228
249
  const paths = /* @__PURE__ */ new Set();
229
- const plugins = value.plugins.map((entry) => {
250
+ const plugins = value2.plugins.map((entry) => {
230
251
  ensure(object(entry) && Object.keys(entry).every((key) => ["id", "path"].includes(key)), "invalid_collection", "Invalid collection entry");
231
252
  ensure(identifier(entry.id), "invalid_collection", "Collection entry id must be a stable identifier");
232
253
  ensure(relativePath(entry.path), "invalid_collection", "Collection entry path must be a relative POSIX path");
@@ -314,68 +335,78 @@ var VIEW_LIMITS = Object.freeze({
314
335
  });
315
336
  var TONES = Object.freeze(["ok", "info", "warn", "error", "muted", "accent", "pending", "bright"]);
316
337
  var WEIGHTS = ["normal", "bold", "dim"];
338
+ var TIME_STYLES = ["duration", "relative"];
317
339
  var ALIGNS = ["start", "center", "end"];
318
340
  var FORBIDDEN = /[\u0000-\u001f\u007f-\u009f\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
319
341
  var invalid = (message) => ensure(false, "invalid_payload", message);
320
- function text(value, field) {
321
- if (typeof value !== "string") invalid(`Plugin view ${field} must be a string`);
322
- ensure(!FORBIDDEN.test(value), "invalid_payload", "Plugin view text contains a control or bidirectional character");
342
+ function text(value2, field) {
343
+ if (typeof value2 !== "string") invalid(`Plugin view ${field} must be a string`);
344
+ ensure(!FORBIDDEN.test(value2), "invalid_payload", "Plugin view text contains a control or bidirectional character");
323
345
  }
324
- function optionalText(value, field) {
325
- if (value !== void 0) text(value, field);
346
+ function optionalText(value2, field) {
347
+ if (value2 !== void 0) text(value2, field);
326
348
  }
327
- function choice(value, choices, field) {
328
- ensure(value === void 0 || choices.includes(value), "invalid_payload", `Invalid plugin view ${field}`);
349
+ function choice(value2, choices, field) {
350
+ ensure(value2 === void 0 || choices.includes(value2), "invalid_payload", `Invalid plugin view ${field}`);
329
351
  }
330
- function tone(value) {
331
- choice(value, TONES, "tone");
352
+ function tone(value2) {
353
+ choice(value2, TONES, "tone");
332
354
  }
333
- function integer(value, max, field) {
334
- ensure(value === void 0 || Number.isInteger(value) && value >= 0 && value <= max, "invalid_payload", `Invalid plugin view ${field}`);
355
+ function integer(value2, max, field) {
356
+ ensure(value2 === void 0 || Number.isInteger(value2) && value2 >= 0 && value2 <= max, "invalid_payload", `Invalid plugin view ${field}`);
335
357
  }
336
- function flag(value, field) {
337
- ensure(value === void 0 || typeof value === "boolean", "invalid_payload", `Invalid plugin view ${field}`);
358
+ function flag(value2, field) {
359
+ ensure(value2 === void 0 || typeof value2 === "boolean", "invalid_payload", `Invalid plugin view ${field}`);
338
360
  }
339
- function number(value) {
340
- ensure(typeof value === "number" && Number.isFinite(value), "invalid_payload", "Plugin view number is not finite");
361
+ function number(value2) {
362
+ ensure(typeof value2 === "number" && Number.isFinite(value2), "invalid_payload", "Plugin view number is not finite");
341
363
  }
342
- function list(value, field, optional = false) {
343
- if (optional && value === void 0) return [];
344
- ensure(Array.isArray(value), "invalid_payload", `Plugin view ${field} must be an array`);
345
- return value;
364
+ function list(value2, field, optional = false) {
365
+ if (optional && value2 === void 0) return [];
366
+ ensure(Array.isArray(value2), "invalid_payload", `Plugin view ${field} must be an array`);
367
+ return value2;
346
368
  }
347
- function entries(value, field, optional, check) {
348
- for (const item of list(value, field, optional)) {
369
+ function entries(value2, field, optional, check) {
370
+ for (const item of list(value2, field, optional)) {
349
371
  ensure(object(item), "invalid_payload", `Plugin view ${field} must contain objects`);
350
372
  check(item);
351
373
  }
352
374
  }
353
- function bounded(value, field, limit, optional = false) {
354
- const values = list(value, field, optional);
375
+ function bounded(value2, field, limit, optional = false) {
376
+ const values = list(value2, field, optional);
355
377
  ensure(values.length <= limit, "invalid_payload", `Plugin view ${field} has more than ${limit} entries`);
356
378
  return values;
357
379
  }
358
- function boundedEntries(value, field, check) {
359
- entries(bounded(value, field, VIEW_LIMITS.items), field, false, check);
380
+ function boundedEntries(value2, field, check) {
381
+ entries(bounded(value2, field, VIEW_LIMITS.items), field, false, check);
360
382
  }
361
- function spans(value, optional) {
362
- entries(value, "spans", optional, (span) => {
383
+ function spans(value2, optional) {
384
+ entries(value2, "spans", optional, (span) => {
363
385
  text(span.text, "span text");
364
386
  tone(span.tone);
365
387
  choice(span.weight, WEIGHTS, "weight");
366
388
  flag(span.mono, "mono");
389
+ if (span.time !== void 0) {
390
+ ensure(
391
+ object(span.time) && Number.isSafeInteger(span.time.at) && span.time.at >= 0,
392
+ "invalid_payload",
393
+ "Plugin view time must be epoch milliseconds"
394
+ );
395
+ choice(span.time.style, TIME_STYLES, "time style");
396
+ ensure(span.time.style !== void 0, "invalid_payload", "Invalid plugin view time style");
397
+ }
367
398
  });
368
399
  }
369
- function action(value, optional = true) {
370
- if (optional && value === void 0) return;
371
- ensure(object(value), "invalid_payload", "Plugin view action must be an object");
372
- text(value.actionId, "action id");
373
- optionalText(value.value, "action value");
374
- optionalText(value.opens, "action opens");
375
- if (value.agentPicker !== void 0) {
376
- ensure(object(value.agentPicker), "invalid_payload", "Agent picker needs a project and machine");
377
- text(value.agentPicker.machineId, "agent picker machine");
378
- text(value.agentPicker.projectId, "agent picker project");
400
+ function action(value2, optional = true) {
401
+ if (optional && value2 === void 0) return;
402
+ ensure(object(value2), "invalid_payload", "Plugin view action must be an object");
403
+ text(value2.actionId, "action id");
404
+ optionalText(value2.value, "action value");
405
+ optionalText(value2.opens, "action opens");
406
+ if (value2.agentPicker !== void 0) {
407
+ ensure(object(value2.agentPicker), "invalid_payload", "Agent picker needs a project and machine");
408
+ text(value2.agentPicker.machineId, "agent picker machine");
409
+ text(value2.agentPicker.projectId, "agent picker project");
379
410
  }
380
411
  }
381
412
  function meter(item) {
@@ -439,6 +470,7 @@ var NODES = {
439
470
  stat(node2) {
440
471
  text(node2.label, "label");
441
472
  text(node2.value, "value");
473
+ spans(node2.valueSpans, true);
442
474
  tone(node2.tone);
443
475
  optionalText(node2.hint, "hint");
444
476
  },
@@ -446,6 +478,7 @@ var NODES = {
446
478
  boundedEntries(node2.items, "items", (item) => {
447
479
  text(item.label, "label");
448
480
  text(item.value, "value");
481
+ spans(item.valueSpans, true);
449
482
  flag(item.mono, "mono");
450
483
  flag(item.copy, "copy");
451
484
  });
@@ -578,14 +611,43 @@ function validateView(root, { kind, manifest } = {}) {
578
611
  ensure(cardLines(root) <= VIEW_LIMITS.cardLines, "payload_too_large", "A card view is taller than 6 lines");
579
612
  }
580
613
  }
581
- function compact(value) {
582
- return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
614
+ function compact(value2) {
615
+ return Object.fromEntries(Object.entries(value2).filter(([, item]) => item !== void 0));
583
616
  }
584
617
  var node = (type, fields) => compact({ type, ...fields });
618
+ function formatTime({ at, style }, now) {
619
+ const elapsed = Math.max(0, now - at);
620
+ if (style === "duration") {
621
+ const seconds2 = Math.floor(elapsed / 1e3);
622
+ const minutes2 = Math.floor(seconds2 / 60), hours2 = Math.floor(minutes2 / 60);
623
+ const pad = (value2) => String(value2).padStart(2, "0");
624
+ if (hours2) return `${hours2}h ${pad(minutes2 % 60)}m ${pad(seconds2 % 60)}s`;
625
+ return minutes2 ? `${minutes2}m ${pad(seconds2 % 60)}s` : `${seconds2}s`;
626
+ }
627
+ const seconds = Math.round(elapsed / 1e3);
628
+ if (seconds < 45) return "now";
629
+ const minutes = Math.round(seconds / 60);
630
+ if (minutes < 60) return `${minutes}m`;
631
+ const hours = Math.floor(minutes / 60);
632
+ if (hours < 24) return minutes % 60 ? `${hours}h ${minutes % 60}m` : `${hours}h`;
633
+ const days = Math.floor(hours / 24);
634
+ return hours % 24 ? `${days}d ${hours % 24}h` : `${days}d`;
635
+ }
636
+ var clockTime = (at) => `${new Date(at).toISOString().slice(11, 16)} UTC`;
637
+ var timeSpan = (style, at, { text: fallback, tone: tone2, weight, mono } = {}) => compact({
638
+ text: fallback ?? (style === "duration" ? `since ${clockTime(at)}` : clockTime(at)),
639
+ tone: tone2,
640
+ weight,
641
+ mono,
642
+ time: { at: Math.max(0, Math.floor(at)), style }
643
+ });
644
+ var value = (content) => Array.isArray(content) ? { value: content.map((span) => span.text).join(""), valueSpans: content.map(compact) } : { value: content };
585
645
  var ui = Object.freeze({
586
646
  view: (root, { title } = {}) => compact({ kind: "view", root, title }),
587
- action: (actionId, { value, opens, agentPicker } = {}) => compact({ actionId, value, opens, agentPicker }),
588
- span: (value, { tone: tone2, weight, mono } = {}) => compact({ text: value, tone: tone2, weight, mono }),
647
+ action: (actionId, { value: value2, opens, agentPicker } = {}) => compact({ actionId, value: value2, opens, agentPicker }),
648
+ span: (content, { tone: tone2, weight, mono, time } = {}) => compact({ text: content, tone: tone2, weight, mono, time }),
649
+ elapsed: (since, options) => timeSpan("duration", since, options),
650
+ relativeTime: (at, options) => timeSpan("relative", at, options),
589
651
  stack: (items, { gap } = {}) => node("stack", { gap, children: items }),
590
652
  row: (items, { align } = {}) => node("row", { children: items, align }),
591
653
  divider: (label) => node("divider", { label }),
@@ -593,18 +655,18 @@ var ui = Object.freeze({
593
655
  text: (content, { tone: tone2, weight, mono } = {}) => node("text", { ...Array.isArray(content) ? { spans: content.map(compact) } : { text: content }, tone: tone2, weight, mono }),
594
656
  badge: (label, tone2) => node("badge", { label, tone: tone2 }),
595
657
  dot: (tone2) => node("dot", { tone: tone2 }),
596
- progress: (value, max, { tone: tone2, label } = {}) => node("progress", { value, max, tone: tone2, label }),
658
+ progress: (value2, max, { tone: tone2, label } = {}) => node("progress", { value: value2, max, tone: tone2, label }),
597
659
  segments: (items) => node("segments", { items: items.map(compact) }),
598
660
  card: (items, { title, tone: tone2, tags, action: action2, externalAction, footer } = {}) => node("card", { title, tone: tone2, tags, action: action2, externalAction, footer, children: items }),
599
- stat: (label, value, { tone: tone2, hint } = {}) => node("stat", { label, value, tone: tone2, hint }),
600
- kv: (items) => node("kv", { items: items.map(compact) }),
661
+ stat: (label, content, { tone: tone2, hint } = {}) => node("stat", { label, ...value(content), tone: tone2, hint }),
662
+ kv: (items) => node("kv", { items: items.map((item) => compact({ ...item, ...value(item.value) })) }),
601
663
  tabs: (id, items, { filters, action: action2 } = {}) => node("tabs", { id, items: items.map(compact), filters, action: action2 }),
602
664
  select: (id, label, options, { filters, action: action2 } = {}) => node("select", { id, label, options: options.map(compact), filters, action: action2 }),
603
665
  table: (id, columns, rows = []) => node("table", { id, columns: columns.map(compact), rows: rows.map(compact) }),
604
666
  log: (lines) => node("log", { lines }),
605
667
  /** `action` is an action object or an action id. */
606
668
  button: (label, action2) => node("button", { label, action: typeof action2 === "string" ? { actionId: action2 } : action2 }),
607
- input: (id, value, action2, { placeholder, maxLength } = {}) => node("input", { id, value, placeholder, maxLength, action: typeof action2 === "string" ? { actionId: action2 } : action2 })
669
+ input: (id, value2, action2, { placeholder, maxLength } = {}) => node("input", { id, value: value2, placeholder, maxLength, action: typeof action2 === "string" ? { actionId: action2 } : action2 })
608
670
  });
609
671
 
610
672
  // ../plugin-sdk/src/index.mjs
@@ -618,6 +680,7 @@ function definePlugin(definition) {
618
680
  }
619
681
  export {
620
682
  COLLECTION_FILE,
683
+ MUX_EXPRESSIONS,
621
684
  PRESENTATIONS,
622
685
  PluginError,
623
686
  SDK_PACKAGE,
@@ -625,6 +688,7 @@ export {
625
688
  VIEW_LIMITS,
626
689
  checkPackageForPublish,
627
690
  definePlugin,
691
+ formatTime,
628
692
  lockfileRequirement,
629
693
  resolveCollection,
630
694
  ui,