clawmini 0.0.8 → 0.0.9
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/.changeset/README.md +8 -0
- package/.changeset/config.json +14 -0
- package/.github/workflows/release.yml +49 -0
- package/CHANGELOG.md +36 -0
- package/README.md +5 -4
- package/dist/adapter-discord/index.d.mts.map +1 -1
- package/dist/adapter-discord/index.mjs +465 -282
- package/dist/adapter-discord/index.mjs.map +1 -1
- package/dist/adapter-google-chat/index.mjs +367 -243
- package/dist/adapter-google-chat/index.mjs.map +1 -1
- package/dist/cli/index.mjs +684 -24
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lite.mjs +43 -13
- package/dist/cli/lite.mjs.map +1 -1
- package/dist/cli/{propose-policy.mjs → manage-policies.mjs} +270 -47
- package/dist/cli/manage-policies.mjs.map +1 -0
- package/dist/cli/run-host.d.mts +1 -0
- package/dist/cli/run-host.mjs +3090 -0
- package/dist/cli/run-host.mjs.map +1 -0
- package/dist/config-CPFQIGdG.mjs +57 -0
- package/dist/config-CPFQIGdG.mjs.map +1 -0
- package/dist/config-Dvl-Pov4.mjs +76 -0
- package/dist/config-Dvl-Pov4.mjs.map +1 -0
- package/dist/daemon/index.d.mts.map +1 -1
- package/dist/daemon/index.mjs +970 -332
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/supervisor-actions-CiW56eLi.mjs +843 -0
- package/dist/supervisor-actions-CiW56eLi.mjs.map +1 -0
- package/dist/turn-log-buffer-DRgW53gl.mjs +767 -0
- package/dist/turn-log-buffer-DRgW53gl.mjs.map +1 -0
- package/dist/web/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
- package/dist/web/_app/immutable/chunks/BhRSsUCh.js +2 -0
- package/dist/web/_app/immutable/chunks/BiLeM2i1.js +1 -0
- package/{web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js → dist/web/_app/immutable/chunks/BmBj85Ll.js} +1 -1
- package/dist/web/_app/immutable/chunks/BrERcKAH.js +1 -0
- package/dist/web/_app/immutable/chunks/Bv9252RM.js +1 -0
- package/dist/web/_app/immutable/chunks/CIXNBPKi.js +1 -0
- package/dist/web/_app/immutable/chunks/DISKL3GN.js +2 -0
- package/dist/web/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
- package/dist/web/_app/immutable/chunks/DnQ3vS13.js +1 -0
- package/dist/web/_app/immutable/chunks/KsloHTKS.js +1 -0
- package/{web/.svelte-kit/output/client/_app/immutable/chunks/Ck-be5J2.js → dist/web/_app/immutable/chunks/RsHsUj-8.js} +2 -2
- package/dist/web/_app/immutable/chunks/{vDehDcuJ.js → wpfV79dV.js} +1 -1
- package/dist/web/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
- package/dist/web/_app/immutable/entry/start.Di0-Jhte.js +1 -0
- package/dist/web/_app/immutable/nodes/{0.CUGC2p-K.js → 0.DYyUA1au.js} +1 -1
- package/dist/web/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
- package/dist/web/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
- package/{web/.svelte-kit/output/client/_app/immutable/nodes/3.0arZe_Uf.js → dist/web/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
- package/dist/web/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
- package/dist/web/_app/immutable/nodes/{5.Bq2JzCEj.js → 5.DLbPVJY2.js} +1 -1
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +12 -12
- package/dist/workspace-oWmVh5mi.mjs +1001 -0
- package/dist/workspace-oWmVh5mi.mjs.map +1 -0
- package/docs/23_adapter_slash_autocomplete/development_log.md +19 -0
- package/docs/23_adapter_slash_autocomplete/notes.md +18 -0
- package/docs/23_adapter_slash_autocomplete/prd.md +46 -0
- package/docs/23_adapter_slash_autocomplete/questions.md +6 -0
- package/docs/23_adapter_slash_autocomplete/tickets.md +21 -0
- package/docs/24_subagent_job_policy_fixes/development_log.md +22 -0
- package/docs/24_subagent_job_policy_fixes/notes.md +28 -0
- package/docs/24_subagent_job_policy_fixes/prd.md +59 -0
- package/docs/24_subagent_job_policy_fixes/questions.md +3 -0
- package/docs/24_subagent_job_policy_fixes/tickets.md +49 -0
- package/docs/25_e2e_test_improvements/development_log.md +30 -0
- package/docs/25_e2e_test_improvements/notes.md +29 -0
- package/docs/25_e2e_test_improvements/prd.md +43 -0
- package/docs/25_e2e_test_improvements/questions.md +12 -0
- package/docs/25_e2e_test_improvements/tickets-2.md +22 -0
- package/docs/25_e2e_test_improvements/tickets.md +22 -0
- package/docs/25_policy_cwd/development_log.md +30 -0
- package/docs/25_policy_cwd/notes.md +28 -0
- package/docs/25_policy_cwd/prd.md +77 -0
- package/docs/25_policy_cwd/questions.md +6 -0
- package/docs/25_policy_cwd/tickets.md +77 -0
- package/docs/CLI_REFERENCE.md +3 -1
- package/docs/PHILOSOPHY.md +35 -0
- package/docs/adapter-visibility/SPEC.md +461 -0
- package/docs/adapter-visibility/SPEC_v2.md +202 -0
- package/docs/auto-update/SPEC.md +344 -0
- package/docs/backups/SPEC.md +296 -0
- package/docs/backups/clawmini.gitignore +69 -0
- package/docs/guides/assets/clawmini-avatar.png +0 -0
- package/docs/guides/backups.md +332 -0
- package/docs/guides/discord_adapter_setup.md +1 -1
- package/docs/guides/google_chat_adapter_setup.md +81 -0
- package/docs/unified-startup/SPEC.md +203 -0
- package/e2e/_helpers/test-environment.test.ts +49 -0
- package/e2e/_helpers/test-environment.ts +548 -0
- package/e2e/adapters/_google-chat-fixtures.ts +340 -0
- package/{src/cli/e2e → e2e/adapters}/adapter-discord.test.ts +22 -23
- package/e2e/adapters/adapter-google-chat-downtime.test.ts +157 -0
- package/e2e/adapters/adapter-google-chat-inbound.test.ts +697 -0
- package/e2e/adapters/adapter-google-chat-outbound.test.ts +297 -0
- package/e2e/adapters/adapter-google-chat-roundtrip.test.ts +56 -0
- package/e2e/adapters/adapter-google-chat-threads.test.ts +1078 -0
- package/e2e/agents/custom-api-env.test.ts +80 -0
- package/e2e/agents/export-lite-func.test.ts +104 -0
- package/e2e/agents/fallbacks.test.ts +124 -0
- package/e2e/agents/interrupt.test.ts +50 -0
- package/e2e/agents/no-reply-necessary.test.ts +57 -0
- package/e2e/agents/session-timeout-subagents.test.ts +76 -0
- package/e2e/agents/subagent-authorization.test.ts +246 -0
- package/e2e/agents/subagent-env.test.ts +49 -0
- package/e2e/agents/subagent-lifecycle.test.ts +782 -0
- package/e2e/agents/subagents-depth.test.ts +47 -0
- package/e2e/cli/agents.test.ts +176 -0
- package/e2e/cli/auto-update.test.ts +741 -0
- package/e2e/cli/basic.test.ts +44 -0
- package/{src/cli/e2e → e2e/cli}/export-lite.test.ts +16 -12
- package/e2e/cli/init-gitignore.test.ts +86 -0
- package/e2e/cli/init.test.ts +76 -0
- package/e2e/cli/messages.test.ts +363 -0
- package/e2e/cli/serve.test.ts +76 -0
- package/{src/cli/e2e → e2e/cli}/skills.test.ts +11 -10
- package/{src/cli/e2e → e2e/daemon}/daemon.test.ts +57 -195
- package/e2e/jobs/agent-jobs.test.ts +216 -0
- package/e2e/jobs/cron.test.ts +64 -0
- package/e2e/jobs/restart.test.ts +108 -0
- package/e2e/policies/approval-session.test.ts +69 -0
- package/e2e/policies/auto-create-policies-file.test.ts +35 -0
- package/e2e/policies/builtin-manage-policies.test.ts +184 -0
- package/e2e/policies/builtin-run-host.test.ts +180 -0
- package/e2e/policies/environment-policies.test.ts +177 -0
- package/e2e/policies/manage-policies.test.ts +566 -0
- package/e2e/policies/output-size.test.ts +98 -0
- package/e2e/policies/policies-context-cwd.test.ts +160 -0
- package/e2e/policies/relative-script-path.test.ts +60 -0
- package/e2e/policies/requests-show.test.ts +135 -0
- package/e2e/policies/requests.test.ts +208 -0
- package/e2e/policies/slash-policies.test.ts +308 -0
- package/e2e/policies/startup-cleanup.test.ts +48 -0
- package/e2e/routers/session-timeout.test.ts +106 -0
- package/e2e/routers/slash-model.test.ts +152 -0
- package/e2e/routers/slash-new.test.ts +50 -0
- package/e2e/routers/slash-restart-adapter.test.ts +96 -0
- package/e2e/routers/slash-restart.test.ts +114 -0
- package/e2e/routers/slash-shutdown.test.ts +55 -0
- package/e2e/routers/slash-stop.test.ts +232 -0
- package/e2e/routers/slash-upgrade.test.ts +88 -0
- package/{src/cli/e2e → e2e/sandbox}/environments.test.ts +14 -13
- package/eslint.config.js +6 -0
- package/napkin.md +1 -1
- package/package.json +8 -3
- package/src/adapter-discord/commands.test.ts +42 -0
- package/src/adapter-discord/commands.ts +33 -0
- package/src/adapter-discord/config.ts +12 -0
- package/src/adapter-discord/forwarder.test.ts +499 -21
- package/src/adapter-discord/forwarder.ts +343 -124
- package/src/adapter-discord/inbound-cache.test.ts +47 -0
- package/src/adapter-discord/inbound-cache.ts +37 -0
- package/src/adapter-discord/index.test.ts +67 -2
- package/src/adapter-discord/index.ts +84 -216
- package/src/adapter-discord/interactions.test.ts +54 -3
- package/src/adapter-discord/interactions.ts +97 -53
- package/src/adapter-discord/processMessage.ts +239 -0
- package/src/adapter-discord/state.ts +1 -0
- package/src/adapter-google-chat/auth.test.ts +9 -5
- package/src/adapter-google-chat/auth.ts +29 -23
- package/src/adapter-google-chat/cards.ts +7 -2
- package/src/adapter-google-chat/client.test.ts +37 -2
- package/src/adapter-google-chat/client.ts +138 -38
- package/src/adapter-google-chat/config.ts +19 -0
- package/src/adapter-google-chat/forwarder.test.ts +81 -56
- package/src/adapter-google-chat/forwarder.ts +394 -185
- package/src/adapter-google-chat/inbound-cache.test.ts +61 -0
- package/src/adapter-google-chat/inbound-cache.ts +36 -0
- package/src/adapter-google-chat/state.test.ts +1 -0
- package/src/adapter-google-chat/state.ts +9 -1
- package/src/adapter-google-chat/subscriptions.ts +8 -6
- package/src/cli/builtin-policies.ts +44 -0
- package/src/cli/commands/agents.ts +59 -5
- package/src/cli/commands/down.ts +54 -2
- package/src/cli/commands/environments.ts +8 -2
- package/src/cli/commands/init.ts +31 -0
- package/src/cli/commands/logs.ts +116 -0
- package/src/cli/commands/policies.ts +6 -4
- package/src/cli/commands/serve.test.ts +67 -0
- package/src/cli/commands/serve.ts +284 -0
- package/src/cli/commands/up.ts +122 -2
- package/src/cli/commands/web-api/agents.ts +3 -2
- package/src/cli/index.ts +4 -0
- package/src/cli/install-detection.test.ts +72 -0
- package/src/cli/install-detection.ts +48 -0
- package/src/cli/lite.ts +54 -22
- package/src/cli/manage-policies-utils.ts +104 -0
- package/src/cli/manage-policies.ts +291 -0
- package/src/cli/run-host.ts +45 -0
- package/src/cli/supervisor-actions.ts +267 -0
- package/src/cli/supervisor-control.test.ts +129 -0
- package/src/cli/supervisor-control.ts +155 -0
- package/src/cli/supervisor-pid.ts +68 -0
- package/src/cli/supervisor.ts +277 -0
- package/src/daemon/agent/agent-context.ts +11 -11
- package/src/daemon/agent/agent-session.ts +8 -1
- package/src/daemon/agent/chat-logger.test.ts +78 -9
- package/src/daemon/agent/chat-logger.ts +25 -5
- package/src/daemon/agent/turn-registry.test.ts +89 -0
- package/src/daemon/agent/turn-registry.ts +94 -0
- package/src/daemon/agent/types.ts +2 -0
- package/src/daemon/api/agent-policy-endpoints.ts +263 -0
- package/src/daemon/api/agent-router.ts +47 -126
- package/src/daemon/api/index.test.ts +1 -0
- package/src/daemon/api/policy-request.test.ts +7 -5
- package/src/daemon/api/router-utils.ts +6 -5
- package/src/daemon/api/subagent-router.ts +110 -74
- package/src/daemon/api/subagent-utils.test.ts +60 -0
- package/src/daemon/api/subagent-utils.ts +113 -87
- package/src/daemon/api/user-router.ts +34 -8
- package/src/daemon/auth.ts +1 -0
- package/src/daemon/cron.test.ts +62 -4
- package/src/daemon/cron.ts +42 -16
- package/src/daemon/events.ts +65 -0
- package/src/daemon/index.ts +24 -1
- package/src/daemon/message-interruption.test.ts +1 -0
- package/src/daemon/message-jobs.test.ts +1 -0
- package/src/daemon/message.ts +78 -14
- package/src/daemon/observation.test.ts +26 -18
- package/src/daemon/pending-replies.test.ts +112 -0
- package/src/daemon/pending-replies.ts +162 -0
- package/src/daemon/policy-request-service.ts +3 -1
- package/src/daemon/policy-utils.test.ts +66 -1
- package/src/daemon/policy-utils.ts +126 -1
- package/src/daemon/request-store.ts +31 -0
- package/src/daemon/routers/session-timeout.ts +4 -0
- package/src/daemon/routers/slash-model.test.ts +344 -0
- package/src/daemon/routers/slash-model.ts +207 -0
- package/src/daemon/routers/slash-policies.test.ts +38 -32
- package/src/daemon/routers/slash-policies.ts +84 -33
- package/src/daemon/routers/slash-restart.test.ts +69 -0
- package/src/daemon/routers/slash-restart.ts +36 -0
- package/src/daemon/routers/slash-shutdown.test.ts +50 -0
- package/src/daemon/routers/slash-shutdown.ts +28 -0
- package/src/daemon/routers/slash-upgrade.test.ts +116 -0
- package/src/daemon/routers/slash-upgrade.ts +76 -0
- package/src/daemon/routers/types.ts +7 -0
- package/src/daemon/routers.ts +16 -0
- package/src/shared/adapters/blockquote.test.ts +28 -0
- package/src/shared/adapters/blockquote.ts +20 -0
- package/src/shared/adapters/filtering.test.ts +224 -10
- package/src/shared/adapters/filtering.ts +95 -7
- package/src/shared/adapters/inbound-cache.test.ts +48 -0
- package/src/shared/adapters/inbound-cache.ts +54 -0
- package/src/shared/adapters/turn-log-buffer.ts +266 -0
- package/src/shared/adapters/turn-log.test.ts +389 -0
- package/src/shared/adapters/turn-log.ts +357 -0
- package/src/shared/agent-utils.ts +12 -5
- package/src/shared/chats.test.ts +4 -0
- package/src/shared/chats.ts +9 -0
- package/src/shared/config.ts +16 -1
- package/src/shared/lite.ts +76 -2
- package/src/shared/policies.ts +26 -0
- package/src/shared/template-manifest.ts +267 -0
- package/src/shared/utils/shell.ts +61 -0
- package/src/shared/version.ts +34 -0
- package/src/shared/workspace.test.ts +217 -0
- package/src/shared/workspace.ts +626 -48
- package/templates/environments/cladding/allowlist-domain.mjs +125 -0
- package/templates/environments/cladding/env.json +21 -1
- package/templates/environments/cladding/run-with-network.mjs +54 -0
- package/templates/environments/macos-proxy/allowlist-domain.mjs +95 -0
- package/templates/environments/macos-proxy/env.json +8 -1
- package/templates/environments/macos-proxy/proxy.mjs +0 -1
- package/templates/gemini/template.json +5 -0
- package/templates/gemini-claw/template.json +13 -0
- package/templates/skills/clawmini-requests/SKILL.md +69 -10
- package/templates/skills/run-host/SKILL.md +51 -0
- package/templates/skills/skill-creator/SKILL.md +4 -3
- package/templates/skills/skill-creator/scripts/validate.sh +52 -0
- package/tsdown.config.ts +10 -1
- package/vitest.config.ts +2 -2
- package/web/.svelte-kit/ambient.d.ts +292 -118
- package/web/.svelte-kit/generated/server/internal.js +1 -1
- package/web/.svelte-kit/output/client/.vite/manifest.json +126 -136
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BhRSsUCh.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BiLeM2i1.js +1 -0
- package/{dist/web/_app/immutable/chunks/CME08kGM.js → web/.svelte-kit/output/client/_app/immutable/chunks/BmBj85Ll.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BrERcKAH.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Bv9252RM.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CIXNBPKi.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DISKL3GN.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DnQ3vS13.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/KsloHTKS.js +1 -0
- package/{dist/web/_app/immutable/chunks/Ck-be5J2.js → web/.svelte-kit/output/client/_app/immutable/chunks/RsHsUj-8.js} +2 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{vDehDcuJ.js → wpfV79dV.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.Di0-Jhte.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.CUGC2p-K.js → 0.DYyUA1au.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
- package/{dist/web/_app/immutable/nodes/3.0arZe_Uf.js → web/.svelte-kit/output/client/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.Bq2JzCEj.js → 5.DLbPVJY2.js} +1 -1
- package/web/.svelte-kit/output/client/_app/version.json +1 -1
- package/web/.svelte-kit/output/server/.vite/manifest.json +12 -10
- package/web/.svelte-kit/output/server/chunks/Icon.js +1 -1
- package/web/.svelte-kit/output/server/chunks/client.js +1 -1
- package/web/.svelte-kit/output/server/chunks/exports.js +1 -1
- package/web/.svelte-kit/output/server/chunks/index-server.js +2 -1
- package/web/.svelte-kit/output/server/chunks/internal.js +1 -1
- package/web/.svelte-kit/output/server/chunks/render-context.js +77 -0
- package/web/.svelte-kit/output/server/chunks/root.js +739 -788
- package/web/.svelte-kit/output/server/chunks/shared.js +234 -21
- package/web/.svelte-kit/output/server/index.js +126 -90
- package/web/.svelte-kit/output/server/manifest-full.js +1 -1
- package/web/.svelte-kit/output/server/manifest.js +1 -1
- package/web/.svelte-kit/output/server/nodes/0.js +1 -1
- package/web/.svelte-kit/output/server/nodes/1.js +1 -1
- package/web/.svelte-kit/output/server/nodes/2.js +1 -1
- package/web/.svelte-kit/output/server/nodes/3.js +1 -1
- package/web/.svelte-kit/output/server/nodes/4.js +1 -1
- package/web/.svelte-kit/output/server/nodes/5.js +1 -1
- package/web/.svelte-kit/output/server/remote-entry.js +245 -81
- package/web/.svelte-kit/tsconfig.json +4 -1
- package/dist/cli/propose-policy.mjs.map +0 -1
- package/dist/lite-CBxOT1y5.mjs +0 -241
- package/dist/lite-CBxOT1y5.mjs.map +0 -1
- package/dist/routing-D8rTxtaV.mjs +0 -245
- package/dist/routing-D8rTxtaV.mjs.map +0 -1
- package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +0 -1
- package/dist/web/_app/immutable/chunks/BmRlVmv6.js +0 -1
- package/dist/web/_app/immutable/chunks/CK9JZLaG.js +0 -2
- package/dist/web/_app/immutable/chunks/Ck3rYNON.js +0 -1
- package/dist/web/_app/immutable/chunks/D5iV40bG.js +0 -1
- package/dist/web/_app/immutable/chunks/DMtIqaiV.js +0 -2
- package/dist/web/_app/immutable/chunks/DhD271EB.js +0 -1
- package/dist/web/_app/immutable/chunks/DpuLqk8d.js +0 -1
- package/dist/web/_app/immutable/chunks/DsIToJCP.js +0 -1
- package/dist/web/_app/immutable/entry/app.BCSV3nrG.js +0 -2
- package/dist/web/_app/immutable/entry/start.D4eLEZUM.js +0 -1
- package/dist/web/_app/immutable/nodes/1.CGC_42IQ.js +0 -1
- package/dist/web/_app/immutable/nodes/4.ClM1bXLE.js +0 -60
- package/dist/workspace-BJmJBfKi.mjs +0 -456
- package/dist/workspace-BJmJBfKi.mjs.map +0 -1
- package/src/cli/e2e/agents.test.ts +0 -140
- package/src/cli/e2e/basic.test.ts +0 -43
- package/src/cli/e2e/cron.test.ts +0 -132
- package/src/cli/e2e/export-lite-func.test.ts +0 -206
- package/src/cli/e2e/fallbacks.test.ts +0 -175
- package/src/cli/e2e/init.test.ts +0 -77
- package/src/cli/e2e/messages.test.ts +0 -332
- package/src/cli/e2e/propose-policy.test.ts +0 -203
- package/src/cli/e2e/requests.test.ts +0 -180
- package/src/cli/e2e/session-timeout.test.ts +0 -192
- package/src/cli/e2e/slash-new.test.ts +0 -93
- package/src/cli/e2e/subagents.test.ts +0 -106
- package/src/cli/e2e/utils.ts +0 -66
- package/src/cli/propose-policy.ts +0 -91
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BmRlVmv6.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/D5iV40bG.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DhD271EB.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DpuLqk8d.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.BCSV3nrG.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.D4eLEZUM.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.CGC_42IQ.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.ClM1bXLE.js +0 -60
- package/web/.svelte-kit/output/server/chunks/false.js +0 -4
- /package/dist/cli/{propose-policy.d.mts → manage-policies.d.mts} +0 -0
- /package/{src/cli/e2e → e2e/_helpers}/global-setup.ts +0 -0
|
@@ -0,0 +1,843 @@
|
|
|
1
|
+
import { C as readSettings, F as pathIsInsideDir, g as getWorkspaceRoot, m as getSettingsPath, u as getClawminiDir, x as readEnvironment } from "./workspace-oWmVh5mi.mjs";
|
|
2
|
+
import fs, { existsSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
6
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
7
|
+
import fsPromises from "node:fs/promises";
|
|
8
|
+
import net from "node:net";
|
|
9
|
+
import { EventEmitter } from "node:events";
|
|
10
|
+
|
|
11
|
+
//#region src/shared/chats.ts
|
|
12
|
+
const DEFAULT_CHAT_ID = "default";
|
|
13
|
+
async function getChatsDir(startDir = process.cwd()) {
|
|
14
|
+
const dir = path.join(getClawminiDir(startDir), "chats");
|
|
15
|
+
if (!existsSync(dir)) await fsPromises.mkdir(dir, { recursive: true });
|
|
16
|
+
return dir;
|
|
17
|
+
}
|
|
18
|
+
function isValidChatId(chatId) {
|
|
19
|
+
if (!chatId || chatId.length === 0) return false;
|
|
20
|
+
return /^[a-zA-Z0-9_-]+$/.test(chatId);
|
|
21
|
+
}
|
|
22
|
+
function assertValidChatId(id) {
|
|
23
|
+
if (!isValidChatId(id)) throw new Error(`Invalid chat ID: ${id}`);
|
|
24
|
+
}
|
|
25
|
+
async function createChat(id, startDir = process.cwd()) {
|
|
26
|
+
assertValidChatId(id);
|
|
27
|
+
const chatsDir = await getChatsDir(startDir);
|
|
28
|
+
const chatDir = path.join(chatsDir, id);
|
|
29
|
+
if (!existsSync(chatDir)) await fsPromises.mkdir(chatDir, { recursive: true });
|
|
30
|
+
const chatFile = path.join(chatDir, "chat.jsonl");
|
|
31
|
+
if (!existsSync(chatFile)) await fsPromises.writeFile(chatFile, "");
|
|
32
|
+
}
|
|
33
|
+
async function listChats(startDir = process.cwd()) {
|
|
34
|
+
const chatsDir = await getChatsDir(startDir);
|
|
35
|
+
try {
|
|
36
|
+
return (await fsPromises.readdir(chatsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
37
|
+
} catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function deleteChat(id, startDir = process.cwd()) {
|
|
42
|
+
assertValidChatId(id);
|
|
43
|
+
const chatsDir = await getChatsDir(startDir);
|
|
44
|
+
const chatDir = path.join(chatsDir, id);
|
|
45
|
+
if (!pathIsInsideDir(chatDir, chatsDir)) throw new Error(`Security Error: Cannot delete chat directory outside of ${chatsDir}`);
|
|
46
|
+
if (existsSync(chatDir)) await fsPromises.rm(chatDir, {
|
|
47
|
+
recursive: true,
|
|
48
|
+
force: true
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async function appendMessage$1(id, message, startDir = process.cwd()) {
|
|
52
|
+
assertValidChatId(id);
|
|
53
|
+
const chatsDir = await getChatsDir(startDir);
|
|
54
|
+
const chatDir = path.join(chatsDir, id);
|
|
55
|
+
if (!existsSync(chatDir)) await createChat(id, startDir);
|
|
56
|
+
const chatFile = path.join(chatDir, "chat.jsonl");
|
|
57
|
+
await fsPromises.appendFile(chatFile, JSON.stringify(message) + "\n");
|
|
58
|
+
}
|
|
59
|
+
async function* readLinesBackwards(filePath) {
|
|
60
|
+
const fd = await fsPromises.open(filePath, "r");
|
|
61
|
+
try {
|
|
62
|
+
const stats = await fd.stat();
|
|
63
|
+
if (stats.size === 0) return;
|
|
64
|
+
const chunkSize = 64 * 1024;
|
|
65
|
+
let position = stats.size;
|
|
66
|
+
const buffer = Buffer.alloc(chunkSize);
|
|
67
|
+
let leftoverBuffer = Buffer.alloc(0);
|
|
68
|
+
while (position > 0) {
|
|
69
|
+
const readSize = Math.min(chunkSize, position);
|
|
70
|
+
position -= readSize;
|
|
71
|
+
const { bytesRead } = await fd.read(buffer, 0, readSize, position);
|
|
72
|
+
const currentChunk = buffer.subarray(0, bytesRead);
|
|
73
|
+
let combinedBuffer = Buffer.concat([currentChunk, leftoverBuffer]);
|
|
74
|
+
let lastNewlineIdx = combinedBuffer.lastIndexOf(10);
|
|
75
|
+
while (lastNewlineIdx !== -1) {
|
|
76
|
+
const line = combinedBuffer.subarray(lastNewlineIdx + 1).toString("utf8").trim();
|
|
77
|
+
if (line) yield line;
|
|
78
|
+
combinedBuffer = combinedBuffer.subarray(0, lastNewlineIdx);
|
|
79
|
+
lastNewlineIdx = combinedBuffer.lastIndexOf(10);
|
|
80
|
+
}
|
|
81
|
+
leftoverBuffer = combinedBuffer;
|
|
82
|
+
}
|
|
83
|
+
if (leftoverBuffer.length > 0) {
|
|
84
|
+
const line = leftoverBuffer.toString("utf8").trim();
|
|
85
|
+
if (line) yield line;
|
|
86
|
+
}
|
|
87
|
+
} finally {
|
|
88
|
+
await fd.close();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function parseChatMessage(line) {
|
|
92
|
+
try {
|
|
93
|
+
const msg = JSON.parse(line);
|
|
94
|
+
if (msg && msg.role === "log") msg.role = "legacy_log";
|
|
95
|
+
return msg;
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function getMessages(id, limit, startDir = process.cwd(), predicate, before) {
|
|
101
|
+
assertValidChatId(id);
|
|
102
|
+
const chatsDir = await getChatsDir(startDir);
|
|
103
|
+
const chatFile = path.join(chatsDir, id, "chat.jsonl");
|
|
104
|
+
if (!existsSync(chatFile)) throw new Error(`Chat directory or file for '${id}' not found.`);
|
|
105
|
+
limit = limit ?? 100;
|
|
106
|
+
if (limit <= 0) {
|
|
107
|
+
let messages = (await fsPromises.readFile(chatFile, "utf8")).split("\n").filter((line) => line.trim() !== "").map((line) => parseChatMessage(line)).filter((msg) => msg !== null);
|
|
108
|
+
if (before) {
|
|
109
|
+
const beforeIndex = messages.findIndex((m) => m.id === before);
|
|
110
|
+
if (beforeIndex !== -1) messages = messages.slice(0, beforeIndex);
|
|
111
|
+
else messages = [];
|
|
112
|
+
}
|
|
113
|
+
if (predicate) messages = messages.filter(predicate);
|
|
114
|
+
return messages;
|
|
115
|
+
}
|
|
116
|
+
const messages = [];
|
|
117
|
+
let skipping = before !== void 0;
|
|
118
|
+
for await (const line of readLinesBackwards(chatFile)) try {
|
|
119
|
+
const msg = parseChatMessage(line);
|
|
120
|
+
if (!msg) continue;
|
|
121
|
+
if (skipping) {
|
|
122
|
+
if (msg.id === before) skipping = false;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (!predicate || predicate(msg)) {
|
|
126
|
+
messages.push(msg);
|
|
127
|
+
if (messages.length >= limit) break;
|
|
128
|
+
}
|
|
129
|
+
} catch {}
|
|
130
|
+
return messages.reverse();
|
|
131
|
+
}
|
|
132
|
+
async function getDefaultChatId(startDir = process.cwd()) {
|
|
133
|
+
const settingsPath = getSettingsPath(startDir);
|
|
134
|
+
if (!existsSync(settingsPath)) return DEFAULT_CHAT_ID;
|
|
135
|
+
try {
|
|
136
|
+
const content = await fsPromises.readFile(settingsPath, "utf8");
|
|
137
|
+
return JSON.parse(content).chats?.defaultId || DEFAULT_CHAT_ID;
|
|
138
|
+
} catch {
|
|
139
|
+
return DEFAULT_CHAT_ID;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function setDefaultChatId(id, startDir = process.cwd()) {
|
|
143
|
+
assertValidChatId(id);
|
|
144
|
+
const settingsPath = getSettingsPath(startDir);
|
|
145
|
+
let settings = {};
|
|
146
|
+
if (existsSync(settingsPath)) try {
|
|
147
|
+
const content = await fsPromises.readFile(settingsPath, "utf8");
|
|
148
|
+
settings = JSON.parse(content);
|
|
149
|
+
} catch {}
|
|
150
|
+
if (!settings.chats) settings.chats = {};
|
|
151
|
+
settings.chats.defaultId = id;
|
|
152
|
+
const clawminiDir = getClawminiDir(startDir);
|
|
153
|
+
if (!existsSync(clawminiDir)) await fsPromises.mkdir(clawminiDir, { recursive: true });
|
|
154
|
+
await fsPromises.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
155
|
+
}
|
|
156
|
+
async function findLastMessage(id, predicate, startDir = process.cwd()) {
|
|
157
|
+
assertValidChatId(id);
|
|
158
|
+
const chatsDir = await getChatsDir(startDir);
|
|
159
|
+
const chatFile = path.join(chatsDir, id, "chat.jsonl");
|
|
160
|
+
if (!existsSync(chatFile)) return null;
|
|
161
|
+
for await (const line of readLinesBackwards(chatFile)) try {
|
|
162
|
+
const msg = parseChatMessage(line);
|
|
163
|
+
if (!msg) continue;
|
|
164
|
+
if (predicate(msg)) return msg;
|
|
165
|
+
} catch {}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/shared/lite.ts
|
|
171
|
+
const LITE_MARKER = "clawmini-lite";
|
|
172
|
+
function sha256(content) {
|
|
173
|
+
return createHash("sha256").update(content).digest("hex");
|
|
174
|
+
}
|
|
175
|
+
function looksLikeLiteScript(content) {
|
|
176
|
+
return content.startsWith("#!") && content.includes(LITE_MARKER);
|
|
177
|
+
}
|
|
178
|
+
async function resolveCompiledScript(scriptName, metaUrl) {
|
|
179
|
+
const __dirname = path.dirname(fileURLToPath(metaUrl));
|
|
180
|
+
const filename = scriptName.endsWith(".mjs") ? scriptName : `${scriptName}.mjs`;
|
|
181
|
+
const searchPaths = [
|
|
182
|
+
path.resolve(__dirname, `cli/${filename}`),
|
|
183
|
+
path.resolve(__dirname, filename),
|
|
184
|
+
path.resolve(__dirname, `../cli/${filename}`),
|
|
185
|
+
path.resolve(__dirname, `../../dist/cli/${filename}`),
|
|
186
|
+
path.resolve(__dirname, `../${filename}`),
|
|
187
|
+
path.resolve(__dirname, `../../${filename}`)
|
|
188
|
+
];
|
|
189
|
+
for (const scriptPath of searchPaths) try {
|
|
190
|
+
await fsPromises.access(scriptPath);
|
|
191
|
+
return scriptPath;
|
|
192
|
+
} catch {}
|
|
193
|
+
throw new Error(`Could not find compiled script: ${filename}`);
|
|
194
|
+
}
|
|
195
|
+
async function getLiteScriptContent() {
|
|
196
|
+
let liteScriptContent;
|
|
197
|
+
const liteScriptPath = await resolveCompiledScript("lite", import.meta.url);
|
|
198
|
+
liteScriptContent = await fsPromises.readFile(liteScriptPath, "utf8");
|
|
199
|
+
if (!liteScriptContent.startsWith("#!")) liteScriptContent = "#!/usr/bin/env node\n" + liteScriptContent;
|
|
200
|
+
return liteScriptContent;
|
|
201
|
+
}
|
|
202
|
+
async function writeLiteScript(outPath) {
|
|
203
|
+
const content = await getLiteScriptContent();
|
|
204
|
+
let finalPath = outPath;
|
|
205
|
+
const isDir = finalPath.endsWith(path.sep) || !(path.extname(finalPath) === ".js" || path.extname(finalPath) === ".mjs" || path.basename(finalPath) === "clawmini-lite");
|
|
206
|
+
try {
|
|
207
|
+
if ((await fsPromises.stat(finalPath)).isDirectory()) finalPath = path.join(finalPath, "clawmini-lite.js");
|
|
208
|
+
} catch {
|
|
209
|
+
if (isDir && !path.extname(finalPath) && !finalPath.endsWith("clawmini-lite") && !finalPath.endsWith("clawmini-lite.js")) {
|
|
210
|
+
await fsPromises.mkdir(finalPath, { recursive: true });
|
|
211
|
+
finalPath = path.join(finalPath, "clawmini-lite.js");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const dir = path.dirname(finalPath);
|
|
215
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
216
|
+
await fsPromises.writeFile(finalPath, content, { mode: 493 });
|
|
217
|
+
return finalPath;
|
|
218
|
+
}
|
|
219
|
+
async function resolveLiteTargetPath(outPath) {
|
|
220
|
+
const isProbablyFile = path.extname(outPath) === ".js" || path.extname(outPath) === ".mjs" || path.basename(outPath) === "clawmini-lite";
|
|
221
|
+
try {
|
|
222
|
+
if ((await fsPromises.stat(outPath)).isDirectory()) return path.join(outPath, "clawmini-lite.js");
|
|
223
|
+
return outPath;
|
|
224
|
+
} catch {
|
|
225
|
+
if (isProbablyFile) return outPath;
|
|
226
|
+
return path.join(outPath, "clawmini-lite.js");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function refreshLiteAt(outPath, opts = {}) {
|
|
230
|
+
const content = await getLiteScriptContent();
|
|
231
|
+
const finalPath = await resolveLiteTargetPath(outPath);
|
|
232
|
+
let existing = null;
|
|
233
|
+
try {
|
|
234
|
+
existing = await fsPromises.readFile(finalPath, "utf8");
|
|
235
|
+
} catch {}
|
|
236
|
+
if (existing !== null) {
|
|
237
|
+
if (sha256(existing) === sha256(content)) return {
|
|
238
|
+
status: "unchanged",
|
|
239
|
+
path: finalPath
|
|
240
|
+
};
|
|
241
|
+
if (!looksLikeLiteScript(existing)) {
|
|
242
|
+
const label = opts.label ? ` (${opts.label})` : "";
|
|
243
|
+
console.warn(`Refusing to overwrite ${finalPath}${label}: existing file is not a clawmini-lite script`);
|
|
244
|
+
return {
|
|
245
|
+
status: "refused",
|
|
246
|
+
path: finalPath
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const dir = path.dirname(finalPath);
|
|
251
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
252
|
+
await fsPromises.writeFile(finalPath, content, { mode: 493 });
|
|
253
|
+
return {
|
|
254
|
+
status: "written",
|
|
255
|
+
path: finalPath
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
async function exportLiteToEnvironment(envName, envConfig, affectedDir) {
|
|
259
|
+
if (!envConfig?.exportLiteTo) return false;
|
|
260
|
+
const finalExportPath = path.resolve(affectedDir, envConfig.exportLiteTo);
|
|
261
|
+
if (!finalExportPath.startsWith(affectedDir + path.sep) && finalExportPath !== affectedDir && !finalExportPath.startsWith(affectedDir + "/")) {
|
|
262
|
+
console.warn(`Skipping export for environment '${envName}': exportLiteTo path '${envConfig.exportLiteTo}' escapes the environment target directory '${affectedDir}'`);
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const result = await refreshLiteAt(finalExportPath, { label: `Environment: ${envName}` });
|
|
267
|
+
if (result.status === "written") console.log(`Successfully exported clawmini-lite to ${result.path} (Environment: ${envName})`);
|
|
268
|
+
else if (result.status === "refused") return false;
|
|
269
|
+
return true;
|
|
270
|
+
} catch (err) {
|
|
271
|
+
console.error(`Failed to export clawmini-lite to ${finalExportPath} (Environment: ${envName}): ${err instanceof Error ? err.message : String(err)}`);
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async function exportLiteToAllEnvironments(startDir = process.cwd()) {
|
|
276
|
+
let exportedToEnvironments = false;
|
|
277
|
+
try {
|
|
278
|
+
const workspaceRoot = getWorkspaceRoot(startDir);
|
|
279
|
+
const settings = await readSettings(workspaceRoot);
|
|
280
|
+
if (settings?.environments) for (const [envPath, envName] of Object.entries(settings.environments)) {
|
|
281
|
+
const envConfig = await readEnvironment(envName, workspaceRoot);
|
|
282
|
+
if (envConfig) {
|
|
283
|
+
if (await exportLiteToEnvironment(envName, envConfig, path.resolve(workspaceRoot, envPath))) exportedToEnvironments = true;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
} catch {}
|
|
287
|
+
return exportedToEnvironments;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/cli/supervisor-pid.ts
|
|
292
|
+
function getSupervisorPidPath(startDir = process.cwd()) {
|
|
293
|
+
return path.join(getClawminiDir(startDir), "supervisor.pid");
|
|
294
|
+
}
|
|
295
|
+
function getProcessStartTime(pid) {
|
|
296
|
+
try {
|
|
297
|
+
const trimmed = execFileSync("ps", [
|
|
298
|
+
"-p",
|
|
299
|
+
String(pid),
|
|
300
|
+
"-o",
|
|
301
|
+
"lstart="
|
|
302
|
+
], {
|
|
303
|
+
encoding: "utf-8",
|
|
304
|
+
stdio: [
|
|
305
|
+
"ignore",
|
|
306
|
+
"pipe",
|
|
307
|
+
"ignore"
|
|
308
|
+
]
|
|
309
|
+
}).trim();
|
|
310
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
311
|
+
} catch {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function readSupervisorPid(startDir = process.cwd()) {
|
|
316
|
+
const p = getSupervisorPidPath(startDir);
|
|
317
|
+
if (!fs.existsSync(p)) return null;
|
|
318
|
+
const content = fs.readFileSync(p, "utf-8").trim();
|
|
319
|
+
const sep = content.indexOf(":");
|
|
320
|
+
if (sep <= 0) return null;
|
|
321
|
+
const pid = parseInt(content.slice(0, sep), 10);
|
|
322
|
+
const storedStart = content.slice(sep + 1).trim();
|
|
323
|
+
if (!Number.isFinite(pid) || pid <= 0 || storedStart.length === 0) return null;
|
|
324
|
+
try {
|
|
325
|
+
process.kill(pid, 0);
|
|
326
|
+
} catch {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
const currentStart = getProcessStartTime(pid);
|
|
330
|
+
if (currentStart === null || currentStart !== storedStart) return null;
|
|
331
|
+
return pid;
|
|
332
|
+
}
|
|
333
|
+
function writeSupervisorPid(pid, startDir = process.cwd()) {
|
|
334
|
+
const startTime = getProcessStartTime(pid);
|
|
335
|
+
if (!startTime) throw new Error(`Cannot read start time for pid ${pid}; refusing to write supervisor.pid`);
|
|
336
|
+
fs.writeFileSync(getSupervisorPidPath(startDir), `${pid}:${startTime}`);
|
|
337
|
+
}
|
|
338
|
+
function removeSupervisorPid(startDir = process.cwd()) {
|
|
339
|
+
const p = getSupervisorPidPath(startDir);
|
|
340
|
+
if (fs.existsSync(p)) try {
|
|
341
|
+
fs.unlinkSync(p);
|
|
342
|
+
} catch {}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
//#endregion
|
|
346
|
+
//#region src/cli/install-detection.ts
|
|
347
|
+
function realpathOrNull(p) {
|
|
348
|
+
try {
|
|
349
|
+
return fs.realpathSync(p);
|
|
350
|
+
} catch {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function getNpmRootGlobal() {
|
|
355
|
+
try {
|
|
356
|
+
return execFileSync("npm", ["root", "-g"], {
|
|
357
|
+
encoding: "utf-8",
|
|
358
|
+
stdio: [
|
|
359
|
+
"ignore",
|
|
360
|
+
"pipe",
|
|
361
|
+
"ignore"
|
|
362
|
+
]
|
|
363
|
+
}).trim() || null;
|
|
364
|
+
} catch {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function detectInstall(entryPath = process.argv[1] ?? "") {
|
|
369
|
+
const entryRealPath = realpathOrNull(entryPath) ?? entryPath;
|
|
370
|
+
const npmRoot = getNpmRootGlobal();
|
|
371
|
+
const npmRootRealPath = npmRoot ? realpathOrNull(npmRoot) ?? npmRoot : null;
|
|
372
|
+
let isNpmGlobal = false;
|
|
373
|
+
if (npmRootRealPath) {
|
|
374
|
+
const rootWithSep = npmRootRealPath.endsWith(path.sep) ? npmRootRealPath : npmRootRealPath + path.sep;
|
|
375
|
+
isNpmGlobal = entryRealPath === npmRootRealPath || entryRealPath.startsWith(rootWithSep);
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
isNpmGlobal,
|
|
379
|
+
entryRealPath,
|
|
380
|
+
npmRootRealPath
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/cli/supervisor-control.ts
|
|
386
|
+
function getControlSocketPath(startDir = process.cwd()) {
|
|
387
|
+
return path.join(getClawminiDir(startDir), "super.sock");
|
|
388
|
+
}
|
|
389
|
+
function startControlServer(handlers, socketPath = getControlSocketPath()) {
|
|
390
|
+
if (fs.existsSync(socketPath)) try {
|
|
391
|
+
fs.unlinkSync(socketPath);
|
|
392
|
+
} catch {}
|
|
393
|
+
const server = net.createServer((socket) => {
|
|
394
|
+
let buf = "";
|
|
395
|
+
let handled = false;
|
|
396
|
+
const respond = (res) => {
|
|
397
|
+
if (handled) return;
|
|
398
|
+
handled = true;
|
|
399
|
+
socket.end(JSON.stringify(res) + "\n");
|
|
400
|
+
};
|
|
401
|
+
socket.on("data", (chunk) => {
|
|
402
|
+
if (handled) return;
|
|
403
|
+
buf += chunk.toString();
|
|
404
|
+
const idx = buf.indexOf("\n");
|
|
405
|
+
if (idx === -1) return;
|
|
406
|
+
const line = buf.slice(0, idx);
|
|
407
|
+
let req;
|
|
408
|
+
try {
|
|
409
|
+
req = JSON.parse(line);
|
|
410
|
+
} catch {
|
|
411
|
+
respond({
|
|
412
|
+
ok: false,
|
|
413
|
+
error: "invalid request"
|
|
414
|
+
});
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const handler = handlers[req.action];
|
|
418
|
+
if (!handler) {
|
|
419
|
+
respond({
|
|
420
|
+
ok: false,
|
|
421
|
+
error: `unknown action: ${req.action}`
|
|
422
|
+
});
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
Promise.resolve().then(() => handler(req)).then((res) => respond(res), (err) => respond({
|
|
426
|
+
ok: false,
|
|
427
|
+
error: err instanceof Error ? err.message : String(err)
|
|
428
|
+
}));
|
|
429
|
+
});
|
|
430
|
+
socket.on("error", () => {});
|
|
431
|
+
});
|
|
432
|
+
server.listen(socketPath, () => {
|
|
433
|
+
try {
|
|
434
|
+
fs.chmodSync(socketPath, 384);
|
|
435
|
+
} catch {}
|
|
436
|
+
});
|
|
437
|
+
return server;
|
|
438
|
+
}
|
|
439
|
+
function sendControlRequest(req, socketPath = getControlSocketPath(), timeoutMs = 5e3) {
|
|
440
|
+
return new Promise((resolve, reject) => {
|
|
441
|
+
const socket = net.createConnection({ path: socketPath });
|
|
442
|
+
let buf = "";
|
|
443
|
+
let settled = false;
|
|
444
|
+
const finish = (fn) => {
|
|
445
|
+
if (settled) return;
|
|
446
|
+
settled = true;
|
|
447
|
+
try {
|
|
448
|
+
socket.destroy();
|
|
449
|
+
} catch {}
|
|
450
|
+
fn();
|
|
451
|
+
};
|
|
452
|
+
const timer = setTimeout(() => {
|
|
453
|
+
finish(() => reject(/* @__PURE__ */ new Error(`Control request timed out after ${timeoutMs}ms`)));
|
|
454
|
+
}, timeoutMs);
|
|
455
|
+
socket.on("connect", () => {
|
|
456
|
+
socket.write(JSON.stringify(req) + "\n");
|
|
457
|
+
});
|
|
458
|
+
socket.on("data", (chunk) => {
|
|
459
|
+
buf += chunk.toString();
|
|
460
|
+
const idx = buf.indexOf("\n");
|
|
461
|
+
if (idx !== -1) {
|
|
462
|
+
const line = buf.slice(0, idx);
|
|
463
|
+
clearTimeout(timer);
|
|
464
|
+
try {
|
|
465
|
+
const res = JSON.parse(line);
|
|
466
|
+
finish(() => resolve(res));
|
|
467
|
+
} catch (err) {
|
|
468
|
+
finish(() => reject(err instanceof Error ? err : new Error(String(err))));
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
socket.on("error", (err) => {
|
|
473
|
+
clearTimeout(timer);
|
|
474
|
+
finish(() => reject(err));
|
|
475
|
+
});
|
|
476
|
+
socket.on("end", () => {
|
|
477
|
+
if (!settled) {
|
|
478
|
+
clearTimeout(timer);
|
|
479
|
+
finish(() => reject(/* @__PURE__ */ new Error("Control server closed connection without responding")));
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
//#endregion
|
|
486
|
+
//#region src/daemon/events.ts
|
|
487
|
+
const daemonEvents = new EventEmitter();
|
|
488
|
+
const DAEMON_EVENT_MESSAGE_APPENDED = "message-appended";
|
|
489
|
+
const DAEMON_EVENT_TYPING = "typing";
|
|
490
|
+
const DAEMON_EVENT_TURN_STARTED = "turn-started";
|
|
491
|
+
const DAEMON_EVENT_TURN_ENDED = "turn-ended";
|
|
492
|
+
/**
|
|
493
|
+
* Unified event carrying both `ChatMessage` appends and turn lifecycle
|
|
494
|
+
* events so a single `waitForMessages` subscription can interleave them
|
|
495
|
+
* in emission order (no merge logic or messageQueue on the consumer side).
|
|
496
|
+
*/
|
|
497
|
+
const DAEMON_EVENT_CHAT_STREAM = "chat-stream";
|
|
498
|
+
function emitMessageAppended(chatId, message) {
|
|
499
|
+
daemonEvents.emit(DAEMON_EVENT_MESSAGE_APPENDED, {
|
|
500
|
+
chatId,
|
|
501
|
+
message
|
|
502
|
+
});
|
|
503
|
+
const envelope = {
|
|
504
|
+
chatId,
|
|
505
|
+
item: {
|
|
506
|
+
kind: "message",
|
|
507
|
+
message
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
daemonEvents.emit(DAEMON_EVENT_CHAT_STREAM, envelope);
|
|
511
|
+
}
|
|
512
|
+
function emitTyping(chatId) {
|
|
513
|
+
daemonEvents.emit(DAEMON_EVENT_TYPING, { chatId });
|
|
514
|
+
}
|
|
515
|
+
function emitTurnStarted(event) {
|
|
516
|
+
daemonEvents.emit(DAEMON_EVENT_TURN_STARTED, event);
|
|
517
|
+
const lifecycle = {
|
|
518
|
+
type: "started",
|
|
519
|
+
turnId: event.turnId,
|
|
520
|
+
rootMessageId: event.rootMessageId,
|
|
521
|
+
...event.externalRef ? { externalRef: event.externalRef } : {}
|
|
522
|
+
};
|
|
523
|
+
const envelope = {
|
|
524
|
+
chatId: event.chatId,
|
|
525
|
+
item: {
|
|
526
|
+
kind: "turn",
|
|
527
|
+
event: lifecycle
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
daemonEvents.emit(DAEMON_EVENT_CHAT_STREAM, envelope);
|
|
531
|
+
}
|
|
532
|
+
function emitTurnEnded(event) {
|
|
533
|
+
daemonEvents.emit(DAEMON_EVENT_TURN_ENDED, event);
|
|
534
|
+
const lifecycle = {
|
|
535
|
+
type: "ended",
|
|
536
|
+
turnId: event.turnId,
|
|
537
|
+
outcome: event.outcome
|
|
538
|
+
};
|
|
539
|
+
const envelope = {
|
|
540
|
+
chatId: event.chatId,
|
|
541
|
+
item: {
|
|
542
|
+
kind: "turn",
|
|
543
|
+
event: lifecycle
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
daemonEvents.emit(DAEMON_EVENT_CHAT_STREAM, envelope);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
//#endregion
|
|
550
|
+
//#region src/daemon/chats.ts
|
|
551
|
+
async function appendMessage(id, message, startDir = process.cwd()) {
|
|
552
|
+
await appendMessage$1(id, message, startDir);
|
|
553
|
+
emitMessageAppended(id, message);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
//#endregion
|
|
557
|
+
//#region src/daemon/pending-replies.ts
|
|
558
|
+
function getPendingRepliesPath(startDir = process.cwd()) {
|
|
559
|
+
return path.join(getClawminiDir(startDir), "pending-replies.json");
|
|
560
|
+
}
|
|
561
|
+
function readFileSafe(filePath) {
|
|
562
|
+
if (!fs.existsSync(filePath)) return null;
|
|
563
|
+
try {
|
|
564
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
565
|
+
const parsed = JSON.parse(raw);
|
|
566
|
+
if (!parsed || parsed.version !== 1 || !Array.isArray(parsed.entries)) return null;
|
|
567
|
+
return parsed;
|
|
568
|
+
} catch {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function writeAtomic(filePath, data) {
|
|
573
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
574
|
+
const tmpPath = `${filePath}.${process.pid}.tmp`;
|
|
575
|
+
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
|
|
576
|
+
fs.renameSync(tmpPath, filePath);
|
|
577
|
+
}
|
|
578
|
+
function tryUnlink(filePath) {
|
|
579
|
+
if (!fs.existsSync(filePath)) return;
|
|
580
|
+
try {
|
|
581
|
+
fs.unlinkSync(filePath);
|
|
582
|
+
} catch {}
|
|
583
|
+
}
|
|
584
|
+
function enqueuePendingReply(entry, startDir = process.cwd()) {
|
|
585
|
+
const filePath = getPendingRepliesPath(startDir);
|
|
586
|
+
const entries = readFileSafe(filePath)?.entries ?? [];
|
|
587
|
+
entries.push(entry);
|
|
588
|
+
writeAtomic(filePath, {
|
|
589
|
+
version: 1,
|
|
590
|
+
entries
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Remove the first entry that matches the predicate. Used to roll back an
|
|
595
|
+
* enqueued entry when the supervisor reports the action could not be started.
|
|
596
|
+
*/
|
|
597
|
+
function dequeuePendingReply(predicate, startDir = process.cwd()) {
|
|
598
|
+
const filePath = getPendingRepliesPath(startDir);
|
|
599
|
+
const existing = readFileSafe(filePath);
|
|
600
|
+
if (!existing) return false;
|
|
601
|
+
const idx = existing.entries.findIndex(predicate);
|
|
602
|
+
if (idx === -1) return false;
|
|
603
|
+
existing.entries.splice(idx, 1);
|
|
604
|
+
if (existing.entries.length === 0) tryUnlink(filePath);
|
|
605
|
+
else writeAtomic(filePath, existing);
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
function renderMessage(entry, runtimeVersion) {
|
|
609
|
+
switch (entry.kind) {
|
|
610
|
+
case "restart-complete": return `Clawmini restarted (v${runtimeVersion}).`;
|
|
611
|
+
case "upgrade-complete": return `Clawmini upgraded to v${runtimeVersion}.`;
|
|
612
|
+
case "upgrade-failed": return `Clawmini upgrade${entry.requestedVersion ? ` to v${entry.requestedVersion}` : ""} failed${entry.reason ? `: ${entry.reason}` : "."}`;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Append a SystemMessage for each pending reply. Called from the daemon
|
|
617
|
+
* startup path so adapters (which reconnect via tRPC subscription with
|
|
618
|
+
* lastMessageId) replay the message after the daemon comes back online.
|
|
619
|
+
*
|
|
620
|
+
* Crash-safe: each entry is consumed only after its SystemMessage is
|
|
621
|
+
* appended. A crash mid-loop leaves the un-delivered entries on disk for the
|
|
622
|
+
* next daemon start to drain.
|
|
623
|
+
*/
|
|
624
|
+
async function drainPendingReplies(runtimeVersion, startDir = process.cwd()) {
|
|
625
|
+
const filePath = getPendingRepliesPath(startDir);
|
|
626
|
+
const data = readFileSafe(filePath);
|
|
627
|
+
if (!data) {
|
|
628
|
+
tryUnlink(filePath);
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
const remaining = [...data.entries];
|
|
632
|
+
while (remaining.length > 0) {
|
|
633
|
+
const entry = remaining[0];
|
|
634
|
+
const sysMsg = {
|
|
635
|
+
id: randomUUID(),
|
|
636
|
+
role: "system",
|
|
637
|
+
content: renderMessage(entry, runtimeVersion),
|
|
638
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
639
|
+
sessionId: void 0,
|
|
640
|
+
event: "router",
|
|
641
|
+
displayRole: "agent",
|
|
642
|
+
...entry.messageId ? { messageId: entry.messageId } : {}
|
|
643
|
+
};
|
|
644
|
+
try {
|
|
645
|
+
await appendMessage(entry.chatId, sysMsg, startDir);
|
|
646
|
+
} catch (err) {
|
|
647
|
+
console.error(`Failed to deliver pending reply to chat ${entry.chatId}:`, err instanceof Error ? err.message : err);
|
|
648
|
+
}
|
|
649
|
+
remaining.shift();
|
|
650
|
+
if (remaining.length === 0) tryUnlink(filePath);
|
|
651
|
+
else writeAtomic(filePath, {
|
|
652
|
+
version: 1,
|
|
653
|
+
entries: remaining
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
//#endregion
|
|
659
|
+
//#region src/cli/supervisor-actions.ts
|
|
660
|
+
const ACTION_GRACE_MS = 1e3;
|
|
661
|
+
/**
|
|
662
|
+
* Wire up the supervisor control socket so the daemon can request
|
|
663
|
+
* /restart, /shutdown, and /upgrade out-of-band.
|
|
664
|
+
*/
|
|
665
|
+
function startSupervisorControl(supervisor) {
|
|
666
|
+
startControlServer({
|
|
667
|
+
restart: async (req) => {
|
|
668
|
+
if (req.chatId) enqueuePendingReply({
|
|
669
|
+
chatId: req.chatId,
|
|
670
|
+
kind: "restart-complete",
|
|
671
|
+
...req.messageId ? { messageId: req.messageId } : {}
|
|
672
|
+
});
|
|
673
|
+
setTimeout(() => {
|
|
674
|
+
supervisor.restartAll().catch((err) => {
|
|
675
|
+
process.stderr.write(`[supervisor] /restart failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
676
|
+
if (req.chatId && req.messageId) dequeuePendingReply((e) => e.kind === "restart-complete" && e.messageId === req.messageId);
|
|
677
|
+
});
|
|
678
|
+
}, ACTION_GRACE_MS);
|
|
679
|
+
return { ok: true };
|
|
680
|
+
},
|
|
681
|
+
shutdown: async () => {
|
|
682
|
+
setTimeout(() => void supervisor.shutdown(0), ACTION_GRACE_MS);
|
|
683
|
+
return { ok: true };
|
|
684
|
+
},
|
|
685
|
+
upgrade: async (req) => {
|
|
686
|
+
const info = detectInstall();
|
|
687
|
+
if (!info.isNpmGlobal) return {
|
|
688
|
+
ok: false,
|
|
689
|
+
error: `not installed via npm install -g (running from ${info.entryRealPath})`
|
|
690
|
+
};
|
|
691
|
+
const version = req.version?.trim();
|
|
692
|
+
if (!version) return {
|
|
693
|
+
ok: false,
|
|
694
|
+
error: "missing target version"
|
|
695
|
+
};
|
|
696
|
+
if (!isAcceptableVersion(version)) return {
|
|
697
|
+
ok: false,
|
|
698
|
+
error: `invalid version: ${version}`
|
|
699
|
+
};
|
|
700
|
+
setTimeout(() => {
|
|
701
|
+
runUpgrade(supervisor, version, req.chatId, req.messageId).catch((err) => {
|
|
702
|
+
process.stderr.write(`[supervisor] /upgrade encountered an unexpected error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
703
|
+
});
|
|
704
|
+
}, ACTION_GRACE_MS);
|
|
705
|
+
return { ok: true };
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
function isAcceptableVersion(version) {
|
|
710
|
+
return /^[a-zA-Z0-9][a-zA-Z0-9._+-]{0,63}$/.test(version);
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* In-place upgrade. Order:
|
|
714
|
+
* 1. `npm install -g clawmini@<version>` (services kept running so the
|
|
715
|
+
* user isn't left in the dark if the install fails).
|
|
716
|
+
* 2. Resolve the freshly-installed binary by absolute path. Bail out with
|
|
717
|
+
* an upgrade-failed reply if it's missing.
|
|
718
|
+
* 3. Enqueue the upgrade-complete reply.
|
|
719
|
+
* 4. Stop all children, spawn the replacement supervisor, exit.
|
|
720
|
+
*
|
|
721
|
+
* Any failure path enqueues an upgrade-failed reply (so the user gets visible
|
|
722
|
+
* feedback) and restarts the daemon to drain it, rather than silently exiting.
|
|
723
|
+
*/
|
|
724
|
+
async function runUpgrade(supervisor, version, chatId, messageId) {
|
|
725
|
+
const info = detectInstall();
|
|
726
|
+
if (!info.isNpmGlobal || !info.npmRootRealPath) {
|
|
727
|
+
process.stderr.write(`[supervisor] /upgrade aborted: clawmini is not installed via npm install -g (running from ${info.entryRealPath}).\n`);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
const installErr = await runNpmInstall(version);
|
|
731
|
+
if (installErr) {
|
|
732
|
+
process.stderr.write(`[supervisor] /upgrade failed: ${installErr}\n`);
|
|
733
|
+
if (chatId) {
|
|
734
|
+
enqueuePendingReply({
|
|
735
|
+
chatId,
|
|
736
|
+
kind: "upgrade-failed",
|
|
737
|
+
...messageId ? { messageId } : {},
|
|
738
|
+
requestedVersion: version,
|
|
739
|
+
reason: installErr
|
|
740
|
+
});
|
|
741
|
+
await supervisor.restartAll().catch((err) => {
|
|
742
|
+
process.stderr.write(`[supervisor] additionally failed to restart services to surface the failure: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
const newCli = path.join(info.npmRootRealPath, "clawmini", "dist", "cli", "index.mjs");
|
|
748
|
+
if (!fs.existsSync(newCli)) {
|
|
749
|
+
const reason = `npm install reported success but ${newCli} is missing`;
|
|
750
|
+
process.stderr.write(`[supervisor] /upgrade aborted: ${reason}\n`);
|
|
751
|
+
if (chatId) {
|
|
752
|
+
enqueuePendingReply({
|
|
753
|
+
chatId,
|
|
754
|
+
kind: "upgrade-failed",
|
|
755
|
+
...messageId ? { messageId } : {},
|
|
756
|
+
requestedVersion: version,
|
|
757
|
+
reason
|
|
758
|
+
});
|
|
759
|
+
await supervisor.restartAll().catch(() => {});
|
|
760
|
+
}
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (chatId) enqueuePendingReply({
|
|
764
|
+
chatId,
|
|
765
|
+
kind: "upgrade-complete",
|
|
766
|
+
...messageId ? { messageId } : {},
|
|
767
|
+
requestedVersion: version
|
|
768
|
+
});
|
|
769
|
+
process.stderr.write("[supervisor] /upgrade: stopping all services...\n");
|
|
770
|
+
await supervisor.stopAllChildren();
|
|
771
|
+
process.stderr.write(`[supervisor] /upgrade: relaunching ${newCli} serve --detach...\n`);
|
|
772
|
+
removeSupervisorPid();
|
|
773
|
+
const replacement = spawn(process.execPath, [
|
|
774
|
+
newCli,
|
|
775
|
+
"serve",
|
|
776
|
+
"--detach"
|
|
777
|
+
], {
|
|
778
|
+
detached: true,
|
|
779
|
+
stdio: "ignore",
|
|
780
|
+
cwd: process.cwd(),
|
|
781
|
+
env: process.env
|
|
782
|
+
});
|
|
783
|
+
if (!await waitForSpawn(replacement)) {
|
|
784
|
+
process.stderr.write(`[supervisor] /upgrade: replacement supervisor failed to spawn — restarting in place\n`);
|
|
785
|
+
if (chatId) {
|
|
786
|
+
dequeuePendingReply((e) => e.kind === "upgrade-complete" && e.messageId === messageId && e.requestedVersion === version);
|
|
787
|
+
enqueuePendingReply({
|
|
788
|
+
chatId,
|
|
789
|
+
kind: "upgrade-failed",
|
|
790
|
+
...messageId ? { messageId } : {},
|
|
791
|
+
requestedVersion: version,
|
|
792
|
+
reason: "replacement supervisor failed to spawn"
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
try {
|
|
796
|
+
await supervisor.restartAll();
|
|
797
|
+
} catch (err) {
|
|
798
|
+
process.stderr.write(`[supervisor] additionally failed to restart services after spawn failure: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
799
|
+
}
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
replacement.unref();
|
|
803
|
+
process.exit(0);
|
|
804
|
+
}
|
|
805
|
+
function runNpmInstall(version) {
|
|
806
|
+
return new Promise((resolve) => {
|
|
807
|
+
const child = spawn("npm", [
|
|
808
|
+
"install",
|
|
809
|
+
"-g",
|
|
810
|
+
`clawmini@${version}`
|
|
811
|
+
], {
|
|
812
|
+
stdio: "inherit",
|
|
813
|
+
env: process.env
|
|
814
|
+
});
|
|
815
|
+
child.on("exit", (code) => {
|
|
816
|
+
if (code === 0) resolve(null);
|
|
817
|
+
else resolve(`npm install -g exited with code ${code}`);
|
|
818
|
+
});
|
|
819
|
+
child.on("error", (err) => {
|
|
820
|
+
resolve(err instanceof Error ? err.message : String(err));
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
function waitForSpawn(child, timeoutMs = 5e3) {
|
|
825
|
+
return new Promise((resolve) => {
|
|
826
|
+
let settled = false;
|
|
827
|
+
const settle = (ok) => {
|
|
828
|
+
if (settled) return;
|
|
829
|
+
settled = true;
|
|
830
|
+
resolve(ok);
|
|
831
|
+
};
|
|
832
|
+
child.once("spawn", () => settle(true));
|
|
833
|
+
child.once("error", (err) => {
|
|
834
|
+
process.stderr.write(`[supervisor] replacement spawn error: ${err.message}\n`);
|
|
835
|
+
settle(false);
|
|
836
|
+
});
|
|
837
|
+
setTimeout(() => settle(true), timeoutMs);
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
//#endregion
|
|
842
|
+
export { getMessages as A, writeLiteScript as C, findLastMessage as D, deleteChat as E, listChats as M, setDefaultChatId as N, getChatsDir as O, resolveCompiledScript as S, createChat as T, removeSupervisorPid as _, DAEMON_EVENT_CHAT_STREAM as a, exportLiteToEnvironment as b, daemonEvents as c, emitTyping as d, getControlSocketPath as f, readSupervisorPid as g, getSupervisorPidPath as h, appendMessage as i, isValidChatId as j, getDefaultChatId as k, emitTurnEnded as l, detectInstall as m, startSupervisorControl as n, DAEMON_EVENT_MESSAGE_APPENDED as o, sendControlRequest as p, drainPendingReplies as r, DAEMON_EVENT_TYPING as s, isAcceptableVersion as t, emitTurnStarted as u, writeSupervisorPid as v, DEFAULT_CHAT_ID as w, getLiteScriptContent as x, exportLiteToAllEnvironments as y };
|
|
843
|
+
//# sourceMappingURL=supervisor-actions-CiW56eLi.mjs.map
|