@topolo/cli 0.13.17 → 0.13.21

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 (148) hide show
  1. package/README.md +18 -4
  2. package/agent-packs/README.md +469 -1
  3. package/agent-packs/coverage_changed.py +1 -1
  4. package/agent-packs/docs/selected-artifacts.md +47 -0
  5. package/agent-packs/documentation/cloud-task-state.md +56 -0
  6. package/agent-packs/domain-contexts/README.md +25 -0
  7. package/agent-packs/domain-contexts/cicd.json +8 -0
  8. package/agent-packs/gui/feed-adapter.js +4 -0
  9. package/agent-packs/gui/index.html +9 -0
  10. package/agent-packs/gui/studio.css +14 -0
  11. package/agent-packs/gui/studio.js +121 -0
  12. package/agent-packs/gui/studio_server.py +355 -0
  13. package/agent-packs/roles/cicd/CLAUDE.md +24 -0
  14. package/agent-packs/specializations/cicd--cicd.json +5 -0
  15. package/agent-packs/specializations/cicd--pipeline-engineering.json +5 -0
  16. package/agent-packs/specializations/cicd--promotion-deployment.json +5 -0
  17. package/agent-packs/specializations/cicd--queue-recovery.json +5 -0
  18. package/agent-packs/specializations/cicd--release-verification.json +5 -0
  19. package/agent-packs/specializations/cicd--runner-capacity.json +5 -0
  20. package/agent-packs/specializations/intakes--engineering-02.json +5 -0
  21. package/agent-packs/specializations/intakes--engineering-03.json +5 -0
  22. package/agent-packs/specializations/intakes--engineering.json +5 -0
  23. package/agent-packs/specializations/intakes--operator-01.json +5 -0
  24. package/agent-packs/specializations/intakes--operator-02.json +5 -0
  25. package/agent-packs/specializations/operator-skills--audio-and-narration-specialist.json +5 -0
  26. package/agent-packs/specializations/operator-skills--brand-and-copywriting-specialist.json +5 -0
  27. package/agent-packs/specializations/operator-skills--capability-research-specialist.json +5 -0
  28. package/agent-packs/specializations/operator-skills--data-analysis-and-visualization.json +5 -0
  29. package/agent-packs/specializations/operator-skills--financial-evidence-specialist.json +5 -0
  30. package/agent-packs/specializations/operator-skills--operating-template-specialist.json +5 -0
  31. package/agent-packs/specializations/operator-skills--operator-skill-library.json +5 -0
  32. package/agent-packs/specializations/operator-skills--operator-skills.json +5 -0
  33. package/agent-packs/specializations/operator-skills--operator-workflow-evaluation.json +5 -0
  34. package/agent-packs/specializations/operator-skills--privacy-and-agreement-review.json +5 -0
  35. package/agent-packs/specializations/operator-skills--storytelling-specialist.json +5 -0
  36. package/agent-packs/specializations/operator-skills--ux-and-accessibility-specialist.json +5 -0
  37. package/agent-packs/specializations/operator-skills--video-production-specialist.json +5 -0
  38. package/agent-packs/specializations/operator-skills--visual-design-specialist.json +5 -0
  39. package/agent-packs/specializations/operator-skills--workflow-integration-specialist.json +5 -0
  40. package/agent-packs/specializations/operators--access-and-privacy.json +5 -0
  41. package/agent-packs/specializations/operators--accounting-evidence-review.json +5 -0
  42. package/agent-packs/specializations/operators--agreement-operations.json +5 -0
  43. package/agent-packs/specializations/operators--books-operator.json +5 -0
  44. package/agent-packs/specializations/operators--brand-operator.json +5 -0
  45. package/agent-packs/specializations/operators--commerce-operations.json +5 -0
  46. package/agent-packs/specializations/operators--communications-operator.json +5 -0
  47. package/agent-packs/specializations/operators--content-and-assets-operator.json +5 -0
  48. package/agent-packs/specializations/operators--customer-operations.json +5 -0
  49. package/agent-packs/specializations/operators--design-operator.json +5 -0
  50. package/agent-packs/specializations/operators--design-production-02.json +5 -0
  51. package/agent-packs/specializations/operators--design-production-03.json +5 -0
  52. package/agent-packs/specializations/operators--design-production-04.json +5 -0
  53. package/agent-packs/specializations/operators--device-and-feed-operator.json +5 -0
  54. package/agent-packs/specializations/operators--director-operator.json +5 -0
  55. package/agent-packs/specializations/operators--experience-review.json +5 -0
  56. package/agent-packs/specializations/operators--growth-operations.json +5 -0
  57. package/agent-packs/specializations/operators--learn-operator.json +5 -0
  58. package/agent-packs/specializations/operators--localization-operator.json +5 -0
  59. package/agent-packs/specializations/operators--operators.json +5 -0
  60. package/agent-packs/specializations/operators--pay-operator.json +5 -0
  61. package/agent-packs/specializations/operators--research-and-intelligence.json +5 -0
  62. package/agent-packs/specializations/operators--roadmap-operator.json +5 -0
  63. package/agent-packs/specializations/operators--social-content-operator.json +5 -0
  64. package/agent-packs/specializations/operators--talent-operations.json +5 -0
  65. package/agent-packs/specializations/operators--web-operator.json +5 -0
  66. package/agent-packs/specializations/operators--workflow-operator.json +5 -0
  67. package/agent-packs/specializations/specialists--adversarial-qa.json +5 -0
  68. package/agent-packs/specializations/specialists--backlog-dispatch.json +5 -0
  69. package/agent-packs/specializations/specialists--build-01.json +5 -0
  70. package/agent-packs/specializations/specialists--build-02.json +5 -0
  71. package/agent-packs/specializations/specialists--build-03.json +5 -0
  72. package/agent-packs/specializations/specialists--developer-environment-steward.json +5 -0
  73. package/agent-packs/specializations/specialists--documentation-knowledge-steward.json +5 -0
  74. package/agent-packs/specializations/specialists--execution-readiness.json +5 -0
  75. package/agent-packs/specializations/specialists--incident-triage.json +5 -0
  76. package/agent-packs/specializations/specialists--platform-package-steward.json +5 -0
  77. package/agent-packs/specializations/specialists--product-direction-01.json +5 -0
  78. package/agent-packs/specializations/specialists--product-direction-02.json +5 -0
  79. package/agent-packs/specializations/specialists--release-recovery.json +5 -0
  80. package/agent-packs/specializations/specialists--release-watch.json +5 -0
  81. package/agent-packs/specializations/specialists--roadmap-planning-01.json +5 -0
  82. package/agent-packs/specializations/specialists--roadmap-planning-02.json +5 -0
  83. package/agent-packs/specializations/specialists--security-permissions-review.json +5 -0
  84. package/agent-packs/specializations/specialists--system-architecture-01.json +5 -0
  85. package/agent-packs/specializations/specialists--system-architecture-02.json +5 -0
  86. package/agent-packs/specializations/specialists--translation.json +5 -0
  87. package/agent-packs/specializations/specialists--ux-consistency-review.json +5 -0
  88. package/agent-packs/specializations/specialists--workflow-improvement.json +5 -0
  89. package/agent-packs/specializations/specialists--worktree-retirement.json +5 -0
  90. package/agent-packs/src/topolo_agent_pack/cicd.py +101 -0
  91. package/agent-packs/src/topolo_agent_pack/claude.py +22 -7
  92. package/agent-packs/src/topolo_agent_pack/claude_activation.py +157 -0
  93. package/agent-packs/src/topolo_agent_pack/claude_completion_recovery.py +216 -0
  94. package/agent-packs/src/topolo_agent_pack/claude_desktop.py +181 -0
  95. package/agent-packs/src/topolo_agent_pack/claude_dispatch.py +240 -0
  96. package/agent-packs/src/topolo_agent_pack/claude_prompt.py +74 -0
  97. package/agent-packs/src/topolo_agent_pack/claude_runner.py +207 -0
  98. package/agent-packs/src/topolo_agent_pack/claude_service.py +397 -0
  99. package/agent-packs/src/topolo_agent_pack/cli.py +188 -18
  100. package/agent-packs/src/topolo_agent_pack/closed_ledger_fence.py +118 -0
  101. package/agent-packs/src/topolo_agent_pack/cloud_attach.py +128 -0
  102. package/agent-packs/src/topolo_agent_pack/cloud_cutover.py +134 -0
  103. package/agent-packs/src/topolo_agent_pack/cloud_delta.py +162 -0
  104. package/agent-packs/src/topolo_agent_pack/cloud_migrate.py +142 -0
  105. package/agent-packs/src/topolo_agent_pack/cloud_recovery.py +42 -0
  106. package/agent-packs/src/topolo_agent_pack/cloud_work.py +126 -0
  107. package/agent-packs/src/topolo_agent_pack/coordinator_activity.py +27 -0
  108. package/agent-packs/src/topolo_agent_pack/coordinator_context.py +91 -0
  109. package/agent-packs/src/topolo_agent_pack/coordinator_refresh.py +116 -0
  110. package/agent-packs/src/topolo_agent_pack/desktop_acceptance.py +45 -0
  111. package/agent-packs/src/topolo_agent_pack/desktop_launcher.py +114 -0
  112. package/agent-packs/src/topolo_agent_pack/domain_context.py +38 -0
  113. package/agent-packs/src/topolo_agent_pack/execution.py +104 -7
  114. package/agent-packs/src/topolo_agent_pack/fresh.py +1 -1
  115. package/agent-packs/src/topolo_agent_pack/frontdoor.py +23 -0
  116. package/agent-packs/src/topolo_agent_pack/linked_task_context.py +80 -0
  117. package/agent-packs/src/topolo_agent_pack/live.py +285 -18
  118. package/agent-packs/src/topolo_agent_pack/native.py +160 -4
  119. package/agent-packs/src/topolo_agent_pack/policy.py +8 -0
  120. package/agent-packs/src/topolo_agent_pack/review_context.py +33 -0
  121. package/agent-packs/src/topolo_agent_pack/role_catalog.py +137 -0
  122. package/agent-packs/src/topolo_agent_pack/role_context.py +63 -0
  123. package/agent-packs/src/topolo_agent_pack/role_refresh.py +50 -0
  124. package/agent-packs/src/topolo_agent_pack/task_models.py +11 -7
  125. package/agent-packs/src/topolo_agent_pack/throughput.py +149 -0
  126. package/agent-packs/src/topolo_agent_pack/topolo.py +7 -1
  127. package/agent-packs/src/topolo_agent_pack/work.py +322 -0
  128. package/agent-packs/src/topolo_agent_pack/work_adoption.py +122 -0
  129. package/agent-packs/src/topolo_agent_pack/work_artifacts.py +84 -0
  130. package/agent-packs/src/topolo_agent_pack/work_context.py +77 -0
  131. package/agent-packs/src/topolo_agent_pack/work_gui.py +51 -0
  132. package/agent-packs/src/topolo_agent_pack/work_native.py +414 -0
  133. package/agent-packs/src/topolo_agent_pack/work_wait.py +151 -0
  134. package/agent-packs/templates/topolo-coordinators/AGENTS.md +7 -0
  135. package/agent-packs/templates/topolo-coordinators/agents/intakes/cicd/AGENTS.md +6 -0
  136. package/agent-packs/templates/topolo-coordinators/agents/intakes/cicd/config.json +4 -0
  137. package/agent-packs/templates/topolo-coordinators/agents/intakes/engineering/AGENTS.md +3 -0
  138. package/agent-packs/templates/topolo-coordinators/agents/intakes/engineering/config.json +4 -0
  139. package/agent-packs/templates/topolo-coordinators/agents/intakes/operator-01/AGENTS.md +3 -0
  140. package/agent-packs/templates/topolo-coordinators/agents/intakes/operator-01/config.json +4 -0
  141. package/agent-packs/templates/topolo-coordinators/pack.json +56 -0
  142. package/dist/chunk-NYDIAYVY.js +144 -0
  143. package/dist/{claude-pack-backend-YEVPAOID.js → chunk-UY5LEU5C.js} +1659 -21
  144. package/dist/claude-desktop-profile-JCQKSY3K.js +13 -0
  145. package/dist/claude-pack-activation-Q25MCEPU.js +506 -0
  146. package/dist/claude-pack-backend-HUTKGIDS.js +90 -0
  147. package/dist/index.js +408 -164
  148. package/package.json +8 -6
package/dist/index.js CHANGED
@@ -36,7 +36,7 @@ function registerAgentPacksCommand(program2) {
36
36
  throw new Error("Exact closed smoke operation, role/case and UUID required.");
37
37
  const store = packs.opts().store ?? resolve(homedir(), "AgentPacks");
38
38
  if (options.harness === "claude") {
39
- const { operateClaudeSmoke } = await import("./claude-pack-backend-YEVPAOID.js");
39
+ const { operateClaudeSmoke } = await import("./claude-pack-backend-HUTKGIDS.js");
40
40
  console.log(JSON.stringify(await operateClaudeSmoke({
41
41
  store,
42
42
  kind: "smoke-" + operation,
@@ -64,9 +64,74 @@ function registerAgentPacksCommand(program2) {
64
64
  if (result.error) throw new Error("Python 3.11 or later is required for local packs.");
65
65
  if (result.status !== 0) process.exitCode = result.status ?? 2;
66
66
  });
67
- packs.command("configure").description("Qualify and configure an adopted Claude roster through its live native backend").argument("<pack>").option("--harness <name>", "Host adapter", "claude").requiredOption("--policy <path>", "Reviewed execution policy JSON").requiredOption("--endpoint <url>", "Explicit loopback main-process inspector endpoint, enabled separately with authorization").requiredOption("--pid <pid>", "Expected Claude main-process PID").option("--apply", "Apply native groups, pins, models, effort and permission modes; otherwise preflight only").action(async (pack, options) => {
67
+ packs.command("startup-settings").description("Apply coordinator pins, model and permissions using discovered native capabilities; separate from cloud activation").argument("<pack>").option("--policy <path>", "Reviewed policy, or new output path with --prepare").option("--allow-native-debugger-menu", "Explicit launcher-only consent for the exact owned main-debugger checkbox").option("--upgrade-control", "Upgrade only the exact idle native control; preserve coordinators, settings and task state").option("--finalize", "Finalize exact native coordinators only after independently reviewed cloud qualification").option("--startup-operation <uuid>", "Original acknowledged startup operation for finalization").option("--qualification-task <uuid>", "Completed cloud qualification task with archived native workers").option("--complete-startup", "Finish only acknowledged settings/control startup without replaying native input or pinning").option("--continue-launch <uuid>", "Continue an exact interrupted cold-launch phase without creating sessions or replaying input").option("--launch-desktop", "Launch or discover the exact owned signed-in Desktop profile before native startup").option("--desktop-profile <path>", "Existing owned Desktop user-data directory; never copied").option("--claude-config-dir <path>", "Existing owned SDK configuration/history directory; never copied").option("--continue-readiness", "Continue only the original acknowledged tool-free probes without resending existing input").option("--reconcile", "Reconcile only an interrupted tool-free coordinator bootstrap; never replay native input").option("--prepare", "Prepare exactly three coordinators and freshly verify approved organization policy before native startup").option("--endpoint <url>", "Explicit authorized loopback Claude main-process endpoint").option("--pid <pid>", "Expected Claude main-process PID").option("--previous-library <path>", "Existing private original coordinator adoption library, retired only after successor acknowledgement").option("--previous-connection <path>", "Explicit private owned Desktop task connection for a quiescent installation transfer").option("--apply", "Apply native startup settings; otherwise preflight only").action(async (pack, options) => {
68
+ const { configureClaudeStartup, recoverClaudeStartup, lockClaudeLibrary, completeClaudeStartup } = await import("./claude-pack-backend-HUTKGIDS.js");
69
+ if (options.continueLaunch) {
70
+ if (!options.launchDesktop || !options.apply || !options.policy || !options.endpoint || !options.pid || options.prepare || options.reconcile || options.continueReadiness || options.completeStartup || options.upgradeControl || options.finalize || options.previousConnection || options.previousLibrary || options.desktopProfile || options.claudeConfigDir || options.startupOperation || options.qualificationTask || options.allowNativeDebuggerMenu) throw Error("Cold continuation requires only exact pending operation, current PID/endpoint/policy, launch-desktop and apply.");
71
+ const { launchActivatedClaudePack } = await import("./claude-pack-activation-Q25MCEPU.js");
72
+ console.log(JSON.stringify(await launchActivatedClaudePack({ store: packs.opts().store ?? resolve(homedir(), "AgentPacks"), pack, policy: options.policy, continueLaunch: options.continueLaunch, endpoint: options.endpoint, pid: Number(options.pid) }), null, 2));
73
+ return;
74
+ }
75
+ if (options.upgradeControl) {
76
+ if (!options.apply || !options.policy || !options.endpoint || !options.pid || !options.startupOperation || options.qualificationTask || options.allowNativeDebuggerMenu || options.finalize || options.launchDesktop || options.prepare || options.reconcile || options.continueReadiness || options.completeStartup || options.previousConnection || options.previousLibrary || options.desktopProfile || options.claudeConfigDir) throw Error("Control upgrade requires only exact original startup and current endpoint/PID/policy/apply.");
77
+ const { upgradeClaudeControl } = await import("./claude-pack-activation-Q25MCEPU.js");
78
+ console.log(JSON.stringify(await upgradeClaudeControl({ store: packs.opts().store ?? resolve(homedir(), "AgentPacks"), pack, policy: options.policy, endpoint: options.endpoint, pid: Number(options.pid), startupOperation: options.startupOperation }), null, 2));
79
+ return;
80
+ }
81
+ if (options.finalize) {
82
+ if (!options.apply || !options.policy || !options.endpoint || !options.pid || !options.startupOperation || !options.qualificationTask || options.launchDesktop || options.prepare || options.reconcile || options.continueReadiness || options.completeStartup || options.previousConnection || options.previousLibrary || options.desktopProfile || options.claudeConfigDir) throw Error("Finalization requires only exact original startup/cloud qualification and current endpoint/PID/policy/apply.");
83
+ const { finalizeClaudePack } = await import("./claude-pack-activation-Q25MCEPU.js");
84
+ console.log(JSON.stringify(await finalizeClaudePack({ store: packs.opts().store ?? resolve(homedir(), "AgentPacks"), pack, policy: options.policy, endpoint: options.endpoint, pid: Number(options.pid), startupOperation: options.startupOperation, qualificationTask: options.qualificationTask, ...options.allowNativeDebuggerMenu ? { allowNativeDebuggerMenu: true } : {} }), null, 2));
85
+ return;
86
+ }
87
+ if (options.startupOperation || options.qualificationTask || options.allowNativeDebuggerMenu) throw Error("Startup/cloud qualification selectors apply only to finalization.");
88
+ if (options.launchDesktop) {
89
+ const root = packs.opts().store ?? resolve(homedir(), "AgentPacks");
90
+ if (existsSync(resolve(root, "claude/activation.json")) && options.apply) {
91
+ const receipt = JSON.parse(readFileSync(resolve(root, "claude/activation.json"), "utf8"));
92
+ if (options.desktopProfile && options.desktopProfile !== receipt.profile?.userData || options.claudeConfigDir && options.claudeConfigDir !== receipt.profile?.codeConfig) throw Error("Activated launch profile differs.");
93
+ if (!options.policy || options.endpoint || options.pid || options.prepare || options.reconcile || options.continueReadiness || options.completeStartup || options.previousLibrary || options.previousConnection) throw Error("Activated launch accepts only current policy and owned profile.");
94
+ const { launchActivatedClaudePack } = await import("./claude-pack-activation-Q25MCEPU.js");
95
+ console.log(JSON.stringify(await launchActivatedClaudePack({ store: root, pack, policy: options.policy }), null, 2));
96
+ return;
97
+ }
98
+ if (!options.policy || !options.desktopProfile || !options.claudeConfigDir || options.endpoint || options.pid || options.prepare || options.reconcile || options.continueReadiness || options.completeStartup || options.previousLibrary || options.previousConnection) throw Error("Managed launch requires only exact existing profile directories, policy and optional apply.");
99
+ const { launchClaudeDesktopProfile } = await import("./claude-desktop-profile-JCQKSY3K.js");
100
+ const release = await lockClaudeLibrary(root);
101
+ try {
102
+ console.log(JSON.stringify(launchClaudeDesktopProfile({ root, pack, policy: options.policy, userData: options.desktopProfile, codeConfig: options.claudeConfigDir, apply: options.apply === true }), null, 2));
103
+ } finally {
104
+ release();
105
+ }
106
+ return;
107
+ }
108
+ if (options.desktopProfile || options.claudeConfigDir || !options.endpoint || !options.pid) throw Error("Native startup requires exact endpoint/PID; profile paths are accepted only for managed launch.");
109
+ if (options.completeStartup) {
110
+ if (!options.apply || !options.policy || options.prepare || options.reconcile || options.continueReadiness || options.previousConnection) throw Error("Late startup completion requires only original policy/apply and existing previous-library proof.");
111
+ console.log(JSON.stringify(await completeClaudeStartup({ store: packs.opts().store ?? resolve(homedir(), "AgentPacks"), pack, policy: options.policy, endpoint: options.endpoint, pid: Number(options.pid), ...options.previousLibrary ? { previousLibrary: options.previousLibrary } : {} }), null, 2));
112
+ return;
113
+ }
114
+ if (options.reconcile) {
115
+ if (options.apply || options.prepare || options.policy || options.previousConnection || options.previousLibrary || options.continueReadiness) throw new Error("Startup reconciliation accepts no apply, preparation, policy or transfer effects.");
116
+ console.log(JSON.stringify(await recoverClaudeStartup({ store: packs.opts().store ?? resolve(homedir(), "AgentPacks"), pack, endpoint: options.endpoint, pid: Number(options.pid) }), null, 2));
117
+ return;
118
+ }
119
+ console.log(JSON.stringify(await configureClaudeStartup({
120
+ store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
121
+ pack,
122
+ policy: options.policy,
123
+ endpoint: options.endpoint,
124
+ pid: Number(options.pid),
125
+ apply: options.apply === true,
126
+ ...options.previousConnection ? { previousConnection: options.previousConnection } : {},
127
+ ...options.previousLibrary ? { previousLibrary: options.previousLibrary } : {},
128
+ ...options.prepare ? { prepare: true } : {},
129
+ ...options.continueReadiness ? { continueReadiness: true } : {}
130
+ }), null, 2));
131
+ });
132
+ packs.command("configure").description("Configure Claude coordinator startup settings through discovered native capabilities; cloud activation is separate").argument("<pack>").option("--harness <name>", "Host adapter", "claude").requiredOption("--policy <path>", "Reviewed execution policy JSON").requiredOption("--endpoint <url>", "Explicit loopback main-process inspector endpoint, enabled separately with authorization").requiredOption("--pid <pid>", "Expected Claude main-process PID").option("--apply", "Apply native groups, pins, models, effort and permission modes; otherwise preflight only").action(async (pack, options) => {
68
133
  if (options.harness !== "claude") throw new Error("Native configure is currently qualified only for Claude Desktop.");
69
- const { configureClaudePack } = await import("./claude-pack-backend-YEVPAOID.js");
134
+ const { configureClaudePack } = await import("./claude-pack-backend-HUTKGIDS.js");
70
135
  const result = await configureClaudePack({
71
136
  store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
72
137
  pack,
@@ -90,9 +155,23 @@ function registerAgentPacksCommand(program2) {
90
155
  "recover",
91
156
  "doctor",
92
157
  "open",
158
+ "desktop-launcher",
93
159
  "policy",
94
160
  "permissions",
95
161
  "lane",
162
+ "work",
163
+ "work-recover",
164
+ "work-install",
165
+ "work-bind-roles",
166
+ "work-cloud-attach",
167
+ "work-cloud-migrate",
168
+ "work-renew-coordinators",
169
+ "work-recover-claude-completion",
170
+ "work-repair-model-ceilings",
171
+ "work-closed-ledger-fence",
172
+ "work-cloud-cutover",
173
+ "work-cloud-prepare-delta",
174
+ "work-refresh-role-refs",
96
175
  "approvals",
97
176
  "remote-recover",
98
177
  "connect",
@@ -108,13 +187,13 @@ function registerAgentPacksCommand(program2) {
108
187
  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
188
  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
189
  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] ?? "")) {
190
+ if (name === "lane" && options.harness === "claude" && !options.adapterHelp && !["allocate", "status", "models-template", "models-install"].includes(args[0] ?? "")) {
112
191
  if (options.connection) {
113
192
  if (args.length !== 1 || !["read", "context-start", "context-read", "fixture-start", "fixture-read", "retire", "close"].includes(args[0]))
114
193
  throw new Error("Closed existing Claude lane control operation required.");
115
194
  const input3 = options.input ? JSON.parse(readFileSync(options.input, "utf8")) : {};
116
195
  if (!input3 || typeof input3 !== "object" || Array.isArray(input3) || Object.keys(input3).some((k) => k !== "operationId")) throw new Error("Only an exact bootstrap/fixture operation UUID may be supplied.");
117
- const { operateClaudeLaneControl } = await import("./claude-pack-backend-YEVPAOID.js");
196
+ const { operateClaudeLaneControl } = await import("./claude-pack-backend-HUTKGIDS.js");
118
197
  console.log(JSON.stringify(await operateClaudeLaneControl({
119
198
  store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
120
199
  connection: options.connection,
@@ -126,7 +205,7 @@ function registerAgentPacksCommand(program2) {
126
205
  throw new Error("Closed Claude lane operation requires --input, --pack, --policy, --endpoint and --pid.");
127
206
  const input2 = JSON.parse(readFileSync(options.input, "utf8"));
128
207
  if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) throw new Error("Closed native lane input object required.");
129
- const { operateClaudeLane } = await import("./claude-pack-backend-YEVPAOID.js");
208
+ const { operateClaudeLane } = await import("./claude-pack-backend-HUTKGIDS.js");
130
209
  console.log(JSON.stringify(await operateClaudeLane({
131
210
  store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
132
211
  pack: options.pack,
@@ -152,7 +231,7 @@ function registerAgentPacksCommand(program2) {
152
231
  decision = response.decision;
153
232
  }
154
233
  if (options.connection) {
155
- const { operateClaudeLaneControl } = await import("./claude-pack-backend-YEVPAOID.js");
234
+ const { operateClaudeLaneControl } = await import("./claude-pack-backend-HUTKGIDS.js");
156
235
  console.log(JSON.stringify(await operateClaudeLaneControl({
157
236
  store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
158
237
  connection: options.connection,
@@ -164,7 +243,7 @@ function registerAgentPacksCommand(program2) {
164
243
  }), null, 2));
165
244
  return;
166
245
  }
167
- const { operateClaudeApprovals } = await import("./claude-pack-backend-YEVPAOID.js");
246
+ const { operateClaudeApprovals } = await import("./claude-pack-backend-HUTKGIDS.js");
168
247
  console.log(JSON.stringify(await operateClaudeApprovals({
169
248
  store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
170
249
  kind: args[0],
@@ -179,7 +258,7 @@ function registerAgentPacksCommand(program2) {
179
258
  if (name !== "lane" && (options.policy || options.endpoint || options.pid || options.apply)) {
180
259
  if (options.harness !== "claude" || !options.policy || !options.endpoint || !options.pid || args.length !== 1)
181
260
  throw new Error("Native switch/recovery requires one Claude pack, --policy, --endpoint and --pid.");
182
- const { configureClaudePack } = await import("./claude-pack-backend-YEVPAOID.js");
261
+ const { configureClaudePack } = await import("./claude-pack-backend-HUTKGIDS.js");
183
262
  const result2 = await configureClaudePack({
184
263
  store: packs.opts().store ?? resolve(homedir(), "AgentPacks"),
185
264
  pack: args[0],
@@ -226,12 +305,10 @@ function registerAgentPacksCommand(program2) {
226
305
  import { Command, Help } from "commander";
227
306
 
228
307
  // src/commands/auth.ts
229
- import { spawn } from "child_process";
230
- import { platform as platform2 } from "os";
231
308
  import { createInterface } from "readline/promises";
232
309
  import { stdin as input } from "process";
233
310
 
234
- // node_modules/.pnpm/@topolo+sdk@0.23.22/node_modules/@topolo/sdk/dist/index.js
311
+ // node_modules/@topolo/sdk/dist/index.js
235
312
  function record(value) {
236
313
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
237
314
  }
@@ -249,6 +326,56 @@ function validTopoloActionAccessPolicy(value) {
249
326
  }
250
327
  return true;
251
328
  }
329
+ function record2(value) {
330
+ return !!value && typeof value === "object" && !Array.isArray(value);
331
+ }
332
+ function text(value, limit = 512) {
333
+ return typeof value === "string" && value.trim() ? value.trim().slice(0, limit) : null;
334
+ }
335
+ function strings2(value) {
336
+ return Array.isArray(value) ? value.slice(0, 8).flatMap((item) => {
337
+ const result = text(item);
338
+ return result ? [result] : [];
339
+ }) : [];
340
+ }
341
+ function pairs(value, first, second) {
342
+ return Array.isArray(value) ? value.slice(0, 8).flatMap((item) => {
343
+ if (!record2(item)) return [];
344
+ const a = text(item[first], 160);
345
+ const b = text(item[second]);
346
+ return a && b ? [{ [first]: a, [second]: b }] : [];
347
+ }) : [];
348
+ }
349
+ function docs(value) {
350
+ const result = text(value, 2048);
351
+ if (!result) return null;
352
+ try {
353
+ const url = new URL(result);
354
+ return url.protocol === "https:" && !url.username && !url.password ? url.href : null;
355
+ } catch {
356
+ return null;
357
+ }
358
+ }
359
+ function normalizeApplicationGuide(value) {
360
+ if (!record2(value) || value.schemaVersion !== 1 || value.source !== "published_application_manifest") return null;
361
+ const purpose = text(value.purpose, 2048);
362
+ const gettingStarted = strings2(value.gettingStarted);
363
+ const docsUrl = docs(value.docsUrl);
364
+ return {
365
+ schemaVersion: 1,
366
+ source: "published_application_manifest",
367
+ publishedAt: text(value.publishedAt, 160),
368
+ purpose,
369
+ problemStatement: text(value.problemStatement, 2048),
370
+ solutionStatement: text(value.solutionStatement, 2048),
371
+ benefits: strings2(value.benefits),
372
+ features: pairs(value.features, "title", "description"),
373
+ gettingStarted,
374
+ worksWellWith: pairs(value.worksWellWith, "appId", "reason"),
375
+ docsUrl,
376
+ missingFields: [...!purpose ? ["purpose"] : [], ...!docsUrl ? ["docsUrl"] : [], ...!gettingStarted.length ? ["gettingStarted"] : []]
377
+ };
378
+ }
252
379
  function applyAuthHeaders(headers, credential) {
253
380
  if (credential.kind === "api_key") {
254
381
  headers.set("X-Api-Key", credential.apiKey);
@@ -364,9 +491,9 @@ function canonicalTopoloServiceErrorCode(value) {
364
491
  }
365
492
  function sanitizeTopoloServiceMessage(value) {
366
493
  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;
494
+ 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();
495
+ if (!text4) return void 0;
496
+ return text4.length > SERVICE_MESSAGE_MAX_LENGTH ? `${text4.slice(0, SERVICE_MESSAGE_MAX_LENGTH - 1).trimEnd()}\u2026` : text4;
370
497
  }
371
498
  function canonicalTopoloRequestId(value) {
372
499
  if (typeof value !== "string") return void 0;
@@ -434,10 +561,10 @@ var TopoloPermissionError = class extends TopoloSdkError {
434
561
  };
435
562
  function extractTopoloServiceErrorCode(body) {
436
563
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
437
- const record4 = body;
438
- const topLevel = canonicalTopoloServiceErrorCode(record4.code);
564
+ const record5 = body;
565
+ const topLevel = canonicalTopoloServiceErrorCode(record5.code);
439
566
  if (topLevel) return topLevel;
440
- const nested = record4.error;
567
+ const nested = record5.error;
441
568
  const nestedString = canonicalTopoloServiceErrorCode(nested);
442
569
  if (nestedString) return nestedString;
443
570
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
@@ -449,13 +576,13 @@ function extractTopoloServiceErrorCode(body) {
449
576
  }
450
577
  function extractTopoloServiceErrorMessage(body) {
451
578
  if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
452
- const record4 = body;
453
- const nested = record4.error;
579
+ const record5 = body;
580
+ const nested = record5.error;
454
581
  const candidates = [];
455
582
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
456
583
  candidates.push(nested.message);
457
584
  }
458
- candidates.push(record4.message, record4.error_description);
585
+ candidates.push(record5.message, record5.error_description);
459
586
  if (typeof nested === "string" && !canonicalTopoloServiceErrorCode(nested)) candidates.push(nested);
460
587
  for (const candidate of candidates) {
461
588
  const message3 = sanitizeTopoloServiceMessage(candidate);
@@ -468,14 +595,14 @@ function serviceErrorCode(body, fallback) {
468
595
  }
469
596
  function extractTopoloServiceErrorDetails(body) {
470
597
  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;
598
+ const record5 = body;
599
+ let candidate = record5.details;
600
+ const nested = record5.error;
474
601
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
475
602
  const nestedRecord = nested;
476
603
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
477
604
  }
478
- if (candidate === void 0) candidate = record4;
605
+ if (candidate === void 0) candidate = record5;
479
606
  if (Array.isArray(candidate)) return validationIssueDetails(canonicalTopoloValidationIssues(candidate)) ?? void 0;
480
607
  if (!candidate || typeof candidate !== "object") return void 0;
481
608
  const source = candidate;
@@ -534,18 +661,18 @@ function validationIssueDetails(issues) {
534
661
  return paths.length ? { paths, issues } : { issues };
535
662
  }
536
663
  function issue(path, message3) {
537
- const text3 = sanitizeTopoloServiceMessage(message3);
538
- if (!path && !text3) return null;
539
- return { ...path ? { path } : {}, ...text3 ? { message: text3 } : {} };
664
+ const text4 = sanitizeTopoloServiceMessage(message3);
665
+ if (!path && !text4) return null;
666
+ return { ...path ? { path } : {}, ...text4 ? { message: text4 } : {} };
540
667
  }
541
668
  function canonicalTopoloValidationIssues(values) {
542
669
  const issues = [];
543
670
  for (const value of values) {
544
671
  if (!value || typeof value !== "object" || Array.isArray(value)) continue;
545
- const record4 = value;
546
- const path = canonicalTopoloValidationPath(record4.field) ?? canonicalTopoloValidationPath(record4.path);
672
+ const record5 = value;
673
+ const path = canonicalTopoloValidationPath(record5.field) ?? canonicalTopoloValidationPath(record5.path);
547
674
  if (!path) continue;
548
- const projected = issue(path, record4.message);
675
+ const projected = issue(path, record5.message);
549
676
  if (projected) issues.push(projected);
550
677
  if (issues.length === SERVICE_ISSUE_LIMIT) break;
551
678
  }
@@ -699,8 +826,8 @@ function sensitive(key, value) {
699
826
  const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
700
827
  if (normalized === "capability") {
701
828
  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);
829
+ const text4 = value.trim();
830
+ return Boolean(text4) && !/^[a-z][a-z0-9_-]{0,31}$/.test(text4);
704
831
  }
705
832
  return ["authorization", "cookie", "setcookie", "proxyauthorization"].includes(normalized) || /(token|secret|password|privatekey|apikey|backupcodes?|recoverycodes?)$/.test(normalized);
706
833
  }
@@ -1269,7 +1396,7 @@ var ActorEnvelopeValidationError = class extends Error {
1269
1396
  }
1270
1397
  };
1271
1398
  function parseActorEnvelope(value) {
1272
- const envelope = record2(value, "actorEnvelope");
1399
+ const envelope = record3(value, "actorEnvelope");
1273
1400
  exactKeys(envelope, [
1274
1401
  "schemaVersion",
1275
1402
  "organizationId",
@@ -1287,28 +1414,28 @@ function parseActorEnvelope(value) {
1287
1414
  }
1288
1415
  const accountableSubject = parseAccountableSubject(envelope.accountableSubject);
1289
1416
  const performer = parseIdentity(envelope.performer, "actorEnvelope.performer");
1290
- const organizationId = text(envelope.organizationId, "actorEnvelope.organizationId");
1417
+ const organizationId = text2(envelope.organizationId, "actorEnvelope.organizationId");
1291
1418
  const channel = member(envelope.channel, CHANNELS, "actorEnvelope.channel");
1292
1419
  const issuedAt = timestamp(envelope.issuedAt, "actorEnvelope.issuedAt");
1293
1420
  const expiresAt = envelope.expiresAt === void 0 ? void 0 : timestamp(envelope.expiresAt, "actorEnvelope.expiresAt");
1294
1421
  if (expiresAt && Date.parse(expiresAt) <= Date.parse(issuedAt)) {
1295
1422
  fail("actorEnvelope.expiresAt", "must be later than issuedAt");
1296
1423
  }
1297
- const assuranceValue = record2(envelope.assurance, "actorEnvelope.assurance");
1424
+ const assuranceValue = record3(envelope.assurance, "actorEnvelope.assurance");
1298
1425
  exactKeys(assuranceValue, ["level", "methods"], "actorEnvelope.assurance");
1299
1426
  const assurance = {
1300
1427
  level: member(assuranceValue.level, ASSURANCE_LEVELS, "actorEnvelope.assurance.level"),
1301
1428
  methods: textArray(assuranceValue.methods, "actorEnvelope.assurance.methods")
1302
1429
  };
1303
- const actionValue = record2(envelope.action, "actorEnvelope.action");
1430
+ const actionValue = record3(envelope.action, "actorEnvelope.action");
1304
1431
  exactKeys(actionValue, ["requestId", "actionId", "resourceType", "resourceId", "inputHash"], "actorEnvelope.action");
1305
- const inputHash = text(actionValue.inputHash, "actorEnvelope.action.inputHash");
1432
+ const inputHash = text2(actionValue.inputHash, "actorEnvelope.action.inputHash");
1306
1433
  if (!HASH_PATTERN.test(inputHash)) fail("actorEnvelope.action.inputHash", "must be a lowercase sha256 digest");
1307
1434
  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") },
1435
+ requestId: text2(actionValue.requestId, "actorEnvelope.action.requestId"),
1436
+ actionId: text2(actionValue.actionId, "actorEnvelope.action.actionId"),
1437
+ ...actionValue.resourceType === void 0 ? {} : { resourceType: text2(actionValue.resourceType, "actorEnvelope.action.resourceType") },
1438
+ ...actionValue.resourceId === void 0 ? {} : { resourceId: text2(actionValue.resourceId, "actorEnvelope.action.resourceId") },
1312
1439
  inputHash
1313
1440
  };
1314
1441
  if (action.resourceType === void 0 !== (action.resourceId === void 0)) {
@@ -1370,12 +1497,12 @@ function canonicalJson(value) {
1370
1497
  }
1371
1498
  function parseAccountableSubject(value) {
1372
1499
  const path = "actorEnvelope.accountableSubject";
1373
- const subject = record2(value, path);
1500
+ const subject = record3(value, path);
1374
1501
  exactKeys(subject, ["principalType", "principalId", "displayName"], path);
1375
1502
  return {
1376
1503
  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`) }
1504
+ principalId: text2(subject.principalId, `${path}.principalId`),
1505
+ ...subject.displayName === void 0 ? {} : { displayName: text2(subject.displayName, `${path}.displayName`) }
1379
1506
  };
1380
1507
  }
1381
1508
  async function sha256CanonicalValue(value) {
@@ -1384,7 +1511,7 @@ async function sha256CanonicalValue(value) {
1384
1511
  return `sha256:${Array.from(new Uint8Array(digest2), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
1385
1512
  }
1386
1513
  function parseIdentity(value, path) {
1387
- const identity = record2(value, path);
1514
+ const identity = record3(value, path);
1388
1515
  exactKeys(identity, [
1389
1516
  "principalType",
1390
1517
  "principalId",
@@ -1397,7 +1524,7 @@ function parseIdentity(value, path) {
1397
1524
  ], path);
1398
1525
  return {
1399
1526
  principalType: member(identity.principalType, PRINCIPAL_TYPES, `${path}.principalType`),
1400
- principalId: text(identity.principalId, `${path}.principalId`),
1527
+ principalId: text2(identity.principalId, `${path}.principalId`),
1401
1528
  ...optionalTextFields(identity, path, [
1402
1529
  "displayName",
1403
1530
  "installationId",
@@ -1410,25 +1537,25 @@ function parseIdentity(value, path) {
1410
1537
  }
1411
1538
  function parseDelegation(value) {
1412
1539
  if (value === null) return null;
1413
- const delegation = record2(value, "actorEnvelope.delegation");
1540
+ const delegation = record3(value, "actorEnvelope.delegation");
1414
1541
  exactKeys(delegation, ["taskId", "runId", "lineage"], "actorEnvelope.delegation");
1415
1542
  if (!Array.isArray(delegation.lineage) || delegation.lineage.length === 0 || delegation.lineage.length > 16) {
1416
1543
  fail("actorEnvelope.delegation.lineage", "must contain between 1 and 16 hops");
1417
1544
  }
1418
1545
  return {
1419
- taskId: text(delegation.taskId, "actorEnvelope.delegation.taskId"),
1420
- runId: text(delegation.runId, "actorEnvelope.delegation.runId"),
1546
+ taskId: text2(delegation.taskId, "actorEnvelope.delegation.taskId"),
1547
+ runId: text2(delegation.runId, "actorEnvelope.delegation.runId"),
1421
1548
  lineage: delegation.lineage.map((value2, index) => {
1422
- const hop = record2(value2, `actorEnvelope.delegation.lineage[${index}]`);
1549
+ const hop = record3(value2, `actorEnvelope.delegation.lineage[${index}]`);
1423
1550
  exactKeys(hop, ["principalType", "principalId"], `actorEnvelope.delegation.lineage[${index}]`);
1424
1551
  return {
1425
1552
  principalType: member(hop.principalType, PRINCIPAL_TYPES, `actorEnvelope.delegation.lineage[${index}].principalType`),
1426
- principalId: text(hop.principalId, `actorEnvelope.delegation.lineage[${index}].principalId`)
1553
+ principalId: text2(hop.principalId, `actorEnvelope.delegation.lineage[${index}].principalId`)
1427
1554
  };
1428
1555
  })
1429
1556
  };
1430
1557
  }
1431
- function record2(value, path) {
1558
+ function record3(value, path) {
1432
1559
  if (!value || typeof value !== "object" || Array.isArray(value)) fail(path, "must be an object");
1433
1560
  return value;
1434
1561
  }
@@ -1436,14 +1563,14 @@ function exactKeys(value, allowed, path) {
1436
1563
  const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
1437
1564
  if (unknown.length) fail(path, `contains unknown field ${unknown[0]}`);
1438
1565
  }
1439
- function text(value, path) {
1566
+ function text2(value, path) {
1440
1567
  if (typeof value !== "string" || value.trim() !== value || value.length === 0 || value.length > 256) {
1441
1568
  fail(path, "must be a non-empty trimmed string of at most 256 characters");
1442
1569
  }
1443
1570
  return value;
1444
1571
  }
1445
1572
  function timestamp(value, path) {
1446
- const result = text(value, path);
1573
+ const result = text2(value, path);
1447
1574
  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
1575
  fail(path, "must be an RFC 3339 UTC timestamp");
1449
1576
  }
@@ -1455,10 +1582,10 @@ function member(value, values, path) {
1455
1582
  }
1456
1583
  function textArray(value, path) {
1457
1584
  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}]`));
1585
+ return value.map((item, index) => text2(item, `${path}[${index}]`));
1459
1586
  }
1460
1587
  function optionalTextFields(value, path, keys) {
1461
- return Object.fromEntries(keys.flatMap((key) => value[key] === void 0 ? [] : [[key, text(value[key], `${path}.${key}`)]]));
1588
+ return Object.fromEntries(keys.flatMap((key) => value[key] === void 0 ? [] : [[key, text2(value[key], `${path}.${key}`)]]));
1462
1589
  }
1463
1590
  function fail(path, message3) {
1464
1591
  throw new ActorEnvelopeValidationError(path, message3);
@@ -2128,6 +2255,7 @@ var TopoloClient = class _TopoloClient {
2128
2255
  for (const item of raw) {
2129
2256
  if (!isRecord4(item)) continue;
2130
2257
  const s = item;
2258
+ const applicationGuide = normalizeApplicationGuide(s.applicationGuide);
2131
2259
  const appId = typeof s.app_id === "string" ? s.app_id : typeof s.id === "string" ? s.id : null;
2132
2260
  if (!appId) continue;
2133
2261
  const permissions = Array.isArray(s.granted_permissions) ? s.granted_permissions.filter((permission) => typeof permission === "string" && permission.trim().length > 0) : [];
@@ -2141,6 +2269,7 @@ var TopoloClient = class _TopoloClient {
2141
2269
  slug: typeof s.app_slug === "string" ? s.app_slug : null,
2142
2270
  name: typeof s.name === "string" ? s.name : null,
2143
2271
  description: typeof s.description === "string" ? s.description : null,
2272
+ ...applicationGuide ? { applicationGuide } : {},
2144
2273
  apiBaseUrl: typeof s.api_base_url === "string" ? s.api_base_url : typeof s.apiBaseUrl === "string" ? s.apiBaseUrl : null,
2145
2274
  launchUrl: typeof s.launch_url === "string" ? s.launch_url : typeof s.launchUrl === "string" ? s.launchUrl : null,
2146
2275
  status: typeof s.status === "string" ? s.status : null,
@@ -2260,14 +2389,14 @@ var TopoloClient = class _TopoloClient {
2260
2389
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
2261
2390
  throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is unavailable.");
2262
2391
  }
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) {
2392
+ const record5 = raw;
2393
+ 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
2394
  throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is invalid.");
2266
2395
  }
2267
2396
  return {
2268
2397
  algorithm: "sha256-v1",
2269
- digest: record4.digest,
2270
- actionCount: Number(record4.actionCount)
2398
+ digest: record5.digest,
2399
+ actionCount: Number(record5.actionCount)
2271
2400
  };
2272
2401
  }
2273
2402
  /** @deprecated Prefer searchActions() so callers retain the continuation cursor. */
@@ -2814,6 +2943,7 @@ function normalizeCatalogPage(value) {
2814
2943
  }
2815
2944
  function normalizeServiceCatalogEntry(item) {
2816
2945
  if (!isRecord4(item)) return null;
2946
+ const applicationGuide = normalizeApplicationGuide(item.applicationGuide);
2817
2947
  const appId = typeof item.app_id === "string" ? item.app_id : typeof item.id === "string" ? item.id : null;
2818
2948
  if (!appId) return null;
2819
2949
  const permissions = Array.isArray(item.granted_permissions) ? item.granted_permissions.filter(
@@ -2829,6 +2959,7 @@ function normalizeServiceCatalogEntry(item) {
2829
2959
  slug: typeof item.app_slug === "string" ? item.app_slug : null,
2830
2960
  name: typeof item.name === "string" ? item.name : null,
2831
2961
  description: typeof item.description === "string" ? item.description : null,
2962
+ ...applicationGuide ? { applicationGuide } : {},
2832
2963
  apiBaseUrl: typeof item.api_base_url === "string" ? item.api_base_url : typeof item.apiBaseUrl === "string" ? item.apiBaseUrl : null,
2833
2964
  launchUrl: typeof item.launch_url === "string" ? item.launch_url : typeof item.launchUrl === "string" ? item.launchUrl : null,
2834
2965
  status: typeof item.status === "string" ? item.status : null,
@@ -2991,10 +3122,10 @@ function extractRequired(body) {
2991
3122
  if (Array.isArray(maybe.required)) return canonicalTopoloRequired(maybe.required);
2992
3123
  for (const nested of [maybe.details, maybe.error]) {
2993
3124
  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;
3125
+ const record5 = nested;
3126
+ if (Array.isArray(record5.required)) return canonicalTopoloRequired(record5.required);
3127
+ if (record5.details && typeof record5.details === "object" && !Array.isArray(record5.details)) {
3128
+ const required = record5.details.required;
2998
3129
  if (Array.isArray(required)) return canonicalTopoloRequired(required);
2999
3130
  }
3000
3131
  }
@@ -3071,8 +3202,8 @@ function compactResultValue(value, depth, budget) {
3071
3202
  return value.length > ACTION_RESULT_MAX_ITEMS ? { count: value.length, items, omittedItems: value.length - ACTION_RESULT_MAX_ITEMS } : items;
3072
3203
  }
3073
3204
  if (typeof value === "object") {
3074
- const record4 = value;
3075
- const allKeys = Object.keys(record4);
3205
+ const record5 = value;
3206
+ const allKeys = Object.keys(record5);
3076
3207
  const ranked = allKeys.sort((left, right) => resultKeyPriority(left) - resultKeyPriority(right));
3077
3208
  const prioritized = ranked.filter((key) => resultKeyPriority(key) < 2);
3078
3209
  const ordinary = ranked.filter((key) => resultKeyPriority(key) === 2);
@@ -3081,7 +3212,7 @@ function compactResultValue(value, depth, budget) {
3081
3212
  ...prioritized,
3082
3213
  ...ordinary.slice(0, ordinaryLimit)
3083
3214
  ].slice(0, ACTION_RESULT_MAX_KEYS);
3084
- const compact = Object.fromEntries(keys.map((key) => [key, compactResultValue(record4[key], depth + 1, budget)]));
3215
+ const compact = Object.fromEntries(keys.map((key) => [key, compactResultValue(record5[key], depth + 1, budget)]));
3085
3216
  if (allKeys.length > keys.length) compact["_omittedKeys"] = allKeys.length - keys.length;
3086
3217
  return compact;
3087
3218
  }
@@ -3886,12 +4017,32 @@ async function pollUntilApproved(params) {
3886
4017
  throw new Error("Device code expired. Run `topolo auth login` again.");
3887
4018
  }
3888
4019
 
3889
- // node_modules/.pnpm/@topolo+sdk@0.23.22/node_modules/@topolo/sdk/dist/node/credential-store.js
4020
+ // src/lib/open-browser.ts
4021
+ import { spawn } from "child_process";
4022
+ import { platform } from "os";
4023
+ function tryOpenBrowser(url) {
4024
+ try {
4025
+ const os = platform();
4026
+ const cmd = os === "darwin" ? "open" : os === "win32" ? "start" : "xdg-open";
4027
+ const args = os === "win32" ? ["", url] : [url];
4028
+ const child = spawn(cmd, args, {
4029
+ detached: true,
4030
+ stdio: "ignore",
4031
+ ...os === "win32" ? { shell: true } : {}
4032
+ });
4033
+ child.unref();
4034
+ return true;
4035
+ } catch {
4036
+ return false;
4037
+ }
4038
+ }
4039
+
4040
+ // node_modules/@topolo/sdk/dist/node/credential-store.js
3890
4041
  import { mkdir as mkdir2, readFile as readFile2, chmod as chmod2, lstat, readdir as readdir2 } from "fs/promises";
3891
4042
  import { existsSync as existsSync2, mkdirSync, lstatSync, readdirSync, readFileSync as readFileSync2, openSync, writeFileSync, fsyncSync, closeSync, renameSync, unlinkSync, rmdirSync, linkSync } from "fs";
3892
4043
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
3893
4044
  import { constants, fstatSync, readSync } from "fs";
3894
- import { homedir as homedir2, platform } from "os";
4045
+ import { homedir as homedir2, platform as platform2 } from "os";
3895
4046
  import { dirname as dirname2, join as join3 } from "path";
3896
4047
  import { createHash, randomUUID } from "crypto";
3897
4048
  import { join as join2 } from "path";
@@ -3997,9 +4148,9 @@ function canonicalTopoloServiceErrorCode2(value) {
3997
4148
  }
3998
4149
  function sanitizeTopoloServiceMessage2(value) {
3999
4150
  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;
4151
+ 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();
4152
+ if (!text3) return void 0;
4153
+ return text3.length > SERVICE_MESSAGE_MAX_LENGTH2 ? `${text3.slice(0, SERVICE_MESSAGE_MAX_LENGTH2 - 1).trimEnd()}\u2026` : text3;
4003
4154
  }
4004
4155
  function canonicalTopoloRequestId2(value) {
4005
4156
  if (typeof value !== "string") return void 0;
@@ -4040,10 +4191,10 @@ var TopoloAuthError2 = class extends TopoloSdkError2 {
4040
4191
  };
4041
4192
  function extractTopoloServiceErrorCode2(body) {
4042
4193
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
4043
- const record3 = body;
4044
- const topLevel = canonicalTopoloServiceErrorCode2(record3.code);
4194
+ const record4 = body;
4195
+ const topLevel = canonicalTopoloServiceErrorCode2(record4.code);
4045
4196
  if (topLevel) return topLevel;
4046
- const nested = record3.error;
4197
+ const nested = record4.error;
4047
4198
  const nestedString = canonicalTopoloServiceErrorCode2(nested);
4048
4199
  if (nestedString) return nestedString;
4049
4200
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
@@ -4058,14 +4209,14 @@ function serviceErrorCode2(body, fallback) {
4058
4209
  }
4059
4210
  function extractTopoloServiceErrorDetails2(body) {
4060
4211
  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;
4212
+ const record4 = body;
4213
+ let candidate = record4.details;
4214
+ const nested = record4.error;
4064
4215
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
4065
4216
  const nestedRecord = nested;
4066
4217
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
4067
4218
  }
4068
- if (candidate === void 0) candidate = record3;
4219
+ if (candidate === void 0) candidate = record4;
4069
4220
  if (Array.isArray(candidate)) return validationIssueDetails2(canonicalTopoloValidationIssues2(candidate)) ?? void 0;
4070
4221
  if (!candidate || typeof candidate !== "object") return void 0;
4071
4222
  const source = candidate;
@@ -4124,18 +4275,18 @@ function validationIssueDetails2(issues) {
4124
4275
  return paths.length ? { paths, issues } : { issues };
4125
4276
  }
4126
4277
  function issue2(path, message3) {
4127
- const text2 = sanitizeTopoloServiceMessage2(message3);
4128
- if (!path && !text2) return null;
4129
- return { ...path ? { path } : {}, ...text2 ? { message: text2 } : {} };
4278
+ const text3 = sanitizeTopoloServiceMessage2(message3);
4279
+ if (!path && !text3) return null;
4280
+ return { ...path ? { path } : {}, ...text3 ? { message: text3 } : {} };
4130
4281
  }
4131
4282
  function canonicalTopoloValidationIssues2(values) {
4132
4283
  const issues = [];
4133
4284
  for (const value of values) {
4134
4285
  if (!value || typeof value !== "object" || Array.isArray(value)) continue;
4135
- const record3 = value;
4136
- const path = canonicalTopoloValidationPath2(record3.field) ?? canonicalTopoloValidationPath2(record3.path);
4286
+ const record4 = value;
4287
+ const path = canonicalTopoloValidationPath2(record4.field) ?? canonicalTopoloValidationPath2(record4.path);
4137
4288
  if (!path) continue;
4138
- const projected = issue2(path, record3.message);
4289
+ const projected = issue2(path, record4.message);
4139
4290
  if (projected) issues.push(projected);
4140
4291
  if (issues.length === SERVICE_ISSUE_LIMIT2) break;
4141
4292
  }
@@ -4572,18 +4723,18 @@ function createProtectedActionSecretStore(options) {
4572
4723
  const key = await account(reference);
4573
4724
  const encoded = await backend.get(key);
4574
4725
  if (!encoded) throw new TopoloSdkError2("action_secret_unavailable", "Protected action reference is missing or belongs to another identity or environment.");
4575
- let record3;
4726
+ let record4;
4576
4727
  try {
4577
- record3 = JSON.parse(encoded);
4728
+ record4 = JSON.parse(encoded);
4578
4729
  } catch {
4579
4730
  throw new TopoloSdkError2("action_secret_invalid", "Protected action reference is corrupt.");
4580
4731
  }
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()) {
4732
+ if (!Number.isFinite(record4?.expiresAt) || !Object.hasOwn(record4, "value")) throw new TopoloSdkError2("action_secret_invalid", "Protected action reference is corrupt.");
4733
+ if (record4.expiresAt <= now()) {
4583
4734
  await backend.delete(key);
4584
4735
  throw new TopoloSdkError2("action_secret_expired", "Protected action reference expired. Repeat the originating action if its contract permits.");
4585
4736
  }
4586
- return record3.value;
4737
+ return record4.value;
4587
4738
  },
4588
4739
  async delete(reference) {
4589
4740
  await backend.delete(await account(reference));
@@ -4659,7 +4810,7 @@ var ENVIRONMENT_DEFAULT_SERVICE_URLS = TOPOLO_ENVIRONMENT_SERVICE_URLS;
4659
4810
  function configPath() {
4660
4811
  const override = process.env.TOPOLO_CONFIG_PATH;
4661
4812
  if (override) return override;
4662
- const base = process.env.XDG_CONFIG_HOME || (platform() === "win32" ? join3(homedir2(), "AppData", "Roaming") : join3(homedir2(), ".config"));
4813
+ const base = process.env.XDG_CONFIG_HOME || (platform2() === "win32" ? join3(homedir2(), "AppData", "Roaming") : join3(homedir2(), ".config"));
4663
4814
  return join3(base, "topolo", "config.json");
4664
4815
  }
4665
4816
  async function readConfig() {
@@ -4678,7 +4829,7 @@ async function writeConfig(config) {
4678
4829
  await withConfigWriteLock(async (_assertOwned, persist) => {
4679
4830
  await persist((current) => protectStoredGrants(config, current), { allowCreate: true });
4680
4831
  });
4681
- if (platform() !== "win32") {
4832
+ if (platform2() !== "win32") {
4682
4833
  try {
4683
4834
  await chmod2(path, 384);
4684
4835
  } catch {
@@ -5524,6 +5675,27 @@ async function continueReauthorization(environment, key) {
5524
5675
  }
5525
5676
  });
5526
5677
  }
5678
+ async function awaitReauthorization(environment, key, options = {}) {
5679
+ const deadline = Date.now() + (options.timeoutMs ?? 15 * 6e4);
5680
+ let lastCode;
5681
+ for (; ; ) {
5682
+ const profile = profileForEnvironment(await readConfig(), environment);
5683
+ const slotKey = key ?? profile.activeContext ?? DEFAULT_SLOT;
5684
+ try {
5685
+ return await continueReauthorization(environment, slotKey);
5686
+ } catch (error) {
5687
+ if (!(error instanceof TopoloReauthRequiredError)) throw error;
5688
+ const prompt = error.reauthorization;
5689
+ if (prompt.userCode !== lastCode) {
5690
+ lastCode = prompt.userCode;
5691
+ options.onPrompt?.(error);
5692
+ }
5693
+ if (prompt.state !== "awaiting_approval" || options.signal?.aborted || Date.now() >= deadline) throw error;
5694
+ const waitMs = Math.max(1, prompt.pollIntervalSeconds ?? 5) * 1e3;
5695
+ await new Promise((resolve22) => setTimeout(resolve22, Math.min(waitMs, Math.max(0, deadline - Date.now()))));
5696
+ }
5697
+ }
5698
+ }
5527
5699
  function resolveAgentName(configAgentName) {
5528
5700
  return process.env.TOPOLO_AGENT_NAME ?? configAgentName;
5529
5701
  }
@@ -5734,13 +5906,43 @@ function normalizeError(err) {
5734
5906
  retryAfter: err.retryAfter,
5735
5907
  // SDK HTTP errors already carry sanitized details; projecting them again
5736
5908
  // 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),
5909
+ details: reauthorizationDetails(err) ?? (err instanceof TopoloHttpError || err instanceof TopoloAuthError || err instanceof TopoloPermissionError ? err.details : extractTopoloServiceErrorDetails(suppliedDetails === void 0 ? body : { details: suppliedDetails })),
5910
+ hint: reauthorizationHint(err) ?? topoloErrorHint({ code, body }) ?? (code ? fallbackHintMap[code] : void 0),
5739
5911
  exitCode: status === 401 || code === "auth_error" || code === "confirmation_required" ? 2 : status === 403 || code === "permission_denied" ? 3 : code === "immutable_drift" ? 4 : 1
5740
5912
  };
5741
5913
  }
5742
5914
  return { message: String(err), exitCode: 1 };
5743
5915
  }
5916
+ function reauthorizationOf(err) {
5917
+ const prompt = err?.reauthorization;
5918
+ return prompt && typeof prompt === "object" ? prompt : void 0;
5919
+ }
5920
+ var REAUTHORIZATION_FIELDS = [
5921
+ "environment",
5922
+ "context",
5923
+ "reason",
5924
+ "state",
5925
+ "verificationUri",
5926
+ "verificationUriComplete",
5927
+ "userCode",
5928
+ "expiresAt",
5929
+ "pollIntervalSeconds",
5930
+ "loginCommand"
5931
+ ];
5932
+ function reauthorizationDetails(err) {
5933
+ const prompt = reauthorizationOf(err);
5934
+ if (!prompt) return void 0;
5935
+ const safe = {};
5936
+ for (const field of REAUTHORIZATION_FIELDS) if (prompt[field] !== void 0) safe[field] = prompt[field];
5937
+ return { reauthorization: safe };
5938
+ }
5939
+ function reauthorizationHint(err) {
5940
+ const prompt = reauthorizationOf(err);
5941
+ if (!prompt) return void 0;
5942
+ const url = prompt.verificationUriComplete ?? prompt.verificationUri;
5943
+ const approve = url ? `Approve at ${url}${prompt.userCode ? ` (code ${prompt.userCode})` : ""}` : "No approval could be started";
5944
+ return `${approve}; or run: ${prompt.loginCommand ?? "topolo auth login"}. The saved sign-in will not be retried.`;
5945
+ }
5744
5946
 
5745
5947
  // src/version.ts
5746
5948
  import { readFileSync as readFileSync3 } from "fs";
@@ -6028,22 +6230,6 @@ async function resolveLoginContext(credential, serviceUrls, clientId, environmen
6028
6230
  }
6029
6231
  return { identity, context: { contextType: "personal", credential, oauthClientId: clientId } };
6030
6232
  }
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
6233
  function startSpinner() {
6048
6234
  if (!process.stderr.isTTY) return null;
6049
6235
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -6060,12 +6246,66 @@ function startSpinner() {
6060
6246
  };
6061
6247
  }
6062
6248
 
6249
+ // src/lib/reauthorization.ts
6250
+ function isReauthRequired(error) {
6251
+ const candidate = error;
6252
+ return error instanceof Error && candidate?.code === "reauth_required" && typeof candidate.reauthorization === "object" && candidate.reauthorization !== null;
6253
+ }
6254
+ function reauthorizationIsInteractive(env = process.env) {
6255
+ return Boolean(process.stderr.isTTY && process.stdin.isTTY) && !env.CI && env.TOPOLO_NO_REAUTH_PROMPT !== "1";
6256
+ }
6257
+ function describe(error) {
6258
+ const prompt = error.reauthorization;
6259
+ const url = prompt.verificationUriComplete ?? prompt.verificationUri;
6260
+ const expires = prompt.expiresAt ? ` (expires ${prompt.expiresAt})` : "";
6261
+ return ` ${url}
6262
+
6263
+ ` + (prompt.userCode ? ` Confirm the page shows this code:
6264
+
6265
+ ${prompt.userCode}
6266
+
6267
+ ` : "") + ` Waiting for approval${expires}
6268
+ `;
6269
+ }
6270
+ async function credentialWithReauthorization(load, environment, context) {
6271
+ try {
6272
+ return await load();
6273
+ } catch (error) {
6274
+ if (!isReauthRequired(error)) throw error;
6275
+ const prompt = error.reauthorization;
6276
+ const url = prompt.verificationUriComplete ?? prompt.verificationUri;
6277
+ if (!reauthorizationIsInteractive() || prompt.state !== "awaiting_approval" || !url) throw error;
6278
+ const opened = tryOpenBrowser(url);
6279
+ process.stderr.write(
6280
+ `
6281
+ Your saved Topolo sign-in for ${prompt.context} (${prompt.environment}) has ended.
6282
+ ${opened ? "Opening your browser to approve it again:" : "Open this link in your browser to approve it again:"}
6283
+ ` + describe(error)
6284
+ );
6285
+ const remaining = prompt.expiresAt ? Date.parse(prompt.expiresAt) - Date.now() : Number.NaN;
6286
+ const timeoutMs = Number.isFinite(remaining) ? Math.max(1e3, Math.min(remaining, 15 * 6e4)) : 10 * 6e4;
6287
+ const credential = await awaitReauthorization(environment, context, {
6288
+ timeoutMs,
6289
+ onPrompt: (next) => process.stderr.write(`
6290
+ A new approval was started:
6291
+ ${describe(next)}`)
6292
+ });
6293
+ if (!credential) throw error;
6294
+ process.stderr.write(" Approved. Continuing.\n");
6295
+ return credential;
6296
+ }
6297
+ }
6298
+
6063
6299
  // src/client.ts
6064
6300
  async function buildClient(options) {
6065
6301
  const environment = options?.environment ?? selectedEnvironment();
6066
6302
  const config = await readConfig();
6067
6303
  const context = commandContextKey(config, environment, options?.context?.trim() || process.env.TOPOLO_CONTEXT);
6068
- const credential = context ? await refreshContextCredentialIfNeeded(environment, context) : await refreshCredentialIfNeeded(environment);
6304
+ const credential = await credentialWithReauthorization(
6305
+ () => context ? refreshContextCredentialIfNeeded(environment, context) : refreshCredentialIfNeeded(environment),
6306
+ environment,
6307
+ context
6308
+ );
6069
6309
  if (!credential) return null;
6070
6310
  const profile = resolvedProfileConfig(config, environment);
6071
6311
  const topolo = createTopolo({
@@ -6081,7 +6321,11 @@ async function buildClient(options) {
6081
6321
  serviceUrls: profile.serviceUrls,
6082
6322
  requireConfirmForWrites: options?.requireConfirmForWrites,
6083
6323
  ...credential.kind === "access_token" && credential.refreshToken ? {
6084
- refreshCredential: () => context ? refreshContextCredentialIfNeeded(environment, context, { force: true }) : refreshCredentialIfNeeded(environment, { force: true })
6324
+ refreshCredential: () => credentialWithReauthorization(
6325
+ () => context ? refreshContextCredentialIfNeeded(environment, context, { force: true }) : refreshCredentialIfNeeded(environment, { force: true }),
6326
+ environment,
6327
+ context
6328
+ )
6085
6329
  } : {},
6086
6330
  ...isDebugEnabled() ? { debug: stderrDebugLogger } : {}
6087
6331
  });
@@ -6263,10 +6507,10 @@ function resolveConfiguredServiceUrl2(service, serviceUrls) {
6263
6507
  }
6264
6508
  return void 0;
6265
6509
  }
6266
- function parseQueryPairs(pairs) {
6267
- if (!pairs || pairs.length === 0) return void 0;
6510
+ function parseQueryPairs(pairs2) {
6511
+ if (!pairs2 || pairs2.length === 0) return void 0;
6268
6512
  const out = {};
6269
- for (const pair of pairs) {
6513
+ for (const pair of pairs2) {
6270
6514
  const eq = pair.indexOf("=");
6271
6515
  if (eq <= 0) {
6272
6516
  throw new Error(`Invalid --query entry "${pair}". Expected key=value.`);
@@ -6474,9 +6718,9 @@ function externalApprovalHandoff(action, result) {
6474
6718
  if (!result || typeof result !== "object" || Array.isArray(result)) return null;
6475
6719
  const invocation = result.invocation;
6476
6720
  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;
6721
+ const record4 = invocation;
6722
+ if (record4.status !== "awaiting_approval") return null;
6723
+ const approval = record4.approval;
6480
6724
  if (!approval || typeof approval !== "object" || Array.isArray(approval)) return null;
6481
6725
  const handoff = approval;
6482
6726
  if (typeof handoff.requestId !== "string" || typeof handoff.verificationUrl !== "string") return null;
@@ -6752,9 +6996,9 @@ async function writeCredentialCustody(request, deps) {
6752
6996
  }
6753
6997
  }
6754
6998
  function requiredText(value, flag) {
6755
- const text2 = value?.trim();
6756
- if (!text2) throw new CustodyError("custody_invalid_input", `${flag} is required.`);
6757
- return text2;
6999
+ const text3 = value?.trim();
7000
+ if (!text3) throw new CustodyError("custody_invalid_input", `${flag} is required.`);
7001
+ return text3;
6758
7002
  }
6759
7003
  function currentUid() {
6760
7004
  return typeof process.getuid === "function" ? process.getuid() : null;
@@ -6923,9 +7167,9 @@ async function writeCustodyFiles(directory, files) {
6923
7167
  }
6924
7168
  function withheldIfSecretLeaks(error, secret) {
6925
7169
  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]) {
7170
+ const record4 = error;
7171
+ const parts = [String(error), String(record4?.message), String(record4?.stack)];
7172
+ for (const value of [record4?.body, record4?.details]) {
6929
7173
  try {
6930
7174
  parts.push(String(value), JSON.stringify(value ?? null));
6931
7175
  } catch {
@@ -7276,8 +7520,8 @@ async function authFetchJson(path, init = {}) {
7276
7520
  }
7277
7521
  headers.set("Authorization", `Bearer ${credential.accessToken}`);
7278
7522
  const response = await fetch(`${authBaseUrl}${path}`, { ...init, headers });
7279
- const text2 = await response.text();
7280
- const payload = text2 ? JSON.parse(text2) : {};
7523
+ const text3 = await response.text();
7524
+ const payload = text3 ? JSON.parse(text3) : {};
7281
7525
  if (!response.ok || payload.success === false) {
7282
7526
  const err = new Error(payload.message || payload.error_description || payload.error || "Topolo Auth request failed");
7283
7527
  err.code = payload.code || payload.error;
@@ -7786,9 +8030,9 @@ async function readTomlRegistrations(path, agent) {
7786
8030
  return [...registrations.values()].filter((registration) => registration.command || registration.url);
7787
8031
  }
7788
8032
  async function readGooseRegistrations(path) {
7789
- const text2 = await readFile4(path, "utf8");
8033
+ const text3 = await readFile4(path, "utf8");
7790
8034
  const registrations = [];
7791
- const lines = text2.split(/\r?\n/);
8035
+ const lines = text3.split(/\r?\n/);
7792
8036
  let inExtensions = false;
7793
8037
  let inTopolo = false;
7794
8038
  let current;
@@ -8030,10 +8274,10 @@ async function registerAgentHttpConfig(agent, homeDir, registration, codexHome)
8030
8274
  return;
8031
8275
  }
8032
8276
  const before = await fileSnapshot(config.path);
8033
- const text2 = withoutMcpServerSections(before.contents ?? "", registration.name);
8277
+ const text3 = withoutMcpServerSections(before.contents ?? "", registration.name);
8034
8278
  const headers = Object.entries(registration.headers).map(([key, value]) => JSON.stringify(key) + " = " + JSON.stringify(value)).join(", ");
8035
8279
  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);
8280
+ await atomicWrite(config.path, text3 + block, before);
8037
8281
  }
8038
8282
  async function unregisterAgentConfig(agent, homeDir, name, projectDir, codexHome) {
8039
8283
  for (const config of agentConfigPaths(agent, homeDir, projectDir, codexHome)) {
@@ -8041,8 +8285,8 @@ async function unregisterAgentConfig(agent, homeDir, name, projectDir, codexHome
8041
8285
  if (config.format === "json") {
8042
8286
  await unregisterJson(config, agent, name);
8043
8287
  } else if (config.format === "toml") {
8044
- const text2 = withoutMcpServerSections(await readFile5(config.path, "utf8"), name);
8045
- await atomicWrite(config.path, text2 ? text2 + "\n" : "");
8288
+ const text3 = withoutMcpServerSections(await readFile5(config.path, "utf8"), name);
8289
+ await atomicWrite(config.path, text3 ? text3 + "\n" : "");
8046
8290
  } else {
8047
8291
  await unregisterGoose(config.path, name);
8048
8292
  }
@@ -8132,12 +8376,12 @@ async function unregisterJson(config, agent, name) {
8132
8376
  async function registerToml(path, agent, mcp, registration) {
8133
8377
  const before = await fileSnapshot(path);
8134
8378
  const existing = before.contents ?? "";
8135
- const text2 = withoutMcpServerSections(existing, registration.name);
8379
+ const text3 = withoutMcpServerSections(existing, registration.name);
8136
8380
  const args = mcp.args.length ? "\nargs = [" + mcp.args.map((item) => JSON.stringify(item)).join(", ") + "]" : "";
8137
8381
  const environment = registrationEnvironment(agent, registration);
8138
8382
  const environmentText = Object.entries(environment).map(([key, value]) => JSON.stringify(key) + " = " + JSON.stringify(value)).join(", ");
8139
8383
  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);
8384
+ await atomicWrite(path, text3 + block, before);
8141
8385
  }
8142
8386
  async function registerGoose(path, mcp, registration) {
8143
8387
  const existing = existsSync5(path) ? await readFile5(path, "utf8") : "";
@@ -8160,8 +8404,8 @@ async function unregisterGoose(path, name) {
8160
8404
  const existing = await readFile5(path, "utf8");
8161
8405
  await atomicWrite(path, removeGooseExtension(existing, name));
8162
8406
  }
8163
- function removeGooseExtension(text2, name) {
8164
- const lines = text2.split(/\r?\n/);
8407
+ function removeGooseExtension(text3, name) {
8408
+ const lines = text3.split(/\r?\n/);
8165
8409
  const kept = [];
8166
8410
  let inExtensions = false;
8167
8411
  let skipping = false;
@@ -8181,11 +8425,11 @@ function removeGooseExtension(text2, name) {
8181
8425
  }
8182
8426
  return kept.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
8183
8427
  }
8184
- function insertGooseExtension(text2, block) {
8185
- if (!text2.trim()) return "extensions:\n" + block + "\n";
8186
- const lines = text2.split(/\r?\n/);
8428
+ function insertGooseExtension(text3, block) {
8429
+ if (!text3.trim()) return "extensions:\n" + block + "\n";
8430
+ const lines = text3.split(/\r?\n/);
8187
8431
  const extensionIndex = lines.findIndex((line) => /^extensions:\s*$/.test(line));
8188
- if (extensionIndex < 0) return text2.trimEnd() + "\n\nextensions:\n" + block + "\n";
8432
+ if (extensionIndex < 0) return text3.trimEnd() + "\n\nextensions:\n" + block + "\n";
8189
8433
  let end = lines.length;
8190
8434
  for (let index = extensionIndex + 1; index < lines.length; index += 1) {
8191
8435
  if (/^\S/.test(lines[index]) && lines[index].trim()) {
@@ -8284,11 +8528,11 @@ async function atomicWrite(path, contents, before) {
8284
8528
  }
8285
8529
  }
8286
8530
  }
8287
- function withoutMcpServerSections(text2, name) {
8531
+ function withoutMcpServerSections(text3, name) {
8288
8532
  const section = "[mcp_servers." + name + "]";
8289
8533
  const subsectionPrefix = "[mcp_servers." + name + ".";
8290
8534
  let skipping = false;
8291
- return text2.split(/\r?\n/).filter((line) => {
8535
+ return text3.split(/\r?\n/).filter((line) => {
8292
8536
  const trimmed = line.trim();
8293
8537
  if (trimmed === section || trimmed.startsWith(subsectionPrefix) && trimmed.endsWith("]")) {
8294
8538
  skipping = true;
@@ -8334,18 +8578,18 @@ function validateMcpHubIdentity(value, where = "identity") {
8334
8578
  if (!value || typeof value !== "object" || Array.isArray(value)) {
8335
8579
  throw new Error(`MCP hub ${where} must be an object.`);
8336
8580
  }
8337
- const record3 = value;
8338
- const unknown = Object.keys(record3).filter((key) => !["name", "env", "context"].includes(key));
8581
+ const record4 = value;
8582
+ const unknown = Object.keys(record4).filter((key) => !["name", "env", "context"].includes(key));
8339
8583
  if (unknown.length) throw new Error(`MCP hub ${where} has unsupported field(s): ${unknown.join(", ")}.`);
8340
- const name = record3.name;
8584
+ const name = record4.name;
8341
8585
  if (typeof name !== "string" || !NAME_PATTERN.test(name) || name === RESERVED_NAME) {
8342
8586
  throw new Error(`MCP hub ${where} name must be topolo or topolo-<name> (and not reserved).`);
8343
8587
  }
8344
- const environment = record3.env;
8588
+ const environment = record4.env;
8345
8589
  if (typeof environment !== "string" || !MCP_HUB_ENVIRONMENTS.includes(environment)) {
8346
8590
  throw new Error(`MCP hub identity ${name} env must be one of ${MCP_HUB_ENVIRONMENTS.join(", ")}.`);
8347
8591
  }
8348
- const context = record3.context;
8592
+ const context = record4.context;
8349
8593
  if (context === void 0) {
8350
8594
  throw new Error(`MCP hub identity ${name} must pin a context (a key from \`topolo context ls\`).`);
8351
8595
  }
@@ -8354,27 +8598,27 @@ function validateMcpHubIdentity(value, where = "identity") {
8354
8598
  }
8355
8599
  return { name, environment, context: context.trim() };
8356
8600
  }
8357
- function parseMcpHubConfig(text2, source) {
8601
+ function parseMcpHubConfig(text3, source) {
8358
8602
  let parsed;
8359
8603
  try {
8360
- parsed = JSON.parse(text2);
8604
+ parsed = JSON.parse(text3);
8361
8605
  } catch (error) {
8362
8606
  throw new Error(`Cannot read malformed MCP hub configuration at ${source}: ${error.message}`);
8363
8607
  }
8364
8608
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
8365
8609
  throw new Error(`MCP hub configuration at ${source} must be a JSON object.`);
8366
8610
  }
8367
- const record3 = parsed;
8368
- const unknown = Object.keys(record3).filter((key) => !["version", "port", "identities"].includes(key));
8611
+ const record4 = parsed;
8612
+ const unknown = Object.keys(record4).filter((key) => !["version", "port", "identities"].includes(key));
8369
8613
  if (unknown.length) {
8370
8614
  throw new Error(`MCP hub configuration at ${source} has unsupported field(s): ${unknown.join(", ")}.`);
8371
8615
  }
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)) {
8616
+ if (record4.version !== 1) throw new Error(`MCP hub configuration at ${source} must declare "version": 1.`);
8617
+ const port = record4.port === void 0 ? MCP_HUB_DEFAULT_PORT : validateMcpHubPort(record4.port);
8618
+ if (record4.identities !== void 0 && !Array.isArray(record4.identities)) {
8375
8619
  throw new Error(`MCP hub configuration at ${source} identities must be an array.`);
8376
8620
  }
8377
- const identities = (record3.identities ?? []).map((entry, index) => validateMcpHubIdentity(entry, `identity #${index + 1}`));
8621
+ const identities = (record4.identities ?? []).map((entry, index) => validateMcpHubIdentity(entry, `identity #${index + 1}`));
8378
8622
  const seen = /* @__PURE__ */ new Set();
8379
8623
  for (const identity of identities) {
8380
8624
  if (seen.has(identity.name)) {
@@ -8396,14 +8640,14 @@ function serializeMcpHubConfig(config) {
8396
8640
  }, null, 2) + "\n";
8397
8641
  }
8398
8642
  async function readMcpHubConfig(path) {
8399
- let text2;
8643
+ let text3;
8400
8644
  try {
8401
- text2 = await readFile6(path, "utf8");
8645
+ text3 = await readFile6(path, "utf8");
8402
8646
  } catch (error) {
8403
8647
  if (error.code === "ENOENT") return emptyMcpHubConfig();
8404
8648
  throw error;
8405
8649
  }
8406
- return parseMcpHubConfig(text2, path);
8650
+ return parseMcpHubConfig(text3, path);
8407
8651
  }
8408
8652
  function upsertMcpHubIdentity(config, identity) {
8409
8653
  const identities = config.identities.filter((entry) => entry.name !== identity.name);
@@ -9725,16 +9969,16 @@ var REVOKE_CREDENTIAL = "app_topolo_auth.principal_credentials.revoke";
9725
9969
  var INSTALLATION_BOOTSTRAP_GRANT = "app_topolo_auth:identity";
9726
9970
  function actionData(value) {
9727
9971
  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;
9972
+ const record4 = value;
9973
+ const data = record4.data;
9974
+ return data && typeof data === "object" ? data : record4;
9731
9975
  }
9732
9976
  function requiredRecord(value, name) {
9733
9977
  if (!value || typeof value !== "object") throw new Error(`Topolo did not return ${name}.`);
9734
9978
  return value;
9735
9979
  }
9736
- function requiredString(record3, key) {
9737
- const value = record3[key];
9980
+ function requiredString(record4, key) {
9981
+ const value = record4[key];
9738
9982
  if (typeof value !== "string" || !value.trim()) throw new Error(`Topolo did not return ${key}.`);
9739
9983
  return value;
9740
9984
  }