@anhlp/alp 0.0.1-beta.4 → 0.0.1-beta.7
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/README.md +11 -412
- package/bin/alp.js +3 -0
- package/package.json +11 -103
- package/dist/THIRD-PARTY-NOTICES.txt +0 -626
- package/dist/acp.js +0 -19936
- package/dist/alpd.js +0 -49562
- package/docs/modular-monorepo.md +0 -214
- package/packages/cli/README.md +0 -7
- package/packages/cli/dist/THIRD-PARTY-NOTICES.txt +0 -651
- package/packages/cli/dist/acp/agent.d.ts +0 -37
- package/packages/cli/dist/acp/agent.js +0 -489
- package/packages/cli/dist/acp/main.d.ts +0 -4
- package/packages/cli/dist/acp/main.js +0 -23
- package/packages/cli/dist/acp.js +0 -19936
- package/packages/cli/dist/alp-web/THIRD-PARTY-NOTICES.txt +0 -2590
- package/packages/cli/dist/alp-web/alp-boundary.json +0 -15
- package/packages/cli/dist/alp-web/apple-touch-icon.png +0 -0
- package/packages/cli/dist/alp-web/assets/TerminalPanel-DLuoa74B.css +0 -1
- package/packages/cli/dist/alp-web/assets/TerminalPanel-PrU2l3u5.js +0 -16
- package/packages/cli/dist/alp-web/assets/index-BJdBTDFX.css +0 -1
- package/packages/cli/dist/alp-web/assets/index-DpfiPv5s.js +0 -52
- package/packages/cli/dist/alp-web/favicon-attention.svg +0 -6
- package/packages/cli/dist/alp-web/favicon-running.svg +0 -6
- package/packages/cli/dist/alp-web/favicon.svg +0 -5
- package/packages/cli/dist/alp-web/index.html +0 -20
- package/packages/cli/dist/alp-web.js +0 -9640
- package/packages/cli/dist/alpd.js +0 -49562
- package/packages/cli/dist/backup.d.ts +0 -4
- package/packages/cli/dist/backup.js +0 -146
- package/packages/cli/dist/build-manifest.json +0 -240
- package/packages/cli/dist/cli.d.ts +0 -2
- package/packages/cli/dist/cli.js +0 -30
- package/packages/cli/dist/daemon.d.ts +0 -35
- package/packages/cli/dist/daemon.js +0 -126
- package/packages/cli/dist/index.d.ts +0 -1
- package/packages/cli/dist/index.js +0 -5
- package/packages/cli/dist/interfaces.d.ts +0 -24
- package/packages/cli/dist/interfaces.js +0 -156
- package/packages/cli/dist/library.d.ts +0 -140
- package/packages/cli/dist/library.js +0 -319
- package/packages/cli/dist/paths.d.ts +0 -3
- package/packages/cli/dist/paths.js +0 -18
- package/packages/cli/dist/projects.d.ts +0 -9
- package/packages/cli/dist/projects.js +0 -159
- package/packages/cli/dist/schedules.d.ts +0 -2
- package/packages/cli/dist/schedules.js +0 -45
- package/packages/cli/dist/sessions.d.ts +0 -43
- package/packages/cli/dist/sessions.js +0 -458
- package/packages/cli/dist/tasks.d.ts +0 -29
- package/packages/cli/dist/tasks.js +0 -345
- package/packages/cli/dist/terminal.d.ts +0 -8
- package/packages/cli/dist/terminal.js +0 -79
- package/packages/cli/dist/usage.d.ts +0 -3
- package/packages/cli/dist/usage.js +0 -78
- package/packages/cli/dist/web-service.d.ts +0 -38
- package/packages/cli/dist/web-service.js +0 -119
- package/packages/client/README.md +0 -29
- package/packages/client/dist/acp-probe.d.ts +0 -44
- package/packages/client/dist/acp-probe.js +0 -37
- package/packages/client/dist/antigravity-probe.d.ts +0 -34
- package/packages/client/dist/antigravity-probe.js +0 -95
- package/packages/client/dist/command.d.ts +0 -5
- package/packages/client/dist/command.js +0 -33
- package/packages/client/dist/doctor.d.ts +0 -13
- package/packages/client/dist/doctor.js +0 -587
- package/packages/client/dist/index.d.ts +0 -151
- package/packages/client/dist/index.js +0 -533
- package/packages/client/dist/integration-lock.d.ts +0 -35
- package/packages/client/dist/integration-lock.js +0 -179
- package/packages/client/dist/ipc.d.ts +0 -42
- package/packages/client/dist/ipc.js +0 -69
- package/packages/client/dist/library-test.d.ts +0 -94
- package/packages/client/dist/library-test.js +0 -37
- package/packages/client/dist/mcp-probe.d.ts +0 -24
- package/packages/client/dist/mcp-probe.js +0 -147
- package/packages/client/dist/portable.d.ts +0 -19
- package/packages/client/dist/portable.js +0 -33
- package/packages/client/dist/prompt.d.ts +0 -32
- package/packages/client/dist/prompt.js +0 -59
- package/packages/client/dist/render.d.ts +0 -6
- package/packages/client/dist/render.js +0 -120
- package/packages/client/dist/rpc/client.d.ts +0 -82
- package/packages/client/dist/rpc/client.js +0 -292
- package/packages/client/dist/rpc/errors.d.ts +0 -42
- package/packages/client/dist/rpc/errors.js +0 -34
- package/packages/client/dist/rpc/framing.d.ts +0 -21
- package/packages/client/dist/rpc/framing.js +0 -57
- package/packages/client/dist/rpc/handshake.d.ts +0 -19
- package/packages/client/dist/rpc/handshake.js +0 -8
- package/packages/client/dist/rpc/reconnect.d.ts +0 -97
- package/packages/client/dist/rpc/reconnect.js +0 -227
- package/packages/client/dist/rpc/registry.d.ts +0 -211
- package/packages/client/dist/rpc/registry.js +0 -145
- package/packages/client/dist/rpc/timers.d.ts +0 -11
- package/packages/client/dist/rpc/timers.js +0 -11
- package/packages/client/dist/service.d.ts +0 -50
- package/packages/client/dist/service.js +0 -143
- package/packages/client/dist/setup.d.ts +0 -2
- package/packages/client/dist/setup.js +0 -146
- package/packages/client/dist/supervise.d.ts +0 -14
- package/packages/client/dist/supervise.js +0 -87
- package/packages/client/dist/websocket.d.ts +0 -51
- package/packages/client/dist/websocket.js +0 -190
- package/packages/core/README.md +0 -7
- package/packages/core/dist/adapter.d.ts +0 -20
- package/packages/core/dist/adapter.js +0 -30
- package/packages/core/dist/atomic.d.ts +0 -2
- package/packages/core/dist/atomic.js +0 -28
- package/packages/core/dist/backup.d.ts +0 -27
- package/packages/core/dist/backup.js +0 -681
- package/packages/core/dist/beads.d.ts +0 -65
- package/packages/core/dist/beads.js +0 -213
- package/packages/core/dist/delegation.d.ts +0 -2
- package/packages/core/dist/delegation.js +0 -32
- package/packages/core/dist/errors.d.ts +0 -4
- package/packages/core/dist/errors.js +0 -11
- package/packages/core/dist/formulas.d.ts +0 -25
- package/packages/core/dist/formulas.js +0 -201
- package/packages/core/dist/hook-run.d.ts +0 -44
- package/packages/core/dist/hook-run.js +0 -60
- package/packages/core/dist/hooks.d.ts +0 -35
- package/packages/core/dist/hooks.js +0 -30
- package/packages/core/dist/index.d.ts +0 -31
- package/packages/core/dist/index.js +0 -65
- package/packages/core/dist/init.d.ts +0 -30
- package/packages/core/dist/init.js +0 -89
- package/packages/core/dist/library-edit.d.ts +0 -93
- package/packages/core/dist/library-edit.js +0 -368
- package/packages/core/dist/library.d.ts +0 -28
- package/packages/core/dist/library.js +0 -108
- package/packages/core/dist/log.d.ts +0 -37
- package/packages/core/dist/log.js +0 -156
- package/packages/core/dist/migrations.d.ts +0 -9
- package/packages/core/dist/migrations.js +0 -95
- package/packages/core/dist/models.d.ts +0 -11
- package/packages/core/dist/models.js +0 -44
- package/packages/core/dist/permissions.d.ts +0 -14
- package/packages/core/dist/permissions.js +0 -229
- package/packages/core/dist/profiles.d.ts +0 -27
- package/packages/core/dist/profiles.js +0 -122
- package/packages/core/dist/promptsafe.d.ts +0 -1
- package/packages/core/dist/promptsafe.js +0 -13
- package/packages/core/dist/providers.d.ts +0 -90
- package/packages/core/dist/providers.js +0 -101
- package/packages/core/dist/resolver.d.ts +0 -41
- package/packages/core/dist/resolver.js +0 -240
- package/packages/core/dist/safe-path.d.ts +0 -2
- package/packages/core/dist/safe-path.js +0 -24
- package/packages/core/dist/shell.d.ts +0 -16
- package/packages/core/dist/shell.js +0 -22
- package/packages/core/dist/state-schema.d.ts +0 -9
- package/packages/core/dist/state-schema.js +0 -54
- package/packages/core/dist/task-rows.d.ts +0 -47
- package/packages/core/dist/task-rows.js +0 -45
- package/packages/core/dist/tasks.d.ts +0 -128
- package/packages/core/dist/tasks.js +0 -835
- package/packages/core/dist/teams.d.ts +0 -80
- package/packages/core/dist/teams.js +0 -159
- package/packages/core/dist/template-path.d.ts +0 -2
- package/packages/core/dist/template-path.js +0 -10
- package/packages/core/dist/trust.d.ts +0 -8
- package/packages/core/dist/trust.js +0 -47
- package/packages/core/dist/types.d.ts +0 -51
- package/packages/core/dist/upgrade.d.ts +0 -10
- package/packages/core/dist/upgrade.js +0 -200
- package/packages/core/dist/user-settings.d.ts +0 -6
- package/packages/core/dist/user-settings.js +0 -72
- package/packages/core/dist/user-worktree.d.ts +0 -29
- package/packages/core/dist/user-worktree.js +0 -242
- package/packages/core/dist/validation.d.ts +0 -17
- package/packages/core/dist/validation.js +0 -296
- package/packages/core/dist/verify.d.ts +0 -15
- package/packages/core/dist/verify.js +0 -123
- package/packages/core/dist/workflow.d.ts +0 -45
- package/packages/core/dist/workflow.js +0 -33
- package/templates/ALP.md +0 -52
- package/templates/agents/lead/AGENT.md +0 -90
- package/templates/agents/main/AGENT.md +0 -150
- package/templates/agents/oracle/AGENT.md +0 -44
- package/templates/agents/peer/AGENT.md +0 -55
- package/templates/agents/reviewer/AGENT.md +0 -80
- package/templates/agents/supervisor/AGENT.md +0 -72
- package/templates/providers/antigravity.json +0 -6
- package/templates/providers/opencode.json +0 -7
- package/templates/role-skills.json +0 -8
- package/templates/skills/bug-loop/SKILL.md +0 -44
- package/templates/skills/bug-loop/references/test-proof.md +0 -25
- package/templates/skills/goal-griller/SKILL.md +0 -49
- package/templates/skills/prompt-leverage/SKILL.md +0 -37
- package/templates/skills/prompt-leverage/references/brief-template.md +0 -27
- package/templates/skills/sequence-execution-plan/SKILL.md +0 -42
- package/templates/skills/sequence-execution-plan/references/plan-template.md +0 -22
- package/templates/skills/smart-commits/SKILL.md +0 -40
- package/templates/skills/xia/SKILL.md +0 -42
- package/templates/teams/cafe/HOUSE_RULES.md +0 -1
- package/templates/teams/cafe/team.json +0 -15
- package/templates/teams/pho/HOUSE_RULES.md +0 -1
- package/templates/teams/pho/team.json +0 -14
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
// packages/core/src/library-edit.js
|
|
2
|
-
import { lstat, mkdir, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { moveFile } from "./atomic.js";
|
|
6
|
-
import { AlpError } from "./errors.js";
|
|
7
|
-
import { assertNoSymlinks } from "./safe-path.js";
|
|
8
|
-
import { agentSources, builtinText, jsonObject, libraryEntries, optionalText } from "./resolver.js";
|
|
9
|
-
import { teamSources, validateTeam } from "./teams.js";
|
|
10
|
-
import { normalizeMcp, validateAgentConfig, validateHook } from "./validation.js";
|
|
11
|
-
import { validateProvider } from "./providers.js";
|
|
12
|
-
var EDIT_KINDS = ["agents", "skills", "mcp", "hooks", "teams", "providers"];
|
|
13
|
-
var validName = (name) => typeof name === "string" && /^[\w.-]+$/.test(name) && name !== "." && name !== "..";
|
|
14
|
-
var object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
15
|
-
var fail = (code, message) => {
|
|
16
|
-
throw new AlpError(code, message);
|
|
17
|
-
};
|
|
18
|
-
var FILES = {
|
|
19
|
-
agents: (name) => [[`${name}/AGENT.md`, "instructions", "text"], [`${name}/agent.json`, "config", "json"]],
|
|
20
|
-
skills: (name) => [[`${name}/SKILL.md`, "body", "text"]],
|
|
21
|
-
mcp: (name) => [[`${name}.json`, "server", "json"]],
|
|
22
|
-
hooks: (name) => [[`${name}.json`, "hook", "json"]],
|
|
23
|
-
teams: (name) => [[`${name}/team.json`, "team", "json"], [`${name}/HOUSE_RULES.md`, "houseRules", "text"]],
|
|
24
|
-
providers: (name) => [[`${name}.json`, "provider", "json"]]
|
|
25
|
-
};
|
|
26
|
-
var ownDirectory = (kind) => ["agents", "skills", "teams"].includes(kind);
|
|
27
|
-
function kindOf(kind) {
|
|
28
|
-
if (!EDIT_KINDS.includes(kind)) fail("INVALID_KIND", `Unknown kind '${kind}'; use one of ${EDIT_KINDS.join(", ")}`);
|
|
29
|
-
return kind;
|
|
30
|
-
}
|
|
31
|
-
function nameOf(name) {
|
|
32
|
-
if (!validName(name)) fail("INVALID_NAME", `'${name}' is not a valid name: use letters, digits, '.', '_' or '-'`);
|
|
33
|
-
return name;
|
|
34
|
-
}
|
|
35
|
-
function base(scope, { root, library }, kind) {
|
|
36
|
-
if (kind === "providers" && scope !== "library") fail("INVALID_SCOPE", "Providers live only in your library");
|
|
37
|
-
if (scope === "library") return library ?? fail("INVALID_SCOPE", "No library: ALP_HOME is not set");
|
|
38
|
-
if (scope === "project") return root ? path.join(path.resolve(root), ".alp") : fail("INVALID_SCOPE", "No project directory");
|
|
39
|
-
return fail("INVALID_SCOPE", `Scope must be library or project, not '${scope}'`);
|
|
40
|
-
}
|
|
41
|
-
var revisionOf = (content) => content === void 0 ? null : createHash("sha256").update(JSON.stringify(content)).digest("hex").slice(0, 16);
|
|
42
|
-
function assertProjectDataContent(kind, content) {
|
|
43
|
-
const deny = () => fail("UNSAFE_LIBRARY_WRITE", "Project-data writes allow only instruction entries and non-executable agent configuration");
|
|
44
|
-
if (!object(content) || !["agents", "skills"].includes(kind)) deny();
|
|
45
|
-
const keys = kind === "skills" ? ["body"] : ["instructions", "config"];
|
|
46
|
-
if (Object.keys(content).some((key) => !keys.includes(key))) deny();
|
|
47
|
-
const text = kind === "skills" ? content.body : content.instructions;
|
|
48
|
-
if (typeof text !== "string" || !text.trim()) deny();
|
|
49
|
-
if (content.config !== void 0) {
|
|
50
|
-
const config = content.config;
|
|
51
|
-
if (!object(config)) deny();
|
|
52
|
-
const allowed = ["description", "model", "thinking", "context", "autocompact"];
|
|
53
|
-
if (Object.keys(config).some((key) => !allowed.includes(key))) deny();
|
|
54
|
-
for (const key of ["description", "thinking"]) if (config[key] !== void 0 && typeof config[key] !== "string") deny();
|
|
55
|
-
if (config.model !== void 0 && (typeof config.model !== "string" || !/^(codex|claude):[^\s/\\:]{1,240}$/.test(config.model))) deny();
|
|
56
|
-
for (const key of ["context", "autocompact"]) if (config[key] !== void 0 && !(typeof config[key] === "string" || typeof config[key] === "number" && Number.isFinite(config[key]))) deny();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
async function projectDataEntry(kind, name, { scope, root, library, templates }) {
|
|
60
|
-
if (scope !== "project" || !root || !["agents", "skills"].includes(kind)) fail("UNSAFE_LIBRARY_WRITE", "Project-data writes require project scope and agents or skills");
|
|
61
|
-
nameOf(name);
|
|
62
|
-
const directory = base(scope, { root, library }, kind);
|
|
63
|
-
await safeEntryPaths(directory, kind, name);
|
|
64
|
-
const found = await layers(kind, name, { root, library, templates });
|
|
65
|
-
if (found.library !== void 0 || found.builtin !== void 0) fail("UNSAFE_LIBRARY_WRITE", "Project-data writes cannot shadow or reveal a library or built-in entry");
|
|
66
|
-
if (found.project !== void 0) assertProjectDataContent(kind, found.project);
|
|
67
|
-
const owned = path.join(directory, kind, name);
|
|
68
|
-
const files = await readdir(owned).catch((error) => {
|
|
69
|
-
if (error.code === "ENOENT") return [];
|
|
70
|
-
throw error;
|
|
71
|
-
});
|
|
72
|
-
const allowed = new Set(FILES[kind](name).map(([file]) => path.basename(file)));
|
|
73
|
-
for (const file of files) {
|
|
74
|
-
const info = await lstat(path.join(owned, file));
|
|
75
|
-
if (!allowed.has(file) || !info.isFile() || info.isSymbolicLink() || info.nlink !== 1) fail("UNSAFE_LIBRARY_WRITE", "Project-data entries cannot contain sidecars, links or executable assets");
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async function safeEntryPaths(directory, kind, name) {
|
|
79
|
-
for (const [file] of FILES[kind](name)) {
|
|
80
|
-
await assertNoSymlinks(directory, path.join(kind, file));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
async function readLayer(kind, name, directory) {
|
|
84
|
-
await safeEntryPaths(directory, kind, name);
|
|
85
|
-
const content = {};
|
|
86
|
-
let found = false;
|
|
87
|
-
for (const [file, key, type] of FILES[kind](name)) {
|
|
88
|
-
const target = path.join(directory, kind, file);
|
|
89
|
-
const text = await optionalText(target);
|
|
90
|
-
if (text === void 0) continue;
|
|
91
|
-
found = true;
|
|
92
|
-
if (type === "text") {
|
|
93
|
-
content[key] = text;
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
try {
|
|
97
|
-
content[key] = JSON.parse(text);
|
|
98
|
-
} catch (cause) {
|
|
99
|
-
throw new AlpError("INVALID_ENTRY", `${target}: ${cause.message}`, { cause });
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
const main = { agents: "instructions", skills: "body", teams: "team" }[kind];
|
|
103
|
-
return found && (!main || content[main] !== void 0) ? content : void 0;
|
|
104
|
-
}
|
|
105
|
-
async function readBuiltin(kind, name, templates) {
|
|
106
|
-
if (kind === "agents") {
|
|
107
|
-
const instructions = await builtinText(`agents/${name}/AGENT.md`, templates);
|
|
108
|
-
if (instructions === void 0) return void 0;
|
|
109
|
-
const config = await builtinText(`agents/${name}/agent.json`, templates);
|
|
110
|
-
return { instructions, ...config !== void 0 ? { config: JSON.parse(config) } : {} };
|
|
111
|
-
}
|
|
112
|
-
if (kind === "teams") {
|
|
113
|
-
const team = await builtinText(`teams/${name}/team.json`, templates);
|
|
114
|
-
if (team === void 0) return void 0;
|
|
115
|
-
return { team: JSON.parse(team), houseRules: await builtinText(`teams/${name}/HOUSE_RULES.md`, templates) ?? "" };
|
|
116
|
-
}
|
|
117
|
-
return void 0;
|
|
118
|
-
}
|
|
119
|
-
async function layers(kind, name, { root, library, templates }) {
|
|
120
|
-
return {
|
|
121
|
-
builtin: await readBuiltin(kind, name, templates),
|
|
122
|
-
library: library ? await readLayer(kind, name, library) : void 0,
|
|
123
|
-
project: root && kind !== "providers" ? await readLayer(kind, name, path.join(path.resolve(root), ".alp")) : void 0
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
async function getEntry(kind, name, { root, library, templates, scope } = {}) {
|
|
127
|
-
kindOf(kind);
|
|
128
|
-
nameOf(name);
|
|
129
|
-
const found = await layers(kind, name, { root, library, templates });
|
|
130
|
-
const order = scope ? [scope] : ["project", "library", "builtin"];
|
|
131
|
-
const source = order.find((layer) => found[layer] !== void 0);
|
|
132
|
-
if (!source) fail("NOT_FOUND", `No ${kind} entry '${name}'${scope ? ` in the ${scope}` : ""}`);
|
|
133
|
-
const below = ["builtin", "library", "project"].slice(0, ["builtin", "library", "project"].indexOf(source)).reverse().find((layer) => found[layer] !== void 0);
|
|
134
|
-
return {
|
|
135
|
-
kind,
|
|
136
|
-
name,
|
|
137
|
-
source: (
|
|
138
|
-
/** @type {'builtin' | 'library' | 'project'} */
|
|
139
|
-
source
|
|
140
|
-
),
|
|
141
|
-
...below ? { overrides: (
|
|
142
|
-
/** @type {'builtin' | 'library'} */
|
|
143
|
-
below
|
|
144
|
-
) } : {},
|
|
145
|
-
content: found[source],
|
|
146
|
-
revision: revisionOf(found[source]),
|
|
147
|
-
usedBy: await usersOf(kind, name, { root, library, templates }),
|
|
148
|
-
// The skills the library gives an agent by name, whatever layer defines it (ALPD §49).
|
|
149
|
-
...kind === "agents" && library ? { librarySkills: await givenSkills(library, name) } : {}
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
async function readGiven(library) {
|
|
153
|
-
const file = path.join(library, "role-skills.json");
|
|
154
|
-
const text = await optionalText(file);
|
|
155
|
-
if (text === void 0) return { file, roles: {} };
|
|
156
|
-
let roles;
|
|
157
|
-
try {
|
|
158
|
-
roles = JSON.parse(text);
|
|
159
|
-
} catch (cause) {
|
|
160
|
-
throw new AlpError("INVALID_LIBRARY", `${file}: ${cause.message}`, { cause });
|
|
161
|
-
}
|
|
162
|
-
if (!object(roles)) fail("INVALID_LIBRARY", `${file}: expected an object of agent names to skill lists`);
|
|
163
|
-
return { file, roles };
|
|
164
|
-
}
|
|
165
|
-
async function givenSkills(library, agent) {
|
|
166
|
-
const { roles } = await readGiven(library);
|
|
167
|
-
return Array.isArray(roles[agent]) ? roles[agent].filter((name) => typeof name === "string") : [];
|
|
168
|
-
}
|
|
169
|
-
async function setGivenSkills(agent, skills, { library } = {}) {
|
|
170
|
-
nameOf(agent);
|
|
171
|
-
if (!library) fail("INVALID_SCOPE", "No library: ALP_HOME is not set");
|
|
172
|
-
if (!Array.isArray(skills) || !skills.every(validName)) fail("INVALID_ENTRY", "Skills must be a list of skill names");
|
|
173
|
-
const unique = [...new Set(skills)];
|
|
174
|
-
for (const skill of unique) if (!await exists(path.join(library, "skills", skill, "SKILL.md"))) fail("NOT_FOUND", `No skill '${skill}' in the library`);
|
|
175
|
-
const { file, roles } = await readGiven(library);
|
|
176
|
-
if (unique.length) roles[agent] = unique;
|
|
177
|
-
else delete roles[agent];
|
|
178
|
-
await writeAtomic(file, JSON.stringify(roles, null, 2) + "\n");
|
|
179
|
-
return { skills: unique };
|
|
180
|
-
}
|
|
181
|
-
async function listEntries(kind, { root, library, templates } = {}) {
|
|
182
|
-
kindOf(kind);
|
|
183
|
-
if (kind !== "teams") return libraryEntries(kind, root, { library, templates });
|
|
184
|
-
const rows = [];
|
|
185
|
-
for (const [name, source] of await teamSources(root, { library, templates })) rows.push({ name, source: source.source, ...source.overrides ? { overrides: source.overrides } : {}, ...source.directory ? { path: source.directory } : {}, usedBy: await usersOf(kind, name, { root, library, templates }) });
|
|
186
|
-
return rows;
|
|
187
|
-
}
|
|
188
|
-
async function usersOf(kind, name, { root, library, templates } = {}) {
|
|
189
|
-
const users = /* @__PURE__ */ new Set();
|
|
190
|
-
if (kind === "providers" && root) {
|
|
191
|
-
const settings = await jsonObject(path.join(path.resolve(root), ".alp", "settings.json"), "INVALID_SETTINGS").catch(() => ({}));
|
|
192
|
-
if (settings.runtime?.provider === name) users.add("project settings");
|
|
193
|
-
}
|
|
194
|
-
if (kind === "teams") {
|
|
195
|
-
if (root) {
|
|
196
|
-
const settings = await jsonObject(path.join(path.resolve(root), ".alp", "settings.json"), "INVALID_SETTINGS").catch(() => ({}));
|
|
197
|
-
if (settings.workflow?.mode === name) users.add("project settings");
|
|
198
|
-
}
|
|
199
|
-
return [...users];
|
|
200
|
-
}
|
|
201
|
-
if (kind === "agents") {
|
|
202
|
-
for (const [team, source] of await teamSources(root, { library, templates })) {
|
|
203
|
-
const text = source.directory ? await optionalText(path.join(source.directory, "team.json")) : await builtinText(`teams/${team}/team.json`, templates);
|
|
204
|
-
try {
|
|
205
|
-
const config = JSON.parse(text ?? "{}");
|
|
206
|
-
if (config.main === name || Object.hasOwn(config.members ?? {}, name) || config.supervisor?.agent === name) users.add(`team ${team}`);
|
|
207
|
-
} catch {
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (root) {
|
|
211
|
-
const settings = await jsonObject(path.join(path.resolve(root), ".alp", "settings.json"), "INVALID_SETTINGS").catch(() => ({}));
|
|
212
|
-
if (settings.defaultAgent === name) users.add("project settings");
|
|
213
|
-
for (const [owner, targets] of Object.entries(object(settings.delegation) ? settings.delegation : {})) if (owner === name || Array.isArray(targets) && targets.includes(name)) users.add("project delegation");
|
|
214
|
-
}
|
|
215
|
-
return [...users].sort();
|
|
216
|
-
}
|
|
217
|
-
const rows = await libraryEntries(kind, root, { library, templates });
|
|
218
|
-
for (const user of rows.find((row) => row.name === name)?.usedBy ?? []) users.add(`agent ${user}`);
|
|
219
|
-
return [...users].sort();
|
|
220
|
-
}
|
|
221
|
-
async function check(kind, name, content, { scope, root, library, templates }) {
|
|
222
|
-
if (!object(content)) fail("INVALID_ENTRY", `${kind} '${name}': content must be an object`);
|
|
223
|
-
const where = `${scope} ${kind} '${name}'`;
|
|
224
|
-
const visible = scope === "project" ? { root, library, templates } : { library, templates };
|
|
225
|
-
const text = (key, required) => {
|
|
226
|
-
if (content[key] === void 0 && !required) return;
|
|
227
|
-
if (typeof content[key] !== "string" || required && !content[key].trim()) fail("INVALID_ENTRY", `${where}: ${key} must be ${required ? "nonempty " : ""}text`);
|
|
228
|
-
};
|
|
229
|
-
const only = (keys) => {
|
|
230
|
-
for (const key of Object.keys(content)) if (!keys.includes(key)) fail("INVALID_ENTRY", `${where}: unknown field '${key}'; expected ${keys.join(", ")}`);
|
|
231
|
-
};
|
|
232
|
-
if (kind === "agents") {
|
|
233
|
-
only(["instructions", "config"]);
|
|
234
|
-
text("instructions", true);
|
|
235
|
-
if (content.config !== void 0) {
|
|
236
|
-
validateAgentConfig(content.config, `${where} agent.json`);
|
|
237
|
-
for (const [list, entries] of [["skills", "skills"], ["mcp", "mcp"], ["hooks", "hooks"]]) {
|
|
238
|
-
if (!content.config[list]?.length) continue;
|
|
239
|
-
const known = new Set((await libraryEntries(entries, visible.root, visible)).map((row) => row.name));
|
|
240
|
-
for (const entry of content.config[list]) if (!known.has(entry)) fail("NOT_FOUND", `${where}: ${list} names '${entry}', which is not in the ${scope === "project" ? "project or the library" : "library"}`);
|
|
241
|
-
}
|
|
242
|
-
const provider = content.config.provider;
|
|
243
|
-
if (provider !== void 0 && !["codex", "claude"].includes(provider) && !(await libraryEntries("providers", void 0, { library })).some((row) => row.name === provider)) {
|
|
244
|
-
fail("NOT_FOUND", `${where}: provider '${provider}' is neither codex, claude nor an ACP provider in your library`);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
} else if (kind === "skills") {
|
|
248
|
-
only(["body"]);
|
|
249
|
-
text("body", true);
|
|
250
|
-
} else if (kind === "mcp") {
|
|
251
|
-
only(["server"]);
|
|
252
|
-
normalizeMcp({ mcpServers: { [name]: content.server } }, base(scope, { root, library }, kind), where);
|
|
253
|
-
} else if (kind === "hooks") {
|
|
254
|
-
only(["hook"]);
|
|
255
|
-
validateHook(content.hook, where);
|
|
256
|
-
} else if (kind === "providers") {
|
|
257
|
-
only(["provider"]);
|
|
258
|
-
validateProvider(content.provider, where, name);
|
|
259
|
-
} else {
|
|
260
|
-
only(["team", "houseRules"]);
|
|
261
|
-
text("houseRules", false);
|
|
262
|
-
validateTeam(content.team, `${where} team.json`);
|
|
263
|
-
const agents = await agentSources(visible.root, visible);
|
|
264
|
-
const supervisor = content.team.supervisor ? [content.team.supervisor.agent] : [];
|
|
265
|
-
for (const agent of [...Object.keys(content.team.members), ...supervisor]) if (!agents.has(agent)) fail("NOT_FOUND", `${where}: agent '${agent}' is not built in, nor in the ${scope === "project" ? "project or the library" : "library"}`);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
async function writeAtomic(file, text) {
|
|
269
|
-
await mkdir(path.dirname(file), { recursive: true });
|
|
270
|
-
const temporary = `${file}.${randomUUID().slice(0, 8)}.tmp`;
|
|
271
|
-
await writeFile(temporary, text);
|
|
272
|
-
await moveFile(temporary, file);
|
|
273
|
-
}
|
|
274
|
-
var exists = (target) => stat(target).then(() => true, () => false);
|
|
275
|
-
async function saveEntry(kind, name, content, { scope, root, library, templates, revision, policy } = {}) {
|
|
276
|
-
kindOf(kind);
|
|
277
|
-
nameOf(name);
|
|
278
|
-
if (policy === "project-data") {
|
|
279
|
-
assertProjectDataContent(kind, content);
|
|
280
|
-
await projectDataEntry(kind, name, { scope, root, library, templates });
|
|
281
|
-
}
|
|
282
|
-
const directory = base(scope, { root, library }, kind);
|
|
283
|
-
await safeEntryPaths(directory, kind, name);
|
|
284
|
-
await check(kind, name, content, { scope, root, library, templates });
|
|
285
|
-
const current = await readLayer(kind, name, directory);
|
|
286
|
-
if (revision !== void 0 && revision !== revisionOf(current)) {
|
|
287
|
-
fail("REVISION_CONFLICT", current === void 0 ? `${kind} '${name}' was removed from the ${scope} since you opened it` : revision === null ? `${kind} '${name}' already exists in the ${scope}` : `${kind} '${name}' changed in the ${scope} since you opened it; reload it and apply your change again`);
|
|
288
|
-
}
|
|
289
|
-
if (scope === "library") await mkdir(directory, { recursive: true, mode: 448 });
|
|
290
|
-
for (const [file, key, type] of FILES[kind](name)) {
|
|
291
|
-
const target = path.join(directory, kind, file);
|
|
292
|
-
const value = content[key];
|
|
293
|
-
const empty = value === void 0 || type === "json" && key === "config" && !Object.keys(value).length || type === "text" && key === "houseRules" && !value.trim();
|
|
294
|
-
if (empty) {
|
|
295
|
-
await rm(target, { force: true });
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
await writeAtomic(target, type === "json" ? JSON.stringify(value, null, 2) + "\n" : value.endsWith("\n") ? value : `${value}
|
|
299
|
-
`);
|
|
300
|
-
}
|
|
301
|
-
return { revision: revisionOf(await readLayer(kind, name, directory)) };
|
|
302
|
-
}
|
|
303
|
-
async function deleteEntry(kind, name, { scope, root, library, templates, revision, policy } = {}) {
|
|
304
|
-
kindOf(kind);
|
|
305
|
-
nameOf(name);
|
|
306
|
-
if (policy === "project-data") await projectDataEntry(kind, name, { scope, root, library, templates });
|
|
307
|
-
const directory = base(scope, { root, library }, kind);
|
|
308
|
-
const current = await readLayer(kind, name, directory);
|
|
309
|
-
if (current === void 0) fail("NOT_FOUND", `No ${kind} entry '${name}' in the ${scope}`);
|
|
310
|
-
if (revision !== void 0 && revision !== revisionOf(current)) fail("REVISION_CONFLICT", `${kind} '${name}' changed in the ${scope} since you opened it`);
|
|
311
|
-
const found = await layers(kind, name, { root: scope === "project" ? root : void 0, library: scope === "project" ? library : void 0, templates });
|
|
312
|
-
const fallback = scope === "project" ? found.library ?? found.builtin : found.builtin;
|
|
313
|
-
if (fallback === void 0) {
|
|
314
|
-
const users = await usersOf(kind, name, { root, library, templates });
|
|
315
|
-
if (users.length) fail("IN_USE", `${kind} '${name}' is used by ${users.join(", ")}; change them first`);
|
|
316
|
-
}
|
|
317
|
-
if (ownDirectory(kind)) await rm(path.join(directory, kind, name), { recursive: true, force: true });
|
|
318
|
-
else for (const [file] of FILES[kind](name)) await rm(path.join(directory, kind, file), { force: true });
|
|
319
|
-
const now = scope === "project" && found.library !== void 0 ? "library" : "builtin";
|
|
320
|
-
return { removed: true, ...fallback !== void 0 ? { now } : {} };
|
|
321
|
-
}
|
|
322
|
-
async function duplicateEntry(kind, from, to, { scope, root, library, templates, policy } = {}) {
|
|
323
|
-
kindOf(kind);
|
|
324
|
-
nameOf(from);
|
|
325
|
-
nameOf(to);
|
|
326
|
-
if (policy === "project-data") {
|
|
327
|
-
await projectDataEntry(kind, from, { scope, root, library, templates });
|
|
328
|
-
await projectDataEntry(kind, to, { scope, root, library, templates });
|
|
329
|
-
}
|
|
330
|
-
const { content } = await getEntry(kind, from, { root, library, templates });
|
|
331
|
-
return saveEntry(kind, to, structuredClone(content), { scope, root, library, templates, revision: null, policy });
|
|
332
|
-
}
|
|
333
|
-
async function renameEntry(kind, from, to, { scope, root, library, templates, policy } = {}) {
|
|
334
|
-
kindOf(kind);
|
|
335
|
-
nameOf(from);
|
|
336
|
-
nameOf(to);
|
|
337
|
-
if (policy === "project-data") {
|
|
338
|
-
await projectDataEntry(kind, from, { scope, root, library, templates });
|
|
339
|
-
await projectDataEntry(kind, to, { scope, root, library, templates });
|
|
340
|
-
}
|
|
341
|
-
const directory = base(scope, { root, library }, kind);
|
|
342
|
-
const content = await readLayer(kind, from, directory);
|
|
343
|
-
if (content === void 0) fail("NOT_FOUND", `No ${kind} entry '${from}' in the ${scope}`);
|
|
344
|
-
if (await readLayer(kind, to, directory) !== void 0) fail("REVISION_CONFLICT", `${kind} '${to}' already exists in the ${scope}`);
|
|
345
|
-
const users = await usersOf(kind, from, { root, library, templates });
|
|
346
|
-
if (users.length) fail("IN_USE", `${kind} '${from}' is used by ${users.join(", ")}; change them first`);
|
|
347
|
-
await check(kind, to, content, { scope, root, library, templates });
|
|
348
|
-
if (ownDirectory(kind)) {
|
|
349
|
-
if (await exists(path.join(directory, kind, to))) fail("REVISION_CONFLICT", `${path.join(directory, kind, to)} already exists`);
|
|
350
|
-
await rename(path.join(directory, kind, from), path.join(directory, kind, to));
|
|
351
|
-
} else {
|
|
352
|
-
await rename(path.join(directory, kind, `${from}.json`), path.join(directory, kind, `${to}.json`));
|
|
353
|
-
}
|
|
354
|
-
return { revision: revisionOf(await readLayer(kind, to, directory)) };
|
|
355
|
-
}
|
|
356
|
-
export {
|
|
357
|
-
EDIT_KINDS,
|
|
358
|
-
assertProjectDataContent,
|
|
359
|
-
deleteEntry,
|
|
360
|
-
duplicateEntry,
|
|
361
|
-
getEntry,
|
|
362
|
-
givenSkills,
|
|
363
|
-
listEntries,
|
|
364
|
-
renameEntry,
|
|
365
|
-
saveEntry,
|
|
366
|
-
setGivenSkills,
|
|
367
|
-
usersOf
|
|
368
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The user's library: skills, role assignments and default providers, kept in
|
|
3
|
-
* ALP_HOME and shared by every project. ALP seeds it from its templates once,
|
|
4
|
-
* then updates only files the user has not changed; a file the user edited or
|
|
5
|
-
* deleted stays that way across app updates.
|
|
6
|
-
*/
|
|
7
|
-
/** ALP_HOME, the user's ALP directory: alpd's home and the skill library. */
|
|
8
|
-
export function alpHome(env?: NodeJS.ProcessEnv): string;
|
|
9
|
-
/**
|
|
10
|
-
* Seeds or updates the library in `home`. A file is written when ALP never
|
|
11
|
-
* shipped it before, and replaced only while it still holds what ALP last wrote.
|
|
12
|
-
* @param {string} home
|
|
13
|
-
* @param {{ templateRoot?: URL, templates?: Record<string, string> }} [options]
|
|
14
|
-
*/
|
|
15
|
-
export function seedLibrary(home: string, options?: {
|
|
16
|
-
templateRoot?: URL;
|
|
17
|
-
templates?: Record<string, string>;
|
|
18
|
-
}): Promise<{
|
|
19
|
-
created: string[];
|
|
20
|
-
updated: string[];
|
|
21
|
-
}>;
|
|
22
|
-
/** Seeds a library once per process; sessions call it on every open. */
|
|
23
|
-
export function ensureLibrary(home: any, options?: {}): any;
|
|
24
|
-
/** The library skills assigned to an agent, as named absolute SKILL.md paths that exist. */
|
|
25
|
-
export function librarySkills(home: any, agent: any): Promise<{
|
|
26
|
-
name: any;
|
|
27
|
-
path: string;
|
|
28
|
-
}[]>;
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
// packages/core/src/library.js
|
|
2
|
-
import { shippedTemplateRoot } from "./template-path.js";
|
|
3
|
-
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
4
|
-
import { moveFile } from "./atomic.js";
|
|
5
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
6
|
-
import os from "node:os";
|
|
7
|
-
import path from "node:path";
|
|
8
|
-
import { AlpError } from "./errors.js";
|
|
9
|
-
function alpHome(env = process.env) {
|
|
10
|
-
return path.resolve(env.ALP_HOME || path.join(os.homedir(), ".alp"));
|
|
11
|
-
}
|
|
12
|
-
var MANIFEST = "library.json";
|
|
13
|
-
var sha = (text) => createHash("sha256").update(text.replaceAll("\r\n", "\n")).digest("hex");
|
|
14
|
-
async function optional(file) {
|
|
15
|
-
try {
|
|
16
|
-
return await readFile(file, "utf8");
|
|
17
|
-
} catch (error) {
|
|
18
|
-
if (error.code === "ENOENT") return void 0;
|
|
19
|
-
throw error;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
async function shippedFiles({ templateRoot, templates }) {
|
|
23
|
-
if (templates) return Object.fromEntries(Object.entries(templates).filter(([name]) => name === "role-skills.json" || name.startsWith("skills/") || name.startsWith("providers/")));
|
|
24
|
-
const root = templateRoot ?? shippedTemplateRoot();
|
|
25
|
-
const files = { "role-skills.json": await readFile(new URL("role-skills.json", root), "utf8") };
|
|
26
|
-
async function walk(relative) {
|
|
27
|
-
for (const entry of await readdir(new URL(`${relative}/`, root), { withFileTypes: true })) {
|
|
28
|
-
if (entry.isDirectory()) await walk(`${relative}/${entry.name}`);
|
|
29
|
-
else if (entry.isFile()) files[`${relative}/${entry.name}`] = await readFile(new URL(`${relative}/${entry.name}`, root), "utf8");
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
await walk("skills");
|
|
33
|
-
await walk("providers");
|
|
34
|
-
return files;
|
|
35
|
-
}
|
|
36
|
-
async function seedLibrary(home, options = {}) {
|
|
37
|
-
const shipped = await shippedFiles(options);
|
|
38
|
-
await mkdir(home, { recursive: true, mode: 448 });
|
|
39
|
-
const manifestPath = path.join(home, MANIFEST);
|
|
40
|
-
const manifestText = await optional(manifestPath);
|
|
41
|
-
const manifest = manifestText ? JSON.parse(manifestText) : { files: {} };
|
|
42
|
-
const created = [];
|
|
43
|
-
const updated = [];
|
|
44
|
-
for (const [name, content] of Object.entries(shipped).sort(([a], [b]) => a.localeCompare(b))) {
|
|
45
|
-
const target = path.join(home, ...name.split("/"));
|
|
46
|
-
const current = await optional(target);
|
|
47
|
-
const seeded = manifest.files[name];
|
|
48
|
-
if (seeded === void 0) {
|
|
49
|
-
if (current !== void 0) continue;
|
|
50
|
-
await mkdir(path.dirname(target), { recursive: true });
|
|
51
|
-
await writeFile(target, content, { flag: "wx" }).catch((error) => {
|
|
52
|
-
if (error.code !== "EEXIST") throw error;
|
|
53
|
-
});
|
|
54
|
-
manifest.files[name] = sha(content);
|
|
55
|
-
created.push(name);
|
|
56
|
-
} else if (current !== void 0 && sha(current) === seeded && seeded !== sha(content)) {
|
|
57
|
-
await writeFile(target, content);
|
|
58
|
-
manifest.files[name] = sha(content);
|
|
59
|
-
updated.push(name);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (created.length || updated.length || manifestText === void 0) {
|
|
63
|
-
await mkdir(home, { recursive: true });
|
|
64
|
-
const temporary = `${manifestPath}.${randomUUID().slice(0, 8)}.tmp`;
|
|
65
|
-
await writeFile(temporary, JSON.stringify(manifest, null, 2) + "\n");
|
|
66
|
-
await moveFile(temporary, manifestPath);
|
|
67
|
-
}
|
|
68
|
-
return { created, updated };
|
|
69
|
-
}
|
|
70
|
-
var seeding = /* @__PURE__ */ new Map();
|
|
71
|
-
function ensureLibrary(home, options = {}) {
|
|
72
|
-
let done = seeding.get(home);
|
|
73
|
-
if (!done) {
|
|
74
|
-
done = seedLibrary(home, options).catch((error) => {
|
|
75
|
-
seeding.delete(home);
|
|
76
|
-
throw error;
|
|
77
|
-
});
|
|
78
|
-
seeding.set(home, done);
|
|
79
|
-
}
|
|
80
|
-
return done;
|
|
81
|
-
}
|
|
82
|
-
var skillName = (name) => typeof name === "string" && /^[\w.-]+$/.test(name) && name !== "." && name !== "..";
|
|
83
|
-
async function librarySkills(home, agent) {
|
|
84
|
-
const file = path.join(home, "role-skills.json");
|
|
85
|
-
const text = await optional(file);
|
|
86
|
-
if (text === void 0) return [];
|
|
87
|
-
let roles;
|
|
88
|
-
try {
|
|
89
|
-
roles = JSON.parse(text);
|
|
90
|
-
} catch (cause) {
|
|
91
|
-
throw new AlpError("INVALID_LIBRARY", `${file}: ${cause.message}`, { cause });
|
|
92
|
-
}
|
|
93
|
-
if (!roles || typeof roles !== "object" || Array.isArray(roles)) throw new AlpError("INVALID_LIBRARY", `${file}: expected an object of role names to skill lists`);
|
|
94
|
-
const names = roles[agent] ?? [];
|
|
95
|
-
if (!Array.isArray(names) || !names.every(skillName)) throw new AlpError("INVALID_LIBRARY", `${file}: ${agent} must list skill directory names`);
|
|
96
|
-
const skills = [];
|
|
97
|
-
for (const name of new Set(names)) {
|
|
98
|
-
const skillPath = path.join(home, "skills", name, "SKILL.md");
|
|
99
|
-
if (await optional(skillPath) !== void 0) skills.push({ name, path: skillPath });
|
|
100
|
-
}
|
|
101
|
-
return skills;
|
|
102
|
-
}
|
|
103
|
-
export {
|
|
104
|
-
alpHome,
|
|
105
|
-
ensureLibrary,
|
|
106
|
-
librarySkills,
|
|
107
|
-
seedLibrary
|
|
108
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
2
|
-
export const LEVELS: Readonly<Record<LogLevel, number>>;
|
|
3
|
-
export const REDACTED: string;
|
|
4
|
-
export const OMITTED: string;
|
|
5
|
-
export type LogFields = {
|
|
6
|
-
code?: string;
|
|
7
|
-
error?: unknown;
|
|
8
|
-
sessionId?: string;
|
|
9
|
-
rootId?: string;
|
|
10
|
-
assignmentId?: string;
|
|
11
|
-
clientMessageId?: string;
|
|
12
|
-
requestId?: string;
|
|
13
|
-
agent?: string;
|
|
14
|
-
[key: string]: unknown;
|
|
15
|
-
};
|
|
16
|
-
export type LogRecord = {
|
|
17
|
-
time: string;
|
|
18
|
-
level: LogLevel;
|
|
19
|
-
component: string;
|
|
20
|
-
code?: string;
|
|
21
|
-
msg: string;
|
|
22
|
-
error?: { name?: string; code?: string | number; message: string; stack?: string; cause?: unknown };
|
|
23
|
-
[key: string]: unknown;
|
|
24
|
-
};
|
|
25
|
-
export type Logger = {
|
|
26
|
-
component: string;
|
|
27
|
-
debug(message: string, fields?: LogFields): void;
|
|
28
|
-
info(message: string, fields?: LogFields): void;
|
|
29
|
-
warn(message: string, fields?: LogFields): void;
|
|
30
|
-
error(message: string, fields?: LogFields): void;
|
|
31
|
-
child(extra?: LogFields, component?: string): Logger;
|
|
32
|
-
};
|
|
33
|
-
export function scrubText(text: unknown, options?: { env?: Record<string, string | undefined>; max?: number }): string;
|
|
34
|
-
export function describeError(error: unknown, options?: { env?: Record<string, string | undefined> }): { name?: string; code?: string | number; message: string; stack?: string; cause?: unknown };
|
|
35
|
-
export function redact(value: unknown, options?: { env?: Record<string, string | undefined> }): any;
|
|
36
|
-
export function createLogger(options: { component: string; level?: LogLevel; context?: LogFields; write?: (line: string) => void; now?: () => Date; env?: Record<string, string | undefined> }): Logger;
|
|
37
|
-
export function readLogTail(file: string, options?: { bytes?: number; env?: Record<string, string | undefined> }): Promise<Array<LogRecord | { legacy: string }>>;
|