@anhlp/alp-runtime 0.0.0-beta.1
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 +202 -0
- package/NOTICE +7 -0
- package/README.md +7 -0
- package/dist/acp-transport.d.ts +114 -0
- package/dist/acp-transport.js +478 -0
- package/dist/antigravity-transport.d.ts +80 -0
- package/dist/antigravity-transport.js +609 -0
- package/dist/board-domain.d.ts +56 -0
- package/dist/board-domain.js +157 -0
- package/dist/board.d.ts +21 -0
- package/dist/board.js +69 -0
- package/dist/catalog.d.ts +31 -0
- package/dist/catalog.js +38 -0
- package/dist/claude-transport.d.ts +157 -0
- package/dist/claude-transport.js +671 -0
- package/dist/contracts.d.ts +163 -0
- package/dist/contracts.js +5 -0
- package/dist/events.d.ts +1 -0
- package/dist/events.js +0 -0
- package/dist/github.d.ts +10 -0
- package/dist/github.js +39 -0
- package/dist/handoff.d.ts +36 -0
- package/dist/handoff.js +73 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +64 -0
- package/dist/language.d.ts +41 -0
- package/dist/language.js +68 -0
- package/dist/live.d.ts +48 -0
- package/dist/live.js +45 -0
- package/dist/mailbox.d.ts +24 -0
- package/dist/mailbox.js +36 -0
- package/dist/mcp-tools.d.ts +115 -0
- package/dist/mcp-tools.js +71 -0
- package/dist/permission-path.d.ts +2 -0
- package/dist/permission-path.js +44 -0
- package/dist/process-info.d.ts +14 -0
- package/dist/process-info.js +32 -0
- package/dist/providers.d.ts +28 -0
- package/dist/providers.js +71 -0
- package/dist/recall.d.ts +42 -0
- package/dist/recall.js +60 -0
- package/dist/resolve.d.ts +121 -0
- package/dist/resolve.js +238 -0
- package/dist/runtime-context.d.ts +43 -0
- package/dist/runtime-context.js +61 -0
- package/dist/runtime.d.ts +4 -0
- package/dist/runtime.js +2979 -0
- package/dist/session-config.d.ts +1973 -0
- package/dist/session-config.js +205 -0
- package/dist/session-state.d.ts +140 -0
- package/dist/session-state.js +0 -0
- package/dist/tool-results.d.ts +12 -0
- package/dist/tool-results.js +25 -0
- package/dist/tools.d.ts +674 -0
- package/dist/tools.js +375 -0
- package/dist/transport.d.ts +47 -0
- package/dist/transport.js +169 -0
- package/dist/usage.d.ts +15 -0
- package/dist/usage.js +35 -0
- package/dist/workspace.d.ts +101 -0
- package/dist/workspace.js +259 -0
- package/dist/worktree-domain.d.ts +88 -0
- package/dist/worktree-domain.js +196 -0
- package/package.json +256 -0
- package/src/acp-transport.ts +473 -0
- package/src/antigravity-transport.ts +658 -0
- package/src/board-domain.ts +185 -0
- package/src/board.ts +80 -0
- package/src/catalog.ts +32 -0
- package/src/claude-transport.ts +771 -0
- package/src/contracts.ts +166 -0
- package/src/events.ts +1 -0
- package/src/github.ts +37 -0
- package/src/handoff.ts +86 -0
- package/src/index.ts +26 -0
- package/src/language.ts +102 -0
- package/src/live.ts +86 -0
- package/src/mailbox.ts +46 -0
- package/src/mcp-tools.ts +73 -0
- package/src/permission-path.ts +37 -0
- package/src/process-info.ts +40 -0
- package/src/providers.ts +84 -0
- package/src/recall.ts +85 -0
- package/src/resolve.ts +230 -0
- package/src/runtime-context.ts +49 -0
- package/src/runtime.ts +3579 -0
- package/src/session-config.ts +301 -0
- package/src/session-state.ts +141 -0
- package/src/tool-results.ts +26 -0
- package/src/tools.ts +379 -0
- package/src/transport.ts +116 -0
- package/src/usage.ts +42 -0
- package/src/workspace.ts +318 -0
- package/src/worktree-domain.ts +216 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// packages/runtime/src/board-domain.ts
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { moveFile } from "@anhlp/alp-core/atomic";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { BOARD_KEEP, live, normalizePaths, overlapping, PIN_BODY_CHARS, PIN_KINDS, renderPin } from "./board.js";
|
|
7
|
+
import { plainObject, toolResult } from "./tool-results.js";
|
|
8
|
+
function createBoardDomain({ options, sessions, boards, loadedBoards, rootOf, lineage, runLog, emit, post, steerMail }) {
|
|
9
|
+
const boardFile = (project) => path.join(options.boardDir, `${createHash("sha256").update(project).digest("hex").slice(0, 16)}.jsonl`);
|
|
10
|
+
let boardWrites = Promise.resolve();
|
|
11
|
+
function prune(pins) {
|
|
12
|
+
const notes = pins.filter((pin) => pin.kind !== "claim" && live(pin));
|
|
13
|
+
return [...pins.filter((pin) => pin.kind === "claim" && live(pin)), ...notes.slice(-BOARD_KEEP)];
|
|
14
|
+
}
|
|
15
|
+
function boardOf(project) {
|
|
16
|
+
let board = boards.get(project);
|
|
17
|
+
if (!board) {
|
|
18
|
+
board = (async () => {
|
|
19
|
+
if (!options.boardDir) return [];
|
|
20
|
+
const text = await readFile(boardFile(project), "utf8").catch(() => "");
|
|
21
|
+
const pins = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const line of text.split("\n").filter(Boolean)) {
|
|
23
|
+
try {
|
|
24
|
+
const entry = JSON.parse(line);
|
|
25
|
+
if (entry.pin?.id) pins.set(entry.pin.id, entry.pin);
|
|
26
|
+
else if (entry.release && pins.has(entry.release)) pins.get(entry.release).released = entry.at;
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
31
|
+
for (const pin of pins.values()) if (pin.kind === "claim" && !pin.released) pin.released = now;
|
|
32
|
+
const kept = prune([...pins.values()]);
|
|
33
|
+
boardWrites = boardWrites.then(async () => {
|
|
34
|
+
await mkdir(options.boardDir, { recursive: true });
|
|
35
|
+
const temporary = `${boardFile(project)}.${randomUUID().slice(0, 8)}.tmp`;
|
|
36
|
+
await writeFile(temporary, kept.map((pin) => JSON.stringify({ pin })).join("\n") + (kept.length ? "\n" : ""));
|
|
37
|
+
await moveFile(temporary, boardFile(project));
|
|
38
|
+
}).catch(() => {
|
|
39
|
+
});
|
|
40
|
+
loadedBoards.set(project, kept);
|
|
41
|
+
return kept;
|
|
42
|
+
})();
|
|
43
|
+
boards.set(project, board);
|
|
44
|
+
}
|
|
45
|
+
return board;
|
|
46
|
+
}
|
|
47
|
+
function saveBoard(project, entry) {
|
|
48
|
+
if (!options.boardDir) return;
|
|
49
|
+
const line = `${JSON.stringify(entry)}
|
|
50
|
+
`;
|
|
51
|
+
boardWrites = boardWrites.then(() => mkdir(options.boardDir, { recursive: true })).then(() => appendFile(boardFile(project), line)).catch(() => {
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const related = (a, b) => lineage(a).includes(b) || lineage(b).includes(a);
|
|
55
|
+
function claimConflicts(sessionId, pins, paths) {
|
|
56
|
+
return pins.filter((pin) => pin.kind === "claim" && live(pin) && pin.sessionId !== sessionId && !related(sessionId, pin.sessionId) && overlapping(paths, pin.paths ?? []).length).map((pin) => ({ pinId: pin.id, agent: pin.agent, sessionId: pin.sessionId, paths: overlapping(pin.paths ?? [], paths), body: pin.body, at: pin.at, ...pin.task ? { task: pin.task } : {} }));
|
|
57
|
+
}
|
|
58
|
+
function taskOf(sessionId) {
|
|
59
|
+
for (const id of lineage(sessionId)) {
|
|
60
|
+
const parent = sessions.get(id)?.parent;
|
|
61
|
+
const taskId = parent ? sessions.get(parent)?.assignments.get(id)?.taskId : void 0;
|
|
62
|
+
if (taskId) return taskId;
|
|
63
|
+
}
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
function addPin(sessionId, session, pins, fields) {
|
|
67
|
+
const project = session.mapping.agent.projectRoot;
|
|
68
|
+
const pin = {
|
|
69
|
+
id: `p-${randomUUID().slice(0, 8)}`,
|
|
70
|
+
project,
|
|
71
|
+
kind: fields.kind,
|
|
72
|
+
body: fields.body,
|
|
73
|
+
...fields.paths ? { paths: fields.paths } : {},
|
|
74
|
+
...fields.task ? { task: fields.task } : {},
|
|
75
|
+
agent: session.mapping.agent.name,
|
|
76
|
+
sessionId,
|
|
77
|
+
rootId: rootOf(sessionId),
|
|
78
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
79
|
+
};
|
|
80
|
+
const kept = prune([...pins, pin]);
|
|
81
|
+
pins.splice(0, pins.length, ...kept);
|
|
82
|
+
saveBoard(project, { pin });
|
|
83
|
+
runLog(pin.rootId, { event: "board.pin", pinId: pin.id, kind: pin.kind, agent: pin.agent, body: pin.body, ...pin.paths ? { paths: pin.paths } : {}, ...pin.task ? { task: pin.task } : {} });
|
|
84
|
+
emit(sessionId, { type: "pin", pin });
|
|
85
|
+
for (const [id, other] of sessions) {
|
|
86
|
+
if (id === sessionId || other.closed || !other.active || other.mapping.agent.projectRoot !== project) continue;
|
|
87
|
+
post(id, { kind: "board", from: pin.agent, assignment: pin.id, body: renderPin(pin), passive: true });
|
|
88
|
+
if (!other.pending) void steerMail(id, other);
|
|
89
|
+
}
|
|
90
|
+
return pin;
|
|
91
|
+
}
|
|
92
|
+
async function pinTool(sessionId, session, args) {
|
|
93
|
+
if (!plainObject(args, ["kind", "body", "paths"]) || !PIN_KINDS.includes(args.kind) || typeof args.body !== "string" || !args.body.trim() || args.body.length > PIN_BODY_CHARS) {
|
|
94
|
+
return toolResult(false, { error: `A pin needs kind (${PIN_KINDS.join(", ")}) and a body of at most ${PIN_BODY_CHARS} characters` });
|
|
95
|
+
}
|
|
96
|
+
if (args.kind === "claim" && session.mapping.mode === "read-only") return toolResult(false, { error: "A read-only session changes no files and cannot claim paths; pin a decision or finding instead" });
|
|
97
|
+
const project = session.mapping.agent.projectRoot;
|
|
98
|
+
let paths;
|
|
99
|
+
if (args.paths !== void 0 || args.kind === "claim") {
|
|
100
|
+
const normalized = normalizePaths(args.paths, project, session.spec.writeRoot ? [session.spec.writeRoot] : void 0);
|
|
101
|
+
if (typeof normalized === "string") return toolResult(false, { error: normalized });
|
|
102
|
+
paths = normalized;
|
|
103
|
+
}
|
|
104
|
+
const pins = await boardOf(project);
|
|
105
|
+
if (session.closed) return toolResult(false, { error: "Session closed" });
|
|
106
|
+
if (args.kind === "claim") {
|
|
107
|
+
const conflicts = claimConflicts(sessionId, pins, paths);
|
|
108
|
+
if (conflicts.length) {
|
|
109
|
+
return toolResult(false, {
|
|
110
|
+
error: "Another agent has claimed overlapping paths; do not edit them. Ask your requester, or claim other paths.",
|
|
111
|
+
conflicts
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const task = args.kind === "claim" ? taskOf(sessionId) : void 0;
|
|
116
|
+
const pin = addPin(sessionId, session, pins, { kind: args.kind, body: args.body, ...paths ? { paths } : {}, ...task ? { task } : {} });
|
|
117
|
+
return toolResult(true, { pinned: pin.id, kind: pin.kind, ...paths ? { paths } : {}, ...task ? { task } : {} });
|
|
118
|
+
}
|
|
119
|
+
async function boardTool(session, args) {
|
|
120
|
+
if (!plainObject(args, ["kinds", "limit"]) || args.kinds !== void 0 && (!Array.isArray(args.kinds) || !args.kinds.every((kind) => PIN_KINDS.includes(kind))) || args.limit !== void 0 && (!Number.isSafeInteger(args.limit) || args.limit < 1)) {
|
|
121
|
+
return toolResult(false, { error: "kinds lists claim, decision or finding; limit is a positive integer" });
|
|
122
|
+
}
|
|
123
|
+
const kinds = args.kinds ?? [...PIN_KINDS];
|
|
124
|
+
const pins = (await boardOf(session.mapping.agent.projectRoot)).filter((pin) => live(pin) && kinds.includes(pin.kind));
|
|
125
|
+
const claims = pins.filter((pin) => pin.kind === "claim");
|
|
126
|
+
const notes = pins.filter((pin) => pin.kind !== "claim").slice(-(args.limit ?? 30));
|
|
127
|
+
const view = ({ project: _project, rootId: _root, released: _released, ...pin }) => pin;
|
|
128
|
+
return toolResult(true, { claims: claims.map(view), notes: notes.map(view) });
|
|
129
|
+
}
|
|
130
|
+
async function unpinTool(sessionId, session, args) {
|
|
131
|
+
if (!plainObject(args, ["pinId"]) || typeof args.pinId !== "string") return toolResult(false, { error: "pinId is required" });
|
|
132
|
+
const pins = await boardOf(session.mapping.agent.projectRoot);
|
|
133
|
+
const pin = pins.find((candidate) => candidate.id === args.pinId && live(candidate));
|
|
134
|
+
if (!pin) return toolResult(false, { error: "No such pin on this board" });
|
|
135
|
+
if (pin.sessionId !== sessionId) return toolResult(false, { error: `Only ${pin.agent}, who pinned it, can take it down` });
|
|
136
|
+
release(pin, "unpinned");
|
|
137
|
+
return toolResult(true, { unpinned: pin.id });
|
|
138
|
+
}
|
|
139
|
+
function release(pin, reason) {
|
|
140
|
+
pin.released = (/* @__PURE__ */ new Date()).toISOString();
|
|
141
|
+
saveBoard(pin.project, { release: pin.id, at: pin.released });
|
|
142
|
+
runLog(pin.rootId, { event: "board.unpin", pinId: pin.id, agent: pin.agent, reason });
|
|
143
|
+
if (sessions.has(pin.sessionId)) emit(pin.sessionId, { type: "unpin", pinId: pin.id, reason });
|
|
144
|
+
void boardOf(pin.project).then((pins) => pins.splice(0, pins.length, ...prune(pins)));
|
|
145
|
+
}
|
|
146
|
+
function releaseClaims(sessionId, project) {
|
|
147
|
+
const board = boards.get(project);
|
|
148
|
+
if (!board) return;
|
|
149
|
+
void board.then((pins) => {
|
|
150
|
+
for (const pin of [...pins]) if (pin.kind === "claim" && live(pin) && pin.sessionId === sessionId) release(pin, "session_ended");
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return { boardOf, claimConflicts, taskOf, addPin, pinTool, boardTool, unpinTool, releaseClaims, flush: () => boardWrites };
|
|
154
|
+
}
|
|
155
|
+
export {
|
|
156
|
+
createBoardDomain
|
|
157
|
+
};
|
package/dist/board.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project board (plans/reference/ALPD.md §18): one group channel per project that every
|
|
3
|
+
* agent working on it shares, across trees. Agents pin claims (paths they are changing),
|
|
4
|
+
* decisions (the approach everyone follows) and findings (what others need to know), so
|
|
5
|
+
* agents working independently neither edit each other's files nor pursue different ideas.
|
|
6
|
+
* These helpers stay pure; storage and delivery live in the runtime.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PIN_KINDS: readonly ["claim", "decision", "finding"];
|
|
9
|
+
import type { Pin } from '@anhlp/alp-protocol/dto';
|
|
10
|
+
export type { PinKind, Pin } from '@anhlp/alp-protocol/dto';
|
|
11
|
+
export declare const PIN_BODY_CHARS = 2000;
|
|
12
|
+
export declare const PIN_PATHS = 50;
|
|
13
|
+
/** Decisions and findings kept per project; live claims are always kept. */
|
|
14
|
+
export declare const BOARD_KEEP = 200;
|
|
15
|
+
/** Normalized project-relative paths, or absolute paths in a declared external write root. */
|
|
16
|
+
export declare function normalizePaths(paths: unknown, project: string, roots?: string[]): string[] | string;
|
|
17
|
+
export declare function overlapping(a: string[], b: string[]): string[];
|
|
18
|
+
export declare const live: (pin: Pin) => boolean;
|
|
19
|
+
export declare function renderPin(pin: Pin): string;
|
|
20
|
+
/** What an agent should know before it starts: live claims, then recent decisions and findings. */
|
|
21
|
+
export declare function renderBoard(pins: Pin[], limit?: number): string;
|
package/dist/board.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// packages/runtime/src/board.ts
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { realpathSync } from "node:fs";
|
|
4
|
+
var PIN_KINDS = ["claim", "decision", "finding"];
|
|
5
|
+
var PIN_BODY_CHARS = 2e3;
|
|
6
|
+
var PIN_PATHS = 50;
|
|
7
|
+
var BOARD_KEEP = 200;
|
|
8
|
+
var DIGEST_CHARS = 3e3;
|
|
9
|
+
function canonicalPath(file) {
|
|
10
|
+
try {
|
|
11
|
+
return realpathSync(file);
|
|
12
|
+
} catch {
|
|
13
|
+
const parent = path.dirname(file);
|
|
14
|
+
return parent === file ? file : path.join(canonicalPath(parent), path.basename(file));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
var containsPath = (outer, inner) => {
|
|
18
|
+
const relative = path.relative(outer, inner);
|
|
19
|
+
return !relative || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
20
|
+
};
|
|
21
|
+
function normalizePaths(paths, project, roots = [project]) {
|
|
22
|
+
if (!Array.isArray(paths) || !paths.length || paths.length > PIN_PATHS) return `paths must list 1 to ${PIN_PATHS} files or directories`;
|
|
23
|
+
const normalized = [];
|
|
24
|
+
for (const entry of paths) {
|
|
25
|
+
if (typeof entry !== "string" || !entry.trim()) return "paths must be nonempty strings";
|
|
26
|
+
const absolute = canonicalPath(path.resolve(project, entry.trim()));
|
|
27
|
+
if (!roots.some((root) => containsPath(canonicalPath(root), absolute))) return `${entry} is outside the project or declared write root`;
|
|
28
|
+
const relative = path.relative(canonicalPath(project), absolute).split(path.sep).join("/");
|
|
29
|
+
normalized.push(relative === "" ? "." : relative === ".." || relative.startsWith("../") || path.isAbsolute(relative) ? absolute.split(path.sep).join("/") : relative);
|
|
30
|
+
}
|
|
31
|
+
return [...new Set(normalized)];
|
|
32
|
+
}
|
|
33
|
+
var contains = (outer, inner) => path.isAbsolute(outer) === path.isAbsolute(inner) && (outer === "." || inner === outer || inner.startsWith(outer.endsWith("/") ? outer : `${outer}/`));
|
|
34
|
+
function overlapping(a, b) {
|
|
35
|
+
return a.filter((left) => b.some((right) => contains(left, right) || contains(right, left)));
|
|
36
|
+
}
|
|
37
|
+
var live = (pin) => !pin.released;
|
|
38
|
+
function renderPin(pin) {
|
|
39
|
+
const where = pin.paths?.length ? ` [${pin.paths.join(", ")}]` : "";
|
|
40
|
+
return `${pin.kind} ${pin.id} by ${pin.agent}${pin.task ? ` for task ${pin.task}` : ""}${where}: ${pin.body}`;
|
|
41
|
+
}
|
|
42
|
+
function renderBoard(pins, limit = DIGEST_CHARS) {
|
|
43
|
+
const claims = pins.filter((pin) => pin.kind === "claim" && live(pin));
|
|
44
|
+
const notes = pins.filter((pin) => pin.kind !== "claim" && live(pin)).reverse();
|
|
45
|
+
if (!claims.length && !notes.length) return "";
|
|
46
|
+
const lines = ["Project board (shared by every agent on this project; read more with alp_board):"];
|
|
47
|
+
let size = lines[0].length;
|
|
48
|
+
for (const pin of [...claims, ...notes]) {
|
|
49
|
+
const line = `- ${renderPin(pin)}`;
|
|
50
|
+
if (size + line.length > limit) {
|
|
51
|
+
lines.push("- \u2026 more on alp_board");
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
lines.push(line);
|
|
55
|
+
size += line.length;
|
|
56
|
+
}
|
|
57
|
+
return lines.join("\n");
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
BOARD_KEEP,
|
|
61
|
+
PIN_BODY_CHARS,
|
|
62
|
+
PIN_KINDS,
|
|
63
|
+
PIN_PATHS,
|
|
64
|
+
live,
|
|
65
|
+
normalizePaths,
|
|
66
|
+
overlapping,
|
|
67
|
+
renderBoard,
|
|
68
|
+
renderPin
|
|
69
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const DEFAULT_MODEL = "gpt-5.6-sol";
|
|
2
|
+
export declare const DEFAULT_CLAUDE_MODEL = "sonnet";
|
|
3
|
+
export declare const DEFAULT_ANTIGRAVITY_MODEL = "gemini-3.8-flash-high";
|
|
4
|
+
/** Oracle runs on one of these; main may consult both for two opinions. */
|
|
5
|
+
export declare const ORACLE_MODELS: string[];
|
|
6
|
+
export declare const ORACLE_THINKING = "high";
|
|
7
|
+
export declare const modes: {
|
|
8
|
+
id: string;
|
|
9
|
+
label: string;
|
|
10
|
+
}[];
|
|
11
|
+
/** Whether a session in `mode` may run with `requested`; a child never exceeds its requester. */
|
|
12
|
+
export declare const withinMode: (requested: string, mode: string) => boolean;
|
|
13
|
+
export declare const writes: (mode: string) => boolean;
|
|
14
|
+
export declare const thinkingOptions: {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
}[];
|
|
18
|
+
export declare const models: {
|
|
19
|
+
defaultThinkingOptionId?: string | undefined;
|
|
20
|
+
id: string;
|
|
21
|
+
label: string;
|
|
22
|
+
description: string;
|
|
23
|
+
thinkingOptions: {
|
|
24
|
+
id: string;
|
|
25
|
+
label: string;
|
|
26
|
+
}[];
|
|
27
|
+
}[];
|
|
28
|
+
export declare function thinkingOptionsFor(runtime: 'codex' | 'claude' | 'antigravity', nativeModel: string): {
|
|
29
|
+
id: string;
|
|
30
|
+
label: string;
|
|
31
|
+
}[];
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// packages/runtime/src/catalog.ts
|
|
2
|
+
import { MODELS } from "@anhlp/alp-core/models";
|
|
3
|
+
var DEFAULT_MODEL = "gpt-5.6-sol";
|
|
4
|
+
var DEFAULT_CLAUDE_MODEL = "sonnet";
|
|
5
|
+
var DEFAULT_ANTIGRAVITY_MODEL = "gemini-3.8-flash-high";
|
|
6
|
+
var ORACLE_MODELS = ["claude:claude-fable-5-1", "codex:gpt-6-astra"];
|
|
7
|
+
var ORACLE_THINKING = "high";
|
|
8
|
+
var modes = [{ id: "read-only", label: "Read only" }, { id: "workspace-write", label: "Workspace write" }, { id: "full-access", label: "Full access" }];
|
|
9
|
+
var modeRank = { "read-only": 0, "workspace-write": 1, "full-access": 2 };
|
|
10
|
+
var withinMode = (requested, mode) => (modeRank[requested] ?? 3) <= (modeRank[mode] ?? -1);
|
|
11
|
+
var writes = (mode) => mode !== "read-only";
|
|
12
|
+
var option = (id) => ({ id, label: id });
|
|
13
|
+
var options = (ids) => ids.map(option);
|
|
14
|
+
var thinkingOptions = options(["none", "off", "low", "medium", "high", "xhigh", "max", "ultra", "ultracode"]);
|
|
15
|
+
var model = (runtime, id, label, description, modelThinkingOptions, defaultThinkingOptionId) => ({
|
|
16
|
+
id: `${runtime}:${id}`,
|
|
17
|
+
label: `${runtime === "codex" ? "Codex" : runtime === "claude" ? "Claude Code" : "Antigravity"} \xB7 ${label}`,
|
|
18
|
+
description,
|
|
19
|
+
thinkingOptions: modelThinkingOptions,
|
|
20
|
+
...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
|
|
21
|
+
});
|
|
22
|
+
var models = MODELS.map((entry) => model(entry.runtime, entry.id, entry.label, entry.description, options(entry.efforts), entry.effort));
|
|
23
|
+
function thinkingOptionsFor(runtime, nativeModel) {
|
|
24
|
+
return models.find((candidate) => candidate.id === `${runtime}:${nativeModel}`)?.thinkingOptions ?? thinkingOptions;
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
DEFAULT_ANTIGRAVITY_MODEL,
|
|
28
|
+
DEFAULT_CLAUDE_MODEL,
|
|
29
|
+
DEFAULT_MODEL,
|
|
30
|
+
ORACLE_MODELS,
|
|
31
|
+
ORACLE_THINKING,
|
|
32
|
+
models,
|
|
33
|
+
modes,
|
|
34
|
+
thinkingOptions,
|
|
35
|
+
thinkingOptionsFor,
|
|
36
|
+
withinMode,
|
|
37
|
+
writes
|
|
38
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const toolShapes: Record<string, Record<string, z.ZodType>>;
|
|
3
|
+
type Listener = (method: string, params: any) => void;
|
|
4
|
+
type RequestHandler = (method: string, params: any) => Promise<unknown>;
|
|
5
|
+
/** The plugin name ALP's skills are loaded under, so Claude Code calls them alp:<name>. */
|
|
6
|
+
export declare const SKILL_PLUGIN = "alp";
|
|
7
|
+
/**
|
|
8
|
+
* A Claude Code plugin in `directory` holding the given skills, linked to their own
|
|
9
|
+
* directories so an edit to a skill reaches the next session (ALPD §59).
|
|
10
|
+
*/
|
|
11
|
+
export declare function skillPlugin(directory: string, skills: Array<{
|
|
12
|
+
name: string;
|
|
13
|
+
path: string;
|
|
14
|
+
}>): string;
|
|
15
|
+
type PermissionRules = {
|
|
16
|
+
allow: string[];
|
|
17
|
+
ask?: string[];
|
|
18
|
+
deny: string[];
|
|
19
|
+
beyondMode?: 'refuse' | 'ask';
|
|
20
|
+
/** The OS sandbox ALP puts Bash in, and the directory it may write besides temp files. */
|
|
21
|
+
floor?: 'read-only' | 'workspace-write';
|
|
22
|
+
floorRoot?: string;
|
|
23
|
+
};
|
|
24
|
+
/** Whether Claude Code can sandbox Bash here: Seatbelt on macOS, bubblewrap and socat on Linux. ALP_CLAUDE_SANDBOX=0 turns it off, =1 claims it (tests). */
|
|
25
|
+
export declare function claudeSandboxAvailable(): boolean;
|
|
26
|
+
/** What ALP asks the user for a permission Claude would otherwise not have. */
|
|
27
|
+
export type PermissionRequest = {
|
|
28
|
+
tool: string;
|
|
29
|
+
input: Record<string, unknown>;
|
|
30
|
+
reason: 'rule' | 'mode';
|
|
31
|
+
rule?: string;
|
|
32
|
+
};
|
|
33
|
+
export type PermissionAnswer = {
|
|
34
|
+
allow: boolean;
|
|
35
|
+
always?: boolean;
|
|
36
|
+
message?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Claude's permission mode for an ALP mode; full-access skips every permission check. */
|
|
39
|
+
export declare const claudePermissionMode: (sandbox: string) => "default" | "acceptEdits" | "bypassPermissions";
|
|
40
|
+
export declare function claudePermissions(sandbox: string, currentSandbox?: () => string, rules?: PermissionRules | null, ask?: (request: PermissionRequest) => Promise<PermissionAnswer>): {
|
|
41
|
+
canUseTool: (name: string, input: Record<string, unknown>, context?: {
|
|
42
|
+
decisionReasonType?: string;
|
|
43
|
+
suggestions?: unknown;
|
|
44
|
+
}) => Promise<{
|
|
45
|
+
behavior: string;
|
|
46
|
+
message: string;
|
|
47
|
+
} | {
|
|
48
|
+
updatedPermissions?: {
|
|
49
|
+
type: string;
|
|
50
|
+
rules: {
|
|
51
|
+
ruleContent?: string | undefined;
|
|
52
|
+
toolName: string;
|
|
53
|
+
}[];
|
|
54
|
+
behavior: string;
|
|
55
|
+
destination: string;
|
|
56
|
+
}[] | undefined;
|
|
57
|
+
behavior: string;
|
|
58
|
+
updatedInput: Record<string, unknown>;
|
|
59
|
+
message?: undefined;
|
|
60
|
+
}>;
|
|
61
|
+
sandbox?: {
|
|
62
|
+
filesystem?: {
|
|
63
|
+
denyWrite: string[];
|
|
64
|
+
} | undefined;
|
|
65
|
+
enabled: boolean;
|
|
66
|
+
autoAllowBashIfSandboxed: boolean;
|
|
67
|
+
allowUnsandboxedCommands: boolean;
|
|
68
|
+
} | undefined;
|
|
69
|
+
settings?: {
|
|
70
|
+
permissions: {
|
|
71
|
+
ask: string[];
|
|
72
|
+
};
|
|
73
|
+
} | undefined;
|
|
74
|
+
disallowedTools: string[];
|
|
75
|
+
allowedTools?: string[] | undefined;
|
|
76
|
+
tools?: string[] | undefined;
|
|
77
|
+
permissionMode: string;
|
|
78
|
+
allowDangerouslySkipPermissions: boolean;
|
|
79
|
+
};
|
|
80
|
+
/** Whether Claude's last rate limit report means requests are refused: rejected, with no overage to fall back on. */
|
|
81
|
+
export declare const claudeLimited: (info?: {
|
|
82
|
+
status: string;
|
|
83
|
+
overageStatus?: string;
|
|
84
|
+
}) => boolean;
|
|
85
|
+
/** Maps Claude Agent SDK streaming sessions to the normalized runtime protocol. */
|
|
86
|
+
export declare class ClaudeTransport {
|
|
87
|
+
private readonly command;
|
|
88
|
+
private readonly cwd;
|
|
89
|
+
private readonly env;
|
|
90
|
+
private listeners;
|
|
91
|
+
private failures;
|
|
92
|
+
private requestHandler?;
|
|
93
|
+
/** Whether the workspace had a .claude directory before a sandboxed session started. */
|
|
94
|
+
private claudeDirectory?;
|
|
95
|
+
private input;
|
|
96
|
+
private query?;
|
|
97
|
+
private pump?;
|
|
98
|
+
private config?;
|
|
99
|
+
private threadId;
|
|
100
|
+
private activeTurn?;
|
|
101
|
+
private closed;
|
|
102
|
+
private assistantText;
|
|
103
|
+
private toolCalls;
|
|
104
|
+
/** The last rate limit Claude reported, and whether the running turn hit one. */
|
|
105
|
+
private rateLimit?;
|
|
106
|
+
private limitedTurn;
|
|
107
|
+
/** The model's context window and the fill at which Claude compacts it, as Claude reports them (ALPD §57). */
|
|
108
|
+
private contextWindow?;
|
|
109
|
+
private compactAt?;
|
|
110
|
+
/** The compaction running now, from its start to its boundary. */
|
|
111
|
+
private compaction?;
|
|
112
|
+
/** The plugin directory that loads the agent's skills, removed on close. */
|
|
113
|
+
private skillDirectory?;
|
|
114
|
+
constructor(command: string, cwd: string, env: NodeJS.ProcessEnv);
|
|
115
|
+
orchestrationContext(): Promise<{
|
|
116
|
+
runtime: string;
|
|
117
|
+
observedAt: string;
|
|
118
|
+
catalogAvailable: boolean;
|
|
119
|
+
models: {
|
|
120
|
+
id: string;
|
|
121
|
+
label: string;
|
|
122
|
+
description: string;
|
|
123
|
+
thinking: string[] | undefined;
|
|
124
|
+
}[];
|
|
125
|
+
usage: {
|
|
126
|
+
available: boolean;
|
|
127
|
+
plan?: undefined;
|
|
128
|
+
windows?: undefined;
|
|
129
|
+
} | {
|
|
130
|
+
available: boolean;
|
|
131
|
+
plan: any;
|
|
132
|
+
windows: {
|
|
133
|
+
name: string;
|
|
134
|
+
usedPercent: any;
|
|
135
|
+
remainingPercent: number | null;
|
|
136
|
+
resetsAt: any;
|
|
137
|
+
}[];
|
|
138
|
+
};
|
|
139
|
+
}>;
|
|
140
|
+
initialize(): Promise<void>;
|
|
141
|
+
/** The plan's usage windows before a session starts, from a Claude process that sends no prompt and is closed after. */
|
|
142
|
+
private probeUsage;
|
|
143
|
+
onNotification(listener: Listener): () => boolean;
|
|
144
|
+
onFailure(listener: (error: Error) => void): () => boolean;
|
|
145
|
+
onRequest(handler: RequestHandler): void;
|
|
146
|
+
request(method: string, params: any): Promise<any>;
|
|
147
|
+
private start;
|
|
148
|
+
/** Reads the window and the compaction threshold Claude resolved for this session, before any turn. */
|
|
149
|
+
private measureContext;
|
|
150
|
+
private convertMcp;
|
|
151
|
+
private consume;
|
|
152
|
+
private handle;
|
|
153
|
+
private emit;
|
|
154
|
+
private fail;
|
|
155
|
+
close(): Promise<void>;
|
|
156
|
+
}
|
|
157
|
+
export {};
|