triflux 10.3.4 → 10.7.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.
- package/LICENSE +21 -21
- package/bin/tfx-doctor-tui.mjs +1 -1
- package/bin/tfx-doctor.mjs +6 -1
- package/bin/tfx-profile.mjs +1 -1
- package/bin/tfx-setup-tui.mjs +1 -1
- package/bin/tfx-setup.mjs +6 -1
- package/bin/triflux.mjs +2396 -1140
- package/hooks/agent-route-guard.mjs +12 -8
- package/hooks/cross-review-tracker.mjs +21 -8
- package/hooks/error-context.mjs +19 -7
- package/hooks/hook-adaptive-collector.mjs +18 -16
- package/hooks/hook-manager.mjs +93 -32
- package/hooks/hook-orchestrator.mjs +108 -24
- package/hooks/hook-registry.json +11 -0
- package/hooks/keyword-rules.json +6 -10
- package/hooks/lib/resolve-root.mjs +1 -1
- package/hooks/mcp-config-watcher.mjs +6 -2
- package/hooks/pipeline-stop.mjs +3 -6
- package/hooks/safety-guard.mjs +99 -28
- package/hooks/session-start-fast.mjs +143 -0
- package/hooks/subagent-verifier.mjs +5 -4
- package/hub/account-broker.mjs +256 -60
- package/hub/adaptive-diagnostic.mjs +75 -48
- package/hub/adaptive-inject.mjs +95 -57
- package/hub/adaptive-memory.mjs +156 -42
- package/hub/adaptive.mjs +60 -31
- package/hub/assign-callbacks.mjs +67 -30
- package/hub/bridge.mjs +0 -1
- package/hub/cli-adapter-base.mjs +200 -48
- package/hub/codex-adapter.mjs +76 -96
- package/hub/codex-compat.mjs +3 -3
- package/hub/codex-preflight.mjs +63 -37
- package/hub/delegator/contracts.mjs +19 -23
- package/hub/delegator/index.mjs +3 -3
- package/hub/delegator/service.mjs +88 -64
- package/hub/delegator/tool-definitions.mjs +5 -5
- package/hub/fullcycle.mjs +33 -17
- package/hub/gemini-adapter.mjs +69 -94
- package/hub/hitl.mjs +89 -30
- package/hub/intent.mjs +161 -38
- package/hub/lib/cache-guard.mjs +43 -17
- package/hub/lib/mcp-response-cache.mjs +66 -32
- package/hub/lib/memory-store.mjs +285 -111
- package/hub/lib/path-utils.mjs +35 -37
- package/hub/lib/process-utils.mjs +106 -37
- package/hub/lib/spawn-trace.mjs +527 -0
- package/hub/lib/ssh-command.mjs +34 -4
- package/hub/lib/ssh-retry.mjs +5 -1
- package/hub/lib/uuidv7.mjs +4 -3
- package/hub/memory-doctor.mjs +266 -106
- package/hub/middleware/request-logger.mjs +61 -34
- package/hub/paths.mjs +9 -9
- package/hub/pipeline/gates/confidence.mjs +34 -15
- package/hub/pipeline/gates/consensus.mjs +27 -15
- package/hub/pipeline/gates/index.mjs +7 -3
- package/hub/pipeline/gates/selfcheck.mjs +57 -19
- package/hub/pipeline/index.mjs +77 -42
- package/hub/pipeline/state.mjs +10 -10
- package/hub/pipeline/transitions.mjs +40 -23
- package/hub/platform.mjs +57 -48
- package/hub/promote-penalties.mjs +25 -7
- package/hub/quality/deslop.mjs +70 -49
- package/hub/research.mjs +32 -25
- package/hub/router.mjs +240 -107
- package/hub/routing/complexity.mjs +132 -29
- package/hub/routing/index.mjs +17 -12
- package/hub/routing/q-learning.mjs +76 -28
- package/hub/server.mjs +4 -4
- package/hub/session-fingerprint.mjs +126 -60
- package/hub/state.mjs +84 -43
- package/hub/store-adapter.mjs +59 -26
- package/hub/store.mjs +356 -153
- package/hub/team/agent-map.json +22 -7
- package/hub/team/ansi.mjs +186 -122
- package/hub/team/backend.mjs +28 -10
- package/hub/team/cli/commands/attach.mjs +29 -9
- package/hub/team/cli/commands/control.mjs +29 -8
- package/hub/team/cli/commands/debug.mjs +32 -11
- package/hub/team/cli/commands/focus.mjs +38 -11
- package/hub/team/cli/commands/interrupt.mjs +18 -6
- package/hub/team/cli/commands/kill.mjs +16 -5
- package/hub/team/cli/commands/list.mjs +11 -4
- package/hub/team/cli/commands/send.mjs +19 -6
- package/hub/team/cli/commands/start/index.mjs +154 -31
- package/hub/team/cli/commands/start/parse-args.mjs +38 -11
- package/hub/team/cli/commands/start/start-headless.mjs +112 -36
- package/hub/team/cli/commands/start/start-in-process.mjs +12 -2
- package/hub/team/cli/commands/start/start-mux.mjs +70 -21
- package/hub/team/cli/commands/start/start-wt.mjs +29 -12
- package/hub/team/cli/commands/status.mjs +43 -14
- package/hub/team/cli/commands/stop.mjs +11 -4
- package/hub/team/cli/commands/task.mjs +8 -3
- package/hub/team/cli/commands/tasks.mjs +1 -1
- package/hub/team/cli/index.mjs +2 -2
- package/hub/team/cli/manifest.mjs +38 -8
- package/hub/team/cli/render.mjs +30 -8
- package/hub/team/cli/services/attach-fallback.mjs +31 -11
- package/hub/team/cli/services/hub-client.mjs +42 -14
- package/hub/team/cli/services/member-selector.mjs +11 -4
- package/hub/team/cli/services/native-control.mjs +48 -21
- package/hub/team/cli/services/runtime-mode.mjs +2 -1
- package/hub/team/cli/services/state-store.mjs +25 -8
- package/hub/team/cli/services/task-model.mjs +16 -6
- package/hub/team/conductor-mesh-bridge.mjs +24 -23
- package/hub/team/conductor.mjs +8 -4
- package/hub/team/dashboard-anchor.mjs +4 -5
- package/hub/team/dashboard-layout.mjs +3 -1
- package/hub/team/dashboard-open.mjs +41 -21
- package/hub/team/dashboard.mjs +76 -28
- package/hub/team/event-log.mjs +18 -10
- package/hub/team/handoff.mjs +31 -15
- package/hub/team/headless.mjs +2 -1
- package/hub/team/health-probe.mjs +69 -54
- package/hub/team/launcher-template.mjs +16 -13
- package/hub/team/native-supervisor.mjs +65 -21
- package/hub/team/native.mjs +74 -35
- package/hub/team/nativeProxy.mjs +184 -113
- package/hub/team/notify.mjs +119 -76
- package/hub/team/orchestrator.mjs +9 -4
- package/hub/team/pane.mjs +12 -7
- package/hub/team/process-cleanup.mjs +25 -16
- package/hub/team/psmux.mjs +491 -201
- package/hub/team/remote-probe.mjs +68 -52
- package/hub/team/remote-session.mjs +117 -59
- package/hub/team/remote-watcher.mjs +61 -33
- package/hub/team/routing.mjs +51 -25
- package/hub/team/runtime-strategy.mjs +3 -1
- package/hub/team/session.mjs +98 -34
- package/hub/team/staleState.mjs +72 -30
- package/hub/team/swarm-locks.mjs +15 -13
- package/hub/team/swarm-planner.mjs +32 -21
- package/hub/team/swarm-reconciler.mjs +48 -23
- package/hub/team/tui-lite.mjs +266 -68
- package/hub/team/tui-remote-adapter.mjs +14 -10
- package/hub/team/tui-viewer.mjs +99 -43
- package/hub/team/tui.mjs +708 -271
- package/hub/team/worktree-lifecycle.mjs +152 -58
- package/hub/team/wt-manager.mjs +24 -14
- package/hub/token-mode.mjs +71 -71
- package/hub/tray.mjs +66 -23
- package/hub/workers/claude-worker.mjs +162 -118
- package/hub/workers/codex-mcp.mjs +192 -141
- package/hub/workers/delegator-mcp.mjs +507 -333
- package/hub/workers/factory.mjs +8 -8
- package/hub/workers/gemini-worker.mjs +115 -84
- package/hub/workers/interface.mjs +6 -1
- package/hub/workers/worker-utils.mjs +21 -14
- package/hud/colors.mjs +27 -9
- package/hud/constants.mjs +162 -26
- package/hud/context-monitor.mjs +82 -41
- package/hud/hud-qos-status.mjs +129 -49
- package/hud/mission-board.mjs +6 -3
- package/hud/providers/claude.mjs +226 -115
- package/hud/providers/codex.mjs +62 -22
- package/hud/providers/gemini.mjs +168 -56
- package/hud/renderers.mjs +384 -119
- package/hud/terminal.mjs +101 -31
- package/hud/utils.mjs +78 -38
- package/mesh/index.mjs +11 -5
- package/mesh/mesh-budget.mjs +18 -9
- package/mesh/mesh-heartbeat.mjs +1 -1
- package/mesh/mesh-queue.mjs +3 -5
- package/mesh/mesh-router.mjs +5 -4
- package/package.json +2 -1
- package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
- package/scripts/__tests__/keyword-detector.test.mjs +77 -28
- package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
- package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
- package/scripts/__tests__/remote-spawn.test.mjs +10 -4
- package/scripts/__tests__/session-start-fast.test.mjs +36 -0
- package/scripts/__tests__/skill-template.test.mjs +98 -50
- package/scripts/__tests__/smoke.test.mjs +1 -1
- package/scripts/__tests__/spawn-trace.test.mjs +102 -0
- package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
- package/scripts/cache-doctor.mjs +11 -4
- package/scripts/cache-warmup.mjs +96 -37
- package/scripts/claudemd-sync.mjs +27 -17
- package/scripts/codex-gateway-preflight.mjs +52 -37
- package/scripts/codex-mcp-gateway-sync.mjs +59 -39
- package/scripts/completions/tfx.bash +47 -47
- package/scripts/completions/tfx.fish +44 -44
- package/scripts/completions/tfx.zsh +83 -83
- package/scripts/config-audit.mjs +232 -0
- package/scripts/convert-to-tmpl.mjs +54 -0
- package/scripts/cross-review-gate.mjs +35 -12
- package/scripts/cross-review-tracker.mjs +21 -8
- package/scripts/demo.mjs +35 -17
- package/scripts/doctor-diagnose.mjs +284 -0
- package/scripts/gen-skill-docs.mjs +7 -2
- package/scripts/gen-skill-manifest.mjs +2 -1
- package/scripts/headless-guard.mjs +86 -48
- package/scripts/hub-ensure.mjs +45 -26
- package/scripts/keyword-detector.mjs +41 -20
- package/scripts/keyword-rules-expander.mjs +47 -30
- package/scripts/lib/claudemd-scanner.mjs +6 -1
- package/scripts/lib/context.mjs +3 -3
- package/scripts/lib/cross-review-utils.mjs +6 -3
- package/scripts/lib/env-probe.mjs +47 -28
- package/scripts/lib/gemini-profiles.mjs +44 -10
- package/scripts/lib/handoff.mjs +33 -17
- package/scripts/lib/hook-utils.mjs +8 -6
- package/scripts/lib/keyword-rules.mjs +43 -19
- package/scripts/lib/logger.mjs +24 -24
- package/scripts/lib/mcp-filter.mjs +377 -239
- package/scripts/lib/mcp-guard-engine.mjs +194 -79
- package/scripts/lib/mcp-manifest.mjs +23 -13
- package/scripts/lib/mcp-server-catalog.mjs +300 -63
- package/scripts/lib/psmux-info.mjs +11 -6
- package/scripts/lib/remote-spawn-transfer.mjs +44 -14
- package/scripts/lib/skill-template.mjs +30 -7
- package/scripts/mcp-check.mjs +58 -39
- package/scripts/mcp-gateway-config.mjs +83 -39
- package/scripts/mcp-gateway-ensure.mjs +43 -35
- package/scripts/mcp-gateway-integration-test.mjs +70 -58
- package/scripts/mcp-gateway-start.mjs +126 -60
- package/scripts/mcp-gateway-verify.mjs +24 -22
- package/scripts/mcp-safety-guard.mjs +44 -11
- package/scripts/notion-read.mjs +199 -84
- package/scripts/pack.mjs +94 -89
- package/scripts/preflight-cache.mjs +27 -10
- package/scripts/preinstall.mjs +42 -13
- package/scripts/remote-spawn.mjs +309 -94
- package/scripts/run.cjs +8 -5
- package/scripts/session-spawn-helper.mjs +130 -39
- package/scripts/session-stale-cleanup.mjs +123 -0
- package/scripts/setup.mjs +941 -492
- package/scripts/test-lock.mjs +20 -7
- package/scripts/test-tfx-route-no-claude-native.mjs +16 -12
- package/scripts/tfx-batch-stats.mjs +32 -11
- package/scripts/tfx-gate-activate.mjs +11 -4
- package/scripts/tfx-route-post.mjs +87 -20
- package/scripts/tfx-route-worker.mjs +57 -51
- package/scripts/tfx-route.sh +41 -124
- package/scripts/tmp-cleanup.mjs +21 -7
- package/scripts/token-snapshot.mjs +204 -85
- package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +1 -0
- package/skills/.omc/state/idle-notif-cooldown.json +3 -0
- package/skills/.omc/state/last-tool-error.json +7 -0
- package/skills/.omc/state/subagent-tracking.json +7 -0
- package/skills/_templates/base.md +1 -6
- package/skills/merge-worktree/SKILL.md.tmpl +144 -0
- package/skills/shared/telemetry-segment.md +6 -0
- package/skills/star-prompt/SKILL.md.tmpl +222 -0
- package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
- package/skills/tfx-analysis/skill.json +1 -6
- package/skills/tfx-auto/SKILL.md +1 -0
- package/skills/tfx-auto-codex/SKILL.md.tmpl +106 -0
- package/skills/tfx-auto-codex/skill.json +1 -3
- package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
- package/skills/tfx-autopilot/skill.json +1 -5
- package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
- package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
- package/skills/tfx-autoroute/skill.json +1 -7
- package/skills/tfx-codex/SKILL.md +1 -0
- package/skills/tfx-codex/skill.json +1 -3
- package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
- package/skills/tfx-codex-swarm/evals/evals.json +1 -1
- package/skills/tfx-codex-swarm/skill.json +1 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
- package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
- package/skills/tfx-debate/SKILL.md.tmpl +192 -0
- package/skills/tfx-debate/skill.json +1 -7
- package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
- package/skills/tfx-deep-analysis/skill.json +1 -5
- package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
- package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
- package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
- package/skills/tfx-deep-qa/skill.json +1 -6
- package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
- package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
- package/skills/tfx-doctor/SKILL.md +21 -0
- package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
- package/skills/tfx-doctor/skill.json +1 -3
- package/skills/tfx-find/SKILL.md +1 -0
- package/skills/tfx-forge/SKILL.md.tmpl +187 -0
- package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
- package/skills/tfx-fullcycle/skill.json +1 -6
- package/skills/tfx-gemini/SKILL.md.tmpl +91 -0
- package/skills/tfx-gemini/skill.json +1 -3
- package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
- package/skills/tfx-hooks/skill.json +1 -3
- package/skills/tfx-hub/SKILL.md.tmpl +212 -0
- package/skills/tfx-hub/skill.json +1 -3
- package/skills/tfx-index/SKILL.md +1 -0
- package/skills/tfx-index/skill.json +1 -6
- package/skills/tfx-interview/SKILL.md.tmpl +285 -0
- package/skills/tfx-multi/SKILL.md.tmpl +183 -0
- package/skills/tfx-multi/skill.json +1 -3
- package/skills/tfx-panel/SKILL.md.tmpl +189 -0
- package/skills/tfx-panel/skill.json +1 -7
- package/skills/tfx-persist/SKILL.md.tmpl +270 -0
- package/skills/tfx-persist/skill.json +1 -7
- package/skills/tfx-plan/SKILL.md +1 -0
- package/skills/tfx-plan/skill.json +1 -6
- package/skills/tfx-profile/SKILL.md.tmpl +239 -0
- package/skills/tfx-profile/skill.json +1 -3
- package/skills/tfx-prune/SKILL.md.tmpl +200 -0
- package/skills/tfx-prune/skill.json +1 -7
- package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
- package/skills/tfx-psmux-rules/skill.json +1 -4
- package/skills/tfx-qa/SKILL.md +1 -0
- package/skills/tfx-qa/skill.json +1 -6
- package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
- package/skills/tfx-ralph/skill.json +1 -4
- package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
- package/skills/tfx-remote-setup/skill.json +1 -3
- package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
- package/skills/tfx-remote-spawn/references/hosts.json +16 -0
- package/skills/tfx-remote-spawn/skill.json +1 -4
- package/skills/tfx-research/SKILL.md +1 -0
- package/skills/tfx-review/SKILL.md +1 -0
- package/skills/tfx-review/skill.json +1 -6
- package/skills/tfx-setup/SKILL.md.tmpl +504 -0
- package/skills/tfx-setup/skill.json +1 -3
- package/skills/tfx-swarm/SKILL.md +22 -0
- package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
- package/tui/codex-profile.mjs +88 -33
- package/tui/core.mjs +45 -15
- package/tui/doctor.mjs +75 -28
- package/tui/gemini-profile.mjs +74 -29
- package/tui/monitor-data.mjs +8 -4
- package/tui/monitor.mjs +71 -27
- package/tui/setup.mjs +133 -42
|
@@ -3,24 +3,29 @@
|
|
|
3
3
|
// Convention: .codex-swarm/wt-{slug} paths, swarm/{runId}/{slug} branches.
|
|
4
4
|
// Remote support: host option → SSH-based git operations via remote-session.mjs.
|
|
5
5
|
|
|
6
|
-
import { execFile } from
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { remoteGit, validateHost } from
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
7
|
+
import { access, mkdir, readdir, rm } from "node:fs/promises";
|
|
8
|
+
import { join, normalize, resolve } from "node:path";
|
|
9
|
+
import { remoteGit, validateHost } from "./remote-session.mjs";
|
|
10
10
|
|
|
11
|
-
const SWARM_ROOT =
|
|
11
|
+
const SWARM_ROOT = ".codex-swarm";
|
|
12
12
|
const SLEEP_MS = 2000; // WT race-guard (MEMORY.md: wt-attach-spacing)
|
|
13
13
|
|
|
14
14
|
function git(args, cwd) {
|
|
15
15
|
return new Promise((res, rej) => {
|
|
16
|
-
execFile(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
execFile(
|
|
17
|
+
"git",
|
|
18
|
+
args,
|
|
19
|
+
{ cwd, windowsHide: true, timeout: 30_000 },
|
|
20
|
+
(err, stdout, stderr) => {
|
|
21
|
+
if (err) {
|
|
22
|
+
const msg = `git ${args[0]} failed: ${stderr?.trim() || err.message}`;
|
|
23
|
+
rej(new Error(msg));
|
|
24
|
+
} else {
|
|
25
|
+
res(stdout.trim());
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
);
|
|
24
29
|
});
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -30,7 +35,7 @@ function sleep(ms) {
|
|
|
30
35
|
|
|
31
36
|
/** Normalize path for Windows compatibility. */
|
|
32
37
|
function normPath(p) {
|
|
33
|
-
return normalize(p).replace(/\\/g,
|
|
38
|
+
return normalize(p).replace(/\\/g, "/");
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
/**
|
|
@@ -45,22 +50,45 @@ function normPath(p) {
|
|
|
45
50
|
* @param {object} [opts.remoteEnv] — remote environment from probeRemoteEnv()
|
|
46
51
|
* @returns {Promise<{ worktreePath: string, branchName: string, remote: boolean }>}
|
|
47
52
|
*/
|
|
48
|
-
export async function ensureWorktree({
|
|
53
|
+
export async function ensureWorktree({
|
|
54
|
+
slug,
|
|
55
|
+
runId,
|
|
56
|
+
rootDir = process.cwd(),
|
|
57
|
+
baseBranch = "main",
|
|
58
|
+
host,
|
|
59
|
+
remoteEnv,
|
|
60
|
+
}) {
|
|
49
61
|
const branchName = `swarm/${runId}/${slug}`;
|
|
50
62
|
|
|
51
63
|
// ── Remote path: SSH-based worktree creation ──
|
|
52
64
|
if (host && remoteEnv) {
|
|
53
|
-
const remoteRoot = rootDir.replace(/\\/g,
|
|
65
|
+
const remoteRoot = rootDir.replace(/\\/g, "/");
|
|
54
66
|
const remoteWtDir = `${remoteRoot}/${SWARM_ROOT}/wt-${slug}`;
|
|
55
67
|
|
|
56
|
-
try {
|
|
68
|
+
try {
|
|
69
|
+
remoteGit(host, remoteEnv, ["worktree", "prune"], remoteRoot);
|
|
70
|
+
} catch {
|
|
71
|
+
/* best-effort */
|
|
72
|
+
}
|
|
57
73
|
|
|
58
74
|
try {
|
|
59
|
-
remoteGit(
|
|
75
|
+
remoteGit(
|
|
76
|
+
host,
|
|
77
|
+
remoteEnv,
|
|
78
|
+
["worktree", "add", remoteWtDir, "-b", branchName, baseBranch],
|
|
79
|
+
remoteRoot,
|
|
80
|
+
);
|
|
60
81
|
} catch {
|
|
61
82
|
try {
|
|
62
|
-
remoteGit(
|
|
63
|
-
|
|
83
|
+
remoteGit(
|
|
84
|
+
host,
|
|
85
|
+
remoteEnv,
|
|
86
|
+
["worktree", "add", remoteWtDir, branchName],
|
|
87
|
+
remoteRoot,
|
|
88
|
+
);
|
|
89
|
+
} catch {
|
|
90
|
+
/* already exists — acceptable */
|
|
91
|
+
}
|
|
64
92
|
}
|
|
65
93
|
|
|
66
94
|
return { worktreePath: remoteWtDir, branchName, remote: true };
|
|
@@ -74,27 +102,36 @@ export async function ensureWorktree({ slug, runId, rootDir = process.cwd(), bas
|
|
|
74
102
|
// Check if worktree already exists
|
|
75
103
|
try {
|
|
76
104
|
await access(wtDir);
|
|
77
|
-
await git([
|
|
105
|
+
await git(["rev-parse", "--is-inside-work-tree"], wtDir);
|
|
78
106
|
return { worktreePath: normPath(wtDir), branchName, remote: false };
|
|
79
107
|
} catch {
|
|
80
108
|
// Doesn't exist or invalid — create fresh
|
|
81
109
|
}
|
|
82
110
|
|
|
83
111
|
try {
|
|
84
|
-
await git([
|
|
85
|
-
} catch {
|
|
112
|
+
await git(["worktree", "prune"], rootDir);
|
|
113
|
+
} catch {
|
|
114
|
+
/* best-effort */
|
|
115
|
+
}
|
|
86
116
|
|
|
87
117
|
await sleep(SLEEP_MS);
|
|
88
118
|
|
|
89
119
|
try {
|
|
90
|
-
await git(
|
|
120
|
+
await git(
|
|
121
|
+
["worktree", "add", wtDir, "-b", branchName, baseBranch],
|
|
122
|
+
rootDir,
|
|
123
|
+
);
|
|
91
124
|
} catch {
|
|
92
|
-
await git([
|
|
125
|
+
await git(["worktree", "add", wtDir, branchName], rootDir);
|
|
93
126
|
}
|
|
94
127
|
|
|
95
128
|
// #34 L2: worktree에 복사된 .claude-plugin 제거 (하네스가 PLUGIN_ROOT를 오인하는 것 방지)
|
|
96
|
-
const pluginDir = join(wtDir,
|
|
97
|
-
try {
|
|
129
|
+
const pluginDir = join(wtDir, ".claude-plugin");
|
|
130
|
+
try {
|
|
131
|
+
await rm(pluginDir, { recursive: true, force: true });
|
|
132
|
+
} catch {
|
|
133
|
+
/* absent → ok */
|
|
134
|
+
}
|
|
98
135
|
|
|
99
136
|
return { worktreePath: normPath(wtDir), branchName, remote: false };
|
|
100
137
|
}
|
|
@@ -108,18 +145,22 @@ export async function ensureWorktree({ slug, runId, rootDir = process.cwd(), bas
|
|
|
108
145
|
* @param {string} [opts.rootDir=process.cwd()]
|
|
109
146
|
* @returns {Promise<{ integrationBranch: string, baseCommit: string }>}
|
|
110
147
|
*/
|
|
111
|
-
export async function prepareIntegrationBranch({
|
|
148
|
+
export async function prepareIntegrationBranch({
|
|
149
|
+
runId,
|
|
150
|
+
baseBranch,
|
|
151
|
+
rootDir = process.cwd(),
|
|
152
|
+
}) {
|
|
112
153
|
const integrationBranch = `swarm/${runId}/merge`;
|
|
113
154
|
|
|
114
155
|
// Record base commit for rollback
|
|
115
|
-
const baseCommit = await git([
|
|
156
|
+
const baseCommit = await git(["rev-parse", baseBranch], rootDir);
|
|
116
157
|
|
|
117
158
|
// Create integration branch from base
|
|
118
159
|
try {
|
|
119
|
-
await git([
|
|
160
|
+
await git(["branch", integrationBranch, baseBranch], rootDir);
|
|
120
161
|
} catch {
|
|
121
162
|
// Branch may already exist — reset to base
|
|
122
|
-
await git([
|
|
163
|
+
await git(["branch", "-f", integrationBranch, baseBranch], rootDir);
|
|
123
164
|
}
|
|
124
165
|
|
|
125
166
|
return { integrationBranch, baseCommit };
|
|
@@ -135,25 +176,41 @@ export async function prepareIntegrationBranch({ runId, baseBranch, rootDir = pr
|
|
|
135
176
|
* @param {string} [opts.rootDir=process.cwd()]
|
|
136
177
|
* @returns {Promise<{ ok: boolean, headCommit?: string, error?: string }>}
|
|
137
178
|
*/
|
|
138
|
-
export async function rebaseShardOntoIntegration({
|
|
179
|
+
export async function rebaseShardOntoIntegration({
|
|
180
|
+
shardBranch,
|
|
181
|
+
integrationBranch,
|
|
182
|
+
rootDir = process.cwd(),
|
|
183
|
+
}) {
|
|
139
184
|
// Backup integration HEAD for rollback
|
|
140
|
-
const backupCommit = await git([
|
|
185
|
+
const backupCommit = await git(["rev-parse", integrationBranch], rootDir);
|
|
141
186
|
|
|
142
187
|
try {
|
|
143
188
|
// Rebase shard onto integration
|
|
144
|
-
await git([
|
|
189
|
+
await git(["rebase", integrationBranch, shardBranch], rootDir);
|
|
145
190
|
|
|
146
191
|
// Fast-forward integration to include shard changes
|
|
147
|
-
await git([
|
|
148
|
-
await git([
|
|
192
|
+
await git(["checkout", integrationBranch], rootDir);
|
|
193
|
+
await git(["merge", "--ff-only", shardBranch], rootDir);
|
|
149
194
|
|
|
150
|
-
const headCommit = await git([
|
|
195
|
+
const headCommit = await git(["rev-parse", "HEAD"], rootDir);
|
|
151
196
|
return { ok: true, headCommit };
|
|
152
197
|
} catch (err) {
|
|
153
198
|
// Abort rebase and restore integration branch
|
|
154
|
-
try {
|
|
155
|
-
|
|
156
|
-
|
|
199
|
+
try {
|
|
200
|
+
await git(["rebase", "--abort"], rootDir);
|
|
201
|
+
} catch {
|
|
202
|
+
/* already clean */
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
await git(["checkout", integrationBranch], rootDir);
|
|
206
|
+
} catch {
|
|
207
|
+
/* best-effort */
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
await git(["reset", "--hard", backupCommit], rootDir);
|
|
211
|
+
} catch {
|
|
212
|
+
/* best-effort */
|
|
213
|
+
}
|
|
157
214
|
|
|
158
215
|
return { ok: false, error: err.message };
|
|
159
216
|
}
|
|
@@ -169,18 +226,30 @@ export async function rebaseShardOntoIntegration({ shardBranch, integrationBranc
|
|
|
169
226
|
* @param {string} [opts.rootDir=process.cwd()]
|
|
170
227
|
* @param {boolean} [opts.force=false]
|
|
171
228
|
*/
|
|
172
|
-
export async function pruneWorktree({
|
|
173
|
-
|
|
229
|
+
export async function pruneWorktree({
|
|
230
|
+
worktreePath,
|
|
231
|
+
branchName,
|
|
232
|
+
rootDir = process.cwd(),
|
|
233
|
+
force = false,
|
|
234
|
+
}) {
|
|
235
|
+
const forceFlag = force ? "--force" : "";
|
|
174
236
|
|
|
175
237
|
// Remove worktree (with retry for Windows file handle issues — E5)
|
|
176
238
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
177
239
|
try {
|
|
178
|
-
await git(
|
|
240
|
+
await git(
|
|
241
|
+
["worktree", "remove", worktreePath, ...(forceFlag ? [forceFlag] : [])],
|
|
242
|
+
rootDir,
|
|
243
|
+
);
|
|
179
244
|
break;
|
|
180
245
|
} catch (_err) {
|
|
181
246
|
if (attempt === 2) {
|
|
182
247
|
// Last resort: rm the directory and prune
|
|
183
|
-
try {
|
|
248
|
+
try {
|
|
249
|
+
await rm(worktreePath, { recursive: true, force: true });
|
|
250
|
+
} catch {
|
|
251
|
+
/* ignore */
|
|
252
|
+
}
|
|
184
253
|
}
|
|
185
254
|
await sleep(SLEEP_MS);
|
|
186
255
|
}
|
|
@@ -188,11 +257,19 @@ export async function pruneWorktree({ worktreePath, branchName, rootDir = proces
|
|
|
188
257
|
|
|
189
258
|
// Prune stale worktree references
|
|
190
259
|
await sleep(SLEEP_MS);
|
|
191
|
-
try {
|
|
260
|
+
try {
|
|
261
|
+
await git(["worktree", "prune"], rootDir);
|
|
262
|
+
} catch {
|
|
263
|
+
/* best-effort */
|
|
264
|
+
}
|
|
192
265
|
|
|
193
266
|
// Delete branch if specified
|
|
194
267
|
if (branchName) {
|
|
195
|
-
try {
|
|
268
|
+
try {
|
|
269
|
+
await git(["branch", "-D", branchName], rootDir);
|
|
270
|
+
} catch {
|
|
271
|
+
/* may not exist */
|
|
272
|
+
}
|
|
196
273
|
}
|
|
197
274
|
}
|
|
198
275
|
|
|
@@ -216,17 +293,18 @@ export async function pruneOrphanWorktrees({ rootDir = process.cwd() } = {}) {
|
|
|
216
293
|
return removed; // .codex-swarm/ doesn't exist → nothing to clean
|
|
217
294
|
}
|
|
218
295
|
|
|
219
|
-
const wtDirs = entries.filter(e => e.startsWith(
|
|
296
|
+
const wtDirs = entries.filter((e) => e.startsWith("wt-"));
|
|
220
297
|
if (wtDirs.length === 0) return removed;
|
|
221
298
|
|
|
222
299
|
// Get registered worktree paths from git
|
|
223
300
|
let registeredPaths;
|
|
224
301
|
try {
|
|
225
|
-
const raw = await git([
|
|
302
|
+
const raw = await git(["worktree", "list", "--porcelain"], rootDir);
|
|
226
303
|
registeredPaths = new Set(
|
|
227
|
-
raw
|
|
228
|
-
.
|
|
229
|
-
.
|
|
304
|
+
raw
|
|
305
|
+
.split("\n")
|
|
306
|
+
.filter((l) => l.startsWith("worktree "))
|
|
307
|
+
.map((l) => normPath(l.slice("worktree ".length))),
|
|
230
308
|
);
|
|
231
309
|
} catch {
|
|
232
310
|
return removed; // git worktree list failed → don't remove anything
|
|
@@ -239,13 +317,19 @@ export async function pruneOrphanWorktrees({ rootDir = process.cwd() } = {}) {
|
|
|
239
317
|
try {
|
|
240
318
|
await rm(fullPath, { recursive: true, force: true });
|
|
241
319
|
removed.push(dir);
|
|
242
|
-
} catch {
|
|
320
|
+
} catch {
|
|
321
|
+
/* best-effort */
|
|
322
|
+
}
|
|
243
323
|
}
|
|
244
324
|
}
|
|
245
325
|
|
|
246
326
|
// Prune stale git references
|
|
247
327
|
if (removed.length > 0) {
|
|
248
|
-
try {
|
|
328
|
+
try {
|
|
329
|
+
await git(["worktree", "prune"], rootDir);
|
|
330
|
+
} catch {
|
|
331
|
+
/* best-effort */
|
|
332
|
+
}
|
|
249
333
|
}
|
|
250
334
|
|
|
251
335
|
return removed;
|
|
@@ -265,24 +349,34 @@ export async function pruneOrphanWorktrees({ rootDir = process.cwd() } = {}) {
|
|
|
265
349
|
* @param {string} [opts.rootDir=process.cwd()] — local repo root
|
|
266
350
|
* @returns {Promise<{ ok: boolean, localRef?: string, error?: string }>}
|
|
267
351
|
*/
|
|
268
|
-
export async function fetchRemoteShard({
|
|
352
|
+
export async function fetchRemoteShard({
|
|
353
|
+
host,
|
|
354
|
+
sshUser,
|
|
355
|
+
remoteRepoPath,
|
|
356
|
+
branchName,
|
|
357
|
+
rootDir = process.cwd(),
|
|
358
|
+
}) {
|
|
269
359
|
validateHost(host);
|
|
270
360
|
|
|
271
361
|
const remoteName = `_swarm-${host}-${Date.now()}`;
|
|
272
362
|
const sshUrl = `ssh://${sshUser}@${host}${remoteRepoPath}`;
|
|
273
363
|
|
|
274
364
|
try {
|
|
275
|
-
await git([
|
|
365
|
+
await git(["remote", "add", remoteName, sshUrl], rootDir);
|
|
276
366
|
|
|
277
|
-
await git([
|
|
367
|
+
await git(["fetch", remoteName, branchName, "--no-tags"], rootDir);
|
|
278
368
|
|
|
279
369
|
const localRef = `${remoteName}/${branchName}`;
|
|
280
|
-
const headCommit = await git([
|
|
370
|
+
const headCommit = await git(["rev-parse", `FETCH_HEAD`], rootDir);
|
|
281
371
|
|
|
282
372
|
return { ok: true, localRef, headCommit };
|
|
283
373
|
} catch (err) {
|
|
284
374
|
return { ok: false, error: err.message };
|
|
285
375
|
} finally {
|
|
286
|
-
try {
|
|
376
|
+
try {
|
|
377
|
+
await git(["remote", "remove", remoteName], rootDir);
|
|
378
|
+
} catch {
|
|
379
|
+
/* cleanup */
|
|
380
|
+
}
|
|
287
381
|
}
|
|
288
382
|
}
|
package/hub/team/wt-manager.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import childProcess from "
|
|
1
|
+
import * as childProcess from "../lib/spawn-trace.mjs";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
3
3
|
import { platform as osPlatform, tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -61,8 +61,8 @@ function buildWrappedCommand(pidFile, command) {
|
|
|
61
61
|
* CreateProcess 이중 쿼팅 문제를 완전히 회피한다.
|
|
62
62
|
*/
|
|
63
63
|
function encodeForPowerShell(script) {
|
|
64
|
-
const buf = Buffer.from(script,
|
|
65
|
-
return buf.toString(
|
|
64
|
+
const buf = Buffer.from(script, "utf16le");
|
|
65
|
+
return buf.toString("base64");
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
function matchesTitlePattern(title, pattern) {
|
|
@@ -316,29 +316,35 @@ export function createWtManager(opts = {}) {
|
|
|
316
316
|
* @param {number} [opts.size] — 퍼센트 (0-100)
|
|
317
317
|
*/
|
|
318
318
|
async function splitPane(opts = {}) {
|
|
319
|
-
const direction = opts.direction ===
|
|
320
|
-
const args = [
|
|
319
|
+
const direction = opts.direction === "H" ? "-H" : "-V";
|
|
320
|
+
const args = ["-w", windowName, "sp", direction];
|
|
321
321
|
|
|
322
322
|
if (opts.title) {
|
|
323
|
-
args.push(
|
|
323
|
+
args.push("--title", String(opts.title));
|
|
324
324
|
}
|
|
325
325
|
if (opts.profile) {
|
|
326
|
-
args.push(
|
|
326
|
+
args.push("--profile", String(opts.profile));
|
|
327
327
|
}
|
|
328
328
|
if (opts.size && Number.isFinite(opts.size)) {
|
|
329
|
-
args.push(
|
|
329
|
+
args.push("-s", String(opts.size / 100));
|
|
330
330
|
}
|
|
331
331
|
if (opts.cwd) {
|
|
332
|
-
args.push(
|
|
332
|
+
args.push("-d", String(opts.cwd));
|
|
333
333
|
}
|
|
334
334
|
if (opts.command) {
|
|
335
335
|
const script = opts.command;
|
|
336
|
-
args.push(
|
|
336
|
+
args.push(
|
|
337
|
+
"--",
|
|
338
|
+
"powershell.exe",
|
|
339
|
+
"-NoExit",
|
|
340
|
+
"-EncodedCommand",
|
|
341
|
+
encodeForPowerShell(script),
|
|
342
|
+
);
|
|
337
343
|
}
|
|
338
344
|
|
|
339
|
-
const child = spawnFn(
|
|
345
|
+
const child = spawnFn("wt.exe", args, {
|
|
340
346
|
detached: true,
|
|
341
|
-
stdio:
|
|
347
|
+
stdio: "ignore",
|
|
342
348
|
});
|
|
343
349
|
child?.unref?.();
|
|
344
350
|
|
|
@@ -355,12 +361,16 @@ export function createWtManager(opts = {}) {
|
|
|
355
361
|
|
|
356
362
|
// 첫 번째는 새 탭으로 생성
|
|
357
363
|
const first = panes[0];
|
|
358
|
-
await createTab({
|
|
364
|
+
await createTab({
|
|
365
|
+
title: first.title,
|
|
366
|
+
command: first.command,
|
|
367
|
+
profile: first.profile,
|
|
368
|
+
});
|
|
359
369
|
|
|
360
370
|
// 나머지는 split-pane으로 분할
|
|
361
371
|
for (let i = 1; i < panes.length; i++) {
|
|
362
372
|
await splitPane({
|
|
363
|
-
direction: panes[i].direction ||
|
|
373
|
+
direction: panes[i].direction || "V",
|
|
364
374
|
title: panes[i].title,
|
|
365
375
|
command: panes[i].command,
|
|
366
376
|
profile: panes[i].profile,
|