@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.
- package/cto/brief.mjs +0 -20
- package/cto/collect.mjs +1 -200
- package/cto/current.schema.json +2 -23
- package/cto/hygiene.mjs +2 -61
- package/cto/lake-root.mjs +0 -56
- package/cto/status.mjs +5 -187
- package/hub/index.mjs +0 -17
- package/hub/team/agent-map.json +0 -1
- package/hub/team/agents-row-attach.py +120 -0
- package/hub/team/agents-row.mjs +200 -0
- package/hub/team/ansi.mjs +1 -35
- package/hub/team/backend.mjs +9 -145
- package/hub/team/claude-daemon-control.mjs +1 -2
- package/hub/team/claude-session-projection.mjs +5 -73
- package/hub/team/cli/commands/attach.mjs +1 -17
- package/hub/team/cli/commands/control.mjs +12 -38
- package/hub/team/cli/commands/debug.mjs +2 -39
- package/hub/team/cli/commands/focus.mjs +5 -31
- package/hub/team/cli/commands/interrupt.mjs +6 -25
- package/hub/team/cli/commands/kill.mjs +1 -30
- package/hub/team/cli/commands/list.mjs +0 -16
- package/hub/team/cli/commands/send.mjs +6 -26
- package/hub/team/cli/commands/start/index.mjs +42 -133
- package/hub/team/cli/commands/start/parse-args.mjs +15 -40
- package/hub/team/cli/commands/start/start-headless.mjs +138 -105
- package/hub/team/cli/commands/start/start-mux.mjs +2 -7
- package/hub/team/cli/commands/status.mjs +2 -57
- package/hub/team/cli/commands/stop.mjs +14 -19
- package/hub/team/cli/help.mjs +4 -5
- package/hub/team/cli/manifest.mjs +5 -1
- package/hub/team/cli/render.mjs +0 -12
- package/hub/team/cli/services/runtime-mode.mjs +27 -98
- package/hub/team/cli/services/state-store.mjs +5 -20
- package/hub/team/handoff.mjs +3 -34
- package/hub/team/headless.mjs +108 -1296
- package/hub/team/orchestrator.mjs +4 -30
- package/hub/team/pane.mjs +6 -28
- package/hub/team/psmux.mjs +3 -34
- package/hub/team/remote-session.mjs +1 -2
- package/hub/team/session-context.mjs +1 -1
- package/hub/team/session.mjs +7 -91
- package/hub/team/tui-core.mjs +1 -1
- package/hub/team/tui-viewer.mjs +11 -58
- package/hub/team/tui.mjs +8 -306
- package/hub/team/uds-orchestrator.mjs +2 -580
- package/hub/team/wt-manager.mjs +2 -2
- package/hub/workers/factory.mjs +6 -84
- package/hub/workers/interface.mjs +1 -7
- package/hub/workers/lib/jsonrpc-core.mjs +11 -0
- package/hub/workers/lib/jsonrpc-ws-uds.mjs +5 -8
- package/package.json +3 -8
- package/scripts/lib/agent-route-policy.mjs +143 -62
- package/scripts/lib/cli-claude.mjs +0 -14
- package/scripts/lib/env-probe.mjs +2 -131
- package/scripts/lib/gemini-profiles.mjs +2 -69
- package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
- package/scripts/lib/machine-profile.mjs +3 -17
- package/scripts/lib/mcp-filter.mjs +109 -53
- package/scripts/lib/mcp-guard-engine.mjs +40 -98
- package/scripts/lib/mcp-health.mjs +2 -2
- package/scripts/lib/mcp-server-catalog.mjs +2 -2
- package/scripts/lib/psmux-info.mjs +11 -59
- package/scripts/lib/skill-template.mjs +0 -245
- package/hub/hub-lifecycle.mjs +0 -248
- package/hub/pipe.mjs +0 -825
- package/hub/promote-penalties.mjs +0 -138
- package/hub/public/dashboard.html +0 -416
- package/hub/schema.sql +0 -209
- package/hub/server.mjs +0 -3048
- package/hub/store-adapter.mjs +0 -182
- package/hub/store.mjs +0 -1736
- package/hub/team/build-worker-prompt.mjs +0 -92
- package/hub/team/check-mcp-hub.mjs +0 -49
- package/hub/team/claude-native-bridge.mjs +0 -987
- package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
- package/hub/team/cli/commands/start/start-wt.mjs +0 -86
- package/hub/team/cli/services/hub-client.mjs +0 -264
- package/hub/team/cli/services/native-control.mjs +0 -145
- package/hub/team/codex-review.mjs +0 -520
- package/hub/team/conductor-mesh-bridge.mjs +0 -122
- package/hub/team/conductor-registry.mjs +0 -121
- package/hub/team/conductor.mjs +0 -1529
- package/hub/team/consensus-meta.mjs +0 -176
- package/hub/team/cto-auto-collect.mjs +0 -115
- package/hub/team/cto-pull.mjs +0 -31
- package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
- package/hub/team/dashboard.mjs +0 -322
- package/hub/team/event-log.mjs +0 -84
- package/hub/team/execution-mode.mjs +0 -324
- package/hub/team/extract-completion-payload.mjs +0 -110
- package/hub/team/headless-bridge-session.mjs +0 -17
- package/hub/team/health-probe.mjs +0 -435
- package/hub/team/interactive-native-launcher.mjs +0 -119
- package/hub/team/interactive-native-worker.mjs +0 -80
- package/hub/team/interactive-tui-transport.mjs +0 -479
- package/hub/team/launcher-template.mjs +0 -144
- package/hub/team/lead-control.mjs +0 -191
- package/hub/team/mcp-selector.mjs +0 -145
- package/hub/team/native-supervisor.mjs +0 -460
- package/hub/team/native.mjs +0 -727
- package/hub/team/recovery-store.mjs +0 -149
- package/hub/team/remote-probe.mjs +0 -292
- package/hub/team/remote-watcher.mjs +0 -506
- package/hub/team/runtime-strategy.mjs +0 -200
- package/hub/team/schemas/worker-completion.json +0 -39
- package/hub/team/sentinel-capture.mjs +0 -127
- package/hub/team/session-sync.mjs +0 -316
- package/hub/team/swarm-cli.mjs +0 -390
- package/hub/team/swarm-hypervisor.mjs +0 -2206
- package/hub/team/swarm-intent.mjs +0 -216
- package/hub/team/swarm-locks.mjs +0 -335
- package/hub/team/swarm-planner.mjs +0 -371
- package/hub/team/swarm-preflight.mjs +0 -366
- package/hub/team/swarm-reconciler.mjs +0 -242
- package/hub/team/synapse-cli.mjs +0 -458
- package/hub/team/synapse-http.mjs +0 -311
- package/hub/team/synapse-registry.mjs +0 -618
- package/hub/team/tui-remote-adapter.mjs +0 -377
- package/hub/team/tui-synapse.mjs +0 -223
- package/hub/team/worker-completion-validator.mjs +0 -79
- package/hub/team/worker-sandbox.mjs +0 -125
- package/hub/team/worktree-lifecycle.mjs +0 -639
- package/hub/team/wt-templates.json +0 -43
- package/hub/tools.mjs +0 -900
- package/hub/workers/antigravity-route-worker.mjs +0 -179
- package/hub/workers/codex-app-server-worker.mjs +0 -1067
- package/hub/workers/delegator-mcp.mjs +0 -1098
- package/hub/workers/lib/jsonrpc-stdio.mjs +0 -204
- package/scripts/lib/claudemd-scanner.mjs +0 -223
- package/scripts/lib/context.mjs +0 -67
- package/scripts/lib/dynamic-route-cli.mjs +0 -107
- package/scripts/lib/handoff.mjs +0 -187
- package/scripts/lib/logger.mjs +0 -122
- package/scripts/lib/stealth-fetch.mjs +0 -176
package/hub/workers/factory.mjs
CHANGED
|
@@ -1,101 +1,23 @@
|
|
|
1
1
|
// hub/workers/factory.mjs — Worker 생성 팩토리
|
|
2
2
|
//
|
|
3
3
|
// Supported worker types:
|
|
4
|
-
// - '
|
|
5
|
-
// - '
|
|
6
|
-
// - 'claude' → ClaudeWorker
|
|
7
|
-
// - 'codex' → CodexMcpWorker (default) or CodexAppServerWorker when
|
|
8
|
-
// opts.transport === 'app-server'
|
|
9
|
-
// - 'codex-app-server' → CodexAppServerWorker (explicit alias)
|
|
10
|
-
// - 'delegator' → DelegatorMcpWorker
|
|
4
|
+
// - 'claude' → ClaudeWorker
|
|
5
|
+
// - 'codex' → CodexMcpWorker
|
|
11
6
|
//
|
|
12
|
-
// For the codex app-server transport the factory injects a default
|
|
13
|
-
// `publishCallback` that forwards each envelope to `/bridge/publish` via the
|
|
14
|
-
// existing `requestJson` helper. Callers can override by passing their own
|
|
15
|
-
// `publishCallback` or swap the transport with `requestJsonFn`.
|
|
16
|
-
|
|
17
|
-
import { AntigravityRouteWorker } from "./antigravity-route-worker.mjs";
|
|
18
7
|
import { ClaudeWorker } from "./claude-worker.mjs";
|
|
19
|
-
import { CodexAppServerWorker } from "./codex-app-server-worker.mjs";
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Build a best-effort publishCallback that posts the envelope to
|
|
23
|
-
* `/bridge/publish`. Failures are swallowed so publish pressure never crashes
|
|
24
|
-
* a running worker turn.
|
|
25
|
-
* @param {(path: string, opts?: object) => Promise<unknown>} [requestJsonFn]
|
|
26
|
-
* @returns {(publishMessage: object) => Promise<void>}
|
|
27
|
-
*/
|
|
28
|
-
function defaultPublishCallback(requestJsonFn = null) {
|
|
29
|
-
return async (publishMessage) => {
|
|
30
|
-
try {
|
|
31
|
-
const publishRequestJson =
|
|
32
|
-
requestJsonFn || (await import("@triflux/core/hub/bridge.mjs")).requestJson;
|
|
33
|
-
await publishRequestJson("/bridge/publish", { body: publishMessage });
|
|
34
|
-
} catch {
|
|
35
|
-
// best-effort; publish failures must not crash the worker
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Construct a CodexAppServerWorker with a default publishCallback wired to
|
|
42
|
-
* `requestJson('/bridge/publish', ...)` unless the caller supplied one.
|
|
43
|
-
*
|
|
44
|
-
* Issue #95 P1 #4 validation: the app-server transport does not yet implement
|
|
45
|
-
* the server-initiated approval / `tool/requestUserInput` round-trip. Any
|
|
46
|
-
* `approvalPolicy !== 'never'` would cause a codex turn to hang waiting for
|
|
47
|
-
* an approval response the worker cannot produce. Reject such configs at
|
|
48
|
-
* factory time with a clear, actionable message.
|
|
49
|
-
*
|
|
50
|
-
* @param {object} [opts]
|
|
51
|
-
*/
|
|
52
|
-
async function createCodexWorker(opts = {}) {
|
|
53
|
-
const { transport, requestJsonFn, publishCallback, ...rest } = opts;
|
|
54
|
-
|
|
55
|
-
if (transport === "app-server") {
|
|
56
|
-
const policy = rest.approvalPolicy;
|
|
57
|
-
if (policy !== undefined && policy !== null && policy !== "never") {
|
|
58
|
-
throw new Error(
|
|
59
|
-
`codex app-server transport currently requires approvalPolicy='never' (got '${policy}'). ` +
|
|
60
|
-
"The server-initiated approval / tool/requestUserInput round-trip is not yet implemented. " +
|
|
61
|
-
"Set approvalPolicy='never' or use transport='mcp'. " +
|
|
62
|
-
"Tracked in follow-up issue.",
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
return new CodexAppServerWorker({
|
|
66
|
-
...rest,
|
|
67
|
-
publishCallback:
|
|
68
|
-
typeof publishCallback === "function"
|
|
69
|
-
? publishCallback
|
|
70
|
-
: defaultPublishCallback(requestJsonFn),
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Default (and transport === 'mcp'): CodexMcpWorker with zero new deps.
|
|
75
|
-
const { CodexMcpWorker } = await import("./codex-mcp.mjs");
|
|
76
|
-
return new CodexMcpWorker(rest);
|
|
77
|
-
}
|
|
78
8
|
|
|
79
9
|
/**
|
|
80
|
-
* @param {'
|
|
10
|
+
* @param {'claude'|'codex'} type
|
|
81
11
|
* @param {object} [opts]
|
|
82
12
|
* @returns {Promise<import('./interface.mjs').IWorker>}
|
|
83
13
|
*/
|
|
84
14
|
export async function createWorker(type, opts = {}) {
|
|
85
15
|
switch (type) {
|
|
86
|
-
case "gemini":
|
|
87
|
-
case "antigravity":
|
|
88
|
-
case "agy":
|
|
89
|
-
return new AntigravityRouteWorker(opts);
|
|
90
16
|
case "claude":
|
|
91
17
|
return new ClaudeWorker(opts);
|
|
92
|
-
case "codex":
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return createCodexWorker({ ...opts, transport: "app-server" });
|
|
96
|
-
case "delegator": {
|
|
97
|
-
const { DelegatorMcpWorker } = await import("./delegator-mcp.mjs");
|
|
98
|
-
return new DelegatorMcpWorker(opts);
|
|
18
|
+
case "codex": {
|
|
19
|
+
const { CodexMcpWorker } = await import("./codex-mcp.mjs");
|
|
20
|
+
return new CodexMcpWorker(opts);
|
|
99
21
|
}
|
|
100
22
|
default:
|
|
101
23
|
throw new Error(`Unknown worker type: ${type}`);
|
|
@@ -16,15 +16,11 @@
|
|
|
16
16
|
* @property {string} [developerInstructions] - 개발자 지침
|
|
17
17
|
* @property {string} [compactPrompt] - 컴팩션 프롬프트
|
|
18
18
|
* @property {number} [timeoutMs] - MCP 요청 타임아웃(ms)
|
|
19
|
-
* @property {'mcp'|'app-server'} [transport] - Codex 전송 계층 선택 (팩토리 전용)
|
|
20
19
|
*/
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* Codex 워커 생성 옵션 (팩토리 레벨)
|
|
24
23
|
* @typedef {object} CodexWorkerFactoryOptions
|
|
25
|
-
* @property {'mcp'|'app-server'} [transport] - 'mcp' (기본) 또는 'app-server'
|
|
26
|
-
* @property {(publishMessage: object) => void|Promise<void>} [publishCallback] - app-server 전용 publish 후크
|
|
27
|
-
* @property {(path: string, opts?: object) => Promise<unknown>} [requestJsonFn] - 테스트/리팩터용 requestJson 주입
|
|
28
24
|
* @property {string} [command] - codex 실행 바이너리 경로
|
|
29
25
|
* @property {string[]} [args] - codex CLI 인자 배열
|
|
30
26
|
* @property {string} [cwd] - 워커 작업 디렉터리
|
|
@@ -61,14 +57,12 @@
|
|
|
61
57
|
* @property {() => Promise<void>} start
|
|
62
58
|
* @property {() => Promise<void>} stop
|
|
63
59
|
* @property {() => boolean} isReady
|
|
64
|
-
* @property {'codex'|'
|
|
60
|
+
* @property {'codex'|'gemini'|'antigravity'|'claude'} type
|
|
65
61
|
*/
|
|
66
62
|
|
|
67
63
|
export const WORKER_TYPES = Object.freeze([
|
|
68
64
|
"codex",
|
|
69
|
-
"codex-app-server",
|
|
70
65
|
"gemini",
|
|
71
66
|
"antigravity",
|
|
72
67
|
"claude",
|
|
73
|
-
"delegator",
|
|
74
68
|
]);
|
|
@@ -12,6 +12,17 @@ export class JsonRpcProtocolError extends Error {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Thrown when the underlying stream closes unexpectedly.
|
|
17
|
+
*/
|
|
18
|
+
export class JsonRpcTransportError extends Error {
|
|
19
|
+
/** @param {string} message @param {{ cause?: unknown }} [options] */
|
|
20
|
+
constructor(message, options = {}) {
|
|
21
|
+
super(message, { cause: options.cause });
|
|
22
|
+
this.name = "JsonRpcTransportError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
export class JsonRpcDispatchBase {
|
|
16
27
|
/**
|
|
17
28
|
* @param {object} options
|
|
@@ -5,27 +5,26 @@
|
|
|
5
5
|
// on the socket — it speaks WebSocket (RFC 6455) after a standard HTTP/1.1
|
|
6
6
|
// Upgrade handshake, one JSON-RPC message per text frame. Confirmed live against
|
|
7
7
|
// codex-cli 0.135.0 (see experiments/native-bridge-feasibility/
|
|
8
|
-
// codex-app-server-uds-
|
|
9
|
-
//
|
|
10
|
-
// close/isOpen), different framing.
|
|
8
|
+
// codex-app-server-uds-smoke.mjs). Public surface: request/notify/
|
|
9
|
+
// onNotification/close/isOpen.
|
|
11
10
|
//
|
|
12
11
|
// Wire framing notes:
|
|
13
12
|
// - client -> server frames MUST be masked (RFC 6455 §5.3).
|
|
14
13
|
// - server -> client frames are unmasked.
|
|
15
14
|
// - one JSON-RPC object per text frame; fragmented frames are reassembled.
|
|
16
15
|
// - outbound JSON-RPC omits the `"jsonrpc":"2.0"` header (OpenAI App Server
|
|
17
|
-
// JSONL variant)
|
|
16
|
+
// JSONL variant).
|
|
18
17
|
//
|
|
19
18
|
// Zero new dependencies — minimal hand-rolled WS client (no `ws` package).
|
|
20
19
|
|
|
21
20
|
import { createHash, randomBytes } from "node:crypto";
|
|
22
21
|
import net from "node:net";
|
|
23
22
|
|
|
24
|
-
import { JsonRpcDispatchBase } from "./jsonrpc-core.mjs";
|
|
25
23
|
import {
|
|
24
|
+
JsonRpcDispatchBase,
|
|
26
25
|
JsonRpcProtocolError,
|
|
27
26
|
JsonRpcTransportError,
|
|
28
|
-
} from "./jsonrpc-
|
|
27
|
+
} from "./jsonrpc-core.mjs";
|
|
29
28
|
|
|
30
29
|
const WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
31
30
|
const DEFAULT_MAX_FRAME_SIZE = 16 * 1024 * 1024; // 16 MiB
|
|
@@ -475,5 +474,3 @@ export class JsonRpcWsUdsClient extends JsonRpcDispatchBase {
|
|
|
475
474
|
this._closeWith("closed", wrapped);
|
|
476
475
|
}
|
|
477
476
|
}
|
|
478
|
-
|
|
479
|
-
export default JsonRpcWsUdsClient;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@triflux/remote",
|
|
3
|
-
"version": "10.
|
|
4
|
-
"description": "triflux remote — team mode, psmux, MCP workers
|
|
3
|
+
"version": "10.52.0",
|
|
4
|
+
"description": "triflux remote — team mode, psmux, MCP workers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "hub/index.mjs",
|
|
7
7
|
"exports": {
|
|
@@ -15,12 +15,7 @@
|
|
|
15
15
|
"@triflux/core": "^10.0.0-alpha.1"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@modelcontextprotocol/sdk": "^1.27.1"
|
|
19
|
-
"ajv": "^8.18.0",
|
|
20
|
-
"better-sqlite3": "^12.10.0",
|
|
21
|
-
"pino": "^10.3.1",
|
|
22
|
-
"pino-pretty": "^13.1.3",
|
|
23
|
-
"zod": "^4.0.0"
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.27.1"
|
|
24
19
|
},
|
|
25
20
|
"files": [
|
|
26
21
|
"hub",
|
|
@@ -1,176 +1,137 @@
|
|
|
1
1
|
// Canonical Codex role policy. Concrete model IDs stay in profile config files.
|
|
2
2
|
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
3
5
|
import {
|
|
4
6
|
normalizeCodexProfileName,
|
|
5
7
|
resolveCodexProfileConfigValues,
|
|
6
8
|
} from "./codex-profile-config.mjs";
|
|
9
|
+
import { resolveGeminiProfileForPurpose } from "./gemini-profiles.mjs";
|
|
7
10
|
|
|
8
11
|
const policy = {
|
|
9
12
|
executor: {
|
|
10
13
|
profile: "gpt61_sol_high",
|
|
11
14
|
timeoutSec: 1080,
|
|
12
|
-
runMode: "fg",
|
|
13
|
-
opusOversight: false,
|
|
14
15
|
mcpHint: "implement",
|
|
15
16
|
subcommand: "exec",
|
|
16
17
|
},
|
|
17
18
|
codex: {
|
|
18
19
|
profile: "gpt61_sol_high",
|
|
19
20
|
timeoutSec: 1080,
|
|
20
|
-
runMode: "fg",
|
|
21
|
-
opusOversight: false,
|
|
22
21
|
mcpHint: "implement",
|
|
23
22
|
subcommand: "exec",
|
|
24
23
|
},
|
|
25
24
|
"build-fixer": {
|
|
26
25
|
profile: "gpt6_luna_high",
|
|
27
26
|
timeoutSec: 540,
|
|
28
|
-
runMode: "fg",
|
|
29
|
-
opusOversight: false,
|
|
30
27
|
mcpHint: "implement",
|
|
31
28
|
subcommand: "exec",
|
|
32
29
|
},
|
|
33
30
|
cleanup: {
|
|
34
31
|
profile: "gpt61_sol_med",
|
|
35
32
|
timeoutSec: 540,
|
|
36
|
-
runMode: "fg",
|
|
37
|
-
opusOversight: false,
|
|
38
33
|
mcpHint: "implement",
|
|
39
34
|
subcommand: "exec",
|
|
40
35
|
},
|
|
41
36
|
deslop: {
|
|
42
37
|
profile: "gpt61_sol_med",
|
|
43
38
|
timeoutSec: 540,
|
|
44
|
-
runMode: "fg",
|
|
45
|
-
opusOversight: false,
|
|
46
39
|
mcpHint: "implement",
|
|
47
40
|
subcommand: "exec",
|
|
48
41
|
},
|
|
49
42
|
debugger: {
|
|
50
43
|
profile: "gpt6_astra_xhigh",
|
|
51
44
|
timeoutSec: 900,
|
|
52
|
-
runMode: "bg",
|
|
53
|
-
opusOversight: false,
|
|
54
45
|
mcpHint: "implement",
|
|
55
46
|
subcommand: "exec",
|
|
56
47
|
},
|
|
57
48
|
"deep-executor": {
|
|
58
49
|
profile: "gpt6_astra_xhigh",
|
|
59
50
|
timeoutSec: 3600,
|
|
60
|
-
runMode: "bg",
|
|
61
|
-
opusOversight: true,
|
|
62
51
|
mcpHint: "implement",
|
|
63
52
|
subcommand: "exec",
|
|
64
53
|
},
|
|
65
54
|
architect: {
|
|
66
55
|
profile: "gpt6_astra_xhigh",
|
|
67
56
|
timeoutSec: 3600,
|
|
68
|
-
runMode: "bg",
|
|
69
|
-
opusOversight: true,
|
|
70
57
|
mcpHint: "analyze",
|
|
71
58
|
subcommand: "exec",
|
|
72
59
|
},
|
|
73
60
|
critic: {
|
|
74
61
|
profile: "gpt6_astra_xhigh",
|
|
75
62
|
timeoutSec: 3600,
|
|
76
|
-
runMode: "bg",
|
|
77
|
-
opusOversight: true,
|
|
78
63
|
mcpHint: "analyze",
|
|
79
64
|
subcommand: "exec",
|
|
80
65
|
},
|
|
81
66
|
planner: {
|
|
82
67
|
profile: "gpt6_astra_xhigh",
|
|
83
68
|
timeoutSec: 3600,
|
|
84
|
-
runMode: "fg",
|
|
85
|
-
opusOversight: true,
|
|
86
69
|
mcpHint: "analyze",
|
|
87
70
|
subcommand: "exec",
|
|
88
71
|
},
|
|
89
72
|
analyst: {
|
|
90
73
|
profile: "gpt6_astra_xhigh",
|
|
91
74
|
timeoutSec: 3600,
|
|
92
|
-
runMode: "fg",
|
|
93
|
-
opusOversight: true,
|
|
94
75
|
mcpHint: "analyze",
|
|
95
76
|
subcommand: "exec",
|
|
96
77
|
},
|
|
97
78
|
"code-reviewer": {
|
|
98
79
|
profile: "gpt61_sol_high",
|
|
99
80
|
timeoutSec: 1800,
|
|
100
|
-
runMode: "bg",
|
|
101
|
-
opusOversight: false,
|
|
102
81
|
mcpHint: "review",
|
|
103
82
|
subcommand: "review",
|
|
104
83
|
},
|
|
105
84
|
"quality-reviewer": {
|
|
106
85
|
profile: "gpt61_sol_high",
|
|
107
86
|
timeoutSec: 1800,
|
|
108
|
-
runMode: "bg",
|
|
109
|
-
opusOversight: false,
|
|
110
87
|
mcpHint: "review",
|
|
111
88
|
subcommand: "review",
|
|
112
89
|
},
|
|
113
90
|
"security-reviewer": {
|
|
114
91
|
profile: "gpt6_astra_xhigh",
|
|
115
92
|
timeoutSec: 1800,
|
|
116
|
-
runMode: "bg",
|
|
117
|
-
opusOversight: true,
|
|
118
93
|
mcpHint: "review",
|
|
119
94
|
subcommand: "review",
|
|
120
95
|
},
|
|
121
96
|
scientist: {
|
|
122
97
|
profile: "gpt61_sol_high",
|
|
123
98
|
timeoutSec: 1440,
|
|
124
|
-
runMode: "bg",
|
|
125
|
-
opusOversight: false,
|
|
126
99
|
mcpHint: "analyze",
|
|
127
100
|
subcommand: "exec",
|
|
128
101
|
},
|
|
129
102
|
"document-specialist": {
|
|
130
103
|
profile: "gpt61_sol_high",
|
|
131
104
|
timeoutSec: 1440,
|
|
132
|
-
runMode: "bg",
|
|
133
|
-
opusOversight: false,
|
|
134
105
|
mcpHint: "analyze",
|
|
135
106
|
subcommand: "exec",
|
|
136
107
|
},
|
|
137
108
|
"scientist-deep": {
|
|
138
109
|
profile: "gpt6_astra_xhigh",
|
|
139
110
|
timeoutSec: 3600,
|
|
140
|
-
runMode: "bg",
|
|
141
|
-
opusOversight: false,
|
|
142
111
|
mcpHint: "analyze",
|
|
143
112
|
subcommand: "exec",
|
|
144
113
|
},
|
|
145
114
|
verifier: {
|
|
146
115
|
profile: "gpt61_sol_high",
|
|
147
116
|
timeoutSec: 1200,
|
|
148
|
-
runMode: "fg",
|
|
149
|
-
opusOversight: false,
|
|
150
117
|
mcpHint: "review",
|
|
151
118
|
subcommand: "review",
|
|
152
119
|
},
|
|
153
120
|
"test-engineer": {
|
|
154
121
|
profile: "gpt61_sol_high",
|
|
155
122
|
timeoutSec: 1200,
|
|
156
|
-
runMode: "bg",
|
|
157
|
-
opusOversight: false,
|
|
158
123
|
mcpHint: "implement",
|
|
159
124
|
subcommand: "exec",
|
|
160
125
|
},
|
|
161
126
|
"qa-tester": {
|
|
162
127
|
profile: "gpt61_sol_high",
|
|
163
128
|
timeoutSec: 1200,
|
|
164
|
-
runMode: "bg",
|
|
165
|
-
opusOversight: false,
|
|
166
129
|
mcpHint: "review",
|
|
167
130
|
subcommand: "review",
|
|
168
131
|
},
|
|
169
132
|
spark: {
|
|
170
133
|
profile: "gpt6_luna_low",
|
|
171
134
|
timeoutSec: 180,
|
|
172
|
-
runMode: "fg",
|
|
173
|
-
opusOversight: false,
|
|
174
135
|
mcpHint: "implement",
|
|
175
136
|
subcommand: "exec",
|
|
176
137
|
},
|
|
@@ -179,16 +140,12 @@ const policy = {
|
|
|
179
140
|
designer: {
|
|
180
141
|
profile: "gpt6_astra_xhigh",
|
|
181
142
|
timeoutSec: 900,
|
|
182
|
-
runMode: "bg",
|
|
183
|
-
opusOversight: false,
|
|
184
143
|
mcpHint: "implement",
|
|
185
144
|
subcommand: "exec",
|
|
186
145
|
},
|
|
187
146
|
writer: {
|
|
188
147
|
profile: "gpt6_luna_high",
|
|
189
148
|
timeoutSec: 900,
|
|
190
|
-
runMode: "bg",
|
|
191
|
-
opusOversight: false,
|
|
192
149
|
mcpHint: "implement",
|
|
193
150
|
subcommand: "exec",
|
|
194
151
|
},
|
|
@@ -198,7 +155,7 @@ function freezePolicy(entry) {
|
|
|
198
155
|
return Object.freeze({ ...entry });
|
|
199
156
|
}
|
|
200
157
|
|
|
201
|
-
|
|
158
|
+
const CODEX_AGENT_POLICY = Object.freeze(
|
|
202
159
|
Object.fromEntries(
|
|
203
160
|
Object.entries(policy).map(([agent, entry]) => [
|
|
204
161
|
agent,
|
|
@@ -206,9 +163,9 @@ export const CODEX_AGENT_POLICY = Object.freeze(
|
|
|
206
163
|
]),
|
|
207
164
|
),
|
|
208
165
|
);
|
|
209
|
-
|
|
166
|
+
const DEFAULT_CODEX_AGENT = "executor";
|
|
210
167
|
|
|
211
|
-
|
|
168
|
+
const CANONICAL_CODEX_PROFILE_OVERRIDES = Object.freeze(
|
|
212
169
|
new Set([
|
|
213
170
|
"gpt6_luna_low",
|
|
214
171
|
"gpt6_luna_high",
|
|
@@ -219,7 +176,7 @@ export const CANONICAL_CODEX_PROFILE_OVERRIDES = Object.freeze(
|
|
|
219
176
|
"gpt6_astra_ultra",
|
|
220
177
|
]),
|
|
221
178
|
);
|
|
222
|
-
|
|
179
|
+
const ULTRA_ELIGIBLE_CODEX_AGENTS = Object.freeze(
|
|
223
180
|
new Set(["deep-executor", "scientist-deep"]),
|
|
224
181
|
);
|
|
225
182
|
|
|
@@ -316,39 +273,163 @@ export function resolveNestedCodexAgentProfile(
|
|
|
316
273
|
return effort.toLowerCase() === "ultra" ? "gpt6_astra_max" : candidate;
|
|
317
274
|
}
|
|
318
275
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
276
|
+
const EXPECTED_DURATION_BY_AGENT = Object.freeze({
|
|
277
|
+
writer: 90,
|
|
278
|
+
verifier: 90,
|
|
279
|
+
"qa-tester": 90,
|
|
280
|
+
executor: 300,
|
|
281
|
+
debugger: 300,
|
|
282
|
+
"test-engineer": 300,
|
|
283
|
+
"code-reviewer": 600,
|
|
284
|
+
"security-reviewer": 600,
|
|
285
|
+
architect: 600,
|
|
286
|
+
planner: 600,
|
|
287
|
+
critic: 600,
|
|
288
|
+
analyst: 600,
|
|
289
|
+
scientist: 900,
|
|
290
|
+
"scientist-deep": 900,
|
|
291
|
+
"deep-executor": 900,
|
|
292
|
+
"document-specialist": 900,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const NATIVE_CODEX_AGENTS = new Set([
|
|
296
|
+
"explore",
|
|
297
|
+
"verifier",
|
|
298
|
+
"test-engineer",
|
|
299
|
+
"qa-tester",
|
|
300
|
+
]);
|
|
301
|
+
|
|
302
|
+
function resolveDirectCodexRoutePolicy(agent) {
|
|
303
|
+
if (agent === "explore") {
|
|
304
|
+
return { ...CODEX_AGENT_POLICY.spark, timeoutSec: 600, mcpHint: "analyze" };
|
|
305
|
+
}
|
|
306
|
+
if (agent === "antigravity" || agent === "agy") {
|
|
307
|
+
return CODEX_AGENT_POLICY.designer;
|
|
308
|
+
}
|
|
309
|
+
return resolveCodexAgentPolicy(agent);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function resolveAgentRoute(
|
|
313
|
+
agent,
|
|
314
|
+
map,
|
|
315
|
+
profileOverride = "auto",
|
|
316
|
+
nested = false,
|
|
317
|
+
geminiProfileResolver = resolveGeminiProfileForPurpose,
|
|
318
|
+
) {
|
|
319
|
+
if (!/^[A-Za-z0-9_.-]+$/.test(agent)) {
|
|
320
|
+
throw new Error(`invalid agent: ${agent}`);
|
|
321
|
+
}
|
|
322
|
+
if (!Object.hasOwn(map, agent)) {
|
|
323
|
+
throw new Error(
|
|
324
|
+
`알 수 없는 에이전트 타입: ${agent}; available: ${Object.keys(map).join(", ")}`,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
const provider = map[agent];
|
|
328
|
+
if (!["codex", "antigravity", "claude"].includes(provider)) {
|
|
329
|
+
throw new Error(`invalid provider for ${agent}: ${provider}`);
|
|
330
|
+
}
|
|
331
|
+
const policy = resolveDirectCodexRoutePolicy(agent);
|
|
332
|
+
const normalizedOverride = normalizeCodexProfileName(profileOverride);
|
|
333
|
+
let resolvedOverride = policy.profile;
|
|
334
|
+
if (normalizedOverride !== "auto") {
|
|
335
|
+
try {
|
|
336
|
+
resolvedOverride = resolveCodexAgentProfile(agent, {
|
|
337
|
+
profileOverride: normalizedOverride,
|
|
338
|
+
nested,
|
|
339
|
+
});
|
|
340
|
+
} catch {
|
|
341
|
+
throw new Error(
|
|
342
|
+
`TFX_CODEX_PROFILE 값이 유효하지 않습니다: ${profileOverride}`,
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return [
|
|
347
|
+
provider,
|
|
348
|
+
policy.profile,
|
|
349
|
+
policy.timeoutSec,
|
|
350
|
+
policy.mcpHint,
|
|
351
|
+
policy.subcommand,
|
|
352
|
+
normalizedOverride,
|
|
353
|
+
resolvedOverride,
|
|
354
|
+
geminiProfileResolver(agent),
|
|
355
|
+
EXPECTED_DURATION_BY_AGENT[agent] ?? 30,
|
|
356
|
+
NATIVE_CODEX_AGENTS.has(agent),
|
|
357
|
+
];
|
|
324
358
|
}
|
|
325
359
|
|
|
326
360
|
function parseCliArgs(argv) {
|
|
327
361
|
const args = [...argv];
|
|
328
362
|
let format = "json";
|
|
329
363
|
let agent = DEFAULT_CODEX_AGENT;
|
|
364
|
+
let mapFile = "";
|
|
365
|
+
let profileOverride = "auto";
|
|
366
|
+
let geminiProfilesModule = "";
|
|
367
|
+
let nested = false;
|
|
330
368
|
while (args.length > 0) {
|
|
331
369
|
const flag = args.shift();
|
|
332
370
|
if (flag === "--format") format = args.shift() || "";
|
|
333
371
|
else if (flag === "--agent") agent = args.shift() || "";
|
|
372
|
+
else if (flag === "--map-file") mapFile = args.shift() || "";
|
|
373
|
+
else if (flag === "--profile-override")
|
|
374
|
+
profileOverride = args.shift() || "";
|
|
375
|
+
else if (flag === "--gemini-profiles-module")
|
|
376
|
+
geminiProfilesModule = args.shift() || "";
|
|
377
|
+
else if (flag === "--nested") nested = true;
|
|
334
378
|
else throw new Error(`unknown argument: ${flag}`);
|
|
335
379
|
}
|
|
336
|
-
if (!new Set(["json", "tsv"]).has(format)) {
|
|
380
|
+
if (!new Set(["json", "tsv", "route"]).has(format)) {
|
|
337
381
|
throw new Error(`unsupported format: ${format}`);
|
|
338
382
|
}
|
|
339
|
-
return {
|
|
383
|
+
return {
|
|
384
|
+
format,
|
|
385
|
+
agent,
|
|
386
|
+
mapFile,
|
|
387
|
+
profileOverride,
|
|
388
|
+
geminiProfilesModule,
|
|
389
|
+
nested,
|
|
390
|
+
};
|
|
340
391
|
}
|
|
341
392
|
|
|
342
|
-
function runCli() {
|
|
343
|
-
const {
|
|
393
|
+
async function runCli() {
|
|
394
|
+
const {
|
|
395
|
+
format,
|
|
396
|
+
agent,
|
|
397
|
+
mapFile,
|
|
398
|
+
profileOverride,
|
|
399
|
+
geminiProfilesModule,
|
|
400
|
+
nested,
|
|
401
|
+
} = parseCliArgs(process.argv.slice(2));
|
|
402
|
+
if (format === "route") {
|
|
403
|
+
if (!mapFile) throw new Error("--map-file is required for route format");
|
|
404
|
+
const map = JSON.parse(readFileSync(mapFile, "utf8"));
|
|
405
|
+
let resolver = resolveGeminiProfileForPurpose;
|
|
406
|
+
if (geminiProfilesModule) {
|
|
407
|
+
try {
|
|
408
|
+
const module = await import(pathToFileURL(geminiProfilesModule).href);
|
|
409
|
+
resolver = (agent) => {
|
|
410
|
+
try {
|
|
411
|
+
return module.resolveGeminiProfileForPurpose(agent) || "flash38";
|
|
412
|
+
} catch {
|
|
413
|
+
return "flash38";
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
} catch {
|
|
417
|
+
resolver = () => "flash38";
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
process.stdout.write(
|
|
421
|
+
resolveAgentRoute(agent, map, profileOverride, nested, resolver).join(
|
|
422
|
+
"\x1e",
|
|
423
|
+
),
|
|
424
|
+
);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
344
427
|
const resolved = resolveCodexAgentPolicy(agent);
|
|
345
428
|
if (format === "tsv") {
|
|
346
429
|
process.stdout.write(
|
|
347
430
|
[
|
|
348
431
|
resolved.profile,
|
|
349
432
|
resolved.timeoutSec,
|
|
350
|
-
resolved.runMode,
|
|
351
|
-
resolved.opusOversight,
|
|
352
433
|
resolved.mcpHint,
|
|
353
434
|
resolved.subcommand,
|
|
354
435
|
].join("\t"),
|
|
@@ -360,7 +441,7 @@ function runCli() {
|
|
|
360
441
|
|
|
361
442
|
if (import.meta.url === new URL(process.argv[1], "file:").href) {
|
|
362
443
|
try {
|
|
363
|
-
runCli();
|
|
444
|
+
await runCli();
|
|
364
445
|
} catch (error) {
|
|
365
446
|
process.stderr.write(`[agent-route-policy] ${error.message}\n`);
|
|
366
447
|
process.exitCode = 1;
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
// 책임: Claude 는 외부 CLI 가 아닌 Claude Code Agent 도구로 dispatch 된다. plan() 은
|
|
4
4
|
// command=null 을 반환하고 호출자가 Agent() 로 라우팅하도록 신호한다.
|
|
5
5
|
//
|
|
6
|
-
// 출처: scripts/tfx-route.sh route_agent() L1062-L1063 (explore|claude),
|
|
7
|
-
// L1196-L1203 (TFX_CLI_MODE=gemini fallback), TFX_VERIFIER_OVERRIDE=claude.
|
|
8
6
|
// timeoutSec은 lane 예상 소요 시간(advisory)이다. hard ceiling 집행은 Bash route가 소유한다.
|
|
9
7
|
|
|
10
8
|
export const id = "claude";
|
|
@@ -14,32 +12,22 @@ export const command = null;
|
|
|
14
12
|
const AGENT_PROFILES = {
|
|
15
13
|
explore: {
|
|
16
14
|
timeoutSec: 600,
|
|
17
|
-
runMode: "fg",
|
|
18
|
-
opusOversight: false,
|
|
19
15
|
model: "haiku",
|
|
20
16
|
},
|
|
21
17
|
claude: {
|
|
22
18
|
timeoutSec: 600,
|
|
23
|
-
runMode: "fg",
|
|
24
|
-
opusOversight: false,
|
|
25
19
|
model: "haiku",
|
|
26
20
|
},
|
|
27
21
|
"test-engineer": {
|
|
28
22
|
timeoutSec: 1200,
|
|
29
|
-
runMode: "bg",
|
|
30
|
-
opusOversight: false,
|
|
31
23
|
model: "sonnet",
|
|
32
24
|
},
|
|
33
25
|
"qa-tester": {
|
|
34
26
|
timeoutSec: 1200,
|
|
35
|
-
runMode: "bg",
|
|
36
|
-
opusOversight: false,
|
|
37
27
|
model: "sonnet",
|
|
38
28
|
},
|
|
39
29
|
verifier: {
|
|
40
30
|
timeoutSec: 1200,
|
|
41
|
-
runMode: "fg",
|
|
42
|
-
opusOversight: false,
|
|
43
31
|
model: "sonnet",
|
|
44
32
|
},
|
|
45
33
|
};
|
|
@@ -64,8 +52,6 @@ export function plan({
|
|
|
64
52
|
profile: "claude-native",
|
|
65
53
|
effort: "n/a",
|
|
66
54
|
timeoutMs: effectiveTimeoutSec * 1000,
|
|
67
|
-
runMode: cfg.runMode,
|
|
68
|
-
opusOversight: cfg.opusOversight,
|
|
69
55
|
model: cfg.model,
|
|
70
56
|
mcpProfile: mcpProfile === "auto" ? null : mcpProfile,
|
|
71
57
|
promptLength: prompt.length,
|