@litfamily/litopencode 1.0.0 → 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.
Files changed (64) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README-Ko-KR.md +8 -7
  3. package/README.md +8 -7
  4. package/dist/activation-prompt-utils.d.ts +1 -1
  5. package/dist/activation-routing.d.ts +1 -1
  6. package/dist/activation-routing.js +1 -8
  7. package/dist/activation-workflow-prompts.d.ts +0 -1
  8. package/dist/activation-workflow-prompts.js +0 -8
  9. package/dist/activation.d.ts +1 -1
  10. package/dist/activation.js +1 -1
  11. package/dist/cli/args.d.ts +1 -1
  12. package/dist/cli/args.js +1 -31
  13. package/dist/cli/loop.js +0 -19
  14. package/dist/cli/managed-skill-assets.d.ts +1 -1
  15. package/dist/cli/managed-skill-assets.js +0 -2
  16. package/dist/cli/types.d.ts +0 -4
  17. package/dist/cli.js +0 -14
  18. package/dist/commands.d.ts +1 -10
  19. package/dist/commands.js +1 -11
  20. package/dist/features.d.ts +1 -22
  21. package/dist/features.js +0 -43
  22. package/dist/hooks.js +0 -13
  23. package/dist/index.d.ts +0 -5
  24. package/dist/index.js +0 -5
  25. package/dist/skills.d.ts +1 -8
  26. package/dist/skills.js +0 -13
  27. package/dist/tool-kit.d.ts +13 -16
  28. package/dist/tool-kit.js +8 -39
  29. package/docs/assets/cover-motion.webp +0 -0
  30. package/docs/assets/readme/badge-version.svg +1 -1
  31. package/docs/privacy.md +2 -2
  32. package/docs/reference.md +5 -48
  33. package/package.json +5 -3
  34. package/skills/frontend-ui-ux/references/complete-contract.md +1 -1
  35. package/skills/lit-plan/SKILL.md +1 -1
  36. package/skills/managed-skill-manifest.json +2 -9
  37. package/skills/visual-qa/references/complete-contract.md +1 -1
  38. package/tools/check-payload-substance.mjs +74 -27
  39. package/tools/payload-substance-parity.json +10 -25
  40. package/tools/version-manifests.json +4 -4
  41. package/dist/cli/skill-loop.d.ts +0 -3
  42. package/dist/cli/skill-loop.js +0 -649
  43. package/dist/skill-loop/apply.d.ts +0 -19
  44. package/dist/skill-loop/apply.js +0 -483
  45. package/dist/skill-loop/config.d.ts +0 -50
  46. package/dist/skill-loop/config.js +0 -215
  47. package/dist/skill-loop/curator.d.ts +0 -18
  48. package/dist/skill-loop/curator.js +0 -232
  49. package/dist/skill-loop/ledger.d.ts +0 -39
  50. package/dist/skill-loop/ledger.js +0 -344
  51. package/dist/skill-loop/proposals.d.ts +0 -48
  52. package/dist/skill-loop/proposals.js +0 -290
  53. package/dist/skill-loop/storage.d.ts +0 -72
  54. package/dist/skill-loop/storage.js +0 -817
  55. package/dist/skill-loop/time.d.ts +0 -2
  56. package/dist/skill-loop/time.js +0 -23
  57. package/dist/skill-loop/transaction.d.ts +0 -62
  58. package/dist/skill-loop/transaction.js +0 -836
  59. package/dist/skill-loop/usage.d.ts +0 -31
  60. package/dist/skill-loop/usage.js +0 -146
  61. package/dist/skill-observer.d.ts +0 -22
  62. package/dist/skill-observer.js +0 -1154
  63. package/skills/skill-observer/SKILL.md +0 -148
  64. package/skills/skill-observer/references/review-contract.md +0 -95
@@ -1,344 +0,0 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import fs from "node:fs/promises";
3
- import path from "node:path";
4
- import { parseStrictJson } from "../strict-json.js";
5
- import { assertPathComponentsSafe, inventoryTree, lstatIfPresent } from "../cli/native-skill-tree.js";
6
- import { assertPortableRelativeFile, canonicalRelativeIdentity } from "./proposals.js";
7
- import { skillLoopPaths } from "./config.js";
8
- import { assertSafeRuntimeFileForWrite, assertSkillLoopLockCapability, ensureSafeRuntimeDirectory, readSafeRuntimeFile, syncDirectory, withSkillLoopMutationLock, writeSafeRuntimeFile } from "./storage.js";
9
- import { isStrictRfc3339 } from "./time.js";
10
- function digest(bytes) {
11
- return createHash("sha256").update(bytes).digest("hex");
12
- }
13
- function equalSnapshots(left, right) {
14
- return JSON.stringify(left) === JSON.stringify(right);
15
- }
16
- async function storeBlob(projectRoot, bytes) {
17
- const value = digest(bytes);
18
- const dir = skillLoopPaths(projectRoot).blobsDir;
19
- const file = path.join(dir, value);
20
- await ensureSafeRuntimeDirectory(projectRoot, dir);
21
- await assertSafeRuntimeFileForWrite(projectRoot, file);
22
- try {
23
- await writeSafeRuntimeFile(projectRoot, file, bytes);
24
- }
25
- catch (error) {
26
- if (!(error instanceof Error && error.message === "SKILL_LOOP_CONFLICT"))
27
- throw error;
28
- }
29
- const stored = await readSafeRuntimeFile(projectRoot, file, { allowMissing: false });
30
- if (stored === undefined || stored.byteLength !== bytes.byteLength || digest(stored) !== value)
31
- throw new Error("LEDGER_BLOB_CORRUPT");
32
- return { algorithm: "sha256", digest: value, size: bytes.byteLength };
33
- }
34
- export async function snapshotSkill(projectRoot, skillRoot) {
35
- const stat = await lstatIfPresent(skillRoot);
36
- if (stat === null)
37
- return [];
38
- if (stat.isSymbolicLink() || !stat.isDirectory())
39
- throw new Error("TARGET_PATH_UNSAFE");
40
- await assertPathComponentsSafe(path.dirname(skillRoot), skillRoot, "Skill snapshot");
41
- const inventory = await inventoryTree(skillRoot);
42
- if (inventory.unsafe.length > 0 || inventory.files.length > 256)
43
- throw new Error("TARGET_PATH_UNSAFE");
44
- const identities = new Set();
45
- const snapshot = [];
46
- for (const relative of inventory.files) {
47
- const file = assertPortableRelativeFile(relative);
48
- const identity = canonicalRelativeIdentity(file);
49
- if (identities.has(identity))
50
- throw new Error("TARGET_PATH_UNSAFE");
51
- identities.add(identity);
52
- const bytes = await fs.readFile(path.join(skillRoot, ...file.split("/")));
53
- snapshot.push({ file, blob: await storeBlob(projectRoot, bytes) });
54
- }
55
- return Object.freeze(snapshot.sort((a, b) => a.file.localeCompare(b.file)));
56
- }
57
- async function blobBytes(projectRoot, item) {
58
- const file = path.join(skillLoopPaths(projectRoot).blobsDir, item.blob.digest);
59
- let bytes;
60
- try {
61
- bytes = await readSafeRuntimeFile(projectRoot, file, { allowMissing: false });
62
- }
63
- catch (error) {
64
- if (error instanceof Error && (error.message === "SKILL_LOOP_PATH_UNSAFE" || "code" in error && error.code === "ENOENT")) {
65
- throw new Error("LEDGER_BLOB_CORRUPT");
66
- }
67
- throw error;
68
- }
69
- if (bytes === undefined)
70
- throw new Error("LEDGER_BLOB_CORRUPT");
71
- if (bytes.byteLength !== item.blob.size || digest(bytes) !== item.blob.digest)
72
- throw new Error("LEDGER_BLOB_CORRUPT");
73
- return bytes;
74
- }
75
- export async function readSnapshotFile(projectRoot, snapshot, relativeFile) {
76
- const identity = canonicalRelativeIdentity(assertPortableRelativeFile(relativeFile));
77
- const item = snapshot.find((candidate) => canonicalRelativeIdentity(candidate.file) === identity);
78
- return item === undefined ? undefined : blobBytes(projectRoot, item);
79
- }
80
- export async function assertSnapshotMatches(projectRoot, skillRoot, expected) {
81
- const actual = await snapshotSkill(projectRoot, skillRoot);
82
- if (!equalSnapshots(actual, expected))
83
- throw new Error("ROLLBACK_STATE_MISMATCH");
84
- }
85
- export async function restoreSnapshot(projectRoot, skillRoot, snapshot) {
86
- const parent = path.dirname(skillRoot);
87
- await fs.mkdir(parent, { recursive: true });
88
- await assertPathComponentsSafe(parent, skillRoot, "Skill restore");
89
- if (snapshot.length === 0) {
90
- await fs.rm(skillRoot, { recursive: true, force: true });
91
- return;
92
- }
93
- const stage = path.join(parent, `.${path.basename(skillRoot)}.${randomUUID()}.stage`);
94
- const backup = path.join(parent, `.${path.basename(skillRoot)}.${randomUUID()}.backup`);
95
- await fs.mkdir(stage, { mode: 0o700 });
96
- try {
97
- for (const item of snapshot) {
98
- const relative = assertPortableRelativeFile(item.file);
99
- const destination = path.join(stage, ...relative.split("/"));
100
- await fs.mkdir(path.dirname(destination), { recursive: true });
101
- await fs.writeFile(destination, await blobBytes(projectRoot, item), { mode: 0o600 });
102
- }
103
- const current = await lstatIfPresent(skillRoot);
104
- if (current !== null)
105
- await fs.rename(skillRoot, backup);
106
- try {
107
- await fs.rename(stage, skillRoot);
108
- }
109
- catch (error) {
110
- if (current !== null)
111
- await fs.rename(backup, skillRoot);
112
- throw error;
113
- }
114
- if (current !== null)
115
- await fs.rm(backup, { recursive: true, force: true });
116
- await syncDirectory(parent);
117
- }
118
- catch (error) {
119
- await fs.rm(stage, { recursive: true, force: true });
120
- throw error;
121
- }
122
- }
123
- function parseLedgerEntry(value) {
124
- if (typeof value !== "object" || value === null || Array.isArray(value))
125
- throw new Error("SKILL_LEDGER_INVALID");
126
- const record = value;
127
- const allowed = new Set(["schema", "id", "createdAt", "proposalId", "actor", "operation", "targetSkill", "targetRoot", "before", "after", "restoresLedgerEntryId", "reason"]);
128
- const timestamp = isStrictRfc3339(record.createdAt);
129
- const proposalId = record.proposalId;
130
- const operation = record.operation;
131
- const restores = record.restoresLedgerEntryId;
132
- if (Object.keys(record).some((key) => !allowed.has(key)) || record.schema !== "litfamily.skill-ledger/v1" ||
133
- typeof record.id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(record.id) || !timestamp ||
134
- (proposalId !== null && (typeof proposalId !== "string" || proposalId.length < 1 || proposalId.length > 128)) ||
135
- (record.actor !== "user" && record.actor !== "curator") ||
136
- (operation !== "apply" && operation !== "reject" && operation !== "rollback" && operation !== "curator-transition") ||
137
- typeof record.targetSkill !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(record.targetSkill) ||
138
- typeof record.targetRoot !== "string" || record.targetRoot.length < 1 || record.targetRoot.length > 2048 ||
139
- (record.reason !== undefined && (typeof record.reason !== "string" || record.reason.length > 8192)) ||
140
- ((operation === "rollback") !== (typeof restores === "string" && restores.length > 0 && restores.length <= 128)) ||
141
- ((operation === "apply" || operation === "reject") && (record.actor !== "user" || proposalId === null)) ||
142
- (operation === "rollback" && record.actor !== "user") ||
143
- (operation === "curator-transition" && (record.actor !== "curator" || proposalId !== null))) {
144
- throw new Error("SKILL_LEDGER_INVALID");
145
- }
146
- try {
147
- if (assertPortableRelativeFile(record.id) !== record.id || assertPortableRelativeFile(record.targetSkill) !== record.targetSkill ||
148
- !path.isAbsolute(record.targetRoot) ||
149
- (typeof proposalId === "string" && assertPortableRelativeFile(proposalId) !== proposalId) ||
150
- (typeof restores === "string" && assertPortableRelativeFile(restores) !== restores)) {
151
- throw new Error("invalid");
152
- }
153
- }
154
- catch {
155
- throw new Error("SKILL_LEDGER_INVALID");
156
- }
157
- return Object.freeze({
158
- schema: "litfamily.skill-ledger/v1",
159
- id: record.id,
160
- createdAt: record.createdAt,
161
- proposalId: proposalId,
162
- actor: record.actor,
163
- operation,
164
- targetSkill: record.targetSkill,
165
- targetRoot: record.targetRoot,
166
- before: parseSkillSnapshot(record.before),
167
- after: parseSkillSnapshot(record.after),
168
- ...(typeof restores === "string" ? { restoresLedgerEntryId: restores } : {}),
169
- ...(typeof record.reason === "string" ? { reason: record.reason } : {})
170
- });
171
- }
172
- export function parseSkillSnapshot(value) {
173
- if (!Array.isArray(value) || value.length > 256)
174
- throw new Error("SKILL_LEDGER_INVALID");
175
- const identities = new Set();
176
- const snapshot = value.map((item) => {
177
- if (typeof item !== "object" || item === null || Array.isArray(item) ||
178
- Object.keys(item).some((key) => key !== "file" && key !== "blob"))
179
- throw new Error("SKILL_LEDGER_INVALID");
180
- const source = item;
181
- let file;
182
- try {
183
- file = assertPortableRelativeFile(source.file);
184
- }
185
- catch {
186
- throw new Error("SKILL_LEDGER_INVALID");
187
- }
188
- const identity = canonicalRelativeIdentity(file);
189
- if (identities.has(identity))
190
- throw new Error("SKILL_LEDGER_INVALID");
191
- identities.add(identity);
192
- if (typeof source.blob !== "object" || source.blob === null || Array.isArray(source.blob) ||
193
- Object.keys(source.blob).some((key) => key !== "algorithm" && key !== "digest" && key !== "size")) {
194
- throw new Error("SKILL_LEDGER_INVALID");
195
- }
196
- const blob = source.blob;
197
- if (blob.algorithm !== "sha256" || typeof blob.digest !== "string" || !/^[a-f0-9]{64}$/u.test(blob.digest) ||
198
- !Number.isInteger(blob.size) || Number(blob.size) < 0)
199
- throw new Error("SKILL_LEDGER_INVALID");
200
- return Object.freeze({ file, blob: Object.freeze({ algorithm: "sha256", digest: blob.digest, size: Number(blob.size) }) });
201
- });
202
- return Object.freeze(snapshot);
203
- }
204
- export async function readSkillLedger(projectRoot) {
205
- const file = skillLoopPaths(projectRoot).ledgerFile;
206
- const bytes = await readSafeRuntimeFile(projectRoot, file, { maxBytes: 16 * 1024 * 1024 });
207
- if (bytes === undefined)
208
- return [];
209
- const raw = bytes.toString("utf8");
210
- const entries = raw.split("\n").filter((line) => line !== "").map((line) => parseLedgerEntry(parseStrictJson(line)));
211
- const ids = new Set();
212
- const restored = new Set();
213
- const proposalTransitions = new Set();
214
- const entriesById = new Map();
215
- for (const entry of entries) {
216
- if (ids.has(entry.id))
217
- throw new Error("SKILL_LEDGER_INVALID");
218
- if (entry.operation === "rollback") {
219
- if (entry.restoresLedgerEntryId === undefined || !ids.has(entry.restoresLedgerEntryId) || restored.has(entry.restoresLedgerEntryId)) {
220
- throw new Error("SKILL_LEDGER_INVALID");
221
- }
222
- restored.add(entry.restoresLedgerEntryId);
223
- const reference = entriesById.get(entry.restoresLedgerEntryId);
224
- if (reference === undefined || (reference.operation !== "apply" && reference.operation !== "curator-transition" && reference.operation !== "rollback") ||
225
- canonicalRelativeIdentity(entry.targetSkill) !== canonicalRelativeIdentity(reference.targetSkill) ||
226
- path.resolve(entry.targetRoot) !== path.resolve(reference.targetRoot) || entry.proposalId !== reference.proposalId ||
227
- !equalSnapshots(entry.before, reference.after) || !equalSnapshots(entry.after, reference.before)) {
228
- throw new Error("SKILL_LEDGER_INVALID");
229
- }
230
- }
231
- if ((entry.operation === "apply" || entry.operation === "reject") && entry.proposalId !== null) {
232
- if (proposalTransitions.has(entry.proposalId))
233
- throw new Error("SKILL_LEDGER_INVALID");
234
- proposalTransitions.add(entry.proposalId);
235
- }
236
- ids.add(entry.id);
237
- entriesById.set(entry.id, entry);
238
- for (const item of [...entry.before, ...entry.after])
239
- await blobBytes(projectRoot, item);
240
- }
241
- return Object.freeze(entries);
242
- }
243
- export function assertProposalLedgerIntegrity(proposals, entries) {
244
- const proposalsById = new Map(proposals.map((proposal) => [proposal.id, proposal]));
245
- const entriesById = new Map(entries.map((entry) => [entry.id, entry]));
246
- for (const entry of entries) {
247
- if ((entry.operation === "apply" || entry.operation === "reject") &&
248
- (entry.proposalId === null || !proposalsById.has(entry.proposalId)))
249
- throw new Error("PROPOSAL_INTEGRITY_INVALID");
250
- if ((entry.operation === "apply" || entry.operation === "reject") && entry.proposalId !== null) {
251
- const proposal = proposalsById.get(entry.proposalId);
252
- if (canonicalRelativeIdentity(entry.targetSkill) !== canonicalRelativeIdentity(proposal.targetSkill) ||
253
- path.resolve(entry.targetRoot) !== path.resolve(proposal.targetRoot))
254
- throw new Error("PROPOSAL_INTEGRITY_INVALID");
255
- }
256
- }
257
- for (const proposal of proposals) {
258
- const related = entries.filter((entry) => entry.proposalId === proposal.id);
259
- if (proposal.status === "pending" || proposal.status === "approved") {
260
- if (related.length !== 0)
261
- throw new Error("PROPOSAL_INTEGRITY_INVALID");
262
- continue;
263
- }
264
- if (proposal.status === "rejected") {
265
- if (related.length !== 1 || related[0]?.operation !== "reject")
266
- throw new Error("PROPOSAL_INTEGRITY_INVALID");
267
- continue;
268
- }
269
- let terminal = proposal.ledgerEntryId === undefined ? undefined : entriesById.get(proposal.ledgerEntryId);
270
- let rollbackDepth = 0;
271
- const visited = new Set();
272
- while (terminal?.operation === "rollback") {
273
- if (terminal.proposalId !== proposal.id || terminal.restoresLedgerEntryId === undefined || visited.has(terminal.id)) {
274
- throw new Error("PROPOSAL_INTEGRITY_INVALID");
275
- }
276
- visited.add(terminal.id);
277
- rollbackDepth += 1;
278
- terminal = entriesById.get(terminal.restoresLedgerEntryId);
279
- }
280
- if (terminal?.operation !== "apply" || terminal.proposalId !== proposal.id ||
281
- (proposal.status === "applied") !== (rollbackDepth % 2 === 0))
282
- throw new Error("PROPOSAL_INTEGRITY_INVALID");
283
- }
284
- }
285
- export async function appendSkillLedger(projectRoot, entry, now = new Date().toISOString(), options = {}) {
286
- if (options.capability === undefined) {
287
- return withSkillLoopMutationLock(projectRoot, (capability) => appendSkillLedger(projectRoot, entry, now, { capability }));
288
- }
289
- assertSkillLoopLockCapability(options.capability, projectRoot);
290
- return (await appendSkillLedgerBatch(projectRoot, [entry], now, { capability: options.capability }))[0];
291
- }
292
- export async function appendSkillLedgerBatch(projectRoot, entries, now = new Date().toISOString(), options = {}) {
293
- if (options.capability === undefined) {
294
- return withSkillLoopMutationLock(projectRoot, (capability) => appendSkillLedgerBatch(projectRoot, entries, now, { capability }));
295
- }
296
- assertSkillLoopLockCapability(options.capability, projectRoot);
297
- if (entries.length === 0)
298
- return [];
299
- const file = skillLoopPaths(projectRoot).ledgerFile;
300
- const records = entries.map((entry) => ({
301
- schema: "litfamily.skill-ledger/v1",
302
- id: `ledger-${randomUUID()}`,
303
- createdAt: now,
304
- ...entry
305
- })).map(parseLedgerEntry);
306
- const existing = await readSkillLedger(projectRoot);
307
- const ids = new Set(existing.map((candidate) => candidate.id));
308
- const byId = new Map(existing.map((candidate) => [candidate.id, candidate]));
309
- const proposalIds = new Set(existing.flatMap((candidate) => candidate.proposalId === null ? [] : [candidate.proposalId]));
310
- const restored = new Set(existing.flatMap((candidate) => candidate.restoresLedgerEntryId === undefined ? [] : [candidate.restoresLedgerEntryId]));
311
- for (const parsed of records) {
312
- if (ids.has(parsed.id))
313
- throw new Error("SKILL_LEDGER_INVALID");
314
- if (parsed.operation === "rollback") {
315
- const reference = parsed.restoresLedgerEntryId === undefined ? undefined : byId.get(parsed.restoresLedgerEntryId);
316
- if (reference === undefined || restored.has(reference.id) ||
317
- (reference.operation !== "apply" && reference.operation !== "curator-transition" && reference.operation !== "rollback") ||
318
- canonicalRelativeIdentity(parsed.targetSkill) !== canonicalRelativeIdentity(reference.targetSkill) ||
319
- path.resolve(parsed.targetRoot) !== path.resolve(reference.targetRoot) || parsed.proposalId !== reference.proposalId ||
320
- !equalSnapshots(parsed.before, reference.after) || !equalSnapshots(parsed.after, reference.before)) {
321
- throw new Error("SKILL_LEDGER_INVALID");
322
- }
323
- }
324
- if ((parsed.operation === "apply" || parsed.operation === "reject") && parsed.proposalId !== null && proposalIds.has(parsed.proposalId)) {
325
- throw new Error("SKILL_LEDGER_INVALID");
326
- }
327
- ids.add(parsed.id);
328
- byId.set(parsed.id, parsed);
329
- if (parsed.restoresLedgerEntryId !== undefined)
330
- restored.add(parsed.restoresLedgerEntryId);
331
- if (parsed.proposalId !== null)
332
- proposalIds.add(parsed.proposalId);
333
- }
334
- const prior = await readSafeRuntimeFile(projectRoot, file) ?? Buffer.alloc(0);
335
- const appended = Buffer.from(records.map((record) => JSON.stringify(record)).join("\n") + "\n", "utf8");
336
- await writeSafeRuntimeFile(projectRoot, file, Buffer.concat([prior, appended]));
337
- return Object.freeze(records);
338
- }
339
- export async function findSkillLedgerEntry(projectRoot, id) {
340
- const entry = (await readSkillLedger(projectRoot)).find((candidate) => candidate.id === id);
341
- if (entry === undefined)
342
- throw new Error("LEDGER_ENTRY_NOT_FOUND");
343
- return entry;
344
- }
@@ -1,48 +0,0 @@
1
- import { type SkillLoopLockCapability } from "./storage.ts";
2
- export type ProposalStatus = "pending" | "approved" | "applied" | "rejected" | "rolled-back";
3
- export type ProposalAction = "patch" | "create" | "add-reference" | "archive";
4
- export type ProposalPatch = {
5
- readonly file: string;
6
- readonly oldString: string;
7
- readonly newString: string;
8
- };
9
- export type ProposalCreateSpec = {
10
- readonly files: readonly {
11
- readonly file: string;
12
- readonly content: string;
13
- }[];
14
- };
15
- export type SkillProposal = {
16
- readonly schema: "litfamily.skill-proposal/v1";
17
- readonly id: string;
18
- readonly createdAt: string;
19
- readonly host: "litopencode";
20
- readonly sessionRef: string;
21
- readonly signal: string;
22
- readonly targetSkill: string;
23
- readonly targetRoot: string;
24
- readonly action: ProposalAction;
25
- readonly patch?: ProposalPatch;
26
- readonly createSpec?: ProposalCreateSpec;
27
- readonly rationale: string;
28
- readonly evidenceRefs: readonly string[];
29
- readonly status: ProposalStatus;
30
- readonly ledgerEntryId?: string;
31
- };
32
- export declare class SkillProposalError extends Error {
33
- readonly code: string;
34
- constructor(code: string, message?: string);
35
- }
36
- export declare const proposalLimit: number;
37
- export declare function canonicalRelativeIdentity(file: string): string;
38
- export declare function assertPortableRelativeFile(file: unknown, targetSkill?: string): string;
39
- export declare function parseSkillProposal(value: unknown, expectedSkillsRoot?: string): SkillProposal;
40
- export declare function enqueueProposal(value: unknown, projectRoot: string, configRoot?: string, options?: {
41
- readonly capability?: SkillLoopLockCapability;
42
- }): Promise<SkillProposal>;
43
- export declare function proposeFromFile(file: string, projectRoot: string, configRoot?: string): Promise<SkillProposal>;
44
- export declare function readProposal(id: string, projectRoot: string, configRoot?: string): Promise<SkillProposal>;
45
- export declare function listProposals(projectRoot: string, configRoot?: string): Promise<readonly SkillProposal[]>;
46
- export declare function updateProposal(proposal: SkillProposal, updates: Readonly<Partial<Pick<SkillProposal, "status" | "ledgerEntryId">>>, projectRoot: string, configRoot?: string, options?: {
47
- readonly capability?: SkillLoopLockCapability;
48
- }): Promise<SkillProposal>;