spawnfile 0.1.12 → 0.1.13

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 (63) hide show
  1. package/README.md +9 -2
  2. package/dist/auth/runtimeCredentials.js +18 -2
  3. package/dist/cli/devCommands.d.ts +3 -0
  4. package/dist/cli/devCommands.js +115 -0
  5. package/dist/cli/lifecycleCommands.js +2 -0
  6. package/dist/cli/runCli.d.ts +6 -0
  7. package/dist/cli/runCli.js +4 -0
  8. package/dist/cli/statusCommand.d.ts +2 -1
  9. package/dist/cli/statusCommand.js +50 -16
  10. package/dist/compiler/buildProject.d.ts +9 -1
  11. package/dist/compiler/buildProject.js +44 -5
  12. package/dist/compiler/compileProject.d.ts +2 -0
  13. package/dist/compiler/compileProject.js +3 -1
  14. package/dist/compiler/containerArtifactsRender.js +25 -69
  15. package/dist/compiler/containerEntrypointRender.js +4 -1
  16. package/dist/compiler/containerPackageRender.d.ts +15 -0
  17. package/dist/compiler/containerPackageRender.js +63 -0
  18. package/dist/compiler/containerTargetResources.js +3 -1
  19. package/dist/compiler/moltnetArtifacts.js +16 -1
  20. package/dist/compiler/moltnetBinaries.d.ts +4 -1
  21. package/dist/compiler/moltnetBinaries.js +24 -3
  22. package/dist/compiler/moltnetClientConfig.js +11 -0
  23. package/dist/compiler/moltnetRuntimeConfig.js +11 -0
  24. package/dist/compiler/runProject.js +7 -1
  25. package/dist/compiler/runProjectDocker.js +157 -12
  26. package/dist/compiler/upProject.js +1 -0
  27. package/dist/deployment/dockerRecover.d.ts +17 -0
  28. package/dist/deployment/dockerRecover.js +129 -0
  29. package/dist/deployment/index.d.ts +1 -0
  30. package/dist/deployment/index.js +1 -0
  31. package/dist/dev/activity.d.ts +14 -0
  32. package/dist/dev/activity.js +48 -0
  33. package/dist/dev/docker.d.ts +16 -0
  34. package/dist/dev/docker.js +71 -0
  35. package/dist/dev/index.d.ts +2 -0
  36. package/dist/dev/index.js +2 -0
  37. package/dist/dev/project.d.ts +35 -0
  38. package/dist/dev/project.js +164 -0
  39. package/dist/runtime/common.d.ts +2 -0
  40. package/dist/runtime/common.js +1 -1
  41. package/dist/runtime/container.d.ts +1 -0
  42. package/dist/runtime/container.js +93 -10
  43. package/dist/runtime/install.d.ts +1 -1
  44. package/dist/runtime/install.js +43 -1
  45. package/dist/runtime/pi/adapter.d.ts +4 -0
  46. package/dist/runtime/pi/adapter.js +198 -0
  47. package/dist/runtime/pi/appActivitySource.d.ts +1 -0
  48. package/dist/runtime/pi/appActivitySource.js +87 -0
  49. package/dist/runtime/pi/appCoreSource.d.ts +1 -0
  50. package/dist/runtime/pi/appCoreSource.js +354 -0
  51. package/dist/runtime/pi/appPreludeSource.d.ts +1 -0
  52. package/dist/runtime/pi/appPreludeSource.js +103 -0
  53. package/dist/runtime/pi/appSource.d.ts +1 -0
  54. package/dist/runtime/pi/appSource.js +8 -0
  55. package/dist/runtime/pi/appTemplate.d.ts +28 -0
  56. package/dist/runtime/pi/appTemplate.js +144 -0
  57. package/dist/runtime/pi/runAuth.d.ts +2 -0
  58. package/dist/runtime/pi/runAuth.js +68 -0
  59. package/dist/runtime/registry.js +3 -0
  60. package/dist/runtime/types.d.ts +1 -0
  61. package/dist/status/deployments.js +5 -12
  62. package/package.json +7 -2
  63. package/runtimes.yaml +27 -11
@@ -1,6 +1,14 @@
1
1
  import { SpawnfileError } from "../shared/index.js";
2
2
  import { resolveRuntimeInstallSelection } from "./install.js";
3
3
  export const RUNTIME_INSTALL_ROOT = "/opt/spawnfile/runtime-installs";
4
+ const PI_RUNTIME_BASE_IMAGE_ENV = "SPAWNFILE_PI_RUNTIME_BASE_IMAGE";
5
+ const DAIMON_RUNTIME_IMAGE_ENV = "SPAWNFILE_DAIMON_RUNTIME_IMAGE";
6
+ const DAIMON_RUNTIME_BASE_IMAGE_ENV = "SPAWNFILE_DAIMON_RUNTIME_BASE_IMAGE";
7
+ const OPENCLAW_RUNTIME_IMAGE_ENV = "SPAWNFILE_OPENCLAW_RUNTIME_IMAGE";
8
+ const PICOCLAW_RUNTIME_IMAGE_ENV = "SPAWNFILE_PICOCLAW_RUNTIME_IMAGE";
9
+ const PI_AI_PACKAGE_NAME = "@earendil-works/pi-ai";
10
+ const PI_CODING_AGENT_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
11
+ const PI_PACKAGE_VERSION = "0.79.9";
4
12
  const assertArtifactInstallSelection = (runtimeName, selection) => {
5
13
  if (selection.kind !== "source_repo") {
6
14
  return;
@@ -11,29 +19,50 @@ const createPicoClawArchiveInstallCommands = (runtimeRoot, selection) => [
11
19
  `mkdir -p ${runtimeRoot}/bin`,
12
20
  `arch="$(dpkg --print-architecture)" && case "$arch" in amd64) asset=${JSON.stringify(selection.versionedAssets.linux_amd64)} ;; arm64) asset=${JSON.stringify(selection.versionedAssets.linux_arm64)} ;; *) echo "Unsupported PicoClaw release architecture: $arch" >&2; exit 1 ;; esac && url="https://github.com/${selection.repository}/releases/download/${selection.tag}/$asset" && curl -fsSL -o /tmp/picoclaw.tar.gz "$url" && rm -rf /tmp/picoclaw-extract && mkdir -p /tmp/picoclaw-extract && tar -xzf /tmp/picoclaw.tar.gz -C /tmp/picoclaw-extract && binary_path="$(find /tmp/picoclaw-extract -type f -name ${JSON.stringify(selection.binaryName)} | head -n 1)" && [ -n "$binary_path" ] && install -m 0755 "$binary_path" ${runtimeRoot}/bin/${selection.binaryName} && ln -sf ${runtimeRoot}/bin/${selection.binaryName} /usr/local/bin/${selection.binaryName} && rm -rf /tmp/picoclaw.tar.gz /tmp/picoclaw-extract`
13
21
  ];
22
+ const createRuntimeImageCopyCommand = (imageRef, runtimeRoot) => `COPY --from=${imageRef} ${runtimeRoot} ${runtimeRoot}`;
23
+ const resolveRuntimeImageRef = (envName, selection) => process.env[envName]?.trim() ||
24
+ (selection.kind === "container_image"
25
+ ? `${selection.image}:${selection.tag}`
26
+ : undefined);
14
27
  export const createRuntimeInstallRecipe = async (runtimeName) => {
15
28
  const selection = await resolveRuntimeInstallSelection(runtimeName);
16
29
  assertArtifactInstallSelection(runtimeName, selection);
17
30
  const installRoot = `${RUNTIME_INSTALL_ROOT}/${runtimeName}`;
18
31
  switch (runtimeName) {
19
32
  case "openclaw": {
20
- if (selection.kind !== "container_image" && selection.kind !== "npm") {
33
+ const openClawRuntimeImage = resolveRuntimeImageRef(OPENCLAW_RUNTIME_IMAGE_ENV, selection);
34
+ if (openClawRuntimeImage) {
35
+ return {
36
+ commands: [],
37
+ copyCommands: [createRuntimeImageCopyCommand(openClawRuntimeImage, installRoot)],
38
+ runtimeName,
39
+ runtimeRoot: installRoot
40
+ };
41
+ }
42
+ if (selection.kind !== "npm") {
21
43
  throw new SpawnfileError("runtime_error", `Runtime ${runtimeName} has no compiled artifact recipe for ${selection.kind}`);
22
44
  }
23
45
  return {
24
- commands: selection.kind === "container_image"
25
- ? []
26
- : [`npm install -g --omit=dev --no-fund --no-audit ${selection.packageName}@${selection.version}`],
27
- copyCommands: selection.kind === "container_image"
28
- ? [`COPY --from=${selection.image}:${selection.tag} /app ${installRoot}`]
29
- : [],
46
+ commands: [
47
+ `npm install -g --omit=dev --no-fund --no-audit ${selection.packageName}@${selection.version}`
48
+ ],
49
+ copyCommands: [],
30
50
  runtimeName,
31
- runtimeRoot: selection.kind === "container_image"
32
- ? installRoot
33
- : `/usr/local/lib/node_modules/${selection.packageName}`
51
+ runtimeRoot: `/usr/local/lib/node_modules/${selection.packageName}`
34
52
  };
35
53
  }
36
54
  case "picoclaw": {
55
+ const picoClawRuntimeImage = resolveRuntimeImageRef(PICOCLAW_RUNTIME_IMAGE_ENV, selection);
56
+ if (picoClawRuntimeImage) {
57
+ return {
58
+ commands: [
59
+ `mkdir -p /usr/local/bin && ln -sf ${installRoot}/bin/picoclaw /usr/local/bin/picoclaw`
60
+ ],
61
+ copyCommands: [createRuntimeImageCopyCommand(picoClawRuntimeImage, installRoot)],
62
+ runtimeName,
63
+ runtimeRoot: installRoot
64
+ };
65
+ }
37
66
  if (selection.kind !== "github_release_archive") {
38
67
  throw new SpawnfileError("runtime_error", `Runtime ${runtimeName} has no compiled artifact recipe for ${selection.kind}`);
39
68
  }
@@ -44,6 +73,60 @@ export const createRuntimeInstallRecipe = async (runtimeName) => {
44
73
  runtimeRoot: installRoot
45
74
  };
46
75
  }
76
+ case "daimon": {
77
+ const daimonRuntimeImage = process.env[DAIMON_RUNTIME_IMAGE_ENV]?.trim() ||
78
+ process.env[DAIMON_RUNTIME_BASE_IMAGE_ENV]?.trim() ||
79
+ (selection.kind === "container_image"
80
+ ? `${selection.image}:${selection.tag}`
81
+ : undefined);
82
+ if (daimonRuntimeImage) {
83
+ return {
84
+ commands: [],
85
+ copyCommands: [createRuntimeImageCopyCommand(daimonRuntimeImage, installRoot)],
86
+ runtimeName,
87
+ runtimeRoot: installRoot
88
+ };
89
+ }
90
+ if (selection.kind !== "npm") {
91
+ throw new SpawnfileError("runtime_error", `Runtime ${runtimeName} has no compiled artifact recipe for ${selection.kind}`);
92
+ }
93
+ const npmPackages = [
94
+ `${selection.packageName}@${selection.version}`,
95
+ `${PI_CODING_AGENT_PACKAGE_NAME}@${PI_PACKAGE_VERSION}`,
96
+ `${PI_AI_PACKAGE_NAME}@${PI_PACKAGE_VERSION}`
97
+ ];
98
+ return {
99
+ commands: [
100
+ `mkdir -p ${installRoot}`,
101
+ `cd ${installRoot} && npm install --omit=dev --no-fund --no-audit ${npmPackages.join(" ")}`
102
+ ],
103
+ copyCommands: [],
104
+ runtimeName,
105
+ runtimeRoot: installRoot
106
+ };
107
+ }
108
+ case "pi": {
109
+ if (selection.kind !== "npm") {
110
+ throw new SpawnfileError("runtime_error", `Runtime ${runtimeName} has no compiled artifact recipe for ${selection.kind}`);
111
+ }
112
+ const prebuiltBaseImage = process.env[PI_RUNTIME_BASE_IMAGE_ENV]?.trim() || undefined;
113
+ const npmPackages = [
114
+ `${selection.packageName}@${selection.version}`,
115
+ `${PI_AI_PACKAGE_NAME}@${selection.version}`
116
+ ];
117
+ return {
118
+ ...(prebuiltBaseImage ? { baseImage: prebuiltBaseImage } : {}),
119
+ commands: prebuiltBaseImage
120
+ ? [`mkdir -p ${installRoot}`]
121
+ : [
122
+ `mkdir -p ${installRoot}`,
123
+ `cd ${installRoot} && npm install --omit=dev --no-fund --no-audit ${npmPackages.join(" ")}`
124
+ ],
125
+ copyCommands: [],
126
+ runtimeName,
127
+ runtimeRoot: installRoot
128
+ };
129
+ }
47
130
  /* c8 ignore next 5 -- compileable runtimes are exhaustively covered above */
48
131
  default:
49
132
  throw new SpawnfileError("runtime_error", `Runtime ${runtimeName} has no container install recipe`);
@@ -1,5 +1,5 @@
1
1
  export type RuntimeInstallSelection = {
2
- ecosystem: "node";
2
+ ecosystem: "go" | "node";
3
3
  image: string;
4
4
  installHint: string;
5
5
  kind: "container_image";
@@ -9,6 +9,27 @@ const convertRemoteToHttps = (remote) => {
9
9
  return remote.replace(/^git\+/, "");
10
10
  };
11
11
  const installHints = new Map([
12
+ [
13
+ "daimon",
14
+ {
15
+ container_image: {
16
+ ecosystem: "node",
17
+ installHint: "Copy a pinned Daimon runtime image."
18
+ },
19
+ github_release_archive: {
20
+ ecosystem: "node",
21
+ installHint: "Download a pinned Daimon runtime release archive."
22
+ },
23
+ npm: {
24
+ ecosystem: "node",
25
+ installHint: "Install the pinned Daimon package and Pi SDK dependencies inside the generated runtime app."
26
+ },
27
+ source_repo: {
28
+ ecosystem: "node",
29
+ installHint: "Checkout the pinned Daimon repo ref and install from the repository root."
30
+ }
31
+ }
32
+ ],
12
33
  [
13
34
  "openclaw",
14
35
  {
@@ -50,6 +71,27 @@ const installHints = new Map([
50
71
  installHint: "Checkout the pinned repo ref and build/install from the repository root."
51
72
  }
52
73
  }
74
+ ],
75
+ [
76
+ "pi",
77
+ {
78
+ container_image: {
79
+ ecosystem: "node",
80
+ installHint: "Copy a pinned Pi harness runtime image."
81
+ },
82
+ github_release_archive: {
83
+ ecosystem: "node",
84
+ installHint: "Download a pinned Pi harness release archive."
85
+ },
86
+ npm: {
87
+ ecosystem: "node",
88
+ installHint: "Install pinned Pi SDK dependencies inside the generated runtime app."
89
+ },
90
+ source_repo: {
91
+ ecosystem: "node",
92
+ installHint: "Checkout the pinned Pi repo ref and install from the repository root."
93
+ }
94
+ }
53
95
  ]
54
96
  ]);
55
97
  export const resolveRuntimeInstallSelection = async (runtimeName) => {
@@ -61,7 +103,7 @@ export const resolveRuntimeInstallSelection = async (runtimeName) => {
61
103
  switch (runtime.install?.kind) {
62
104
  case "container_image":
63
105
  return {
64
- ecosystem: "node",
106
+ ecosystem: installProfile.container_image.ecosystem,
65
107
  image: runtime.install.image,
66
108
  installHint: installProfile.container_image.installHint,
67
109
  kind: "container_image",
@@ -0,0 +1,4 @@
1
+ import type { RuntimeAdapter } from "../types.js";
2
+ export declare const piAdapter: RuntimeAdapter;
3
+ export declare const daimonAdapter: RuntimeAdapter;
4
+ export declare const PI_RUNTIME_PACKAGE = "@earendil-works/pi-coding-agent@0.79.9";
@@ -0,0 +1,198 @@
1
+ import path from "node:path";
2
+ import { listExecutionModelSecretNames } from "../../compiler/modelEnv.js";
3
+ import { SpawnfileError } from "../../shared/index.js";
4
+ import { createAgentCapabilities, createDiagnostic, createDocumentFiles, createSkillFiles } from "../common.js";
5
+ import { createPiAgentConfig, PI_PACKAGE_NAME, PI_PACKAGE_VERSION, renderPiApp, renderPiAppConfig, renderPiModelsConfig, renderPiPackageJson } from "./appTemplate.js";
6
+ import { preparePiRuntimeAuth } from "./runAuth.js";
7
+ const PI_CONFIG_FILE = "pi-app.json";
8
+ const PI_CONTROL_PORT = 19690;
9
+ const PI_MODELS_FILE = "home/.pi/agent/models.json";
10
+ const moveWorkspaceFileToAgentWorkspace = (file, agentSlug) => {
11
+ if (!file.path.startsWith("workspace/")) {
12
+ return file;
13
+ }
14
+ const relativePath = file.path.slice("workspace/".length);
15
+ return {
16
+ ...file,
17
+ path: path.posix.join("workspace", "agents", agentSlug, relativePath)
18
+ };
19
+ };
20
+ const createContainerTargets = async (inputs) => {
21
+ const agentInputs = inputs.filter((input) => input.kind === "agent" && input.value.kind === "agent");
22
+ if (agentInputs.length === 0) {
23
+ return [];
24
+ }
25
+ const agents = agentInputs.map((input) => createPiAgentConfig(input.value, input.slug, input.id));
26
+ const envFiles = [
27
+ ...new Set(agentInputs.flatMap((input) => listExecutionModelSecretNames(input.value.execution)))
28
+ ].map((secretName) => ({
29
+ envName: secretName,
30
+ relativePath: `secrets/${secretName}`
31
+ }));
32
+ return [
33
+ {
34
+ envFiles,
35
+ files: [
36
+ ...agentInputs.flatMap((input) => input.emittedFiles.map((file) => moveWorkspaceFileToAgentWorkspace(file, input.slug))),
37
+ {
38
+ content: renderPiAppConfig(agents),
39
+ path: PI_CONFIG_FILE
40
+ },
41
+ {
42
+ content: renderPiModelsConfig(agentInputs.map((input) => input.value)),
43
+ path: PI_MODELS_FILE
44
+ },
45
+ {
46
+ content: renderPiPackageJson(),
47
+ path: "runtime/package.json"
48
+ },
49
+ {
50
+ content: renderPiApp(),
51
+ mode: 0o755,
52
+ path: "runtime/app.mjs"
53
+ }
54
+ ],
55
+ id: "pi-app",
56
+ sourceIds: agentInputs.map((input) => input.id).sort()
57
+ }
58
+ ];
59
+ };
60
+ const scheduleOutcomeFor = (node) => {
61
+ if (!node.schedule) {
62
+ return {};
63
+ }
64
+ if (node.schedule.kind === "every" || node.schedule.kind === "disabled") {
65
+ return {
66
+ message: "Pi generated runtime app owns this schedule",
67
+ outcome: "supported"
68
+ };
69
+ }
70
+ return {
71
+ message: "Pi generated runtime app supports every schedules in Spawnfile v0.1",
72
+ outcome: "degraded"
73
+ };
74
+ };
75
+ const createScheduleDiagnostics = (node) => node.schedule?.kind === "cron"
76
+ ? [
77
+ createDiagnostic("warn", "Pi generated runtime app supports every schedules in Spawnfile v0.1; cron schedules are degraded")
78
+ ]
79
+ : [];
80
+ const moltnetCapabilityOptions = (node) => node.surfaces?.moltnet
81
+ ? {
82
+ moltnetMessage: "Pi generated runtime app exposes a control endpoint for Moltnet bridge wake delivery",
83
+ moltnetOutcome: "supported"
84
+ }
85
+ : {};
86
+ const assertSupportedPiSurfaces = (surfaces) => {
87
+ if (!surfaces) {
88
+ return;
89
+ }
90
+ const unsupported = [
91
+ surfaces.discord ? "discord" : null,
92
+ surfaces.http ? "http" : null,
93
+ surfaces.slack ? "slack" : null,
94
+ surfaces.telegram ? "telegram" : null,
95
+ surfaces.webhook ? "webhook" : null,
96
+ surfaces.whatsapp ? "whatsapp" : null
97
+ ].filter((surface) => surface !== null);
98
+ if (unsupported.length > 0) {
99
+ throw new SpawnfileError("validation_error", `Pi runtime only supports Moltnet surfaces in Spawnfile v0.1; unsupported surfaces: ${unsupported.join(", ")}`);
100
+ }
101
+ };
102
+ export const piAdapter = {
103
+ assertSupportedModelTarget(target) {
104
+ if (target.endpoint) {
105
+ if (target.provider !== "custom" && target.provider !== "local") {
106
+ throw new SpawnfileError("validation_error", "Pi runtime only supports endpoints on custom or local model providers");
107
+ }
108
+ if (target.auth.method === "none" || target.auth.method === "api_key") {
109
+ return;
110
+ }
111
+ throw new SpawnfileError("validation_error", `Pi runtime endpoint models only support none or api_key auth, got ${target.auth.method}`);
112
+ }
113
+ if (target.provider === "openai") {
114
+ if (target.auth.method === "api_key" || target.auth.method === "codex") {
115
+ return;
116
+ }
117
+ }
118
+ if (target.provider === "anthropic" && target.auth.method === "api_key") {
119
+ return;
120
+ }
121
+ if (target.provider === "anthropic" && target.auth.method === "claude-code") {
122
+ return;
123
+ }
124
+ throw new SpawnfileError("validation_error", `Pi runtime does not support model auth method ${target.auth.method} for provider ${target.provider}`);
125
+ },
126
+ assertSupportedSurfaces(surfaces) {
127
+ assertSupportedPiSurfaces(surfaces);
128
+ },
129
+ container: {
130
+ configFileName: PI_CONFIG_FILE,
131
+ configPathEnv: "SPAWNFILE_PI_CONFIG",
132
+ homeEnv: "SPAWNFILE_PI_HOME",
133
+ instancePaths: {
134
+ configPathTemplate: "<instance-root>/pi/<config-file>",
135
+ homePathTemplate: "<instance-root>/home",
136
+ sourceWorkspacePathTemplate: "<instance-root>/workspace/agents/<source-slug>",
137
+ workspacePathTemplate: "<instance-root>/workspace"
138
+ },
139
+ port: PI_CONTROL_PORT,
140
+ portEnv: "SPAWNFILE_PI_CONTROL_PORT",
141
+ standaloneBaseImage: "node:24-bookworm-slim",
142
+ startCommand: ["node", "<runtime-root>/app.mjs", "<config-path>"],
143
+ systemDeps: ["bash", "ca-certificates", "curl", "git", "procps"]
144
+ },
145
+ systemInstructionSurface: {
146
+ placement: "append_pointer",
147
+ resolvePath() {
148
+ return "workspace/AGENTS.md";
149
+ }
150
+ },
151
+ async compileAgent(node) {
152
+ const scheduleOutcome = scheduleOutcomeFor(node);
153
+ return {
154
+ capabilities: createAgentCapabilities(node, {
155
+ ...moltnetCapabilityOptions(node),
156
+ mcpOutcome: node.mcpServers.length > 0 ? "degraded" : "supported",
157
+ sandboxOutcome: node.execution?.sandbox ? "degraded" : "supported",
158
+ scheduleMessage: scheduleOutcome.message,
159
+ scheduleOutcome: scheduleOutcome.outcome,
160
+ subagentOutcome: node.subagents.length > 0 ? "degraded" : "supported"
161
+ }),
162
+ diagnostics: [
163
+ ...createScheduleDiagnostics(node),
164
+ ...(node.execution?.sandbox
165
+ ? [createDiagnostic("warn", "Pi runtime relies on container and workspace isolation; Pi itself is not a sandbox engine")]
166
+ : []),
167
+ ...(node.mcpServers.length > 0
168
+ ? [createDiagnostic("warn", "Pi runtime does not lower MCP server declarations in Spawnfile v0.1")]
169
+ : []),
170
+ ...(node.subagents.length > 0
171
+ ? [createDiagnostic("warn", "Pi runtime groups compiled agents but does not preserve native parent-owned subagent semantics in v0.1")]
172
+ : [])
173
+ ],
174
+ files: [
175
+ ...createDocumentFiles("workspace", node.docs),
176
+ ...createSkillFiles("workspace/skills", node.skills)
177
+ ]
178
+ };
179
+ },
180
+ async createContainerTargets(inputs) {
181
+ return createContainerTargets(inputs);
182
+ },
183
+ name: "pi",
184
+ prepareRuntimeAuth: preparePiRuntimeAuth,
185
+ validateRuntimeOptions(options) {
186
+ const diagnostics = [];
187
+ const unsupported = Object.keys(options).filter((key) => key !== "restrict_to_workspace");
188
+ for (const key of unsupported) {
189
+ diagnostics.push(createDiagnostic("warn", `Pi runtime option ${key} is not used yet`));
190
+ }
191
+ return diagnostics;
192
+ }
193
+ };
194
+ export const daimonAdapter = {
195
+ ...piAdapter,
196
+ name: "daimon"
197
+ };
198
+ export const PI_RUNTIME_PACKAGE = `${PI_PACKAGE_NAME}@${PI_PACKAGE_VERSION}`;
@@ -0,0 +1 @@
1
+ export declare const renderPiActivitySource: () => string;
@@ -0,0 +1,87 @@
1
+ export const renderPiActivitySource = () => String.raw `
2
+ const maxActivityEvents = 500;
3
+
4
+ const createActivityBroker = () => {
5
+ let sequence = 0;
6
+ const events = [];
7
+ const clients = new Set();
8
+
9
+ const normalizeFilter = (value) => typeof value === "string" && value.trim().length > 0
10
+ ? value.trim()
11
+ : "";
12
+ const matchesFilter = (event, filter) => {
13
+ const normalized = normalizeFilter(filter);
14
+ return normalized === "" ||
15
+ event.agent_id === normalized ||
16
+ event.agent_slug === normalized ||
17
+ event.agent_name === normalized ||
18
+ event.agent_id === "agent:" + normalized;
19
+ };
20
+ const parseTail = (value) => {
21
+ const parsed = Number(value);
22
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : maxActivityEvents;
23
+ };
24
+
25
+ const publish = (event) => {
26
+ const full = {
27
+ version: "spawnfile.activity.v1",
28
+ sequence: ++sequence,
29
+ created_at: new Date().toISOString(),
30
+ ...event
31
+ };
32
+ events.push(full);
33
+ if (events.length > maxActivityEvents) {
34
+ events.splice(0, events.length - maxActivityEvents);
35
+ }
36
+ const frame = "data: " + JSON.stringify(full) + "\n\n";
37
+ for (const client of [...clients]) {
38
+ if (!matchesFilter(full, client.filter)) {
39
+ continue;
40
+ }
41
+ try {
42
+ client.response.write(frame);
43
+ } catch {
44
+ clients.delete(client);
45
+ }
46
+ }
47
+ return full;
48
+ };
49
+
50
+ const list = (filter, tail) => {
51
+ const selected = events.filter((event) => matchesFilter(event, filter));
52
+ return selected.slice(Math.max(0, selected.length - parseTail(tail)));
53
+ };
54
+
55
+ const stream = (request, response, filter, tail) => {
56
+ response.writeHead(200, {
57
+ "cache-control": "no-cache",
58
+ "connection": "keep-alive",
59
+ "content-type": "text/event-stream"
60
+ });
61
+ response.write("event: ready\ndata: {\"status\":\"ok\"}\n\n");
62
+ for (const event of list(filter, tail)) {
63
+ response.write("data: " + JSON.stringify(event) + "\n\n");
64
+ }
65
+ const client = { filter: normalizeFilter(filter), response };
66
+ clients.add(client);
67
+ request.on("close", () => clients.delete(client));
68
+ };
69
+
70
+ return { list, publish, stream };
71
+ };
72
+
73
+ const redactActivityText = (value) => {
74
+ let redacted = String(value);
75
+ redacted = redacted.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi, "Bearer [REDACTED]");
76
+ redacted = redacted.replace(/\bmagt_v1_[A-Za-z0-9_-]{16,}\b/g, "[REDACTED]");
77
+ redacted = redacted.replace(/\b(?:sk|sk-proj)-[A-Za-z0-9_-]{20,}\b/g, "[REDACTED]");
78
+ redacted = redacted.replace(
79
+ /("([^"]*(?:api[_-]?key|token|secret|password)[^"]*)"\s*:\s*")([^"]+)(")/gi,
80
+ "$1[REDACTED]$4"
81
+ );
82
+ redacted = redacted.replace(/\/(?:Users|home|private|tmp|var|opt|run)\/[^\s"']+/g, "[path]");
83
+ return redacted.length > 1000 ? redacted.slice(0, 1000) + "..." : redacted;
84
+ };
85
+
86
+ const formatActivityError = (error) => redactActivityText(error instanceof Error ? error.message : String(error));
87
+ `;
@@ -0,0 +1 @@
1
+ export declare const renderPiCoreSource: () => string;