@testchimp/cli 0.1.62 → 0.1.64
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/chimphands/run.d.ts +2 -0
- package/dist/chimphands/run.js +39 -2
- package/package.json +1 -1
package/dist/chimphands/run.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ type RunOptions = {
|
|
|
19
19
|
runtimeId?: string;
|
|
20
20
|
};
|
|
21
21
|
export declare function runChimphands(opts: RunOptions): Promise<void>;
|
|
22
|
+
/** OpenCode workspace-scoped APIs require directory routing (header + query). */
|
|
23
|
+
export declare function appendOpencodeDirectoryRouting(path: string, query: string | undefined, headers: Record<string, string>, directory: string): string;
|
|
22
24
|
/** Runtime-aware entry: register + attach to local OpenCode server (Phase 1+). */
|
|
23
25
|
export declare function serveChimphands(opts: RunOptions & {
|
|
24
26
|
attachUrl: string;
|
package/dist/chimphands/run.js
CHANGED
|
@@ -67,7 +67,7 @@ const CHIMPHANDS_AGENT_PROMPT = `You are ChimpHands, TestChimp's coding agent. Y
|
|
|
67
67
|
- This conversation uses ONE working branch and ONE pull request. Reuse them for all follow-up work in this chat.
|
|
68
68
|
- If bootstrap lists a working branch, checkout that branch and push additional commits there — update the same PR.
|
|
69
69
|
- Only create a NEW branch/PR when (a) no working branch exists yet for this conversation, or (b) the prior PR was merged/closed (verify with \`gh pr view\`).
|
|
70
|
-
- Commit and push on the session working branch after meaningful edit batches.
|
|
70
|
+
- Commit and push on the session working branch after meaningful edit batches. When \`CHIMPHANDS_UI_ATTACHED\` is \`false\` (no browser watching live), **commit and push before ending every turn** so the user can review async via PR / Files changed. The host also commits any remaining dirty worktree after each turn and before idle teardown.
|
|
71
71
|
- Branch names MUST start with \`testchimp-\` or \`chimphands-\`.
|
|
72
72
|
- When creating a NEW working branch: create it, then IMMEDIATELY publish it with
|
|
73
73
|
\`git push -u origin <branch>\` BEFORE calling report-branch. Users open the branch URL in the UI —
|
|
@@ -939,10 +939,12 @@ function writeOpencodeConfig(backend, apiKey, boot) {
|
|
|
939
939
|
const modelId = resolveOpencodeModelId(boot);
|
|
940
940
|
const model = `${TESTCHIMP_PROVIDER_ID}/${modelId}`;
|
|
941
941
|
const sessionId = bootStr(boot, "session_id", "sessionId");
|
|
942
|
+
const uiAttached = !!(boot.uiAttached ?? boot.ui_attached);
|
|
942
943
|
const mcpEnv = {
|
|
943
944
|
TESTCHIMP_API_KEY: apiKey,
|
|
944
945
|
TESTCHIMP_BACKEND_URL: backend,
|
|
945
946
|
TESTCHIMP_EXECUTION_SOURCE: "CLOUD_AGENT",
|
|
947
|
+
CHIMPHANDS_UI_ATTACHED: uiAttached ? "true" : "false",
|
|
946
948
|
};
|
|
947
949
|
const serviceUserId = bootStr(boot, "chimphands_service_account_user_id", "chimphandsServiceAccountUserId");
|
|
948
950
|
if (serviceUserId) {
|
|
@@ -1569,6 +1571,7 @@ export async function runChimphands(opts) {
|
|
|
1569
1571
|
const githubRunId = (process.env.GITHUB_RUN_ID || "").trim();
|
|
1570
1572
|
const poster = new AgentEventPoster(backend, apiKey, sessionId);
|
|
1571
1573
|
poster.uiAttached = !!(boot.uiAttached ?? boot.ui_attached);
|
|
1574
|
+
process.env.CHIMPHANDS_UI_ATTACHED = poster.uiAttached ? "true" : "false";
|
|
1572
1575
|
let stopLiveSse = null;
|
|
1573
1576
|
/** Do not open localhost OpenCode /event until serve has been (re)started with config. */
|
|
1574
1577
|
let opencodeHttpReady = !attachUrl;
|
|
@@ -1597,6 +1600,7 @@ export async function runChimphands(opts) {
|
|
|
1597
1600
|
};
|
|
1598
1601
|
const syncLiveSse = (attached) => {
|
|
1599
1602
|
pendingUiAttached = attached;
|
|
1603
|
+
process.env.CHIMPHANDS_UI_ATTACHED = attached ? "true" : "false";
|
|
1600
1604
|
if (!attachUrl) {
|
|
1601
1605
|
poster.uiAttached = attached;
|
|
1602
1606
|
return;
|
|
@@ -1977,6 +1981,11 @@ export async function runChimphands(opts) {
|
|
|
1977
1981
|
console.error(`ChimpHands turn-end reconcile failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1978
1982
|
}
|
|
1979
1983
|
}
|
|
1984
|
+
// Async / no UI: checkpoint dirty worktree after each turn so PR + Files changed
|
|
1985
|
+
// are reviewable when the user opens the session later (live VCS tunnel may be idle).
|
|
1986
|
+
if (!poster.uiAttached) {
|
|
1987
|
+
await commitAndPushDirtyWorktree("chimphands: commit after turn (async / no UI attached)");
|
|
1988
|
+
}
|
|
1980
1989
|
if (result.code !== 0 && !result.cancelled) {
|
|
1981
1990
|
const errMsg = (result.err || "opencode failed").trim() || "opencode failed";
|
|
1982
1991
|
console.error(`ChimpHands OpenCode failed: ${errMsg}`);
|
|
@@ -2122,9 +2131,35 @@ async function commitAndPushDirtyWorktree(message) {
|
|
|
2122
2131
|
console.error(`ChimpHands commit-before-idle failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2123
2132
|
}
|
|
2124
2133
|
}
|
|
2134
|
+
function opencodeProxyNeedsDirectory(path) {
|
|
2135
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
2136
|
+
return (p.startsWith("/vcs") ||
|
|
2137
|
+
p.startsWith("/api/vcs") ||
|
|
2138
|
+
p.startsWith("/file") ||
|
|
2139
|
+
p.startsWith("/api/fs") ||
|
|
2140
|
+
p.startsWith("/api/session") ||
|
|
2141
|
+
p.startsWith("/path") ||
|
|
2142
|
+
p.startsWith("/session") ||
|
|
2143
|
+
p.startsWith("/instance") ||
|
|
2144
|
+
p.startsWith("/event") ||
|
|
2145
|
+
p.startsWith("/global/event"));
|
|
2146
|
+
}
|
|
2147
|
+
/** OpenCode workspace-scoped APIs require directory routing (header + query). */
|
|
2148
|
+
export function appendOpencodeDirectoryRouting(path, query, headers, directory) {
|
|
2149
|
+
if (!opencodeProxyNeedsDirectory(path)) {
|
|
2150
|
+
return query || "";
|
|
2151
|
+
}
|
|
2152
|
+
headers["x-opencode-directory"] = directory;
|
|
2153
|
+
if (query?.includes("directory=")) {
|
|
2154
|
+
return query;
|
|
2155
|
+
}
|
|
2156
|
+
const dirParam = `directory=${encodeURIComponent(directory)}`;
|
|
2157
|
+
return query ? `${query}&${dirParam}` : dirParam;
|
|
2158
|
+
}
|
|
2125
2159
|
function startTunnelWorker(backend, apiKey, runtimeId, attachUrl, sessionId, handlers) {
|
|
2126
2160
|
let stopped = false;
|
|
2127
2161
|
const base = attachUrl.replace(/\/$/, "");
|
|
2162
|
+
const workDirectory = process.cwd();
|
|
2128
2163
|
let ws = null;
|
|
2129
2164
|
let reconnectTimer = null;
|
|
2130
2165
|
let backoffMs = 1000;
|
|
@@ -2140,8 +2175,10 @@ function startTunnelWorker(backend, apiKey, runtimeId, attachUrl, sessionId, han
|
|
|
2140
2175
|
if (!req.requestId || socket.readyState !== 1)
|
|
2141
2176
|
return;
|
|
2142
2177
|
const requestId = req.requestId;
|
|
2143
|
-
const
|
|
2178
|
+
const pathPart = req.path || "/";
|
|
2144
2179
|
const headers = { ...(req.headers || {}) };
|
|
2180
|
+
const query = appendOpencodeDirectoryRouting(pathPart, req.query, headers, workDirectory);
|
|
2181
|
+
const target = base + pathPart + (query ? `?${query}` : "");
|
|
2145
2182
|
const init = { method: req.method || "GET", headers };
|
|
2146
2183
|
if (req.bodyBase64) {
|
|
2147
2184
|
init.body = Buffer.from(req.bodyBase64, "base64");
|
package/package.json
CHANGED