@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.
- package/README.md +18 -4
- package/agent-packs/README.md +469 -1
- package/agent-packs/coverage_changed.py +1 -1
- package/agent-packs/docs/selected-artifacts.md +47 -0
- package/agent-packs/documentation/cloud-task-state.md +56 -0
- package/agent-packs/domain-contexts/README.md +25 -0
- package/agent-packs/domain-contexts/cicd.json +8 -0
- package/agent-packs/gui/feed-adapter.js +4 -0
- package/agent-packs/gui/index.html +9 -0
- package/agent-packs/gui/studio.css +14 -0
- package/agent-packs/gui/studio.js +121 -0
- package/agent-packs/gui/studio_server.py +355 -0
- package/agent-packs/roles/cicd/CLAUDE.md +24 -0
- package/agent-packs/specializations/cicd--cicd.json +5 -0
- package/agent-packs/specializations/cicd--pipeline-engineering.json +5 -0
- package/agent-packs/specializations/cicd--promotion-deployment.json +5 -0
- package/agent-packs/specializations/cicd--queue-recovery.json +5 -0
- package/agent-packs/specializations/cicd--release-verification.json +5 -0
- package/agent-packs/specializations/cicd--runner-capacity.json +5 -0
- package/agent-packs/specializations/intakes--engineering-02.json +5 -0
- package/agent-packs/specializations/intakes--engineering-03.json +5 -0
- package/agent-packs/specializations/intakes--engineering.json +5 -0
- package/agent-packs/specializations/intakes--operator-01.json +5 -0
- package/agent-packs/specializations/intakes--operator-02.json +5 -0
- package/agent-packs/specializations/operator-skills--audio-and-narration-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--brand-and-copywriting-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--capability-research-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--data-analysis-and-visualization.json +5 -0
- package/agent-packs/specializations/operator-skills--financial-evidence-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--operating-template-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--operator-skill-library.json +5 -0
- package/agent-packs/specializations/operator-skills--operator-skills.json +5 -0
- package/agent-packs/specializations/operator-skills--operator-workflow-evaluation.json +5 -0
- package/agent-packs/specializations/operator-skills--privacy-and-agreement-review.json +5 -0
- package/agent-packs/specializations/operator-skills--storytelling-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--ux-and-accessibility-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--video-production-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--visual-design-specialist.json +5 -0
- package/agent-packs/specializations/operator-skills--workflow-integration-specialist.json +5 -0
- package/agent-packs/specializations/operators--access-and-privacy.json +5 -0
- package/agent-packs/specializations/operators--accounting-evidence-review.json +5 -0
- package/agent-packs/specializations/operators--agreement-operations.json +5 -0
- package/agent-packs/specializations/operators--books-operator.json +5 -0
- package/agent-packs/specializations/operators--brand-operator.json +5 -0
- package/agent-packs/specializations/operators--commerce-operations.json +5 -0
- package/agent-packs/specializations/operators--communications-operator.json +5 -0
- package/agent-packs/specializations/operators--content-and-assets-operator.json +5 -0
- package/agent-packs/specializations/operators--customer-operations.json +5 -0
- package/agent-packs/specializations/operators--design-operator.json +5 -0
- package/agent-packs/specializations/operators--design-production-02.json +5 -0
- package/agent-packs/specializations/operators--design-production-03.json +5 -0
- package/agent-packs/specializations/operators--design-production-04.json +5 -0
- package/agent-packs/specializations/operators--device-and-feed-operator.json +5 -0
- package/agent-packs/specializations/operators--director-operator.json +5 -0
- package/agent-packs/specializations/operators--experience-review.json +5 -0
- package/agent-packs/specializations/operators--growth-operations.json +5 -0
- package/agent-packs/specializations/operators--learn-operator.json +5 -0
- package/agent-packs/specializations/operators--localization-operator.json +5 -0
- package/agent-packs/specializations/operators--operators.json +5 -0
- package/agent-packs/specializations/operators--pay-operator.json +5 -0
- package/agent-packs/specializations/operators--research-and-intelligence.json +5 -0
- package/agent-packs/specializations/operators--roadmap-operator.json +5 -0
- package/agent-packs/specializations/operators--social-content-operator.json +5 -0
- package/agent-packs/specializations/operators--talent-operations.json +5 -0
- package/agent-packs/specializations/operators--web-operator.json +5 -0
- package/agent-packs/specializations/operators--workflow-operator.json +5 -0
- package/agent-packs/specializations/specialists--adversarial-qa.json +5 -0
- package/agent-packs/specializations/specialists--backlog-dispatch.json +5 -0
- package/agent-packs/specializations/specialists--build-01.json +5 -0
- package/agent-packs/specializations/specialists--build-02.json +5 -0
- package/agent-packs/specializations/specialists--build-03.json +5 -0
- package/agent-packs/specializations/specialists--developer-environment-steward.json +5 -0
- package/agent-packs/specializations/specialists--documentation-knowledge-steward.json +5 -0
- package/agent-packs/specializations/specialists--execution-readiness.json +5 -0
- package/agent-packs/specializations/specialists--incident-triage.json +5 -0
- package/agent-packs/specializations/specialists--platform-package-steward.json +5 -0
- package/agent-packs/specializations/specialists--product-direction-01.json +5 -0
- package/agent-packs/specializations/specialists--product-direction-02.json +5 -0
- package/agent-packs/specializations/specialists--release-recovery.json +5 -0
- package/agent-packs/specializations/specialists--release-watch.json +5 -0
- package/agent-packs/specializations/specialists--roadmap-planning-01.json +5 -0
- package/agent-packs/specializations/specialists--roadmap-planning-02.json +5 -0
- package/agent-packs/specializations/specialists--security-permissions-review.json +5 -0
- package/agent-packs/specializations/specialists--system-architecture-01.json +5 -0
- package/agent-packs/specializations/specialists--system-architecture-02.json +5 -0
- package/agent-packs/specializations/specialists--translation.json +5 -0
- package/agent-packs/specializations/specialists--ux-consistency-review.json +5 -0
- package/agent-packs/specializations/specialists--workflow-improvement.json +5 -0
- package/agent-packs/specializations/specialists--worktree-retirement.json +5 -0
- package/agent-packs/src/topolo_agent_pack/cicd.py +101 -0
- package/agent-packs/src/topolo_agent_pack/claude.py +22 -7
- package/agent-packs/src/topolo_agent_pack/claude_activation.py +157 -0
- package/agent-packs/src/topolo_agent_pack/claude_completion_recovery.py +216 -0
- package/agent-packs/src/topolo_agent_pack/claude_desktop.py +181 -0
- package/agent-packs/src/topolo_agent_pack/claude_dispatch.py +240 -0
- package/agent-packs/src/topolo_agent_pack/claude_prompt.py +74 -0
- package/agent-packs/src/topolo_agent_pack/claude_runner.py +207 -0
- package/agent-packs/src/topolo_agent_pack/claude_service.py +397 -0
- package/agent-packs/src/topolo_agent_pack/cli.py +188 -18
- package/agent-packs/src/topolo_agent_pack/closed_ledger_fence.py +118 -0
- package/agent-packs/src/topolo_agent_pack/cloud_attach.py +128 -0
- package/agent-packs/src/topolo_agent_pack/cloud_cutover.py +134 -0
- package/agent-packs/src/topolo_agent_pack/cloud_delta.py +162 -0
- package/agent-packs/src/topolo_agent_pack/cloud_migrate.py +142 -0
- package/agent-packs/src/topolo_agent_pack/cloud_recovery.py +42 -0
- package/agent-packs/src/topolo_agent_pack/cloud_work.py +126 -0
- package/agent-packs/src/topolo_agent_pack/coordinator_activity.py +27 -0
- package/agent-packs/src/topolo_agent_pack/coordinator_context.py +91 -0
- package/agent-packs/src/topolo_agent_pack/coordinator_refresh.py +116 -0
- package/agent-packs/src/topolo_agent_pack/desktop_acceptance.py +45 -0
- package/agent-packs/src/topolo_agent_pack/desktop_launcher.py +114 -0
- package/agent-packs/src/topolo_agent_pack/domain_context.py +38 -0
- package/agent-packs/src/topolo_agent_pack/execution.py +104 -7
- package/agent-packs/src/topolo_agent_pack/fresh.py +1 -1
- package/agent-packs/src/topolo_agent_pack/frontdoor.py +23 -0
- package/agent-packs/src/topolo_agent_pack/linked_task_context.py +80 -0
- package/agent-packs/src/topolo_agent_pack/live.py +285 -18
- package/agent-packs/src/topolo_agent_pack/native.py +160 -4
- package/agent-packs/src/topolo_agent_pack/policy.py +8 -0
- package/agent-packs/src/topolo_agent_pack/review_context.py +33 -0
- package/agent-packs/src/topolo_agent_pack/role_catalog.py +137 -0
- package/agent-packs/src/topolo_agent_pack/role_context.py +63 -0
- package/agent-packs/src/topolo_agent_pack/role_refresh.py +50 -0
- package/agent-packs/src/topolo_agent_pack/task_models.py +11 -7
- package/agent-packs/src/topolo_agent_pack/throughput.py +149 -0
- package/agent-packs/src/topolo_agent_pack/topolo.py +7 -1
- package/agent-packs/src/topolo_agent_pack/work.py +322 -0
- package/agent-packs/src/topolo_agent_pack/work_adoption.py +122 -0
- package/agent-packs/src/topolo_agent_pack/work_artifacts.py +84 -0
- package/agent-packs/src/topolo_agent_pack/work_context.py +77 -0
- package/agent-packs/src/topolo_agent_pack/work_gui.py +51 -0
- package/agent-packs/src/topolo_agent_pack/work_native.py +414 -0
- package/agent-packs/src/topolo_agent_pack/work_wait.py +151 -0
- package/agent-packs/templates/topolo-coordinators/AGENTS.md +7 -0
- package/agent-packs/templates/topolo-coordinators/agents/intakes/cicd/AGENTS.md +6 -0
- package/agent-packs/templates/topolo-coordinators/agents/intakes/cicd/config.json +4 -0
- package/agent-packs/templates/topolo-coordinators/agents/intakes/engineering/AGENTS.md +3 -0
- package/agent-packs/templates/topolo-coordinators/agents/intakes/engineering/config.json +4 -0
- package/agent-packs/templates/topolo-coordinators/agents/intakes/operator-01/AGENTS.md +3 -0
- package/agent-packs/templates/topolo-coordinators/agents/intakes/operator-01/config.json +4 -0
- package/agent-packs/templates/topolo-coordinators/pack.json +56 -0
- package/dist/chunk-NYDIAYVY.js +144 -0
- package/dist/{claude-pack-backend-YEVPAOID.js → chunk-UY5LEU5C.js} +1659 -21
- package/dist/claude-desktop-profile-JCQKSY3K.js +13 -0
- package/dist/claude-pack-activation-Q25MCEPU.js +506 -0
- package/dist/claude-pack-backend-HUTKGIDS.js +90 -0
- package/dist/index.js +408 -164
- 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-
|
|
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("
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
368
|
-
if (!
|
|
369
|
-
return
|
|
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
|
|
438
|
-
const topLevel = canonicalTopoloServiceErrorCode(
|
|
564
|
+
const record5 = body;
|
|
565
|
+
const topLevel = canonicalTopoloServiceErrorCode(record5.code);
|
|
439
566
|
if (topLevel) return topLevel;
|
|
440
|
-
const nested =
|
|
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
|
|
453
|
-
const nested =
|
|
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(
|
|
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
|
|
472
|
-
let candidate =
|
|
473
|
-
const nested =
|
|
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 =
|
|
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
|
|
538
|
-
if (!path && !
|
|
539
|
-
return { ...path ? { path } : {}, ...
|
|
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
|
|
546
|
-
const path = canonicalTopoloValidationPath(
|
|
672
|
+
const record5 = value;
|
|
673
|
+
const path = canonicalTopoloValidationPath(record5.field) ?? canonicalTopoloValidationPath(record5.path);
|
|
547
674
|
if (!path) continue;
|
|
548
|
-
const projected = issue(path,
|
|
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
|
|
703
|
-
return Boolean(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1430
|
+
const actionValue = record3(envelope.action, "actorEnvelope.action");
|
|
1304
1431
|
exactKeys(actionValue, ["requestId", "actionId", "resourceType", "resourceId", "inputHash"], "actorEnvelope.action");
|
|
1305
|
-
const 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:
|
|
1309
|
-
actionId:
|
|
1310
|
-
...actionValue.resourceType === void 0 ? {} : { resourceType:
|
|
1311
|
-
...actionValue.resourceId === void 0 ? {} : { 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 =
|
|
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:
|
|
1378
|
-
...subject.displayName === void 0 ? {} : { 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 =
|
|
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:
|
|
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 =
|
|
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:
|
|
1420
|
-
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 =
|
|
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:
|
|
1553
|
+
principalId: text2(hop.principalId, `actorEnvelope.delegation.lineage[${index}].principalId`)
|
|
1427
1554
|
};
|
|
1428
1555
|
})
|
|
1429
1556
|
};
|
|
1430
1557
|
}
|
|
1431
|
-
function
|
|
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
|
|
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 =
|
|
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) =>
|
|
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,
|
|
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
|
|
2264
|
-
if (
|
|
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:
|
|
2270
|
-
actionCount: Number(
|
|
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
|
|
2995
|
-
if (Array.isArray(
|
|
2996
|
-
if (
|
|
2997
|
-
const 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
|
|
3075
|
-
const allKeys = Object.keys(
|
|
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(
|
|
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
|
-
//
|
|
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
|
|
4001
|
-
if (!
|
|
4002
|
-
return
|
|
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
|
|
4044
|
-
const topLevel = canonicalTopoloServiceErrorCode2(
|
|
4194
|
+
const record4 = body;
|
|
4195
|
+
const topLevel = canonicalTopoloServiceErrorCode2(record4.code);
|
|
4045
4196
|
if (topLevel) return topLevel;
|
|
4046
|
-
const nested =
|
|
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
|
|
4062
|
-
let candidate =
|
|
4063
|
-
const nested =
|
|
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 =
|
|
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
|
|
4128
|
-
if (!path && !
|
|
4129
|
-
return { ...path ? { path } : {}, ...
|
|
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
|
|
4136
|
-
const path = canonicalTopoloValidationPath2(
|
|
4286
|
+
const record4 = value;
|
|
4287
|
+
const path = canonicalTopoloValidationPath2(record4.field) ?? canonicalTopoloValidationPath2(record4.path);
|
|
4137
4288
|
if (!path) continue;
|
|
4138
|
-
const projected = issue2(path,
|
|
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
|
|
4726
|
+
let record4;
|
|
4576
4727
|
try {
|
|
4577
|
-
|
|
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(
|
|
4582
|
-
if (
|
|
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
|
|
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 || (
|
|
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 (
|
|
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 =
|
|
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: () =>
|
|
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(
|
|
6267
|
-
if (!
|
|
6510
|
+
function parseQueryPairs(pairs2) {
|
|
6511
|
+
if (!pairs2 || pairs2.length === 0) return void 0;
|
|
6268
6512
|
const out = {};
|
|
6269
|
-
for (const pair of
|
|
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
|
|
6478
|
-
if (
|
|
6479
|
-
const 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
|
|
6756
|
-
if (!
|
|
6757
|
-
return
|
|
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
|
|
6927
|
-
const parts = [String(error), String(
|
|
6928
|
-
for (const value of [
|
|
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
|
|
7280
|
-
const payload =
|
|
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
|
|
8033
|
+
const text3 = await readFile4(path, "utf8");
|
|
7790
8034
|
const registrations = [];
|
|
7791
|
-
const lines =
|
|
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
|
|
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,
|
|
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
|
|
8045
|
-
await atomicWrite(config.path,
|
|
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
|
|
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,
|
|
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(
|
|
8164
|
-
const lines =
|
|
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(
|
|
8185
|
-
if (!
|
|
8186
|
-
const lines =
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
8338
|
-
const unknown = Object.keys(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
8601
|
+
function parseMcpHubConfig(text3, source) {
|
|
8358
8602
|
let parsed;
|
|
8359
8603
|
try {
|
|
8360
|
-
parsed = JSON.parse(
|
|
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
|
|
8368
|
-
const unknown = Object.keys(
|
|
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 (
|
|
8373
|
-
const port =
|
|
8374
|
-
if (
|
|
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 = (
|
|
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
|
|
8643
|
+
let text3;
|
|
8400
8644
|
try {
|
|
8401
|
-
|
|
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(
|
|
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
|
|
9729
|
-
const data =
|
|
9730
|
-
return data && typeof data === "object" ? data :
|
|
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(
|
|
9737
|
-
const value =
|
|
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
|
}
|