@triflux/core 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.
Files changed (90) hide show
  1. package/hooks/agy-session-hook.mjs +11 -56
  2. package/hooks/codex-session-hook.mjs +11 -101
  3. package/hub/bridge.mjs +1 -79
  4. package/hub/cli-adapter-base.mjs +12 -90
  5. package/hub/codex-adapter.mjs +0 -1
  6. package/hub/codex-preflight.mjs +5 -28
  7. package/hub/index.mjs +3 -9
  8. package/hub/lib/cto-env.mjs +0 -23
  9. package/hub/lib/known-errors.json +2 -2
  10. package/hub/lib/process-utils.mjs +0 -123
  11. package/hub/lib/spawn-trace.mjs +3 -2
  12. package/hub/lib/timeout-defaults.mjs +0 -1
  13. package/hub/paths.mjs +0 -6
  14. package/hub/pipeline/index.mjs +0 -190
  15. package/hub/pipeline/transitions.mjs +0 -10
  16. package/hub/reflexion.mjs +1 -84
  17. package/hub/role-contract.mjs +0 -2
  18. package/hud/cli-policy.mjs +0 -26
  19. package/hud/colors.mjs +0 -13
  20. package/hud/constants.mjs +7 -153
  21. package/hud/context-monitor.mjs +3 -64
  22. package/hud/hud-qos-status.mjs +54 -264
  23. package/hud/providers/claude.mjs +4 -16
  24. package/hud/providers/gemini.mjs +83 -689
  25. package/hud/renderers.mjs +59 -367
  26. package/hud/terminal.mjs +1 -63
  27. package/hud/utils.mjs +2 -26
  28. package/package.json +1 -4
  29. package/scripts/lib/agent-route-policy.mjs +162 -14
  30. package/scripts/lib/claudemd-scanner.mjs +2 -199
  31. package/scripts/lib/cli-claude.mjs +0 -2
  32. package/scripts/lib/context.mjs +3 -19
  33. package/scripts/lib/env-probe.mjs +5 -64
  34. package/scripts/lib/gemini-profiles.mjs +2 -69
  35. package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
  36. package/scripts/lib/machine-profile.mjs +3 -17
  37. package/scripts/lib/mcp-filter.mjs +109 -53
  38. package/scripts/lib/mcp-health.mjs +2 -2
  39. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  40. package/scripts/lib/psmux-info.mjs +25 -104
  41. package/scripts/lib/session-presence.mjs +1 -1
  42. package/scripts/lib/skill-template.mjs +0 -271
  43. package/hub/codex-compat.mjs +0 -12
  44. package/hub/dynamic-routing-engine.mjs +0 -511
  45. package/hub/fullcycle.mjs +0 -113
  46. package/hub/gemini-adapter.mjs +0 -174
  47. package/hub/intent.mjs +0 -321
  48. package/hub/lib/mcp-response-cache.mjs +0 -239
  49. package/hub/lib/path-utils.mjs +0 -165
  50. package/hub/lib/risk-tier.mjs +0 -53
  51. package/hub/lib/ssh-command.mjs +0 -231
  52. package/hub/lib/staged-file-detect.mjs +0 -43
  53. package/hub/lib/tfx-route-args.mjs +0 -353
  54. package/hub/lib/timeline-adapter.mjs +0 -190
  55. package/hub/pipeline/gates/confidence.mjs +0 -75
  56. package/hub/pipeline/gates/consensus.mjs +0 -106
  57. package/hub/pipeline/gates/index.mjs +0 -9
  58. package/hub/pipeline/gates/selfcheck.mjs +0 -120
  59. package/hub/quality/deslop.mjs +0 -274
  60. package/hub/research.mjs +0 -155
  61. package/hub/role-control-events.mjs +0 -113
  62. package/hub/routing/complexity.mjs +0 -269
  63. package/hub/routing/index.mjs +0 -122
  64. package/hub/routing/q-learning.mjs +0 -387
  65. package/hub/routing-snapshot.mjs +0 -261
  66. package/hub/token-mode.mjs +0 -228
  67. package/hud/mission-board.mjs +0 -56
  68. package/hud/providers/cto.mjs +0 -76
  69. package/mesh/index.mjs +0 -69
  70. package/mesh/mesh-budget.mjs +0 -137
  71. package/mesh/mesh-heartbeat.mjs +0 -100
  72. package/mesh/mesh-protocol.mjs +0 -96
  73. package/mesh/mesh-queue.mjs +0 -163
  74. package/mesh/mesh-registry.mjs +0 -78
  75. package/mesh/mesh-router.mjs +0 -77
  76. package/scripts/lib/agent-json.mjs +0 -27
  77. package/scripts/lib/async.mjs +0 -174
  78. package/scripts/lib/cli-agy.mjs +0 -85
  79. package/scripts/lib/cli-codex.mjs +0 -62
  80. package/scripts/lib/cli-gemini.mjs +0 -37
  81. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  82. package/scripts/lib/env.mjs +0 -14
  83. package/scripts/lib/hub.mjs +0 -48
  84. package/scripts/lib/pid.mjs +0 -63
  85. package/scripts/lib/quota.mjs +0 -47
  86. package/scripts/lib/skill-state.mjs +0 -220
  87. package/scripts/lib/team.mjs +0 -75
  88. package/scripts/lib/timeout.mjs +0 -66
  89. package/scripts/lib/tmp.mjs +0 -26
  90. package/scripts/lib/toml.mjs +0 -132
@@ -1,96 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
-
3
- export const MSG_TYPES = Object.freeze({
4
- REQUEST: "request",
5
- RESPONSE: "response",
6
- EVENT: "event",
7
- HEARTBEAT: "heartbeat",
8
- });
9
-
10
- const VALID_TYPES = new Set(Object.values(MSG_TYPES));
11
-
12
- /**
13
- * Creates an immutable mesh message.
14
- * @param {string} type - One of MSG_TYPES values
15
- * @param {string} from - Sender agent ID
16
- * @param {string} to - Recipient agent ID (or "*" for broadcast)
17
- * @param {unknown} payload - Message payload
18
- * @returns {Readonly<object>}
19
- */
20
- export function createMessage(type, from, to, payload = null) {
21
- if (!VALID_TYPES.has(type)) {
22
- throw new TypeError(`Invalid message type: ${type}`);
23
- }
24
- if (!from || typeof from !== "string") {
25
- throw new TypeError("from must be a non-empty string");
26
- }
27
- if (!to || typeof to !== "string") {
28
- throw new TypeError("to must be a non-empty string");
29
- }
30
- return Object.freeze({
31
- type,
32
- from,
33
- to,
34
- payload,
35
- timestamp: new Date().toISOString(),
36
- correlationId: randomUUID(),
37
- });
38
- }
39
-
40
- /**
41
- * Serializes a message to a JSON string.
42
- * @param {object} message
43
- * @returns {string}
44
- */
45
- export function serialize(message) {
46
- return JSON.stringify(message);
47
- }
48
-
49
- /**
50
- * Deserializes a JSON string to a message object.
51
- * @param {string} raw
52
- * @returns {object}
53
- */
54
- export function deserialize(raw) {
55
- if (typeof raw !== "string") {
56
- throw new TypeError("raw must be a string");
57
- }
58
- let parsed;
59
- try {
60
- parsed = JSON.parse(raw);
61
- } catch {
62
- throw new SyntaxError(`Failed to parse message: ${raw}`);
63
- }
64
- return parsed;
65
- }
66
-
67
- /**
68
- * Validates a message object.
69
- * @param {unknown} message
70
- * @returns {{ valid: boolean, errors: string[] }}
71
- */
72
- export function validate(message) {
73
- const errors = [];
74
-
75
- if (!message || typeof message !== "object") {
76
- return { valid: false, errors: ["message must be an object"] };
77
- }
78
-
79
- if (!VALID_TYPES.has(message.type)) {
80
- errors.push(`Invalid type: ${message.type}`);
81
- }
82
- if (!message.from || typeof message.from !== "string") {
83
- errors.push("from must be a non-empty string");
84
- }
85
- if (!message.to || typeof message.to !== "string") {
86
- errors.push("to must be a non-empty string");
87
- }
88
- if (!message.timestamp || typeof message.timestamp !== "string") {
89
- errors.push("timestamp must be a non-empty string");
90
- }
91
- if (!message.correlationId || typeof message.correlationId !== "string") {
92
- errors.push("correlationId must be a non-empty string");
93
- }
94
-
95
- return { valid: errors.length === 0, errors };
96
- }
@@ -1,163 +0,0 @@
1
- const DEFAULT_MAX_QUEUE_SIZE = 100;
2
- const DEFAULT_TTL_MS = 0; // 0 = no expiry
3
-
4
- /**
5
- * Creates a per-agent message queue with TTL and size limits.
6
- *
7
- * @param {object} [opts]
8
- * @param {number} [opts.maxQueueSize=100] - Max messages per agent queue
9
- * @param {number} [opts.ttlMs=0] - Message TTL in ms (0 = no expiry)
10
- * @returns {object} Queue API
11
- */
12
- export function createMessageQueue(opts = {}) {
13
- const { maxQueueSize = DEFAULT_MAX_QUEUE_SIZE, ttlMs = DEFAULT_TTL_MS } =
14
- opts;
15
-
16
- /** @type {Map<string, Array<{ message: object, enqueuedAt: number }>>} */
17
- const queues = new Map();
18
-
19
- /**
20
- * Returns the queue array for an agent (creates if absent).
21
- * @param {string} agentId
22
- * @returns {Array}
23
- */
24
- function getQueue(agentId) {
25
- let q = queues.get(agentId);
26
- if (!q) {
27
- q = [];
28
- queues.set(agentId, q);
29
- }
30
- return q;
31
- }
32
-
33
- /**
34
- * Removes expired messages from the front of a queue.
35
- * @param {Array} q
36
- * @param {number} now
37
- */
38
- function purgeExpired(q, now) {
39
- if (ttlMs <= 0) return;
40
- while (q.length > 0 && now - q[0].enqueuedAt > ttlMs) {
41
- q.shift();
42
- }
43
- }
44
-
45
- /**
46
- * Adds a message to the target agent's queue.
47
- * If queue exceeds maxQueueSize, the oldest message is dropped.
48
- *
49
- * @param {string} agentId - Target agent
50
- * @param {object} message - Mesh message
51
- * @returns {{ queued: boolean, dropped: boolean }}
52
- */
53
- function enqueue(agentId, message) {
54
- if (!agentId || typeof agentId !== "string") {
55
- throw new TypeError("agentId must be a non-empty string");
56
- }
57
- const q = getQueue(agentId);
58
- const now = Date.now();
59
-
60
- purgeExpired(q, now);
61
-
62
- let dropped = false;
63
- if (q.length >= maxQueueSize) {
64
- q.shift();
65
- dropped = true;
66
- }
67
-
68
- q.push({ message, enqueuedAt: now });
69
- return { queued: true, dropped };
70
- }
71
-
72
- /**
73
- * Removes and returns the next message for an agent.
74
- *
75
- * @param {string} agentId
76
- * @returns {object | null} The message, or null if queue is empty
77
- */
78
- function dequeue(agentId) {
79
- const q = queues.get(agentId);
80
- if (!q || q.length === 0) return null;
81
-
82
- const now = Date.now();
83
- purgeExpired(q, now);
84
-
85
- if (q.length === 0) return null;
86
- return q.shift().message;
87
- }
88
-
89
- /**
90
- * Returns the next message without removing it.
91
- *
92
- * @param {string} agentId
93
- * @returns {object | null}
94
- */
95
- function peek(agentId) {
96
- const q = queues.get(agentId);
97
- if (!q || q.length === 0) return null;
98
-
99
- const now = Date.now();
100
- purgeExpired(q, now);
101
-
102
- if (q.length === 0) return null;
103
- return q[0].message;
104
- }
105
-
106
- /**
107
- * Returns the number of (non-expired) messages in an agent's queue.
108
- *
109
- * @param {string} agentId
110
- * @returns {number}
111
- */
112
- function size(agentId) {
113
- const q = queues.get(agentId);
114
- if (!q) return 0;
115
-
116
- const now = Date.now();
117
- purgeExpired(q, now);
118
-
119
- return q.length;
120
- }
121
-
122
- /**
123
- * Drains all messages for an agent.
124
- *
125
- * @param {string} agentId
126
- * @returns {object[]} Array of messages
127
- */
128
- function drain(agentId) {
129
- const q = queues.get(agentId);
130
- if (!q || q.length === 0) return [];
131
-
132
- const now = Date.now();
133
- purgeExpired(q, now);
134
-
135
- const messages = q.map((entry) => entry.message);
136
- q.length = 0;
137
- return messages;
138
- }
139
-
140
- /**
141
- * Removes an agent's queue entirely.
142
- * @param {string} agentId
143
- */
144
- function clear(agentId) {
145
- queues.delete(agentId);
146
- }
147
-
148
- /**
149
- * Returns total message count across all agent queues.
150
- * @returns {number}
151
- */
152
- function totalSize() {
153
- let total = 0;
154
- const now = Date.now();
155
- for (const [, q] of queues) {
156
- purgeExpired(q, now);
157
- total += q.length;
158
- }
159
- return total;
160
- }
161
-
162
- return { enqueue, dequeue, peek, size, drain, clear, totalSize };
163
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * Creates an agent registry for the mesh network.
3
- * Agents register with capabilities; registry enables discovery.
4
- * @returns {object} Registry API
5
- */
6
- export function createRegistry() {
7
- // Map<agentId, AgentInfo>
8
- const agents = new Map();
9
-
10
- /**
11
- * Registers an agent with the registry.
12
- * @param {string} agentId
13
- * @param {string[]} capabilities
14
- */
15
- function register(agentId, capabilities = []) {
16
- if (!agentId || typeof agentId !== "string") {
17
- throw new TypeError("agentId must be a non-empty string");
18
- }
19
- if (!Array.isArray(capabilities)) {
20
- throw new TypeError("capabilities must be an array");
21
- }
22
- const info = Object.freeze({
23
- agentId,
24
- capabilities: Object.freeze([...capabilities]),
25
- registeredAt: new Date().toISOString(),
26
- });
27
- agents.set(agentId, info);
28
- }
29
-
30
- /**
31
- * Unregisters an agent from the registry.
32
- * @param {string} agentId
33
- */
34
- function unregister(agentId) {
35
- agents.delete(agentId);
36
- }
37
-
38
- /**
39
- * Discovers agents that have a specific capability.
40
- * @param {string} capability
41
- * @returns {string[]} Array of agentIds
42
- */
43
- function discover(capability) {
44
- const result = [];
45
- for (const [agentId, info] of agents) {
46
- if (info.capabilities.includes(capability)) {
47
- result.push(agentId);
48
- }
49
- }
50
- return result;
51
- }
52
-
53
- /**
54
- * Gets agent info by ID.
55
- * @param {string} agentId
56
- * @returns {object | null}
57
- */
58
- function getAgent(agentId) {
59
- return agents.get(agentId) ?? null;
60
- }
61
-
62
- /**
63
- * Lists all registered agents.
64
- * @returns {object[]}
65
- */
66
- function listAll() {
67
- return [...agents.values()];
68
- }
69
-
70
- /**
71
- * Clears all registered agents.
72
- */
73
- function clear() {
74
- agents.clear();
75
- }
76
-
77
- return { register, unregister, discover, getAgent, listAll, clear };
78
- }
@@ -1,77 +0,0 @@
1
- import { validate } from "./mesh-protocol.mjs";
2
-
3
- /**
4
- * Routes a mesh message to target agent(s) based on the `to` field.
5
- *
6
- * Addressing modes:
7
- * - "agent-id" → direct delivery (registry lookup)
8
- * - "*" → broadcast to all registered agents
9
- * - "capability:X" → discover agents with capability X
10
- *
11
- * @param {object} message - A mesh-protocol message
12
- * @param {object} registry - A mesh-registry instance
13
- * @returns {{ routed: boolean, targets?: string[], reason?: string }}
14
- */
15
- export function routeMessage(message, registry) {
16
- const { valid, errors } = validate(message);
17
- if (!valid) {
18
- return { routed: false, reason: `invalid message: ${errors.join(", ")}` };
19
- }
20
-
21
- const { to, from } = message;
22
-
23
- // Broadcast
24
- if (to === "*") {
25
- const all = registry.listAll();
26
- const targets = all.map((a) => a.agentId).filter((id) => id !== from);
27
- if (targets.length === 0) {
28
- return { routed: false, reason: "broadcast: no agents registered" };
29
- }
30
- return { routed: true, targets };
31
- }
32
-
33
- // Capability-based routing
34
- if (to.startsWith("capability:")) {
35
- const capability = to.slice("capability:".length);
36
- if (!capability) {
37
- return { routed: false, reason: "capability: empty capability name" };
38
- }
39
- const targets = registry.discover(capability);
40
- if (targets.length === 0) {
41
- return {
42
- routed: false,
43
- reason: `capability: no agents with "${capability}"`,
44
- };
45
- }
46
- return { routed: true, targets };
47
- }
48
-
49
- // Direct addressing
50
- const agent = registry.getAgent(to);
51
- if (!agent) {
52
- return { routed: false, reason: `agent not found: "${to}"` };
53
- }
54
- return { routed: true, targets: [to] };
55
- }
56
-
57
- /**
58
- * Routes a message and collects dead-letter info when delivery fails.
59
- *
60
- * @param {object} message
61
- * @param {object} registry
62
- * @returns {{ routed: boolean, targets?: string[], deadLetter?: object }}
63
- */
64
- export function routeOrDeadLetter(message, registry) {
65
- const result = routeMessage(message, registry);
66
- if (!result.routed) {
67
- return {
68
- ...result,
69
- deadLetter: {
70
- originalMessage: message,
71
- reason: result.reason,
72
- timestamp: new Date().toISOString(),
73
- },
74
- };
75
- }
76
- return result;
77
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }