@midhunxavier/code-flow 0.0.0-stage → 0.1.0-preview.3
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/LICENSE +21 -0
- package/README.md +141 -2
- package/bin/codeflow.mjs +8 -0
- package/bin/launcher.mjs +127 -0
- package/dist/remote-host.json +1 -0
- package/licenses/inter.txt +92 -0
- package/licenses/preact.txt +21 -0
- package/licenses/signals-core.txt +21 -0
- package/licenses/signals.txt +21 -0
- package/licenses/typescript-notices.txt +193 -0
- package/licenses/typescript.txt +55 -0
- package/licenses/uqr.txt +22 -0
- package/licenses/xterm-fit.txt +19 -0
- package/licenses/xterm.txt +21 -0
- package/package.json +34 -4
- package/public/assets/changes-62ZIEQSN.js +1 -0
- package/public/assets/chunk-2PZVOKID.js +1 -0
- package/public/assets/chunk-4D5IENEB.js +1 -0
- package/public/assets/chunk-5SARP5MU.js +1 -0
- package/public/assets/chunk-63YLZ3PR.js +1 -0
- package/public/assets/chunk-7FUHKF2M.js +1 -0
- package/public/assets/chunk-APQEVJ2K.js +1 -0
- package/public/assets/chunk-CGOZQMEZ.js +2 -0
- package/public/assets/chunk-J4VYS3KV.js +2 -0
- package/public/assets/chunk-L7TUCIYF.js +1 -0
- package/public/assets/chunk-SIHDWM2Y.js +154 -0
- package/public/assets/chunk-TEJVYIKC.js +1 -0
- package/public/assets/code-browser-VB2HGZSG.js +4 -0
- package/public/assets/filtered-tasks-ES5CP4KV.js +1 -0
- package/public/assets/interactive-browser-7F5ZXRUV.js +7 -0
- package/public/assets/join-project-6RTFHNCA.js +1 -0
- package/public/assets/main-65EW73SB.js +1 -0
- package/public/assets/project-invitations-view-GMPWGWYM.js +1 -0
- package/public/assets/settings-UB5Q4AQM.js +9 -0
- package/public/assets/styles-18792BB4.css +32 -0
- package/public/assets/team-server-wizard-2GLDWS6D.js +8 -0
- package/public/assets/terminal-IWAIM4DE.js +62 -0
- package/public/assets.json +1 -0
- package/public/bundle-meta.json +1 -0
- package/public/docs/.nojekyll +0 -0
- package/public/docs/accessibility.html +19 -0
- package/public/docs/acp-agents.html +117 -0
- package/public/docs/agent-containers.html +79 -0
- package/public/docs/api.html +1130 -0
- package/public/docs/app.js +342 -0
- package/public/docs/application-improvements.html +275 -0
- package/public/docs/architecture-explorer.html +19 -0
- package/public/docs/architecture.html +149 -0
- package/public/docs/auto-team.html +148 -0
- package/public/docs/automations.html +109 -0
- package/public/docs/checkpoint-review.html +37 -0
- package/public/docs/code-hosts.html +35 -0
- package/public/docs/code-intelligence.html +35 -0
- package/public/docs/configuration.html +346 -0
- package/public/docs/context-inspection.html +23 -0
- package/public/docs/coordinated-changes.html +28 -0
- package/public/docs/deferred-runs.html +25 -0
- package/public/docs/dependency-discovery.html +19 -0
- package/public/docs/documentation.html +84 -0
- package/public/docs/dynamic-teams-evaluation.html +174 -0
- package/public/docs/dynamic-teams-implementation-plan.html +882 -0
- package/public/docs/dynamic-teams-implementation-review-1.html +141 -0
- package/public/docs/dynamic-teams-plan-review-0.html +204 -0
- package/public/docs/extensions.html +42 -0
- package/public/docs/external-sources.html +96 -0
- package/public/docs/filesystem-policy.html +26 -0
- package/public/docs/filtered-tasks.html +44 -0
- package/public/docs/font-license.txt +92 -0
- package/public/docs/getting-started.html +143 -0
- package/public/docs/github-review-threads.html +26 -0
- package/public/docs/github.html +157 -0
- package/public/docs/help.html +69 -0
- package/public/docs/index.html +88 -0
- package/public/docs/installation.html +80 -0
- package/public/docs/launch-profiles.html +48 -0
- package/public/docs/maintenance.html +60 -0
- package/public/docs/memory-claims.html +31 -0
- package/public/docs/memory-storage.html +58 -0
- package/public/docs/notifications.html +39 -0
- package/public/docs/patterns.html +195 -0
- package/public/docs/performance-results.html +210 -0
- package/public/docs/performance.html +166 -0
- package/public/docs/project-conventions.html +22 -0
- package/public/docs/project-first-navigation-plan.html +587 -0
- package/public/docs/project-teams-implementation-plan.html +772 -0
- package/public/docs/project-teams.html +129 -0
- package/public/docs/provider-compatibility.html +20 -0
- package/public/docs/releasing.html +65 -0
- package/public/docs/remote-workers.html +64 -0
- package/public/docs/review-inbox.html +26 -0
- package/public/docs/run-storage.html +23 -0
- package/public/docs/runs.html +141 -0
- package/public/docs/search.json +1 -0
- package/public/docs/security.html +133 -0
- package/public/docs/shared-projects.html +31 -0
- package/public/docs/ssh-projects.html +60 -0
- package/public/docs/style.css +768 -0
- package/public/docs/task-reruns.html +30 -0
- package/public/docs/team-collaboration.html +412 -0
- package/public/docs/verification.html +22 -0
- package/public/docs/vscode.html +53 -0
- package/public/docs/worker-permission-verification.html +131 -0
- package/public/index.html +17 -0
- package/scripts/check-node.mjs +7 -0
- package/scripts/codeflow.mjs +55 -0
- package/scripts/computer-use.swift +64 -0
- package/scripts/pty.py +273 -0
- package/src/acp-connections.js +110 -0
- package/src/adapters/acp-presets.js +37 -0
- package/src/adapters/acp-types.js +0 -0
- package/src/adapters/acp.js +328 -0
- package/src/adapters/agent-tools.js +28 -0
- package/src/adapters/agy-auth.js +67 -0
- package/src/adapters/agy-isolation.js +242 -0
- package/src/adapters/agy-tools.js +45 -0
- package/src/adapters/agy.js +326 -0
- package/src/adapters/claude-stream.js +58 -0
- package/src/adapters/claude.js +282 -0
- package/src/adapters/codex-app-server.js +555 -0
- package/src/adapters/codex.js +311 -0
- package/src/adapters/errors.js +57 -0
- package/src/adapters/index.js +91 -0
- package/src/adapters/managed-permissions.js +37 -0
- package/src/adapters/model-discovery.js +100 -0
- package/src/adapters/process.js +433 -0
- package/src/adapters/team-tools.js +103 -0
- package/src/adapters/types.js +0 -0
- package/src/agent-browser.js +688 -0
- package/src/agent-computer.js +88 -0
- package/src/agent-container.js +155 -0
- package/src/agent-team-definitions.js +131 -0
- package/src/agent-tool-client.mjs +79 -0
- package/src/agent-tools.js +296 -0
- package/src/approvals.js +134 -0
- package/src/architecture.js +456 -0
- package/src/assets.js +44 -0
- package/src/automation.js +901 -0
- package/src/browser-files.js +293 -0
- package/src/browser-ownership.js +150 -0
- package/src/certificate-renewal.js +75 -0
- package/src/chat-family.js +25 -0
- package/src/chat-handoff.js +87 -0
- package/src/checkpoint-review.js +72 -0
- package/src/checks.js +303 -0
- package/src/code-host-git.js +102 -0
- package/src/code-hosts-api.js +99 -0
- package/src/code-hosts.js +482 -0
- package/src/code-intelligence-worker.mjs +452 -0
- package/src/code-intelligence.js +141 -0
- package/src/collab/api.js +365 -0
- package/src/collab/checkpoints.js +198 -0
- package/src/collab/connections.js +139 -0
- package/src/collab/host-execution.js +347 -0
- package/src/collab/hub-client.js +210 -0
- package/src/collab/link-api.js +229 -0
- package/src/collab/link.js +595 -0
- package/src/collab/model.js +496 -0
- package/src/collab/runner.js +1014 -0
- package/src/collab/store.js +1452 -0
- package/src/collab/terminals.js +361 -0
- package/src/collaboration-reviews.js +116 -0
- package/src/config.js +48 -0
- package/src/context-budget.js +14 -0
- package/src/context-inspection.js +204 -0
- package/src/context.js +154 -0
- package/src/conventions.js +283 -0
- package/src/coordinated-api.js +247 -0
- package/src/deferred-launch.js +82 -0
- package/src/deferred-runs.js +515 -0
- package/src/dependency-health.js +35 -0
- package/src/diff.js +43 -0
- package/src/docs-help.js +316 -0
- package/src/doctor.js +232 -0
- package/src/documentation-changes.js +20 -0
- package/src/engine.js +5258 -0
- package/src/env.js +44 -0
- package/src/execution-budget.js +8 -0
- package/src/experience.js +50 -0
- package/src/extensions.js +144 -0
- package/src/filesystem-access.js +107 -0
- package/src/filesystem-policy.js +238 -0
- package/src/filtered-task-limits.js +93 -0
- package/src/filtered-tasks-api.js +53 -0
- package/src/filtered-tasks.js +576 -0
- package/src/frame-policy.js +66 -0
- package/src/fs.js +57 -0
- package/src/git.js +626 -0
- package/src/github-review-threads.js +181 -0
- package/src/github.js +538 -0
- package/src/http.js +69 -0
- package/src/improve-settings.js +38 -0
- package/src/improve.js +187 -0
- package/src/integrations.js +373 -0
- package/src/integrity.js +259 -0
- package/src/journey-api.js +77 -0
- package/src/journey-replay.js +65 -0
- package/src/journey-store.js +97 -0
- package/src/journeys.js +60 -0
- package/src/json.js +81 -0
- package/src/launch-profiles.js +292 -0
- package/src/learnings.js +80 -0
- package/src/local-app-url.js +19 -0
- package/src/log.js +39 -0
- package/src/maintenance.js +335 -0
- package/src/memory-analysis.js +182 -0
- package/src/memory-claims.js +153 -0
- package/src/memory-sqlite.js +236 -0
- package/src/memory.js +552 -0
- package/src/merge-validation.js +58 -0
- package/src/model-catalog.js +239 -0
- package/src/model-research.js +91 -0
- package/src/notes.js +176 -0
- package/src/notifications.js +413 -0
- package/src/patterns/auto-team-model.js +230 -0
- package/src/patterns/auto-team.js +816 -0
- package/src/patterns/council.js +199 -0
- package/src/patterns/debate.js +188 -0
- package/src/patterns/findings.js +141 -0
- package/src/patterns/index.js +21 -0
- package/src/patterns/loop.js +158 -0
- package/src/patterns/pipeline.js +125 -0
- package/src/patterns/prompts.js +181 -0
- package/src/patterns/race.js +147 -0
- package/src/patterns/schemas.js +40 -0
- package/src/patterns/solo.js +46 -0
- package/src/patterns/supervisor.js +235 -0
- package/src/patterns/task-draft.js +29 -0
- package/src/patterns/task-review.js +45 -0
- package/src/patterns/tdd.js +231 -0
- package/src/patterns/team-strategies.js +67 -0
- package/src/performance.js +43 -0
- package/src/persistence-status.js +35 -0
- package/src/phone-sessions.js +96 -0
- package/src/preview-overlay.js +392 -0
- package/src/preview.js +230 -0
- package/src/privacy.js +23 -0
- package/src/project-report.js +22 -0
- package/src/project-team-budget.js +22 -0
- package/src/project-team-model.js +225 -0
- package/src/project-team-policy.js +42 -0
- package/src/project-team-store.js +234 -0
- package/src/project-team-usage.js +24 -0
- package/src/project-teams-api.js +43 -0
- package/src/project-teams.js +644 -0
- package/src/projects.js +290 -0
- package/src/provider-eligibility.js +9 -0
- package/src/readiness.js +98 -0
- package/src/remote-tls.js +66 -0
- package/src/remote-workers/bundles.js +198 -0
- package/src/remote-workers/client.js +332 -0
- package/src/remote-workers/durability.js +37 -0
- package/src/remote-workers/protocol.js +68 -0
- package/src/remote-workers/stdio.js +138 -0
- package/src/remote-workers/worker.js +304 -0
- package/src/remote.js +204 -0
- package/src/repo-config.js +201 -0
- package/src/repo-coordination.js +725 -0
- package/src/repo-tree.js +106 -0
- package/src/repository-identity.js +13 -0
- package/src/retention-policy.js +466 -0
- package/src/review-inbox.js +38 -0
- package/src/routing.js +49 -0
- package/src/run-analysis.js +111 -0
- package/src/run-cold-store.js +231 -0
- package/src/run-environment.js +15 -0
- package/src/run-history.js +91 -0
- package/src/run-log.js +160 -0
- package/src/run-permissions.js +111 -0
- package/src/run-projection.js +77 -0
- package/src/run-recovery.js +53 -0
- package/src/run-status.js +56 -0
- package/src/serve.js +138 -0
- package/src/server.js +2871 -0
- package/src/shared-access.js +103 -0
- package/src/shared-accounts.js +381 -0
- package/src/shared-api.js +239 -0
- package/src/shell.js +346 -0
- package/src/ship.js +344 -0
- package/src/slots.js +74 -0
- package/src/snapshot.js +388 -0
- package/src/source-context.js +17 -0
- package/src/sse-writer.js +70 -0
- package/src/ssh-projects/bootstrap.mjs +95 -0
- package/src/ssh-projects/config.js +45 -0
- package/src/ssh-projects/gateway.js +143 -0
- package/src/ssh-projects/manager.js +320 -0
- package/src/ssh-projects/team-autostart.mjs +93 -0
- package/src/ssh-projects/team-remove.mjs +69 -0
- package/src/ssh-projects/team-status.mjs +39 -0
- package/src/ssh-projects/transport.js +133 -0
- package/src/stats.js +139 -0
- package/src/store.js +544 -0
- package/src/stream.js +91 -0
- package/src/sweeps.js +241 -0
- package/src/tailscale.js +101 -0
- package/src/task-draft.js +23 -0
- package/src/task-team.js +164 -0
- package/src/team-evaluation.js +243 -0
- package/src/team-mailbox.js +160 -0
- package/src/team-memory.js +84 -0
- package/src/team-rerun-graph.js +15 -0
- package/src/team-reruns.js +130 -0
- package/src/team-scheduler.js +121 -0
- package/src/team-steering.js +21 -0
- package/src/team-template-store.js +98 -0
- package/src/team-templates.js +117 -0
- package/src/team-tool-client.mjs +79 -0
- package/src/team-tools.js +235 -0
- package/src/teams.js +0 -0
- package/src/templates.js +62 -0
- package/src/transcript.js +134 -0
- package/src/verification-integrity.js +27 -0
- package/src/verification.js +183 -0
- package/src/watch.js +195 -0
- package/src/work-queue.js +47 -0
- package/src/workflow-control.js +83 -0
- package/src/workspace-api.js +207 -0
- package/src/workspace-changes.js +61 -0
- package/src/workspace.js +146 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Read-only probe. Never installs, starts or reconnects a team server, and never
|
|
2
|
+
// emits its owner token or the secret path in a device-access link.
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
async function status() {
|
|
8
|
+
let runtime;
|
|
9
|
+
try { runtime = JSON.parse(await readFile(join(homedir(), ".codeflow/team-server/runtime.json"), "utf8")); }
|
|
10
|
+
catch (error) { return { state: error.code === "ENOENT" ? "not-installed" : "unavailable" }; }
|
|
11
|
+
if (runtime?.protocol !== 1 || !Number.isInteger(runtime.port) || runtime.port < 1 || runtime.port > 65535
|
|
12
|
+
|| !/^[a-f0-9]{64}$/.test(runtime.token ?? "") || !/^[a-f0-9]{32}$/.test(runtime.instance ?? "")) return { state: "unavailable" };
|
|
13
|
+
const get = async path => {
|
|
14
|
+
const response = await fetch(`http://127.0.0.1:${runtime.port}${path}`, {
|
|
15
|
+
headers: { authorization: `Bearer ${runtime.token}` }, signal: AbortSignal.timeout(4000), redirect: "error",
|
|
16
|
+
});
|
|
17
|
+
if (!response.ok) throw new Error("Status unavailable");
|
|
18
|
+
return response.json();
|
|
19
|
+
};
|
|
20
|
+
try {
|
|
21
|
+
const identity = await get("/api/team-host-runtime");
|
|
22
|
+
if (identity.instance !== runtime.instance) return { state: "unavailable" };
|
|
23
|
+
const remote = await get("/api/remote");
|
|
24
|
+
let address;
|
|
25
|
+
if (remote.enabled && remote.lan && remote.secure && !remote.lanError) {
|
|
26
|
+
try {
|
|
27
|
+
const url = new URL(remote.tailscaleUrl ?? remote.lanUrls?.[0]);
|
|
28
|
+
if (url.protocol === "https:" && !url.username && !url.password) address = url.origin;
|
|
29
|
+
} catch { /* An absent or invalid address cannot be shared. */ }
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
state: "running",
|
|
33
|
+
access: !remote.enabled || !remote.lan ? "disabled" : remote.lanError ? "error" : address ? "ready" : "incomplete",
|
|
34
|
+
...(address ? { address } : {}),
|
|
35
|
+
network: remote.transport === "tailscale" ? "Tailscale" : "Private network",
|
|
36
|
+
};
|
|
37
|
+
} catch { return { state: "unavailable" }; }
|
|
38
|
+
}
|
|
39
|
+
console.log("CODEFLOW_TEAM_STATUS " + JSON.stringify(await status()));
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { isAbsolute, join } from "node:path";
|
|
5
|
+
import { Duplex } from "node:stream";
|
|
6
|
+
const validSshHost = (host) => typeof host === "string" && /^[A-Za-z0-9][A-Za-z0-9._@-]{0,199}$/.test(host);
|
|
7
|
+
function validSshOptions(options) {
|
|
8
|
+
return (options.port === void 0 || Number.isInteger(options.port) && Number(options.port) >= 1 && Number(options.port) <= 65535) && (options.identityFile === void 0 || typeof options.identityFile === "string" && options.identityFile.length <= 4096 && (isAbsolute(options.identityFile) || options.identityFile.startsWith("~/")) && !/[\x00-\x1f\x7f%]/.test(options.identityFile));
|
|
9
|
+
}
|
|
10
|
+
const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
11
|
+
const OPTIONS = ["-T", "-a", "-k", "-o", "GSSAPIDelegateCredentials=no", "-o", "SendEnv=-*", "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", "-o", "ForwardAgent=no", "-o", "ForwardX11=no", "-o", "PermitLocalCommand=no", "-o", "RemoteCommand=none", "-o", "ClearAllForwardings=yes", "-o", "ConnectTimeout=15", "-o", "ServerAliveInterval=15", "-o", "ServerAliveCountMax=3"];
|
|
12
|
+
class SshTransport {
|
|
13
|
+
constructor(host, binary = "ssh", options = {}) {
|
|
14
|
+
this.host = host;
|
|
15
|
+
this.binary = binary;
|
|
16
|
+
this.options = options;
|
|
17
|
+
if (!validSshHost(host)) throw new Error("Enter an SSH host alias or user@hostname");
|
|
18
|
+
if (!validSshOptions(options)) throw new Error("Use a port from 1 to 65535 and an absolute or ~/ SSH key path without control characters or % tokens");
|
|
19
|
+
}
|
|
20
|
+
directory = "";
|
|
21
|
+
children = /* @__PURE__ */ new Set();
|
|
22
|
+
closed = false;
|
|
23
|
+
async init() {
|
|
24
|
+
this.directory = await mkdtemp(join(tmpdir(), "cf-ssh-"));
|
|
25
|
+
}
|
|
26
|
+
start(args, command) {
|
|
27
|
+
if (this.closed) throw new Error("SSH connection is closed");
|
|
28
|
+
const env = {};
|
|
29
|
+
for (const name of ["PATH", "HOME", "USER", "LOGNAME", "SSH_AUTH_SOCK", "SYSTEMROOT", "SystemRoot", "TMPDIR"]) if (process.env[name]) env[name] = process.env[name];
|
|
30
|
+
const connection = [...this.options.port ? ["-p", String(this.options.port)] : [], ...this.options.identityFile ? ["-i", this.options.identityFile] : []];
|
|
31
|
+
const child = spawn(this.binary, [...OPTIONS, ...connection, "-o", "ControlMaster=auto", "-o", "ControlPersist=60", "-o", `ControlPath=${join(this.directory, "socket")}`, ...args, this.host, ...command ? [command] : []], { env, stdio: ["pipe", "pipe", "pipe"] });
|
|
32
|
+
this.children.add(child);
|
|
33
|
+
child.once("close", () => this.children.delete(child));
|
|
34
|
+
return child;
|
|
35
|
+
}
|
|
36
|
+
async bootstrap(code, payload, teamServer = false) {
|
|
37
|
+
const command = `exec sh -c ${quote(`exec "\${SHELL:-/bin/sh}" -lc ${quote(`exec node --input-type=module -e ${quote(code)}${teamServer ? " -- --team-server" : ""}`)}`)}`;
|
|
38
|
+
const child = this.start([], command);
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
let stdout = "", stderr = "", settled = false;
|
|
41
|
+
const finish = (error) => {
|
|
42
|
+
if (settled) return;
|
|
43
|
+
settled = true;
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
error ? reject(error) : resolve(stdout);
|
|
46
|
+
};
|
|
47
|
+
const timer = setTimeout(() => {
|
|
48
|
+
child.kill();
|
|
49
|
+
finish(new Error("SSH setup timed out. Check the server's SSH login, Node.js and ~/.codeflow/ssh-host/host.log."));
|
|
50
|
+
}, 12e4);
|
|
51
|
+
child.stdout.on("data", (data) => {
|
|
52
|
+
stdout += data;
|
|
53
|
+
if (stdout.length > 64 * 1024) {
|
|
54
|
+
child.kill();
|
|
55
|
+
finish(new Error("SSH setup produced too much output"));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
child.stderr.on("data", (data) => {
|
|
59
|
+
stderr = (stderr + data).slice(-8192);
|
|
60
|
+
});
|
|
61
|
+
child.once("error", finish);
|
|
62
|
+
child.stdin.on("error", () => void 0);
|
|
63
|
+
child.once("close", (code2) => finish(code2 === 0 ? void 0 : new Error(`SSH setup failed: ${stderr.trim() || `exit ${code2}`}. Verify ${this.host} with the same port and key in an SSH terminal first.`)));
|
|
64
|
+
child.stdin.end(payload);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
open(port, hostname = "127.0.0.1") {
|
|
68
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error("Invalid remote port");
|
|
69
|
+
if (!["localhost", "127.0.0.1", "::1", "[::1]"].includes(hostname)) throw new Error("SSH forwards only remote loopback addresses");
|
|
70
|
+
const host = hostname.includes(":") ? "[::1]" : hostname;
|
|
71
|
+
const child = this.start(["-W", `${host}:${port}`]);
|
|
72
|
+
const stream = new Duplex({
|
|
73
|
+
read() {
|
|
74
|
+
child.stdout.resume();
|
|
75
|
+
},
|
|
76
|
+
write(chunk, encoding, callback) {
|
|
77
|
+
child.stdin.write(chunk, encoding, callback);
|
|
78
|
+
},
|
|
79
|
+
final(callback) {
|
|
80
|
+
child.stdin.end(callback);
|
|
81
|
+
},
|
|
82
|
+
destroy(error, callback) {
|
|
83
|
+
child.stdin.destroy();
|
|
84
|
+
child.stdout.destroy();
|
|
85
|
+
child.kill();
|
|
86
|
+
callback(error);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
child.stdout.on("data", (chunk) => {
|
|
90
|
+
if (!stream.push(chunk)) child.stdout.pause();
|
|
91
|
+
});
|
|
92
|
+
child.stdout.on("end", () => stream.push(null));
|
|
93
|
+
child.stdout.on("error", (error) => stream.destroy(error));
|
|
94
|
+
stream.on("error", () => void 0);
|
|
95
|
+
child.stdin.on("error", () => void 0);
|
|
96
|
+
let stderr = "";
|
|
97
|
+
child.stderr.on("data", (data) => {
|
|
98
|
+
stderr = (stderr + data).slice(-2048);
|
|
99
|
+
});
|
|
100
|
+
child.once("error", (error) => stream.destroy(error));
|
|
101
|
+
child.once("close", (code) => {
|
|
102
|
+
if (code) stream.destroy(new Error(`SSH connection failed: ${stderr.trim() || `exit ${code}`}`));
|
|
103
|
+
});
|
|
104
|
+
return stream;
|
|
105
|
+
}
|
|
106
|
+
async close() {
|
|
107
|
+
if (this.closed) return;
|
|
108
|
+
const child = this.start(["-O", "exit"]);
|
|
109
|
+
child.on("error", () => void 0);
|
|
110
|
+
child.stdout.resume();
|
|
111
|
+
child.stderr.resume();
|
|
112
|
+
child.stdin.end();
|
|
113
|
+
await new Promise((resolve) => {
|
|
114
|
+
const timer = setTimeout(() => {
|
|
115
|
+
child.kill();
|
|
116
|
+
resolve();
|
|
117
|
+
}, 2e3);
|
|
118
|
+
child.once("close", () => {
|
|
119
|
+
clearTimeout(timer);
|
|
120
|
+
resolve();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
this.closed = true;
|
|
124
|
+
for (const process2 of this.children) process2.kill();
|
|
125
|
+
await rm(this.directory, { recursive: true, force: true });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
SshTransport,
|
|
130
|
+
quote,
|
|
131
|
+
validSshHost,
|
|
132
|
+
validSshOptions
|
|
133
|
+
};
|
package/src/stats.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { runPassed, checksLabel } from "./run-status.js";
|
|
2
|
+
const tokensOf = (r) => (r.usage.inputTokens ?? 0) + (r.usage.outputTokens ?? 0);
|
|
3
|
+
const lastLine = (stat) => stat?.trim().split("\n").pop()?.trim();
|
|
4
|
+
function computeStats(all, filter = {}) {
|
|
5
|
+
const runs = all.filter((r) => (!filter.repo || r.repo === filter.repo) && (!filter.since || r.createdAt >= filter.since));
|
|
6
|
+
const agents = /* @__PURE__ */ new Map();
|
|
7
|
+
const patterns = /* @__PURE__ */ new Map();
|
|
8
|
+
const cohorts = /* @__PURE__ */ new Map();
|
|
9
|
+
const agent = (id) => {
|
|
10
|
+
let a = agents.get(id);
|
|
11
|
+
if (!a) {
|
|
12
|
+
a = { agent: id, runs: 0, steps: 0, writeSteps: 0, failures: 0, inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, costUsd: 0, ms: 0, judged: 0, passed: 0, attributedJudged: 0, attributedPassed: 0, sharedJudged: 0, confidence: { low: 0, high: 1, samples: 0 }, raceEntries: 0, raceWins: 0, loopSolves: 0, findings: 0, agreedFindings: 0 };
|
|
13
|
+
agents.set(id, a);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
for (const r of runs) {
|
|
18
|
+
const sourceKind = r.source?.kind ?? "task";
|
|
19
|
+
const key = JSON.stringify([r.repo, r.pattern, sourceKind]);
|
|
20
|
+
const cohort = cohorts.get(key) ?? { key, repo: r.repo, pattern: r.pattern, sourceKind, runs: 0, judged: 0, passed: 0, tokens: 0, costUsd: 0, ms: 0 };
|
|
21
|
+
cohorts.set(key, cohort);
|
|
22
|
+
cohort.runs++;
|
|
23
|
+
if (r.status === "done" && ["Passed", "Failed"].includes(checksLabel(r))) {
|
|
24
|
+
cohort.judged++;
|
|
25
|
+
if (runPassed(r)) cohort.passed++;
|
|
26
|
+
}
|
|
27
|
+
cohort.tokens += tokensOf(r);
|
|
28
|
+
cohort.costUsd += r.usage.costUsd ?? 0;
|
|
29
|
+
cohort.ms += r.endedAt ? r.endedAt - r.createdAt : 0;
|
|
30
|
+
const p = patterns.get(r.pattern) ?? { pattern: r.pattern, runs: 0, done: 0, passed: 0, failing: 0, failed: 0, stopped: 0, flagged: 0, proven: 0, weak: 0, unproven: 0, ended: 0, ms: 0, steps: 0, tokens: 0, costUsd: 0 };
|
|
31
|
+
patterns.set(r.pattern, p);
|
|
32
|
+
p.runs++;
|
|
33
|
+
if (r.status === "done") p.done++;
|
|
34
|
+
if (r.status === "failed") p.failed++;
|
|
35
|
+
if (r.status === "stopped") p.stopped++;
|
|
36
|
+
if (runPassed(r)) p.passed++;
|
|
37
|
+
if (checksLabel(r) === "Failed") p.failing++;
|
|
38
|
+
if (r.integrity && Object.keys(r.integrity).length) p.flagged++;
|
|
39
|
+
if (r.facts?.proof === "proven") p.proven++;
|
|
40
|
+
if (r.facts?.proof === "weak") p.weak++;
|
|
41
|
+
if (r.facts?.proof === "unproven") p.unproven++;
|
|
42
|
+
if (r.endedAt) {
|
|
43
|
+
p.ended++;
|
|
44
|
+
p.ms += r.endedAt - r.createdAt;
|
|
45
|
+
}
|
|
46
|
+
p.steps += r.usage.agentSteps;
|
|
47
|
+
p.tokens += tokensOf(r);
|
|
48
|
+
p.costUsd += r.usage.costUsd ?? 0;
|
|
49
|
+
const writers = Object.values(r.usage.byAgent ?? {}).filter((u) => u && u.writeSteps > 0).length;
|
|
50
|
+
for (const [id, u] of Object.entries(r.usage.byAgent ?? {})) {
|
|
51
|
+
if (!u) continue;
|
|
52
|
+
const a = agent(id);
|
|
53
|
+
a.runs++;
|
|
54
|
+
a.steps += u.steps;
|
|
55
|
+
a.writeSteps += u.writeSteps;
|
|
56
|
+
a.failures += u.failures;
|
|
57
|
+
a.inputTokens += u.inputTokens;
|
|
58
|
+
a.outputTokens += u.outputTokens;
|
|
59
|
+
a.cacheReadTokens += u.cacheReadTokens;
|
|
60
|
+
a.costUsd += u.costUsd;
|
|
61
|
+
a.ms += u.ms;
|
|
62
|
+
if (u.writeSteps && r.status === "done" && ["Passed", "Failed"].includes(checksLabel(r))) {
|
|
63
|
+
a.judged++;
|
|
64
|
+
if (runPassed(r)) a.passed++;
|
|
65
|
+
if (writers === 1) {
|
|
66
|
+
a.attributedJudged++;
|
|
67
|
+
if (runPassed(r)) a.attributedPassed++;
|
|
68
|
+
} else a.sharedJudged++;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const id of r.facts?.entrants ?? []) agent(id).raceEntries++;
|
|
72
|
+
if (r.facts?.winner) agent(r.facts.winner).raceWins++;
|
|
73
|
+
if (r.facts?.solvedBy) agent(r.facts.solvedBy).loopSolves++;
|
|
74
|
+
for (const f of r.review?.findings ?? []) {
|
|
75
|
+
for (const id of f.raisedBy) {
|
|
76
|
+
agent(id).findings++;
|
|
77
|
+
if (f.raisedBy.length > 1) agent(id).agreedFindings++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
for (const a of agents.values()) a.confidence = { ...confidenceInterval(a.attributedPassed, a.attributedJudged), samples: a.attributedJudged };
|
|
82
|
+
const groups = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const r of runs) {
|
|
84
|
+
if (!r.group) continue;
|
|
85
|
+
const g = groups.get(r.group.id) ?? { id: r.group.id, task: r.task, createdAt: r.createdAt, runs: [] };
|
|
86
|
+
groups.set(r.group.id, g);
|
|
87
|
+
g.createdAt = Math.min(g.createdAt, r.createdAt);
|
|
88
|
+
g.runs.push({
|
|
89
|
+
id: r.id,
|
|
90
|
+
label: r.group.label,
|
|
91
|
+
pattern: r.pattern,
|
|
92
|
+
roles: r.roles,
|
|
93
|
+
status: r.status,
|
|
94
|
+
verdict: runPassed(r) ? "passed" : checksLabel(r) === "Failed" ? "failing" : void 0,
|
|
95
|
+
ms: r.endedAt ? r.endedAt - r.createdAt : void 0,
|
|
96
|
+
steps: r.usage.agentSteps,
|
|
97
|
+
tokens: tokensOf(r),
|
|
98
|
+
costUsd: r.usage.costUsd ?? 0,
|
|
99
|
+
flagged: Object.values(r.integrity ?? {}).flat().length,
|
|
100
|
+
proof: r.facts?.proof,
|
|
101
|
+
stat: lastLine(r.artifacts.find((a) => a.stat?.trim())?.stat)
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
runs: runs.length,
|
|
106
|
+
tokens: runs.reduce((n, r) => n + tokensOf(r), 0),
|
|
107
|
+
costUsd: runs.reduce((n, r) => n + (r.usage.costUsd ?? 0), 0),
|
|
108
|
+
ms: runs.reduce((n, r) => n + (r.endedAt ? r.endedAt - r.createdAt : 0), 0),
|
|
109
|
+
agents: [...agents.values()].sort((a, b) => b.runs - a.runs),
|
|
110
|
+
patterns: [...patterns.values()].sort((a, b) => b.runs - a.runs),
|
|
111
|
+
groups: [...groups.values()].sort((a, b) => b.createdAt - a.createdAt),
|
|
112
|
+
cohorts: [...cohorts.values()].sort((a, b) => b.runs - a.runs)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const MIN_SAMPLES = 3;
|
|
116
|
+
function rankAgents(runs, repo, cohort = {}) {
|
|
117
|
+
const comparable = runs.filter((r) => (!cohort.pattern || r.pattern === cohort.pattern) && (!cohort.sourceKind || (r.source?.kind ?? "task") === cohort.sourceKind));
|
|
118
|
+
const stats = computeStats(comparable, { repo }).agents.filter((a) => a.attributedJudged >= MIN_SAMPLES);
|
|
119
|
+
if (stats.length < 2) return { order: [], why: {} };
|
|
120
|
+
const ranked = stats.sort((a, b) => b.confidence.low - a.confidence.low || b.attributedJudged - a.attributedJudged || a.agent.localeCompare(b.agent));
|
|
121
|
+
return {
|
|
122
|
+
order: ranked.map((a) => a.agent),
|
|
123
|
+
why: Object.fromEntries(ranked.map((a) => [a.agent, `${a.attributedPassed} of ${a.attributedJudged} runs passed in this repo with this provider as the sole writer; 95% interval ${Math.round(100 * a.confidence.low)}\u2013${Math.round(100 * a.confidence.high)}%${a.sharedJudged ? `; ${a.sharedJudged} shared outcomes excluded` : ""}${cohort.pattern ? `; ${cohort.pattern} tasks` : "; task difficulty varies"}`]))
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function confidenceInterval(passed, samples) {
|
|
127
|
+
if (!samples) return { low: 0, high: 1 };
|
|
128
|
+
const z = 1.959963984540054;
|
|
129
|
+
const p = Math.max(0, Math.min(samples, passed)) / samples;
|
|
130
|
+
const denominator = 1 + z * z / samples;
|
|
131
|
+
const center = (p + z * z / (2 * samples)) / denominator;
|
|
132
|
+
const margin = z * Math.sqrt(p * (1 - p) / samples + z * z / (4 * samples * samples)) / denominator;
|
|
133
|
+
return { low: Math.max(0, center - margin), high: Math.min(1, center + margin) };
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
computeStats,
|
|
137
|
+
confidenceInterval,
|
|
138
|
+
rankAgents
|
|
139
|
+
};
|