@triflux/remote 10.50.2 → 10.52.0

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 (134) hide show
  1. package/cto/brief.mjs +0 -20
  2. package/cto/collect.mjs +1 -200
  3. package/cto/current.schema.json +2 -23
  4. package/cto/hygiene.mjs +2 -61
  5. package/cto/lake-root.mjs +0 -56
  6. package/cto/status.mjs +5 -187
  7. package/hub/index.mjs +0 -17
  8. package/hub/team/agent-map.json +0 -1
  9. package/hub/team/agents-row-attach.py +120 -0
  10. package/hub/team/agents-row.mjs +200 -0
  11. package/hub/team/ansi.mjs +1 -35
  12. package/hub/team/backend.mjs +9 -145
  13. package/hub/team/claude-daemon-control.mjs +1 -2
  14. package/hub/team/claude-session-projection.mjs +5 -73
  15. package/hub/team/cli/commands/attach.mjs +1 -17
  16. package/hub/team/cli/commands/control.mjs +12 -38
  17. package/hub/team/cli/commands/debug.mjs +2 -39
  18. package/hub/team/cli/commands/focus.mjs +5 -31
  19. package/hub/team/cli/commands/interrupt.mjs +6 -25
  20. package/hub/team/cli/commands/kill.mjs +1 -30
  21. package/hub/team/cli/commands/list.mjs +0 -16
  22. package/hub/team/cli/commands/send.mjs +6 -26
  23. package/hub/team/cli/commands/start/index.mjs +42 -133
  24. package/hub/team/cli/commands/start/parse-args.mjs +15 -40
  25. package/hub/team/cli/commands/start/start-headless.mjs +138 -105
  26. package/hub/team/cli/commands/start/start-mux.mjs +2 -7
  27. package/hub/team/cli/commands/status.mjs +2 -57
  28. package/hub/team/cli/commands/stop.mjs +14 -19
  29. package/hub/team/cli/help.mjs +4 -5
  30. package/hub/team/cli/manifest.mjs +5 -1
  31. package/hub/team/cli/render.mjs +0 -12
  32. package/hub/team/cli/services/runtime-mode.mjs +27 -98
  33. package/hub/team/cli/services/state-store.mjs +5 -20
  34. package/hub/team/handoff.mjs +3 -34
  35. package/hub/team/headless.mjs +108 -1296
  36. package/hub/team/orchestrator.mjs +4 -30
  37. package/hub/team/pane.mjs +6 -28
  38. package/hub/team/psmux.mjs +3 -34
  39. package/hub/team/remote-session.mjs +1 -2
  40. package/hub/team/session-context.mjs +1 -1
  41. package/hub/team/session.mjs +7 -91
  42. package/hub/team/tui-core.mjs +1 -1
  43. package/hub/team/tui-viewer.mjs +11 -58
  44. package/hub/team/tui.mjs +8 -306
  45. package/hub/team/uds-orchestrator.mjs +2 -580
  46. package/hub/team/wt-manager.mjs +2 -2
  47. package/hub/workers/factory.mjs +6 -84
  48. package/hub/workers/interface.mjs +1 -7
  49. package/hub/workers/lib/jsonrpc-core.mjs +11 -0
  50. package/hub/workers/lib/jsonrpc-ws-uds.mjs +5 -8
  51. package/package.json +3 -8
  52. package/scripts/lib/agent-route-policy.mjs +143 -62
  53. package/scripts/lib/cli-claude.mjs +0 -14
  54. package/scripts/lib/env-probe.mjs +2 -131
  55. package/scripts/lib/gemini-profiles.mjs +2 -69
  56. package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
  57. package/scripts/lib/machine-profile.mjs +3 -17
  58. package/scripts/lib/mcp-filter.mjs +109 -53
  59. package/scripts/lib/mcp-guard-engine.mjs +40 -98
  60. package/scripts/lib/mcp-health.mjs +2 -2
  61. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  62. package/scripts/lib/psmux-info.mjs +11 -59
  63. package/scripts/lib/skill-template.mjs +0 -245
  64. package/hub/hub-lifecycle.mjs +0 -248
  65. package/hub/pipe.mjs +0 -825
  66. package/hub/promote-penalties.mjs +0 -138
  67. package/hub/public/dashboard.html +0 -416
  68. package/hub/schema.sql +0 -209
  69. package/hub/server.mjs +0 -3048
  70. package/hub/store-adapter.mjs +0 -182
  71. package/hub/store.mjs +0 -1736
  72. package/hub/team/build-worker-prompt.mjs +0 -92
  73. package/hub/team/check-mcp-hub.mjs +0 -49
  74. package/hub/team/claude-native-bridge.mjs +0 -987
  75. package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
  76. package/hub/team/cli/commands/start/start-wt.mjs +0 -86
  77. package/hub/team/cli/services/hub-client.mjs +0 -264
  78. package/hub/team/cli/services/native-control.mjs +0 -145
  79. package/hub/team/codex-review.mjs +0 -520
  80. package/hub/team/conductor-mesh-bridge.mjs +0 -122
  81. package/hub/team/conductor-registry.mjs +0 -121
  82. package/hub/team/conductor.mjs +0 -1529
  83. package/hub/team/consensus-meta.mjs +0 -176
  84. package/hub/team/cto-auto-collect.mjs +0 -115
  85. package/hub/team/cto-pull.mjs +0 -31
  86. package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
  87. package/hub/team/dashboard.mjs +0 -322
  88. package/hub/team/event-log.mjs +0 -84
  89. package/hub/team/execution-mode.mjs +0 -324
  90. package/hub/team/extract-completion-payload.mjs +0 -110
  91. package/hub/team/headless-bridge-session.mjs +0 -17
  92. package/hub/team/health-probe.mjs +0 -435
  93. package/hub/team/interactive-native-launcher.mjs +0 -119
  94. package/hub/team/interactive-native-worker.mjs +0 -80
  95. package/hub/team/interactive-tui-transport.mjs +0 -479
  96. package/hub/team/launcher-template.mjs +0 -144
  97. package/hub/team/lead-control.mjs +0 -191
  98. package/hub/team/mcp-selector.mjs +0 -145
  99. package/hub/team/native-supervisor.mjs +0 -460
  100. package/hub/team/native.mjs +0 -727
  101. package/hub/team/recovery-store.mjs +0 -149
  102. package/hub/team/remote-probe.mjs +0 -292
  103. package/hub/team/remote-watcher.mjs +0 -506
  104. package/hub/team/runtime-strategy.mjs +0 -200
  105. package/hub/team/schemas/worker-completion.json +0 -39
  106. package/hub/team/sentinel-capture.mjs +0 -127
  107. package/hub/team/session-sync.mjs +0 -316
  108. package/hub/team/swarm-cli.mjs +0 -390
  109. package/hub/team/swarm-hypervisor.mjs +0 -2206
  110. package/hub/team/swarm-intent.mjs +0 -216
  111. package/hub/team/swarm-locks.mjs +0 -335
  112. package/hub/team/swarm-planner.mjs +0 -371
  113. package/hub/team/swarm-preflight.mjs +0 -366
  114. package/hub/team/swarm-reconciler.mjs +0 -242
  115. package/hub/team/synapse-cli.mjs +0 -458
  116. package/hub/team/synapse-http.mjs +0 -311
  117. package/hub/team/synapse-registry.mjs +0 -618
  118. package/hub/team/tui-remote-adapter.mjs +0 -377
  119. package/hub/team/tui-synapse.mjs +0 -223
  120. package/hub/team/worker-completion-validator.mjs +0 -79
  121. package/hub/team/worker-sandbox.mjs +0 -125
  122. package/hub/team/worktree-lifecycle.mjs +0 -639
  123. package/hub/team/wt-templates.json +0 -43
  124. package/hub/tools.mjs +0 -900
  125. package/hub/workers/antigravity-route-worker.mjs +0 -179
  126. package/hub/workers/codex-app-server-worker.mjs +0 -1067
  127. package/hub/workers/delegator-mcp.mjs +0 -1098
  128. package/hub/workers/lib/jsonrpc-stdio.mjs +0 -204
  129. package/scripts/lib/claudemd-scanner.mjs +0 -223
  130. package/scripts/lib/context.mjs +0 -67
  131. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  132. package/scripts/lib/handoff.mjs +0 -187
  133. package/scripts/lib/logger.mjs +0 -122
  134. package/scripts/lib/stealth-fetch.mjs +0 -176
@@ -1,371 +0,0 @@
1
- // hub/team/swarm-planner.mjs — PRD → Swarm execution plan generator
2
- // Parses a PRD markdown document into shards (units of work), each with:
3
- // - file-lease-map: files the shard is allowed to modify
4
- // - MCP manifest: MCP servers the shard needs
5
- // - mergeOrder: topological order for integrating results
6
- //
7
- // PRD format expected:
8
- // ## Shard: <name>
9
- // - agent: codex|gemini|claude
10
- // - files: path/a.mjs, path/b.mjs
11
- // - mcp: server1, server2
12
- // - depends: shard-name-1, shard-name-2
13
- // - critical: true|false
14
- // - redundancy: false|fallback|true|same-cli
15
- // - prompt: |
16
- // multi-line prompt text
17
-
18
- import { readFileSync } from "node:fs";
19
- import { selectHostForCapability } from "@triflux/core/hub/lib/ssh-command.mjs";
20
-
21
- /** Shard schema defaults */
22
- const SHARD_DEFAULTS = Object.freeze({
23
- agent: "codex",
24
- files: [],
25
- mcp: [],
26
- depends: [],
27
- critical: false,
28
- redundancy: false,
29
- prompt: "",
30
- host: "",
31
- });
32
-
33
- /**
34
- * Parse a PRD markdown into shard definitions.
35
- * @param {string} content — PRD markdown content
36
- * @returns {Shard[]}
37
- */
38
- export function parseShards(content) {
39
- const lines = content.split(/\r?\n/);
40
- const shards = [];
41
- let current = null;
42
- let inPrompt = false;
43
- let promptLines = [];
44
-
45
- function flushPrompt() {
46
- if (current && promptLines.length > 0) {
47
- current.prompt = promptLines.join("\n").trim();
48
- promptLines = [];
49
- }
50
- inPrompt = false;
51
- }
52
-
53
- function flushShard() {
54
- flushPrompt();
55
- if (current) {
56
- shards.push({ ...SHARD_DEFAULTS, ...current });
57
- current = null;
58
- }
59
- }
60
-
61
- for (const line of lines) {
62
- // New shard header: ## Shard: <name>
63
- const shardMatch = line.match(/^##\s+Shard:\s*(.+)$/i);
64
- if (shardMatch) {
65
- flushShard();
66
- current = { name: shardMatch[1].trim() };
67
- continue;
68
- }
69
-
70
- // Non-shard heading ends current shard (e.g. ## Notes)
71
- if (/^##\s+/.test(line) && !line.match(/^##\s+Shard:/i)) {
72
- flushShard();
73
- continue;
74
- }
75
-
76
- if (!current) continue;
77
-
78
- // Prompt block continuation
79
- if (inPrompt) {
80
- if (/^- \w+:/i.test(line)) {
81
- flushPrompt();
82
- // fall through to field parsing
83
- } else {
84
- promptLines.push(line);
85
- continue;
86
- }
87
- }
88
-
89
- // Field parsing: - key: value
90
- const fieldMatch = line.match(/^-\s+(\w+):\s*(.*)$/i);
91
- if (!fieldMatch) continue;
92
-
93
- const [, key, rawValue] = fieldMatch;
94
- const value = rawValue.trim();
95
-
96
- switch (key.toLowerCase()) {
97
- case "agent":
98
- current.agent = value.toLowerCase();
99
- break;
100
- case "files":
101
- current.files = value
102
- .split(/,\s*/)
103
- .map((f) => f.trim())
104
- .filter(Boolean);
105
- break;
106
- case "mcp":
107
- current.mcp = value
108
- .split(/,\s*/)
109
- .map((s) => s.trim())
110
- .filter(Boolean);
111
- break;
112
- case "depends":
113
- current.depends = value
114
- .split(/,\s*/)
115
- .map((d) => d.trim())
116
- .filter(Boolean)
117
- .filter(
118
- (d) => !["none", "-", "—", "n/a", "없음"].includes(d.toLowerCase()),
119
- );
120
- break;
121
- case "critical":
122
- current.critical = /^(true|yes|1)$/i.test(value);
123
- break;
124
- case "redundancy":
125
- if (/^(true|yes|1|fallback)$/i.test(value)) {
126
- current.redundancy = "fallback";
127
- } else if (/^(same-cli|same_cli|same|primary)$/i.test(value)) {
128
- current.redundancy = "same-cli";
129
- } else {
130
- current.redundancy = false;
131
- }
132
- break;
133
- case "host":
134
- current.host = value;
135
- break;
136
- case "prompt":
137
- if (value && !value.startsWith("|")) {
138
- current.prompt = value;
139
- } else {
140
- inPrompt = true;
141
- promptLines = [];
142
- }
143
- break;
144
- default:
145
- // store unknown fields as-is
146
- current[key] = value;
147
- }
148
- }
149
-
150
- flushShard();
151
- return shards;
152
- }
153
-
154
- /**
155
- * Build file-lease-map from shards.
156
- * Maps each shard name to its allowed files.
157
- * Detects conflicting file assignments across shards.
158
- * @param {Shard[]} shards
159
- * @returns {{ leaseMap: Map<string, string[]>, conflicts: Array<{ file: string, shards: string[] }> }}
160
- */
161
- export function buildFileLeaseMap(shards) {
162
- const leaseMap = new Map();
163
- const fileOwners = new Map(); // file → [shard names]
164
-
165
- for (const shard of shards) {
166
- leaseMap.set(shard.name, [...shard.files]);
167
- for (const file of shard.files) {
168
- const owners = fileOwners.get(file) || [];
169
- owners.push(shard.name);
170
- fileOwners.set(file, owners);
171
- }
172
- }
173
-
174
- const conflicts = [];
175
- for (const [file, owners] of fileOwners) {
176
- if (owners.length > 1) {
177
- conflicts.push({ file, shards: owners });
178
- }
179
- }
180
-
181
- return { leaseMap, conflicts };
182
- }
183
-
184
- /**
185
- * Build MCP manifest from shards.
186
- * Maps each shard name to its required MCP servers.
187
- * @param {Shard[]} shards
188
- * @returns {Map<string, string[]>}
189
- */
190
- export function buildMcpManifest(shards) {
191
- const manifest = new Map();
192
- for (const shard of shards) {
193
- manifest.set(shard.name, [...shard.mcp]);
194
- }
195
- return manifest;
196
- }
197
-
198
- /**
199
- * Compute topological merge order based on shard dependencies.
200
- * @param {Shard[]} shards
201
- * @returns {{ order: string[], cycles: string[][] }}
202
- */
203
- export function computeMergeOrder(shards) {
204
- const nameSet = new Set(shards.map((s) => s.name));
205
- const adj = new Map(); // name → [dependents]
206
- const inDeg = new Map(); // name → number
207
-
208
- for (const shard of shards) {
209
- adj.set(shard.name, []);
210
- inDeg.set(shard.name, 0);
211
- }
212
-
213
- for (const shard of shards) {
214
- for (const dep of shard.depends) {
215
- if (!nameSet.has(dep)) continue; // ignore unknown deps
216
- adj.get(dep).push(shard.name);
217
- inDeg.set(shard.name, inDeg.get(shard.name) + 1);
218
- }
219
- }
220
-
221
- // Kahn's algorithm
222
- const queue = [];
223
- for (const [name, deg] of inDeg) {
224
- if (deg === 0) queue.push(name);
225
- }
226
-
227
- const order = [];
228
- while (queue.length > 0) {
229
- // stable sort: alphabetical among same-level nodes
230
- queue.sort();
231
- const node = queue.shift();
232
- order.push(node);
233
-
234
- for (const next of adj.get(node)) {
235
- const newDeg = inDeg.get(next) - 1;
236
- inDeg.set(next, newDeg);
237
- if (newDeg === 0) queue.push(next);
238
- }
239
- }
240
-
241
- // Detect cycles (nodes not in order)
242
- const cycles = [];
243
- if (order.length < shards.length) {
244
- const remaining = shards
245
- .filter((s) => !order.includes(s.name))
246
- .map((s) => s.name);
247
- cycles.push(remaining);
248
- }
249
-
250
- return { order, cycles };
251
- }
252
-
253
- /**
254
- * Full planning pipeline: parse PRD → build plan.
255
- * @param {string} prdPath — path to PRD markdown file
256
- * @param {object} [opts]
257
- * @param {string} [opts.content] — PRD content (if provided, prdPath is ignored)
258
- * @returns {SwarmPlan}
259
- */
260
- export function planSwarm(prdPath, opts = {}) {
261
- const content = opts.content || readFileSync(prdPath, "utf8");
262
- const shards = parseShards(content);
263
-
264
- if (shards.length === 0) {
265
- throw new Error(
266
- 'No shards found in PRD. Expected "## Shard: <name>" sections.',
267
- );
268
- }
269
-
270
- const emptyPromptShards = shards.filter(
271
- (s) => !s.prompt || s.prompt.trim() === "",
272
- );
273
- if (emptyPromptShards.length > 0) {
274
- const names = emptyPromptShards.map((s) => s.name).join(", ");
275
- throw new Error(
276
- `Shard(s) with empty prompt: ${names}. ` +
277
- `Each shard must include a non-empty "- prompt: |" block. ` +
278
- `See docs/prd/_template.md for PRD format.`,
279
- );
280
- }
281
-
282
- const { leaseMap, conflicts } = buildFileLeaseMap(shards);
283
- const mcpManifest = buildMcpManifest(shards);
284
- const { order: mergeOrder, cycles } = computeMergeOrder(shards);
285
-
286
- if (cycles.length > 0) {
287
- throw new Error(`Dependency cycle detected: ${cycles[0].join(" → ")}`);
288
- }
289
-
290
- // Auto-remote suggestion: PRD에 host 미지정 shard가 있고,
291
- // hosts.json에 가용 원격 호스트가 있으면 제안 데이터를 생성한다.
292
- const remoteSuggestion = buildRemoteSuggestion(shards, opts.repoRoot);
293
-
294
- return Object.freeze({
295
- shards: Object.freeze(shards.map((s) => Object.freeze({ ...s }))),
296
- leaseMap,
297
- mcpManifest,
298
- mergeOrder,
299
- conflicts,
300
- criticalShards: shards.filter((s) => s.critical).map((s) => s.name),
301
- remoteSuggestion,
302
- });
303
- }
304
-
305
- /**
306
- * PRD shard에 host가 없고 원격 호스트가 가용하면 분배 제안을 생성한다.
307
- * 실제 AskUserQuestion 호출은 스킬(tfx-swarm)에서 수행. 여기는 데이터만.
308
- * @param {Shard[]} shards
309
- * @param {string} [repoRoot]
310
- * @returns {object|null} 제안 데이터 또는 null (제안 없음)
311
- */
312
- function buildRemoteSuggestion(shards, repoRoot) {
313
- const localShards = shards.filter((s) => !s.host);
314
- if (localShards.length === 0) return null; // 모든 shard에 host 지정됨
315
-
316
- // 각 shard의 agent에 대해 가용 원격 호스트 조회
317
- const agentTypes = [...new Set(localShards.map((s) => s.agent))];
318
- const availableHosts = [];
319
-
320
- for (const agent of agentTypes) {
321
- try {
322
- const hosts = selectHostForCapability(agent, repoRoot);
323
- for (const h of hosts) {
324
- if (!availableHosts.find((ah) => ah.name === h.name)) {
325
- availableHosts.push(h);
326
- }
327
- }
328
- } catch {
329
- // hosts.json 없거나 파싱 실패 → 무시
330
- }
331
- }
332
-
333
- if (availableHosts.length === 0) return null;
334
-
335
- // 분배 제안: 로컬 shard 중 절반(내림)을 원격에 배치
336
- const remoteCount = Math.min(
337
- Math.floor(localShards.length / 2),
338
- availableHosts.length,
339
- );
340
- if (remoteCount === 0) return null;
341
-
342
- // 의존성 없는 shard를 우선 원격 후보로 선택
343
- const candidates = localShards
344
- .filter((s) => s.depends.length === 0)
345
- .concat(localShards.filter((s) => s.depends.length > 0));
346
-
347
- const suggested = [];
348
- for (let i = 0; i < remoteCount && i < candidates.length; i++) {
349
- const shard = candidates[i];
350
- const host = availableHosts[i % availableHosts.length];
351
- suggested.push({
352
- shardName: shard.name,
353
- host: host.name,
354
- hostDescription: host.config.description,
355
- specs: host.specs,
356
- });
357
- }
358
-
359
- return Object.freeze({
360
- localCount: localShards.length - remoteCount,
361
- remoteCount,
362
- totalShards: shards.length,
363
- availableHosts: availableHosts.map((h) => ({
364
- name: h.name,
365
- description: h.config.description,
366
- specs: h.specs,
367
- capabilities: h.config.capabilities,
368
- })),
369
- suggested: Object.freeze(suggested),
370
- });
371
- }