@proagentstore/cli 0.4.57 → 0.4.58
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/browser-runner/coding/engine-acts.js +7 -7
- package/dist/browser-runner/coding/engine-adapter.js +186 -0
- package/dist/browser-runner/coding/engine-usage.js +27 -3
- package/dist/browser-runner/coding/github-browse.js +796 -0
- package/dist/browser-runner/coding/handlers.js +1 -1
- package/dist/browser-runner/coding/headless.js +86 -120
- package/dist/browser-runner/coding/inspect.js +188 -13
- package/dist/browser-runner/coding/repo.js +44 -1
- package/dist/browser-runner/coding/runtime.js +14 -2
- package/dist/browser-runner/server.js +103 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { homedir } from "node:os";
|
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { RunnerInputError } from "../errors.js";
|
|
4
4
|
import { defaultStatePath, HeadlessSession } from "./headless.js";
|
|
5
|
-
import { InspectError, readGitRemoteOrigin, readRepoFile, repoSearch, repoTree, runRepoGit } from "./inspect.js";
|
|
5
|
+
import { InspectError, readGitRemoteOrigin, readRepoFile, repoSearch, repoSync, repoTree, runRepoGit } from "./inspect.js";
|
|
6
6
|
import { switchRepoBranch } from "./repo-write.js";
|
|
7
7
|
import { checkWorkdir, ensureRepo, sanitizeSessionName } from "./repo.js";
|
|
8
8
|
import { asTurnAuthor } from "./turn-author.js";
|
|
@@ -54,7 +54,15 @@ export class CodingRuntime {
|
|
|
54
54
|
}
|
|
55
55
|
/** Run a whitelisted read-only git command in the session's repo. */
|
|
56
56
|
git(input) {
|
|
57
|
-
return runRepoGit(this.resolveWorkDir(input), input.cmd, { path: input.path, n: input.n });
|
|
57
|
+
return runRepoGit(this.resolveWorkDir(input), input.cmd, { path: input.path, n: input.n, ref: input.ref });
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Where the checkout stands against its upstream — fetch (cached), then count ahead/behind
|
|
61
|
+
* (#785). Never pulls. The one endpoint here that reaches the NETWORK, which is why it carries
|
|
62
|
+
* its own cache and its own no-prompt environment (`inspect.ts`).
|
|
63
|
+
*/
|
|
64
|
+
sync(input) {
|
|
65
|
+
return repoSync(this.resolveWorkDir(input), { branch: input.branch, forceFetch: input.forceFetch });
|
|
58
66
|
}
|
|
59
67
|
/**
|
|
60
68
|
* The ONE write the platform may make in a checkout by itself (#322) — put it back on a branch
|
|
@@ -158,6 +166,8 @@ export class CodingRuntime {
|
|
|
158
166
|
// exactly the question asked about a session that just stopped.
|
|
159
167
|
authResolved: session.authResolved,
|
|
160
168
|
engineRuntime: session.engineRuntime,
|
|
169
|
+
engineMode: session.engineMode,
|
|
170
|
+
engineModeWarning: session.engineModeWarning,
|
|
161
171
|
// Reported on EVERY capture, including one where the session is not alive: "how did the
|
|
162
172
|
// last turn end" is exactly the question asked about a session that just stopped, and
|
|
163
173
|
// the omitted-when-null shape keeps "not measured" distinguishable from a verdict.
|
|
@@ -252,6 +262,8 @@ export class CodingRuntime {
|
|
|
252
262
|
takeover: this.takeovers.has(sessionId),
|
|
253
263
|
authResolved: s.authResolved,
|
|
254
264
|
engineRuntime: s.engineRuntime,
|
|
265
|
+
engineMode: s.engineMode,
|
|
266
|
+
engineModeWarning: s.engineModeWarning,
|
|
255
267
|
ghGuard: s.ghGuard,
|
|
256
268
|
}));
|
|
257
269
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createServer, } from "node:http";
|
|
2
2
|
import { URL } from "node:url";
|
|
3
3
|
import { LocalRunner, RunnerInputError } from "./runner.js";
|
|
4
|
+
import { probeGitSshIdentity } from "./coding/repo.js";
|
|
5
|
+
import { listGithubOrgs, listGithubRepos, searchGithubRepos, getGithubRepoDetail, getGithubCredentialScope } from "./coding/github-browse.js";
|
|
4
6
|
export function createRunnerServer(runner) {
|
|
5
7
|
return createServer(async (req, res) => {
|
|
6
8
|
try {
|
|
@@ -176,6 +178,95 @@ async function route(runner, req, res) {
|
|
|
176
178
|
// use tmux, have their own /tmux/* endpoints and are unaffected.
|
|
177
179
|
return json(res, 200, { tracked: runner.coding.diagnostics() });
|
|
178
180
|
}
|
|
181
|
+
if ((req.method === "GET" || req.method === "POST") && path === "/coding/git-identity") {
|
|
182
|
+
// Report the SSH identity this machine presents to github.com (#684). Called by
|
|
183
|
+
// `coding_diagnostics` to surface deploy-key vs user-account mismatches without a
|
|
184
|
+
// failed clone. Never throws on the runner side — a network hiccup returns identity:null.
|
|
185
|
+
const b = req.method === "POST" ? await readJson(req).catch(() => ({})) : {};
|
|
186
|
+
const host = String(b.host || "github.com");
|
|
187
|
+
return json(res, 200, probeGitSshIdentity(host));
|
|
188
|
+
}
|
|
189
|
+
// ── GitHub credential scope (#688) ────────────────────────────────────────
|
|
190
|
+
// Read-only: reports the authenticated gh login + org memberships. Surfaces
|
|
191
|
+
// which account and organisations the runner's credentials can reach, before
|
|
192
|
+
// any browse operation begins. Never writes, never mutates anything on GitHub.
|
|
193
|
+
if ((req.method === "GET" || req.method === "POST") && path === "/coding/github-credentials") {
|
|
194
|
+
return json(res, 200, getGithubCredentialScope());
|
|
195
|
+
}
|
|
196
|
+
// ── GitHub org + repo enumeration (#685) ──────────────────────────────────
|
|
197
|
+
// Read-only: lists orgs and repos reachable by the machine's `gh` credentials.
|
|
198
|
+
// Never writes, never mutates anything on GitHub.
|
|
199
|
+
if ((req.method === "GET" || req.method === "POST") && path === "/coding/github-orgs") {
|
|
200
|
+
return json(res, 200, listGithubOrgs());
|
|
201
|
+
}
|
|
202
|
+
if ((req.method === "GET" || req.method === "POST") && path === "/coding/github-repos") {
|
|
203
|
+
const b = req.method === "POST"
|
|
204
|
+
? await readJson(req).catch(() => ({}))
|
|
205
|
+
: {};
|
|
206
|
+
// Query params override body for GET callers (more REST-idiomatic).
|
|
207
|
+
const qOwner = url.searchParams.get("owner");
|
|
208
|
+
const qLimit = url.searchParams.get("limit");
|
|
209
|
+
const qSince = url.searchParams.get("since");
|
|
210
|
+
const qVis = url.searchParams.get("visibility");
|
|
211
|
+
const input = {
|
|
212
|
+
owner: qOwner ?? b.owner,
|
|
213
|
+
limit: qLimit ? Number(qLimit) : b.limit,
|
|
214
|
+
since: qSince ?? b.since,
|
|
215
|
+
visibility: (qVis === "public" || qVis === "private" || qVis === "all")
|
|
216
|
+
? qVis
|
|
217
|
+
: b.visibility,
|
|
218
|
+
};
|
|
219
|
+
return json(res, 200, listGithubRepos(input));
|
|
220
|
+
}
|
|
221
|
+
// ── GitHub repository search (#686) ───────────────────────────────────────
|
|
222
|
+
// Read-only: searches repos reachable by the machine's `gh` credentials via
|
|
223
|
+
// GitHub's own search API. One API call per query (no per-repo fan-out).
|
|
224
|
+
// Results are cached in-process for 5 minutes to guard the 30 req/min quota.
|
|
225
|
+
if ((req.method === "GET" || req.method === "POST") && path === "/coding/github-search") {
|
|
226
|
+
const b = req.method === "POST"
|
|
227
|
+
? await readJson(req).catch(() => ({}))
|
|
228
|
+
: {};
|
|
229
|
+
const qQuery = url.searchParams.get("query");
|
|
230
|
+
const qOwner = url.searchParams.get("owner");
|
|
231
|
+
const qLang = url.searchParams.get("language");
|
|
232
|
+
const qTopic = url.searchParams.get("topic");
|
|
233
|
+
const qPushedAfter = url.searchParams.get("pushedAfter");
|
|
234
|
+
const qOpenPrs = url.searchParams.get("openPrs");
|
|
235
|
+
const qLimit = url.searchParams.get("limit");
|
|
236
|
+
const qSort = url.searchParams.get("sort");
|
|
237
|
+
const bTyped = b;
|
|
238
|
+
const input = {
|
|
239
|
+
query: qQuery ?? bTyped.query,
|
|
240
|
+
owner: qOwner ?? bTyped.owner,
|
|
241
|
+
language: qLang ?? bTyped.language,
|
|
242
|
+
topic: qTopic ?? bTyped.topic,
|
|
243
|
+
pushedAfter: qPushedAfter ?? bTyped.pushedAfter,
|
|
244
|
+
openPrs: qOpenPrs !== null ? qOpenPrs === "true" : bTyped.openPrs,
|
|
245
|
+
limit: qLimit ? Number(qLimit) : bTyped.limit,
|
|
246
|
+
sort: (qSort === "stars" || qSort === "forks" || qSort === "updated")
|
|
247
|
+
? qSort
|
|
248
|
+
: bTyped.sort,
|
|
249
|
+
};
|
|
250
|
+
return json(res, 200, searchGithubRepos(input));
|
|
251
|
+
}
|
|
252
|
+
// ── GitHub repository detail (#687) ──────────────────────────────────────
|
|
253
|
+
// Read-only: fetches issues, PRs, and branches for a given owner/repo slug
|
|
254
|
+
// via `gh api`. Results are cached in-process for 2 minutes.
|
|
255
|
+
if ((req.method === "GET" || req.method === "POST") && path === "/coding/github-repo-detail") {
|
|
256
|
+
const b = req.method === "POST"
|
|
257
|
+
? await readJson(req).catch(() => ({}))
|
|
258
|
+
: {};
|
|
259
|
+
const bTyped = b;
|
|
260
|
+
const qRepo = url.searchParams.get("repo");
|
|
261
|
+
const qLimit = url.searchParams.get("limit");
|
|
262
|
+
const qState = url.searchParams.get("state");
|
|
263
|
+
const input = {
|
|
264
|
+
repo: qRepo ?? bTyped.repo ?? "",
|
|
265
|
+
limit: qLimit ? Number(qLimit) : bTyped.limit,
|
|
266
|
+
state: (qState === "all" || qState === "open") ? qState : bTyped.state,
|
|
267
|
+
};
|
|
268
|
+
return json(res, 200, getGithubRepoDetail(input));
|
|
269
|
+
}
|
|
179
270
|
if (req.method === "POST" && path === "/coding/browse") {
|
|
180
271
|
const { readdirSync, statSync } = await import("node:fs");
|
|
181
272
|
const { resolve } = await import("node:path");
|
|
@@ -240,6 +331,18 @@ async function route(runner, req, res) {
|
|
|
240
331
|
return json(res, 400, { error: e instanceof Error ? e.message : String(e) });
|
|
241
332
|
}
|
|
242
333
|
}
|
|
334
|
+
// Where the checkout stands against its upstream (#785): fetch (cached a minute), then count
|
|
335
|
+
// ahead/behind. Never pulls. A SEPARATE endpoint for the reason `/coding/search` is one: an
|
|
336
|
+
// older runner 404s it, which the cloud reads as "unverified" — never as "in sync".
|
|
337
|
+
if (req.method === "POST" && path === "/coding/sync") {
|
|
338
|
+
const b = await readJson(req);
|
|
339
|
+
try {
|
|
340
|
+
return json(res, 200, runner.coding.sync(b));
|
|
341
|
+
}
|
|
342
|
+
catch (e) {
|
|
343
|
+
return json(res, 400, { error: e instanceof Error ? e.message : String(e) });
|
|
344
|
+
}
|
|
345
|
+
}
|
|
243
346
|
// The ONE write surface (#322). A standing policy may put a checkout back on the branch it
|
|
244
347
|
// declared; it may not commit, discard, or touch a remote. An older runner 404s this, which the
|
|
245
348
|
// cloud reports as "asked, not confirmed" rather than as done.
|