@topolo/cli 0.13.16 → 0.13.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -108,7 +108,7 @@ function registerAgentPacksCommand(program2) {
108
108
  if (name === "approvals") command.option("--connection <id>", "Exact private dynamic lane control connection").option("--intake <id>", "Exact owning native intake identity").option("--fingerprint <hash>", "Exact pending native request fingerprint").option("--response <path>", "Recorded one-request response JSON").option("--human-decision-recorded", "Assert that the exact human decision is recorded in the intake");
109
109
  command.option("--harness <name>", "Local host adapter (codex, claude Desktop Code sessions)", "codex").option("--adapter-help", "Show every option supported by the selected adapter").argument("[arguments...]").allowUnknownOption().allowExcessArguments().addHelpText("after", name === "add" ? "\nExamples:\n topolo agent-packs add founder\n topolo agent-packs add founder --group specialists\n topolo agent-packs add founder --agent strategy\n" : "\nRun topolo agent-packs <command> --adapter-help for all adapter options. Cloud commands require explicit --environment and --context-key.\n").action(async (args, options) => {
110
110
  if (!["codex", "claude"].includes(options.harness)) throw new Error(`The ${options.harness} pack adapter is not available. Supported adapters: codex, claude.`);
111
- if (name === "lane" && options.harness === "claude" && !options.adapterHelp && !["status", "models-template", "models-install"].includes(args[0] ?? "")) {
111
+ if (name === "lane" && options.harness === "claude" && !options.adapterHelp && !["allocate", "status", "models-template", "models-install"].includes(args[0] ?? "")) {
112
112
  if (options.connection) {
113
113
  if (args.length !== 1 || !["read", "context-start", "context-read", "fixture-start", "fixture-read", "retire", "close"].includes(args[0]))
114
114
  throw new Error("Closed existing Claude lane control operation required.");
@@ -226,12 +226,10 @@ function registerAgentPacksCommand(program2) {
226
226
  import { Command, Help } from "commander";
227
227
 
228
228
  // src/commands/auth.ts
229
- import { spawn } from "child_process";
230
- import { platform as platform2 } from "os";
231
229
  import { createInterface } from "readline/promises";
232
230
  import { stdin as input } from "process";
233
231
 
234
- // node_modules/.pnpm/@topolo+sdk@0.23.22/node_modules/@topolo/sdk/dist/index.js
232
+ // node_modules/.pnpm/@topolo+sdk@0.23.24/node_modules/@topolo/sdk/dist/index.js
235
233
  function record(value) {
236
234
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
237
235
  }
@@ -249,6 +247,56 @@ function validTopoloActionAccessPolicy(value) {
249
247
  }
250
248
  return true;
251
249
  }
250
+ function record2(value) {
251
+ return !!value && typeof value === "object" && !Array.isArray(value);
252
+ }
253
+ function text(value, limit = 512) {
254
+ return typeof value === "string" && value.trim() ? value.trim().slice(0, limit) : null;
255
+ }
256
+ function strings2(value) {
257
+ return Array.isArray(value) ? value.slice(0, 8).flatMap((item) => {
258
+ const result = text(item);
259
+ return result ? [result] : [];
260
+ }) : [];
261
+ }
262
+ function pairs(value, first, second) {
263
+ return Array.isArray(value) ? value.slice(0, 8).flatMap((item) => {
264
+ if (!record2(item)) return [];
265
+ const a = text(item[first], 160);
266
+ const b = text(item[second]);
267
+ return a && b ? [{ [first]: a, [second]: b }] : [];
268
+ }) : [];
269
+ }
270
+ function docs(value) {
271
+ const result = text(value, 2048);
272
+ if (!result) return null;
273
+ try {
274
+ const url = new URL(result);
275
+ return url.protocol === "https:" && !url.username && !url.password ? url.href : null;
276
+ } catch {
277
+ return null;
278
+ }
279
+ }
280
+ function normalizeApplicationGuide(value) {
281
+ if (!record2(value) || value.schemaVersion !== 1 || value.source !== "published_application_manifest") return null;
282
+ const purpose = text(value.purpose, 2048);
283
+ const gettingStarted = strings2(value.gettingStarted);
284
+ const docsUrl = docs(value.docsUrl);
285
+ return {
286
+ schemaVersion: 1,
287
+ source: "published_application_manifest",
288
+ publishedAt: text(value.publishedAt, 160),
289
+ purpose,
290
+ problemStatement: text(value.problemStatement, 2048),
291
+ solutionStatement: text(value.solutionStatement, 2048),
292
+ benefits: strings2(value.benefits),
293
+ features: pairs(value.features, "title", "description"),
294
+ gettingStarted,
295
+ worksWellWith: pairs(value.worksWellWith, "appId", "reason"),
296
+ docsUrl,
297
+ missingFields: [...!purpose ? ["purpose"] : [], ...!docsUrl ? ["docsUrl"] : [], ...!gettingStarted.length ? ["gettingStarted"] : []]
298
+ };
299
+ }
252
300
  function applyAuthHeaders(headers, credential) {
253
301
  if (credential.kind === "api_key") {
254
302
  headers.set("X-Api-Key", credential.apiKey);
@@ -364,9 +412,9 @@ function canonicalTopoloServiceErrorCode(value) {
364
412
  }
365
413
  function sanitizeTopoloServiceMessage(value) {
366
414
  if (typeof value !== "string") return void 0;
367
- const text3 = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
368
- if (!text3) return void 0;
369
- return text3.length > SERVICE_MESSAGE_MAX_LENGTH ? `${text3.slice(0, SERVICE_MESSAGE_MAX_LENGTH - 1).trimEnd()}\u2026` : text3;
415
+ const text4 = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
416
+ if (!text4) return void 0;
417
+ return text4.length > SERVICE_MESSAGE_MAX_LENGTH ? `${text4.slice(0, SERVICE_MESSAGE_MAX_LENGTH - 1).trimEnd()}\u2026` : text4;
370
418
  }
371
419
  function canonicalTopoloRequestId(value) {
372
420
  if (typeof value !== "string") return void 0;
@@ -434,10 +482,10 @@ var TopoloPermissionError = class extends TopoloSdkError {
434
482
  };
435
483
  function extractTopoloServiceErrorCode(body) {
436
484
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
437
- const record4 = body;
438
- const topLevel = canonicalTopoloServiceErrorCode(record4.code);
485
+ const record5 = body;
486
+ const topLevel = canonicalTopoloServiceErrorCode(record5.code);
439
487
  if (topLevel) return topLevel;
440
- const nested = record4.error;
488
+ const nested = record5.error;
441
489
  const nestedString = canonicalTopoloServiceErrorCode(nested);
442
490
  if (nestedString) return nestedString;
443
491
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
@@ -449,13 +497,13 @@ function extractTopoloServiceErrorCode(body) {
449
497
  }
450
498
  function extractTopoloServiceErrorMessage(body) {
451
499
  if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
452
- const record4 = body;
453
- const nested = record4.error;
500
+ const record5 = body;
501
+ const nested = record5.error;
454
502
  const candidates = [];
455
503
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
456
504
  candidates.push(nested.message);
457
505
  }
458
- candidates.push(record4.message, record4.error_description);
506
+ candidates.push(record5.message, record5.error_description);
459
507
  if (typeof nested === "string" && !canonicalTopoloServiceErrorCode(nested)) candidates.push(nested);
460
508
  for (const candidate of candidates) {
461
509
  const message3 = sanitizeTopoloServiceMessage(candidate);
@@ -468,14 +516,14 @@ function serviceErrorCode(body, fallback) {
468
516
  }
469
517
  function extractTopoloServiceErrorDetails(body) {
470
518
  if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
471
- const record4 = body;
472
- let candidate = record4.details;
473
- const nested = record4.error;
519
+ const record5 = body;
520
+ let candidate = record5.details;
521
+ const nested = record5.error;
474
522
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
475
523
  const nestedRecord = nested;
476
524
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
477
525
  }
478
- if (candidate === void 0) candidate = record4;
526
+ if (candidate === void 0) candidate = record5;
479
527
  if (Array.isArray(candidate)) return validationIssueDetails(canonicalTopoloValidationIssues(candidate)) ?? void 0;
480
528
  if (!candidate || typeof candidate !== "object") return void 0;
481
529
  const source = candidate;
@@ -534,18 +582,18 @@ function validationIssueDetails(issues) {
534
582
  return paths.length ? { paths, issues } : { issues };
535
583
  }
536
584
  function issue(path, message3) {
537
- const text3 = sanitizeTopoloServiceMessage(message3);
538
- if (!path && !text3) return null;
539
- return { ...path ? { path } : {}, ...text3 ? { message: text3 } : {} };
585
+ const text4 = sanitizeTopoloServiceMessage(message3);
586
+ if (!path && !text4) return null;
587
+ return { ...path ? { path } : {}, ...text4 ? { message: text4 } : {} };
540
588
  }
541
589
  function canonicalTopoloValidationIssues(values) {
542
590
  const issues = [];
543
591
  for (const value of values) {
544
592
  if (!value || typeof value !== "object" || Array.isArray(value)) continue;
545
- const record4 = value;
546
- const path = canonicalTopoloValidationPath(record4.field) ?? canonicalTopoloValidationPath(record4.path);
593
+ const record5 = value;
594
+ const path = canonicalTopoloValidationPath(record5.field) ?? canonicalTopoloValidationPath(record5.path);
547
595
  if (!path) continue;
548
- const projected = issue(path, record4.message);
596
+ const projected = issue(path, record5.message);
549
597
  if (projected) issues.push(projected);
550
598
  if (issues.length === SERVICE_ISSUE_LIMIT) break;
551
599
  }
@@ -699,8 +747,8 @@ function sensitive(key, value) {
699
747
  const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
700
748
  if (normalized === "capability") {
701
749
  if (typeof value !== "string") return value !== null && value !== void 0 && typeof value !== "boolean" && typeof value !== "number";
702
- const text3 = value.trim();
703
- return Boolean(text3) && !/^[a-z][a-z0-9_-]{0,31}$/.test(text3);
750
+ const text4 = value.trim();
751
+ return Boolean(text4) && !/^[a-z][a-z0-9_-]{0,31}$/.test(text4);
704
752
  }
705
753
  return ["authorization", "cookie", "setcookie", "proxyauthorization"].includes(normalized) || /(token|secret|password|privatekey|apikey|backupcodes?|recoverycodes?)$/.test(normalized);
706
754
  }
@@ -1269,7 +1317,7 @@ var ActorEnvelopeValidationError = class extends Error {
1269
1317
  }
1270
1318
  };
1271
1319
  function parseActorEnvelope(value) {
1272
- const envelope = record2(value, "actorEnvelope");
1320
+ const envelope = record3(value, "actorEnvelope");
1273
1321
  exactKeys(envelope, [
1274
1322
  "schemaVersion",
1275
1323
  "organizationId",
@@ -1287,28 +1335,28 @@ function parseActorEnvelope(value) {
1287
1335
  }
1288
1336
  const accountableSubject = parseAccountableSubject(envelope.accountableSubject);
1289
1337
  const performer = parseIdentity(envelope.performer, "actorEnvelope.performer");
1290
- const organizationId = text(envelope.organizationId, "actorEnvelope.organizationId");
1338
+ const organizationId = text2(envelope.organizationId, "actorEnvelope.organizationId");
1291
1339
  const channel = member(envelope.channel, CHANNELS, "actorEnvelope.channel");
1292
1340
  const issuedAt = timestamp(envelope.issuedAt, "actorEnvelope.issuedAt");
1293
1341
  const expiresAt = envelope.expiresAt === void 0 ? void 0 : timestamp(envelope.expiresAt, "actorEnvelope.expiresAt");
1294
1342
  if (expiresAt && Date.parse(expiresAt) <= Date.parse(issuedAt)) {
1295
1343
  fail("actorEnvelope.expiresAt", "must be later than issuedAt");
1296
1344
  }
1297
- const assuranceValue = record2(envelope.assurance, "actorEnvelope.assurance");
1345
+ const assuranceValue = record3(envelope.assurance, "actorEnvelope.assurance");
1298
1346
  exactKeys(assuranceValue, ["level", "methods"], "actorEnvelope.assurance");
1299
1347
  const assurance = {
1300
1348
  level: member(assuranceValue.level, ASSURANCE_LEVELS, "actorEnvelope.assurance.level"),
1301
1349
  methods: textArray(assuranceValue.methods, "actorEnvelope.assurance.methods")
1302
1350
  };
1303
- const actionValue = record2(envelope.action, "actorEnvelope.action");
1351
+ const actionValue = record3(envelope.action, "actorEnvelope.action");
1304
1352
  exactKeys(actionValue, ["requestId", "actionId", "resourceType", "resourceId", "inputHash"], "actorEnvelope.action");
1305
- const inputHash = text(actionValue.inputHash, "actorEnvelope.action.inputHash");
1353
+ const inputHash = text2(actionValue.inputHash, "actorEnvelope.action.inputHash");
1306
1354
  if (!HASH_PATTERN.test(inputHash)) fail("actorEnvelope.action.inputHash", "must be a lowercase sha256 digest");
1307
1355
  const action = {
1308
- requestId: text(actionValue.requestId, "actorEnvelope.action.requestId"),
1309
- actionId: text(actionValue.actionId, "actorEnvelope.action.actionId"),
1310
- ...actionValue.resourceType === void 0 ? {} : { resourceType: text(actionValue.resourceType, "actorEnvelope.action.resourceType") },
1311
- ...actionValue.resourceId === void 0 ? {} : { resourceId: text(actionValue.resourceId, "actorEnvelope.action.resourceId") },
1356
+ requestId: text2(actionValue.requestId, "actorEnvelope.action.requestId"),
1357
+ actionId: text2(actionValue.actionId, "actorEnvelope.action.actionId"),
1358
+ ...actionValue.resourceType === void 0 ? {} : { resourceType: text2(actionValue.resourceType, "actorEnvelope.action.resourceType") },
1359
+ ...actionValue.resourceId === void 0 ? {} : { resourceId: text2(actionValue.resourceId, "actorEnvelope.action.resourceId") },
1312
1360
  inputHash
1313
1361
  };
1314
1362
  if (action.resourceType === void 0 !== (action.resourceId === void 0)) {
@@ -1370,12 +1418,12 @@ function canonicalJson(value) {
1370
1418
  }
1371
1419
  function parseAccountableSubject(value) {
1372
1420
  const path = "actorEnvelope.accountableSubject";
1373
- const subject = record2(value, path);
1421
+ const subject = record3(value, path);
1374
1422
  exactKeys(subject, ["principalType", "principalId", "displayName"], path);
1375
1423
  return {
1376
1424
  principalType: member(subject.principalType, ACCOUNTABLE_SUBJECT_TYPES, `${path}.principalType`),
1377
- principalId: text(subject.principalId, `${path}.principalId`),
1378
- ...subject.displayName === void 0 ? {} : { displayName: text(subject.displayName, `${path}.displayName`) }
1425
+ principalId: text2(subject.principalId, `${path}.principalId`),
1426
+ ...subject.displayName === void 0 ? {} : { displayName: text2(subject.displayName, `${path}.displayName`) }
1379
1427
  };
1380
1428
  }
1381
1429
  async function sha256CanonicalValue(value) {
@@ -1384,7 +1432,7 @@ async function sha256CanonicalValue(value) {
1384
1432
  return `sha256:${Array.from(new Uint8Array(digest2), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
1385
1433
  }
1386
1434
  function parseIdentity(value, path) {
1387
- const identity = record2(value, path);
1435
+ const identity = record3(value, path);
1388
1436
  exactKeys(identity, [
1389
1437
  "principalType",
1390
1438
  "principalId",
@@ -1397,7 +1445,7 @@ function parseIdentity(value, path) {
1397
1445
  ], path);
1398
1446
  return {
1399
1447
  principalType: member(identity.principalType, PRINCIPAL_TYPES, `${path}.principalType`),
1400
- principalId: text(identity.principalId, `${path}.principalId`),
1448
+ principalId: text2(identity.principalId, `${path}.principalId`),
1401
1449
  ...optionalTextFields(identity, path, [
1402
1450
  "displayName",
1403
1451
  "installationId",
@@ -1410,25 +1458,25 @@ function parseIdentity(value, path) {
1410
1458
  }
1411
1459
  function parseDelegation(value) {
1412
1460
  if (value === null) return null;
1413
- const delegation = record2(value, "actorEnvelope.delegation");
1461
+ const delegation = record3(value, "actorEnvelope.delegation");
1414
1462
  exactKeys(delegation, ["taskId", "runId", "lineage"], "actorEnvelope.delegation");
1415
1463
  if (!Array.isArray(delegation.lineage) || delegation.lineage.length === 0 || delegation.lineage.length > 16) {
1416
1464
  fail("actorEnvelope.delegation.lineage", "must contain between 1 and 16 hops");
1417
1465
  }
1418
1466
  return {
1419
- taskId: text(delegation.taskId, "actorEnvelope.delegation.taskId"),
1420
- runId: text(delegation.runId, "actorEnvelope.delegation.runId"),
1467
+ taskId: text2(delegation.taskId, "actorEnvelope.delegation.taskId"),
1468
+ runId: text2(delegation.runId, "actorEnvelope.delegation.runId"),
1421
1469
  lineage: delegation.lineage.map((value2, index) => {
1422
- const hop = record2(value2, `actorEnvelope.delegation.lineage[${index}]`);
1470
+ const hop = record3(value2, `actorEnvelope.delegation.lineage[${index}]`);
1423
1471
  exactKeys(hop, ["principalType", "principalId"], `actorEnvelope.delegation.lineage[${index}]`);
1424
1472
  return {
1425
1473
  principalType: member(hop.principalType, PRINCIPAL_TYPES, `actorEnvelope.delegation.lineage[${index}].principalType`),
1426
- principalId: text(hop.principalId, `actorEnvelope.delegation.lineage[${index}].principalId`)
1474
+ principalId: text2(hop.principalId, `actorEnvelope.delegation.lineage[${index}].principalId`)
1427
1475
  };
1428
1476
  })
1429
1477
  };
1430
1478
  }
1431
- function record2(value, path) {
1479
+ function record3(value, path) {
1432
1480
  if (!value || typeof value !== "object" || Array.isArray(value)) fail(path, "must be an object");
1433
1481
  return value;
1434
1482
  }
@@ -1436,14 +1484,14 @@ function exactKeys(value, allowed, path) {
1436
1484
  const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
1437
1485
  if (unknown.length) fail(path, `contains unknown field ${unknown[0]}`);
1438
1486
  }
1439
- function text(value, path) {
1487
+ function text2(value, path) {
1440
1488
  if (typeof value !== "string" || value.trim() !== value || value.length === 0 || value.length > 256) {
1441
1489
  fail(path, "must be a non-empty trimmed string of at most 256 characters");
1442
1490
  }
1443
1491
  return value;
1444
1492
  }
1445
1493
  function timestamp(value, path) {
1446
- const result = text(value, path);
1494
+ const result = text2(value, path);
1447
1495
  if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(result) || Number.isNaN(Date.parse(result))) {
1448
1496
  fail(path, "must be an RFC 3339 UTC timestamp");
1449
1497
  }
@@ -1455,10 +1503,10 @@ function member(value, values, path) {
1455
1503
  }
1456
1504
  function textArray(value, path) {
1457
1505
  if (!Array.isArray(value) || value.length === 0 || value.length > 16) fail(path, "must contain between 1 and 16 values");
1458
- return value.map((item, index) => text(item, `${path}[${index}]`));
1506
+ return value.map((item, index) => text2(item, `${path}[${index}]`));
1459
1507
  }
1460
1508
  function optionalTextFields(value, path, keys) {
1461
- return Object.fromEntries(keys.flatMap((key) => value[key] === void 0 ? [] : [[key, text(value[key], `${path}.${key}`)]]));
1509
+ return Object.fromEntries(keys.flatMap((key) => value[key] === void 0 ? [] : [[key, text2(value[key], `${path}.${key}`)]]));
1462
1510
  }
1463
1511
  function fail(path, message3) {
1464
1512
  throw new ActorEnvelopeValidationError(path, message3);
@@ -2128,6 +2176,7 @@ var TopoloClient = class _TopoloClient {
2128
2176
  for (const item of raw) {
2129
2177
  if (!isRecord4(item)) continue;
2130
2178
  const s = item;
2179
+ const applicationGuide = normalizeApplicationGuide(s.applicationGuide);
2131
2180
  const appId = typeof s.app_id === "string" ? s.app_id : typeof s.id === "string" ? s.id : null;
2132
2181
  if (!appId) continue;
2133
2182
  const permissions = Array.isArray(s.granted_permissions) ? s.granted_permissions.filter((permission) => typeof permission === "string" && permission.trim().length > 0) : [];
@@ -2141,6 +2190,7 @@ var TopoloClient = class _TopoloClient {
2141
2190
  slug: typeof s.app_slug === "string" ? s.app_slug : null,
2142
2191
  name: typeof s.name === "string" ? s.name : null,
2143
2192
  description: typeof s.description === "string" ? s.description : null,
2193
+ ...applicationGuide ? { applicationGuide } : {},
2144
2194
  apiBaseUrl: typeof s.api_base_url === "string" ? s.api_base_url : typeof s.apiBaseUrl === "string" ? s.apiBaseUrl : null,
2145
2195
  launchUrl: typeof s.launch_url === "string" ? s.launch_url : typeof s.launchUrl === "string" ? s.launchUrl : null,
2146
2196
  status: typeof s.status === "string" ? s.status : null,
@@ -2260,14 +2310,14 @@ var TopoloClient = class _TopoloClient {
2260
2310
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
2261
2311
  throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is unavailable.");
2262
2312
  }
2263
- const record4 = raw;
2264
- if (record4.algorithm !== "sha256-v1" || typeof record4.digest !== "string" || !/^[a-f0-9]{64}$/.test(record4.digest) || !Number.isSafeInteger(record4.actionCount) || Number(record4.actionCount) < 0) {
2313
+ const record5 = raw;
2314
+ if (record5.algorithm !== "sha256-v1" || typeof record5.digest !== "string" || !/^[a-f0-9]{64}$/.test(record5.digest) || !Number.isSafeInteger(record5.actionCount) || Number(record5.actionCount) < 0) {
2265
2315
  throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is invalid.");
2266
2316
  }
2267
2317
  return {
2268
2318
  algorithm: "sha256-v1",
2269
- digest: record4.digest,
2270
- actionCount: Number(record4.actionCount)
2319
+ digest: record5.digest,
2320
+ actionCount: Number(record5.actionCount)
2271
2321
  };
2272
2322
  }
2273
2323
  /** @deprecated Prefer searchActions() so callers retain the continuation cursor. */
@@ -2814,6 +2864,7 @@ function normalizeCatalogPage(value) {
2814
2864
  }
2815
2865
  function normalizeServiceCatalogEntry(item) {
2816
2866
  if (!isRecord4(item)) return null;
2867
+ const applicationGuide = normalizeApplicationGuide(item.applicationGuide);
2817
2868
  const appId = typeof item.app_id === "string" ? item.app_id : typeof item.id === "string" ? item.id : null;
2818
2869
  if (!appId) return null;
2819
2870
  const permissions = Array.isArray(item.granted_permissions) ? item.granted_permissions.filter(
@@ -2829,6 +2880,7 @@ function normalizeServiceCatalogEntry(item) {
2829
2880
  slug: typeof item.app_slug === "string" ? item.app_slug : null,
2830
2881
  name: typeof item.name === "string" ? item.name : null,
2831
2882
  description: typeof item.description === "string" ? item.description : null,
2883
+ ...applicationGuide ? { applicationGuide } : {},
2832
2884
  apiBaseUrl: typeof item.api_base_url === "string" ? item.api_base_url : typeof item.apiBaseUrl === "string" ? item.apiBaseUrl : null,
2833
2885
  launchUrl: typeof item.launch_url === "string" ? item.launch_url : typeof item.launchUrl === "string" ? item.launchUrl : null,
2834
2886
  status: typeof item.status === "string" ? item.status : null,
@@ -2991,10 +3043,10 @@ function extractRequired(body) {
2991
3043
  if (Array.isArray(maybe.required)) return canonicalTopoloRequired(maybe.required);
2992
3044
  for (const nested of [maybe.details, maybe.error]) {
2993
3045
  if (!nested || typeof nested !== "object" || Array.isArray(nested)) continue;
2994
- const record4 = nested;
2995
- if (Array.isArray(record4.required)) return canonicalTopoloRequired(record4.required);
2996
- if (record4.details && typeof record4.details === "object" && !Array.isArray(record4.details)) {
2997
- const required = record4.details.required;
3046
+ const record5 = nested;
3047
+ if (Array.isArray(record5.required)) return canonicalTopoloRequired(record5.required);
3048
+ if (record5.details && typeof record5.details === "object" && !Array.isArray(record5.details)) {
3049
+ const required = record5.details.required;
2998
3050
  if (Array.isArray(required)) return canonicalTopoloRequired(required);
2999
3051
  }
3000
3052
  }
@@ -3071,8 +3123,8 @@ function compactResultValue(value, depth, budget) {
3071
3123
  return value.length > ACTION_RESULT_MAX_ITEMS ? { count: value.length, items, omittedItems: value.length - ACTION_RESULT_MAX_ITEMS } : items;
3072
3124
  }
3073
3125
  if (typeof value === "object") {
3074
- const record4 = value;
3075
- const allKeys = Object.keys(record4);
3126
+ const record5 = value;
3127
+ const allKeys = Object.keys(record5);
3076
3128
  const ranked = allKeys.sort((left, right) => resultKeyPriority(left) - resultKeyPriority(right));
3077
3129
  const prioritized = ranked.filter((key) => resultKeyPriority(key) < 2);
3078
3130
  const ordinary = ranked.filter((key) => resultKeyPriority(key) === 2);
@@ -3081,7 +3133,7 @@ function compactResultValue(value, depth, budget) {
3081
3133
  ...prioritized,
3082
3134
  ...ordinary.slice(0, ordinaryLimit)
3083
3135
  ].slice(0, ACTION_RESULT_MAX_KEYS);
3084
- const compact = Object.fromEntries(keys.map((key) => [key, compactResultValue(record4[key], depth + 1, budget)]));
3136
+ const compact = Object.fromEntries(keys.map((key) => [key, compactResultValue(record5[key], depth + 1, budget)]));
3085
3137
  if (allKeys.length > keys.length) compact["_omittedKeys"] = allKeys.length - keys.length;
3086
3138
  return compact;
3087
3139
  }
@@ -3886,12 +3938,32 @@ async function pollUntilApproved(params) {
3886
3938
  throw new Error("Device code expired. Run `topolo auth login` again.");
3887
3939
  }
3888
3940
 
3889
- // node_modules/.pnpm/@topolo+sdk@0.23.22/node_modules/@topolo/sdk/dist/node/credential-store.js
3941
+ // src/lib/open-browser.ts
3942
+ import { spawn } from "child_process";
3943
+ import { platform } from "os";
3944
+ function tryOpenBrowser(url) {
3945
+ try {
3946
+ const os = platform();
3947
+ const cmd = os === "darwin" ? "open" : os === "win32" ? "start" : "xdg-open";
3948
+ const args = os === "win32" ? ["", url] : [url];
3949
+ const child = spawn(cmd, args, {
3950
+ detached: true,
3951
+ stdio: "ignore",
3952
+ ...os === "win32" ? { shell: true } : {}
3953
+ });
3954
+ child.unref();
3955
+ return true;
3956
+ } catch {
3957
+ return false;
3958
+ }
3959
+ }
3960
+
3961
+ // node_modules/.pnpm/@topolo+sdk@0.23.24/node_modules/@topolo/sdk/dist/node/credential-store.js
3890
3962
  import { mkdir as mkdir2, readFile as readFile2, chmod as chmod2, lstat, readdir as readdir2 } from "fs/promises";
3891
3963
  import { existsSync as existsSync2, mkdirSync, lstatSync, readdirSync, readFileSync as readFileSync2, openSync, writeFileSync, fsyncSync, closeSync, renameSync, unlinkSync, rmdirSync, linkSync } from "fs";
3892
3964
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
3893
3965
  import { constants, fstatSync, readSync } from "fs";
3894
- import { homedir as homedir2, platform } from "os";
3966
+ import { homedir as homedir2, platform as platform2 } from "os";
3895
3967
  import { dirname as dirname2, join as join3 } from "path";
3896
3968
  import { createHash, randomUUID } from "crypto";
3897
3969
  import { join as join2 } from "path";
@@ -3997,9 +4069,9 @@ function canonicalTopoloServiceErrorCode2(value) {
3997
4069
  }
3998
4070
  function sanitizeTopoloServiceMessage2(value) {
3999
4071
  if (typeof value !== "string") return void 0;
4000
- const text2 = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
4001
- if (!text2) return void 0;
4002
- return text2.length > SERVICE_MESSAGE_MAX_LENGTH2 ? `${text2.slice(0, SERVICE_MESSAGE_MAX_LENGTH2 - 1).trimEnd()}\u2026` : text2;
4072
+ const text3 = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
4073
+ if (!text3) return void 0;
4074
+ return text3.length > SERVICE_MESSAGE_MAX_LENGTH2 ? `${text3.slice(0, SERVICE_MESSAGE_MAX_LENGTH2 - 1).trimEnd()}\u2026` : text3;
4003
4075
  }
4004
4076
  function canonicalTopoloRequestId2(value) {
4005
4077
  if (typeof value !== "string") return void 0;
@@ -4040,10 +4112,10 @@ var TopoloAuthError2 = class extends TopoloSdkError2 {
4040
4112
  };
4041
4113
  function extractTopoloServiceErrorCode2(body) {
4042
4114
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
4043
- const record3 = body;
4044
- const topLevel = canonicalTopoloServiceErrorCode2(record3.code);
4115
+ const record4 = body;
4116
+ const topLevel = canonicalTopoloServiceErrorCode2(record4.code);
4045
4117
  if (topLevel) return topLevel;
4046
- const nested = record3.error;
4118
+ const nested = record4.error;
4047
4119
  const nestedString = canonicalTopoloServiceErrorCode2(nested);
4048
4120
  if (nestedString) return nestedString;
4049
4121
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
@@ -4058,14 +4130,14 @@ function serviceErrorCode2(body, fallback) {
4058
4130
  }
4059
4131
  function extractTopoloServiceErrorDetails2(body) {
4060
4132
  if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
4061
- const record3 = body;
4062
- let candidate = record3.details;
4063
- const nested = record3.error;
4133
+ const record4 = body;
4134
+ let candidate = record4.details;
4135
+ const nested = record4.error;
4064
4136
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
4065
4137
  const nestedRecord = nested;
4066
4138
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
4067
4139
  }
4068
- if (candidate === void 0) candidate = record3;
4140
+ if (candidate === void 0) candidate = record4;
4069
4141
  if (Array.isArray(candidate)) return validationIssueDetails2(canonicalTopoloValidationIssues2(candidate)) ?? void 0;
4070
4142
  if (!candidate || typeof candidate !== "object") return void 0;
4071
4143
  const source = candidate;
@@ -4124,18 +4196,18 @@ function validationIssueDetails2(issues) {
4124
4196
  return paths.length ? { paths, issues } : { issues };
4125
4197
  }
4126
4198
  function issue2(path, message3) {
4127
- const text2 = sanitizeTopoloServiceMessage2(message3);
4128
- if (!path && !text2) return null;
4129
- return { ...path ? { path } : {}, ...text2 ? { message: text2 } : {} };
4199
+ const text3 = sanitizeTopoloServiceMessage2(message3);
4200
+ if (!path && !text3) return null;
4201
+ return { ...path ? { path } : {}, ...text3 ? { message: text3 } : {} };
4130
4202
  }
4131
4203
  function canonicalTopoloValidationIssues2(values) {
4132
4204
  const issues = [];
4133
4205
  for (const value of values) {
4134
4206
  if (!value || typeof value !== "object" || Array.isArray(value)) continue;
4135
- const record3 = value;
4136
- const path = canonicalTopoloValidationPath2(record3.field) ?? canonicalTopoloValidationPath2(record3.path);
4207
+ const record4 = value;
4208
+ const path = canonicalTopoloValidationPath2(record4.field) ?? canonicalTopoloValidationPath2(record4.path);
4137
4209
  if (!path) continue;
4138
- const projected = issue2(path, record3.message);
4210
+ const projected = issue2(path, record4.message);
4139
4211
  if (projected) issues.push(projected);
4140
4212
  if (issues.length === SERVICE_ISSUE_LIMIT2) break;
4141
4213
  }
@@ -4572,18 +4644,18 @@ function createProtectedActionSecretStore(options) {
4572
4644
  const key = await account(reference);
4573
4645
  const encoded = await backend.get(key);
4574
4646
  if (!encoded) throw new TopoloSdkError2("action_secret_unavailable", "Protected action reference is missing or belongs to another identity or environment.");
4575
- let record3;
4647
+ let record4;
4576
4648
  try {
4577
- record3 = JSON.parse(encoded);
4649
+ record4 = JSON.parse(encoded);
4578
4650
  } catch {
4579
4651
  throw new TopoloSdkError2("action_secret_invalid", "Protected action reference is corrupt.");
4580
4652
  }
4581
- if (!Number.isFinite(record3?.expiresAt) || !Object.hasOwn(record3, "value")) throw new TopoloSdkError2("action_secret_invalid", "Protected action reference is corrupt.");
4582
- if (record3.expiresAt <= now()) {
4653
+ if (!Number.isFinite(record4?.expiresAt) || !Object.hasOwn(record4, "value")) throw new TopoloSdkError2("action_secret_invalid", "Protected action reference is corrupt.");
4654
+ if (record4.expiresAt <= now()) {
4583
4655
  await backend.delete(key);
4584
4656
  throw new TopoloSdkError2("action_secret_expired", "Protected action reference expired. Repeat the originating action if its contract permits.");
4585
4657
  }
4586
- return record3.value;
4658
+ return record4.value;
4587
4659
  },
4588
4660
  async delete(reference) {
4589
4661
  await backend.delete(await account(reference));
@@ -4659,7 +4731,7 @@ var ENVIRONMENT_DEFAULT_SERVICE_URLS = TOPOLO_ENVIRONMENT_SERVICE_URLS;
4659
4731
  function configPath() {
4660
4732
  const override = process.env.TOPOLO_CONFIG_PATH;
4661
4733
  if (override) return override;
4662
- const base = process.env.XDG_CONFIG_HOME || (platform() === "win32" ? join3(homedir2(), "AppData", "Roaming") : join3(homedir2(), ".config"));
4734
+ const base = process.env.XDG_CONFIG_HOME || (platform2() === "win32" ? join3(homedir2(), "AppData", "Roaming") : join3(homedir2(), ".config"));
4663
4735
  return join3(base, "topolo", "config.json");
4664
4736
  }
4665
4737
  async function readConfig() {
@@ -4678,7 +4750,7 @@ async function writeConfig(config) {
4678
4750
  await withConfigWriteLock(async (_assertOwned, persist) => {
4679
4751
  await persist((current) => protectStoredGrants(config, current), { allowCreate: true });
4680
4752
  });
4681
- if (platform() !== "win32") {
4753
+ if (platform2() !== "win32") {
4682
4754
  try {
4683
4755
  await chmod2(path, 384);
4684
4756
  } catch {
@@ -5524,6 +5596,27 @@ async function continueReauthorization(environment, key) {
5524
5596
  }
5525
5597
  });
5526
5598
  }
5599
+ async function awaitReauthorization(environment, key, options = {}) {
5600
+ const deadline = Date.now() + (options.timeoutMs ?? 15 * 6e4);
5601
+ let lastCode;
5602
+ for (; ; ) {
5603
+ const profile = profileForEnvironment(await readConfig(), environment);
5604
+ const slotKey = key ?? profile.activeContext ?? DEFAULT_SLOT;
5605
+ try {
5606
+ return await continueReauthorization(environment, slotKey);
5607
+ } catch (error) {
5608
+ if (!(error instanceof TopoloReauthRequiredError)) throw error;
5609
+ const prompt = error.reauthorization;
5610
+ if (prompt.userCode !== lastCode) {
5611
+ lastCode = prompt.userCode;
5612
+ options.onPrompt?.(error);
5613
+ }
5614
+ if (prompt.state !== "awaiting_approval" || options.signal?.aborted || Date.now() >= deadline) throw error;
5615
+ const waitMs = Math.max(1, prompt.pollIntervalSeconds ?? 5) * 1e3;
5616
+ await new Promise((resolve22) => setTimeout(resolve22, Math.min(waitMs, Math.max(0, deadline - Date.now()))));
5617
+ }
5618
+ }
5619
+ }
5527
5620
  function resolveAgentName(configAgentName) {
5528
5621
  return process.env.TOPOLO_AGENT_NAME ?? configAgentName;
5529
5622
  }
@@ -5734,13 +5827,43 @@ function normalizeError(err) {
5734
5827
  retryAfter: err.retryAfter,
5735
5828
  // SDK HTTP errors already carry sanitized details; projecting them again
5736
5829
  // would drop form-level issues that have no field path.
5737
- details: err instanceof TopoloHttpError || err instanceof TopoloAuthError || err instanceof TopoloPermissionError ? err.details : extractTopoloServiceErrorDetails(suppliedDetails === void 0 ? body : { details: suppliedDetails }),
5738
- hint: topoloErrorHint({ code, body }) ?? (code ? fallbackHintMap[code] : void 0),
5830
+ details: reauthorizationDetails(err) ?? (err instanceof TopoloHttpError || err instanceof TopoloAuthError || err instanceof TopoloPermissionError ? err.details : extractTopoloServiceErrorDetails(suppliedDetails === void 0 ? body : { details: suppliedDetails })),
5831
+ hint: reauthorizationHint(err) ?? topoloErrorHint({ code, body }) ?? (code ? fallbackHintMap[code] : void 0),
5739
5832
  exitCode: status === 401 || code === "auth_error" || code === "confirmation_required" ? 2 : status === 403 || code === "permission_denied" ? 3 : code === "immutable_drift" ? 4 : 1
5740
5833
  };
5741
5834
  }
5742
5835
  return { message: String(err), exitCode: 1 };
5743
5836
  }
5837
+ function reauthorizationOf(err) {
5838
+ const prompt = err?.reauthorization;
5839
+ return prompt && typeof prompt === "object" ? prompt : void 0;
5840
+ }
5841
+ var REAUTHORIZATION_FIELDS = [
5842
+ "environment",
5843
+ "context",
5844
+ "reason",
5845
+ "state",
5846
+ "verificationUri",
5847
+ "verificationUriComplete",
5848
+ "userCode",
5849
+ "expiresAt",
5850
+ "pollIntervalSeconds",
5851
+ "loginCommand"
5852
+ ];
5853
+ function reauthorizationDetails(err) {
5854
+ const prompt = reauthorizationOf(err);
5855
+ if (!prompt) return void 0;
5856
+ const safe = {};
5857
+ for (const field of REAUTHORIZATION_FIELDS) if (prompt[field] !== void 0) safe[field] = prompt[field];
5858
+ return { reauthorization: safe };
5859
+ }
5860
+ function reauthorizationHint(err) {
5861
+ const prompt = reauthorizationOf(err);
5862
+ if (!prompt) return void 0;
5863
+ const url = prompt.verificationUriComplete ?? prompt.verificationUri;
5864
+ const approve = url ? `Approve at ${url}${prompt.userCode ? ` (code ${prompt.userCode})` : ""}` : "No approval could be started";
5865
+ return `${approve}; or run: ${prompt.loginCommand ?? "topolo auth login"}. The saved sign-in will not be retried.`;
5866
+ }
5744
5867
 
5745
5868
  // src/version.ts
5746
5869
  import { readFileSync as readFileSync3 } from "fs";
@@ -6028,22 +6151,6 @@ async function resolveLoginContext(credential, serviceUrls, clientId, environmen
6028
6151
  }
6029
6152
  return { identity, context: { contextType: "personal", credential, oauthClientId: clientId } };
6030
6153
  }
6031
- function tryOpenBrowser(url) {
6032
- try {
6033
- const os = platform2();
6034
- const cmd = os === "darwin" ? "open" : os === "win32" ? "start" : "xdg-open";
6035
- const args = os === "win32" ? ["", url] : [url];
6036
- const child = spawn(cmd, args, {
6037
- detached: true,
6038
- stdio: "ignore",
6039
- ...os === "win32" ? { shell: true } : {}
6040
- });
6041
- child.unref();
6042
- return true;
6043
- } catch {
6044
- return false;
6045
- }
6046
- }
6047
6154
  function startSpinner() {
6048
6155
  if (!process.stderr.isTTY) return null;
6049
6156
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -6060,12 +6167,66 @@ function startSpinner() {
6060
6167
  };
6061
6168
  }
6062
6169
 
6170
+ // src/lib/reauthorization.ts
6171
+ function isReauthRequired(error) {
6172
+ const candidate = error;
6173
+ return error instanceof Error && candidate?.code === "reauth_required" && typeof candidate.reauthorization === "object" && candidate.reauthorization !== null;
6174
+ }
6175
+ function reauthorizationIsInteractive(env = process.env) {
6176
+ return Boolean(process.stderr.isTTY && process.stdin.isTTY) && !env.CI && env.TOPOLO_NO_REAUTH_PROMPT !== "1";
6177
+ }
6178
+ function describe(error) {
6179
+ const prompt = error.reauthorization;
6180
+ const url = prompt.verificationUriComplete ?? prompt.verificationUri;
6181
+ const expires = prompt.expiresAt ? ` (expires ${prompt.expiresAt})` : "";
6182
+ return ` ${url}
6183
+
6184
+ ` + (prompt.userCode ? ` Confirm the page shows this code:
6185
+
6186
+ ${prompt.userCode}
6187
+
6188
+ ` : "") + ` Waiting for approval${expires}
6189
+ `;
6190
+ }
6191
+ async function credentialWithReauthorization(load, environment, context) {
6192
+ try {
6193
+ return await load();
6194
+ } catch (error) {
6195
+ if (!isReauthRequired(error)) throw error;
6196
+ const prompt = error.reauthorization;
6197
+ const url = prompt.verificationUriComplete ?? prompt.verificationUri;
6198
+ if (!reauthorizationIsInteractive() || prompt.state !== "awaiting_approval" || !url) throw error;
6199
+ const opened = tryOpenBrowser(url);
6200
+ process.stderr.write(
6201
+ `
6202
+ Your saved Topolo sign-in for ${prompt.context} (${prompt.environment}) has ended.
6203
+ ${opened ? "Opening your browser to approve it again:" : "Open this link in your browser to approve it again:"}
6204
+ ` + describe(error)
6205
+ );
6206
+ const remaining = prompt.expiresAt ? Date.parse(prompt.expiresAt) - Date.now() : Number.NaN;
6207
+ const timeoutMs = Number.isFinite(remaining) ? Math.max(1e3, Math.min(remaining, 15 * 6e4)) : 10 * 6e4;
6208
+ const credential = await awaitReauthorization(environment, context, {
6209
+ timeoutMs,
6210
+ onPrompt: (next) => process.stderr.write(`
6211
+ A new approval was started:
6212
+ ${describe(next)}`)
6213
+ });
6214
+ if (!credential) throw error;
6215
+ process.stderr.write(" Approved. Continuing.\n");
6216
+ return credential;
6217
+ }
6218
+ }
6219
+
6063
6220
  // src/client.ts
6064
6221
  async function buildClient(options) {
6065
6222
  const environment = options?.environment ?? selectedEnvironment();
6066
6223
  const config = await readConfig();
6067
6224
  const context = commandContextKey(config, environment, options?.context?.trim() || process.env.TOPOLO_CONTEXT);
6068
- const credential = context ? await refreshContextCredentialIfNeeded(environment, context) : await refreshCredentialIfNeeded(environment);
6225
+ const credential = await credentialWithReauthorization(
6226
+ () => context ? refreshContextCredentialIfNeeded(environment, context) : refreshCredentialIfNeeded(environment),
6227
+ environment,
6228
+ context
6229
+ );
6069
6230
  if (!credential) return null;
6070
6231
  const profile = resolvedProfileConfig(config, environment);
6071
6232
  const topolo = createTopolo({
@@ -6081,7 +6242,11 @@ async function buildClient(options) {
6081
6242
  serviceUrls: profile.serviceUrls,
6082
6243
  requireConfirmForWrites: options?.requireConfirmForWrites,
6083
6244
  ...credential.kind === "access_token" && credential.refreshToken ? {
6084
- refreshCredential: () => context ? refreshContextCredentialIfNeeded(environment, context, { force: true }) : refreshCredentialIfNeeded(environment, { force: true })
6245
+ refreshCredential: () => credentialWithReauthorization(
6246
+ () => context ? refreshContextCredentialIfNeeded(environment, context, { force: true }) : refreshCredentialIfNeeded(environment, { force: true }),
6247
+ environment,
6248
+ context
6249
+ )
6085
6250
  } : {},
6086
6251
  ...isDebugEnabled() ? { debug: stderrDebugLogger } : {}
6087
6252
  });
@@ -6263,10 +6428,10 @@ function resolveConfiguredServiceUrl2(service, serviceUrls) {
6263
6428
  }
6264
6429
  return void 0;
6265
6430
  }
6266
- function parseQueryPairs(pairs) {
6267
- if (!pairs || pairs.length === 0) return void 0;
6431
+ function parseQueryPairs(pairs2) {
6432
+ if (!pairs2 || pairs2.length === 0) return void 0;
6268
6433
  const out = {};
6269
- for (const pair of pairs) {
6434
+ for (const pair of pairs2) {
6270
6435
  const eq = pair.indexOf("=");
6271
6436
  if (eq <= 0) {
6272
6437
  throw new Error(`Invalid --query entry "${pair}". Expected key=value.`);
@@ -6474,9 +6639,9 @@ function externalApprovalHandoff(action, result) {
6474
6639
  if (!result || typeof result !== "object" || Array.isArray(result)) return null;
6475
6640
  const invocation = result.invocation;
6476
6641
  if (!invocation || typeof invocation !== "object" || Array.isArray(invocation)) return null;
6477
- const record3 = invocation;
6478
- if (record3.status !== "awaiting_approval") return null;
6479
- const approval = record3.approval;
6642
+ const record4 = invocation;
6643
+ if (record4.status !== "awaiting_approval") return null;
6644
+ const approval = record4.approval;
6480
6645
  if (!approval || typeof approval !== "object" || Array.isArray(approval)) return null;
6481
6646
  const handoff = approval;
6482
6647
  if (typeof handoff.requestId !== "string" || typeof handoff.verificationUrl !== "string") return null;
@@ -6752,9 +6917,9 @@ async function writeCredentialCustody(request, deps) {
6752
6917
  }
6753
6918
  }
6754
6919
  function requiredText(value, flag) {
6755
- const text2 = value?.trim();
6756
- if (!text2) throw new CustodyError("custody_invalid_input", `${flag} is required.`);
6757
- return text2;
6920
+ const text3 = value?.trim();
6921
+ if (!text3) throw new CustodyError("custody_invalid_input", `${flag} is required.`);
6922
+ return text3;
6758
6923
  }
6759
6924
  function currentUid() {
6760
6925
  return typeof process.getuid === "function" ? process.getuid() : null;
@@ -6923,9 +7088,9 @@ async function writeCustodyFiles(directory, files) {
6923
7088
  }
6924
7089
  function withheldIfSecretLeaks(error, secret) {
6925
7090
  const variants = [secret, encodeURIComponent(secret)];
6926
- const record3 = error;
6927
- const parts = [String(error), String(record3?.message), String(record3?.stack)];
6928
- for (const value of [record3?.body, record3?.details]) {
7091
+ const record4 = error;
7092
+ const parts = [String(error), String(record4?.message), String(record4?.stack)];
7093
+ for (const value of [record4?.body, record4?.details]) {
6929
7094
  try {
6930
7095
  parts.push(String(value), JSON.stringify(value ?? null));
6931
7096
  } catch {
@@ -7276,8 +7441,8 @@ async function authFetchJson(path, init = {}) {
7276
7441
  }
7277
7442
  headers.set("Authorization", `Bearer ${credential.accessToken}`);
7278
7443
  const response = await fetch(`${authBaseUrl}${path}`, { ...init, headers });
7279
- const text2 = await response.text();
7280
- const payload = text2 ? JSON.parse(text2) : {};
7444
+ const text3 = await response.text();
7445
+ const payload = text3 ? JSON.parse(text3) : {};
7281
7446
  if (!response.ok || payload.success === false) {
7282
7447
  const err = new Error(payload.message || payload.error_description || payload.error || "Topolo Auth request failed");
7283
7448
  err.code = payload.code || payload.error;
@@ -7786,9 +7951,9 @@ async function readTomlRegistrations(path, agent) {
7786
7951
  return [...registrations.values()].filter((registration) => registration.command || registration.url);
7787
7952
  }
7788
7953
  async function readGooseRegistrations(path) {
7789
- const text2 = await readFile4(path, "utf8");
7954
+ const text3 = await readFile4(path, "utf8");
7790
7955
  const registrations = [];
7791
- const lines = text2.split(/\r?\n/);
7956
+ const lines = text3.split(/\r?\n/);
7792
7957
  let inExtensions = false;
7793
7958
  let inTopolo = false;
7794
7959
  let current;
@@ -8030,10 +8195,10 @@ async function registerAgentHttpConfig(agent, homeDir, registration, codexHome)
8030
8195
  return;
8031
8196
  }
8032
8197
  const before = await fileSnapshot(config.path);
8033
- const text2 = withoutMcpServerSections(before.contents ?? "", registration.name);
8198
+ const text3 = withoutMcpServerSections(before.contents ?? "", registration.name);
8034
8199
  const headers = Object.entries(registration.headers).map(([key, value]) => JSON.stringify(key) + " = " + JSON.stringify(value)).join(", ");
8035
8200
  const block = "\n\n[mcp_servers." + registration.name + "]\nurl = " + JSON.stringify(registration.url) + "\nhttp_headers = { " + headers + " }\n";
8036
- await atomicWrite(config.path, text2 + block, before);
8201
+ await atomicWrite(config.path, text3 + block, before);
8037
8202
  }
8038
8203
  async function unregisterAgentConfig(agent, homeDir, name, projectDir, codexHome) {
8039
8204
  for (const config of agentConfigPaths(agent, homeDir, projectDir, codexHome)) {
@@ -8041,8 +8206,8 @@ async function unregisterAgentConfig(agent, homeDir, name, projectDir, codexHome
8041
8206
  if (config.format === "json") {
8042
8207
  await unregisterJson(config, agent, name);
8043
8208
  } else if (config.format === "toml") {
8044
- const text2 = withoutMcpServerSections(await readFile5(config.path, "utf8"), name);
8045
- await atomicWrite(config.path, text2 ? text2 + "\n" : "");
8209
+ const text3 = withoutMcpServerSections(await readFile5(config.path, "utf8"), name);
8210
+ await atomicWrite(config.path, text3 ? text3 + "\n" : "");
8046
8211
  } else {
8047
8212
  await unregisterGoose(config.path, name);
8048
8213
  }
@@ -8132,12 +8297,12 @@ async function unregisterJson(config, agent, name) {
8132
8297
  async function registerToml(path, agent, mcp, registration) {
8133
8298
  const before = await fileSnapshot(path);
8134
8299
  const existing = before.contents ?? "";
8135
- const text2 = withoutMcpServerSections(existing, registration.name);
8300
+ const text3 = withoutMcpServerSections(existing, registration.name);
8136
8301
  const args = mcp.args.length ? "\nargs = [" + mcp.args.map((item) => JSON.stringify(item)).join(", ") + "]" : "";
8137
8302
  const environment = registrationEnvironment(agent, registration);
8138
8303
  const environmentText = Object.entries(environment).map(([key, value]) => JSON.stringify(key) + " = " + JSON.stringify(value)).join(", ");
8139
8304
  const block = agent === "grok" ? "\n\n[mcp_servers." + registration.name + "]\ncommand = " + JSON.stringify(mcp.command) + args + "\nenv = { " + environmentText + " }\n" : "\n\n[mcp_servers." + registration.name + "]\ncommand = " + JSON.stringify(mcp.command) + args + "\n\n[mcp_servers." + registration.name + ".env]\n" + Object.entries(environment).map(([key, value]) => key + " = " + JSON.stringify(value)).join("\n") + "\n";
8140
- await atomicWrite(path, text2 + block, before);
8305
+ await atomicWrite(path, text3 + block, before);
8141
8306
  }
8142
8307
  async function registerGoose(path, mcp, registration) {
8143
8308
  const existing = existsSync5(path) ? await readFile5(path, "utf8") : "";
@@ -8160,8 +8325,8 @@ async function unregisterGoose(path, name) {
8160
8325
  const existing = await readFile5(path, "utf8");
8161
8326
  await atomicWrite(path, removeGooseExtension(existing, name));
8162
8327
  }
8163
- function removeGooseExtension(text2, name) {
8164
- const lines = text2.split(/\r?\n/);
8328
+ function removeGooseExtension(text3, name) {
8329
+ const lines = text3.split(/\r?\n/);
8165
8330
  const kept = [];
8166
8331
  let inExtensions = false;
8167
8332
  let skipping = false;
@@ -8181,11 +8346,11 @@ function removeGooseExtension(text2, name) {
8181
8346
  }
8182
8347
  return kept.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
8183
8348
  }
8184
- function insertGooseExtension(text2, block) {
8185
- if (!text2.trim()) return "extensions:\n" + block + "\n";
8186
- const lines = text2.split(/\r?\n/);
8349
+ function insertGooseExtension(text3, block) {
8350
+ if (!text3.trim()) return "extensions:\n" + block + "\n";
8351
+ const lines = text3.split(/\r?\n/);
8187
8352
  const extensionIndex = lines.findIndex((line) => /^extensions:\s*$/.test(line));
8188
- if (extensionIndex < 0) return text2.trimEnd() + "\n\nextensions:\n" + block + "\n";
8353
+ if (extensionIndex < 0) return text3.trimEnd() + "\n\nextensions:\n" + block + "\n";
8189
8354
  let end = lines.length;
8190
8355
  for (let index = extensionIndex + 1; index < lines.length; index += 1) {
8191
8356
  if (/^\S/.test(lines[index]) && lines[index].trim()) {
@@ -8284,11 +8449,11 @@ async function atomicWrite(path, contents, before) {
8284
8449
  }
8285
8450
  }
8286
8451
  }
8287
- function withoutMcpServerSections(text2, name) {
8452
+ function withoutMcpServerSections(text3, name) {
8288
8453
  const section = "[mcp_servers." + name + "]";
8289
8454
  const subsectionPrefix = "[mcp_servers." + name + ".";
8290
8455
  let skipping = false;
8291
- return text2.split(/\r?\n/).filter((line) => {
8456
+ return text3.split(/\r?\n/).filter((line) => {
8292
8457
  const trimmed = line.trim();
8293
8458
  if (trimmed === section || trimmed.startsWith(subsectionPrefix) && trimmed.endsWith("]")) {
8294
8459
  skipping = true;
@@ -8334,18 +8499,18 @@ function validateMcpHubIdentity(value, where = "identity") {
8334
8499
  if (!value || typeof value !== "object" || Array.isArray(value)) {
8335
8500
  throw new Error(`MCP hub ${where} must be an object.`);
8336
8501
  }
8337
- const record3 = value;
8338
- const unknown = Object.keys(record3).filter((key) => !["name", "env", "context"].includes(key));
8502
+ const record4 = value;
8503
+ const unknown = Object.keys(record4).filter((key) => !["name", "env", "context"].includes(key));
8339
8504
  if (unknown.length) throw new Error(`MCP hub ${where} has unsupported field(s): ${unknown.join(", ")}.`);
8340
- const name = record3.name;
8505
+ const name = record4.name;
8341
8506
  if (typeof name !== "string" || !NAME_PATTERN.test(name) || name === RESERVED_NAME) {
8342
8507
  throw new Error(`MCP hub ${where} name must be topolo or topolo-<name> (and not reserved).`);
8343
8508
  }
8344
- const environment = record3.env;
8509
+ const environment = record4.env;
8345
8510
  if (typeof environment !== "string" || !MCP_HUB_ENVIRONMENTS.includes(environment)) {
8346
8511
  throw new Error(`MCP hub identity ${name} env must be one of ${MCP_HUB_ENVIRONMENTS.join(", ")}.`);
8347
8512
  }
8348
- const context = record3.context;
8513
+ const context = record4.context;
8349
8514
  if (context === void 0) {
8350
8515
  throw new Error(`MCP hub identity ${name} must pin a context (a key from \`topolo context ls\`).`);
8351
8516
  }
@@ -8354,27 +8519,27 @@ function validateMcpHubIdentity(value, where = "identity") {
8354
8519
  }
8355
8520
  return { name, environment, context: context.trim() };
8356
8521
  }
8357
- function parseMcpHubConfig(text2, source) {
8522
+ function parseMcpHubConfig(text3, source) {
8358
8523
  let parsed;
8359
8524
  try {
8360
- parsed = JSON.parse(text2);
8525
+ parsed = JSON.parse(text3);
8361
8526
  } catch (error) {
8362
8527
  throw new Error(`Cannot read malformed MCP hub configuration at ${source}: ${error.message}`);
8363
8528
  }
8364
8529
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
8365
8530
  throw new Error(`MCP hub configuration at ${source} must be a JSON object.`);
8366
8531
  }
8367
- const record3 = parsed;
8368
- const unknown = Object.keys(record3).filter((key) => !["version", "port", "identities"].includes(key));
8532
+ const record4 = parsed;
8533
+ const unknown = Object.keys(record4).filter((key) => !["version", "port", "identities"].includes(key));
8369
8534
  if (unknown.length) {
8370
8535
  throw new Error(`MCP hub configuration at ${source} has unsupported field(s): ${unknown.join(", ")}.`);
8371
8536
  }
8372
- if (record3.version !== 1) throw new Error(`MCP hub configuration at ${source} must declare "version": 1.`);
8373
- const port = record3.port === void 0 ? MCP_HUB_DEFAULT_PORT : validateMcpHubPort(record3.port);
8374
- if (record3.identities !== void 0 && !Array.isArray(record3.identities)) {
8537
+ if (record4.version !== 1) throw new Error(`MCP hub configuration at ${source} must declare "version": 1.`);
8538
+ const port = record4.port === void 0 ? MCP_HUB_DEFAULT_PORT : validateMcpHubPort(record4.port);
8539
+ if (record4.identities !== void 0 && !Array.isArray(record4.identities)) {
8375
8540
  throw new Error(`MCP hub configuration at ${source} identities must be an array.`);
8376
8541
  }
8377
- const identities = (record3.identities ?? []).map((entry, index) => validateMcpHubIdentity(entry, `identity #${index + 1}`));
8542
+ const identities = (record4.identities ?? []).map((entry, index) => validateMcpHubIdentity(entry, `identity #${index + 1}`));
8378
8543
  const seen = /* @__PURE__ */ new Set();
8379
8544
  for (const identity of identities) {
8380
8545
  if (seen.has(identity.name)) {
@@ -8396,14 +8561,14 @@ function serializeMcpHubConfig(config) {
8396
8561
  }, null, 2) + "\n";
8397
8562
  }
8398
8563
  async function readMcpHubConfig(path) {
8399
- let text2;
8564
+ let text3;
8400
8565
  try {
8401
- text2 = await readFile6(path, "utf8");
8566
+ text3 = await readFile6(path, "utf8");
8402
8567
  } catch (error) {
8403
8568
  if (error.code === "ENOENT") return emptyMcpHubConfig();
8404
8569
  throw error;
8405
8570
  }
8406
- return parseMcpHubConfig(text2, path);
8571
+ return parseMcpHubConfig(text3, path);
8407
8572
  }
8408
8573
  function upsertMcpHubIdentity(config, identity) {
8409
8574
  const identities = config.identities.filter((entry) => entry.name !== identity.name);
@@ -9725,16 +9890,16 @@ var REVOKE_CREDENTIAL = "app_topolo_auth.principal_credentials.revoke";
9725
9890
  var INSTALLATION_BOOTSTRAP_GRANT = "app_topolo_auth:identity";
9726
9891
  function actionData(value) {
9727
9892
  if (!value || typeof value !== "object") throw new Error("Topolo returned an invalid action response.");
9728
- const record3 = value;
9729
- const data = record3.data;
9730
- return data && typeof data === "object" ? data : record3;
9893
+ const record4 = value;
9894
+ const data = record4.data;
9895
+ return data && typeof data === "object" ? data : record4;
9731
9896
  }
9732
9897
  function requiredRecord(value, name) {
9733
9898
  if (!value || typeof value !== "object") throw new Error(`Topolo did not return ${name}.`);
9734
9899
  return value;
9735
9900
  }
9736
- function requiredString(record3, key) {
9737
- const value = record3[key];
9901
+ function requiredString(record4, key) {
9902
+ const value = record4[key];
9738
9903
  if (typeof value !== "string" || !value.trim()) throw new Error(`Topolo did not return ${key}.`);
9739
9904
  return value;
9740
9905
  }