@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
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ acknowledgeClaudeDesktopProfile,
4
+ launchClaudeDesktopProfile,
5
+ readClaudeDesktopProfile,
6
+ verifyClaudeDesktopProfileNative
7
+ } from "./chunk-NYDIAYVY.js";
8
+ export {
9
+ acknowledgeClaudeDesktopProfile,
10
+ launchClaudeDesktopProfile,
11
+ readClaudeDesktopProfile,
12
+ verifyClaudeDesktopProfileNative
13
+ };
@@ -0,0 +1,506 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ bindClaudeFrontdoorHooks,
4
+ discoverClaudeNativeCapabilities,
5
+ evaluateClaudeMain,
6
+ lockClaudeLibrary,
7
+ materializeClaudeHookAdapter,
8
+ nativeClaudeDesktopControlExpression,
9
+ observeClaudeFrontdoors,
10
+ qualifyClaudePython,
11
+ readClaudeTaskConnection,
12
+ validateInspectorEndpoint
13
+ } from "./chunk-UY5LEU5C.js";
14
+ import {
15
+ acknowledgeClaudeDesktopProfile,
16
+ launchClaudeDesktopProfile,
17
+ readClaudeDesktopProfile,
18
+ verifyClaudeDesktopProfileNative
19
+ } from "./chunk-NYDIAYVY.js";
20
+
21
+ // src/lib/claude-desktop-menu.ts
22
+ import { spawnSync } from "child_process";
23
+ var claudeInspectorMenuScript = `on run argv
24
+ set targetPID to item 1 of argv as integer
25
+ set desiredEnabled to item 2 of argv is "enable"
26
+ tell application "System Events"
27
+ repeat 100 times
28
+ set targets to application processes whose unix id is targetPID
29
+ if (count of targets) > 1 then error "Native process identity is ambiguous"
30
+ if (count of targets) is 1 then exit repeat
31
+ delay 0.1
32
+ end repeat
33
+ if (count of targets) is not 1 then error "Exact native process is unavailable"
34
+ set targetProcess to item 1 of targets
35
+ if name of targetProcess is not "Claude" then error "Native application identity differs"
36
+ tell targetProcess
37
+ set ready to false
38
+ repeat 100 times
39
+ set matches to {}
40
+ set parentNames to {}
41
+ try
42
+ repeat with topItem in menu bar items of menu bar 1
43
+ try
44
+ set candidates to menu items of menu 1 of topItem whose name is "Enable Main Process Debugger"
45
+ repeat with candidate in candidates
46
+ set end of matches to contents of candidate
47
+ set end of parentNames to name of topItem
48
+ end repeat
49
+ end try
50
+ end repeat
51
+ end try
52
+ if (count of matches) > 1 then error "Unique native main-debugger capability is unavailable"
53
+ if (count of matches) is 1 then
54
+ if enabled of item 1 of matches is true then
55
+ set ready to true
56
+ exit repeat
57
+ end if
58
+ end if
59
+ delay 0.1
60
+ end repeat
61
+ if ready is not true then error "Unique enabled native main-debugger capability did not become ready"
62
+ set exactItem to item 1 of matches
63
+ if enabled of exactItem is not true then error "Native main-debugger capability is disabled"
64
+ set mark to value of attribute "AXMenuItemMarkChar" of exactItem
65
+ set isChecked to mark is not missing value and mark is not ""
66
+ if isChecked is desiredEnabled then error "Native inspector checkbox is already in the requested state; ownership must be reconciled"
67
+ set parentName to item 1 of parentNames
68
+ set frontmost to true
69
+ set parents to menu bar items of menu bar 1 whose name is parentName
70
+ if (count of parents) is not 1 then error "Native debugger parent changed"
71
+ if (count of (value of attribute "AXVisibleChildren" of menu 1 of item 1 of parents)) is 0 then perform action "AXPress" of item 1 of parents
72
+ set opened to false
73
+ repeat 40 times
74
+ set parents to menu bar items of menu bar 1 whose name is parentName
75
+ if (count of parents) is not 1 then error "Native debugger parent changed"
76
+ if (count of (value of attribute "AXVisibleChildren" of menu 1 of item 1 of parents)) > 0 then
77
+ set opened to true
78
+ exit repeat
79
+ end if
80
+ delay 0.05
81
+ end repeat
82
+ if opened is not true then error "Native debugger menu did not open"
83
+ set freshMatches to menu items of menu 1 of item 1 of parents whose name is "Enable Main Process Debugger"
84
+ if (count of freshMatches) is not 1 then error "Unique open debugger capability changed"
85
+ set exactItem to item 1 of freshMatches
86
+ if enabled of exactItem is not true then error "Native main-debugger capability is disabled"
87
+ set mark to value of attribute "AXMenuItemMarkChar" of exactItem
88
+ set isChecked to mark is not missing value and mark is not ""
89
+ if isChecked is desiredEnabled then error "Inspector ownership changed"
90
+ if "AXPress" is not in (name of actions of exactItem) then error "Native debugger press capability unavailable"
91
+ perform action "AXPress" of exactItem
92
+ repeat 40 times
93
+ set parents to menu bar items of menu bar 1 whose name is parentName
94
+ if (count of parents) is not 1 then error "Native debugger parent changed"
95
+ set freshMatches to menu items of menu 1 of item 1 of parents whose name is "Enable Main Process Debugger"
96
+ if (count of freshMatches) is not 1 then error "Native debugger checkbox changed"
97
+ set mark to value of attribute "AXMenuItemMarkChar" of item 1 of freshMatches
98
+ set isChecked to mark is not missing value and mark is not ""
99
+ if isChecked is desiredEnabled then
100
+ if desiredEnabled then return "owned-main-debugger-click-acknowledged"
101
+ return "owned-main-debugger-closed-acknowledged"
102
+ end if
103
+ delay 0.05
104
+ end repeat
105
+ error "Native debugger checkbox did not acknowledge requested state"
106
+ end tell
107
+ end tell
108
+ end run`;
109
+ function setInspectorMenu(pid, enabled, run) {
110
+ if (!Number.isSafeInteger(pid) || pid <= 1) throw Error("Exact owned Desktop PID required.");
111
+ const result = run("/usr/bin/osascript", ["-e", claudeInspectorMenuScript, String(pid), enabled ? "enable" : "disable"], { encoding: "utf8", timeout: 3e4, maxBuffer: 16384 });
112
+ if (result.error || result.status !== 0 || result.stdout.trim() !== (enabled ? "owned-main-debugger-click-acknowledged" : "owned-main-debugger-closed-acknowledged")) throw Error("Approved native main-debugger menu activation unavailable; no signal or fallback used.");
113
+ return { state: enabled ? "owned-native-debugger-menu-acknowledged" : "owned-native-debugger-menu-disabled", pid };
114
+ }
115
+ function enableClaudeInspectorMenu(pid, run = spawnSync) {
116
+ return setInspectorMenu(pid, true, run);
117
+ }
118
+ function disableClaudeInspectorMenu(pid, run = spawnSync) {
119
+ return setInspectorMenu(pid, false, run);
120
+ }
121
+
122
+ // src/lib/claude-pack-activation.ts
123
+ import * as fs from "fs";
124
+ import * as path from "path";
125
+ import { createHash, randomBytes, randomUUID } from "crypto";
126
+ import { spawnSync as spawnSync2 } from "child_process";
127
+ import { fileURLToPath } from "url";
128
+ import { createServer } from "net";
129
+ var digest = (data) => createHash("sha256").update(data).digest("hex");
130
+ function owned(file) {
131
+ const s = fs.lstatSync(file);
132
+ if (!s.isFile() || s.isSymbolicLink() || s.nlink !== 1 || s.uid !== process.getuid?.() || s.mode & 18 || s.size > 1048576 || fs.realpathSync(file) !== file) throw Error("Exact owned bounded activation record required.");
133
+ return fs.readFileSync(file, "utf8");
134
+ }
135
+ function put(file, text, exclusive = false) {
136
+ if (exclusive) {
137
+ const fd = fs.openSync(file, "wx", 384);
138
+ try {
139
+ fs.writeFileSync(fd, text);
140
+ fs.fsyncSync(fd);
141
+ } finally {
142
+ fs.closeSync(fd);
143
+ }
144
+ } else {
145
+ const temporary = file + "." + randomUUID() + ".tmp";
146
+ put(temporary, text, true);
147
+ fs.renameSync(temporary, file);
148
+ }
149
+ const d = fs.openSync(path.dirname(file), "r");
150
+ try {
151
+ fs.fsyncSync(d);
152
+ } finally {
153
+ fs.closeSync(d);
154
+ }
155
+ }
156
+ function json(file) {
157
+ return JSON.parse(owned(file));
158
+ }
159
+ function append(file, row) {
160
+ const fd = fs.openSync(file, "a", 384);
161
+ try {
162
+ fs.writeFileSync(fd, JSON.stringify(row) + "\n");
163
+ fs.fsyncSync(fd);
164
+ } finally {
165
+ fs.closeSync(fd);
166
+ }
167
+ }
168
+ function cloud(root, params) {
169
+ const here = path.dirname(fileURLToPath(import.meta.url));
170
+ const adapter = [path.resolve(here, "../agent-packs/topolo-agent-pack"), path.resolve(here, "../../agent-packs/topolo-agent-pack")].find(fs.existsSync);
171
+ if (!adapter) throw Error("Bundled activation helper unavailable.");
172
+ const frozen = materializeClaudeHookAdapter(root, adapter), python = qualifyClaudePython();
173
+ const script = `import sys,json,pathlib,hashlib
174
+ p=json.loads(sys.stdin.read(65537))
175
+ assert hashlib.sha256(pathlib.Path(sys.executable).read_bytes()).hexdigest()==p['python']['sha256']
176
+ for name,digest in p['files'].items():
177
+ assert hashlib.sha256(pathlib.Path(name).read_bytes()).hexdigest()==digest
178
+ sys.path.insert(0,p['source'])
179
+ from topolo_agent_pack.claude_activation import observe
180
+ r=observe(p['root'],**p['params'])
181
+ print(json.dumps(r))`;
182
+ const result = spawnSync2(python.executable, ["-I", "-B", "-c", script], { encoding: "utf8", input: JSON.stringify({ root, source: frozen.source, files: frozen.files, python, params }), timeout: 18e4, maxBuffer: 1048576 });
183
+ if (result.error || result.status !== 0) throw Error("Cloud activation/closure proof failed; preserve native ownership.");
184
+ return JSON.parse(result.stdout);
185
+ }
186
+ function observer(pid, profile, members, journal, warm = false) {
187
+ return `(async()=>{if(process.pid!==${pid})throw Error('Desktop PID changed');const load=process.getBuiltinModule('module').createRequire(process.resourcesPath+'/app.asar/package.json'),caps=(${discoverClaudeNativeCapabilities.toString()})(load,process.resourcesPath);const check=()=>{caps.assertCurrent();(${verifyClaudeDesktopProfileNative.toString()})(${JSON.stringify(profile)},process.pid,load('electron').app,caps.manager,process.env);};check();const fs=load('node:fs');const checkpoint=row=>{const fd=fs.openSync(${JSON.stringify(journal)},'a',384);try{fs.writeSync(fd,JSON.stringify(row)+'\\n');fs.fsyncSync(fd);}finally{fs.closeSync(fd);}};return (${observeClaudeFrontdoors.toString()})(caps.manager,${JSON.stringify(members)},check,${warm},checkpoint);})()`;
188
+ }
189
+ function checkResult(result, members) {
190
+ if (result?.state !== "installed-frontdoors-verified" || result.nativeInputsSent !== false || result.members?.length !== 3 || result.members.some((r, i) => ["key", "sessionId", "cwd", "title", "model", "effort", "permissionMode"].some((k) => r[k] !== members[i][k]) || !r.pinned || !/^[-a-f0-9]{36}$/.test(r.cliSessionId))) throw Error("Exact installed native front-door acknowledgement differs.");
191
+ }
192
+ function sameNativeConnection(left, right) {
193
+ const keys = ["identity", "pid", "runtime", "secretPath", "socket"];
194
+ return left && Object.keys(left).sort().join() === keys.join() && keys.every((k) => left[k] === right[k]);
195
+ }
196
+ function installedBindingMatches(binding, connection, pid, members) {
197
+ const channels = { engineering: "engineering", "operator-01": "operations", cicd: "cicd" };
198
+ return sameNativeConnection(binding.nativeConnection, connection) && binding.desktopPid === pid && binding.roles?.length === 3 && binding.roles.every((r, i) => Object.keys(r).sort().join() === "channel,cwd,sessionId" && r.channel === channels[members[i].key.split("/").at(-1)] && r.cwd === members[i].cwd);
199
+ }
200
+ function immutable(root, pack, policy) {
201
+ if (["startup-operation.json", "native-operation.json"].some((n) => fs.existsSync(path.join(root, "claude", n)))) throw Error("Unresolved native startup retains custody.");
202
+ const profile = readClaudeDesktopProfile(root);
203
+ if (!profile || profile.profile.pack !== pack) throw Error("Owned signed-in Desktop profile required.");
204
+ const p = json(policy);
205
+ if (p.pack !== pack || p.installationConsent?.profile !== "full-access" || profile.profile.consentDigest !== digest(JSON.stringify(p.installationConsent))) throw Error("Current activation consent differs.");
206
+ return { profile, policy: p };
207
+ }
208
+ async function finalizeClaudePack(options, evaluate = evaluateClaudeMain, prove = cloud, finishInspector = closeClaudeInspector, bind = bindClaudeFrontdoorHooks) {
209
+ const root = fs.realpathSync(options.store), release = await lockClaudeLibrary(root);
210
+ try {
211
+ const { profile } = immutable(root, options.pack, options.policy);
212
+ if (profile.pid !== options.pid) throw Error("Current native profile PID differs.");
213
+ if (!/^[a-f0-9-]{36}$/.test(options.startupOperation) || !/^[a-f0-9-]{36}$/.test(options.qualificationTask)) throw Error("Exact startup and qualification identities required.");
214
+ const file = path.join(root, "claude/activation.json"), pending = path.join(root, "claude/activation-operation.json");
215
+ const prior = fs.existsSync(pending) ? json(pending) : null;
216
+ if (fs.existsSync(file) && !prior) {
217
+ const { receipt: receipt2 } = validateActivation(root, options.pack, options.policy);
218
+ if (receipt2.startupOperation !== options.startupOperation || receipt2.qualificationTask !== options.qualificationTask || receipt2.pid !== options.pid) throw Error("Existing activation belongs to another operation.");
219
+ const proof2 = prove(root, { qualification_task: options.qualificationTask, start_service: true, native_proof: true });
220
+ checkResult(proof2.native, receipt2.members);
221
+ return { state: "claude-pack-activated", alreadyActivated: true, cloudReady: true, nativeInputsSent: false, coordinators: 3 };
222
+ }
223
+ if (prior && (prior.startupOperation !== options.startupOperation || prior.qualificationTask !== options.qualificationTask)) throw Error("Another activation operation retains custody.");
224
+ const startup = path.join(root, "claude/journals", options.startupOperation + ".jsonl"), text = owned(startup), rows = text.trimEnd().split("\n").map((r) => JSON.parse(r)), plan = rows[0];
225
+ if (!text.endsWith("\n") || plan.kind !== "startup-plan" || plan.operationId !== options.startupOperation || plan.libraryRoot !== root || plan.members?.length !== 3 || !rows.some((r) => r.kind === "frontdoor-hooks-prepared") || plan.previousCoordinators?.length && !rows.some((r) => r.kind === "previous-coordinators-retired" && JSON.stringify(r.retired) === JSON.stringify(plan.previousCoordinators.map((r2) => r2.sessionId)))) throw Error("Completed original startup acknowledgement required.");
226
+ const statePath = path.join(root, "claude/state.json"), state = json(statePath), members = plan.members;
227
+ const selected = state.agents.filter((r) => r.pack === options.pack);
228
+ if (selected.length !== 3 || selected.some((r, i) => r.key !== members[i].key || r.desktopSessionId !== members[i].sessionId || r.sourceRevision !== plan.sourceRevision || r.workspace !== members[i].cwd)) throw Error("Original prepared coordinator identity differs.");
229
+ for (const [f, hash] of Object.entries(plan.context)) {
230
+ if (f === statePath && prior) continue;
231
+ if (digest(owned(f)) !== hash) throw Error("Original startup context changed.");
232
+ }
233
+ const connection = readClaudeTaskConnection(path.join(root, "claude/desktop-task-connection.json"), options.pid), binding = json(path.join(root, "work/claude-frontdoors.json"));
234
+ if (!installedBindingMatches(binding, connection, options.pid, members)) throw Error("Current installed front-door binding differs.");
235
+ const controlJournal = path.join(root, "claude/journals", options.startupOperation + ".activation.jsonl");
236
+ if (!fs.existsSync(controlJournal)) put(controlJournal, JSON.stringify({ kind: "activation-native-observation", startupOperation: options.startupOperation }) + "\n", true);
237
+ const boundMembers = members.map((m, i) => ({ ...m, cliSessionId: binding.roles[i].sessionId }));
238
+ const observed = await evaluate(options.endpoint, observer(options.pid, profile.profile, boundMembers, controlJournal, true));
239
+ checkResult(observed, members);
240
+ if (observed.members.some((m, i) => m.cliSessionId !== binding.roles[i].sessionId)) throw Error("Native SDK and installed hook identity differ.");
241
+ const proof = prove(root, { qualification_task: options.qualificationTask, start_service: true });
242
+ if (proof.activated !== true || proof.service?.desktopPid !== options.pid || proof.qualificationTaskId !== options.qualificationTask) throw Error("Live cloud qualification differs.");
243
+ const next = structuredClone(state), changes = [];
244
+ for (let i = 0; i < selected.length; i++) {
245
+ const before = selected[i], native = observed.members[i], record = next.agents.find((r) => r.key === before.key);
246
+ const key = members[i].cwd.replace(/[^a-zA-Z0-9]/g, "-");
247
+ if (key.length > 200) throw Error("Native SDK path codec exceeds qualified bounds.");
248
+ const transcript = path.join(profile.profile.codeConfig, "projects", key, native.cliSessionId + ".jsonl");
249
+ owned(transcript);
250
+ const identity = path.join(root, "claude/identities", digest(before.key) + ".json"), oldIdentity = owned(identity);
251
+ if (!prior && JSON.stringify(JSON.parse(oldIdentity)) !== JSON.stringify(before)) throw Error("Prepared identity and state differ.");
252
+ Object.assign(record, { importState: "desktop-adopted", cliSessionId: native.cliSessionId, transcript });
253
+ changes.push({ file: identity, before: oldIdentity, after: JSON.stringify(record) + "\n" });
254
+ }
255
+ changes.push({ file: statePath, before: owned(statePath), after: JSON.stringify(next) + "\n" });
256
+ const active = { operationId: options.startupOperation, pack: options.pack, keys: members.map((m) => m.key), sourceRevision: plan.sourceRevision };
257
+ const activePath = path.join(root, "claude/active.json");
258
+ changes.push({ file: activePath, before: fs.existsSync(activePath) ? owned(activePath) : null, after: JSON.stringify(active) + "\n" });
259
+ const receipt = { format: "topolo-claude-pack-activation-v1", root, pack: options.pack, startupOperation: options.startupOperation, startupDigest: digest(text), sourceRevision: plan.sourceRevision, policyDigest: digest(owned(options.policy)), members: observed.members, qualificationTask: options.qualificationTask, cloud: proof.binding, profile: profile.profile, pid: options.pid, connection, cloudReady: true, nativeInputsSent: false, menuAutomationConsent: { approved: options.allowNativeDebuggerMenu === true, principalId: JSON.parse(owned(options.policy)).installationConsent.principalId, scope: "owned-claude-main-debugger-checkbox-only" } };
260
+ const operation = prior ?? { format: "topolo-claude-activation-operation-v1", startupOperation: options.startupOperation, qualificationTask: options.qualificationTask, state: "prepared", changes, receipt };
261
+ if (prior && JSON.stringify(prior.receipt) !== JSON.stringify(receipt)) throw Error("Pending activation proof differs; reconcile without adoption.");
262
+ if (!prior) put(pending, JSON.stringify(operation) + "\n", true);
263
+ for (const change of operation.changes) {
264
+ const current = fs.existsSync(change.file) ? owned(change.file) : null;
265
+ if (current !== change.before && current !== change.after) throw Error("Activation metadata changed outside its journal.");
266
+ if (current !== change.after) put(change.file, change.after);
267
+ }
268
+ const control = await evaluate(options.endpoint, nativeClaudeDesktopControlExpression(options.pid, root, connection, connection.secretPath, controlJournal, { existing: connection, coordinators: members, frontdoors: observed.members }));
269
+ if (!["native-desktop-task-control-installed", "native-desktop-task-control-reused"].includes(control.state)) throw Error("Qualified closed native control was not acknowledged.");
270
+ const hookInput = path.join(root, "claude/journals", options.startupOperation + ".activation-frontdoors.json");
271
+ bind(root, options.pid, observed.members.map((m) => ({ key: m.key, cwd: m.cwd, sessionId: m.cliSessionId })), hookInput, void 0, connection, fs.existsSync(hookInput));
272
+ for (const [file2, hash] of Object.entries(plan.context)) if (file2 !== statePath && digest(owned(file2)) !== hash) throw Error("Selected role context changed during hook migration.");
273
+ put(file, JSON.stringify(receipt) + "\n");
274
+ fs.unlinkSync(pending);
275
+ return { state: "claude-pack-activated", pack: options.pack, coordinators: 3, cloudReady: true, nativeInputsSent: false, qualificationTask: options.qualificationTask };
276
+ } finally {
277
+ try {
278
+ const p = readClaudeDesktopProfile(root);
279
+ if (p?.pid === options.pid) await finishInspector(options.endpoint, options.pid, p.profile, evaluate);
280
+ } finally {
281
+ await release();
282
+ }
283
+ }
284
+ }
285
+ async function upgradeClaudeControl(options, evaluate = evaluateClaudeMain, finishInspector = closeClaudeInspector) {
286
+ const root = fs.realpathSync(options.store);
287
+ let release;
288
+ try {
289
+ release = await lockClaudeLibrary(root, true);
290
+ const { profile } = immutable(root, options.pack, options.policy);
291
+ if (profile.pid !== options.pid || !/^[a-f0-9-]{36}$/.test(options.startupOperation)) throw Error("Exact current profile and original startup required.");
292
+ if (["activation-operation.json", "launch-operation.json"].some((n) => fs.existsSync(path.join(root, "claude", n)))) throw Error("Unresolved activation or launch retains custody.");
293
+ const startup = path.join(root, "claude/journals", options.startupOperation + ".jsonl"), text = owned(startup), rows = text.trimEnd().split("\n").map((r) => JSON.parse(r)), plan = rows[0];
294
+ if (!text.endsWith("\n") || plan.kind !== "startup-plan" || plan.operationId !== options.startupOperation || plan.libraryRoot !== root || plan.installationConsent?.pack !== options.pack || plan.members?.length !== 3 || !rows.some((r) => r.kind === "frontdoor-hooks-prepared") || plan.previousCoordinators?.length && !rows.some((r) => r.kind === "previous-coordinators-retired" && JSON.stringify(r.retired) === JSON.stringify(plan.previousCoordinators.map((m) => m.sessionId)))) throw Error("Completed exact original startup required.");
295
+ const statePath = path.join(root, "claude/state.json"), state = json(statePath), selected = state.agents.filter((m) => m.pack === options.pack), members = plan.members;
296
+ if (selected.length !== 3 || selected.some((m, i) => m.key !== members[i].key || m.desktopSessionId !== members[i].sessionId || m.workspace !== members[i].cwd || m.sourceRevision !== plan.sourceRevision)) throw Error("Original coordinator roster changed.");
297
+ const adopted = fs.existsSync(path.join(root, "claude/activation.json")) ? validateActivation(root, options.pack, options.policy).receipt : null;
298
+ if (adopted && (adopted.startupOperation !== options.startupOperation || adopted.startupDigest !== digest(text))) throw Error("Activated startup ownership differs.");
299
+ for (const [file, hash] of Object.entries(plan.context)) if (!(adopted && file === statePath) && digest(owned(file)) !== hash) throw Error("Original startup context changed.");
300
+ const connection = readClaudeTaskConnection(path.join(root, "claude/desktop-task-connection.json"), options.pid), binding = json(path.join(root, "work/claude-frontdoors.json"));
301
+ if (!installedBindingMatches(binding, connection, options.pid, members)) throw Error("Installed native front-door binding differs.");
302
+ const operationId = randomUUID(), journal = path.join(root, "claude/journals", operationId + ".control-upgrade.jsonl");
303
+ put(journal, JSON.stringify({ kind: "owned-control-upgrade", operationId, startupOperation: options.startupOperation, startupDigest: digest(text), policyDigest: digest(owned(options.policy)), connection, members, nativeInputsSent: false }) + "\n", true);
304
+ const observed = await evaluate(options.endpoint, observer(options.pid, profile.profile, members.map((m, i) => ({ ...m, cliSessionId: binding.roles[i].sessionId })), journal));
305
+ checkResult(observed, members);
306
+ if (observed.members.some((m, i) => m.cliSessionId !== binding.roles[i].sessionId)) throw Error("Native SDK and installed binding differ.");
307
+ const result = await evaluate(options.endpoint, nativeClaudeDesktopControlExpression(options.pid, root, connection, connection.secretPath, journal, { existing: connection, coordinators: members, frontdoors: observed.members }));
308
+ if (!["native-desktop-task-control-installed", "native-desktop-task-control-reused"].includes(result?.state)) throw Error("Owned native control upgrade was not acknowledged.");
309
+ append(journal, { kind: "owned-control-upgrade-verified", operationId, nativeInputsSent: false });
310
+ return { state: "claude-control-upgraded", startupOperation: options.startupOperation, pid: options.pid, coordinators: 3, nativeInputsSent: false };
311
+ } finally {
312
+ try {
313
+ const profile = readClaudeDesktopProfile(root);
314
+ if (profile?.pid === options.pid) await finishInspector(options.endpoint, options.pid, profile.profile, evaluate);
315
+ } finally {
316
+ if (release) await release();
317
+ }
318
+ }
319
+ }
320
+ function validateActivation(root, pack, policy, continueLaunch = false) {
321
+ const { profile } = immutable(root, pack, policy), receipt = json(path.join(root, "claude/activation.json"));
322
+ if (fs.existsSync(path.join(root, "claude/activation-operation.json")) || !continueLaunch && fs.existsSync(path.join(root, "claude/launch-operation.json"))) throw Error("Unresolved activation or launch retains custody.");
323
+ if (receipt.format !== "topolo-claude-pack-activation-v1" || receipt.root !== root || receipt.pack !== pack || receipt.policyDigest !== digest(owned(policy)) || JSON.stringify(receipt.profile) !== JSON.stringify(profile.profile)) throw Error("Activated pack/profile/consent changed.");
324
+ const state = json(path.join(root, "claude/state.json")), active = json(path.join(root, "claude/active.json"));
325
+ if (active.pack !== pack || active.operationId !== receipt.startupOperation || JSON.stringify(active.keys) !== JSON.stringify(receipt.members.map((m) => m.key))) throw Error("Verified active coordinator roster changed.");
326
+ for (const m of receipt.members) {
327
+ const r = state.agents.filter((r2) => r2.key === m.key);
328
+ if (r.length !== 1 || r[0].importState !== "desktop-adopted" || r[0].desktopSessionId !== m.sessionId || r[0].cliSessionId !== m.cliSessionId || r[0].workspace !== m.cwd || r[0].sourceRevision !== receipt.sourceRevision) throw Error("Activated coordinator identity changed.");
329
+ }
330
+ return { profile, receipt };
331
+ }
332
+ async function port(preferred = 0) {
333
+ const server = createServer();
334
+ await new Promise((done, fail) => {
335
+ server.once("error", fail);
336
+ server.listen(preferred, "127.0.0.1", done);
337
+ });
338
+ const selected = server.address().port;
339
+ await new Promise((done) => server.close(() => done()));
340
+ return selected;
341
+ }
342
+ async function resolveClaudeInspectorEndpoint(port2) {
343
+ let last;
344
+ for (let n = 0; n < 100; n++) {
345
+ let response;
346
+ try {
347
+ response = await fetch("http://127.0.0.1:" + port2 + "/json/list", { signal: AbortSignal.timeout(500) });
348
+ } catch (error) {
349
+ last = error;
350
+ await new Promise((r) => setTimeout(r, 100));
351
+ continue;
352
+ }
353
+ if (!response.ok) throw Error("Native inspector discovery was refused.");
354
+ const text = await response.text();
355
+ if (Buffer.byteLength(text) > 16384) throw Error("Native inspector discovery exceeded bounds.");
356
+ const rows = JSON.parse(text);
357
+ if (!Array.isArray(rows) || rows.length !== 1 || typeof rows[0].webSocketDebuggerUrl !== "string") throw Error("Ambiguous native inspector endpoint.");
358
+ const u = new URL(rows[0].webSocketDebuggerUrl);
359
+ if (u.hostname !== "127.0.0.1" || Number(u.port) !== port2 || u.protocol !== "ws:") throw Error("Native inspector left loopback boundary.");
360
+ return u.href;
361
+ }
362
+ throw Error("Owned temporary native inspector unavailable: " + String(last));
363
+ }
364
+ async function closeClaudeInspector(url, pid, profile, evaluate, disable = disableClaudeInspectorMenu) {
365
+ const ack = await evaluate(url, `(()=>{if(process.pid!==${pid})throw Error('Inspector owner changed');const load=process.getBuiltinModule('module').createRequire(process.resourcesPath+'/app.asar/package.json'),app=load('electron').app;if(app.getPath('userData')!==${JSON.stringify(profile.userData)})throw Error('Inspector profile differs');return{closing:true};})()`);
366
+ if (ack?.closing !== true) throw Error("Native inspector closure acknowledgement differs.");
367
+ const menu = disable(pid);
368
+ if (menu.state !== "owned-native-debugger-menu-disabled" || menu.pid !== pid) throw Error("Owned native debugger checkbox closure was not acknowledged.");
369
+ await new Promise((r) => setTimeout(r, 100));
370
+ try {
371
+ await fetch(new URL("/json/list", url.replace(/^ws:/, "http:")), { signal: AbortSignal.timeout(500) });
372
+ } catch {
373
+ return;
374
+ }
375
+ throw Error("Temporary inspector closure was not verified.");
376
+ }
377
+ async function launchActivatedClaudePack(options, deps = {}) {
378
+ const root = fs.realpathSync(options.store), release = await lockClaudeLibrary(root), prove = deps.prove ?? cloud, launch = deps.launch ?? launchClaudeDesktopProfile, evaluate = deps.evaluate ?? evaluateClaudeMain;
379
+ let inspection;
380
+ let pendingInspection;
381
+ try {
382
+ const continuing = options.continueLaunch !== void 0;
383
+ const { profile, receipt } = validateActivation(root, options.pack, options.policy, continuing);
384
+ const args = { root, pack: options.pack, policy: options.policy, userData: profile.profile.userData, codeConfig: profile.profile.codeConfig, app: profile.profile.app };
385
+ const before = launch({ ...args, apply: false });
386
+ if (continuing && before.pid === receipt.pid) throw Error("Pending cold launch cannot adopt the previous owner.");
387
+ if (before.pid === receipt.pid) {
388
+ const binding = json(path.join(root, "work/claude-frontdoors.json"));
389
+ if (!installedBindingMatches(binding, receipt.connection, receipt.pid, receipt.members) || binding.roles.some((m, i) => m.sessionId !== receipt.members[i].cliSessionId)) throw Error("Warm coordinator binding differs.");
390
+ const proof2 = prove(root, { warm_connection: receipt.connection });
391
+ if (proof2.warmOwner !== true || proof2.nativeInputsSent !== false || proof2.workerCustodyPreserved !== true) throw Error("Warm ownership proof differs.");
392
+ if (proof2.service?.desktopPid !== receipt.pid || JSON.stringify(proof2.binding) !== JSON.stringify(receipt.cloud)) throw Error("Current owning dispatcher differs.");
393
+ return { state: "claude-pack-ready", nativeReady: true, cloudReady: true, coordinators: 3, nativeInputsSent: false, pid: receipt.pid };
394
+ }
395
+ if (receipt.menuAutomationConsent?.approved !== true || receipt.menuAutomationConsent.scope !== "owned-claude-main-debugger-checkbox-only" || receipt.menuAutomationConsent.principalId !== json(options.policy).installationConsent.principalId) throw Error("Explicit installation-owner main-debugger menu consent required for cold restore.");
396
+ try {
397
+ process.kill(receipt.pid, 0);
398
+ throw Error("Previous native owner remains alive.");
399
+ } catch (error) {
400
+ if (error.code !== "ESRCH") throw error;
401
+ }
402
+ if (continuing && !/^[a-f0-9-]{36}$/.test(options.continueLaunch)) throw Error("Exact pending cold launch identity required.");
403
+ const operationId = options.continueLaunch ?? randomUUID(), journal = path.join(root, "claude/journals", operationId + ".launch.jsonl"), secretPath = path.join(root, "claude/journals", operationId + ".desktop-secret.json");
404
+ const marker = path.join(root, "claude/launch-operation.json"), previous = json(path.join(root, "work/claude-frontdoors.json"));
405
+ if (continuing) {
406
+ if (!options.endpoint || !Number.isSafeInteger(options.pid) || options.pid !== before.pid) throw Error("Exact already launched profile PID and approved endpoint required.");
407
+ validateInspectorEndpoint(options.endpoint);
408
+ inspection = { url: options.endpoint, pid: options.pid, profile: profile.profile };
409
+ }
410
+ if (continuing) {
411
+ const pending = json(marker), text = owned(journal), rows = text.trimEnd().split("\n").map((row) => JSON.parse(row)), first = rows[0], installs = rows.filter((r) => r.kind === "native-desktop-task-control-installed"), installed2 = installs[0];
412
+ if (installed2) {
413
+ const setup = rows.slice(0, rows.indexOf(installed2) + 1), activity = rows.slice(setup.length);
414
+ const workerKinds = ["worker-workspace-trust-attempt", "worker-workspace-trust-verified", "worker-create-attempt", "worker-create-verified", "worker-task-send-attempt", "worker-task-send-acknowledged", "worker-archive-attempt", "worker-archive-verified"];
415
+ const pid2 = options.pid, url2 = options.endpoint, descriptor2 = { ...receipt.connection, pid: pid2, identity: digest(JSON.stringify({ root, pack: options.pack, operationId })), socket: path.join("/tmp", "topolo-claude-task-" + operationId + ".sock"), secretPath };
416
+ const allowed = ["closed-native-rebind", "closed-native-rebind-continuation", "frontdoor-connect-only-attempt", "native-python-capability-qualified", "native-desktop-task-control-installed"];
417
+ const created = setup.filter((r) => r.kind === "native-desktop-task-control-installed"), connects = setup.filter((r) => r.kind === "frontdoor-connect-only-attempt"), continuations = setup.filter((r) => r.kind === "closed-native-rebind-continuation");
418
+ const input2 = path.join(root, "claude/journals", operationId + ".frontdoors.json"), bound = json(input2);
419
+ if (Object.keys(pending).sort().join() !== "journal,operationId,previousPid,state" || pending.operationId !== operationId || pending.state !== "may-have-effects" || pending.previousPid !== receipt.pid || pending.journal !== journal || !text.endsWith("\n") || first.kind !== "closed-native-rebind" || first.operationId !== operationId || first.previousPid !== receipt.pid || JSON.stringify(first.members) !== JSON.stringify(receipt.members) || setup.some((r) => !allowed.includes(r.kind)) || activity.some((r) => !workerKinds.includes(r.kind)) || installs.length !== 1 || created.length !== 1 || setup.filter((r) => r.kind === "native-python-capability-qualified").length !== 1 || continuations.length > 1 || continuations.some((r) => r.operationId !== operationId || r.pid !== pid2 || r.nativeInputsSent !== false || r.originalJournalSHA256 !== digest(JSON.stringify(first) + "\n")) || new Set(connects.map((r) => r.sessionId)).size !== connects.length || connects.some((r) => !receipt.members.some((m) => m.sessionId === r.sessionId && m.cliSessionId === r.cliSessionId)) || ["identity", "pid", "runtime", "secretPath", "socket"].some((k) => installed2[k] !== descriptor2[k]) || !sameNativeConnection(readClaudeTaskConnection(path.join(root, "claude/desktop-task-connection.json"), receipt.pid), receipt.connection) || !installedBindingMatches(previous, descriptor2, pid2, receipt.members) || previous.roles.some((r, i) => r.sessionId !== receipt.members[i].cliSessionId) || bound.desktopPid !== pid2 || !sameNativeConnection(bound.nativeConnection, descriptor2) || JSON.stringify(bound.roles) !== JSON.stringify(receipt.members.map((m) => ({ key: m.key, cwd: m.cwd, sessionId: m.cliSessionId }))) || Object.keys(json(secretPath)).join() !== "token" || !/^[a-f0-9]{64}$/.test(json(secretPath).token)) throw Error("Pending post-control launch custody differs; do not replay.");
420
+ let proof2 = prove(root, { successor_connection: descriptor2 });
421
+ if (proof2.existingSuccessor !== true) {
422
+ if (activity.length) throw Error("Worker audit activity requires the exact authenticated successor; preserve its custody.");
423
+ prove(root, { previous: { ...previous, desktopPid: receipt.pid, nativeConnection: receipt.connection }, connection: descriptor2, wait_retired_service: true });
424
+ proof2 = prove(root, { start_service: true, native_proof: true, require_native_idle: true });
425
+ } else if (proof2.serviceStarted !== false || proof2.workerCustodyPreserved !== true || proof2.nativeInputsSent !== false) throw Error("Successor reconciliation must preserve live worker custody.");
426
+ checkResult(proof2.native, receipt.members);
427
+ if (proof2.service?.desktopPid !== pid2 || JSON.stringify(proof2.binding) !== JSON.stringify(receipt.cloud) || proof2.native.members.some((m, i) => m.cliSessionId !== receipt.members[i].cliSessionId)) throw Error("Successor dispatcher differs.");
428
+ const actual2 = await evaluate(url2, `(()=>{if(process.pid!==${pid2})throw Error('Native PID changed');const load=process.getBuiltinModule('module').createRequire(process.resourcesPath+'/app.asar/package.json');return{state:'native-profile-verified',pid:process.pid,userData:load('electron').app.getPath('userData'),codeConfig:process.env.CLAUDE_CONFIG_DIR};})()`);
429
+ acknowledgeClaudeDesktopProfile(root, readClaudeDesktopProfile(root), actual2);
430
+ put(path.join(root, "claude/desktop-task-connection.json"), JSON.stringify(descriptor2) + "\n");
431
+ await (deps.close ?? closeClaudeInspector)(url2, pid2, profile.profile, evaluate);
432
+ inspection = void 0;
433
+ append(journal, { kind: "closed-native-rebind-verified", pid: pid2, nativeInputsSent: false, completedExistingControl: true, originalJournalSHA256: digest(text) });
434
+ put(path.join(root, "claude/activation.json"), JSON.stringify({ ...receipt, pid: pid2, connection: descriptor2 }) + "\n");
435
+ fs.unlinkSync(marker);
436
+ return { state: "claude-pack-ready", nativeReady: true, cloudReady: true, coordinators: 3, nativeInputsSent: false, pid: pid2 };
437
+ }
438
+ }
439
+ if (!sameNativeConnection(previous.nativeConnection, receipt.connection)) throw Error("Previous native connection ownership differs.");
440
+ prove(root, { previous, wait_retired_service: true });
441
+ let pid, url;
442
+ if (continuing) {
443
+ pid = options.pid;
444
+ url = options.endpoint;
445
+ const pending = json(marker), text = owned(journal), rows = text.trimEnd().split("\n").map((row) => JSON.parse(row)), first = rows[0];
446
+ if (Object.keys(pending).sort().join() !== "journal,operationId,previousPid,state" || pending.operationId !== operationId || pending.state !== "may-have-effects" || pending.previousPid !== receipt.pid || pending.journal !== journal || !text.endsWith("\n") || rows.length !== 1 || first.kind !== "closed-native-rebind" || first.operationId !== operationId || first.previousPid !== receipt.pid || JSON.stringify(first.members) !== JSON.stringify(receipt.members) || fs.existsSync(secretPath) || fs.existsSync(path.join(root, "claude/journals", operationId + ".frontdoors.json")) || !sameNativeConnection(readClaudeTaskConnection(path.join(root, "claude/desktop-task-connection.json"), receipt.pid), receipt.connection)) throw Error("Pending launch progressed beyond the exact pre-control phase; preserve its custody.");
447
+ append(journal, { kind: "closed-native-rebind-continuation", operationId, pid, originalJournalSHA256: digest(text), nativeInputsSent: false });
448
+ } else {
449
+ const selected = await (deps.port ?? port)(9229);
450
+ put(marker, JSON.stringify({ operationId, state: "may-have-effects", previousPid: receipt.pid, journal }) + "\n", true);
451
+ put(journal, JSON.stringify({ kind: "closed-native-rebind", operationId, members: receipt.members, previousPid: receipt.pid }) + "\n", true);
452
+ if (!before.pid) launch({ ...args, apply: true });
453
+ let current = launch({ ...args, apply: false });
454
+ for (let n = 0; !current.pid && n < 100; n++) {
455
+ await new Promise((r) => setTimeout(r, 100));
456
+ current = launch({ ...args, apply: false });
457
+ }
458
+ if (!Number.isSafeInteger(current.pid) || current.pid === receipt.pid) throw Error("Exact successor profile process missing.");
459
+ pid = current.pid;
460
+ pendingInspection = { port: selected, pid, profile: profile.profile };
461
+ (deps.activateInspector ?? enableClaudeInspectorMenu)(pid);
462
+ url = await (deps.endpoint ?? resolveClaudeInspectorEndpoint)(selected);
463
+ inspection = { url, pid, profile: profile.profile };
464
+ pendingInspection = void 0;
465
+ }
466
+ const native = await evaluate(url, observer(pid, profile.profile, receipt.members, journal, true));
467
+ checkResult(native, receipt.members);
468
+ const descriptor = { ...receipt.connection, pid, identity: digest(JSON.stringify({ root, pack: options.pack, operationId })), socket: path.join("/tmp", "topolo-claude-task-" + operationId + ".sock"), secretPath };
469
+ prove(root, { previous, connection: descriptor });
470
+ put(secretPath, JSON.stringify({ token: randomBytes(32).toString("hex") }) + "\n", true);
471
+ const installed = await evaluate(url, nativeClaudeDesktopControlExpression(pid, root, descriptor, secretPath, journal, { coordinators: receipt.members, frontdoors: receipt.members }));
472
+ if (installed.state !== "native-desktop-task-control-installed") throw Error("Successor closed control is unacknowledged.");
473
+ const input = path.join(root, "claude/journals", operationId + ".frontdoors.json");
474
+ (deps.bind ?? bindClaudeFrontdoorHooks)(root, pid, receipt.members.map((m) => ({ key: m.key, cwd: m.cwd, sessionId: m.cliSessionId })), input, void 0, descriptor);
475
+ const proof = prove(root, { start_service: true, native_proof: true });
476
+ checkResult(proof.native, receipt.members);
477
+ if (proof.service?.desktopPid !== pid || JSON.stringify(proof.binding) !== JSON.stringify(receipt.cloud) || proof.native.members.some((m, i) => m.cliSessionId !== receipt.members[i].cliSessionId)) throw Error("Successor dispatcher differs.");
478
+ const next = { ...receipt, pid, connection: descriptor };
479
+ put(path.join(root, "claude/desktop-task-connection.json"), JSON.stringify(descriptor) + "\n");
480
+ const actual = await evaluate(url, `(()=>{if(process.pid!==${pid})throw Error('Native PID changed');const load=process.getBuiltinModule('module').createRequire(process.resourcesPath+'/app.asar/package.json');return{state:'native-profile-verified',pid:process.pid,userData:load('electron').app.getPath('userData'),codeConfig:process.env.CLAUDE_CONFIG_DIR};})()`);
481
+ acknowledgeClaudeDesktopProfile(root, readClaudeDesktopProfile(root), actual);
482
+ await (deps.close ?? closeClaudeInspector)(url, pid, profile.profile, evaluate);
483
+ inspection = void 0;
484
+ append(journal, { kind: "closed-native-rebind-verified", pid, nativeInputsSent: false });
485
+ put(path.join(root, "claude/activation.json"), JSON.stringify(next) + "\n");
486
+ fs.unlinkSync(marker);
487
+ return { state: "claude-pack-ready", nativeReady: true, cloudReady: true, coordinators: 3, nativeInputsSent: false, pid };
488
+ } finally {
489
+ try {
490
+ if (pendingInspection) {
491
+ const url = await (deps.endpoint ?? resolveClaudeInspectorEndpoint)(pendingInspection.port);
492
+ inspection = { url, pid: pendingInspection.pid, profile: pendingInspection.profile };
493
+ }
494
+ if (inspection) await (deps.close ?? closeClaudeInspector)(inspection.url, inspection.pid, inspection.profile, evaluate);
495
+ } finally {
496
+ await release();
497
+ }
498
+ }
499
+ }
500
+ export {
501
+ closeClaudeInspector,
502
+ finalizeClaudePack,
503
+ launchActivatedClaudePack,
504
+ resolveClaudeInspectorEndpoint,
505
+ upgradeClaudeControl
506
+ };
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ CLAUDE_NATIVE_QUALIFIER,
4
+ bindClaudeFrontdoorHooks,
5
+ claudeLaneExpression,
6
+ claudeTaskConnectionCoordinators,
7
+ completeClaudeStartup,
8
+ configureClaudePack,
9
+ configureClaudeStartup,
10
+ ensureClaudeCoordinators,
11
+ evaluateClaudeMain,
12
+ lockClaudeLibrary,
13
+ materializeClaudeHookAdapter,
14
+ materializeClaudeWorkerGuard,
15
+ nativeClaudeDesktopControlExpression,
16
+ nativeClaudeSettingsExpression,
17
+ nativePackExpression,
18
+ operateClaudeApprovals,
19
+ operateClaudeLane,
20
+ operateClaudeLaneControl,
21
+ operateClaudeSmoke,
22
+ prepareClaudeDynamicLane,
23
+ prepareClaudeNativePlan,
24
+ prepareClaudePrivateHelperConnection,
25
+ prepareClaudeStartup,
26
+ privateClaudeHelperEnvironment,
27
+ qualifyClaudePython,
28
+ readClaudePreviousCoordinatorLibrary,
29
+ readClaudeReadinessContinuation,
30
+ readClaudeTaskConnection,
31
+ reconcileClaudeStartupAbsence,
32
+ recoverClaudeStartup,
33
+ requestClaudeApprovalControl,
34
+ requireClaudePrivateQueryEffectQualified,
35
+ retireClaudeCoordinators,
36
+ runClaudeLaneHelper,
37
+ runClaudeSmokeHelper,
38
+ snapshotClaudeMarkdown,
39
+ snapshotClaudeWorkerSource,
40
+ validateInspectorEndpoint,
41
+ verifyClaudeOrganizationPolicy,
42
+ verifyClaudePlanContext,
43
+ verifyClaudePreviousCoordinatorCustody,
44
+ verifyClaudeReadinessContinuation
45
+ } from "./chunk-UY5LEU5C.js";
46
+ import "./chunk-NYDIAYVY.js";
47
+ export {
48
+ CLAUDE_NATIVE_QUALIFIER,
49
+ bindClaudeFrontdoorHooks,
50
+ claudeLaneExpression,
51
+ claudeTaskConnectionCoordinators,
52
+ completeClaudeStartup,
53
+ configureClaudePack,
54
+ configureClaudeStartup,
55
+ ensureClaudeCoordinators,
56
+ evaluateClaudeMain,
57
+ lockClaudeLibrary,
58
+ materializeClaudeHookAdapter,
59
+ materializeClaudeWorkerGuard,
60
+ nativeClaudeDesktopControlExpression,
61
+ nativeClaudeSettingsExpression,
62
+ nativePackExpression,
63
+ operateClaudeApprovals,
64
+ operateClaudeLane,
65
+ operateClaudeLaneControl,
66
+ operateClaudeSmoke,
67
+ prepareClaudeDynamicLane,
68
+ prepareClaudeNativePlan,
69
+ prepareClaudePrivateHelperConnection,
70
+ prepareClaudeStartup,
71
+ privateClaudeHelperEnvironment,
72
+ qualifyClaudePython,
73
+ readClaudePreviousCoordinatorLibrary,
74
+ readClaudeReadinessContinuation,
75
+ readClaudeTaskConnection,
76
+ reconcileClaudeStartupAbsence,
77
+ recoverClaudeStartup,
78
+ requestClaudeApprovalControl,
79
+ requireClaudePrivateQueryEffectQualified,
80
+ retireClaudeCoordinators,
81
+ runClaudeLaneHelper,
82
+ runClaudeSmokeHelper,
83
+ snapshotClaudeMarkdown,
84
+ snapshotClaudeWorkerSource,
85
+ validateInspectorEndpoint,
86
+ verifyClaudeOrganizationPolicy,
87
+ verifyClaudePlanContext,
88
+ verifyClaudePreviousCoordinatorCustody,
89
+ verifyClaudeReadinessContinuation
90
+ };