@agentteams/runner 0.0.98 → 0.0.100
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/dist/handlers/trigger-handler.d.ts +2 -0
- package/dist/handlers/trigger-handler.js +36 -5
- package/dist/handlers/trigger-handler.js.map +1 -1
- package/dist/handlers/trigger-handler.test.js +298 -0
- package/dist/handlers/trigger-handler.test.js.map +1 -1
- package/dist/runners/capabilities.js +1 -0
- package/dist/runners/capabilities.js.map +1 -1
- package/dist/runners/capabilities.test.js +12 -1
- package/dist/runners/capabilities.test.js.map +1 -1
- package/dist/runners/index.js +3 -0
- package/dist/runners/index.js.map +1 -1
- package/dist/runners/index.test.js +2 -0
- package/dist/runners/index.test.js.map +1 -1
- package/dist/runners/kimi-cli.d.ts +28 -0
- package/dist/runners/kimi-cli.js +257 -0
- package/dist/runners/kimi-cli.js.map +1 -0
- package/dist/runners/kimi-cli.test.d.ts +1 -0
- package/dist/runners/kimi-cli.test.js +118 -0
- package/dist/runners/kimi-cli.test.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/utils/resolve-member-repo.d.ts +39 -0
- package/dist/utils/resolve-member-repo.js +180 -0
- package/dist/utils/resolve-member-repo.js.map +1 -0
- package/dist/utils/resolve-member-repo.test.d.ts +1 -0
- package/dist/utils/resolve-member-repo.test.js +201 -0
- package/dist/utils/resolve-member-repo.test.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createWriteStream } from 'node:fs';
|
|
3
|
+
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { platform } from 'node:os';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { describeExecutableResolution, resolveExecutablePathWithPreference } from '../executable.js';
|
|
7
|
+
import { logger } from '../logger.js';
|
|
8
|
+
import { setupCloseWatchdog, terminateRunnerChild } from './process-control.js';
|
|
9
|
+
const OUTPUT_PREVIEW_MAX = 400;
|
|
10
|
+
const OUTPUT_CAPTURE_MAX = 200_000;
|
|
11
|
+
const normalizedModel = (model) => (typeof model === 'string' ? model.trim() : '');
|
|
12
|
+
export const buildKimiCliArgs = (prompt, model) => {
|
|
13
|
+
const selectedModel = normalizedModel(model);
|
|
14
|
+
const modelArgs = selectedModel.length > 0 && selectedModel !== 'default' ? ['-m', selectedModel] : [];
|
|
15
|
+
return ['-p', prompt, ...modelArgs];
|
|
16
|
+
};
|
|
17
|
+
export const getKimiExecutablePreference = (isWindows) => isWindows ? ['kimi.cmd', 'kimi'] : ['kimi'];
|
|
18
|
+
const toPowerShellLiteral = (value) => `'${value.replaceAll("'", "''")}'`;
|
|
19
|
+
export const toKimiPowerShellEncodedCommand = (resolvedExecutablePath, promptFilePath, model) => {
|
|
20
|
+
const selectedModel = normalizedModel(model);
|
|
21
|
+
const modelSegment = selectedModel.length > 0 && selectedModel !== 'default' ? ` '-m' ${toPowerShellLiteral(selectedModel)}` : '';
|
|
22
|
+
const scriptContent = [
|
|
23
|
+
"$ErrorActionPreference = 'Stop'",
|
|
24
|
+
'$utf8NoBom = [System.Text.UTF8Encoding]::new($false)',
|
|
25
|
+
'[Console]::InputEncoding = $utf8NoBom',
|
|
26
|
+
'[Console]::OutputEncoding = $utf8NoBom',
|
|
27
|
+
'$OutputEncoding = $utf8NoBom',
|
|
28
|
+
'chcp 65001 > $null',
|
|
29
|
+
`$promptText = [System.IO.File]::ReadAllText(${toPowerShellLiteral(promptFilePath)}, $utf8NoBom)`,
|
|
30
|
+
`& ${toPowerShellLiteral(resolvedExecutablePath)} '-p' $promptText${modelSegment}`,
|
|
31
|
+
].join('\r\n');
|
|
32
|
+
return Buffer.from(scriptContent, 'utf16le').toString('base64');
|
|
33
|
+
};
|
|
34
|
+
const toOutputPreview = (chunk) => {
|
|
35
|
+
const text = (typeof chunk === 'string' ? chunk : String(chunk)).trim();
|
|
36
|
+
return text.length <= OUTPUT_PREVIEW_MAX ? text : `${text.slice(0, OUTPUT_PREVIEW_MAX)}...`;
|
|
37
|
+
};
|
|
38
|
+
const defaultDependencies = {
|
|
39
|
+
platform,
|
|
40
|
+
resolveExecutablePathWithPreference,
|
|
41
|
+
describeExecutableResolution,
|
|
42
|
+
spawn,
|
|
43
|
+
createWriteStream,
|
|
44
|
+
mkdir,
|
|
45
|
+
writeFile,
|
|
46
|
+
rm,
|
|
47
|
+
setupCloseWatchdog,
|
|
48
|
+
terminateRunnerChild,
|
|
49
|
+
};
|
|
50
|
+
export class KimiCliRunner {
|
|
51
|
+
deps;
|
|
52
|
+
constructor(dependencies = {}) {
|
|
53
|
+
this.deps = { ...defaultDependencies, ...dependencies };
|
|
54
|
+
}
|
|
55
|
+
async run(opts) {
|
|
56
|
+
if (!opts.authPath || opts.authPath.trim().length === 0) {
|
|
57
|
+
logger.error('authPath is missing for trigger');
|
|
58
|
+
return { exitCode: 1, errorMessage: 'authPath is missing for trigger' };
|
|
59
|
+
}
|
|
60
|
+
const cwd = opts.authPath;
|
|
61
|
+
const logPath = join(cwd, '.agentteams', 'runner', 'log', `${opts.triggerId}.log`);
|
|
62
|
+
await this.deps.mkdir(dirname(logPath), { recursive: true });
|
|
63
|
+
const isWindows = this.deps.platform() === 'win32';
|
|
64
|
+
const resolvedExecutablePath = this.deps.resolveExecutablePathWithPreference('kimi', getKimiExecutablePreference(isWindows));
|
|
65
|
+
const windowsPromptFilePath = isWindows
|
|
66
|
+
? join(cwd, '.agentteams', 'runner', 'tmp', `${opts.triggerId}.prompt.txt`)
|
|
67
|
+
: null;
|
|
68
|
+
if (windowsPromptFilePath) {
|
|
69
|
+
await this.deps.mkdir(dirname(windowsPromptFilePath), { recursive: true });
|
|
70
|
+
await this.deps.writeFile(windowsPromptFilePath, opts.prompt, { encoding: 'utf8' });
|
|
71
|
+
}
|
|
72
|
+
const removeWindowsPromptFile = async () => {
|
|
73
|
+
if (!windowsPromptFilePath)
|
|
74
|
+
return;
|
|
75
|
+
try {
|
|
76
|
+
await this.deps.rm(windowsPromptFilePath, { force: true });
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
logger.warn('Failed to remove Windows prompt temp file', {
|
|
80
|
+
triggerId: opts.triggerId,
|
|
81
|
+
promptFilePath: windowsPromptFilePath,
|
|
82
|
+
error: error instanceof Error ? error.message : String(error),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const args = buildKimiCliArgs(opts.prompt, opts.model);
|
|
87
|
+
const executableInfo = this.deps.describeExecutableResolution('kimi', {
|
|
88
|
+
platform: () => (isWindows ? 'win32' : this.deps.platform()),
|
|
89
|
+
});
|
|
90
|
+
logger.info('Runner prompt prepared', {
|
|
91
|
+
triggerId: opts.triggerId,
|
|
92
|
+
promptLength: opts.prompt.length,
|
|
93
|
+
requestedCommand: executableInfo.requestedCommand,
|
|
94
|
+
resolvedExecutablePath,
|
|
95
|
+
platform: executableInfo.platform,
|
|
96
|
+
shell: false,
|
|
97
|
+
detached: !isWindows,
|
|
98
|
+
windowsWrapper: isWindows ? 'powershell.exe -EncodedCommand' : null,
|
|
99
|
+
});
|
|
100
|
+
const env = {
|
|
101
|
+
...process.env,
|
|
102
|
+
AGENTTEAMS_API_KEY: opts.apiKey,
|
|
103
|
+
AGENTTEAMS_API_URL: opts.apiUrl,
|
|
104
|
+
AGENTTEAMS_TEAM_ID: opts.teamId,
|
|
105
|
+
AGENTTEAMS_PROJECT_ID: opts.projectId,
|
|
106
|
+
AGENTTEAMS_AGENT_NAME: opts.agentConfigId,
|
|
107
|
+
};
|
|
108
|
+
let child;
|
|
109
|
+
try {
|
|
110
|
+
child = isWindows
|
|
111
|
+
? this.deps.spawn('powershell.exe', [
|
|
112
|
+
'-NoLogo',
|
|
113
|
+
'-NonInteractive',
|
|
114
|
+
'-ExecutionPolicy',
|
|
115
|
+
'Bypass',
|
|
116
|
+
'-EncodedCommand',
|
|
117
|
+
toKimiPowerShellEncodedCommand(resolvedExecutablePath, windowsPromptFilePath ?? '', opts.model),
|
|
118
|
+
], { cwd, detached: false, shell: false, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'], env })
|
|
119
|
+
: this.deps.spawn(resolvedExecutablePath, args, {
|
|
120
|
+
cwd,
|
|
121
|
+
detached: true,
|
|
122
|
+
shell: false,
|
|
123
|
+
windowsHide: true,
|
|
124
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
125
|
+
env,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
await removeWindowsPromptFile();
|
|
130
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
131
|
+
logger.error('Runner process launch failed', { triggerId: opts.triggerId, error: message });
|
|
132
|
+
return { exitCode: 1, errorMessage: message };
|
|
133
|
+
}
|
|
134
|
+
const logStream = this.deps.createWriteStream(logPath, { flags: 'a' });
|
|
135
|
+
logStream.on('error', (error) => logger.warn('Runner log stream error', { triggerId: opts.triggerId, error: error.message }));
|
|
136
|
+
child.stdout?.pipe(logStream);
|
|
137
|
+
child.stderr?.pipe(logStream);
|
|
138
|
+
let lastOutput = '';
|
|
139
|
+
let outputText = '';
|
|
140
|
+
const appendOutputText = (chunk) => {
|
|
141
|
+
if (outputText.length < OUTPUT_CAPTURE_MAX) {
|
|
142
|
+
outputText += chunk.slice(0, OUTPUT_CAPTURE_MAX - outputText.length);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const idleTimer = { reset: () => { } };
|
|
146
|
+
child.stdout?.on('data', (chunk) => {
|
|
147
|
+
const rawOutput = Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk);
|
|
148
|
+
appendOutputText(rawOutput);
|
|
149
|
+
const output = toOutputPreview(rawOutput);
|
|
150
|
+
if (output.length > 0) {
|
|
151
|
+
lastOutput = output;
|
|
152
|
+
idleTimer.reset();
|
|
153
|
+
opts.onStdoutChunk?.(output);
|
|
154
|
+
logger.info('Runner stdout', { triggerId: opts.triggerId, pid: child.pid, output });
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
child.stderr?.on('data', (chunk) => {
|
|
158
|
+
const rawOutput = Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk);
|
|
159
|
+
const output = toOutputPreview(rawOutput);
|
|
160
|
+
if (output.length > 0) {
|
|
161
|
+
idleTimer.reset();
|
|
162
|
+
// Kimi sends thinking/tool progress to stderr during successful print-mode runs.
|
|
163
|
+
// Keep the raw stream in the runner log, but do not expose it as an error or result.
|
|
164
|
+
logger.info('Kimi CLI progress', { triggerId: opts.triggerId, pid: child.pid, output });
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
logger.info('Runner started', { triggerId: opts.triggerId, cwd, logPath, pid: child.pid });
|
|
168
|
+
return await new Promise((resolve) => {
|
|
169
|
+
let finished = false;
|
|
170
|
+
let timedOut = false;
|
|
171
|
+
let idleTimedOut = false;
|
|
172
|
+
let cancelled = false;
|
|
173
|
+
let idleTimeoutId = null;
|
|
174
|
+
const startIdleTimeout = () => {
|
|
175
|
+
if (idleTimeoutId)
|
|
176
|
+
clearTimeout(idleTimeoutId);
|
|
177
|
+
idleTimeoutId = setTimeout(() => {
|
|
178
|
+
idleTimedOut = true;
|
|
179
|
+
timedOut = true;
|
|
180
|
+
logger.warn('Runner idle timeout reached; no output for configured idle period', {
|
|
181
|
+
triggerId: opts.triggerId,
|
|
182
|
+
idleTimeoutMs: opts.idleTimeoutMs,
|
|
183
|
+
});
|
|
184
|
+
this.deps.terminateRunnerChild(child, isWindows, opts.triggerId, 'timeout');
|
|
185
|
+
}, opts.idleTimeoutMs);
|
|
186
|
+
};
|
|
187
|
+
idleTimer.reset = startIdleTimeout;
|
|
188
|
+
startIdleTimeout();
|
|
189
|
+
const handleAbort = () => {
|
|
190
|
+
cancelled = true;
|
|
191
|
+
this.deps.terminateRunnerChild(child, isWindows, opts.triggerId, 'cancel');
|
|
192
|
+
};
|
|
193
|
+
const cleanup = async () => {
|
|
194
|
+
if (finished)
|
|
195
|
+
return;
|
|
196
|
+
finished = true;
|
|
197
|
+
if (idleTimeoutId)
|
|
198
|
+
clearTimeout(idleTimeoutId);
|
|
199
|
+
idleTimer.reset = () => { };
|
|
200
|
+
logStream.end();
|
|
201
|
+
await removeWindowsPromptFile();
|
|
202
|
+
opts.signal?.removeEventListener('abort', handleAbort);
|
|
203
|
+
};
|
|
204
|
+
const timeoutId = setTimeout(() => {
|
|
205
|
+
timedOut = true;
|
|
206
|
+
this.deps.terminateRunnerChild(child, isWindows, opts.triggerId, 'timeout');
|
|
207
|
+
}, opts.timeoutMs);
|
|
208
|
+
if (opts.signal?.aborted)
|
|
209
|
+
handleAbort();
|
|
210
|
+
else
|
|
211
|
+
opts.signal?.addEventListener('abort', handleAbort, { once: true });
|
|
212
|
+
child.on('error', async (error) => {
|
|
213
|
+
clearTimeout(timeoutId);
|
|
214
|
+
await cleanup();
|
|
215
|
+
logger.error('Runner process launch failed', { triggerId: opts.triggerId, error: error.message });
|
|
216
|
+
resolve({ exitCode: 1, lastOutput, outputText: outputText.trim() || undefined, errorMessage: error.message });
|
|
217
|
+
});
|
|
218
|
+
const closeWatchdog = this.deps.setupCloseWatchdog(child, opts.triggerId);
|
|
219
|
+
child.on('close', async (code) => {
|
|
220
|
+
closeWatchdog.cancel();
|
|
221
|
+
clearTimeout(timeoutId);
|
|
222
|
+
await cleanup();
|
|
223
|
+
logger.info('Runner process closed', { triggerId: opts.triggerId, pid: child.pid, exitCode: code, timedOut });
|
|
224
|
+
const finalizedOutputText = outputText.trim() || undefined;
|
|
225
|
+
if (timedOut) {
|
|
226
|
+
resolve({
|
|
227
|
+
exitCode: 1,
|
|
228
|
+
idleTimedOut,
|
|
229
|
+
lastOutput,
|
|
230
|
+
outputText: finalizedOutputText,
|
|
231
|
+
errorMessage: idleTimedOut
|
|
232
|
+
? `Runner idle timed out after ${Math.round(opts.idleTimeoutMs / 60_000)}m of no output`
|
|
233
|
+
: `Runner fail-safe timed out after ${Math.round(opts.timeoutMs / 3_600_000)}h`,
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (cancelled) {
|
|
238
|
+
resolve({
|
|
239
|
+
exitCode: 1,
|
|
240
|
+
cancelled: true,
|
|
241
|
+
lastOutput,
|
|
242
|
+
outputText: finalizedOutputText,
|
|
243
|
+
errorMessage: 'Runner cancelled by user',
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
resolve({
|
|
248
|
+
exitCode: code ?? 1,
|
|
249
|
+
lastOutput,
|
|
250
|
+
outputText: finalizedOutputText,
|
|
251
|
+
errorMessage: code === 0 ? undefined : `Runner exited with code ${code ?? 1}`,
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=kimi-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kimi-cli.js","sourceRoot":"","sources":["../../src/runners/kimi-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { PassThrough } from 'node:stream';
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import test from 'node:test';
|
|
5
|
+
import { buildKimiCliArgs, getKimiExecutablePreference, KimiCliRunner, toKimiPowerShellEncodedCommand, } from './kimi-cli.js';
|
|
6
|
+
test('buildKimiCliArgs uses Kimi print mode without approval bypass flags', () => {
|
|
7
|
+
assert.deepEqual(buildKimiCliArgs('hello', null), ['-p', 'hello']);
|
|
8
|
+
assert.deepEqual(buildKimiCliArgs('hello', 'default'), ['-p', 'hello']);
|
|
9
|
+
assert.deepEqual(buildKimiCliArgs('hello', 'k3'), ['-p', 'hello', '-m', 'k3']);
|
|
10
|
+
});
|
|
11
|
+
test('uses platform-specific Kimi executable preferences', () => {
|
|
12
|
+
assert.deepEqual(getKimiExecutablePreference(false), ['kimi']);
|
|
13
|
+
assert.deepEqual(getKimiExecutablePreference(true), ['kimi.cmd', 'kimi']);
|
|
14
|
+
});
|
|
15
|
+
const decodePowerShellCommand = (encoded) => Buffer.from(encoded, 'base64').toString('utf16le');
|
|
16
|
+
test('toKimiPowerShellEncodedCommand reads the prompt from a file and preserves Kimi arguments', () => {
|
|
17
|
+
const script = decodePowerShellCommand(toKimiPowerShellEncodedCommand('C:/kimi.cmd', 'C:/repo/.agentteams/runner/tmp/trigger.prompt.txt', 'k3'));
|
|
18
|
+
assert.match(script, /\[System\.IO\.File\]::ReadAllText/);
|
|
19
|
+
assert.match(script, /'-p' \$promptText '-m' 'k3'/);
|
|
20
|
+
assert.doesNotMatch(script, /--yolo|--auto|--plan/);
|
|
21
|
+
});
|
|
22
|
+
test('toKimiPowerShellEncodedCommand omits the default model', () => {
|
|
23
|
+
const script = decodePowerShellCommand(toKimiPowerShellEncodedCommand('C:/kimi.cmd', 'C:/repo/.agentteams/runner/tmp/trigger.prompt.txt', 'default'));
|
|
24
|
+
assert.match(script, /'-p' \$promptText/);
|
|
25
|
+
assert.doesNotMatch(script, /-m/);
|
|
26
|
+
});
|
|
27
|
+
const createFakeChild = () => {
|
|
28
|
+
const child = new EventEmitter();
|
|
29
|
+
child.pid = 4242;
|
|
30
|
+
child.stdout = new PassThrough();
|
|
31
|
+
child.stderr = new PassThrough();
|
|
32
|
+
return child;
|
|
33
|
+
};
|
|
34
|
+
test('KimiCliRunner launches print mode and captures text output', async () => {
|
|
35
|
+
const child = createFakeChild();
|
|
36
|
+
const spawned = [];
|
|
37
|
+
const runner = new KimiCliRunner({
|
|
38
|
+
platform: () => 'linux',
|
|
39
|
+
resolveExecutablePathWithPreference: (() => '/usr/local/bin/kimi'),
|
|
40
|
+
describeExecutableResolution: (() => ({
|
|
41
|
+
requestedCommand: 'kimi',
|
|
42
|
+
resolvedExecutablePath: '/usr/local/bin/kimi',
|
|
43
|
+
platform: 'linux',
|
|
44
|
+
shell: false,
|
|
45
|
+
})),
|
|
46
|
+
mkdir: (async () => undefined),
|
|
47
|
+
createWriteStream: (() => new PassThrough()),
|
|
48
|
+
setupCloseWatchdog: (() => ({ cancel: () => { } })),
|
|
49
|
+
spawn: ((command, args, options) => {
|
|
50
|
+
spawned.push({ command, args, options });
|
|
51
|
+
queueMicrotask(() => {
|
|
52
|
+
child.stdout.emit('data', Buffer.from('Kimi result'));
|
|
53
|
+
child.stderr.emit('data', Buffer.from('tool progress'));
|
|
54
|
+
child.emit('close', 0);
|
|
55
|
+
});
|
|
56
|
+
return child;
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
const options = {
|
|
60
|
+
triggerId: 'trigger-kimi',
|
|
61
|
+
prompt: 'hello',
|
|
62
|
+
authPath: '/repo',
|
|
63
|
+
apiKey: 'key',
|
|
64
|
+
apiUrl: 'https://api.example.com',
|
|
65
|
+
teamId: 'team',
|
|
66
|
+
projectId: 'project',
|
|
67
|
+
timeoutMs: 1_000,
|
|
68
|
+
idleTimeoutMs: 1_000,
|
|
69
|
+
agentConfigId: 'agent',
|
|
70
|
+
model: 'k3',
|
|
71
|
+
onStderrChunk: () => assert.fail('Kimi stderr progress must not be reported as an error chunk'),
|
|
72
|
+
};
|
|
73
|
+
const result = await runner.run(options);
|
|
74
|
+
assert.equal(result.exitCode, 0);
|
|
75
|
+
assert.equal(result.outputText, 'Kimi result');
|
|
76
|
+
assert.equal(spawned[0]?.command, '/usr/local/bin/kimi');
|
|
77
|
+
assert.deepEqual(spawned[0]?.args, ['-p', 'hello', '-m', 'k3']);
|
|
78
|
+
assert.equal(spawned[0]?.options.windowsHide, true);
|
|
79
|
+
});
|
|
80
|
+
test('does not use Kimi stderr progress as fallback output or error', async () => {
|
|
81
|
+
const child = createFakeChild();
|
|
82
|
+
const runner = new KimiCliRunner({
|
|
83
|
+
platform: () => 'linux',
|
|
84
|
+
resolveExecutablePathWithPreference: (() => '/usr/local/bin/kimi'),
|
|
85
|
+
describeExecutableResolution: (() => ({
|
|
86
|
+
requestedCommand: 'kimi',
|
|
87
|
+
resolvedExecutablePath: '/usr/local/bin/kimi',
|
|
88
|
+
platform: 'linux',
|
|
89
|
+
shell: false,
|
|
90
|
+
})),
|
|
91
|
+
mkdir: (async () => undefined),
|
|
92
|
+
createWriteStream: (() => new PassThrough()),
|
|
93
|
+
setupCloseWatchdog: (() => ({ cancel: () => { } })),
|
|
94
|
+
spawn: (() => {
|
|
95
|
+
queueMicrotask(() => {
|
|
96
|
+
child.stderr.emit('data', Buffer.from('resuming session'));
|
|
97
|
+
child.emit('close', 17);
|
|
98
|
+
});
|
|
99
|
+
return child;
|
|
100
|
+
}),
|
|
101
|
+
});
|
|
102
|
+
const result = await runner.run({
|
|
103
|
+
triggerId: 'trigger-kimi-error',
|
|
104
|
+
prompt: 'hello',
|
|
105
|
+
authPath: '/repo',
|
|
106
|
+
apiKey: 'key',
|
|
107
|
+
apiUrl: 'https://api.example.com',
|
|
108
|
+
teamId: 'team',
|
|
109
|
+
projectId: 'project',
|
|
110
|
+
timeoutMs: 1_000,
|
|
111
|
+
idleTimeoutMs: 1_000,
|
|
112
|
+
agentConfigId: 'agent',
|
|
113
|
+
});
|
|
114
|
+
assert.equal(result.outputText, undefined);
|
|
115
|
+
assert.equal(result.lastOutput, '');
|
|
116
|
+
assert.equal(result.errorMessage, 'Runner exited with code 17');
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=kimi-cli.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kimi-cli.test.js","sourceRoot":"","sources":["../../src/runners/kimi-cli.test.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -92,6 +92,8 @@ export type TriggerRuntime = {
|
|
|
92
92
|
attachments?: TriggerRuntimeAttachment[];
|
|
93
93
|
parentHistoryMarkdown: string | null;
|
|
94
94
|
useWorktree: boolean;
|
|
95
|
+
repositoryId?: string | null;
|
|
96
|
+
repositoryRemoteUrl?: string | null;
|
|
95
97
|
baseBranch: string | null;
|
|
96
98
|
worktreeId: string | null;
|
|
97
99
|
conventions?: ConventionMeta[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize a git remote URL to a comparable `host[:port]/owner/repo` form.
|
|
3
|
+
*
|
|
4
|
+
* Handles scheme URLs (`https://`, `ssh://`, `git://`) and scp-like syntax
|
|
5
|
+
* (`git@host:owner/repo`). Strips user info, a trailing `.git` suffix, and
|
|
6
|
+
* trailing slashes, then lowercases the result so that the same repository
|
|
7
|
+
* registered over https matches an ssh origin (and vice versa). A non-default
|
|
8
|
+
* port stays part of the identity — self-hosted services on different ports of
|
|
9
|
+
* the same host are different servers — while protocol-default ports (https
|
|
10
|
+
* 443, ssh 22, ...) match their port-less form.
|
|
11
|
+
*/
|
|
12
|
+
export declare function normalizeRemoteUrl(rawUrl: string): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Discover member git repositories directly under a non-git project root.
|
|
15
|
+
*
|
|
16
|
+
* Judgement criteria are kept in contract with the CLI's `findMemberRepos`
|
|
17
|
+
* (cli/src/utils/projectLayout.ts): only physical directories at depth 1 are
|
|
18
|
+
* considered; hidden directories, `node_modules`, symlinked directories, and
|
|
19
|
+
* bare repositories are excluded; a candidate counts only when its canonical
|
|
20
|
+
* path is itself the top level of a git work tree. Results are sorted by path
|
|
21
|
+
* for deterministic output.
|
|
22
|
+
*/
|
|
23
|
+
export declare function findMemberRepoCandidates(rootDir: string): string[];
|
|
24
|
+
export type WorktreeAuthPathResolution = {
|
|
25
|
+
path: string;
|
|
26
|
+
} | {
|
|
27
|
+
error: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the repository to create a worktree from.
|
|
31
|
+
*
|
|
32
|
+
* If `authPath` itself is a git repository it is returned as-is. Otherwise the
|
|
33
|
+
* project repository's `remoteUrl` is matched against the `origin` remote of
|
|
34
|
+
* each member repository directly under `authPath`; exactly one match resolves
|
|
35
|
+
* to that member repository, while a missing remote URL, zero matches, or
|
|
36
|
+
* multiple matches fail with a user-facing explanation. There is no silent
|
|
37
|
+
* fallback to running on the non-git root.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveWorktreeAuthPath(authPath: string, repositoryRemoteUrl: string | null): WorktreeAuthPathResolution;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { readdirSync, realpathSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { isGitRepo } from './git-worktree.js';
|
|
5
|
+
// windowsHide 누락 시 콘솔 미부착 부모(데몬)가 git.exe를 띄울 때 콘솔 창이 노출된다.
|
|
6
|
+
function runGit(args, cwd) {
|
|
7
|
+
try {
|
|
8
|
+
const output = execFileSync('git', args, {
|
|
9
|
+
cwd,
|
|
10
|
+
encoding: 'utf8',
|
|
11
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
12
|
+
windowsHide: true,
|
|
13
|
+
});
|
|
14
|
+
const trimmed = output.trim();
|
|
15
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// 프로토콜별 기본 포트. URL은 http/https/ftp의 기본 포트를 스스로 지우지만
|
|
22
|
+
// ssh/git 같은 비표준 스킴은 지우지 않으므로 직접 비교해 제거한다.
|
|
23
|
+
const DEFAULT_PORTS = {
|
|
24
|
+
'http:': '80',
|
|
25
|
+
'https:': '443',
|
|
26
|
+
'ssh:': '22',
|
|
27
|
+
'git:': '9418',
|
|
28
|
+
'ftp:': '21',
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Normalize a git remote URL to a comparable `host[:port]/owner/repo` form.
|
|
32
|
+
*
|
|
33
|
+
* Handles scheme URLs (`https://`, `ssh://`, `git://`) and scp-like syntax
|
|
34
|
+
* (`git@host:owner/repo`). Strips user info, a trailing `.git` suffix, and
|
|
35
|
+
* trailing slashes, then lowercases the result so that the same repository
|
|
36
|
+
* registered over https matches an ssh origin (and vice versa). A non-default
|
|
37
|
+
* port stays part of the identity — self-hosted services on different ports of
|
|
38
|
+
* the same host are different servers — while protocol-default ports (https
|
|
39
|
+
* 443, ssh 22, ...) match their port-less form.
|
|
40
|
+
*/
|
|
41
|
+
export function normalizeRemoteUrl(rawUrl) {
|
|
42
|
+
const trimmed = rawUrl.trim();
|
|
43
|
+
if (!trimmed)
|
|
44
|
+
return null;
|
|
45
|
+
let host;
|
|
46
|
+
let pathname;
|
|
47
|
+
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(trimmed)) {
|
|
48
|
+
try {
|
|
49
|
+
const parsed = new URL(trimmed);
|
|
50
|
+
const defaultPort = DEFAULT_PORTS[parsed.protocol];
|
|
51
|
+
host = parsed.port && parsed.port !== defaultPort ? `${parsed.hostname}:${parsed.port}` : parsed.hostname;
|
|
52
|
+
pathname = parsed.pathname;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// scp-like syntax: [user@]host:owner/repo
|
|
60
|
+
const scpMatch = /^(?:[^@/]+@)?([^:/]+):(.+)$/.exec(trimmed);
|
|
61
|
+
if (!scpMatch)
|
|
62
|
+
return null;
|
|
63
|
+
host = scpMatch[1];
|
|
64
|
+
pathname = scpMatch[2];
|
|
65
|
+
}
|
|
66
|
+
const normalizedPath = pathname
|
|
67
|
+
.replace(/^\/+/, '')
|
|
68
|
+
.replace(/\/+$/, '')
|
|
69
|
+
.replace(/\.git$/i, '');
|
|
70
|
+
if (!host || !normalizedPath)
|
|
71
|
+
return null;
|
|
72
|
+
return `${host}/${normalizedPath}`.toLowerCase();
|
|
73
|
+
}
|
|
74
|
+
// git 출력이 상대 경로일 가능성에 대비해 CLI findMemberRepos와 같은 방식으로 절대화한다.
|
|
75
|
+
function resolveGitTopLevel(candidate) {
|
|
76
|
+
const topLevel = runGit(['rev-parse', '--show-toplevel'], candidate);
|
|
77
|
+
if (!topLevel)
|
|
78
|
+
return null;
|
|
79
|
+
return path.isAbsolute(topLevel) ? path.resolve(topLevel) : path.resolve(candidate, topLevel);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Discover member git repositories directly under a non-git project root.
|
|
83
|
+
*
|
|
84
|
+
* Judgement criteria are kept in contract with the CLI's `findMemberRepos`
|
|
85
|
+
* (cli/src/utils/projectLayout.ts): only physical directories at depth 1 are
|
|
86
|
+
* considered; hidden directories, `node_modules`, symlinked directories, and
|
|
87
|
+
* bare repositories are excluded; a candidate counts only when its canonical
|
|
88
|
+
* path is itself the top level of a git work tree. Results are sorted by path
|
|
89
|
+
* for deterministic output.
|
|
90
|
+
*/
|
|
91
|
+
export function findMemberRepoCandidates(rootDir) {
|
|
92
|
+
const root = path.resolve(rootDir);
|
|
93
|
+
let entries;
|
|
94
|
+
try {
|
|
95
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const members = [];
|
|
101
|
+
for (const entry of entries) {
|
|
102
|
+
// Dirent.isDirectory() is false for symlinks, which keeps symlinked
|
|
103
|
+
// directories out without an extra lstat call.
|
|
104
|
+
if (!entry.isDirectory())
|
|
105
|
+
continue;
|
|
106
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules')
|
|
107
|
+
continue;
|
|
108
|
+
const candidate = path.join(root, entry.name);
|
|
109
|
+
// Bare repositories have no work tree, so --show-toplevel resolves null.
|
|
110
|
+
const topLevel = resolveGitTopLevel(candidate);
|
|
111
|
+
if (!topLevel)
|
|
112
|
+
continue;
|
|
113
|
+
let canonical;
|
|
114
|
+
try {
|
|
115
|
+
canonical = realpathSync(candidate);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
// Requiring canonical equality keeps out candidates that merely live
|
|
121
|
+
// inside some other repository's work tree.
|
|
122
|
+
if (canonical !== topLevel)
|
|
123
|
+
continue;
|
|
124
|
+
members.push(candidate);
|
|
125
|
+
}
|
|
126
|
+
return members.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
127
|
+
}
|
|
128
|
+
const RUNNER_BOX_OFF_HINT = 'Turn off the runner box (worktree) option and request the run again.';
|
|
129
|
+
/**
|
|
130
|
+
* Resolve the repository to create a worktree from.
|
|
131
|
+
*
|
|
132
|
+
* If `authPath` itself is a git repository it is returned as-is. Otherwise the
|
|
133
|
+
* project repository's `remoteUrl` is matched against the `origin` remote of
|
|
134
|
+
* each member repository directly under `authPath`; exactly one match resolves
|
|
135
|
+
* to that member repository, while a missing remote URL, zero matches, or
|
|
136
|
+
* multiple matches fail with a user-facing explanation. There is no silent
|
|
137
|
+
* fallback to running on the non-git root.
|
|
138
|
+
*/
|
|
139
|
+
export function resolveWorktreeAuthPath(authPath, repositoryRemoteUrl) {
|
|
140
|
+
if (isGitRepo(authPath)) {
|
|
141
|
+
return { path: authPath };
|
|
142
|
+
}
|
|
143
|
+
if (repositoryRemoteUrl === null) {
|
|
144
|
+
return {
|
|
145
|
+
error: `Worktree requested but ${authPath} is not a git repository and the selected repository has no remote URL, ` +
|
|
146
|
+
`so a member repository cannot be resolved. ${RUNNER_BOX_OFF_HINT}`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// ProjectRepository.remoteUrl은 임의 문자열이라 credential 포함 URL
|
|
150
|
+
// (https://user:token@host/repo.git)일 수 있다. 오류는 서버 로그·트리거 로그·
|
|
151
|
+
// worktreeError로 영구 전송되므로 raw URL을 절대 보간하지 않는다 — 표시에는
|
|
152
|
+
// userinfo/query가 제거된 정규화 신원(host/owner/repo)만 사용한다.
|
|
153
|
+
const normalizedTarget = normalizeRemoteUrl(repositoryRemoteUrl);
|
|
154
|
+
if (!normalizedTarget) {
|
|
155
|
+
return {
|
|
156
|
+
error: `Worktree requested but ${authPath} is not a git repository and the selected repository remote URL ` +
|
|
157
|
+
`is not recognized. ${RUNNER_BOX_OFF_HINT}`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const matches = findMemberRepoCandidates(authPath).filter((candidate) => {
|
|
161
|
+
const origin = runGit(['remote', 'get-url', 'origin'], candidate);
|
|
162
|
+
if (!origin)
|
|
163
|
+
return false;
|
|
164
|
+
return normalizeRemoteUrl(origin) === normalizedTarget;
|
|
165
|
+
});
|
|
166
|
+
if (matches.length === 0) {
|
|
167
|
+
return {
|
|
168
|
+
error: `Worktree requested but no member repository under ${authPath} has an origin remote matching ` +
|
|
169
|
+
`${normalizedTarget}. ${RUNNER_BOX_OFF_HINT}`,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
if (matches.length > 1) {
|
|
173
|
+
return {
|
|
174
|
+
error: `Worktree requested but multiple member repositories under ${authPath} have an origin remote matching ` +
|
|
175
|
+
`${normalizedTarget} (${matches.map((match) => path.basename(match)).join(', ')}). ${RUNNER_BOX_OFF_HINT}`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return { path: matches[0] };
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=resolve-member-repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-member-repo.js","sourceRoot":"","sources":["../../src/utils/resolve-member-repo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|