toolroll 0.9.92 → 0.9.94
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/CHANGELOG.md +87 -0
- package/dist/activity-line.d.ts +7 -4
- package/dist/activity-line.js +9 -7
- package/dist/agent-fence.d.ts +4 -0
- package/dist/agent-fence.js +4 -1
- package/dist/approval-authority.d.ts +7 -1
- package/dist/approval-authority.js +11 -2
- package/dist/approval-password.d.ts +31 -0
- package/dist/approval-password.js +26 -0
- package/dist/assignment-status.d.ts +1 -1
- package/dist/assignment-ui.js +3 -3
- package/dist/assignment.js +16 -3
- package/dist/boot-identity.d.ts +2 -1
- package/dist/boot-identity.js +6 -4
- package/dist/bounded-spawn.d.ts +57 -0
- package/dist/bounded-spawn.js +220 -0
- package/dist/browser/terminal.js +42 -42
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +26 -26
- package/dist/browser-crew.js +2 -2
- package/dist/browser-shell.d.ts +1 -1
- package/dist/browser-shell.js +2 -2
- package/dist/browser-workspace.d.ts +48 -7
- package/dist/browser-workspace.js +3 -3
- package/dist/builder-restart.d.ts +21 -0
- package/dist/builder-restart.js +50 -0
- package/dist/builder.d.ts +4 -0
- package/dist/builder.js +73 -25
- package/dist/chat-acceptance.js +1 -1
- package/dist/chat-actions.d.ts +12 -2
- package/dist/chat-actions.js +25 -2
- package/dist/chat-channel.js +11 -0
- package/dist/chat-decide.d.ts +7 -2
- package/dist/chat-decide.js +37 -9
- package/dist/chat-quiet.js +3 -3
- package/dist/chat-voice.d.ts +1 -1
- package/dist/chat-voice.js +2 -2
- package/dist/check-facts.d.ts +126 -0
- package/dist/check-facts.js +318 -0
- package/dist/check-failure.d.ts +22 -3
- package/dist/check-failure.js +57 -13
- package/dist/check-levels-ui.d.ts +4 -0
- package/dist/check-levels-ui.js +10 -1
- package/dist/check-load.d.ts +85 -0
- package/dist/check-load.js +147 -0
- package/dist/check-only-standing.d.ts +36 -0
- package/dist/check-only-standing.js +39 -0
- package/dist/check-only.d.ts +15 -0
- package/dist/check-only.js +99 -0
- package/dist/check-report.d.ts +7 -0
- package/dist/check-report.js +4 -3
- package/dist/check-stamp.d.ts +46 -0
- package/dist/check-stamp.js +93 -0
- package/dist/checkout-cleanup.d.ts +36 -5
- package/dist/checkout-cleanup.js +166 -14
- package/dist/cli-help.d.ts +4 -1
- package/dist/cli-help.js +47 -30
- package/dist/cli.js +16 -1
- package/dist/code-extract.d.ts +44 -0
- package/dist/code-extract.js +88 -0
- package/dist/code-map-acts.d.ts +24 -0
- package/dist/code-map-acts.js +53 -0
- package/dist/code-map-admission.d.ts +52 -0
- package/dist/code-map-admission.js +295 -0
- package/dist/code-map-build.d.ts +63 -0
- package/dist/code-map-build.js +415 -0
- package/dist/code-map-cli.d.ts +153 -0
- package/dist/code-map-cli.js +103 -0
- package/dist/code-map-main.d.ts +1 -0
- package/dist/code-map-main.js +48 -0
- package/dist/code-map-read.d.ts +106 -0
- package/dist/code-map-read.js +171 -0
- package/dist/code-map-report.d.ts +37 -0
- package/dist/code-map-report.js +95 -0
- package/dist/code-map-shape.d.ts +172 -0
- package/dist/code-map-shape.js +327 -0
- package/dist/code-map-store.d.ts +136 -0
- package/dist/code-map-store.js +233 -0
- package/dist/coding-provider.d.ts +2 -0
- package/dist/coding-provider.js +3 -2
- package/dist/coding-update.js +3 -2
- package/dist/coding-workspace.js +4 -4
- package/dist/console-chrome.js +2 -2
- package/dist/containment.d.ts +5 -0
- package/dist/containment.js +14 -1
- package/dist/contracts/chat-actions.d.ts +9 -0
- package/dist/contracts/chat-actions.js +2 -0
- package/dist/contracts/cli.d.ts +52 -0
- package/dist/contracts/cli.js +4 -0
- package/dist/contracts/console-api.d.ts +12 -5
- package/dist/contracts/console-api.js +12 -5
- package/dist/contracts/gateway-tools.d.ts +17 -0
- package/dist/contracts/gateway-tools.js +3 -1
- package/dist/contracts/lead-tools.d.ts +61 -0
- package/dist/contracts/lead-tools.js +10 -1
- package/dist/contracts/project-knowledge.d.ts +38 -5
- package/dist/contracts/project-knowledge.js +11 -5
- package/dist/contracts/project-memory.d.ts +3 -1
- package/dist/contracts/project-memory.js +3 -2
- package/dist/contracts/release-check.d.ts +25 -1
- package/dist/contracts/release-check.js +19 -0
- package/dist/contracts/storage.d.ts +14 -0
- package/dist/contracts/storage.js +3 -1
- package/dist/contracts/store-json.d.ts +2 -0
- package/dist/contracts/youiyoux-request.d.ts +1 -1
- package/dist/contracts/youiyoux-request.js +1 -1
- package/dist/desktop-access.js +6 -2
- package/dist/desktop-update.d.ts +2 -2
- package/dist/desktop-update.js +13 -9
- package/dist/dispatch.js +18 -15
- package/dist/dispose.js +8 -2
- package/dist/easy-start.js +2 -3
- package/dist/eval-hooks.d.ts +55 -0
- package/dist/eval-hooks.js +227 -4
- package/dist/evals.js +2 -1
- package/dist/fast-start.d.ts +136 -0
- package/dist/fast-start.js +431 -0
- package/dist/fast-terms.d.ts +9 -0
- package/dist/fast-terms.js +23 -0
- package/dist/fenced-check-coverage.d.ts +62 -0
- package/dist/fenced-check-coverage.js +54 -0
- package/dist/first-run.js +1 -1
- package/dist/flaky-ci.d.ts +31 -0
- package/dist/flaky-ci.js +149 -0
- package/dist/flaky-cli.d.ts +60 -0
- package/dist/flaky-cli.js +60 -0
- package/dist/flaky.d.ts +83 -0
- package/dist/flaky.js +264 -0
- package/dist/flow-card-task.js +3 -0
- package/dist/flow-triggers.d.ts +1 -1
- package/dist/flow-triggers.js +1 -1
- package/dist/github-import.d.ts +62 -0
- package/dist/github-import.js +146 -0
- package/dist/guides.js +15 -10
- package/dist/invoke.d.ts +5 -1
- package/dist/invoke.js +49 -14
- package/dist/job-object-helper.ps1 +10 -3
- package/dist/keymap.d.ts +41 -0
- package/dist/keymap.js +51 -0
- package/dist/knowledge-cli.js +1 -1
- package/dist/knowledge-ui.d.ts +21 -4
- package/dist/knowledge-ui.js +75 -7
- package/dist/laptop-background.d.ts +16 -0
- package/dist/laptop-background.js +108 -2
- package/dist/lead-context.js +1 -1
- package/dist/lead-contract.d.ts +1 -1
- package/dist/lead-contract.js +2 -2
- package/dist/lead-progress.js +3 -0
- package/dist/lead-status.d.ts +2 -0
- package/dist/lead-status.js +6 -2
- package/dist/lead-tools.js +51 -2
- package/dist/lead.js +1 -1
- package/dist/lesson-notes.d.ts +81 -0
- package/dist/lesson-notes.js +336 -0
- package/dist/limits-ui.js +1 -1
- package/dist/local-owner.d.ts +1 -1
- package/dist/local-owner.js +11 -0
- package/dist/machine-check.d.ts +16 -0
- package/dist/machine-check.js +26 -0
- package/dist/machine-identity.d.ts +75 -0
- package/dist/machine-identity.js +170 -0
- package/dist/mcp-core.js +11 -1
- package/dist/memory-cli.d.ts +300 -1
- package/dist/memory-cli.js +62 -9
- package/dist/memory-pass.d.ts +16 -0
- package/dist/memory-pass.js +67 -3
- package/dist/memory-tidy.d.ts +181 -0
- package/dist/memory-tidy.js +523 -0
- package/dist/memory-use.d.ts +35 -0
- package/dist/memory-use.js +109 -0
- package/dist/merge-checklist.d.ts +55 -0
- package/dist/merge-checklist.js +182 -0
- package/dist/needs-you.d.ts +32 -13
- package/dist/needs-you.js +108 -49
- package/dist/nightly-github.d.ts +2 -0
- package/dist/nightly-github.js +4 -4
- package/dist/operate-remote-arguments.js +6 -1
- package/dist/operate-remote.js +3 -1
- package/dist/operate.d.ts +6 -1
- package/dist/operate.js +540 -70
- package/dist/phase-routing.js +2 -2
- package/dist/plain-schema.d.ts +23 -0
- package/dist/plain-schema.js +94 -0
- package/dist/plain-words.d.ts +20 -0
- package/dist/plain-words.js +66 -0
- package/dist/planner.js +2 -1
- package/dist/process-liveness.d.ts +2 -0
- package/dist/process-liveness.js +61 -17
- package/dist/project-delete-ui.d.ts +7 -2
- package/dist/project-delete-ui.js +12 -1
- package/dist/project-delete.js +13 -2
- package/dist/project-knowledge.d.ts +18 -11
- package/dist/project-knowledge.js +39 -9
- package/dist/project-learning.d.ts +2 -1
- package/dist/project-learning.js +15 -45
- package/dist/project-memory.d.ts +5 -0
- package/dist/project-memory.js +22 -2
- package/dist/proof.js +30 -5
- package/dist/provider-auth.js +1 -1
- package/dist/publish.js +9 -1
- package/dist/pull-request-flow.js +5 -0
- package/dist/push.d.ts +26 -3
- package/dist/push.js +55 -15
- package/dist/release-adapters.d.ts +9 -0
- package/dist/release-adapters.js +87 -1
- package/dist/release-approval.d.ts +191 -0
- package/dist/release-approval.js +382 -0
- package/dist/release-auto.js +26 -17
- package/dist/release-card.d.ts +74 -6
- package/dist/release-card.js +179 -23
- package/dist/release-carry.d.ts +7 -2
- package/dist/release-carry.js +39 -9
- package/dist/release-cli.d.ts +4 -0
- package/dist/release-cli.js +38 -23
- package/dist/release-coverage.js +1 -1
- package/dist/release-next.d.ts +48 -0
- package/dist/release-next.js +161 -0
- package/dist/release.d.ts +50 -1
- package/dist/release.js +118 -11
- package/dist/remote-destination.d.ts +36 -0
- package/dist/remote-destination.js +217 -0
- package/dist/remote-main.d.ts +48 -0
- package/dist/remote-main.js +84 -5
- package/dist/repository-context.d.ts +3 -2
- package/dist/repository-context.js +112 -70
- package/dist/restart-certification.d.ts +1 -0
- package/dist/restart-certification.js +8 -6
- package/dist/result-acts.d.ts +29 -21
- package/dist/result-acts.js +36 -25
- package/dist/result-follow-ups.d.ts +2 -2
- package/dist/result-follow-ups.js +18 -4
- package/dist/result-review.d.ts +1 -1
- package/dist/route-change-check.d.ts +4 -0
- package/dist/route-change-check.js +13 -0
- package/dist/route-change.d.ts +22 -0
- package/dist/route-change.js +89 -0
- package/dist/route-hooks.js +3 -2
- package/dist/route-results.d.ts +6 -1
- package/dist/route-results.js +14 -5
- package/dist/run-closeout.d.ts +1 -1
- package/dist/run-closeout.js +7 -5
- package/dist/runner-process.js +3 -2
- package/dist/runner.js +2 -1
- package/dist/scope.d.ts +6 -1
- package/dist/scope.js +22 -9
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +24 -18
- package/dist/server/chat.js +14 -12
- package/dist/server/chrome.d.ts +1 -1
- package/dist/server/chrome.js +26 -35
- package/dist/server/console.css +23 -0
- package/dist/server/guards.js +4 -0
- package/dist/server/home.d.ts +6 -0
- package/dist/server/home.js +21 -13
- package/dist/server/http.js +1 -1
- package/dist/server/kit.js +1 -1
- package/dist/server/merge-ready-view.d.ts +10 -0
- package/dist/server/merge-ready-view.js +30 -0
- package/dist/server/pages-assets.d.ts +1 -0
- package/dist/server/pages-assets.js +8 -5
- package/dist/server/pages.js +103 -82
- package/dist/server/render-chat.js +2 -2
- package/dist/server/render-code-map.d.ts +30 -0
- package/dist/server/render-code-map.js +137 -0
- package/dist/server/render-flaky.d.ts +20 -0
- package/dist/server/render-flaky.js +59 -0
- package/dist/server/render-history.js +1 -1
- package/dist/server/render-new-task.d.ts +26 -1
- package/dist/server/render-new-task.js +30 -5
- package/dist/server/render-pages.d.ts +1 -175
- package/dist/server/render-pages.js +38 -313
- package/dist/server/render-projects.d.ts +2 -1
- package/dist/server/render-projects.js +9 -7
- package/dist/server/render-release.d.ts +19 -0
- package/dist/server/render-release.js +84 -0
- package/dist/server/render-results.d.ts +2 -2
- package/dist/server/render-results.js +71 -73
- package/dist/server/render-tasks.d.ts +13 -2
- package/dist/server/render-tasks.js +156 -139
- package/dist/server/retired-routes.d.ts +17 -0
- package/dist/server/retired-routes.js +53 -0
- package/dist/server/route-table.d.ts +4 -1
- package/dist/server/route-table.js +52 -13
- package/dist/server/settings.js +129 -22
- package/dist/server/task-views.js +61 -26
- package/dist/server/tasks.d.ts +17 -6
- package/dist/server/tasks.js +273 -338
- package/dist/server/welcome.js +1 -1
- package/dist/settings-groups-ui.js +1 -1
- package/dist/setup-guide.d.ts +2 -2
- package/dist/stop-proof.d.ts +67 -0
- package/dist/stop-proof.js +295 -0
- package/dist/storage-sweep-process.js +1 -1
- package/dist/storage-sweep.d.ts +5 -3
- package/dist/storage-sweep.js +30 -9
- package/dist/storage-ui.js +28 -17
- package/dist/storage.d.ts +27 -2
- package/dist/storage.js +39 -2
- package/dist/store.d.ts +148 -34
- package/dist/store.js +626 -177
- package/dist/surface.js +46 -5
- package/dist/sweep-quarantine.d.ts +1 -0
- package/dist/sweep-quarantine.js +6 -4
- package/dist/tamper-scan.d.ts +4 -0
- package/dist/tamper-scan.js +90 -0
- package/dist/task-aliases.d.ts +5 -0
- package/dist/task-aliases.js +9 -0
- package/dist/task-control.js +4 -1
- package/dist/task-outcome-cli.d.ts +2 -0
- package/dist/task-outcome-cli.js +36 -17
- package/dist/task-sizing.d.ts +5 -0
- package/dist/task-sizing.js +2 -0
- package/dist/task-source.d.ts +7 -0
- package/dist/task-source.js +14 -0
- package/dist/task-status.d.ts +9 -0
- package/dist/task-status.js +40 -49
- package/dist/teardown-git.d.ts +16 -0
- package/dist/teardown-git.js +63 -5
- package/dist/telegram-progress.js +5 -3
- package/dist/telegram-status.js +6 -4
- package/dist/test-infra.d.ts +8 -0
- package/dist/test-infra.js +18 -0
- package/dist/tidy.js +1 -1
- package/dist/toolroll-update-ui.js +2 -2
- package/dist/toolroll-update.js +18 -5
- package/dist/tui-contract.d.ts +24 -0
- package/dist/tui-source.js +67 -8
- package/dist/tui.js +51 -51
- package/dist/vanished-retry.d.ts +30 -0
- package/dist/vanished-retry.js +174 -0
- package/dist/work-index.d.ts +2 -0
- package/dist/work-index.js +82 -70
- package/dist/work-summary.d.ts +2 -2
- package/dist/work-summary.js +2 -0
- package/dist/workspace-ui.d.ts +4 -2
- package/dist/workspace-ui.js +28 -22
- package/dist/worktree.d.ts +12 -3
- package/dist/worktree.js +68 -13
- package/package.json +1 -1
- package/dist/server/render-next.d.ts +0 -63
- package/dist/server/render-next.js +0 -109
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The code map's records (docs/plans/code-map.md §3): immutable versions, the pointer to the current one, and the
|
|
3
|
+
* per-project refresh record whose lease fences every later write. Delivery and measurement rows sit here too. The
|
|
4
|
+
* rows are Toolroll's own; nothing goes in a repository.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
8
|
+
import { trustedRemoteIdentity } from "./store.js";
|
|
9
|
+
import { LIMITS } from "./code-map-shape.js";
|
|
10
|
+
export const V152_SCHEMA = `
|
|
11
|
+
CREATE TABLE IF NOT EXISTS code_map_version (
|
|
12
|
+
id INTEGER PRIMARY KEY, repo TEXT NOT NULL, remote_digest TEXT NOT NULL, remote_record INTEGER NOT NULL, commit_sha TEXT NOT NULL,
|
|
13
|
+
extractor TEXT NOT NULL, built_at TEXT NOT NULL, manifest BLOB NOT NULL, manifest_sha TEXT NOT NULL, graph BLOB NOT NULL, graph_sha TEXT NOT NULL, report TEXT NOT NULL
|
|
14
|
+
);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS code_map_version_repo ON code_map_version (repo, id);
|
|
16
|
+
CREATE TABLE IF NOT EXISTS code_map_current (repo TEXT PRIMARY KEY, version INTEGER NOT NULL REFERENCES code_map_version(id));
|
|
17
|
+
CREATE TABLE IF NOT EXISTS code_map_refresh (
|
|
18
|
+
repo TEXT PRIMARY KEY, lease_token INTEGER NOT NULL DEFAULT 0, lease_owner TEXT, lease_until TEXT,
|
|
19
|
+
request_id INTEGER NOT NULL DEFAULT 0, requested_at TEXT, requested_by TEXT,
|
|
20
|
+
failures INTEGER NOT NULL DEFAULT 0, retry_after TEXT, last_error TEXT, last_checked_at TEXT,
|
|
21
|
+
seen_digest TEXT, seen_record INTEGER, seen_commit TEXT, seen_extractor TEXT, seen_state TEXT,
|
|
22
|
+
spawn_pid INTEGER, spawn_pgid INTEGER, spawn_started TEXT, spawn_folder TEXT, enforced TEXT, proxy TEXT
|
|
23
|
+
);
|
|
24
|
+
CREATE TABLE IF NOT EXISTS code_map_family (
|
|
25
|
+
root_task TEXT PRIMARY KEY, repo TEXT NOT NULL, arm TEXT NOT NULL CHECK (arm IN ('map','holdout')), enrolled_at TEXT NOT NULL, observe_until TEXT NOT NULL
|
|
26
|
+
);
|
|
27
|
+
CREATE INDEX IF NOT EXISTS code_map_family_repo ON code_map_family (repo);
|
|
28
|
+
CREATE TABLE IF NOT EXISTS code_map_snapshot (
|
|
29
|
+
run INTEGER PRIMARY KEY, state TEXT NOT NULL CHECK (state IN ('map','off','none','remote-changed','holdout','unavailable')),
|
|
30
|
+
version INTEGER, excerpt TEXT NOT NULL, excerpt_sha TEXT NOT NULL, file_selected INTEGER NOT NULL CHECK (file_selected IN (0,1))
|
|
31
|
+
);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS code_map_snapshot_version ON code_map_snapshot (version);
|
|
33
|
+
CREATE TABLE IF NOT EXISTS code_map_delivery (
|
|
34
|
+
id INTEGER PRIMARY KEY, run INTEGER NOT NULL, attempt INTEGER NOT NULL, at TEXT NOT NULL,
|
|
35
|
+
outcome TEXT NOT NULL CHECK (outcome IN ('delivered','not-delivered')),
|
|
36
|
+
reason TEXT CHECK (reason IS NULL OR reason IN ('no-confinement','write-failed','sha-mismatch','version-pruned','not-selected')), path_sha TEXT,
|
|
37
|
+
UNIQUE (run, attempt)
|
|
38
|
+
);
|
|
39
|
+
CREATE TABLE IF NOT EXISTS code_map_meta (id INTEGER PRIMARY KEY CHECK (id = 1), run_watermark INTEGER NOT NULL);
|
|
40
|
+
CREATE TRIGGER IF NOT EXISTS code_map_version_no_update BEFORE UPDATE ON code_map_version BEGIN SELECT RAISE(ABORT,'a code map version is immutable'); END;
|
|
41
|
+
CREATE TRIGGER IF NOT EXISTS code_map_version_guarded_delete BEFORE DELETE ON code_map_version
|
|
42
|
+
WHEN EXISTS (SELECT 1 FROM code_map_current WHERE version = OLD.id)
|
|
43
|
+
OR EXISTS (SELECT 1 FROM code_map_snapshot s JOIN run r ON r.id = s.run WHERE s.version = OLD.id AND r.outcome IS NULL)
|
|
44
|
+
BEGIN SELECT RAISE(ABORT,'a code map version in use stays'); END;
|
|
45
|
+
CREATE TRIGGER IF NOT EXISTS code_map_family_no_update BEFORE UPDATE ON code_map_family BEGIN SELECT RAISE(ABORT,'a family arm is frozen'); END;
|
|
46
|
+
CREATE TRIGGER IF NOT EXISTS code_map_family_no_delete BEFORE DELETE ON code_map_family BEGIN SELECT RAISE(ABORT,'a family arm is frozen'); END;
|
|
47
|
+
CREATE TRIGGER IF NOT EXISTS code_map_snapshot_no_update BEFORE UPDATE ON code_map_snapshot BEGIN SELECT RAISE(ABORT,'a code map snapshot is immutable'); END;
|
|
48
|
+
CREATE TRIGGER IF NOT EXISTS code_map_snapshot_no_delete BEFORE DELETE ON code_map_snapshot BEGIN SELECT RAISE(ABORT,'a code map snapshot is immutable'); END;
|
|
49
|
+
CREATE TRIGGER IF NOT EXISTS code_map_delivery_no_update BEFORE UPDATE ON code_map_delivery BEGIN SELECT RAISE(ABORT,'a code map delivery is immutable'); END;
|
|
50
|
+
CREATE TRIGGER IF NOT EXISTS code_map_delivery_no_delete BEFORE DELETE ON code_map_delivery BEGIN SELECT RAISE(ABORT,'a code map delivery is immutable'); END;
|
|
51
|
+
CREATE TRIGGER IF NOT EXISTS code_map_meta_no_update BEFORE UPDATE ON code_map_meta BEGIN SELECT RAISE(ABORT,'the watermark is set once'); END;
|
|
52
|
+
CREATE TRIGGER IF NOT EXISTS code_map_meta_no_delete BEFORE DELETE ON code_map_meta BEGIN SELECT RAISE(ABORT,'the watermark is set once'); END;
|
|
53
|
+
`;
|
|
54
|
+
/** The tables and triggers V152_SCHEMA makes, for the startup check and the tests. */
|
|
55
|
+
export const V152_TABLES = Object.freeze(["code_map_version", "code_map_current", "code_map_refresh", "code_map_family", "code_map_snapshot", "code_map_delivery", "code_map_meta"]);
|
|
56
|
+
export const V152_TRIGGERS = Object.freeze(["code_map_version_no_update", "code_map_version_guarded_delete", "code_map_family_no_update", "code_map_family_no_delete", "code_map_snapshot_no_update",
|
|
57
|
+
"code_map_snapshot_no_delete", "code_map_delivery_no_update", "code_map_delivery_no_delete", "code_map_meta_no_update", "code_map_meta_no_delete"]);
|
|
58
|
+
/** v152: a saved project reads the map on, with no enrollment yet. */
|
|
59
|
+
export const V152_ADDED_COLUMNS = Object.freeze({
|
|
60
|
+
project: {
|
|
61
|
+
code_map: { definition: "INTEGER NOT NULL DEFAULT 1 CHECK (code_map IN (0,1))", saved: "1" },
|
|
62
|
+
code_map_enroll_until: { definition: "TEXT", saved: "NULL" },
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const sha = (value) => createHash("sha256").update(value).digest("hex");
|
|
66
|
+
export const digestOfUrl = (url) => sha(url);
|
|
67
|
+
export const CODE_MAP_ACT = "code map check";
|
|
68
|
+
const sameIdentity = (a, b) => a !== null && b !== null && a.url === b.url && a.record === b.record;
|
|
69
|
+
export function codeMapOn(store, repo) {
|
|
70
|
+
const row = store.handle.prepare("SELECT code_map FROM project WHERE path = ?").get(repo);
|
|
71
|
+
return row !== undefined && Number(row["code_map"]) === 1;
|
|
72
|
+
}
|
|
73
|
+
const textOf = (value) => (typeof value === "string" ? value : null);
|
|
74
|
+
const intOf = (value) => (value === null || value === undefined ? null : Number(value));
|
|
75
|
+
function refreshOf(row) {
|
|
76
|
+
return {
|
|
77
|
+
repo: String(row["repo"]), leaseToken: Number(row["lease_token"]), leaseOwner: textOf(row["lease_owner"]), leaseUntil: textOf(row["lease_until"]), requestId: Number(row["request_id"]),
|
|
78
|
+
requestedAt: textOf(row["requested_at"]), requestedBy: textOf(row["requested_by"]), failures: Number(row["failures"]), retryAfter: textOf(row["retry_after"]), lastError: textOf(row["last_error"]),
|
|
79
|
+
lastCheckedAt: textOf(row["last_checked_at"]), seen: { digest: textOf(row["seen_digest"]), record: intOf(row["seen_record"]), commit: textOf(row["seen_commit"]), extractor: textOf(row["seen_extractor"]), state: textOf(row["seen_state"]) },
|
|
80
|
+
spawn: { pid: intOf(row["spawn_pid"]), pgid: intOf(row["spawn_pgid"]), startedAt: textOf(row["spawn_started"]), folder: textOf(row["spawn_folder"]) }, enforced: textOf(row["enforced"]), proxy: textOf(row["proxy"]),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function readRefresh(store, repo) {
|
|
84
|
+
const row = store.handle.prepare("SELECT * FROM code_map_refresh WHERE repo = ?").get(repo);
|
|
85
|
+
return row === undefined ? null : refreshOf(row);
|
|
86
|
+
}
|
|
87
|
+
const ensureRefresh = (store, repo) => { store.handle.prepare("INSERT OR IGNORE INTO code_map_refresh (repo) VALUES (?)").run(repo); };
|
|
88
|
+
export const LEASE_MS = 10 * 60_000;
|
|
89
|
+
/** Take the lease in one statement. A takeover always gets a higher token; null when it is held. */
|
|
90
|
+
export function takeLease(store, repo, owner, now) {
|
|
91
|
+
ensureRefresh(store, repo);
|
|
92
|
+
const before = readRefresh(store, repo);
|
|
93
|
+
const taken = store.handle.prepare(`UPDATE code_map_refresh SET lease_token = lease_token + 1, lease_owner = ?, lease_until = ?
|
|
94
|
+
WHERE repo = ? AND (lease_owner IS NULL OR lease_until < ?)`).run(owner, new Date(now.getTime() + LEASE_MS).toISOString(), repo, now.toISOString());
|
|
95
|
+
if (Number(taken.changes) !== 1)
|
|
96
|
+
return null;
|
|
97
|
+
const after = readRefresh(store, repo);
|
|
98
|
+
return { repo, token: after.leaseToken, owner, requestId: after.requestId, previous: before.spawn };
|
|
99
|
+
}
|
|
100
|
+
/** A fenced write: changes rows only while this lease stands. Zero rows means the lease was lost. */
|
|
101
|
+
function fenced(store, lease, set, values, extra = "", extraValues = []) {
|
|
102
|
+
const ran = store.handle.prepare(`UPDATE code_map_refresh SET ${set} WHERE repo = ? AND lease_token = ? AND lease_owner = ?${extra}`).run(...values, lease.repo, lease.token, lease.owner, ...extraValues);
|
|
103
|
+
return Number(ran.changes) === 1;
|
|
104
|
+
}
|
|
105
|
+
export const extendLease = (store, lease, now) => fenced(store, lease, "lease_until = ?", [new Date(now.getTime() + LEASE_MS).toISOString()]);
|
|
106
|
+
export const releaseLease = (store, lease) => fenced(store, lease, "lease_owner = NULL, lease_until = NULL, spawn_pid = NULL, spawn_pgid = NULL, spawn_started = NULL, spawn_folder = NULL", []);
|
|
107
|
+
export const clearOldSpawn = (store, lease) => fenced(store, lease, "spawn_pid = NULL, spawn_pgid = NULL, spawn_started = NULL, spawn_folder = NULL", []);
|
|
108
|
+
export const recordFolder = (store, lease, folder) => fenced(store, lease, "spawn_folder = ?", [folder]);
|
|
109
|
+
export const recordSpawn = (store, lease, spawn) => fenced(store, lease, "spawn_pid = ?, spawn_pgid = ?, spawn_started = ?", [spawn.pid, spawn.pgid, spawn.startedAt]);
|
|
110
|
+
/** Clear the request this lease saw, and only that one: a request made during the build stays queued. */
|
|
111
|
+
export const clearRequest = (store, lease) => fenced(store, lease, "requested_at = NULL, requested_by = NULL", [], " AND request_id = ?", [lease.requestId]);
|
|
112
|
+
/** A finished check that found nothing wrong: failures reset. */
|
|
113
|
+
export const recordCheck = (store, lease, facts, now) => fenced(store, lease, "failures = 0, retry_after = NULL, last_error = NULL, last_checked_at = ?, seen_digest = ?, seen_record = ?, seen_commit = ?, seen_extractor = ?, seen_state = ?, enforced = COALESCE(?, enforced), proxy = ?", [now.toISOString(), facts.digest, facts.record, facts.commit, facts.extractor, facts.state, facts.enforced ?? null, facts.proxy ?? null]);
|
|
114
|
+
/** What the peek saw, kept even if the build then fails: the page's "Main has moved to …". */
|
|
115
|
+
export const recordPeek = (store, lease, commit) => fenced(store, lease, "seen_commit = ?", [commit]);
|
|
116
|
+
export const BACKOFF_MS = [30 * 60_000, 2 * 3_600_000, 6 * 3_600_000];
|
|
117
|
+
/** A failed check: 30 minutes, then 2 hours, then 6 hours. */
|
|
118
|
+
export function recordFailure(store, lease, why, state, now) {
|
|
119
|
+
const failures = readRefresh(store, lease.repo)?.failures ?? 0;
|
|
120
|
+
const wait = BACKOFF_MS[Math.min(failures, BACKOFF_MS.length - 1)];
|
|
121
|
+
return fenced(store, lease, "failures = failures + 1, retry_after = ?, last_error = ?, last_checked_at = ?, seen_state = ?", [new Date(now.getTime() + wait).toISOString(), why.slice(0, 300), now.toISOString(), state]);
|
|
122
|
+
}
|
|
123
|
+
export const REQUEST_GAP_MS = 10 * 60_000;
|
|
124
|
+
/** Queue a manual check: at most one per project per 10 minutes. It never bypasses back-off. */
|
|
125
|
+
export function requestRefresh(store, repo, by, now) {
|
|
126
|
+
return store.transact(() => {
|
|
127
|
+
ensureRefresh(store, repo);
|
|
128
|
+
const held = readRefresh(store, repo);
|
|
129
|
+
if (held.requestedAt !== null)
|
|
130
|
+
return "already-queued";
|
|
131
|
+
const last = store.handle.prepare("SELECT at FROM action_ledger WHERE repo = ? AND action = 'code map refresh asked' ORDER BY id DESC LIMIT 1").get(repo);
|
|
132
|
+
if (last !== undefined && now.getTime() - Date.parse(String(last["at"])) < REQUEST_GAP_MS)
|
|
133
|
+
return "already-queued";
|
|
134
|
+
store.handle.prepare("UPDATE code_map_refresh SET request_id = request_id + 1, requested_at = ?, requested_by = ? WHERE repo = ?").run(now.toISOString(), by, repo);
|
|
135
|
+
store.recordAction({ at: now.toISOString(), actor: by, repo, taskId: null, runId: null, action: "code map refresh asked", outcome: "queued", source: "request", detail: null });
|
|
136
|
+
return "queued";
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/** The remote-change transaction's part: the pointer clears and a build still running for the old remote is fenced out.
|
|
140
|
+
* Called from store.recordProjectRemote, inside the transaction that records the new remote. */
|
|
141
|
+
export function codeMapRemoteChanged(store, repo) {
|
|
142
|
+
store.handle.prepare("DELETE FROM code_map_current WHERE repo = ?").run(repo);
|
|
143
|
+
store.handle.prepare("UPDATE code_map_refresh SET lease_token = lease_token + 1, lease_owner = NULL, lease_until = NULL, seen_commit = NULL, seen_digest = NULL, seen_record = NULL, failures = 0, retry_after = NULL WHERE repo = ?").run(repo);
|
|
144
|
+
}
|
|
145
|
+
const versionOf = (row) => ({ id: Number(row["id"]), repo: String(row["repo"]), remoteDigest: String(row["remote_digest"]), remoteRecord: Number(row["remote_record"]),
|
|
146
|
+
commit: String(row["commit_sha"]), extractor: String(row["extractor"]), builtAt: String(row["built_at"]), report: String(row["report"]) });
|
|
147
|
+
const VERSION_COLUMNS = "id, repo, remote_digest, remote_record, commit_sha, extractor, built_at, report";
|
|
148
|
+
export function currentVersion(store, repo) {
|
|
149
|
+
const row = store.handle.prepare(`SELECT ${VERSION_COLUMNS} FROM code_map_version WHERE id = (SELECT version FROM code_map_current WHERE repo = ?)`).get(repo);
|
|
150
|
+
return row === undefined ? null : versionOf(row);
|
|
151
|
+
}
|
|
152
|
+
export function versionRow(store, id) {
|
|
153
|
+
const row = store.handle.prepare(`SELECT ${VERSION_COLUMNS} FROM code_map_version WHERE id = ?`).get(id);
|
|
154
|
+
return row === undefined ? null : versionOf(row);
|
|
155
|
+
}
|
|
156
|
+
/** The stored bytes, checked against their digests before they are parsed; null when they don't verify. */
|
|
157
|
+
export function readVersionMap(store, id) {
|
|
158
|
+
const row = store.handle.prepare("SELECT manifest, manifest_sha, graph, graph_sha FROM code_map_version WHERE id = ?").get(id);
|
|
159
|
+
if (row === undefined)
|
|
160
|
+
return null;
|
|
161
|
+
try {
|
|
162
|
+
const manifest = gunzipSync(row["manifest"], { maxOutputLength: LIMITS.storedBytes * 2 });
|
|
163
|
+
const graph = gunzipSync(row["graph"], { maxOutputLength: LIMITS.storedBytes * 2 });
|
|
164
|
+
if (sha(manifest) !== row["manifest_sha"] || sha(graph) !== row["graph_sha"])
|
|
165
|
+
return null;
|
|
166
|
+
return { ...JSON.parse(manifest.toString("utf8")), ...JSON.parse(graph.toString("utf8")) };
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
export function encodeMap(map) {
|
|
173
|
+
const { edges, ...rest } = map;
|
|
174
|
+
const manifest = Buffer.from(JSON.stringify(rest));
|
|
175
|
+
const graph = Buffer.from(JSON.stringify({ edges }));
|
|
176
|
+
return { manifest: gzipSync(manifest), manifestSha: sha(manifest), graph: gzipSync(graph), graphSha: sha(graph), bytes: manifest.length + graph.length };
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Store a built version and, in the same transaction, make it current only if the identity captured before the fetch
|
|
180
|
+
* still stands, the map is still on, the build still holds its lease, and the pointer is where it found it. A build that
|
|
181
|
+
* lost its lease stores nothing at all.
|
|
182
|
+
*/
|
|
183
|
+
export function publishVersion(store, lease, input, now) {
|
|
184
|
+
return store.transact(() => {
|
|
185
|
+
const held = readRefresh(store, lease.repo);
|
|
186
|
+
if (held === null || held.leaseToken !== lease.token || held.leaseOwner !== lease.owner)
|
|
187
|
+
return null;
|
|
188
|
+
const { map, encoded } = input;
|
|
189
|
+
const stored = store.handle.prepare(`INSERT INTO code_map_version (repo, remote_digest, remote_record, commit_sha, extractor, built_at, manifest, manifest_sha, graph, graph_sha, report)
|
|
190
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(lease.repo, map.remote.urlDigest, map.remote.record, map.commit, map.extractor, now.toISOString(), encoded.manifest, encoded.manifestSha, encoded.graph, encoded.graphSha, input.report);
|
|
191
|
+
const version = Number(stored.lastInsertRowid);
|
|
192
|
+
const pointer = store.handle.prepare("SELECT version FROM code_map_current WHERE repo = ?").get(lease.repo);
|
|
193
|
+
const at = pointer === undefined ? null : Number(pointer["version"]);
|
|
194
|
+
if (!sameIdentity(input.identity, trustedRemoteIdentity(store, lease.repo)))
|
|
195
|
+
return { version, current: false, why: "remote-changed" };
|
|
196
|
+
if (!codeMapOn(store, lease.repo))
|
|
197
|
+
return { version, current: false, why: "off" };
|
|
198
|
+
if (at !== input.startedFrom)
|
|
199
|
+
return { version, current: false, why: "pointer-moved" };
|
|
200
|
+
store.handle.prepare("INSERT INTO code_map_current (repo, version) VALUES (?, ?) ON CONFLICT (repo) DO UPDATE SET version = excluded.version").run(lease.repo, version);
|
|
201
|
+
return { version, current: true, why: "published" };
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
/** Keep the current version, the 10 before it and any named by an unfinished run. */
|
|
205
|
+
export function tidyVersions(store, repo) {
|
|
206
|
+
return store.transact(() => {
|
|
207
|
+
const current = store.handle.prepare("SELECT version FROM code_map_current WHERE repo = ?").get(repo);
|
|
208
|
+
if (current === undefined)
|
|
209
|
+
return 0;
|
|
210
|
+
const ran = store.handle.prepare(`DELETE FROM code_map_version WHERE repo = ? AND id < ? AND id NOT IN (
|
|
211
|
+
SELECT id FROM code_map_version WHERE repo = ? AND id < ? ORDER BY id DESC LIMIT 10)
|
|
212
|
+
AND id NOT IN (SELECT s.version FROM code_map_snapshot s JOIN run r ON r.id = s.run WHERE s.version IS NOT NULL AND r.outcome IS NULL)`).run(repo, Number(current["version"]), repo, Number(current["version"]));
|
|
213
|
+
return Number(ran.changes);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/** A project removed from the lists: its map rows go with it, except what stays with its runs (snapshots, deliveries,
|
|
217
|
+
* family arms) and any version an unfinished run still names. */
|
|
218
|
+
export function forgetCodeMap(store, repo) {
|
|
219
|
+
store.handle.prepare("DELETE FROM code_map_current WHERE repo = ?").run(repo);
|
|
220
|
+
store.handle.prepare("DELETE FROM code_map_refresh WHERE repo = ?").run(repo);
|
|
221
|
+
store.handle.prepare(`DELETE FROM code_map_version WHERE repo = ? AND id NOT IN (SELECT s.version FROM code_map_snapshot s JOIN run r ON r.id = s.run WHERE s.version IS NOT NULL AND r.outcome IS NULL)`).run(repo);
|
|
222
|
+
}
|
|
223
|
+
/** The startup check: a store at this version holds every table and trigger, or its map can't be trusted. */
|
|
224
|
+
export function codeMapShapeProblem(db) {
|
|
225
|
+
const has = db.prepare("SELECT 1 FROM sqlite_master WHERE type = ? AND name = ?");
|
|
226
|
+
for (const table of V152_TABLES)
|
|
227
|
+
if (has.get("table", table) === undefined)
|
|
228
|
+
return `the code map table ${table} is missing`;
|
|
229
|
+
for (const trigger of V152_TRIGGERS)
|
|
230
|
+
if (has.get("trigger", trigger) === undefined)
|
|
231
|
+
return `the code map trigger ${trigger} is missing`;
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
@@ -15,6 +15,8 @@ export type CodingCustody = {
|
|
|
15
15
|
observationFailures?: ProcessObservationFailure[];
|
|
16
16
|
host: string;
|
|
17
17
|
bootId: string | null;
|
|
18
|
+
/** v150: this machine's stable id (machine-identity.ts); absent in custody saved before it. */
|
|
19
|
+
machineId?: string | null;
|
|
18
20
|
container?: {
|
|
19
21
|
backend: string;
|
|
20
22
|
id: string;
|
package/dist/coding-provider.js
CHANGED
|
@@ -6,6 +6,7 @@ import { dirname, join } from "node:path";
|
|
|
6
6
|
import { codexFenceConfig, fenceFor, FENCE_POLICY_CURRENT, runFolders, taskBoundary, trustedWorktreeBinding } from "./agent-fence.js";
|
|
7
7
|
import { poolRootOf } from "./worktree.js";
|
|
8
8
|
import { currentBootId } from "./boot-identity.js";
|
|
9
|
+
import { currentMachineId } from "./machine-identity.js";
|
|
9
10
|
import { createContainer, currentContainment } from "./containment.js";
|
|
10
11
|
import { processMayBeAlive } from "./process-liveness.js";
|
|
11
12
|
import { observeProcessTree, sampleProcessTree, stopProcessTree } from "./process-tree.js";
|
|
@@ -82,7 +83,7 @@ export function createCodexCodingProvider(options = {}) {
|
|
|
82
83
|
const descendants = new Map();
|
|
83
84
|
let ancestryUnknown = false;
|
|
84
85
|
const observationFailures = [];
|
|
85
|
-
const host = hostname();
|
|
86
|
+
const host = hostname(), machineId = currentMachineId();
|
|
86
87
|
// Bind the boot at creation, not when an old snapshot is requested later.
|
|
87
88
|
const bootId = currentBootId();
|
|
88
89
|
let nextId = 0;
|
|
@@ -94,7 +95,7 @@ export function createCodexCodingProvider(options = {}) {
|
|
|
94
95
|
return {
|
|
95
96
|
pid, group: pid !== null && process.platform !== "win32",
|
|
96
97
|
descendants: [...descendants.values()].map(one => ({ ...one })),
|
|
97
|
-
observationUnknown: ancestryUnknown, host, bootId,
|
|
98
|
+
observationUnknown: ancestryUnknown, host, bootId, machineId,
|
|
98
99
|
...(observationFailures.length === 0 ? {} : { observationFailures: observationFailures.map(one => ({ ...one })) }),
|
|
99
100
|
...(container === null ? {} : { container: { backend: container.backend, id: container.id, ...(container.identity === undefined ? {} : { identity: container.identity }) } }),
|
|
100
101
|
};
|
package/dist/coding-update.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { chmodSync, closeSync, fsyncSync, lstatSync, openSync } from 'node:fs';
|
|
3
|
-
import {
|
|
3
|
+
import { isThisMachine } from './machine-identity.js';
|
|
4
4
|
import { sqliteRuntime } from './sqlite-runtime.js';
|
|
5
5
|
import { processMayBeAlive } from './process-liveness.js';
|
|
6
6
|
const gatePrefix = 'so_coding_update_';
|
|
@@ -141,7 +141,8 @@ export function releaseStaleCodingOwner(orders, stoppedPids, alive = processMayB
|
|
|
141
141
|
c = {};
|
|
142
142
|
}
|
|
143
143
|
const processes = Array.isArray(c.descendants) ? c.descendants : null;
|
|
144
|
-
if (c.host !==
|
|
144
|
+
if (typeof c.host !== 'string' || (c.machineId !== undefined && c.machineId !== null && typeof c.machineId !== 'string')
|
|
145
|
+
|| !isThisMachine({ host: c.host, machineId: (c.machineId ?? null) }) || c.container || c.observationUnknown !== false || processes === null)
|
|
145
146
|
refuse("the agent's tool processes could not be accounted for");
|
|
146
147
|
const recorded = [...(c.pid === null ? [] : [{ pid: c.pid, group: c.group }]), ...processes];
|
|
147
148
|
for (const one of recorded) {
|
package/dist/coding-workspace.js
CHANGED
|
@@ -2,8 +2,8 @@ import { checkoutGit } from './teardown-git.js';
|
|
|
2
2
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { mkdirSync, chmodSync, realpathSync } from 'node:fs';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { currentBootId, provenDeadByBootChange } from './boot-identity.js';
|
|
6
|
+
import { isThisMachine } from './machine-identity.js';
|
|
7
7
|
import { containerEmptiness } from './container-state.js';
|
|
8
8
|
import { sqliteRuntime } from './sqlite-runtime.js';
|
|
9
9
|
import { run } from './exec.js';
|
|
@@ -536,9 +536,9 @@ export class CodingWorkspace {
|
|
|
536
536
|
return false;
|
|
537
537
|
try {
|
|
538
538
|
const c = readCodingCustodyWitness(String(row['payload']));
|
|
539
|
-
if (c === null || c.host !==
|
|
539
|
+
if (c === null || typeof c.host !== 'string' || !isThisMachine(c))
|
|
540
540
|
return false;
|
|
541
|
-
if (provenDeadByBootChange(c))
|
|
541
|
+
if (provenDeadByBootChange(c, { host: c.host, bootId: currentBootId() }))
|
|
542
542
|
return true;
|
|
543
543
|
if (c.container)
|
|
544
544
|
return containerEmptiness(c.container.backend, c.container.id, process.platform, c.container.identity) === 'empty';
|
package/dist/console-chrome.js
CHANGED
|
@@ -49,11 +49,11 @@ export function projectSummaryOf(store, now, access, actor, projects, evidenceRo
|
|
|
49
49
|
};
|
|
50
50
|
const rows = projects.map(one => {
|
|
51
51
|
const state = states.get(one.path);
|
|
52
|
-
return { path: one.path, name: one.name, href: `/
|
|
52
|
+
return { path: one.path, name: one.name, href: `/tasks?project=${encodeURIComponent(one.path)}`, state: state?.state ?? "idle", counts: state?.counts ?? { ...NO_COUNTS }, ...railOf(state) };
|
|
53
53
|
});
|
|
54
54
|
const unplaced = states.get(null);
|
|
55
55
|
if (unplaced !== undefined && unplaced.state !== "idle")
|
|
56
|
-
rows.push({ path: null, name: "No project", href: "/
|
|
56
|
+
rows.push({ path: null, name: "No project", href: "/tasks", state: unplaced.state, counts: unplaced.counts, ...railOf(unplaced) });
|
|
57
57
|
return boundProjectSummary(rows);
|
|
58
58
|
}
|
|
59
59
|
/** One access, canonically and in full (every field it has, so a field added later keys too): the same reader and
|
package/dist/containment.d.ts
CHANGED
|
@@ -161,6 +161,11 @@ export type Container = {
|
|
|
161
161
|
waitEmpty(timeoutMs: number): Promise<boolean>;
|
|
162
162
|
/** Remove the OS object (only an empty one can go) and dismiss the janitor. */
|
|
163
163
|
release(): void;
|
|
164
|
+
/** Hard limits on the whole object, set before `launch`; false when this object can't enforce them. */
|
|
165
|
+
limit?(limits: {
|
|
166
|
+
memoryBytes: number;
|
|
167
|
+
pids: number;
|
|
168
|
+
}): boolean;
|
|
164
169
|
};
|
|
165
170
|
export type ContainerFactory = (effective: EffectiveContainment, label: string) => Container;
|
|
166
171
|
/** Tests: substitute the OS object (a scripted or file-backed stand-in). */
|
package/dist/containment.js
CHANGED
|
@@ -353,6 +353,17 @@ export function cgroup2Container(capability, label, mountOverride) {
|
|
|
353
353
|
backend: "cgroup2",
|
|
354
354
|
id: dir,
|
|
355
355
|
identity,
|
|
356
|
+
limit({ memoryBytes, pids }) {
|
|
357
|
+
// The controllers exist here only if the delegated parent enabled them for its children.
|
|
358
|
+
try {
|
|
359
|
+
writeFileSync(join(dir, "memory.max"), String(memoryBytes));
|
|
360
|
+
writeFileSync(join(dir, "pids.max"), String(pids));
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
},
|
|
356
367
|
launch(file, args) {
|
|
357
368
|
return {
|
|
358
369
|
file: "/bin/sh",
|
|
@@ -445,6 +456,7 @@ export function jobObjectContainer(capability, label) {
|
|
|
445
456
|
let authorized = false;
|
|
446
457
|
let cancelled = false;
|
|
447
458
|
let helperChild = null;
|
|
459
|
+
let memoryLimit = 0;
|
|
448
460
|
const fail = (detail) => { failure ??= detail; if (state !== "empty")
|
|
449
461
|
state = "lost"; connection?.destroy(); };
|
|
450
462
|
const authorize = () => {
|
|
@@ -517,10 +529,11 @@ export function jobObjectContainer(capability, label) {
|
|
|
517
529
|
};
|
|
518
530
|
return {
|
|
519
531
|
backend: "job-object", id, identity,
|
|
532
|
+
limit({ memoryBytes }) { memoryLimit = memoryBytes; return true; },
|
|
520
533
|
launch(file, args) {
|
|
521
534
|
return {
|
|
522
535
|
file: capability.powershell,
|
|
523
|
-
args: ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", capability.helper, "-Pipe", pipe, "-Encoded", Buffer.from(JSON.stringify([file, ...args]), "utf8").toString("base64"), "-JobName", id],
|
|
536
|
+
args: ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", capability.helper, "-Pipe", pipe, "-Encoded", Buffer.from(JSON.stringify([file, ...args]), "utf8").toString("base64"), "-JobName", id, ...(memoryLimit > 0 ? ["-MemoryLimit", String(memoryLimit)] : [])],
|
|
524
537
|
extraStdio: [],
|
|
525
538
|
async attach(child) {
|
|
526
539
|
// Called only after the durable onSpawn callback succeeded.
|
|
@@ -260,6 +260,13 @@ export declare const chatActionRequestSchemas: {
|
|
|
260
260
|
repo: z.ZodString;
|
|
261
261
|
trial: z.ZodInt;
|
|
262
262
|
}, z.core.$strict>;
|
|
263
|
+
readonly code_map_switch: z.ZodObject<{
|
|
264
|
+
repo: z.ZodString;
|
|
265
|
+
on: z.ZodBoolean;
|
|
266
|
+
}, z.core.$strict>;
|
|
267
|
+
readonly code_map_holdout_end: z.ZodObject<{
|
|
268
|
+
repo: z.ZodString;
|
|
269
|
+
}, z.core.$strict>;
|
|
263
270
|
/** The line, and (from 1) the line it replaces; 0 or none adds it. */
|
|
264
271
|
readonly lead_about_you: z.ZodObject<{
|
|
265
272
|
line: z.ZodString;
|
|
@@ -295,6 +302,8 @@ export declare const SHARED_ACTION_VERSION = 1;
|
|
|
295
302
|
export declare const sharedActionSchema: z.ZodObject<{
|
|
296
303
|
version: z.ZodLiteral<1>;
|
|
297
304
|
operation: z.ZodEnum<{
|
|
305
|
+
code_map_holdout_end: "code_map_holdout_end";
|
|
306
|
+
code_map_switch: "code_map_switch";
|
|
298
307
|
decision_record: "decision_record";
|
|
299
308
|
decision_retire: "decision_retire";
|
|
300
309
|
flow_browser: "flow_browser";
|
|
@@ -85,6 +85,8 @@ export const chatActionRequestSchemas = {
|
|
|
85
85
|
suggestion_not_now: z.strictObject({ repo: words, suggestion: words }),
|
|
86
86
|
// Slice 3: stopping a trial (starting one stays in Settings → Models, behind a step-up).
|
|
87
87
|
trial_stop: z.strictObject({ repo: words, trial: id }),
|
|
88
|
+
code_map_switch: z.strictObject({ repo: words, on: z.boolean() }),
|
|
89
|
+
code_map_holdout_end: z.strictObject({ repo: words }),
|
|
88
90
|
/** The line, and (from 1) the line it replaces; 0 or none adds it. */
|
|
89
91
|
lead_about_you: z.strictObject({ line: words, replaces: z.int().min(0).optional() }),
|
|
90
92
|
scope_approve: z.strictObject({ task: words }),
|
package/dist/contracts/cli.d.ts
CHANGED
|
@@ -566,6 +566,58 @@ export declare const COMMAND_OUTPUTS: {
|
|
|
566
566
|
reason: z.ZodString;
|
|
567
567
|
message: z.ZodOptional<z.ZodString>;
|
|
568
568
|
}, z.core.$loose>], "ok">;
|
|
569
|
+
readonly "task ready": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
570
|
+
envelopeVersion: z.ZodLiteral<1>;
|
|
571
|
+
ok: z.ZodLiteral<true>;
|
|
572
|
+
command: z.ZodLiteral<"task ready">;
|
|
573
|
+
taskId: z.ZodString;
|
|
574
|
+
activeTaskId: z.ZodString;
|
|
575
|
+
run: z.ZodNullable<z.ZodNumber>;
|
|
576
|
+
head: z.ZodNullable<z.ZodString>;
|
|
577
|
+
answer: z.ZodEnum<{
|
|
578
|
+
merged: "merged";
|
|
579
|
+
no: "no";
|
|
580
|
+
"not-yet": "not-yet";
|
|
581
|
+
yes: "yes";
|
|
582
|
+
}>;
|
|
583
|
+
sentence: z.ZodString;
|
|
584
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
585
|
+
key: z.ZodEnum<{
|
|
586
|
+
build: "build";
|
|
587
|
+
checks: "checks";
|
|
588
|
+
comments: "comments";
|
|
589
|
+
conflicts: "conflicts";
|
|
590
|
+
plan: "plan";
|
|
591
|
+
"pr-ci": "pr-ci";
|
|
592
|
+
"pull-request": "pull-request";
|
|
593
|
+
release: "release";
|
|
594
|
+
requirements: "requirements";
|
|
595
|
+
"up-to-date": "up-to-date";
|
|
596
|
+
}>;
|
|
597
|
+
label: z.ZodString;
|
|
598
|
+
mark: z.ZodEnum<{
|
|
599
|
+
no: "no";
|
|
600
|
+
skip: "skip";
|
|
601
|
+
unknown: "unknown";
|
|
602
|
+
waiting: "waiting";
|
|
603
|
+
yes: "yes";
|
|
604
|
+
}>;
|
|
605
|
+
say: z.ZodString;
|
|
606
|
+
act: z.ZodNullable<z.ZodObject<{
|
|
607
|
+
kind: z.ZodEnum<{
|
|
608
|
+
fix: "fix";
|
|
609
|
+
retry: "retry";
|
|
610
|
+
"run-checks": "run-checks";
|
|
611
|
+
}>;
|
|
612
|
+
}, z.core.$loose>>;
|
|
613
|
+
}, z.core.$loose>>;
|
|
614
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
615
|
+
envelopeVersion: z.ZodLiteral<1>;
|
|
616
|
+
ok: z.ZodLiteral<false>;
|
|
617
|
+
command: z.ZodLiteral<"task ready">;
|
|
618
|
+
reason: z.ZodString;
|
|
619
|
+
message: z.ZodOptional<z.ZodString>;
|
|
620
|
+
}, z.core.$loose>], "ok">;
|
|
569
621
|
readonly "task hold": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
570
622
|
envelopeVersion: z.ZodLiteral<1>;
|
|
571
623
|
ok: z.ZodLiteral<true>;
|
package/dist/contracts/cli.js
CHANGED
|
@@ -183,6 +183,10 @@ export const COMMAND_OUTPUTS = {
|
|
|
183
183
|
// `status` is the observation's own answer (the one merges read); the rows are each check's timing.
|
|
184
184
|
"task ship": answers("task ship", { task: str, pullRequest: int, githubRepo: str, head: str, observedAt: str, status: z.enum(["passing", "failing", "running", "none"]),
|
|
185
185
|
checks: rows({ name: str, workflow: nullable(str), state: z.enum(["queued", "running", "passed", "failed", "skipped", "cancelled", "neutral"]), startedAt: nullable(str), completedAt: nullable(str), url: nullable(str), kind: z.enum(["run", "status"]), seconds: nullable(int) }) }),
|
|
186
|
+
// "Can I merge?" (merge-checklist.ts): the answer, its sentence, and one row per fact, each blocker with its act.
|
|
187
|
+
"task ready": answers("task ready", { taskId: str, activeTaskId: str, run: nullable(int), head: nullable(str), answer: z.enum(["yes", "no", "not-yet", "merged"]), sentence: str,
|
|
188
|
+
rows: rows({ key: z.enum(["plan", "build", "checks", "requirements", "pull-request", "pr-ci", "up-to-date", "conflicts", "comments", "release"]), label: str,
|
|
189
|
+
mark: z.enum(["yes", "no", "waiting", "unknown", "skip"]), say: str, act: nullable(z.looseObject({ kind: z.enum(["run-checks", "retry", "fix"]) })) }) }),
|
|
186
190
|
"task hold": answers("task hold", { id: str, reason: str, until: nullable(str) }),
|
|
187
191
|
"task unhold": answers("task unhold", { id: str }),
|
|
188
192
|
"task wait": answers("task wait", { task: str, outcome: str }),
|
|
@@ -98,7 +98,7 @@ export declare const CONSOLE_FORMS: {
|
|
|
98
98
|
readonly signIn: FormContract<"action" | "client-id" | "client-secret" | "groups-claim" | "issuer" | "label" | "password" | "passwords" | "scopes" | `group-${string}` | `projects-${string}` | `role-${string}`>;
|
|
99
99
|
readonly updates: FormContract<"password" | "version" | "when">;
|
|
100
100
|
readonly retention: FormContract<"chat" | "checkouts" | "evidence" | "notifications" | "password">;
|
|
101
|
-
readonly storage: FormContract<"cleanup" | "password" | "path" | "preview">;
|
|
101
|
+
readonly storage: FormContract<"cleanup" | "idle" | "password" | "path" | "preview">;
|
|
102
102
|
readonly pullRequests: FormContract<"act" | "base" | "github" | "method" | "password" | "repo" | "when-green">;
|
|
103
103
|
readonly checks: FormContract<"act" | "command" | "level" | "on" | "password" | "repo" | "timeout">;
|
|
104
104
|
readonly backups: FormContract<"every" | "folder" | "keep" | "live_every" | "live_folder" | "password">;
|
|
@@ -115,6 +115,8 @@ export declare const CONSOLE_FORMS: {
|
|
|
115
115
|
readonly modelsRules: FormContract<"id" | "password" | "rule" | "scope">;
|
|
116
116
|
readonly knowledgeRefresh: FormContract<"repo">;
|
|
117
117
|
readonly knowledgeProposal: FormContract<"decision" | "proposal" | "repo">;
|
|
118
|
+
readonly knowledgeNote: FormContract<"claim" | "decision" | "proposal" | "repo">;
|
|
119
|
+
readonly knowledgeTidy: FormContract<"action" | "choice" | "claim" | "proposal" | "repo" | "revision" | "target" | "why">;
|
|
118
120
|
readonly knowledgeDecision: FormContract<"action" | "claim" | "decision" | "reason" | "repo" | "why">;
|
|
119
121
|
readonly knowledgeChange: FormContract<"action" | "content" | "id" | "identity" | "instructions" | "path" | "repo" | "restore" | "revision" | "title">;
|
|
120
122
|
readonly learningChange: FormContract<"action" | "identity" | "lesson" | "repo" | "revision" | "sha" | "version">;
|
|
@@ -140,7 +142,12 @@ export declare const CONSOLE_FORMS: {
|
|
|
140
142
|
readonly projectsSelect: FormContract<"path" | "return">;
|
|
141
143
|
readonly projectsRemove: FormContract<"repo">;
|
|
142
144
|
readonly projectsOpen: FormContract<"path" | "return">;
|
|
143
|
-
readonly
|
|
145
|
+
readonly codeMap: FormContract<"on" | "repo">;
|
|
146
|
+
readonly codeMapRefresh: FormContract<never>;
|
|
147
|
+
readonly tasksFast: FormContract<"digest" | "preview">;
|
|
148
|
+
readonly keepGrown: FormContract<never>;
|
|
149
|
+
readonly releaseGoOn: FormContract<"password">;
|
|
150
|
+
readonly tasksAdd: FormContract<"acceptance" | "after" | "from" | "from-head" | "from-read" | "goal" | "id" | "not" | "permission-mode" | "plain" | "plan-first" | "planning-policy" | "projectRevision" | "quality-mode" | "repo" | "scout" | "title" | "touches">;
|
|
144
151
|
readonly queue: FormContract<"before" | "column" | "from" | "note" | "projectRevision" | "queueRevision" | "respond" | "runner" | "task">;
|
|
145
152
|
readonly runnerRegister: FormContract<"capacity" | "name" | "token">;
|
|
146
153
|
readonly mode: FormContract<"auto-approve" | "chat-approve" | "days" | "digest" | "expiry" | "name" | "nonce" | "plan-auto" | "publication" | "repair-auto" | "review-auto" | "review-retry-auto" | "token">;
|
|
@@ -150,7 +157,7 @@ export declare const CONSOLE_FORMS: {
|
|
|
150
157
|
readonly peopleRevoke: FormContract<"name" | "token">;
|
|
151
158
|
readonly runnerRetire: FormContract<"name" | "token">;
|
|
152
159
|
readonly decisionAnswer: FormContract<"choice" | "confirm" | "note" | "return">;
|
|
153
|
-
readonly
|
|
160
|
+
readonly recheckStopped: FormContract<"return" | "run">;
|
|
154
161
|
readonly merge: FormContract<"anyway" | "run" | "token">;
|
|
155
162
|
readonly onboard: FormContract<"big-ok" | "nonce" | "repo" | "root" | "token">;
|
|
156
163
|
readonly pushSubscribe: FormContract<"auth" | "endpoint" | "p256dh" | "token">;
|
|
@@ -198,8 +205,8 @@ export declare const CONSOLE_FORMS: {
|
|
|
198
205
|
readonly taskRevision: FormContract<"revision-id" | "token">;
|
|
199
206
|
readonly taskCancel: FormContract<"reason">;
|
|
200
207
|
readonly taskRoute: FormContract<"agent" | "clear-phase" | "model" | "phase" | "provider" | "return" | "risky" | "sawDigest" | "size">;
|
|
201
|
-
readonly taskScope: FormContract<"acceptance" | "budget-microusd" | "budget-usd" | "goal" | "goal-brief" | "not" | "permission-mode" | "quality-mode" | "requirement" | "requirement-new" | "sawDigest" | "touches">;
|
|
202
|
-
readonly taskApprove: FormContract<"digest" | "nonce" | "rebuild" | "return" | "token">;
|
|
208
|
+
readonly taskScope: FormContract<"acceptance" | "budget-microusd" | "budget-usd" | "goal" | "goal-brief" | "not" | "permission-mode" | "quality-mode" | "requirement" | "requirement-how" | "requirement-new" | "requirement-new-how" | "sawDigest" | "touches">;
|
|
209
|
+
readonly taskApprove: FormContract<"digest" | "nonce" | "rebuild" | "return" | "sheet" | "token">;
|
|
203
210
|
readonly taskAcceptProof: FormContract<"note" | "return" | "run">;
|
|
204
211
|
readonly taskComplete: FormContract<"accept" | "note" | "publish" | "receipt" | "return" | "run">;
|
|
205
212
|
readonly taskStop: FormContract<"return" | "run">;
|
|
@@ -107,7 +107,7 @@ export const CONSOLE_FORMS = {
|
|
|
107
107
|
signIn: formContract("POST /settings/sign-in", ["action", "password", "issuer", "client-id", "client-secret", "label", "scopes", "groups-claim", "passwords"], { prefixes: ["group-", "role-", "projects-"] }),
|
|
108
108
|
updates: formContract("POST /settings/updates, /settings/updates/seen, /settings/updates/cancel", ["password", "version", "when"]),
|
|
109
109
|
retention: formContract("POST /settings/retention", ["password", "evidence", "checkouts", "chat", "notifications"]),
|
|
110
|
-
storage: formContract("POST /settings/storage, /settings/storage/clean, /settings/storage/discard", ["password", "cleanup", "preview", "path"]),
|
|
110
|
+
storage: formContract("POST /settings/storage, /settings/storage/clean, /settings/storage/discard", ["password", "cleanup", "idle", "preview", "path"]),
|
|
111
111
|
pullRequests: formContract("POST /settings/pull-requests", ["repo", "act", "password", "github", "base", "method", "when-green"]),
|
|
112
112
|
checks: formContract("POST /settings/checks", ["repo", "password", "act", "on", "level", "command", "timeout"]),
|
|
113
113
|
backups: formContract("POST /settings/backups", ["password", "every", "keep", "folder", "live_every", "live_folder"]),
|
|
@@ -129,6 +129,8 @@ export const CONSOLE_FORMS = {
|
|
|
129
129
|
modelsRules: formContract("POST /settings/models/accept, /settings/models/keep, /settings/models/suggest-on, /settings/models/turn-off, /settings/models/not-now, /settings/models/suggest-off, /settings/models/try, /settings/models/stop", ["password", "scope", "id", "rule"]),
|
|
130
130
|
knowledgeRefresh: formContract("POST /settings/knowledge/refresh", ["repo"]),
|
|
131
131
|
knowledgeProposal: formContract("POST /settings/knowledge/proposal", ["repo", "decision", "proposal"]),
|
|
132
|
+
knowledgeNote: formContract("POST /settings/knowledge/note", ["repo", "decision", "proposal", "claim"]),
|
|
133
|
+
knowledgeTidy: formContract("POST /settings/knowledge/tidy", ["repo", "action", "proposal", "choice", "claim", "why", "target", "revision"]),
|
|
132
134
|
knowledgeDecision: formContract("POST /settings/knowledge/decision", ["repo", "action", "claim", "why", "decision", "reason"]),
|
|
133
135
|
knowledgeChange: formContract("POST /settings/knowledge/change", ["repo", "action", "identity", "revision", "instructions", "title", "content", "path", "id", "restore"]),
|
|
134
136
|
learningChange: formContract("POST /settings/learning/change", ["repo", "action", "identity", "revision", "lesson", "version", "sha"]),
|
|
@@ -155,7 +157,12 @@ export const CONSOLE_FORMS = {
|
|
|
155
157
|
projectsSelect: formContract("POST /projects/select", ["path", "return"]),
|
|
156
158
|
projectsRemove: formContract("POST /projects/remove", ["repo"]),
|
|
157
159
|
projectsOpen: formContract("POST /projects/open", ["path", "return"]),
|
|
158
|
-
|
|
160
|
+
codeMap: formContract("POST /settings/project/code-map, /settings/project/code-map/holdout", ["repo", "on"]),
|
|
161
|
+
codeMapRefresh: formContract("POST /projects/<project>/map/refresh", []),
|
|
162
|
+
tasksFast: formContract("POST /tasks/fast", ["preview", "digest"]),
|
|
163
|
+
keepGrown: formContract("POST /t/<id>/keep-grown", []),
|
|
164
|
+
releaseGoOn: formContract("POST /t/<id>/release/go-on", ["password"]),
|
|
165
|
+
tasksAdd: formContract("POST /tasks/add", ["projectRevision", "plain", "from", "from-head", "from-read", "id", "title", "repo", "goal", "not", "touches", "scout", "permission-mode", "quality-mode", "after", "acceptance", "planning-policy", "plan-first"]),
|
|
159
166
|
queue: formContract("POST /queue/move, /queue/note", ["runner", "note", "from", "projectRevision", "respond", "task", "column", "before", "queueRevision"]),
|
|
160
167
|
runnerRegister: formContract("POST /fleet/runner/register", ["token", "name", "capacity"]),
|
|
161
168
|
mode: formContract("POST /mode/confirm, /mode/sign", ["name", "days", "auto-approve", "plan-auto", "chat-approve", "publication", "expiry", "nonce", "digest", "token", "review-auto", "review-retry-auto", "repair-auto"]),
|
|
@@ -165,7 +172,7 @@ export const CONSOLE_FORMS = {
|
|
|
165
172
|
peopleRevoke: formContract("POST /people/revoke", ["token", "name"]),
|
|
166
173
|
runnerRetire: formContract("POST /fleet/runner/retire", ["token", "name"]),
|
|
167
174
|
decisionAnswer: formContract("POST /d/<id>/answer", ["return", "choice", "confirm", "note"]),
|
|
168
|
-
|
|
175
|
+
recheckStopped: formContract("POST /t/<task>/recheck-stopped", ["run", "return"]),
|
|
169
176
|
merge: formContract("POST /t/<task>/merge", ["run", "token", "anyway"]),
|
|
170
177
|
onboard: formContract("POST /projects/onboard-preview, /projects/onboard-confirm", ["repo", "root", "token", "nonce", "big-ok"]),
|
|
171
178
|
pushSubscribe: formContract("POST /push/subscribe", ["token", "endpoint", "p256dh", "auth"]),
|
|
@@ -216,8 +223,8 @@ export const CONSOLE_FORMS = {
|
|
|
216
223
|
taskRevision: formContract("POST /t/<task>/accept-revision|reject-revision", ["revision-id", "token"]),
|
|
217
224
|
taskCancel: formContract("POST /t/<task>/cancel", ["reason"]),
|
|
218
225
|
taskRoute: formContract("POST /t/<task>/route", ["size", "risky", "phase", "clear-phase", "agent", "provider", "model", "sawDigest", "return"]),
|
|
219
|
-
taskScope: formContract("POST /t/<task>/scope", ["sawDigest", "permission-mode", "quality-mode", "budget-usd", "budget-microusd", "requirement", "requirement-new", "goal-brief", "goal", "not", "touches", "acceptance"]),
|
|
220
|
-
taskApprove: formContract("POST /t/<task>/approve", ["return", "digest", "token", "nonce", "rebuild"]),
|
|
226
|
+
taskScope: formContract("POST /t/<task>/scope", ["sawDigest", "permission-mode", "quality-mode", "budget-usd", "budget-microusd", "requirement", "requirement-new", "requirement-how", "requirement-new-how", "goal-brief", "goal", "not", "touches", "acceptance"]),
|
|
227
|
+
taskApprove: formContract("POST /t/<task>/approve", ["return", "digest", "token", "nonce", "rebuild", "sheet"]),
|
|
221
228
|
taskAcceptProof: formContract("POST /t/<task>/accept-proof", ["run", "note", "return"]),
|
|
222
229
|
taskComplete: formContract("POST /t/<task>/complete", ["receipt", "run", "accept", "note", "publish", "return"]),
|
|
223
230
|
taskStop: formContract("POST /t/<task>/stop", ["run", "return"]),
|