@litfamily/litopencode 1.0.1 → 1.0.2
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 +7 -0
- package/README-Ko-KR.md +8 -7
- package/README.md +8 -7
- package/dist/activation-prompt-utils.d.ts +1 -1
- package/dist/activation-routing.d.ts +1 -1
- package/dist/activation-routing.js +1 -8
- package/dist/activation-workflow-prompts.d.ts +0 -1
- package/dist/activation-workflow-prompts.js +0 -8
- package/dist/activation.d.ts +1 -1
- package/dist/activation.js +1 -1
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.js +1 -31
- package/dist/cli/loop.js +0 -19
- package/dist/cli/managed-skill-assets.d.ts +1 -1
- package/dist/cli/managed-skill-assets.js +0 -2
- package/dist/cli/types.d.ts +0 -4
- package/dist/cli.js +0 -14
- package/dist/commands.d.ts +1 -10
- package/dist/commands.js +1 -11
- package/dist/features.d.ts +1 -22
- package/dist/features.js +0 -43
- package/dist/hooks.js +0 -13
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -5
- package/dist/skills.d.ts +1 -8
- package/dist/skills.js +0 -13
- package/docs/assets/cover-motion.webp +0 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/privacy.md +2 -2
- package/docs/reference.md +5 -48
- package/package.json +2 -1
- package/skills/frontend-ui-ux/references/complete-contract.md +1 -1
- package/skills/lit-plan/SKILL.md +1 -1
- package/skills/managed-skill-manifest.json +2 -9
- package/skills/visual-qa/references/complete-contract.md +1 -1
- package/tools/check-payload-substance.mjs +74 -27
- package/tools/payload-substance-parity.json +10 -25
- package/tools/version-manifests.json +2 -2
- package/dist/cli/skill-loop.d.ts +0 -3
- package/dist/cli/skill-loop.js +0 -649
- package/dist/skill-loop/apply.d.ts +0 -19
- package/dist/skill-loop/apply.js +0 -483
- package/dist/skill-loop/config.d.ts +0 -50
- package/dist/skill-loop/config.js +0 -215
- package/dist/skill-loop/curator.d.ts +0 -18
- package/dist/skill-loop/curator.js +0 -232
- package/dist/skill-loop/ledger.d.ts +0 -39
- package/dist/skill-loop/ledger.js +0 -344
- package/dist/skill-loop/proposals.d.ts +0 -48
- package/dist/skill-loop/proposals.js +0 -290
- package/dist/skill-loop/storage.d.ts +0 -72
- package/dist/skill-loop/storage.js +0 -817
- package/dist/skill-loop/time.d.ts +0 -2
- package/dist/skill-loop/time.js +0 -23
- package/dist/skill-loop/transaction.d.ts +0 -62
- package/dist/skill-loop/transaction.js +0 -836
- package/dist/skill-loop/usage.d.ts +0 -31
- package/dist/skill-loop/usage.js +0 -146
- package/dist/skill-observer.d.ts +0 -22
- package/dist/skill-observer.js +0 -1154
- package/skills/skill-observer/SKILL.md +0 -148
- package/skills/skill-observer/references/review-contract.md +0 -95
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { containsIngressSecret } from "../secret-shapes.js";
|
|
4
|
-
import { decodeStrictUtf8, parseStrictJson } from "../strict-json.js";
|
|
5
|
-
import { resolveSkillLoopPaths, skillLoopPaths, writeJsonAtomically } from "./config.js";
|
|
6
|
-
import { assertSafeRuntimeFileForWrite, assertSkillLoopLockCapability, ensureSafeRuntimeDirectory, readSafeRuntimeFile, withSkillLoopMutationLock } from "./storage.js";
|
|
7
|
-
import { isStrictRfc3339 } from "./time.js";
|
|
8
|
-
export class SkillProposalError extends Error {
|
|
9
|
-
code;
|
|
10
|
-
constructor(code, message = code) {
|
|
11
|
-
super(message);
|
|
12
|
-
this.name = "SkillProposalError";
|
|
13
|
-
this.code = code;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export const proposalLimit = 64 * 1024;
|
|
17
|
-
const idPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
|
|
18
|
-
const skillPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
|
|
19
|
-
const portableDevice = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/iu;
|
|
20
|
-
const portableForbidden = /[\\:*?"<>|\u0000-\u001f\u007f-\u009f]/u;
|
|
21
|
-
function isRecord(value) {
|
|
22
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23
|
-
}
|
|
24
|
-
function exactKeys(value, allowed) {
|
|
25
|
-
const set = new Set(allowed);
|
|
26
|
-
if (Object.keys(value).some((key) => !set.has(key)))
|
|
27
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
28
|
-
}
|
|
29
|
-
function requiredString(value, max, pattern) {
|
|
30
|
-
if (typeof value !== "string" || value.length === 0 || value.length > max || (pattern && !pattern.test(value))) {
|
|
31
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
32
|
-
}
|
|
33
|
-
return value;
|
|
34
|
-
}
|
|
35
|
-
function validTimestamp(value) {
|
|
36
|
-
const text = requiredString(value, 64);
|
|
37
|
-
if (!isStrictRfc3339(text))
|
|
38
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
39
|
-
return text;
|
|
40
|
-
}
|
|
41
|
-
export function canonicalRelativeIdentity(file) {
|
|
42
|
-
return file.split("/").map((segment) => segment.normalize("NFKC").toLocaleLowerCase("en-US").replace(/[. ]+$/u, "")).join("/");
|
|
43
|
-
}
|
|
44
|
-
export function assertPortableRelativeFile(file, targetSkill) {
|
|
45
|
-
const text = requiredString(file, 1024);
|
|
46
|
-
if (path.posix.isAbsolute(text) || /^[A-Za-z]:/u.test(text) || text.startsWith("//") || portableForbidden.test(text) ||
|
|
47
|
-
text.includes("//") || text.split("/").some((part) => part === "" || part === "." || part === ".." || /[. ]$/u.test(part) || portableDevice.test(part))) {
|
|
48
|
-
throw new SkillProposalError("PROPOSAL_PATH_INVALID");
|
|
49
|
-
}
|
|
50
|
-
const identity = canonicalRelativeIdentity(text);
|
|
51
|
-
if (targetSkill !== undefined) {
|
|
52
|
-
const targetIdentity = canonicalRelativeIdentity(targetSkill);
|
|
53
|
-
if (identity === targetIdentity || identity.startsWith(`${targetIdentity}/`)) {
|
|
54
|
-
throw new SkillProposalError("PROPOSAL_PATH_INVALID");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return text;
|
|
58
|
-
}
|
|
59
|
-
function assertNoSecrets(value) {
|
|
60
|
-
if (typeof value === "string") {
|
|
61
|
-
if (containsIngressSecret(value))
|
|
62
|
-
throw new SkillProposalError("PROPOSAL_SECRET_REFUSED");
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (Array.isArray(value)) {
|
|
66
|
-
for (const entry of value)
|
|
67
|
-
assertNoSecrets(entry);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
if (isRecord(value))
|
|
71
|
-
for (const entry of Object.values(value))
|
|
72
|
-
assertNoSecrets(entry);
|
|
73
|
-
}
|
|
74
|
-
export function parseSkillProposal(value, expectedSkillsRoot) {
|
|
75
|
-
if (!isRecord(value))
|
|
76
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
77
|
-
exactKeys(value, ["schema", "id", "createdAt", "host", "sessionRef", "signal", "targetSkill", "targetRoot", "action", "patch", "createSpec", "rationale", "evidenceRefs", "status", "ledgerEntryId"]);
|
|
78
|
-
assertNoSecrets(value);
|
|
79
|
-
if (value.schema !== "litfamily.skill-proposal/v1" || value.host !== "litopencode") {
|
|
80
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
81
|
-
}
|
|
82
|
-
const targetSkill = requiredString(value.targetSkill, 128, skillPattern);
|
|
83
|
-
try {
|
|
84
|
-
if (assertPortableRelativeFile(targetSkill) !== targetSkill || targetSkill.includes("/"))
|
|
85
|
-
throw new Error("invalid");
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
throw new SkillProposalError("PROPOSAL_PATH_INVALID");
|
|
89
|
-
}
|
|
90
|
-
const status = value.status;
|
|
91
|
-
if (status !== "pending" && status !== "approved" && status !== "applied" && status !== "rejected" && status !== "rolled-back") {
|
|
92
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
93
|
-
}
|
|
94
|
-
const action = value.action;
|
|
95
|
-
if (action !== "patch" && action !== "create" && action !== "add-reference" && action !== "archive") {
|
|
96
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
97
|
-
}
|
|
98
|
-
const targetRootInput = requiredString(value.targetRoot, 2048);
|
|
99
|
-
const targetRoot = targetRootInput === "$OPENCODE_SKILLS_ROOT" && expectedSkillsRoot !== undefined
|
|
100
|
-
? path.resolve(expectedSkillsRoot)
|
|
101
|
-
: path.resolve(targetRootInput);
|
|
102
|
-
if (expectedSkillsRoot !== undefined && targetRoot !== path.resolve(expectedSkillsRoot)) {
|
|
103
|
-
throw new SkillProposalError("PROPOSAL_TARGET_ROOT_MISMATCH");
|
|
104
|
-
}
|
|
105
|
-
let patch;
|
|
106
|
-
let createSpec;
|
|
107
|
-
if (action === "patch") {
|
|
108
|
-
if (!isRecord(value.patch) || value.createSpec !== undefined)
|
|
109
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
110
|
-
exactKeys(value.patch, ["file", "oldString", "newString"]);
|
|
111
|
-
patch = {
|
|
112
|
-
file: assertPortableRelativeFile(value.patch.file, targetSkill),
|
|
113
|
-
oldString: requiredString(value.patch.oldString, 65536),
|
|
114
|
-
newString: typeof value.patch.newString === "string" && value.patch.newString.length <= 65536
|
|
115
|
-
? value.patch.newString
|
|
116
|
-
: (() => { throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID"); })()
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
else if (action === "create" || action === "add-reference") {
|
|
120
|
-
if (!isRecord(value.createSpec) || value.patch !== undefined)
|
|
121
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
122
|
-
exactKeys(value.createSpec, ["files"]);
|
|
123
|
-
if (!Array.isArray(value.createSpec.files) || value.createSpec.files.length < 1 || value.createSpec.files.length > 64) {
|
|
124
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
125
|
-
}
|
|
126
|
-
const identities = new Set();
|
|
127
|
-
const files = value.createSpec.files.map((entry) => {
|
|
128
|
-
if (!isRecord(entry))
|
|
129
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
130
|
-
exactKeys(entry, ["file", "content"]);
|
|
131
|
-
const file = assertPortableRelativeFile(entry.file, targetSkill);
|
|
132
|
-
const identity = canonicalRelativeIdentity(file);
|
|
133
|
-
if (identities.has(identity))
|
|
134
|
-
throw new SkillProposalError("PROPOSAL_PATH_INVALID");
|
|
135
|
-
identities.add(identity);
|
|
136
|
-
if (typeof entry.content !== "string" || entry.content.length > 65536)
|
|
137
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
138
|
-
return { file, content: entry.content };
|
|
139
|
-
});
|
|
140
|
-
createSpec = { files };
|
|
141
|
-
}
|
|
142
|
-
else if (value.patch !== undefined || value.createSpec !== undefined) {
|
|
143
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
144
|
-
}
|
|
145
|
-
const evidenceRefs = value.evidenceRefs;
|
|
146
|
-
if (!Array.isArray(evidenceRefs) || evidenceRefs.length > 32 || evidenceRefs.some((entry) => typeof entry !== "string" || entry.length < 1 || entry.length > 2048) || new Set(evidenceRefs).size !== evidenceRefs.length) {
|
|
147
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
148
|
-
}
|
|
149
|
-
const ledgerEntryId = value.ledgerEntryId;
|
|
150
|
-
if ((status === "applied" || status === "rolled-back") !== (typeof ledgerEntryId === "string" && ledgerEntryId.length > 0 && ledgerEntryId.length <= 128)) {
|
|
151
|
-
throw new SkillProposalError("PROPOSAL_SCHEMA_INVALID");
|
|
152
|
-
}
|
|
153
|
-
if (typeof ledgerEntryId === "string") {
|
|
154
|
-
try {
|
|
155
|
-
if (!idPattern.test(ledgerEntryId) || assertPortableRelativeFile(ledgerEntryId) !== ledgerEntryId)
|
|
156
|
-
throw new Error("invalid");
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
throw new SkillProposalError("PROPOSAL_INTEGRITY_INVALID");
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return Object.freeze({
|
|
163
|
-
schema: "litfamily.skill-proposal/v1",
|
|
164
|
-
id: (() => {
|
|
165
|
-
const id = requiredString(value.id, 128, idPattern);
|
|
166
|
-
try {
|
|
167
|
-
if (assertPortableRelativeFile(id) !== id || id.includes("/"))
|
|
168
|
-
throw new Error("invalid");
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
throw new SkillProposalError("PROPOSAL_PATH_INVALID");
|
|
172
|
-
}
|
|
173
|
-
return id;
|
|
174
|
-
})(),
|
|
175
|
-
createdAt: validTimestamp(value.createdAt),
|
|
176
|
-
host: "litopencode",
|
|
177
|
-
sessionRef: requiredString(value.sessionRef, 512),
|
|
178
|
-
signal: requiredString(value.signal, 128),
|
|
179
|
-
targetSkill,
|
|
180
|
-
targetRoot,
|
|
181
|
-
action,
|
|
182
|
-
...(patch === undefined ? {} : { patch }),
|
|
183
|
-
...(createSpec === undefined ? {} : { createSpec }),
|
|
184
|
-
rationale: requiredString(value.rationale, 8192),
|
|
185
|
-
evidenceRefs: Object.freeze([...evidenceRefs]),
|
|
186
|
-
status,
|
|
187
|
-
...(typeof ledgerEntryId === "string" ? { ledgerEntryId } : {})
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
export async function enqueueProposal(value, projectRoot, configRoot, options = {}) {
|
|
191
|
-
if (options.capability === undefined) {
|
|
192
|
-
return withSkillLoopMutationLock(projectRoot, (capability) => enqueueProposal(value, projectRoot, configRoot, { capability }));
|
|
193
|
-
}
|
|
194
|
-
assertSkillLoopLockCapability(options.capability, projectRoot);
|
|
195
|
-
const paths = await resolveSkillLoopPaths(projectRoot, configRoot ?? skillLoopPaths(projectRoot).configRoot);
|
|
196
|
-
const proposal = parseSkillProposal(value, paths.skillsRoot);
|
|
197
|
-
if (Buffer.byteLength(JSON.stringify(proposal), "utf8") > proposalLimit)
|
|
198
|
-
throw new SkillProposalError("PROPOSAL_TOO_LARGE");
|
|
199
|
-
if (proposal.status !== "pending")
|
|
200
|
-
throw new SkillProposalError("PROPOSAL_STATUS_INVALID");
|
|
201
|
-
const file = path.join(paths.proposalsDir, `${proposal.id}.json`);
|
|
202
|
-
await ensureSafeRuntimeDirectory(projectRoot, paths.proposalsDir);
|
|
203
|
-
await assertSafeRuntimeFileForWrite(projectRoot, file);
|
|
204
|
-
try {
|
|
205
|
-
await fs.lstat(file);
|
|
206
|
-
throw new SkillProposalError("PROPOSAL_ALREADY_EXISTS");
|
|
207
|
-
}
|
|
208
|
-
catch (error) {
|
|
209
|
-
if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
|
|
210
|
-
throw error;
|
|
211
|
-
}
|
|
212
|
-
await writeJsonAtomically(projectRoot, file, proposal, options.capability);
|
|
213
|
-
return proposal;
|
|
214
|
-
}
|
|
215
|
-
export async function proposeFromFile(file, projectRoot, configRoot) {
|
|
216
|
-
const bytes = await fs.readFile(path.resolve(file));
|
|
217
|
-
if (bytes.byteLength > proposalLimit)
|
|
218
|
-
throw new SkillProposalError("PROPOSAL_TOO_LARGE");
|
|
219
|
-
return enqueueProposal(parseStrictJson(decodeStrictUtf8(bytes)), projectRoot, configRoot);
|
|
220
|
-
}
|
|
221
|
-
export async function readProposal(id, projectRoot, configRoot) {
|
|
222
|
-
if (!idPattern.test(id))
|
|
223
|
-
throw new SkillProposalError("PROPOSAL_ID_INVALID");
|
|
224
|
-
const paths = await resolveSkillLoopPaths(projectRoot, configRoot ?? skillLoopPaths(projectRoot).configRoot);
|
|
225
|
-
const bytes = await readSafeRuntimeFile(projectRoot, path.join(paths.proposalsDir, `${id}.json`), { maxBytes: proposalLimit });
|
|
226
|
-
if (bytes === undefined)
|
|
227
|
-
throw new SkillProposalError("PROPOSAL_NOT_FOUND");
|
|
228
|
-
const proposal = parseSkillProposal(parseStrictJson(decodeStrictUtf8(bytes)), paths.skillsRoot);
|
|
229
|
-
if (proposal.id !== id)
|
|
230
|
-
throw new SkillProposalError("PROPOSAL_INTEGRITY_INVALID");
|
|
231
|
-
return proposal;
|
|
232
|
-
}
|
|
233
|
-
async function readProposalDirectory(directory) {
|
|
234
|
-
return fs.readdir(directory, { withFileTypes: true, encoding: "utf8" });
|
|
235
|
-
}
|
|
236
|
-
export async function listProposals(projectRoot, configRoot) {
|
|
237
|
-
const paths = await resolveSkillLoopPaths(projectRoot, configRoot ?? skillLoopPaths(projectRoot).configRoot);
|
|
238
|
-
try {
|
|
239
|
-
const stat = await fs.lstat(paths.proposalsDir);
|
|
240
|
-
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
241
|
-
throw new SkillProposalError("PROPOSAL_INTEGRITY_INVALID");
|
|
242
|
-
}
|
|
243
|
-
catch (error) {
|
|
244
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
245
|
-
return [];
|
|
246
|
-
throw error;
|
|
247
|
-
}
|
|
248
|
-
let entries;
|
|
249
|
-
try {
|
|
250
|
-
entries = await readProposalDirectory(paths.proposalsDir);
|
|
251
|
-
}
|
|
252
|
-
catch (error) {
|
|
253
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
254
|
-
return [];
|
|
255
|
-
throw error;
|
|
256
|
-
}
|
|
257
|
-
const records = [];
|
|
258
|
-
const identities = new Set();
|
|
259
|
-
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
260
|
-
if (entry.isSymbolicLink() || !entry.isFile() || !entry.name.endsWith(".json"))
|
|
261
|
-
throw new SkillProposalError("PROPOSAL_INTEGRITY_INVALID");
|
|
262
|
-
const fileId = entry.name.slice(0, -".json".length);
|
|
263
|
-
const bytes = await readSafeRuntimeFile(projectRoot, path.join(paths.proposalsDir, entry.name), { allowMissing: false, maxBytes: proposalLimit });
|
|
264
|
-
const record = parseSkillProposal(parseStrictJson(decodeStrictUtf8(bytes)), paths.skillsRoot);
|
|
265
|
-
if (record.id !== fileId)
|
|
266
|
-
throw new SkillProposalError("PROPOSAL_INTEGRITY_INVALID");
|
|
267
|
-
const identity = canonicalRelativeIdentity(record.id);
|
|
268
|
-
if (identities.has(identity))
|
|
269
|
-
throw new SkillProposalError("PROPOSAL_INTEGRITY_INVALID");
|
|
270
|
-
identities.add(identity);
|
|
271
|
-
records.push(record);
|
|
272
|
-
}
|
|
273
|
-
return Object.freeze(records);
|
|
274
|
-
}
|
|
275
|
-
export async function updateProposal(proposal, updates, projectRoot, configRoot, options = {}) {
|
|
276
|
-
if (options.capability === undefined) {
|
|
277
|
-
return withSkillLoopMutationLock(projectRoot, (capability) => updateProposal(proposal, updates, projectRoot, configRoot, { capability }));
|
|
278
|
-
}
|
|
279
|
-
assertSkillLoopLockCapability(options.capability, projectRoot);
|
|
280
|
-
const paths = await resolveSkillLoopPaths(projectRoot, configRoot ?? skillLoopPaths(projectRoot).configRoot);
|
|
281
|
-
const current = await readProposal(proposal.id, projectRoot, configRoot);
|
|
282
|
-
if (current.status !== proposal.status || current.ledgerEntryId !== proposal.ledgerEntryId)
|
|
283
|
-
throw new SkillProposalError("PROPOSAL_CONFLICT");
|
|
284
|
-
const next = { ...proposal, ...updates };
|
|
285
|
-
if (updates.ledgerEntryId === undefined && Object.hasOwn(updates, "ledgerEntryId"))
|
|
286
|
-
delete next.ledgerEntryId;
|
|
287
|
-
const parsed = parseSkillProposal(next, paths.skillsRoot);
|
|
288
|
-
await writeJsonAtomically(projectRoot, path.join(paths.proposalsDir, `${proposal.id}.json`), parsed, options.capability);
|
|
289
|
-
return parsed;
|
|
290
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
declare const capabilityBrand: unique symbol;
|
|
2
|
-
export type PhysicalDirectoryPin = {
|
|
3
|
-
readonly lexical: string;
|
|
4
|
-
readonly physical: string;
|
|
5
|
-
readonly dev: number;
|
|
6
|
-
readonly ino: number;
|
|
7
|
-
readonly ctimeMs: number;
|
|
8
|
-
readonly birthtimeMs: number;
|
|
9
|
-
};
|
|
10
|
-
export type PhysicalSkillLoopRoots = {
|
|
11
|
-
readonly project: PhysicalDirectoryPin;
|
|
12
|
-
readonly config: PhysicalDirectoryPin;
|
|
13
|
-
readonly skills: PhysicalDirectoryPin;
|
|
14
|
-
};
|
|
15
|
-
export type SkillLoopLockCapability = {
|
|
16
|
-
readonly [capabilityBrand]: true;
|
|
17
|
-
};
|
|
18
|
-
export declare function pinPhysicalDirectory(directory: string, create?: boolean): Promise<PhysicalDirectoryPin>;
|
|
19
|
-
export declare function pinPhysicalDirectoryIfPresent(directory: string): Promise<PhysicalDirectoryPin | undefined>;
|
|
20
|
-
export declare function canonicalPhysicalPath(target: string): Promise<string>;
|
|
21
|
-
export declare function assertPhysicalDirectoryPin(pin: PhysicalDirectoryPin): Promise<void>;
|
|
22
|
-
export declare function pinPhysicalSkillLoopRoots(projectRoot: string, configRoot: string): Promise<PhysicalSkillLoopRoots>;
|
|
23
|
-
export declare function ensureSafeRuntimeDirectory(projectRoot: string, directory: string): Promise<void>;
|
|
24
|
-
export declare function assertSafeRuntimeFileForWrite(projectRoot: string, file: string): Promise<void>;
|
|
25
|
-
export declare function readSafeRuntimeFile(projectRoot: string, file: string, options?: {
|
|
26
|
-
readonly allowMissing?: boolean;
|
|
27
|
-
readonly maxBytes?: number;
|
|
28
|
-
}): Promise<Buffer | undefined>;
|
|
29
|
-
export declare function writeSafeRuntimeFile(projectRoot: string, file: string, bytes: Uint8Array): Promise<void>;
|
|
30
|
-
export declare function removeSafeRuntimeFile(projectRoot: string, file: string): Promise<void>;
|
|
31
|
-
export declare function syncDirectory(directory: string): Promise<void>;
|
|
32
|
-
export declare function anchoredRenameInSkillsRoot(capability: SkillLoopLockCapability, source: string, destination: string): Promise<void>;
|
|
33
|
-
export declare function anchoredRemoveFromSkillsRoot(capability: SkillLoopLockCapability, target: string): Promise<void>;
|
|
34
|
-
export declare function anchoredCopyIntoSkillsRoot(capability: SkillLoopLockCapability, source: string, destination: string, files: readonly {
|
|
35
|
-
readonly file: string;
|
|
36
|
-
readonly blob: {
|
|
37
|
-
readonly digest: string;
|
|
38
|
-
readonly size: number;
|
|
39
|
-
};
|
|
40
|
-
}[]): Promise<void>;
|
|
41
|
-
export declare function anchoredVerifySkillTree(capability: SkillLoopLockCapability, target: string, files: readonly {
|
|
42
|
-
readonly file: string;
|
|
43
|
-
readonly blob: {
|
|
44
|
-
readonly digest: string;
|
|
45
|
-
readonly size: number;
|
|
46
|
-
};
|
|
47
|
-
}[]): Promise<void>;
|
|
48
|
-
export declare function anchoredAssertSkillPathAbsent(capability: SkillLoopLockCapability, target: string): Promise<void>;
|
|
49
|
-
export declare function anchoredReadFileFromSkillsRoot(capability: SkillLoopLockCapability, target: string, maxBytes: number): Promise<{
|
|
50
|
-
readonly bytes: Buffer;
|
|
51
|
-
readonly dev: number;
|
|
52
|
-
readonly ino: number;
|
|
53
|
-
readonly ctimeMs: number;
|
|
54
|
-
readonly birthtimeMs: number;
|
|
55
|
-
} | undefined>;
|
|
56
|
-
export declare function anchoredWriteFileToSkillsRoot(capability: SkillLoopLockCapability, target: string, bytes: Uint8Array, expected: {
|
|
57
|
-
readonly dev: number;
|
|
58
|
-
readonly ino: number;
|
|
59
|
-
readonly ctimeMs: number;
|
|
60
|
-
readonly birthtimeMs: number;
|
|
61
|
-
} | null): Promise<void>;
|
|
62
|
-
type ProcessProbe = (command: string, args: readonly string[]) => {
|
|
63
|
-
readonly status: number | null;
|
|
64
|
-
readonly stdout: string;
|
|
65
|
-
};
|
|
66
|
-
export declare function processBirthIdentityForPlatform(pid: number, platform: NodeJS.Platform, probe?: ProcessProbe): string | undefined;
|
|
67
|
-
export declare function assertSkillLoopGlobalBoundarySupported(platform?: NodeJS.Platform): void;
|
|
68
|
-
export declare function assertSkillLoopLockCapability(capability: unknown, projectRoot: string, skillsRoot?: string): asserts capability is SkillLoopLockCapability;
|
|
69
|
-
export declare function assertSkillLoopRootPins(capability: SkillLoopLockCapability): Promise<void>;
|
|
70
|
-
export declare function withSkillLoopMutationLock<T>(projectRoot: string, run: (capability: SkillLoopLockCapability) => Promise<T>): Promise<T>;
|
|
71
|
-
export declare function withSkillRootsMutationLock<T>(projectRoot: string, configRoot: string, run: (capability: SkillLoopLockCapability, roots: PhysicalSkillLoopRoots) => Promise<T>): Promise<T>;
|
|
72
|
-
export {};
|