@triflux/remote 10.50.1 → 10.51.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 -12
- package/cto/collect.mjs +16 -247
- package/cto/current.schema.json +4 -20
- package/cto/events.mjs +13 -294
- package/cto/hygiene.mjs +26 -346
- package/cto/lake-root.mjs +114 -16
- package/cto/status.mjs +33 -128
- package/hub/index.mjs +0 -8
- package/hub/store-adapter.mjs +1 -1
- package/hub/team/agent-map.json +0 -1
- package/hub/team/ansi.mjs +1 -35
- package/hub/team/backend.mjs +9 -145
- 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 +1 -37
- 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 +41 -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 +0 -3
- 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/hub-client.mjs +2 -88
- package/hub/team/cli/services/runtime-mode.mjs +27 -98
- package/hub/team/handoff.mjs +3 -34
- package/hub/team/headless.mjs +14 -755
- package/hub/team/orchestrator.mjs +4 -30
- package/hub/team/pane.mjs +6 -28
- package/hub/team/psmux.mjs +16 -403
- package/hub/team/remote-session.mjs +1 -2
- package/hub/team/session.mjs +8 -119
- package/hub/team/swarm-intent.mjs +0 -198
- package/hub/team/terminal-opener.mjs +11 -35
- package/hub/team/tui-core.mjs +1 -1
- package/hub/team/tui-viewer.mjs +2 -2
- package/hub/team/tui.mjs +8 -269
- package/hub/team/wt-manager.mjs +2 -2
- package/hub/workers/factory.mjs +4 -37
- package/hub/workers/lib/jsonrpc-ws-uds.mjs +0 -2
- package/package.json +1 -1
- package/scripts/lib/agent-route-policy.mjs +162 -14
- package/scripts/lib/claudemd-scanner.mjs +2 -199
- package/scripts/lib/cli-claude.mjs +0 -2
- package/scripts/lib/context.mjs +3 -19
- package/scripts/lib/env-probe.mjs +5 -64
- package/scripts/lib/gemini-profiles.mjs +2 -69
- package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
- package/scripts/lib/machine-profile.mjs +3 -17
- package/scripts/lib/mcp-filter.mjs +109 -53
- package/scripts/lib/mcp-health.mjs +2 -2
- package/scripts/lib/mcp-server-catalog.mjs +2 -2
- package/scripts/lib/psmux-info.mjs +25 -104
- package/scripts/lib/skill-template.mjs +0 -271
- package/cto/hygiene-actions.mjs +0 -355
- package/cto/hygiene-notify.mjs +0 -170
- 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/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.mjs +0 -1529
- package/hub/team/consensus-meta.mjs +0 -176
- 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/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/swarm-cli.mjs +0 -390
- package/hub/team/swarm-hypervisor.mjs +0 -2206
- 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/tui-remote-adapter.mjs +0 -377
- package/hub/team/worker-completion-validator.mjs +0 -79
- package/hub/team/worktree-lifecycle.mjs +0 -639
- package/hub/team/wt-templates.json +0 -43
- package/hub/workers/antigravity-route-worker.mjs +0 -179
- package/hub/workers/gemini-worker.mjs +0 -217
- package/scripts/lib/agent-json.mjs +0 -27
- package/scripts/lib/async.mjs +0 -174
- package/scripts/lib/cli-agy.mjs +0 -85
- package/scripts/lib/cli-codex.mjs +0 -62
- package/scripts/lib/cli-gemini.mjs +0 -37
- package/scripts/lib/dynamic-route-cli.mjs +0 -107
- package/scripts/lib/env.mjs +0 -14
- package/scripts/lib/hub.mjs +0 -48
- package/scripts/lib/pid.mjs +0 -63
- package/scripts/lib/quota.mjs +0 -47
- package/scripts/lib/skill-state.mjs +0 -220
- package/scripts/lib/team.mjs +0 -75
- package/scripts/lib/timeout.mjs +0 -66
- package/scripts/lib/tmp.mjs +0 -26
- package/scripts/lib/toml.mjs +0 -132
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
// hub/workers/antigravity-route-worker.mjs — SDK-free Antigravity route worker
|
|
2
|
-
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
|
-
import { dirname, resolve } from "node:path";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
|
|
8
|
-
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
|
|
10
|
-
|
|
11
|
-
function resolveCandidatePath(candidate, cwd = process.cwd()) {
|
|
12
|
-
if (!candidate) return null;
|
|
13
|
-
const normalized = String(candidate).startsWith("/")
|
|
14
|
-
? String(candidate)
|
|
15
|
-
: resolve(cwd, String(candidate));
|
|
16
|
-
return existsSync(normalized) ? normalized : null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function resolveRouteScript(
|
|
20
|
-
explicitPath,
|
|
21
|
-
cwd = process.cwd(),
|
|
22
|
-
env = process.env,
|
|
23
|
-
) {
|
|
24
|
-
const candidates = [
|
|
25
|
-
explicitPath,
|
|
26
|
-
env.TFX_DELEGATOR_ROUTE_SCRIPT,
|
|
27
|
-
env.TFX_ROUTE_SCRIPT,
|
|
28
|
-
resolve(SCRIPT_DIR, "..", "..", "scripts", "tfx-route.sh"),
|
|
29
|
-
resolve(cwd, "scripts", "tfx-route.sh"),
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
for (const candidate of candidates) {
|
|
33
|
-
const resolved = resolveCandidatePath(candidate, cwd);
|
|
34
|
-
if (resolved) return resolved;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function parseRouteType(stderr = "") {
|
|
41
|
-
const match = String(stderr).match(/type=([a-z-]+)/);
|
|
42
|
-
if (!match) return "antigravity";
|
|
43
|
-
return match[1] === "gemini" ? "antigravity" : match[1];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function normalizeResult(result = {}) {
|
|
47
|
-
const output = result.output || result.error || "";
|
|
48
|
-
const exitCode = result.exitCode ?? (result.ok ? 0 : 1);
|
|
49
|
-
return {
|
|
50
|
-
response: output,
|
|
51
|
-
output,
|
|
52
|
-
exitCode,
|
|
53
|
-
stderr: result.stderr || "",
|
|
54
|
-
raw: result,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export class AntigravityRouteWorker {
|
|
59
|
-
type = "antigravity";
|
|
60
|
-
|
|
61
|
-
constructor(options = {}) {
|
|
62
|
-
this.cwd = options.cwd || process.cwd();
|
|
63
|
-
this.env = { ...process.env, ...(options.env || {}) };
|
|
64
|
-
this.routeScript = resolveRouteScript(
|
|
65
|
-
options.routeScript,
|
|
66
|
-
this.cwd,
|
|
67
|
-
this.env,
|
|
68
|
-
);
|
|
69
|
-
this.bashCommand = options.bashCommand || this.env.BASH_BIN || "bash";
|
|
70
|
-
this.timeoutMs =
|
|
71
|
-
Number.isFinite(Number(options.timeoutMs)) &&
|
|
72
|
-
Number(options.timeoutMs) > 0
|
|
73
|
-
? Number(options.timeoutMs)
|
|
74
|
-
: DEFAULT_TIMEOUT_MS;
|
|
75
|
-
this.children = new Set();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
isReady() {
|
|
79
|
-
return Boolean(this.routeScript);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async start() {}
|
|
83
|
-
|
|
84
|
-
async stop() {
|
|
85
|
-
for (const child of this.children) {
|
|
86
|
-
child.kill("SIGTERM");
|
|
87
|
-
}
|
|
88
|
-
this.children.clear();
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async run(prompt, options = {}) {
|
|
92
|
-
if (!this.routeScript) {
|
|
93
|
-
return normalizeResult({
|
|
94
|
-
ok: false,
|
|
95
|
-
output: "tfx-route.sh 경로를 찾지 못했습니다.",
|
|
96
|
-
exitCode: 70,
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const timeoutMs =
|
|
101
|
-
Number.isFinite(Number(options.timeoutMs)) &&
|
|
102
|
-
Number(options.timeoutMs) > 0
|
|
103
|
-
? Number(options.timeoutMs)
|
|
104
|
-
: this.timeoutMs;
|
|
105
|
-
const timeoutSec = Math.max(1, Math.ceil(timeoutMs / 1000));
|
|
106
|
-
const childArgs = [
|
|
107
|
-
this.routeScript,
|
|
108
|
-
options.agentType || "executor",
|
|
109
|
-
String(prompt ?? ""),
|
|
110
|
-
options.mcpProfile || "auto",
|
|
111
|
-
String(timeoutSec),
|
|
112
|
-
];
|
|
113
|
-
const childEnv = {
|
|
114
|
-
...this.env,
|
|
115
|
-
...(options.env || {}),
|
|
116
|
-
TFX_CLI_MODE: "antigravity",
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const result = await new Promise((resolveResult) => {
|
|
120
|
-
const child = spawn(this.bashCommand, childArgs, {
|
|
121
|
-
cwd: options.cwd || this.cwd,
|
|
122
|
-
env: childEnv,
|
|
123
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
124
|
-
});
|
|
125
|
-
this.children.add(child);
|
|
126
|
-
|
|
127
|
-
let stdout = "";
|
|
128
|
-
let stderr = "";
|
|
129
|
-
const timeout = setTimeout(() => {
|
|
130
|
-
child.kill("SIGTERM");
|
|
131
|
-
}, timeoutMs);
|
|
132
|
-
timeout.unref?.();
|
|
133
|
-
|
|
134
|
-
child.stdout?.setEncoding("utf8");
|
|
135
|
-
child.stderr?.setEncoding("utf8");
|
|
136
|
-
child.stdout?.on("data", (chunk) => {
|
|
137
|
-
stdout += chunk;
|
|
138
|
-
});
|
|
139
|
-
child.stderr?.on("data", (chunk) => {
|
|
140
|
-
stderr += chunk;
|
|
141
|
-
});
|
|
142
|
-
child.on("close", (code, signal) => {
|
|
143
|
-
clearTimeout(timeout);
|
|
144
|
-
this.children.delete(child);
|
|
145
|
-
const timedOut = signal === "SIGTERM" && code === null;
|
|
146
|
-
resolveResult({
|
|
147
|
-
ok: code === 0,
|
|
148
|
-
output: stdout.trim() || stderr.trim(),
|
|
149
|
-
stderr: stderr.trim(),
|
|
150
|
-
exitCode: timedOut ? 124 : (code ?? 1),
|
|
151
|
-
providerResolved: parseRouteType(stderr),
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
child.on("error", (error) => {
|
|
155
|
-
clearTimeout(timeout);
|
|
156
|
-
this.children.delete(child);
|
|
157
|
-
resolveResult({
|
|
158
|
-
ok: false,
|
|
159
|
-
output: error.message,
|
|
160
|
-
stderr,
|
|
161
|
-
exitCode: 1,
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
return normalizeResult(result);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async execute(prompt, options = {}) {
|
|
170
|
-
const result = await this.run(prompt, options);
|
|
171
|
-
return {
|
|
172
|
-
output: result.output,
|
|
173
|
-
exitCode: result.exitCode,
|
|
174
|
-
threadId: null,
|
|
175
|
-
sessionKey: null,
|
|
176
|
-
raw: result.raw,
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
}
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
// hub/workers/gemini-worker.mjs
|
|
2
|
-
// Deprecated compatibility surface. Direct Gemini CLI execution is removed;
|
|
3
|
-
// old imports now route through Antigravity.
|
|
4
|
-
|
|
5
|
-
import { existsSync } from "node:fs";
|
|
6
|
-
import { extname } from "node:path";
|
|
7
|
-
|
|
8
|
-
import { AntigravityRouteWorker } from "./antigravity-route-worker.mjs";
|
|
9
|
-
import { withRetry } from "./worker-utils.mjs";
|
|
10
|
-
|
|
11
|
-
function toStringList(value) {
|
|
12
|
-
if (!Array.isArray(value)) return [];
|
|
13
|
-
return value.map((item) => String(item ?? "").trim()).filter(Boolean);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Windows에서 cmd.exe에 전달할 인자를 안전하게 quoting한다.
|
|
18
|
-
*/
|
|
19
|
-
function quoteWindowsCmdArg(value) {
|
|
20
|
-
const raw = String(value ?? "").replace(/[\r\n]/g, " ");
|
|
21
|
-
if (raw.length === 0) return '""';
|
|
22
|
-
if (!/[\s"()^&|<>%!]/.test(raw)) return raw;
|
|
23
|
-
const escaped = raw
|
|
24
|
-
.replace(/%/g, "%%")
|
|
25
|
-
.replace(/(\\*)"/g, '$1$1\\"')
|
|
26
|
-
.replace(/(\\+)$/g, "$1$1");
|
|
27
|
-
return `"${escaped}"`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Windows npm shim(.cmd) spawn 문제를 해결한다.
|
|
32
|
-
*/
|
|
33
|
-
function buildSpawnSpec(command, args) {
|
|
34
|
-
if (process.platform !== "win32") {
|
|
35
|
-
return { command, args, shell: false };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let resolved = command;
|
|
39
|
-
if (!extname(resolved)) {
|
|
40
|
-
for (const ext of [".exe", ".cmd", ".bat"]) {
|
|
41
|
-
if (existsSync(resolved + ext)) {
|
|
42
|
-
resolved = resolved + ext;
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (/\.(cmd|bat)$/i.test(resolved)) {
|
|
49
|
-
const line = [resolved, ...args].map(quoteWindowsCmdArg).join(" ");
|
|
50
|
-
return {
|
|
51
|
-
command: "cmd.exe",
|
|
52
|
-
args: ["/d", "/s", "/v:off", "/c", line],
|
|
53
|
-
shell: false,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return { command: resolved, args, shell: false };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function createWorkerError(message, details = {}) {
|
|
61
|
-
const error = new Error(message);
|
|
62
|
-
Object.assign(error, details);
|
|
63
|
-
return error;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function normalizeRetryOptions(retryOptions) {
|
|
67
|
-
if (!retryOptions || typeof retryOptions !== "object") {
|
|
68
|
-
return Object.freeze({});
|
|
69
|
-
}
|
|
70
|
-
return Object.freeze({ ...retryOptions });
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function isAntigravityRetryable(error) {
|
|
74
|
-
return (
|
|
75
|
-
error?.code === "WORKER_EXIT" &&
|
|
76
|
-
error?.result?.exitCode !== 0 &&
|
|
77
|
-
error?.result?.exitCode !== 2
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function detectAntigravityCategory(error) {
|
|
82
|
-
const combined =
|
|
83
|
-
`${error?.message || ""}\n${error?.stderr || ""}`.toLowerCase();
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
/(unauthorized|forbidden|auth|login|token|credential|apikey|api key)/.test(
|
|
87
|
-
combined,
|
|
88
|
-
)
|
|
89
|
-
) {
|
|
90
|
-
return "auth";
|
|
91
|
-
}
|
|
92
|
-
if (
|
|
93
|
-
error?.result?.exitCode === 2 ||
|
|
94
|
-
/unknown option|invalid option|config|route script/.test(combined)
|
|
95
|
-
) {
|
|
96
|
-
return "config";
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return "transient";
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function buildAntigravityErrorInfo(error, attempts) {
|
|
103
|
-
const category = detectAntigravityCategory(error);
|
|
104
|
-
const retryable = isAntigravityRetryable(error);
|
|
105
|
-
let recovery =
|
|
106
|
-
"Retry the Antigravity route worker after correcting the issue.";
|
|
107
|
-
|
|
108
|
-
if (category === "auth") {
|
|
109
|
-
recovery = "Refresh the Antigravity authentication state and retry.";
|
|
110
|
-
} else if (category === "config") {
|
|
111
|
-
recovery = "Check the Antigravity route worker configuration.";
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return Object.freeze({
|
|
115
|
-
code: error?.code || "ANTIGRAVITY_EXECUTION_ERROR",
|
|
116
|
-
retryable,
|
|
117
|
-
attempts,
|
|
118
|
-
category,
|
|
119
|
-
recovery,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export class GeminiWorker extends AntigravityRouteWorker {
|
|
124
|
-
type = "antigravity";
|
|
125
|
-
|
|
126
|
-
constructor(options = {}) {
|
|
127
|
-
const { command, commandArgs, args, model, approvalMode, yolo, ...rest } =
|
|
128
|
-
options;
|
|
129
|
-
void commandArgs;
|
|
130
|
-
void args;
|
|
131
|
-
void model;
|
|
132
|
-
void approvalMode;
|
|
133
|
-
void yolo;
|
|
134
|
-
super(rest);
|
|
135
|
-
this.command = command || "agy";
|
|
136
|
-
this.retryOptions = normalizeRetryOptions(options.retryOptions);
|
|
137
|
-
this.lastRun = null;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
getStatus() {
|
|
141
|
-
return {
|
|
142
|
-
type: "antigravity",
|
|
143
|
-
state: this.children.size > 0 ? "running" : "idle",
|
|
144
|
-
pid: null,
|
|
145
|
-
last_run_at_ms: this.lastRun?.finishedAtMs || null,
|
|
146
|
-
last_exit_code: this.lastRun?.exitCode ?? null,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async run(prompt, options = {}) {
|
|
151
|
-
const startedAtMs = Date.now();
|
|
152
|
-
const result = await super.run(prompt, options);
|
|
153
|
-
const normalized = {
|
|
154
|
-
type: "antigravity",
|
|
155
|
-
command: this.command,
|
|
156
|
-
args: toStringList(options.extraArgs),
|
|
157
|
-
response: result.response || result.output || "",
|
|
158
|
-
output: result.output || result.response || "",
|
|
159
|
-
stderr: result.stderr || "",
|
|
160
|
-
exitCode: result.exitCode ?? 1,
|
|
161
|
-
exitSignal: null,
|
|
162
|
-
timedOut: result.exitCode === 124,
|
|
163
|
-
startedAtMs,
|
|
164
|
-
finishedAtMs: Date.now(),
|
|
165
|
-
raw: result.raw || result,
|
|
166
|
-
};
|
|
167
|
-
this.lastRun = normalized;
|
|
168
|
-
|
|
169
|
-
if (normalized.exitCode !== 0) {
|
|
170
|
-
throw createWorkerError(
|
|
171
|
-
`Antigravity route worker exited with code ${normalized.exitCode}`,
|
|
172
|
-
{
|
|
173
|
-
code: "WORKER_EXIT",
|
|
174
|
-
result: normalized,
|
|
175
|
-
stderr: normalized.stderr,
|
|
176
|
-
},
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return normalized;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async execute(prompt, options = {}) {
|
|
184
|
-
let attempts = 0;
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
const result = await withRetry(
|
|
188
|
-
async () => {
|
|
189
|
-
attempts += 1;
|
|
190
|
-
return this.run(prompt, options);
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
...this.retryOptions,
|
|
194
|
-
shouldRetry: (error) => isAntigravityRetryable(error),
|
|
195
|
-
},
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
output: result.response,
|
|
200
|
-
exitCode: 0,
|
|
201
|
-
sessionKey: options.sessionKey || null,
|
|
202
|
-
raw: result,
|
|
203
|
-
};
|
|
204
|
-
} catch (error) {
|
|
205
|
-
return {
|
|
206
|
-
output: error.stderr || error.message || "Antigravity worker failed",
|
|
207
|
-
exitCode: error.code === "ETIMEDOUT" ? 124 : 1,
|
|
208
|
-
sessionKey: options.sessionKey || null,
|
|
209
|
-
error: buildAntigravityErrorInfo(error, attempts || 1),
|
|
210
|
-
raw: error.result || null,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/** @visibleForTesting - 테스트 전용 export. 외부 소비 금지. */
|
|
217
|
-
export { buildSpawnSpec, quoteWindowsCmdArg };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
|
|
4
|
-
export function agentJsonPath({ tmpDir, pid = process.pid }) {
|
|
5
|
-
return join(tmpDir, `tfx-agent-${pid}.json`);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function registerAgent({
|
|
9
|
-
tmpDir,
|
|
10
|
-
pid = process.pid,
|
|
11
|
-
cli = "",
|
|
12
|
-
agent = "",
|
|
13
|
-
started = Math.floor(Date.now() / 1000),
|
|
14
|
-
}) {
|
|
15
|
-
mkdirSync(tmpDir, { recursive: true });
|
|
16
|
-
const file = agentJsonPath({ tmpDir, pid });
|
|
17
|
-
writeFileSync(
|
|
18
|
-
file,
|
|
19
|
-
`${JSON.stringify({ pid, cli, agent, started })}\n`,
|
|
20
|
-
"utf8",
|
|
21
|
-
);
|
|
22
|
-
return file;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function removeAgent({ tmpDir, pid = process.pid }) {
|
|
26
|
-
rmSync(agentJsonPath({ tmpDir, pid }), { force: true });
|
|
27
|
-
}
|
package/scripts/lib/async.mjs
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { randomUUID } from "node:crypto";
|
|
3
|
-
import {
|
|
4
|
-
existsSync,
|
|
5
|
-
mkdirSync,
|
|
6
|
-
readFileSync,
|
|
7
|
-
statSync,
|
|
8
|
-
writeFileSync,
|
|
9
|
-
} from "node:fs";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
|
|
12
|
-
function jobDir(jobsDir, jobId) {
|
|
13
|
-
return join(jobsDir, jobId);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function readState(dir) {
|
|
17
|
-
const path = join(dir, "state.json");
|
|
18
|
-
if (!existsSync(path)) return null;
|
|
19
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function writeState(dir, state) {
|
|
23
|
-
writeFileSync(join(dir, "state.json"), `${JSON.stringify(state, null, 2)}\n`);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function fileSize(path) {
|
|
27
|
-
try {
|
|
28
|
-
return statSync(path).size;
|
|
29
|
-
} catch {
|
|
30
|
-
return 0;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function isAlive(pid) {
|
|
35
|
-
if (!pid || pid === "starting") return false;
|
|
36
|
-
try {
|
|
37
|
-
process.kill(Number(pid), 0);
|
|
38
|
-
return true;
|
|
39
|
-
} catch {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function createJob({
|
|
45
|
-
jobsDir,
|
|
46
|
-
command,
|
|
47
|
-
args = [],
|
|
48
|
-
env = process.env,
|
|
49
|
-
cwd = process.cwd(),
|
|
50
|
-
timeoutMs = 0,
|
|
51
|
-
}) {
|
|
52
|
-
mkdirSync(jobsDir, { recursive: true });
|
|
53
|
-
const id = randomUUID();
|
|
54
|
-
const dir = jobDir(jobsDir, id);
|
|
55
|
-
mkdirSync(dir, { recursive: true });
|
|
56
|
-
const startedAt = Date.now();
|
|
57
|
-
const stdoutPath = join(dir, "result.log");
|
|
58
|
-
const stderrPath = join(dir, "stderr.log");
|
|
59
|
-
writeState(dir, {
|
|
60
|
-
id,
|
|
61
|
-
state: "starting",
|
|
62
|
-
startedAt,
|
|
63
|
-
command,
|
|
64
|
-
args,
|
|
65
|
-
timeoutMs,
|
|
66
|
-
});
|
|
67
|
-
writeFileSync(join(dir, "pid"), "starting");
|
|
68
|
-
writeFileSync(join(dir, "start_time"), String(Math.floor(startedAt / 1000)));
|
|
69
|
-
|
|
70
|
-
const child = spawn(command, args, {
|
|
71
|
-
cwd,
|
|
72
|
-
env,
|
|
73
|
-
detached: true,
|
|
74
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
75
|
-
});
|
|
76
|
-
child.unref?.();
|
|
77
|
-
writeFileSync(join(dir, "pid"), String(child.pid));
|
|
78
|
-
writeState(dir, {
|
|
79
|
-
id,
|
|
80
|
-
state: "running",
|
|
81
|
-
pid: child.pid,
|
|
82
|
-
startedAt,
|
|
83
|
-
command,
|
|
84
|
-
args,
|
|
85
|
-
timeoutMs,
|
|
86
|
-
});
|
|
87
|
-
child.stdout?.on("data", (chunk) => {
|
|
88
|
-
writeFileSync(stdoutPath, chunk, { flag: "a" });
|
|
89
|
-
});
|
|
90
|
-
child.stderr?.on("data", (chunk) => {
|
|
91
|
-
writeFileSync(stderrPath, chunk, { flag: "a" });
|
|
92
|
-
});
|
|
93
|
-
let timer = null;
|
|
94
|
-
let timedOut = false;
|
|
95
|
-
if (timeoutMs > 0) {
|
|
96
|
-
timer = setTimeout(() => {
|
|
97
|
-
timedOut = true;
|
|
98
|
-
try {
|
|
99
|
-
process.kill(child.pid, "SIGTERM");
|
|
100
|
-
} catch {
|
|
101
|
-
// Process already exited.
|
|
102
|
-
}
|
|
103
|
-
}, timeoutMs);
|
|
104
|
-
timer.unref?.();
|
|
105
|
-
}
|
|
106
|
-
child.on("exit", (code) => {
|
|
107
|
-
if (timer) clearTimeout(timer);
|
|
108
|
-
const exitCode = timedOut ? 124 : (code ?? 1);
|
|
109
|
-
writeFileSync(join(dir, "exit_code"), String(exitCode));
|
|
110
|
-
writeFileSync(join(dir, "done"), "");
|
|
111
|
-
writeState(dir, {
|
|
112
|
-
id,
|
|
113
|
-
state: exitCode === 0 ? "done" : exitCode === 124 ? "timeout" : "failed",
|
|
114
|
-
pid: child.pid,
|
|
115
|
-
startedAt,
|
|
116
|
-
finishedAt: Date.now(),
|
|
117
|
-
exitCode,
|
|
118
|
-
command,
|
|
119
|
-
args,
|
|
120
|
-
timeoutMs,
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
return { id, dir, pid: child.pid };
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export function getJobStatus(jobId, { jobsDir }) {
|
|
128
|
-
const dir = jobDir(jobsDir, jobId);
|
|
129
|
-
if (!existsSync(dir))
|
|
130
|
-
return { state: "error", text: "error: job not found", exitCode: 1 };
|
|
131
|
-
const state = readState(dir);
|
|
132
|
-
if (state?.state === "done") return { ...state, text: "done" };
|
|
133
|
-
if (state?.state === "timeout") return { ...state, text: "timeout" };
|
|
134
|
-
if (state?.state === "failed") return { ...state, text: "failed" };
|
|
135
|
-
const pidText = existsSync(join(dir, "pid"))
|
|
136
|
-
? readFileSync(join(dir, "pid"), "utf8").trim()
|
|
137
|
-
: "";
|
|
138
|
-
if (pidText === "starting")
|
|
139
|
-
return { ...(state ?? {}), state: "starting", text: "starting" };
|
|
140
|
-
if (isAlive(pidText)) {
|
|
141
|
-
const start =
|
|
142
|
-
Number(readFileSync(join(dir, "start_time"), "utf8")) ||
|
|
143
|
-
Math.floor(Date.now() / 1000);
|
|
144
|
-
const elapsed = Math.max(0, Math.floor(Date.now() / 1000) - start);
|
|
145
|
-
const bytes = fileSize(join(dir, "result.log"));
|
|
146
|
-
return {
|
|
147
|
-
...(state ?? {}),
|
|
148
|
-
state: "running",
|
|
149
|
-
text: `running elapsed=${elapsed}s output=${bytes}B`,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
return { ...(state ?? {}), state: "failed", text: "failed" };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function getJobResult(jobId, { jobsDir }) {
|
|
156
|
-
const dir = jobDir(jobsDir, jobId);
|
|
157
|
-
if (!existsSync(dir)) throw new Error("job not found");
|
|
158
|
-
const status = getJobStatus(jobId, { jobsDir });
|
|
159
|
-
if (!["done", "timeout", "failed"].includes(status.state)) {
|
|
160
|
-
throw new Error("job still running");
|
|
161
|
-
}
|
|
162
|
-
const stdout = existsSync(join(dir, "result.log"))
|
|
163
|
-
? readFileSync(join(dir, "result.log"), "utf8")
|
|
164
|
-
: "";
|
|
165
|
-
const stderr = existsSync(join(dir, "stderr.log"))
|
|
166
|
-
? readFileSync(join(dir, "stderr.log"), "utf8")
|
|
167
|
-
: "";
|
|
168
|
-
return {
|
|
169
|
-
state: status.state,
|
|
170
|
-
exitCode: status.exitCode ?? 1,
|
|
171
|
-
stdout: stdout || stderr,
|
|
172
|
-
stderr,
|
|
173
|
-
};
|
|
174
|
-
}
|
package/scripts/lib/cli-agy.mjs
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// cli-agy.mjs — Antigravity (agy) CLI adapter (Phase 0 PoC).
|
|
2
|
-
//
|
|
3
|
-
// 책임: agy 1.1.27 부터 --print 는 값(프롬프트)이 필수이고 stdin 프롬프트는 거부되므로
|
|
4
|
-
// plan() 은 프롬프트를 args 의 --print 값으로 넣고 stdinMode="argv" 를 돌려준다.
|
|
5
|
-
// --print 뒤에 다른 플래그가 오면 그 플래그를 프롬프트로 삼키므로 항상 마지막에 둔다.
|
|
6
|
-
//
|
|
7
|
-
// 출처: scripts/tfx-route.sh route_agent() L1052-L1059, run_codex_exec() L2036-L2046.
|
|
8
|
-
// .claude/rules/tfx-update-logic.md Antigravity CLI 1.0.0 정밀 sanity matrix.
|
|
9
|
-
// timeoutSec은 lane 예상 소요 시간(advisory)이다. hard ceiling 집행은 Bash route가 소유한다.
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
resolveGeminiModel,
|
|
13
|
-
resolveGeminiProfileForPurpose,
|
|
14
|
-
} from "./gemini-profiles.mjs";
|
|
15
|
-
|
|
16
|
-
export const id = "agy";
|
|
17
|
-
export const cliType = "antigravity";
|
|
18
|
-
export const command = "agy";
|
|
19
|
-
|
|
20
|
-
// #310: agent-map.json normalizes upstream callers to antigravity,
|
|
21
|
-
// but this adapter also accepts the direct `agy` route for compatibility.
|
|
22
|
-
const AGENT_PROFILES = {
|
|
23
|
-
antigravity: {
|
|
24
|
-
profile: "agy_v1",
|
|
25
|
-
timeoutSec: 900,
|
|
26
|
-
runMode: "bg",
|
|
27
|
-
opusOversight: false,
|
|
28
|
-
mcpHint: "docs",
|
|
29
|
-
},
|
|
30
|
-
agy: {
|
|
31
|
-
profile: "agy_v1",
|
|
32
|
-
timeoutSec: 900,
|
|
33
|
-
runMode: "bg",
|
|
34
|
-
opusOversight: false,
|
|
35
|
-
mcpHint: "docs",
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const DEFAULT_PROFILE = AGENT_PROFILES.antigravity;
|
|
40
|
-
|
|
41
|
-
export function plan({
|
|
42
|
-
agent,
|
|
43
|
-
prompt = "",
|
|
44
|
-
mcpProfile = "auto",
|
|
45
|
-
timeoutSec,
|
|
46
|
-
contextFile,
|
|
47
|
-
geminiProfilesPath,
|
|
48
|
-
} = {}) {
|
|
49
|
-
if (!agent) {
|
|
50
|
-
throw new Error("[cli-agy] agent required");
|
|
51
|
-
}
|
|
52
|
-
const cfg = AGENT_PROFILES[agent] ?? DEFAULT_PROFILE;
|
|
53
|
-
const effectiveTimeoutSec =
|
|
54
|
-
Number.isFinite(timeoutSec) && timeoutSec > 0 ? timeoutSec : cfg.timeoutSec;
|
|
55
|
-
return {
|
|
56
|
-
command,
|
|
57
|
-
profile: cfg.profile,
|
|
58
|
-
effort: cfg.profile,
|
|
59
|
-
// effort 는 역할별 SSOT(gemini-profiles.mjs): designer → High, writer → Medium ...
|
|
60
|
-
geminiProfile: resolveGeminiProfileForPurpose(agent),
|
|
61
|
-
model: resolveGeminiModel(resolveGeminiProfileForPurpose(agent), {
|
|
62
|
-
profilesPath: geminiProfilesPath,
|
|
63
|
-
}),
|
|
64
|
-
args: [
|
|
65
|
-
"--dangerously-skip-permissions",
|
|
66
|
-
"--model",
|
|
67
|
-
resolveGeminiModel(resolveGeminiProfileForPurpose(agent), {
|
|
68
|
-
profilesPath: geminiProfilesPath,
|
|
69
|
-
}),
|
|
70
|
-
"--print",
|
|
71
|
-
prompt,
|
|
72
|
-
],
|
|
73
|
-
stdinMode: "argv",
|
|
74
|
-
timeoutMs: effectiveTimeoutSec * 1000,
|
|
75
|
-
runMode: cfg.runMode,
|
|
76
|
-
opusOversight: cfg.opusOversight,
|
|
77
|
-
mcpProfile: mcpProfile === "auto" ? cfg.mcpHint : mcpProfile,
|
|
78
|
-
promptLength: prompt.length,
|
|
79
|
-
contextFile: contextFile || null,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function describe() {
|
|
84
|
-
return { id, cliType, command, agents: Object.keys(AGENT_PROFILES) };
|
|
85
|
-
}
|