@plico-ai/runtime 0.0.0-stage → 0.1.0

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 (188) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +4 -0
  3. package/README.md +11 -2
  4. package/dist/artifacts.d.ts +10 -0
  5. package/dist/artifacts.js +106 -0
  6. package/dist/engine/context.d.ts +16 -0
  7. package/dist/engine/context.js +77 -0
  8. package/dist/engine/engine.d.ts +12 -0
  9. package/dist/engine/engine.js +235 -0
  10. package/dist/engine/errors.d.ts +12 -0
  11. package/dist/engine/errors.js +19 -0
  12. package/dist/engine/index.d.ts +7 -0
  13. package/dist/engine/index.js +5 -0
  14. package/dist/engine/journal.d.ts +65 -0
  15. package/dist/engine/journal.js +1 -0
  16. package/dist/engine/memory-journal.d.ts +2 -0
  17. package/dist/engine/memory-journal.js +125 -0
  18. package/dist/engine/sqlite-engine.d.ts +7 -0
  19. package/dist/engine/sqlite-engine.js +6 -0
  20. package/dist/engine/sqlite-journal.d.ts +5 -0
  21. package/dist/engine/sqlite-journal.js +136 -0
  22. package/dist/engine/types.d.ts +97 -0
  23. package/dist/engine/types.js +1 -0
  24. package/dist/env.d.ts +7 -0
  25. package/dist/env.js +19 -0
  26. package/dist/errors.d.ts +18 -0
  27. package/dist/errors.js +40 -0
  28. package/dist/evals/discover.d.ts +3 -0
  29. package/dist/evals/discover.js +49 -0
  30. package/dist/evals/index.d.ts +3 -0
  31. package/dist/evals/index.js +3 -0
  32. package/dist/evals/promote.d.ts +7 -0
  33. package/dist/evals/promote.js +32 -0
  34. package/dist/evals/run-evals.d.ts +2 -0
  35. package/dist/evals/run-evals.js +69 -0
  36. package/dist/events.d.ts +28 -0
  37. package/dist/events.js +104 -0
  38. package/dist/guards.d.ts +1 -0
  39. package/dist/guards.js +3 -0
  40. package/dist/index.d.ts +18 -0
  41. package/dist/index.js +17 -0
  42. package/dist/instructions.d.ts +4 -0
  43. package/dist/instructions.js +23 -0
  44. package/dist/policy/approval.d.ts +8 -0
  45. package/dist/policy/approval.js +27 -0
  46. package/dist/providers/ai-sdk.d.ts +10 -0
  47. package/dist/providers/ai-sdk.js +154 -0
  48. package/dist/providers/configured.d.ts +17 -0
  49. package/dist/providers/configured.js +60 -0
  50. package/dist/providers/openai-compatible.d.ts +8 -0
  51. package/dist/providers/openai-compatible.js +14 -0
  52. package/dist/providers/project-module.d.ts +7 -0
  53. package/dist/providers/project-module.js +29 -0
  54. package/dist/providers/registry.d.ts +20 -0
  55. package/dist/providers/registry.js +53 -0
  56. package/dist/readiness/check-readiness.d.ts +2 -0
  57. package/dist/readiness/check-readiness.js +33 -0
  58. package/dist/readiness/checks/approval-policy.d.ts +5 -0
  59. package/dist/readiness/checks/approval-policy.js +19 -0
  60. package/dist/readiness/checks/artifact-access.d.ts +3 -0
  61. package/dist/readiness/checks/artifact-access.js +5 -0
  62. package/dist/readiness/checks/artifacts.d.ts +6 -0
  63. package/dist/readiness/checks/artifacts.js +22 -0
  64. package/dist/readiness/checks/env.d.ts +3 -0
  65. package/dist/readiness/checks/env.js +10 -0
  66. package/dist/readiness/checks/evals.d.ts +2 -0
  67. package/dist/readiness/checks/evals.js +53 -0
  68. package/dist/readiness/checks/persistence.d.ts +3 -0
  69. package/dist/readiness/checks/persistence.js +61 -0
  70. package/dist/readiness/checks/project.d.ts +7 -0
  71. package/dist/readiness/checks/project.js +21 -0
  72. package/dist/readiness/checks/provider.d.ts +2 -0
  73. package/dist/readiness/checks/provider.js +20 -0
  74. package/dist/readiness/checks/server-config.d.ts +2 -0
  75. package/dist/readiness/checks/server-config.js +13 -0
  76. package/dist/readiness/checks/studio.d.ts +2 -0
  77. package/dist/readiness/checks/studio.js +16 -0
  78. package/dist/readiness/checks/thread-store.d.ts +3 -0
  79. package/dist/readiness/checks/thread-store.js +12 -0
  80. package/dist/readiness/checks/tools.d.ts +3 -0
  81. package/dist/readiness/checks/tools.js +42 -0
  82. package/dist/readiness/diagnostic.d.ts +2 -0
  83. package/dist/readiness/diagnostic.js +7 -0
  84. package/dist/readiness/index.d.ts +1 -0
  85. package/dist/readiness/index.js +1 -0
  86. package/dist/readiness/open-database.d.ts +8 -0
  87. package/dist/readiness/open-database.js +15 -0
  88. package/dist/run/artifact-tool-context.d.ts +19 -0
  89. package/dist/run/artifact-tool-context.js +74 -0
  90. package/dist/run/finalize.d.ts +16 -0
  91. package/dist/run/finalize.js +11 -0
  92. package/dist/run/index.d.ts +1 -0
  93. package/dist/run/index.js +1 -0
  94. package/dist/run/pinned-instructions.d.ts +18 -0
  95. package/dist/run/pinned-instructions.js +36 -0
  96. package/dist/run/record-tools.d.ts +8 -0
  97. package/dist/run/record-tools.js +21 -0
  98. package/dist/run/run-project.d.ts +17 -0
  99. package/dist/run/run-project.js +222 -0
  100. package/dist/run/strategies/approval.d.ts +9 -0
  101. package/dist/run/strategies/approval.js +42 -0
  102. package/dist/run/strategies/default-dry.d.ts +3 -0
  103. package/dist/run/strategies/default-dry.js +5 -0
  104. package/dist/run/strategies/provider.d.ts +6 -0
  105. package/dist/run/strategies/provider.js +193 -0
  106. package/dist/run/strategies/scripted.d.ts +5 -0
  107. package/dist/run/strategies/scripted.js +106 -0
  108. package/dist/run/tool-fingerprint.d.ts +2 -0
  109. package/dist/run/tool-fingerprint.js +26 -0
  110. package/dist/run/tool-step.d.ts +4 -0
  111. package/dist/run/tool-step.js +62 -0
  112. package/dist/run/tracing.d.ts +12 -0
  113. package/dist/run/tracing.js +92 -0
  114. package/dist/script.d.ts +4 -0
  115. package/dist/script.js +51 -0
  116. package/dist/storage/index.d.ts +1 -0
  117. package/dist/storage/index.js +1 -0
  118. package/dist/storage/metadata.d.ts +5 -0
  119. package/dist/storage/metadata.js +26 -0
  120. package/dist/storage/sqlite/append-event.d.ts +3 -0
  121. package/dist/storage/sqlite/append-event.js +108 -0
  122. package/dist/storage/sqlite/driver.d.ts +9 -0
  123. package/dist/storage/sqlite/driver.js +13 -0
  124. package/dist/storage/sqlite/index.d.ts +1 -0
  125. package/dist/storage/sqlite/index.js +1 -0
  126. package/dist/storage/sqlite/open.d.ts +3 -0
  127. package/dist/storage/sqlite/open.js +54 -0
  128. package/dist/storage/sqlite/owner-lock.d.ts +5 -0
  129. package/dist/storage/sqlite/owner-lock.js +55 -0
  130. package/dist/storage/sqlite/project-thread.d.ts +4 -0
  131. package/dist/storage/sqlite/project-thread.js +33 -0
  132. package/dist/storage/sqlite/queries.d.ts +9 -0
  133. package/dist/storage/sqlite/queries.js +134 -0
  134. package/dist/storage/sqlite/recover-interrupted.d.ts +2 -0
  135. package/dist/storage/sqlite/recover-interrupted.js +46 -0
  136. package/dist/storage/sqlite/schema.d.ts +10 -0
  137. package/dist/storage/sqlite/schema.js +205 -0
  138. package/dist/storage/sqlite/store.d.ts +2 -0
  139. package/dist/storage/sqlite/store.js +51 -0
  140. package/dist/storage/sqlite/thread-log.d.ts +4 -0
  141. package/dist/storage/sqlite/thread-log.js +9 -0
  142. package/dist/storage/sqlite/thread-title.d.ts +24 -0
  143. package/dist/storage/sqlite/thread-title.js +85 -0
  144. package/dist/storage/sqlite/threads.d.ts +47 -0
  145. package/dist/storage/sqlite/threads.js +156 -0
  146. package/dist/threads/stopwords.d.ts +1 -0
  147. package/dist/threads/stopwords.js +16 -0
  148. package/dist/threads/suggest-title.d.ts +9 -0
  149. package/dist/threads/suggest-title.js +102 -0
  150. package/dist/threads/titler.d.ts +10 -0
  151. package/dist/threads/titler.js +63 -0
  152. package/dist/threads/words.d.ts +12 -0
  153. package/dist/threads/words.js +39 -0
  154. package/dist/tools/artifact-model-tool-operations.d.ts +29 -0
  155. package/dist/tools/artifact-model-tool-operations.js +124 -0
  156. package/dist/tools/artifact-model-tools.d.ts +2 -0
  157. package/dist/tools/artifact-model-tools.js +101 -0
  158. package/dist/tools/discover.d.ts +4 -0
  159. package/dist/tools/discover.js +34 -0
  160. package/dist/tools/index.d.ts +3 -0
  161. package/dist/tools/index.js +3 -0
  162. package/dist/tools/load.d.ts +2 -0
  163. package/dist/tools/load.js +83 -0
  164. package/dist/tools/normalize.d.ts +2 -0
  165. package/dist/tools/normalize.js +48 -0
  166. package/dist/tools/schema.d.ts +7 -0
  167. package/dist/tools/schema.js +101 -0
  168. package/dist/tools/skill-model-tool.d.ts +7 -0
  169. package/dist/tools/skill-model-tool.js +38 -0
  170. package/dist/types/artifacts.d.ts +5 -0
  171. package/dist/types/artifacts.js +1 -0
  172. package/dist/types/evals.d.ts +16 -0
  173. package/dist/types/evals.js +1 -0
  174. package/dist/types/index.d.ts +10 -0
  175. package/dist/types/index.js +1 -0
  176. package/dist/types/provider.d.ts +45 -0
  177. package/dist/types/provider.js +1 -0
  178. package/dist/types/readiness.d.ts +9 -0
  179. package/dist/types/readiness.js +1 -0
  180. package/dist/types/run.d.ts +28 -0
  181. package/dist/types/run.js +1 -0
  182. package/dist/types/script.d.ts +16 -0
  183. package/dist/types/script.js +1 -0
  184. package/dist/types/store.d.ts +24 -0
  185. package/dist/types/store.js +1 -0
  186. package/dist/types/tools.d.ts +15 -0
  187. package/dist/types/tools.js +1 -0
  188. package/package.json +77 -3
@@ -0,0 +1,21 @@
1
+ import { validateProject } from "@plico-ai/core";
2
+ import { makeDiagnostic } from "../diagnostic.js";
3
+ export async function checkProject(projectRoot) {
4
+ const diagnostics = [];
5
+ const validation = await validateProject(projectRoot);
6
+ if (!validation.ok || !validation.project) {
7
+ for (const issue of validation.errors ?? []) {
8
+ const subsystem = issue.path.startsWith("tools/") ? "tools.discovery" : "project.structure";
9
+ diagnostics.push(makeDiagnostic("error", subsystem, issue.message, issue.path));
10
+ }
11
+ for (const issue of validation.warnings ?? []) {
12
+ diagnostics.push(makeDiagnostic("warning", "project.structure", issue.message, issue.path));
13
+ }
14
+ return { diagnostics, project: validation.project };
15
+ }
16
+ diagnostics.push(makeDiagnostic("ok", "project.structure", "Project is valid", "plico.config.ts"));
17
+ for (const issue of validation.warnings ?? []) {
18
+ diagnostics.push(makeDiagnostic("warning", "project.structure", issue.message, issue.path));
19
+ }
20
+ return { diagnostics, project: validation.project };
21
+ }
@@ -0,0 +1,2 @@
1
+ import type { ProjectConfig, ReadinessDiagnostic } from "@plico-ai/contracts";
2
+ export declare function checkProvider(model: ProjectConfig["model"]): ReadinessDiagnostic[];
@@ -0,0 +1,20 @@
1
+ import { resolveModelEndpoint } from "../../providers/registry.js";
2
+ import { makeDiagnostic } from "../diagnostic.js";
3
+ export function checkProvider(model) {
4
+ if (!model)
5
+ return [
6
+ makeDiagnostic("warning", "provider.config", "No model configured. Add model settings for real provider runs.", "plico.config.ts"),
7
+ ];
8
+ const { apiKeyEnv } = resolveModelEndpoint(model);
9
+ if (!apiKeyEnv)
10
+ return [
11
+ makeDiagnostic("ok", "provider.credentials", "The project supplies its own provider credentials."),
12
+ ];
13
+ if (!process.env[apiKeyEnv])
14
+ return [
15
+ makeDiagnostic("warning", "provider.credentials", `Set ${apiKeyEnv} to run the configured model.`),
16
+ ];
17
+ return [
18
+ makeDiagnostic("ok", "provider.credentials", "Model provider credentials are configured."),
19
+ ];
20
+ }
@@ -0,0 +1,2 @@
1
+ import type { ReadinessDiagnostic } from "../../types/index.js";
2
+ export declare function checkServerConfig(projectRoot: string): Promise<ReadinessDiagnostic[]>;
@@ -0,0 +1,13 @@
1
+ import { loadProject } from "@plico-ai/core";
2
+ import { makeDiagnostic } from "../diagnostic.js";
3
+ export async function checkServerConfig(projectRoot) {
4
+ try {
5
+ await loadProject(projectRoot);
6
+ return [makeDiagnostic("ok", "server.config", "Project config loads successfully for server")];
7
+ }
8
+ catch {
9
+ return [
10
+ makeDiagnostic("warning", "server.config", "plico.config.ts could not be loaded. Server may not start."),
11
+ ];
12
+ }
13
+ }
@@ -0,0 +1,2 @@
1
+ import type { ReadinessDiagnostic } from "../../types/index.js";
2
+ export declare function checkStudio(studioPath: string | undefined): Promise<ReadinessDiagnostic[]>;
@@ -0,0 +1,16 @@
1
+ import { access } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { makeDiagnostic } from "../diagnostic.js";
4
+ export async function checkStudio(studioPath) {
5
+ if (studioPath === undefined)
6
+ return [];
7
+ try {
8
+ await access(join(studioPath, "index.html"));
9
+ return [makeDiagnostic("ok", "studio.assets", "Studio assets are built", studioPath)];
10
+ }
11
+ catch {
12
+ return [
13
+ makeDiagnostic("warning", "studio.assets", "Studio assets not found. Build them with: pnpm --filter @plico-ai/studio build", studioPath),
14
+ ];
15
+ }
16
+ }
@@ -0,0 +1,3 @@
1
+ import type { ThreadStore } from "../../storage/sqlite/threads.js";
2
+ import type { EventStore, ReadinessDiagnostic } from "../../types/index.js";
3
+ export declare function checkThreadStore(eventStore: EventStore | undefined, threadStore: Pick<ThreadStore, "storageIdentity"> | undefined): ReadinessDiagnostic[];
@@ -0,0 +1,12 @@
1
+ import { makeDiagnostic } from "../diagnostic.js";
2
+ export function checkThreadStore(eventStore, threadStore) {
3
+ if (!threadStore)
4
+ return [];
5
+ const sharesIdentity = threadStore.storageIdentity !== undefined &&
6
+ threadStore.storageIdentity === eventStore?.storageIdentity;
7
+ return sharesIdentity
8
+ ? [makeDiagnostic("ok", "threads.store", "Thread and run stores share the same database.")]
9
+ : [
10
+ makeDiagnostic("error", "threads.store", "Thread and run stores must use the same database. Thread runs cannot start."),
11
+ ];
12
+ }
@@ -0,0 +1,3 @@
1
+ import { type LoadedProject } from "@plico-ai/core";
2
+ import type { ReadinessDiagnostic } from "../../types/index.js";
3
+ export declare function checkTools(project: LoadedProject): Promise<ReadinessDiagnostic[]>;
@@ -0,0 +1,42 @@
1
+ import { join } from "node:path";
2
+ import { getProjectPaths, getProjectRelativePaths } from "@plico-ai/core";
3
+ import { discoverToolFiles, loadToolFile } from "../../tools/index.js";
4
+ import { makeDiagnostic } from "../diagnostic.js";
5
+ import { checkApprovalPolicy } from "./approval-policy.js";
6
+ export async function checkTools(project) {
7
+ const diagnostics = [];
8
+ const projectPaths = getProjectPaths(project.root);
9
+ const relativePaths = getProjectRelativePaths();
10
+ let toolFiles;
11
+ try {
12
+ toolFiles = await discoverToolFiles(project);
13
+ }
14
+ catch (error) {
15
+ if (error.code !== "ENOENT")
16
+ throw error;
17
+ return [
18
+ makeDiagnostic("error", "tools.discovery", "tools/ directory not found. Create tools/ to declare tools.", relativePaths.directories.tools),
19
+ ...checkApprovalPolicy(project, [], { toolsComplete: false }),
20
+ ];
21
+ }
22
+ if (toolFiles.length === 0) {
23
+ diagnostics.push(makeDiagnostic("warning", "tools.discovery", "No tools declared. Add a .tool.ts module to get started."));
24
+ diagnostics.push(...checkApprovalPolicy(project, []));
25
+ return diagnostics;
26
+ }
27
+ let validCount = 0;
28
+ const tools = [];
29
+ for (const entry of toolFiles) {
30
+ const source = `${relativePaths.directories.tools}/${entry}`;
31
+ try {
32
+ tools.push(await loadToolFile(join(projectPaths.directories.tools, entry), source));
33
+ validCount++;
34
+ }
35
+ catch (error) {
36
+ diagnostics.push(makeDiagnostic("error", "tools.discovery", `Schema validation failed for ${entry}: ${String(error)}`, source));
37
+ }
38
+ }
39
+ diagnostics.push(makeDiagnostic(validCount === toolFiles.length ? "ok" : "warning", "tools.discovery", `${validCount}/${toolFiles.length} tool(s) valid`));
40
+ diagnostics.push(...checkApprovalPolicy(project, tools, { toolsComplete: validCount === toolFiles.length }));
41
+ return diagnostics;
42
+ }
@@ -0,0 +1,2 @@
1
+ import type { ReadinessDiagnostic } from "../types/index.js";
2
+ export declare function makeDiagnostic(severity: ReadinessDiagnostic["severity"], subsystem: string, message: string, path?: string): ReadinessDiagnostic;
@@ -0,0 +1,7 @@
1
+ export function makeDiagnostic(severity, subsystem, message, path) {
2
+ const result = { severity, subsystem, message };
3
+ if (path !== undefined) {
4
+ result.path = path;
5
+ }
6
+ return result;
7
+ }
@@ -0,0 +1 @@
1
+ export { checkReadiness } from "./check-readiness.js";
@@ -0,0 +1 @@
1
+ export { checkReadiness } from "./check-readiness.js";
@@ -0,0 +1,8 @@
1
+ import type { EventStore } from "../types/index.js";
2
+ export interface ReadinessDatabase {
3
+ eventStore?: EventStore;
4
+ /** True when the caller supplied the store, rather than readiness opening one. */
5
+ attached: boolean;
6
+ openError?: string;
7
+ }
8
+ export declare function openDatabase(databasePath: string, eventStore: EventStore | undefined): ReadinessDatabase;
@@ -0,0 +1,15 @@
1
+ import { existsSync } from "node:fs";
2
+ import { createSqliteEventStore } from "../storage/index.js";
3
+ export function openDatabase(databasePath, eventStore) {
4
+ if (eventStore)
5
+ return { eventStore, attached: true };
6
+ if (!existsSync(databasePath))
7
+ return { attached: false };
8
+ try {
9
+ const store = createSqliteEventStore({ databasePath, readOnly: true });
10
+ return { eventStore: store, attached: false };
11
+ }
12
+ catch (error) {
13
+ return { attached: false, openError: error.message };
14
+ }
15
+ }
@@ -0,0 +1,19 @@
1
+ import type { ArtifactContent, PlicoEvent, PlicoEventPayloads } from "@plico-ai/contracts";
2
+ import type { ToolArtifactContext } from "../types/index.js";
3
+ export interface StagedArtifactWrite {
4
+ path: string;
5
+ content: ArtifactContent;
6
+ mimeType: string;
7
+ contentHash: string;
8
+ version: number;
9
+ }
10
+ interface StagedArtifactContext {
11
+ context: ToolArtifactContext;
12
+ writes(): StagedArtifactWrite[];
13
+ workspaceCreated(): boolean;
14
+ workspaceId: string;
15
+ }
16
+ export declare function createStagedArtifactContext(runId: string, threadId: string | undefined, history: PlicoEvent[]): StagedArtifactContext;
17
+ export declare function validateArtifactPath(path: string): void;
18
+ export declare function artifactWriteEventPayload(write: StagedArtifactWrite): PlicoEventPayloads["artifact.file.written"];
19
+ export {};
@@ -0,0 +1,74 @@
1
+ import { artifactFileMetadata, buildArtifactWorkspace, decodeArtifactContent, encodeArtifactContent, hashArtifactContent, } from "../artifacts.js";
2
+ const maxArtifactContentBytes = 1024 * 1024;
3
+ const maxArtifactPathLength = 1024;
4
+ export function createStagedArtifactContext(runId, threadId, history) {
5
+ const workspaceId = threadId ? `${threadId}:workspace` : `${runId}:workspace`;
6
+ const initialWorkspace = buildArtifactWorkspace(workspaceId, history);
7
+ const files = new Map((initialWorkspace?.files ?? []).map((file) => [file.path, file]));
8
+ const writesList = [];
9
+ const context = {
10
+ async read(path) {
11
+ const file = files.get(path);
12
+ if (!file)
13
+ return undefined;
14
+ return { ...file, content: decodeArtifactContent(file.content) };
15
+ },
16
+ async write(path, content, options) {
17
+ validateArtifactPath(path);
18
+ validateArtifactContent(content);
19
+ const encoded = encodeArtifactContent(content);
20
+ const file = {
21
+ path,
22
+ content: encoded,
23
+ mimeType: options?.mimeType ??
24
+ (typeof content === "string" ? "text/plain" : "application/octet-stream"),
25
+ version: (files.get(path)?.version ?? 0) + 1,
26
+ contentHash: hashArtifactContent(encoded),
27
+ };
28
+ files.set(path, file);
29
+ writesList.push({
30
+ path: file.path,
31
+ content: file.content,
32
+ mimeType: file.mimeType,
33
+ contentHash: file.contentHash,
34
+ version: file.version,
35
+ });
36
+ return { path, version: file.version };
37
+ },
38
+ async list() {
39
+ return [...files.values()].map(artifactFileMetadata);
40
+ },
41
+ };
42
+ return {
43
+ context,
44
+ writes: () => [...writesList],
45
+ workspaceCreated: () => initialWorkspace === undefined && writesList.length > 0,
46
+ workspaceId,
47
+ };
48
+ }
49
+ export function validateArtifactPath(path) {
50
+ const segments = path.split(/[\\/]/);
51
+ if (path.length === 0 ||
52
+ path.length > maxArtifactPathLength ||
53
+ path.startsWith("/") ||
54
+ path.startsWith("\\") ||
55
+ /^[a-zA-Z]:/.test(path) ||
56
+ segments.some((segment) => segment === ".." || segment === "")) {
57
+ throw new Error(`Invalid artifact path: expected a non-empty relative path without '..' and at most ${maxArtifactPathLength} characters.`);
58
+ }
59
+ }
60
+ function validateArtifactContent(content) {
61
+ const sizeBytes = typeof content === "string" ? Buffer.byteLength(content, "utf8") : content.byteLength;
62
+ if (sizeBytes > maxArtifactContentBytes)
63
+ throw new Error("Artifact content exceeds the 1 MiB write limit.");
64
+ }
65
+ export function artifactWriteEventPayload(write) {
66
+ const content = write.content;
67
+ return {
68
+ path: write.path,
69
+ content,
70
+ mimeType: write.mimeType,
71
+ contentHash: write.contentHash,
72
+ version: write.version,
73
+ };
74
+ }
@@ -0,0 +1,16 @@
1
+ import type { PlicoEvent, RunResult, RunStatus } from "@plico-ai/contracts";
2
+ import type { ValidationIssue } from "@plico-ai/core";
3
+ import type { EventStore } from "../types/index.js";
4
+ export interface FinalizeRunInput {
5
+ runId: string;
6
+ projectRoot: string;
7
+ projectName: string;
8
+ status: RunStatus;
9
+ startedAt: string;
10
+ events: PlicoEvent[];
11
+ output?: string | undefined;
12
+ errors?: ValidationIssue[] | undefined;
13
+ eventStore?: EventStore | undefined;
14
+ }
15
+ /** Builds the result after the run has stopped or finished. */
16
+ export declare function finalizeRun(input: FinalizeRunInput): Promise<RunResult>;
@@ -0,0 +1,11 @@
1
+ /** Builds the result after the run has stopped or finished. */
2
+ export async function finalizeRun(input) {
3
+ const result = {
4
+ runId: input.runId,
5
+ status: input.status,
6
+ ...(input.output === undefined ? {} : { output: input.output }),
7
+ events: input.events,
8
+ ...(input.errors === undefined ? {} : { errors: input.errors }),
9
+ };
10
+ return result;
11
+ }
@@ -0,0 +1 @@
1
+ export { recoverRuns, runProject } from "./run-project.js";
@@ -0,0 +1 @@
1
+ export { recoverRuns, runProject } from "./run-project.js";
@@ -0,0 +1,18 @@
1
+ import type { ValidationIssue } from "@plico-ai/contracts";
2
+ import { type LoadedProject, type Skill } from "@plico-ai/core";
3
+ import type { InMemoryEventLog } from "../events.js";
4
+ /**
5
+ * Records the instructions and skills a run starts with. A run that resumes reuses what it
6
+ * recorded, so editing `agent.md` or a skill while it waits does not change its behaviour.
7
+ */
8
+ export declare function pinInstructions(project: LoadedProject, events: InMemoryEventLog): Promise<{
9
+ instructions: {
10
+ content: string;
11
+ };
12
+ skills: Skill[];
13
+ }>;
14
+ /**
15
+ * A run that already recorded its instructions and skills does not read them again, so an
16
+ * `agent.md` or skill that is invalid now must not stop it from resuming.
17
+ */
18
+ export declare function ignoredWhenPinned(issue: ValidationIssue): boolean;
@@ -0,0 +1,36 @@
1
+ import { readSkills } from "@plico-ai/core";
2
+ import { composeInstructions } from "../instructions.js";
3
+ /**
4
+ * Records the instructions and skills a run starts with. A run that resumes reuses what it
5
+ * recorded, so editing `agent.md` or a skill while it waits does not change its behaviour.
6
+ */
7
+ export async function pinInstructions(project, events) {
8
+ const recorded = events.all().find((event) => event.type === "instructions.composed");
9
+ if (recorded?.type === "instructions.composed") {
10
+ await events.append("instructions.composed", recorded.payload);
11
+ // Runs recorded before skills were pinned fall back to the skills on disk.
12
+ const skills = recorded.payload.skills ?? (await readSkills(project.root)).skills;
13
+ return { instructions: { content: recorded.payload.content }, skills };
14
+ }
15
+ const { skills } = await readSkills(project.root);
16
+ const instructions = await composeInstructions(project, skills);
17
+ await events.append("instructions.composed", {
18
+ length: instructions.content.length,
19
+ sources: instructions.sources,
20
+ content: instructions.content,
21
+ skills: skills.map(({ name, description, source, body }) => ({
22
+ name,
23
+ description,
24
+ source,
25
+ body,
26
+ })),
27
+ });
28
+ return { instructions, skills };
29
+ }
30
+ /**
31
+ * A run that already recorded its instructions and skills does not read them again, so an
32
+ * `agent.md` or skill that is invalid now must not stop it from resuming.
33
+ */
34
+ export function ignoredWhenPinned(issue) {
35
+ return issue.path === "agent.md" || issue.path === "skills" || issue.path.startsWith("skills/");
36
+ }
@@ -0,0 +1,8 @@
1
+ import type { InMemoryEventLog } from "../events.js";
2
+ import type { DeclaredTool } from "../types/index.js";
3
+ /**
4
+ * Records the tools a run discovered with a hash of the tool code. A resumed run compares both, so
5
+ * a changed handler fails the run before the tool runs. Runs recorded without a hash are compared
6
+ * on their declarations only.
7
+ */
8
+ export declare function recordTools(root: string, tools: DeclaredTool[], events: InMemoryEventLog): Promise<void>;
@@ -0,0 +1,21 @@
1
+ import { fingerprintTools } from "./tool-fingerprint.js";
2
+ /**
3
+ * Records the tools a run discovered with a hash of the tool code. A resumed run compares both, so
4
+ * a changed handler fails the run before the tool runs. Runs recorded without a hash are compared
5
+ * on their declarations only.
6
+ */
7
+ export async function recordTools(root, tools, events) {
8
+ const recorded = events.all().find((event) => event.type === "tools.discovered");
9
+ const legacy = recorded?.type === "tools.discovered" && recorded.payload.fingerprint === undefined;
10
+ await events.append("tools.discovered", {
11
+ tools: tools.map((tool) => ({
12
+ source: tool.source,
13
+ name: tool.name,
14
+ description: tool.description,
15
+ inputSchema: tool.inputSchema,
16
+ capabilities: tool.capabilities,
17
+ approval: tool.approval,
18
+ })),
19
+ ...(legacy ? {} : { fingerprint: await fingerprintTools(root) }),
20
+ });
21
+ }
@@ -0,0 +1,17 @@
1
+ import { type Engine, type RecoveredRun } from "../engine/index.js";
2
+ import type { RunProjectOptions, RunResult } from "../types/index.js";
3
+ export declare function runProject(root: string, options?: RunProjectOptions): Promise<RunResult>;
4
+ /**
5
+ * Continues runs a dead process left running. The provider and event store come from this process;
6
+ * the project path, message and script come from the journal.
7
+ */
8
+ export declare function recoverRuns(options: RunProjectOptions & {
9
+ engine: Engine;
10
+ recoveryFilter?: {
11
+ projectRoot: string;
12
+ providerRecoveryKey?: string;
13
+ providerOnly?: boolean;
14
+ };
15
+ onRecoveryStarted?: (runId: string) => void;
16
+ onRecoverySettled?: (runId: string) => void;
17
+ }): Promise<RecoveredRun[]>;