@puzzmo/cli 1.0.35 → 1.0.37
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/lib/agents/codex.d.ts +2 -4
- package/lib/agents/codex.js +32 -61
- package/lib/agents/codex.js.map +1 -1
- package/lib/agents/copilot.d.ts +3 -4
- package/lib/agents/copilot.js +24 -94
- package/lib/agents/copilot.js.map +1 -1
- package/lib/commands/upload.js +41 -1
- package/lib/commands/upload.js.map +1 -1
- package/lib/util/api.d.ts +4 -0
- package/lib/util/api.js +2 -2
- package/lib/util/api.js.map +1 -1
- package/package.json +1 -3
- package/src/agents/codex.ts +37 -62
- package/src/agents/copilot.ts +27 -94
- package/src/commands/upload.ts +37 -1
- package/src/util/api.ts +12 -2
package/lib/agents/codex.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { Agent } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* user's installed `codex` CLI and reuses its ChatGPT subscription auth.
|
|
5
|
-
*/
|
|
2
|
+
/** Codex adapter — wraps the local `codex` CLI in `exec --json` mode so the
|
|
3
|
+
* user's existing ChatGPT subscription auth keeps working. */
|
|
6
4
|
export declare const codexAgent: Agent;
|
package/lib/agents/codex.js
CHANGED
|
@@ -1,92 +1,63 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* user's installed `codex` CLI and reuses its ChatGPT subscription auth.
|
|
5
|
-
*/
|
|
1
|
+
import { runStreamJsonCli } from "./stream-json-cli.js";
|
|
2
|
+
/** Codex adapter — wraps the local `codex` CLI in `exec --json` mode so the
|
|
3
|
+
* user's existing ChatGPT subscription auth keeps working. */
|
|
6
4
|
export const codexAgent = {
|
|
7
5
|
name: "codex",
|
|
8
|
-
run(input) {
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
run: (input) => runStreamJsonCli({
|
|
7
|
+
cmd: "codex",
|
|
8
|
+
buildArgs: (prompt) => ["exec", "--json", "--skip-git-repo-check", prompt],
|
|
9
|
+
parseLine: parseCodexLine,
|
|
10
|
+
}, input),
|
|
11
11
|
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/** Map one JSONL event from `codex exec --json` to an AgentEvent. Schema matches
|
|
13
|
+
* the `ThreadEvent` union in `@openai/codex-sdk`. */
|
|
14
|
+
const parseCodexLine = (line) => {
|
|
15
|
+
let event;
|
|
15
16
|
try {
|
|
16
|
-
|
|
17
|
-
workingDirectory: input.cwd ?? process.cwd(),
|
|
18
|
-
skipGitRepoCheck: true,
|
|
19
|
-
});
|
|
17
|
+
event = JSON.parse(line);
|
|
20
18
|
}
|
|
21
|
-
catch
|
|
22
|
-
|
|
23
|
-
return;
|
|
19
|
+
catch {
|
|
20
|
+
return { type: "system", text: line };
|
|
24
21
|
}
|
|
25
|
-
let streamed;
|
|
26
|
-
try {
|
|
27
|
-
streamed = await thread.runStreamed(input.prompt, { signal: input.signal });
|
|
28
|
-
}
|
|
29
|
-
catch (e) {
|
|
30
|
-
yield { type: "error", message: `Codex run failed: ${e.message}` };
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
try {
|
|
34
|
-
for await (const event of streamed.events) {
|
|
35
|
-
const mapped = mapCodexEvent(event);
|
|
36
|
-
for (const m of mapped)
|
|
37
|
-
yield m;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
yield { type: "error", message: e.message ?? String(e) };
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
const mapCodexEvent = (event) => {
|
|
46
22
|
if (event.type === "item.completed" || event.type === "item.updated") {
|
|
47
23
|
const item = event.item;
|
|
48
24
|
if (!item)
|
|
49
|
-
return
|
|
25
|
+
return null;
|
|
50
26
|
if (item.type === "agent_message" && event.type === "item.completed")
|
|
51
|
-
return
|
|
27
|
+
return { type: "text", text: appendNL(item.text ?? "") };
|
|
52
28
|
if (item.type === "reasoning" && event.type === "item.completed")
|
|
53
|
-
return
|
|
29
|
+
return { type: "thinking", text: appendNL(item.text ?? "") };
|
|
54
30
|
if (item.type === "command_execution") {
|
|
55
31
|
if (item.status === "in_progress" && event.type === "item.updated")
|
|
56
|
-
return
|
|
32
|
+
return null;
|
|
57
33
|
if (item.status === "completed" || item.status === "failed")
|
|
58
|
-
return
|
|
59
|
-
return
|
|
34
|
+
return { type: "tool_result", ok: item.status === "completed", summary: item.command ?? "" };
|
|
35
|
+
return { type: "tool_use", name: "Bash", summary: item.command ?? "" };
|
|
60
36
|
}
|
|
61
37
|
if (item.type === "file_change") {
|
|
62
38
|
const summary = (item.changes ?? []).map((c) => `${c.kind} ${c.path}`).join(", ");
|
|
63
|
-
return
|
|
39
|
+
return { type: "tool_result", ok: item.status === "completed", summary };
|
|
64
40
|
}
|
|
65
41
|
if (item.type === "mcp_tool_call") {
|
|
66
42
|
if (item.status === "in_progress")
|
|
67
|
-
return
|
|
68
|
-
return
|
|
43
|
+
return { type: "tool_use", name: `${item.server}/${item.tool}`, summary: "" };
|
|
44
|
+
return { type: "tool_result", ok: item.status === "completed", summary: item.error?.message ?? "" };
|
|
69
45
|
}
|
|
70
46
|
if (item.type === "web_search")
|
|
71
|
-
return
|
|
72
|
-
if (item.type === "todo_list")
|
|
73
|
-
return [];
|
|
47
|
+
return { type: "tool_use", name: "WebSearch", summary: item.query ?? "" };
|
|
74
48
|
if (item.type === "error")
|
|
75
|
-
return
|
|
76
|
-
return
|
|
49
|
+
return { type: "error", message: item.message ?? "" };
|
|
50
|
+
return null;
|
|
77
51
|
}
|
|
78
52
|
if (event.type === "turn.completed")
|
|
79
|
-
return
|
|
53
|
+
return { type: "result", ok: true };
|
|
80
54
|
if (event.type === "turn.failed")
|
|
81
|
-
return
|
|
82
|
-
{ type: "error", message: event.error?.message ?? "turn failed" },
|
|
83
|
-
{ type: "result", ok: false },
|
|
84
|
-
];
|
|
55
|
+
return { type: "error", message: event.error?.message ?? "turn failed" };
|
|
85
56
|
if (event.type === "thread.started")
|
|
86
|
-
return
|
|
57
|
+
return { type: "system", text: "Thread started" };
|
|
87
58
|
if (event.type === "error")
|
|
88
|
-
return
|
|
89
|
-
return
|
|
59
|
+
return { type: "error", message: event.message ?? "" };
|
|
60
|
+
return null;
|
|
90
61
|
};
|
|
91
62
|
const appendNL = (s) => (s.endsWith("\n") ? s : s + "\n");
|
|
92
63
|
//# sourceMappingURL=codex.js.map
|
package/lib/agents/codex.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/agents/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/agents/codex.ts"],"names":[],"mappings":"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"}
|
package/lib/agents/copilot.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Agent } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
2
|
+
/** Copilot adapter — wraps the local `copilot` CLI (`@github/copilot`) in
|
|
3
|
+
* `--output-format json` mode so the user's existing OAuth/Copilot Pro
|
|
4
|
+
* subscription auth keeps working. */
|
|
6
5
|
export declare const copilotAgent: Agent;
|
package/lib/agents/copilot.js
CHANGED
|
@@ -1,115 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
1
|
+
import { runStreamJsonCli } from "./stream-json-cli.js";
|
|
2
|
+
/** Copilot adapter — wraps the local `copilot` CLI (`@github/copilot`) in
|
|
3
|
+
* `--output-format json` mode so the user's existing OAuth/Copilot Pro
|
|
4
|
+
* subscription auth keeps working. */
|
|
6
5
|
export const copilotAgent = {
|
|
7
6
|
name: "copilot",
|
|
8
|
-
run(input) {
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
run: (input) => runStreamJsonCli({
|
|
8
|
+
cmd: "copilot",
|
|
9
|
+
buildArgs: (prompt) => ["-p", prompt, "--output-format", "json", "--stream", "on", "--allow-all-tools"],
|
|
10
|
+
parseLine: parseCopilotLine,
|
|
11
|
+
}, input),
|
|
11
12
|
};
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
/** Map one JSONL event from `copilot --output-format json` to an AgentEvent.
|
|
14
|
+
* Schema: `node_modules/@github/copilot/schemas/session-events.schema.json`. */
|
|
15
|
+
const parseCopilotLine = (line) => {
|
|
16
|
+
let event;
|
|
14
17
|
try {
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
catch (e) {
|
|
18
|
-
yield { type: "error", message: `Copilot client failed to start: ${e.message}` };
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
const events = [];
|
|
22
|
-
let waiting = null;
|
|
23
|
-
const push = (e) => {
|
|
24
|
-
events.push(e);
|
|
25
|
-
waiting?.();
|
|
26
|
-
waiting = null;
|
|
27
|
-
};
|
|
28
|
-
let session;
|
|
29
|
-
try {
|
|
30
|
-
session = await client.createSession({
|
|
31
|
-
streaming: true,
|
|
32
|
-
workingDirectory: input.cwd ?? process.cwd(),
|
|
33
|
-
onPermissionRequest: approveAll,
|
|
34
|
-
onEvent: (event) => {
|
|
35
|
-
const mapped = mapCopilotEvent(event);
|
|
36
|
-
for (const m of mapped)
|
|
37
|
-
push(m);
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
yield { type: "error", message: `Copilot session creation failed: ${e.message}` };
|
|
43
|
-
await safeStop(client);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const cancel = () => {
|
|
47
|
-
session.disconnect().catch(() => { });
|
|
48
|
-
};
|
|
49
|
-
if (input.signal)
|
|
50
|
-
input.signal.addEventListener("abort", cancel);
|
|
51
|
-
let runError = null;
|
|
52
|
-
let runDone = false;
|
|
53
|
-
session
|
|
54
|
-
.sendAndWait({ prompt: input.prompt }, 600_000)
|
|
55
|
-
.catch((e) => {
|
|
56
|
-
runError = e;
|
|
57
|
-
})
|
|
58
|
-
.finally(() => {
|
|
59
|
-
runDone = true;
|
|
60
|
-
waiting?.();
|
|
61
|
-
waiting = null;
|
|
62
|
-
});
|
|
63
|
-
try {
|
|
64
|
-
while (true) {
|
|
65
|
-
if (events.length > 0) {
|
|
66
|
-
yield events.shift();
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (runDone) {
|
|
70
|
-
if (runError)
|
|
71
|
-
yield { type: "error", message: runError.message };
|
|
72
|
-
yield { type: "result", ok: !runError };
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
await new Promise((r) => (waiting = r));
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
await session.disconnect().catch(() => { });
|
|
80
|
-
await safeStop(client);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
const safeStop = async (client) => {
|
|
84
|
-
try {
|
|
85
|
-
await client.stop();
|
|
18
|
+
event = JSON.parse(line);
|
|
86
19
|
}
|
|
87
20
|
catch {
|
|
88
|
-
|
|
21
|
+
return { type: "system", text: line };
|
|
89
22
|
}
|
|
90
|
-
};
|
|
91
|
-
const mapCopilotEvent = (event) => {
|
|
92
23
|
if (event.type === "assistant.message_delta")
|
|
93
|
-
return
|
|
24
|
+
return { type: "text", text: event.data?.deltaContent ?? "" };
|
|
94
25
|
if (event.type === "assistant.reasoning_delta")
|
|
95
|
-
return
|
|
26
|
+
return { type: "thinking", text: event.data?.deltaContent ?? event.data?.delta ?? "" };
|
|
96
27
|
if (event.type === "tool.execution_start") {
|
|
97
28
|
const name = event.data?.toolName ?? "tool";
|
|
98
|
-
|
|
99
|
-
return [{ type: "tool_use", name, summary: summarizeToolArgs(name, args) }];
|
|
29
|
+
return { type: "tool_use", name, summary: summarizeToolArgs(event.data?.arguments) };
|
|
100
30
|
}
|
|
101
31
|
if (event.type === "tool.execution_complete") {
|
|
102
32
|
const ok = event.data?.success === true;
|
|
103
33
|
const summary = event.data?.result?.content?.slice(0, 200) ?? event.data?.error?.message ?? "";
|
|
104
|
-
return
|
|
34
|
+
return { type: "tool_result", ok, summary };
|
|
105
35
|
}
|
|
106
36
|
if (event.type === "session.error")
|
|
107
|
-
return
|
|
108
|
-
if (event.type === "
|
|
109
|
-
return
|
|
110
|
-
return
|
|
37
|
+
return { type: "error", message: event.data?.message ?? "session error" };
|
|
38
|
+
if (event.type === "assistant.turn_end")
|
|
39
|
+
return { type: "result", ok: true };
|
|
40
|
+
return null;
|
|
111
41
|
};
|
|
112
|
-
const summarizeToolArgs = (
|
|
42
|
+
const summarizeToolArgs = (args) => {
|
|
113
43
|
if (!args || typeof args !== "object")
|
|
114
44
|
return "";
|
|
115
45
|
if (typeof args.command === "string")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../src/agents/copilot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../src/agents/copilot.ts"],"names":[],"mappings":"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"}
|
package/lib/commands/upload.js
CHANGED
|
@@ -49,8 +49,14 @@ export const upload = async (dir, options = {}) => {
|
|
|
49
49
|
const gameSlug = puzzmoFile.game.slug;
|
|
50
50
|
// Determine SHA
|
|
51
51
|
const sha = getGitSHA() || hashFiles(files);
|
|
52
|
+
const description = getGitMessage();
|
|
53
|
+
const repoURL = getGitRepoURL();
|
|
52
54
|
console.log(`\nUploading ${gameSlug} (${sha.slice(0, 8)})`);
|
|
53
55
|
console.log(`Directory: ${distDir}`);
|
|
56
|
+
if (description)
|
|
57
|
+
console.log(`Message: ${description}`);
|
|
58
|
+
if (repoURL)
|
|
59
|
+
console.log(`Repo: ${repoURL}`);
|
|
54
60
|
console.log("");
|
|
55
61
|
let totalBytes = 0;
|
|
56
62
|
for (const file of files) {
|
|
@@ -68,7 +74,7 @@ export const upload = async (dir, options = {}) => {
|
|
|
68
74
|
console.log("Uploading...");
|
|
69
75
|
const result = await uploadFiles(token, gameSlug, sha, files, distDir, puzzmoFile, (batch, totalBatches, uploaded) => {
|
|
70
76
|
console.log(` Batch ${batch}/${totalBatches} done (${uploaded} file(s) uploaded)`);
|
|
71
|
-
}, { verbose });
|
|
77
|
+
}, { verbose, description, repoURL });
|
|
72
78
|
console.log(`\nDone - ${result.versionID}`);
|
|
73
79
|
console.log(`Assets: ${result.assetsBase}`);
|
|
74
80
|
};
|
|
@@ -94,6 +100,40 @@ const getGitSHA = () => {
|
|
|
94
100
|
return null;
|
|
95
101
|
}
|
|
96
102
|
};
|
|
103
|
+
/** Gets the subject line of the latest commit, or null if not in a git repo */
|
|
104
|
+
const getGitMessage = () => {
|
|
105
|
+
try {
|
|
106
|
+
return execSync("git log -1 --pretty=%s", { encoding: "utf-8" }).trim() || null;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
/** Gets the origin remote URL normalized to https, or null if unavailable */
|
|
113
|
+
const getGitRepoURL = () => {
|
|
114
|
+
try {
|
|
115
|
+
const raw = execSync("git config --get remote.origin.url", { encoding: "utf-8" }).trim();
|
|
116
|
+
return raw ? normalizeRepoURL(raw) : null;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
/** Converts SSH-style git URLs to https; strips trailing .git */
|
|
123
|
+
const normalizeRepoURL = (url) => {
|
|
124
|
+
let normalized = url;
|
|
125
|
+
// git@host:owner/repo(.git) -> https://host/owner/repo
|
|
126
|
+
const sshMatch = normalized.match(/^git@([^:]+):(.+)$/);
|
|
127
|
+
if (sshMatch)
|
|
128
|
+
normalized = `https://${sshMatch[1]}/${sshMatch[2]}`;
|
|
129
|
+
// ssh://git@host/owner/repo(.git) -> https://host/owner/repo
|
|
130
|
+
else if (normalized.startsWith("ssh://"))
|
|
131
|
+
normalized = normalized.replace(/^ssh:\/\/(?:[^@]+@)?/, "https://");
|
|
132
|
+
// git://host/owner/repo(.git) -> https://host/owner/repo
|
|
133
|
+
else if (normalized.startsWith("git://"))
|
|
134
|
+
normalized = normalized.replace(/^git:\/\//, "https://");
|
|
135
|
+
return normalized.replace(/\.git$/, "");
|
|
136
|
+
};
|
|
97
137
|
/** Hashes all file contents to produce a deterministic SHA */
|
|
98
138
|
const hashFiles = (filePaths) => {
|
|
99
139
|
const hash = crypto.createHash("sha256");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"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"}
|
package/lib/util/api.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export type UploadProgress = (batch: number, totalBatches: number, uploaded: num
|
|
|
17
17
|
/** Options for uploadFiles */
|
|
18
18
|
export type UploadFilesOptions = {
|
|
19
19
|
verbose?: boolean;
|
|
20
|
+
/** Commit message subject for the new GameRuntimeVersion */
|
|
21
|
+
description?: string | null;
|
|
22
|
+
/** HTTPS repo URL to set on the GameRuntime */
|
|
23
|
+
repoURL?: string | null;
|
|
20
24
|
};
|
|
21
25
|
/** Multi-step upload: init -> batched file uploads -> complete */
|
|
22
26
|
export declare const uploadFiles: (token: string, gameSlug: string, sha: string, filePaths: string[], baseDir: string, puzzmoFile: PuzzmoFile, onProgress?: UploadProgress | undefined, options?: UploadFilesOptions) => Promise<CompleteResponse>;
|
package/lib/util/api.js
CHANGED
|
@@ -68,12 +68,12 @@ const uploadFile = async (url, token, filePath, baseDir, verbose) => {
|
|
|
68
68
|
};
|
|
69
69
|
/** Multi-step upload: init -> batched file uploads -> complete */
|
|
70
70
|
export const uploadFiles = async (token, gameSlug, sha, filePaths, baseDir, puzzmoFile, onProgress, options = {}) => {
|
|
71
|
-
const { verbose = false } = options;
|
|
71
|
+
const { verbose = false, description, repoURL } = options;
|
|
72
72
|
const apiURL = getAPIURL();
|
|
73
73
|
if (verbose)
|
|
74
74
|
console.log(` API URL: ${apiURL}`);
|
|
75
75
|
// Step 1: Init session (includes puzzmo.json metadata)
|
|
76
|
-
const init = (await jsonPost(`${apiURL}/cliUpload`, token, { gameSlug, sha, puzzmoFile }, "upload init", verbose));
|
|
76
|
+
const init = (await jsonPost(`${apiURL}/cliUpload`, token, { gameSlug, sha, puzzmoFile, description, repoURL }, "upload init", verbose));
|
|
77
77
|
if (verbose)
|
|
78
78
|
console.log(` session: ${init.sessionID}`);
|
|
79
79
|
// Step 2: Upload files in concurrent batches
|
package/lib/util/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/util/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAYvC,MAAM,UAAU,GAAG,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/util/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAYvC,MAAM,UAAU,GAAG,EAAE,CAAA;AAkBrB,yFAAyF;AACzF,MAAM,gBAAgB,GAAG,KAAK,EAAE,GAAW,EAAE,IAAiB,EAAE,IAAY,EAAE,OAAgB,EAAqB,EAAE,CAAC;IACpH,IAAI,OAAO;QAAE,OAAO,CAAC,GAAG,CAAC,SAAO,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAA;IACxE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QAClC,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,SAAO,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI,GAAG,CAAC,CAAA;QACzE,OAAO,GAAG,CAAA;IACZ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,KAAK,GAAI,CAAyB,CAAC,KAAK,CAAA;QAC9C,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,CAAW,CAAC,OAAO,CAAA;QACtG,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QACpE,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC,CAAA;IACvE,CAAC;AAAA,CACF,CAAA;AAED,8FAA8F;AAC9F,MAAM,YAAY,GAAG,KAAK,EAAE,GAAa,EAAE,GAAW,EAAE,IAAY,EAAE,OAAgB,EAAE,EAAE,CAAC;IACzF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;IAC7B,IAAI,IAAa,CAAA;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;YAC/E,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,KAAK,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,SAAS,GAAG,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC,CAAA;QACvH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,KAAK,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;IAC1G,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,SAAS,GAAI,IAA2B,CAAC,KAAK,IAAI,GAAG,CAAC,UAAU,IAAI,eAAe,CAAA;QACzF,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAClE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,KAAK,GAAG,CAAC,MAAM,SAAS,GAAG,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,CAAA;IACnG,CAAC;IACD,OAAO,IAAI,CAAA;AAAA,CACZ,CAAA;AAED,gCAAgC;AAChC,MAAM,QAAQ,GAAG,KAAK,EAAE,GAAW,EAAE,KAAa,EAAE,IAAY,EAAE,IAAY,EAAE,OAAgB,EAAE,EAAE,CAAC;IACnG,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAChC,GAAG,EACH;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QACjF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,EACD,IAAI,EACJ,OAAO,CACR,CAAA;IACD,OAAO,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;AAAA,CAC7C,CAAA;AAED,uEAAuE;AACvE,MAAM,UAAU,GAAG,KAAK,EAAE,GAAW,EAAE,KAAa,EAAE,QAAgB,EAAE,OAAe,EAAE,OAAgB,EAAyB,EAAE,CAAC;IACnI,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IACrD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;IACzC,MAAM,IAAI,GAAG,gBAAgB,YAAY,GAAG,CAAA;IAE5C,MAAM,OAAO,GAAG,GAAG,GAAG,SAAS,kBAAkB,CAAC,YAAY,CAAC,EAAE,CAAA;IACjE,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAChC,OAAO,EACP;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,KAAK,EAAE;YAChC,cAAc,EAAE,0BAA0B;SAC3C;QACD,IAAI,EAAE,OAAO;KACd,EACD,IAAI,EACJ,OAAO,CACR,CAAA;IACD,OAAO,CAAC,MAAM,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAiB,CAAA;AAAA,CACzE,CAAA;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC9B,KAAa,EACb,QAAgB,EAChB,GAAW,EACX,SAAmB,EACnB,OAAe,EACf,UAAsB,EACtB,UAA2B,EAC3B,OAAO,GAAuB,EAAE,EACL,EAAE,CAAC;IAC9B,MAAM,EAAE,OAAO,GAAG,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IACzD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,IAAI,OAAO;QAAE,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,EAAE,CAAC,CAAA;IAEhD,uDAAuD;IACvD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAC1B,GAAG,MAAM,YAAY,EACrB,KAAK,EACL,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,EACnD,aAAa,EACb,OAAO,CACR,CAAiB,CAAA;IAClB,IAAI,OAAO;QAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;IAExD,6CAA6C;IAC7C,MAAM,OAAO,GAAG,GAAG,MAAM,cAAc,IAAI,CAAC,SAAS,OAAO,CAAA;IAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,UAAU,CAAC,CAAA;IAC7D,IAAI,aAAa,GAAG,CAAC,CAAA;IAErB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAA;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAA;QAC/C,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;QACtF,aAAa,IAAI,KAAK,CAAC,MAAM,CAAA;QAC7B,UAAU,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,aAAa,CAAC,CAAA;IACrD,CAAC;IAED,mBAAmB;IACnB,OAAO,CAAC,MAAM,QAAQ,CAAC,GAAG,MAAM,cAAc,IAAI,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAqB,CAAA;AAAA,CACrI,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puzzmo/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.37",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"puzzmo": "./lib/index.js"
|
|
@@ -23,8 +23,6 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@cfworker/json-schema": "^4.1.1",
|
|
25
25
|
"@clack/prompts": "^1.1.0",
|
|
26
|
-
"@github/copilot-sdk": "0.2.2",
|
|
27
|
-
"@openai/codex-sdk": "0.122.0",
|
|
28
26
|
"@opencode-ai/sdk": "1.14.20",
|
|
29
27
|
"@puzzmo/agent-cli-detect": "*"
|
|
30
28
|
}
|
package/src/agents/codex.ts
CHANGED
|
@@ -1,84 +1,59 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runStreamJsonCli } from "./stream-json-cli.js"
|
|
2
|
+
import type { AgentEvent, Agent } from "./types.js"
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Codex adapter — wraps `@openai/codex-sdk`, which itself shells out to the
|
|
7
|
-
* user's installed `codex` CLI and reuses its ChatGPT subscription auth.
|
|
8
|
-
*/
|
|
4
|
+
/** Codex adapter — wraps the local `codex` CLI in `exec --json` mode so the
|
|
5
|
+
* user's existing ChatGPT subscription auth keeps working. */
|
|
9
6
|
export const codexAgent: Agent = {
|
|
10
7
|
name: "codex",
|
|
11
|
-
run(input)
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
run: (input) =>
|
|
9
|
+
runStreamJsonCli(
|
|
10
|
+
{
|
|
11
|
+
cmd: "codex",
|
|
12
|
+
buildArgs: (prompt) => ["exec", "--json", "--skip-git-repo-check", prompt],
|
|
13
|
+
parseLine: parseCodexLine,
|
|
14
|
+
},
|
|
15
|
+
input,
|
|
16
|
+
),
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
/** Map one JSONL event from `codex exec --json` to an AgentEvent. Schema matches
|
|
20
|
+
* the `ThreadEvent` union in `@openai/codex-sdk`. */
|
|
21
|
+
const parseCodexLine = (line: string): AgentEvent | null => {
|
|
22
|
+
let event: any
|
|
19
23
|
try {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
})
|
|
24
|
-
} catch (e: any) {
|
|
25
|
-
yield { type: "error", message: `Failed to start codex thread: ${e.message}` }
|
|
26
|
-
return
|
|
24
|
+
event = JSON.parse(line)
|
|
25
|
+
} catch {
|
|
26
|
+
return { type: "system", text: line }
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
let streamed
|
|
30
|
-
try {
|
|
31
|
-
streamed = await thread.runStreamed(input.prompt, { signal: input.signal })
|
|
32
|
-
} catch (e: any) {
|
|
33
|
-
yield { type: "error", message: `Codex run failed: ${e.message}` }
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
for await (const event of streamed.events) {
|
|
39
|
-
const mapped = mapCodexEvent(event)
|
|
40
|
-
for (const m of mapped) yield m
|
|
41
|
-
}
|
|
42
|
-
} catch (e: any) {
|
|
43
|
-
yield { type: "error", message: e.message ?? String(e) }
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const mapCodexEvent = (event: any): AgentEvent[] => {
|
|
49
29
|
if (event.type === "item.completed" || event.type === "item.updated") {
|
|
50
30
|
const item = event.item
|
|
51
|
-
if (!item) return
|
|
52
|
-
if (item.type === "agent_message" && event.type === "item.completed") return
|
|
53
|
-
if (item.type === "reasoning" && event.type === "item.completed") return
|
|
31
|
+
if (!item) return null
|
|
32
|
+
if (item.type === "agent_message" && event.type === "item.completed") return { type: "text", text: appendNL(item.text ?? "") }
|
|
33
|
+
if (item.type === "reasoning" && event.type === "item.completed") return { type: "thinking", text: appendNL(item.text ?? "") }
|
|
54
34
|
if (item.type === "command_execution") {
|
|
55
|
-
if (item.status === "in_progress" && event.type === "item.updated") return
|
|
35
|
+
if (item.status === "in_progress" && event.type === "item.updated") return null
|
|
56
36
|
if (item.status === "completed" || item.status === "failed")
|
|
57
|
-
return
|
|
58
|
-
return
|
|
37
|
+
return { type: "tool_result", ok: item.status === "completed", summary: item.command ?? "" }
|
|
38
|
+
return { type: "tool_use", name: "Bash", summary: item.command ?? "" }
|
|
59
39
|
}
|
|
60
40
|
if (item.type === "file_change") {
|
|
61
41
|
const summary = (item.changes ?? []).map((c: any) => `${c.kind} ${c.path}`).join(", ")
|
|
62
|
-
return
|
|
42
|
+
return { type: "tool_result", ok: item.status === "completed", summary }
|
|
63
43
|
}
|
|
64
44
|
if (item.type === "mcp_tool_call") {
|
|
65
|
-
if (item.status === "in_progress") return
|
|
66
|
-
return
|
|
45
|
+
if (item.status === "in_progress") return { type: "tool_use", name: `${item.server}/${item.tool}`, summary: "" }
|
|
46
|
+
return { type: "tool_result", ok: item.status === "completed", summary: item.error?.message ?? "" }
|
|
67
47
|
}
|
|
68
|
-
if (item.type === "web_search") return
|
|
69
|
-
if (item.type === "
|
|
70
|
-
|
|
71
|
-
return []
|
|
48
|
+
if (item.type === "web_search") return { type: "tool_use", name: "WebSearch", summary: item.query ?? "" }
|
|
49
|
+
if (item.type === "error") return { type: "error", message: item.message ?? "" }
|
|
50
|
+
return null
|
|
72
51
|
}
|
|
73
|
-
if (event.type === "turn.completed") return
|
|
74
|
-
if (event.type === "turn.failed")
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
]
|
|
79
|
-
if (event.type === "thread.started") return [{ type: "system", text: "Thread started" }]
|
|
80
|
-
if (event.type === "error") return [{ type: "error", message: event.message ?? "" }]
|
|
81
|
-
return []
|
|
52
|
+
if (event.type === "turn.completed") return { type: "result", ok: true }
|
|
53
|
+
if (event.type === "turn.failed") return { type: "error", message: event.error?.message ?? "turn failed" }
|
|
54
|
+
if (event.type === "thread.started") return { type: "system", text: "Thread started" }
|
|
55
|
+
if (event.type === "error") return { type: "error", message: event.message ?? "" }
|
|
56
|
+
return null
|
|
82
57
|
}
|
|
83
58
|
|
|
84
59
|
const appendNL = (s: string) => (s.endsWith("\n") ? s : s + "\n")
|
package/src/agents/copilot.ts
CHANGED
|
@@ -1,116 +1,49 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runStreamJsonCli } from "./stream-json-cli.js"
|
|
2
|
+
import type { Agent, AgentEvent } from "./types.js"
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Copilot adapter — wraps `@github/copilot-sdk`, which spawns the bundled
|
|
7
|
-
* `@github/copilot` CLI and reuses its OAuth/Copilot Pro subscription auth.
|
|
8
|
-
*/
|
|
4
|
+
/** Copilot adapter — wraps the local `copilot` CLI (`@github/copilot`) in
|
|
5
|
+
* `--output-format json` mode so the user's existing OAuth/Copilot Pro
|
|
6
|
+
* subscription auth keeps working. */
|
|
9
7
|
export const copilotAgent: Agent = {
|
|
10
8
|
name: "copilot",
|
|
11
|
-
run(input)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const client = new CopilotClient({ cwd: input.cwd ?? process.cwd() })
|
|
18
|
-
try {
|
|
19
|
-
await client.start()
|
|
20
|
-
} catch (e: any) {
|
|
21
|
-
yield { type: "error", message: `Copilot client failed to start: ${e.message}` }
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const events: AgentEvent[] = []
|
|
26
|
-
let waiting: (() => void) | null = null
|
|
27
|
-
const push = (e: AgentEvent) => {
|
|
28
|
-
events.push(e)
|
|
29
|
-
waiting?.()
|
|
30
|
-
waiting = null
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
let session
|
|
34
|
-
try {
|
|
35
|
-
session = await client.createSession({
|
|
36
|
-
streaming: true,
|
|
37
|
-
workingDirectory: input.cwd ?? process.cwd(),
|
|
38
|
-
onPermissionRequest: approveAll,
|
|
39
|
-
onEvent: (event: any) => {
|
|
40
|
-
const mapped = mapCopilotEvent(event)
|
|
41
|
-
for (const m of mapped) push(m)
|
|
9
|
+
run: (input) =>
|
|
10
|
+
runStreamJsonCli(
|
|
11
|
+
{
|
|
12
|
+
cmd: "copilot",
|
|
13
|
+
buildArgs: (prompt) => ["-p", prompt, "--output-format", "json", "--stream", "on", "--allow-all-tools"],
|
|
14
|
+
parseLine: parseCopilotLine,
|
|
42
15
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
yield { type: "error", message: `Copilot session creation failed: ${e.message}` }
|
|
46
|
-
await safeStop(client)
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const cancel = () => {
|
|
51
|
-
session.disconnect().catch(() => {})
|
|
52
|
-
}
|
|
53
|
-
if (input.signal) input.signal.addEventListener("abort", cancel)
|
|
54
|
-
|
|
55
|
-
let runError = null as Error | null
|
|
56
|
-
let runDone = false
|
|
57
|
-
session
|
|
58
|
-
.sendAndWait({ prompt: input.prompt }, 600_000)
|
|
59
|
-
.catch((e: Error) => {
|
|
60
|
-
runError = e
|
|
61
|
-
})
|
|
62
|
-
.finally(() => {
|
|
63
|
-
runDone = true
|
|
64
|
-
waiting?.()
|
|
65
|
-
waiting = null
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
while (true) {
|
|
70
|
-
if (events.length > 0) {
|
|
71
|
-
yield events.shift()!
|
|
72
|
-
continue
|
|
73
|
-
}
|
|
74
|
-
if (runDone) {
|
|
75
|
-
if (runError) yield { type: "error", message: runError.message }
|
|
76
|
-
yield { type: "result", ok: !runError }
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
await new Promise<void>((r) => (waiting = r))
|
|
80
|
-
}
|
|
81
|
-
} finally {
|
|
82
|
-
await session.disconnect().catch(() => {})
|
|
83
|
-
await safeStop(client)
|
|
84
|
-
}
|
|
16
|
+
input,
|
|
17
|
+
),
|
|
85
18
|
}
|
|
86
19
|
|
|
87
|
-
|
|
20
|
+
/** Map one JSONL event from `copilot --output-format json` to an AgentEvent.
|
|
21
|
+
* Schema: `node_modules/@github/copilot/schemas/session-events.schema.json`. */
|
|
22
|
+
const parseCopilotLine = (line: string): AgentEvent | null => {
|
|
23
|
+
let event: any
|
|
88
24
|
try {
|
|
89
|
-
|
|
25
|
+
event = JSON.parse(line)
|
|
90
26
|
} catch {
|
|
91
|
-
|
|
27
|
+
return { type: "system", text: line }
|
|
92
28
|
}
|
|
93
|
-
}
|
|
94
29
|
|
|
95
|
-
|
|
96
|
-
if (event.type === "assistant.
|
|
97
|
-
if (event.type === "assistant.reasoning_delta") return [{ type: "thinking", text: event.data?.deltaContent ?? event.data?.delta ?? "" }]
|
|
30
|
+
if (event.type === "assistant.message_delta") return { type: "text", text: event.data?.deltaContent ?? "" }
|
|
31
|
+
if (event.type === "assistant.reasoning_delta") return { type: "thinking", text: event.data?.deltaContent ?? event.data?.delta ?? "" }
|
|
98
32
|
if (event.type === "tool.execution_start") {
|
|
99
33
|
const name = event.data?.toolName ?? "tool"
|
|
100
|
-
|
|
101
|
-
return [{ type: "tool_use", name, summary: summarizeToolArgs(name, args) }]
|
|
34
|
+
return { type: "tool_use", name, summary: summarizeToolArgs(event.data?.arguments) }
|
|
102
35
|
}
|
|
103
36
|
if (event.type === "tool.execution_complete") {
|
|
104
37
|
const ok = event.data?.success === true
|
|
105
38
|
const summary = event.data?.result?.content?.slice(0, 200) ?? event.data?.error?.message ?? ""
|
|
106
|
-
return
|
|
39
|
+
return { type: "tool_result", ok, summary }
|
|
107
40
|
}
|
|
108
|
-
if (event.type === "session.error") return
|
|
109
|
-
if (event.type === "
|
|
110
|
-
return
|
|
41
|
+
if (event.type === "session.error") return { type: "error", message: event.data?.message ?? "session error" }
|
|
42
|
+
if (event.type === "assistant.turn_end") return { type: "result", ok: true }
|
|
43
|
+
return null
|
|
111
44
|
}
|
|
112
45
|
|
|
113
|
-
const summarizeToolArgs = (
|
|
46
|
+
const summarizeToolArgs = (args: any): string => {
|
|
114
47
|
if (!args || typeof args !== "object") return ""
|
|
115
48
|
if (typeof args.command === "string") return args.command.slice(0, 200)
|
|
116
49
|
if (typeof args.file_path === "string") return args.file_path
|
package/src/commands/upload.ts
CHANGED
|
@@ -59,9 +59,13 @@ export const upload = async (dir: string, options: UploadOptions = {}) => {
|
|
|
59
59
|
|
|
60
60
|
// Determine SHA
|
|
61
61
|
const sha = getGitSHA() || hashFiles(files)
|
|
62
|
+
const description = getGitMessage()
|
|
63
|
+
const repoURL = getGitRepoURL()
|
|
62
64
|
|
|
63
65
|
console.log(`\nUploading ${gameSlug} (${sha.slice(0, 8)})`)
|
|
64
66
|
console.log(`Directory: ${distDir}`)
|
|
67
|
+
if (description) console.log(`Message: ${description}`)
|
|
68
|
+
if (repoURL) console.log(`Repo: ${repoURL}`)
|
|
65
69
|
console.log("")
|
|
66
70
|
|
|
67
71
|
let totalBytes = 0
|
|
@@ -89,7 +93,7 @@ export const upload = async (dir: string, options: UploadOptions = {}) => {
|
|
|
89
93
|
(batch, totalBatches, uploaded) => {
|
|
90
94
|
console.log(` Batch ${batch}/${totalBatches} done (${uploaded} file(s) uploaded)`)
|
|
91
95
|
},
|
|
92
|
-
{ verbose },
|
|
96
|
+
{ verbose, description, repoURL },
|
|
93
97
|
)
|
|
94
98
|
|
|
95
99
|
console.log(`\nDone - ${result.versionID}`)
|
|
@@ -117,6 +121,38 @@ const getGitSHA = (): string | null => {
|
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
|
|
124
|
+
/** Gets the subject line of the latest commit, or null if not in a git repo */
|
|
125
|
+
const getGitMessage = (): string | null => {
|
|
126
|
+
try {
|
|
127
|
+
return execSync("git log -1 --pretty=%s", { encoding: "utf-8" }).trim() || null
|
|
128
|
+
} catch {
|
|
129
|
+
return null
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Gets the origin remote URL normalized to https, or null if unavailable */
|
|
134
|
+
const getGitRepoURL = (): string | null => {
|
|
135
|
+
try {
|
|
136
|
+
const raw = execSync("git config --get remote.origin.url", { encoding: "utf-8" }).trim()
|
|
137
|
+
return raw ? normalizeRepoURL(raw) : null
|
|
138
|
+
} catch {
|
|
139
|
+
return null
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Converts SSH-style git URLs to https; strips trailing .git */
|
|
144
|
+
const normalizeRepoURL = (url: string): string => {
|
|
145
|
+
let normalized = url
|
|
146
|
+
// git@host:owner/repo(.git) -> https://host/owner/repo
|
|
147
|
+
const sshMatch = normalized.match(/^git@([^:]+):(.+)$/)
|
|
148
|
+
if (sshMatch) normalized = `https://${sshMatch[1]}/${sshMatch[2]}`
|
|
149
|
+
// ssh://git@host/owner/repo(.git) -> https://host/owner/repo
|
|
150
|
+
else if (normalized.startsWith("ssh://")) normalized = normalized.replace(/^ssh:\/\/(?:[^@]+@)?/, "https://")
|
|
151
|
+
// git://host/owner/repo(.git) -> https://host/owner/repo
|
|
152
|
+
else if (normalized.startsWith("git://")) normalized = normalized.replace(/^git:\/\//, "https://")
|
|
153
|
+
return normalized.replace(/\.git$/, "")
|
|
154
|
+
}
|
|
155
|
+
|
|
120
156
|
/** Hashes all file contents to produce a deterministic SHA */
|
|
121
157
|
const hashFiles = (filePaths: string[]): string => {
|
|
122
158
|
const hash = crypto.createHash("sha256")
|
package/src/util/api.ts
CHANGED
|
@@ -25,6 +25,10 @@ export type UploadProgress = (batch: number, totalBatches: number, uploaded: num
|
|
|
25
25
|
/** Options for uploadFiles */
|
|
26
26
|
export type UploadFilesOptions = {
|
|
27
27
|
verbose?: boolean
|
|
28
|
+
/** Commit message subject for the new GameRuntimeVersion */
|
|
29
|
+
description?: string | null
|
|
30
|
+
/** HTTPS repo URL to set on the GameRuntime */
|
|
31
|
+
repoURL?: string | null
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
/** Wraps fetch to surface the underlying network cause (DNS, ECONNREFUSED, TLS, etc.) */
|
|
@@ -112,12 +116,18 @@ export const uploadFiles = async (
|
|
|
112
116
|
onProgress?: UploadProgress,
|
|
113
117
|
options: UploadFilesOptions = {},
|
|
114
118
|
): Promise<CompleteResponse> => {
|
|
115
|
-
const { verbose = false } = options
|
|
119
|
+
const { verbose = false, description, repoURL } = options
|
|
116
120
|
const apiURL = getAPIURL()
|
|
117
121
|
if (verbose) console.log(` API URL: ${apiURL}`)
|
|
118
122
|
|
|
119
123
|
// Step 1: Init session (includes puzzmo.json metadata)
|
|
120
|
-
const init = (await jsonPost(
|
|
124
|
+
const init = (await jsonPost(
|
|
125
|
+
`${apiURL}/cliUpload`,
|
|
126
|
+
token,
|
|
127
|
+
{ gameSlug, sha, puzzmoFile, description, repoURL },
|
|
128
|
+
"upload init",
|
|
129
|
+
verbose,
|
|
130
|
+
)) as InitResponse
|
|
121
131
|
if (verbose) console.log(` session: ${init.sessionID}`)
|
|
122
132
|
|
|
123
133
|
// Step 2: Upload files in concurrent batches
|