triflux 10.44.0 → 10.46.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/README.md +1 -1
- package/adapters/codex/skills/tfx-harness/SKILL.md +45 -9
- package/bin/tfx-live.mjs +1298 -100
- package/bin/triflux.mjs +9 -6
- package/config/routing-policy.json +1 -1
- package/hooks/codex-session-hook.mjs +67 -1
- package/hooks/cto-north-star-brief.mjs +3 -16
- package/hooks/error-context.mjs +3 -6
- package/hooks/hook-manager.mjs +1 -1
- package/hooks/hook-registry.json +0 -11
- package/hooks/keyword-rules.json +8 -4
- package/hooks/permission-safe-allow.mjs +36 -2
- package/hooks/session-start-fast.mjs +50 -1
- package/hooks/session-start-lake.mjs +3 -16
- package/hub/bridge.mjs +111 -5
- package/hub/dynamic-routing-engine.mjs +1 -1
- package/hub/gemini-adapter.mjs +29 -11
- package/hub/lib/memory-store.mjs +66 -30
- package/hub/lib/tfx-route-args.mjs +41 -4
- package/hub/pipe.mjs +10 -15
- package/hub/reflexion.mjs +0 -57
- package/hub/router.mjs +202 -24
- package/hub/schema.sql +1 -0
- package/hub/server.mjs +172 -93
- package/hub/store.mjs +106 -33
- package/hub/team/backend.mjs +4 -2
- package/hub/team/claude-daemon-control.mjs +2 -0
- package/hub/team/cli/commands/start/start-headless.mjs +2 -0
- package/hub/team/cli/commands/start/start-mux.mjs +24 -3
- package/hub/team/cli/services/runtime-mode.mjs +23 -9
- package/hub/team/codex-review.mjs +2 -3
- package/hub/team/conductor.mjs +80 -24
- package/hub/team/cto-auto-collect.mjs +2 -6
- package/hub/team/cto-pull.mjs +4 -0
- package/hub/team/dashboard-open.mjs +1 -0
- package/hub/team/execution-mode.mjs +38 -2
- package/hub/team/headless.mjs +493 -82
- package/hub/team/interactive-tui-transport.mjs +15 -1
- package/hub/team/launcher-template.mjs +19 -2
- package/hub/team/orchestrator.mjs +36 -9
- package/hub/team/pane.mjs +176 -14
- package/hub/team/psmux.mjs +79 -70
- package/hub/team/retry-state-machine.mjs +47 -16
- package/hub/team/session.mjs +57 -0
- package/hub/team/terminal-opener.mjs +68 -13
- package/hub/team/tui-viewer.mjs +65 -14
- package/hub/team/uds-orchestrator.mjs +384 -83
- package/hub/tools.mjs +6 -0
- package/hub/workers/codex-mcp.mjs +35 -6
- package/hud/cli-policy.mjs +69 -0
- package/hud/constants.mjs +20 -17
- package/hud/context-monitor.mjs +31 -21
- package/hud/hud-qos-status.mjs +81 -91
- package/hud/providers/claude.mjs +150 -84
- package/hud/providers/codex.mjs +10 -1
- package/hud/renderers.mjs +21 -59
- package/hud/utils.mjs +1 -15
- package/package.json +1 -1
- package/scripts/__tests__/keyword-detector.test.mjs +89 -1
- package/scripts/__tests__/release-governance.test.mjs +329 -12
- package/scripts/__tests__/release-publish-ancestor.test.mjs +67 -0
- package/scripts/__tests__/release-verify-wait.test.mjs +169 -0
- package/scripts/__tests__/resolve-auto-release.test.mjs +216 -0
- package/scripts/__tests__/skill-surface.test.mjs +6 -4
- package/scripts/__tests__/tfx-route-bash-node-parity.test.mjs +7 -5
- package/scripts/__tests__/tfx-route-node-entry.test.mjs +27 -21
- package/scripts/claude-login-detect.mjs +107 -25
- package/scripts/ensure-agy-hooks.mjs +31 -1
- package/scripts/keyword-detector.mjs +11 -1
- package/scripts/lib/agent-route-policy.mjs +47 -39
- package/scripts/lib/cli-agy.mjs +24 -4
- package/scripts/lib/codex-profile-config.mjs +45 -13
- package/scripts/lib/codex-recovery.sh +19 -0
- package/scripts/lib/gemini-profiles.mjs +113 -29
- package/scripts/lib/keyword-rules.mjs +12 -0
- package/scripts/lib/logger.mjs +60 -43
- package/scripts/lib/machine-profile.mjs +293 -0
- package/scripts/lib/mcp-health.mjs +44 -18
- package/scripts/notion-read.mjs +2 -1
- package/scripts/release/check-packages-mirror.mjs +53 -1
- package/scripts/release/lib.mjs +1 -2
- package/scripts/release/prepare.mjs +24 -9
- package/scripts/release/publish.mjs +16 -1
- package/scripts/release/resolve-auto-release.mjs +136 -0
- package/scripts/release/verify.mjs +74 -25
- package/scripts/remote-spawn.mjs +830 -32
- package/scripts/session-stale-cleanup.mjs +0 -1
- package/scripts/setup.mjs +487 -150
- package/scripts/sync-hub-mcp-settings.mjs +11 -3
- package/scripts/test-lock.mjs +15 -1
- package/scripts/tfx-gate-activate.mjs +4 -4
- package/scripts/tfx-route-post.mjs +90 -13
- package/scripts/tfx-route.sh +520 -141
- package/skills/merge-worktree/SKILL.md +3 -3
- package/skills/star-prompt/skill.json +1 -1
- package/skills/tfx-analysis/SKILL.md +8 -9
- package/skills/tfx-analysis/skill.json +1 -10
- package/skills/tfx-auto/SKILL.md +208 -50
- package/skills/tfx-auto/skill.json +2 -23
- package/skills/tfx-doctor/skill.json +0 -3
- package/skills/tfx-find/skill.json +0 -7
- package/skills/tfx-forge/SKILL.md +2 -2
- package/skills/tfx-forge/skill.json +0 -7
- package/skills/tfx-goal-clarify/skill.json +5 -0
- package/skills/tfx-harness/SKILL.md +26 -3
- package/skills/tfx-harness/skill.json +5 -0
- package/skills/tfx-hooks/SKILL.md +0 -2
- package/skills/tfx-hooks/skill.json +0 -3
- package/skills/tfx-hub/SKILL.md +1 -6
- package/skills/tfx-hub/skill.json +0 -3
- package/skills/tfx-index/skill.json +0 -6
- package/skills/tfx-interview/SKILL.md +0 -2
- package/skills/tfx-live/SKILL.md +131 -5
- package/skills/tfx-live/skill.json +0 -5
- package/skills/tfx-plan/SKILL.md +7 -8
- package/skills/tfx-plan/skill.json +1 -12
- package/skills/tfx-profile/SKILL.md +15 -13
- package/skills/tfx-profile/skill.json +0 -3
- package/skills/tfx-prune/SKILL.md +4 -6
- package/skills/tfx-qa/SKILL.md +7 -7
- package/skills/tfx-qa/skill.json +1 -11
- package/skills/tfx-ralph/SKILL.md +8 -11
- package/skills/tfx-remote/SKILL.md +2 -2
- package/skills/tfx-remote/skill.json +0 -3
- package/skills/tfx-research/SKILL.md +2 -2
- package/skills/tfx-research/skill.json +1 -16
- package/skills/tfx-review/SKILL.md +11 -11
- package/skills/tfx-review/skill.json +1 -11
- package/skills/tfx-setup/SKILL.md +5 -6
- package/skills/tfx-setup/skill.json +0 -3
- package/skills/tfx-ship/SKILL.md +43 -36
- package/skills/tfx-ship/skill.json +1 -9
- package/skills/tfx-wt/skill.json +0 -7
- package/tui/codex-profile.mjs +3 -3
- package/tui/gemini-profile.mjs +11 -24
- package/tui/monitor.mjs +1 -0
- package/tui/setup.mjs +7 -6
- package/scripts/headless-guard-fast.sh +0 -29
- package/scripts/headless-guard.mjs +0 -523
- package/skills/tfx-autopilot/SKILL.md +0 -51
- package/skills/tfx-autopilot/skill.json +0 -12
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +0 -75
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/eval_metadata.json +0 -42
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +0 -39
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/analysis.md +0 -87
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/classification.md +0 -35
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/commands.sh +0 -275
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/routing.md +0 -56
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +0 -39
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/analysis.md +0 -92
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/classification.md +0 -71
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/commands.sh +0 -264
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/routing.md +0 -113
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/eval_metadata.json +0 -32
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +0 -29
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/analysis.md +0 -96
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/classification.md +0 -38
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/commands.sh +0 -151
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/routing.md +0 -51
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +0 -29
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/analysis.md +0 -127
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/classification.md +0 -57
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/commands.sh +0 -129
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/routing.md +0 -84
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/eval_metadata.json +0 -27
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +0 -24
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/analysis.md +0 -98
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/classification.md +0 -65
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/commands.sh +0 -123
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/routing.md +0 -66
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +0 -20
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/analysis.md +0 -88
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/classification.md +0 -40
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/commands.sh +0 -130
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/routing.md +0 -61
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/timing.json +0 -5
- package/skills/tfx-consensus/SKILL.md +0 -56
- package/skills/tfx-consensus/skill.json +0 -8
- package/skills/tfx-debate/SKILL.md +0 -60
- package/skills/tfx-debate/skill.json +0 -14
- package/skills/tfx-fullcycle/SKILL.md +0 -47
- package/skills/tfx-fullcycle/skill.json +0 -13
- package/skills/tfx-multi/SKILL.md +0 -45
- package/skills/tfx-multi/references/agent-wrapper-rules.md +0 -94
- package/skills/tfx-multi/references/thorough-pipeline.md +0 -105
- package/skills/tfx-multi/skill.json +0 -10
- package/skills/tfx-panel/SKILL.md +0 -60
- package/skills/tfx-panel/skill.json +0 -14
- package/skills/tfx-persist/SKILL.md +0 -63
- package/skills/tfx-persist/skill.json +0 -14
- package/skills/tfx-psmux-rules/SKILL.md +0 -41
- package/skills/tfx-psmux-rules/skill.json +0 -10
- package/skills/tfx-remote-setup/SKILL.md +0 -42
- package/skills/tfx-remote-setup/skill.json +0 -10
- package/skills/tfx-remote-spawn/SKILL.md +0 -52
- package/skills/tfx-remote-spawn/skill.json +0 -10
- package/skills/tfx-swarm/SKILL.md +0 -49
- package/skills/tfx-swarm/skill.json +0 -13
package/hub/team/backend.mjs
CHANGED
|
@@ -21,10 +21,12 @@ export function buildAntigravityCommand(
|
|
|
21
21
|
// and `"` reach the shell verbatim (P1: shell injection).
|
|
22
22
|
const promptFile = `${resultFile}.prompt`;
|
|
23
23
|
writeFileSync(promptFile, prompt);
|
|
24
|
+
// agy 1.1.27 부터 --print 는 값(프롬프트)이 필수이고 stdin 프롬프트는 거부된다.
|
|
25
|
+
// 파일 내용을 셸이 재해석하지 않는 형태(따옴표 안 명령 치환 / Get-Content 식)로 값에 넣는다.
|
|
24
26
|
if (isWindows) {
|
|
25
|
-
return `Get-Content -Raw '${promptFile}'
|
|
27
|
+
return `agy --dangerously-skip-permissions --print (Get-Content -Raw '${promptFile}') > '${resultFile}' 2>'${resultFile}.err'`;
|
|
26
28
|
}
|
|
27
|
-
return `agy --
|
|
29
|
+
return `agy --dangerously-skip-permissions --print "$(cat '${promptFile}')" > '${resultFile}' 2>'${resultFile}.err'`;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
const _require = createRequire(import.meta.url);
|
|
@@ -321,10 +321,12 @@ export async function probeClaudeDaemonCandidates({
|
|
|
321
321
|
short,
|
|
322
322
|
sessionId,
|
|
323
323
|
timeoutMs = 6000,
|
|
324
|
+
tmpRoot = "/tmp",
|
|
324
325
|
} = {}) {
|
|
325
326
|
const candidates = await buildClaudeDaemonDiscoveryCandidates({
|
|
326
327
|
configDir,
|
|
327
328
|
env,
|
|
329
|
+
tmpRoot,
|
|
328
330
|
});
|
|
329
331
|
const callerProvenance = detectCallerProvenance(env);
|
|
330
332
|
const targetRequested = Boolean(short || sessionId);
|
|
@@ -88,6 +88,8 @@ export async function startHeadlessTeam({
|
|
|
88
88
|
timeoutSec: timeoutSec || 900,
|
|
89
89
|
layout,
|
|
90
90
|
autoAttach: !!autoAttach,
|
|
91
|
+
leadPane: process.env.TMUX_PANE,
|
|
92
|
+
leadTmux: process.env.TMUX,
|
|
91
93
|
dashboard: !!dashboard,
|
|
92
94
|
dashboardLayout,
|
|
93
95
|
dashboardSize: dashboardSize ?? 0.5,
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
attachSession,
|
|
6
6
|
configureTeammateKeybindings,
|
|
7
7
|
createSession,
|
|
8
|
+
splitAttachToClient,
|
|
8
9
|
} from "../../../session.mjs";
|
|
9
10
|
import { BOLD, DIM, GREEN, RESET } from "../../../shared.mjs";
|
|
10
11
|
import { ok, warn } from "../../render.mjs";
|
|
@@ -62,12 +63,23 @@ export async function startMuxTeam({
|
|
|
62
63
|
|
|
63
64
|
ok("CLI 초기화 대기 (3초)...");
|
|
64
65
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
65
|
-
await orchestrate(sessionId, assignments, {
|
|
66
|
+
const promptInjectionFailures = await orchestrate(sessionId, assignments, {
|
|
66
67
|
hubUrl,
|
|
67
68
|
teammateMode,
|
|
68
69
|
lead: { target: leadTarget, cli: lead, task },
|
|
70
|
+
onInjectionFailure(failure) {
|
|
71
|
+
warn(
|
|
72
|
+
`${failure.cli} ${failure.role} prompt 제출 실패 (${failure.target}): ${failure.message}`,
|
|
73
|
+
);
|
|
74
|
+
},
|
|
69
75
|
});
|
|
70
|
-
|
|
76
|
+
if (promptInjectionFailures.length === 0) {
|
|
77
|
+
ok("리드/워커 프롬프트 주입 완료");
|
|
78
|
+
} else {
|
|
79
|
+
warn(
|
|
80
|
+
`prompt 제출 실패 ${promptInjectionFailures.length}건 — 세션 상태에 기록함`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
71
83
|
|
|
72
84
|
return {
|
|
73
85
|
sessionName: sessionId,
|
|
@@ -78,6 +90,7 @@ export async function startMuxTeam({
|
|
|
78
90
|
teammateMode,
|
|
79
91
|
startedAt: Date.now(),
|
|
80
92
|
hubUrl,
|
|
93
|
+
promptInjectionFailures,
|
|
81
94
|
members,
|
|
82
95
|
panes: Object.fromEntries(
|
|
83
96
|
members.map((member) => [
|
|
@@ -113,7 +126,15 @@ export async function startMuxTeam({
|
|
|
113
126
|
);
|
|
114
127
|
console.log(` ${DIM}Ctrl+B → D: 세션 분리 (백그라운드)${RESET}\n`);
|
|
115
128
|
if (process.stdout.isTTY && process.stdin.isTTY) attachSession(sessionId);
|
|
116
|
-
else
|
|
129
|
+
else if (
|
|
130
|
+
splitAttachToClient(sessionId, {
|
|
131
|
+
targetPane: process.env.TMUX_PANE,
|
|
132
|
+
tmuxEnv: process.env.TMUX,
|
|
133
|
+
})
|
|
134
|
+
) {
|
|
135
|
+
ok("non-TTY 환경: 바깥 tmux 클라이언트 창을 분할해 attach함");
|
|
136
|
+
console.log(` ${DIM}분할 pane에서 나가기: Ctrl+B → D${RESET}\n`);
|
|
137
|
+
} else {
|
|
117
138
|
warn("TTY 미지원 환경이라 자동 attach를 생략함");
|
|
118
139
|
console.log(` ${DIM}수동 연결: tfx multi attach${RESET}\n`);
|
|
119
140
|
}
|
|
@@ -5,16 +5,28 @@ import {
|
|
|
5
5
|
sessionExists,
|
|
6
6
|
} from "../../session.mjs";
|
|
7
7
|
|
|
8
|
-
export function normalizeTeammateMode(mode = "auto") {
|
|
8
|
+
export function normalizeTeammateMode(mode = "auto", deps = {}) {
|
|
9
|
+
const platform = deps.platform || process.platform;
|
|
10
|
+
const env = deps.env || process.env;
|
|
11
|
+
const detectMux = deps.detectMultiplexer || detectMultiplexer;
|
|
9
12
|
const raw = String(mode).toLowerCase();
|
|
10
13
|
if (raw === "inline" || raw === "native") return "in-process";
|
|
11
14
|
if (raw === "headless" || raw === "hl") return "headless";
|
|
12
|
-
if (raw === "in-process" || raw === "tmux"
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
+
if (raw === "in-process" || raw === "tmux") return raw;
|
|
16
|
+
if (raw === "psmux") return platform === "win32" ? "psmux" : "in-process";
|
|
17
|
+
if (
|
|
18
|
+
raw === "wt" ||
|
|
19
|
+
raw === "windows-terminal" ||
|
|
20
|
+
raw === "windows_terminal"
|
|
21
|
+
) {
|
|
22
|
+
return platform === "win32" ? "wt" : "in-process";
|
|
23
|
+
}
|
|
15
24
|
if (raw === "auto") {
|
|
16
|
-
if (
|
|
17
|
-
const mux =
|
|
25
|
+
if (env.TMUX) return "tmux";
|
|
26
|
+
const mux = detectMux();
|
|
27
|
+
if (platform !== "win32") {
|
|
28
|
+
return mux === "tmux" ? "tmux" : "in-process";
|
|
29
|
+
}
|
|
18
30
|
if (mux === "psmux") return "psmux";
|
|
19
31
|
if (mux === "tmux") return "tmux";
|
|
20
32
|
return "in-process";
|
|
@@ -57,9 +69,11 @@ export function isTeamAlive(state) {
|
|
|
57
69
|
return sessionExists(state.sessionName);
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
export function ensureTmuxOrExit() {
|
|
61
|
-
const
|
|
62
|
-
|
|
72
|
+
export function ensureTmuxOrExit(deps = {}) {
|
|
73
|
+
const platform = deps.platform || process.platform;
|
|
74
|
+
const detectMux = deps.detectMultiplexer || detectMultiplexer;
|
|
75
|
+
const mux = detectMux();
|
|
76
|
+
if (mux && (platform === "win32" || mux === "tmux")) return mux;
|
|
63
77
|
const error = new Error("tmux 미발견");
|
|
64
78
|
error.code = "TMUX_REQUIRED";
|
|
65
79
|
throw error;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Codex headless review helper. Runs a cross-model review of a git diff
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// intentionally because `tfx` is the sanctioned entry point).
|
|
2
|
+
// through node `spawn` rather than the Bash tool, because `tfx` is the
|
|
3
|
+
// sanctioned entry point for Codex.
|
|
5
4
|
//
|
|
6
5
|
// Contract:
|
|
7
6
|
// runCodexReview({ ref = "HEAD", base?: string, timeoutMs = 180_000 })
|
package/hub/team/conductor.mjs
CHANGED
|
@@ -21,6 +21,11 @@ import { dirname, join } from "node:path";
|
|
|
21
21
|
import { createRegistry } from "../../mesh/mesh-registry.mjs";
|
|
22
22
|
import { resolveNestedCodexAgentProfile } from "../../scripts/lib/cli-codex.mjs";
|
|
23
23
|
import { codexProfileConfigOverrides } from "../../scripts/lib/codex-profile-config.mjs";
|
|
24
|
+
import {
|
|
25
|
+
buildDisabledCliError,
|
|
26
|
+
normalizeCliName,
|
|
27
|
+
resolveCliPolicy,
|
|
28
|
+
} from "../../scripts/lib/machine-profile.mjs";
|
|
24
29
|
import { broker } from "../account-broker.mjs";
|
|
25
30
|
import { runPreflight as runCodexPreflight } from "../codex-preflight.mjs";
|
|
26
31
|
import {
|
|
@@ -606,30 +611,53 @@ export function createConductor(opts = {}) {
|
|
|
606
611
|
}
|
|
607
612
|
}
|
|
608
613
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
614
|
+
let spawnSpec;
|
|
615
|
+
try {
|
|
616
|
+
spawnSpec = buildSpawnSpecForMode(MODES.HEADLESS, {
|
|
617
|
+
cli: session.config.agent,
|
|
618
|
+
prompt: session.config.prompt,
|
|
619
|
+
profile: session.config.profile,
|
|
620
|
+
role: session.config.role,
|
|
621
|
+
model: session.config.model,
|
|
622
|
+
env: session.config.env,
|
|
623
|
+
mcpServers: session.config.mcpServers,
|
|
624
|
+
excludeMcpServers,
|
|
625
|
+
resolveCommand: opts.deps?.resolveCliExecutable,
|
|
626
|
+
onWarning: (message, details = {}) => {
|
|
627
|
+
eventLog.append("mcp_server_skipped", {
|
|
628
|
+
session: session.id,
|
|
629
|
+
message,
|
|
630
|
+
...details,
|
|
631
|
+
});
|
|
632
|
+
emitter.emit("warning", {
|
|
633
|
+
type: "mcp_server_skipped",
|
|
634
|
+
session: session.id,
|
|
635
|
+
message,
|
|
636
|
+
...details,
|
|
637
|
+
});
|
|
638
|
+
},
|
|
639
|
+
});
|
|
640
|
+
} catch (err) {
|
|
641
|
+
// respawnSession 은 `void` 로 호출되므로 여기서 던지면 처리되지 않은 거부가
|
|
642
|
+
// 된다. spec 생성 실패를 명시 실패로 접어 세션이 매달리지 않게 한다.
|
|
643
|
+
// 정책 차단과 그 밖의 spec 생성 실패는 원인이 다르므로 이벤트를 나눈다.
|
|
644
|
+
const message = err?.message || String(err);
|
|
645
|
+
const blockedByPolicy = err?.code === "TFX_CLI_DISABLED";
|
|
646
|
+
const eventName = blockedByPolicy
|
|
647
|
+
? "session_spawn_blocked"
|
|
648
|
+
: "session_spawn_failed";
|
|
649
|
+
const reason = blockedByPolicy ? "spawn_blocked" : "spawn_failed";
|
|
650
|
+
const detail = {
|
|
651
|
+
session: session.id,
|
|
652
|
+
agent: session.config.agent,
|
|
653
|
+
code: err?.code || null,
|
|
654
|
+
error: message,
|
|
655
|
+
};
|
|
656
|
+
eventLog.append(eventName, detail);
|
|
657
|
+
emitter.emit("warning", { type: eventName, ...detail });
|
|
658
|
+
handleFailure(session, `${reason}:${message}`);
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
633
661
|
|
|
634
662
|
// #90 branch guard: shard spawn cwd가 main 브랜치면 즉시 abort.
|
|
635
663
|
// swarm shard는 반드시 shard 전용 worktree 브랜치에서 실행되어야 한다.
|
|
@@ -1176,6 +1204,34 @@ export function createConductor(opts = {}) {
|
|
|
1176
1204
|
}
|
|
1177
1205
|
}
|
|
1178
1206
|
|
|
1207
|
+
// TFX_DISABLE_* SSOT 집행. 계정 임대와 worker sandbox 생성보다 앞에 둔다.
|
|
1208
|
+
// 뒤에 두면 정책으로 거부된 세션이 샌드박스 디렉터리와 auth.json 사본을
|
|
1209
|
+
// 남기고, 임대 반납이 회로 차단기 실패로 집계돼 멀쩡한 계정이 cooldown 에
|
|
1210
|
+
// 들어간다. 다른 CLI 로 자동 전환하지 않고 호출자에게 그대로 던진다.
|
|
1211
|
+
// claude 처럼 정책 대상이 아닌 agent 는 프로파일 파일을 읽지 않는다 (F4 와 동일).
|
|
1212
|
+
if (!config.remote && normalizeCliName(config.agent)) {
|
|
1213
|
+
const blockedCli = buildDisabledCliError(
|
|
1214
|
+
config.agent,
|
|
1215
|
+
resolveCliPolicy(process.env),
|
|
1216
|
+
);
|
|
1217
|
+
if (blockedCli) {
|
|
1218
|
+
eventLog.append("session_spawn_blocked", {
|
|
1219
|
+
session: config.id,
|
|
1220
|
+
agent: config.agent,
|
|
1221
|
+
code: blockedCli.code || null,
|
|
1222
|
+
error: blockedCli.message,
|
|
1223
|
+
});
|
|
1224
|
+
emitter.emit("warning", {
|
|
1225
|
+
type: "session_spawn_blocked",
|
|
1226
|
+
session: config.id,
|
|
1227
|
+
agent: config.agent,
|
|
1228
|
+
code: blockedCli.code || null,
|
|
1229
|
+
error: blockedCli.message,
|
|
1230
|
+
});
|
|
1231
|
+
throw blockedCli;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1179
1235
|
// broker lease (graceful — broker null if accounts.json absent)
|
|
1180
1236
|
let lease = null;
|
|
1181
1237
|
const activeBroker = getActiveBroker();
|
|
@@ -2,16 +2,12 @@ import { existsSync, statSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
4
|
import { resolveLakeRootDir } from "../../cto/lake-root.mjs";
|
|
5
|
+
import { resolveRoleControlSnapshot } from "../lib/cto-env.mjs";
|
|
5
6
|
|
|
6
7
|
const DEFAULT_DEBOUNCE_MS = 120_000;
|
|
7
|
-
const OFF_VALUES = new Set(["0", "false", "off", "no"]);
|
|
8
8
|
|
|
9
9
|
export function isCtoAutoCollectDisabled(env = process.env) {
|
|
10
|
-
return
|
|
11
|
-
String(env?.TFX_CTO_AUTO_COLLECT ?? "")
|
|
12
|
-
.trim()
|
|
13
|
-
.toLowerCase(),
|
|
14
|
-
);
|
|
10
|
+
return !resolveRoleControlSnapshot(env).auto_collect_enabled;
|
|
15
11
|
}
|
|
16
12
|
|
|
17
13
|
function freshCurrentMd(projectRoot, now, debounceMs) {
|
package/hub/team/cto-pull.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
|
+
import { resolveRoleControlSnapshot } from "../lib/cto-env.mjs";
|
|
5
|
+
|
|
4
6
|
function defaultLakeRoot() {
|
|
5
7
|
return join(process.cwd(), ".triflux", "lake");
|
|
6
8
|
}
|
|
@@ -9,9 +11,11 @@ function defaultLakeRoot() {
|
|
|
9
11
|
* Read the CTO north-star lake snapshot without affecting runtime control flow.
|
|
10
12
|
* @param {object} [opts]
|
|
11
13
|
* @param {string} [opts.lakeRoot] Directory containing current.json.
|
|
14
|
+
* @param {object} [opts.env] Environment values used for the CTO kill-switch.
|
|
12
15
|
* @returns {object|null}
|
|
13
16
|
*/
|
|
14
17
|
export function readCtoSnapshot(opts = {}) {
|
|
18
|
+
if (!resolveRoleControlSnapshot(opts.env).north_star_enabled) return null;
|
|
15
19
|
try {
|
|
16
20
|
const lakeRoot = opts.lakeRoot || defaultLakeRoot();
|
|
17
21
|
const parsed = JSON.parse(
|
|
@@ -4,6 +4,15 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
4
4
|
import { dirname, resolve as pathResolve } from "node:path";
|
|
5
5
|
import { resolveNestedCodexAgentProfile } from "../../scripts/lib/cli-codex.mjs";
|
|
6
6
|
import { codexProfileConfigOverrides } from "../../scripts/lib/codex-profile-config.mjs";
|
|
7
|
+
import {
|
|
8
|
+
resolveGeminiModel,
|
|
9
|
+
resolveGeminiProfileForPurpose,
|
|
10
|
+
} from "../../scripts/lib/gemini-profiles.mjs";
|
|
11
|
+
import {
|
|
12
|
+
buildDisabledCliError,
|
|
13
|
+
normalizeCliName,
|
|
14
|
+
resolveCliPolicy,
|
|
15
|
+
} from "../../scripts/lib/machine-profile.mjs";
|
|
7
16
|
import { whichCommand } from "../platform.mjs";
|
|
8
17
|
|
|
9
18
|
const WIN32_EXT_PRECEDENCE = [".cmd", ".exe", ".bat", ".ps1"];
|
|
@@ -96,6 +105,19 @@ export function resolveCliExecutable(cli, opts = {}) {
|
|
|
96
105
|
|
|
97
106
|
export function buildSpawnSpecForMode(mode, opts = {}) {
|
|
98
107
|
const cli = normalizeCli(opts.cli || "codex");
|
|
108
|
+
|
|
109
|
+
// TFX_DISABLE_* SSOT 집행. route 를 우회하는 spawn 경로도 tfx-route.sh 와 같은
|
|
110
|
+
// 정책을 따른다. 정책 판독은 런타임 process.env 와 machine profile 만 쓰고,
|
|
111
|
+
// 자식에게 넘길 세션 env(opts.env)는 쓰지 않는다. 주입 시임은 opts.cliPolicy
|
|
112
|
+
// (계산된 정책)와 opts.policyEnv(env 객체) 둘뿐이다.
|
|
113
|
+
// claude 처럼 정책 대상이 아닌 CLI 는 프로파일 파일을 읽지 않는다.
|
|
114
|
+
if (normalizeCliName(cli)) {
|
|
115
|
+
const cliPolicy =
|
|
116
|
+
opts.cliPolicy ?? resolveCliPolicy(opts.policyEnv ?? process.env);
|
|
117
|
+
const blockedCli = buildDisabledCliError(cli, cliPolicy);
|
|
118
|
+
if (blockedCli) throw blockedCli;
|
|
119
|
+
}
|
|
120
|
+
|
|
99
121
|
const prompt = asPrompt(opts.prompt);
|
|
100
122
|
const commandName = cli === "antigravity" ? "agy" : cli;
|
|
101
123
|
const resolvedCommand = resolveCliExecutable(commandName, opts);
|
|
@@ -126,12 +148,26 @@ export function buildSpawnSpecForMode(mode, opts = {}) {
|
|
|
126
148
|
};
|
|
127
149
|
|
|
128
150
|
if (cli === "antigravity") {
|
|
129
|
-
|
|
151
|
+
// agy 1.1.27: --print 는 값(프롬프트)을 받는 마지막 인자다. stdin 프롬프트는
|
|
152
|
+
// "empty prompt" 로 거부되므로 argv 로 넘긴다.
|
|
153
|
+
// effort 는 역할별 SSOT(scripts/lib/gemini-profiles.mjs). 명시 model 이 우선한다.
|
|
154
|
+
const model =
|
|
155
|
+
typeof opts.model === "string" && opts.model.trim()
|
|
156
|
+
? resolveGeminiModel(opts.model.trim(), {
|
|
157
|
+
profilesPath: opts.geminiProfilesPath,
|
|
158
|
+
})
|
|
159
|
+
: resolveGeminiModel(
|
|
160
|
+
resolveGeminiProfileForPurpose(opts.role || opts.agent),
|
|
161
|
+
{ profilesPath: opts.geminiProfilesPath },
|
|
162
|
+
);
|
|
163
|
+
const args = ["--dangerously-skip-permissions"];
|
|
164
|
+
if (model) args.push("--model", model);
|
|
165
|
+
args.push("--print", prompt);
|
|
130
166
|
return {
|
|
131
167
|
...wrap(args),
|
|
132
168
|
useExec: true,
|
|
133
169
|
shell: false,
|
|
134
|
-
stdinPrompt:
|
|
170
|
+
stdinPrompt: false,
|
|
135
171
|
prompt,
|
|
136
172
|
};
|
|
137
173
|
}
|