@murphai/murph 0.2.11 → 0.2.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.
- package/CHANGELOG.md +78 -0
- package/README.md +1 -1
- package/config.schema.json +6 -12
- package/dist/cli-entry.d.ts.map +1 -1
- package/dist/cli-entry.js +3 -25
- package/dist/cli-entry.js.map +1 -1
- package/dist/commands/automation.d.ts +8 -8
- package/dist/commands/inbox.d.ts.map +1 -1
- package/dist/commands/inbox.js +0 -7
- package/dist/commands/inbox.js.map +1 -1
- package/dist/commands/meal.d.ts.map +1 -1
- package/dist/commands/meal.js +130 -16
- package/dist/commands/meal.js.map +1 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +47 -11
- package/dist/commands/search.js.map +1 -1
- package/dist/incur.generated.d.ts +5 -4
- package/dist/incur.generated.d.ts.map +1 -1
- package/dist/vault-cli-command-manifest.d.ts +1 -1
- package/dist/vault-cli-command-manifest.d.ts.map +1 -1
- package/dist/vault-cli-command-manifest.js +1 -1
- package/dist/vault-cli-command-manifest.js.map +1 -1
- package/node_modules/@murphai/assistant-cli/dist/assistant/service.d.ts +2 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.d.ts +0 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.js +0 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/prompt-builder.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.js +0 -26
- package/node_modules/@murphai/assistant-engine/dist/assistant/automation/reply.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/descriptors.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/descriptors.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.d.ts +4 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.js +28 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/runtime.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/types.d.ts +4 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/channels/types.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-bootstrap.js +3 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/cli-surface-bootstrap.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.d.ts +64 -12
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.js +193 -34
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/runtime-state.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.d.ts +11 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.js +2 -7
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/schedule.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/store.d.ts +4 -6
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron/store.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron.js +510 -166
- package/node_modules/@murphai/assistant-engine/dist/assistant/cron.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-delivery.d.ts +4 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-delivery.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-delivery.js +33 -14
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-delivery.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-turn-metadata.d.ts +6 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-turn-metadata.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-turn-metadata.js +26 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome-turn-metadata.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/first-contact-welcome.js +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/food-auto-log-hooks.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/food-auto-log-hooks.js +53 -46
- package/node_modules/@murphai/assistant-engine/dist/assistant/food-auto-log-hooks.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.d.ts +9 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.d.ts.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.js +53 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/model-behavior.js.map +1 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.js +69 -15
- package/node_modules/@murphai/assistant-engine/dist/assistant/outbox.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-catalog.js +5 -4
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-catalog.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-turn-runner.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-turn-runner.js +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/provider-turn-runner.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/catalog.js +3 -3
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/catalog.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.js +76 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/codex-cli.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/openai-compatible.d.ts +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/openai-compatible.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/openai-compatible.js +7 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/openai-compatible.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/registry.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/registry.js +3 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/registry.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.d.ts +3 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.js +3 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/providers/types.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/rich-content-routing.d.ts +2 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/rich-content-routing.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/rich-content-routing.js +30 -8
- package/node_modules/@murphai/assistant-engine/dist/assistant/rich-content-routing.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.d.ts +2 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.js +10 -6
- package/node_modules/@murphai/assistant-engine/dist/assistant/system-prompt.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/capability-definitions.d.ts +82 -2
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/capability-definitions.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/capability-definitions.js +71 -13
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/capability-definitions.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/execution-adapters.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/execution-adapters.js +0 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-cli-tools/execution-adapters.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex.d.ts +7 -0
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex.d.ts.map +1 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex.js +75 -1
- package/node_modules/@murphai/assistant-engine/dist/assistant-codex.js.map +1 -1
- package/node_modules/@murphai/assistant-engine/package.json +2 -2
- package/node_modules/@murphai/assistantd/package.json +1 -1
- package/node_modules/@murphai/core/dist/automation.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/automation.js +10 -7
- package/node_modules/@murphai/core/dist/automation.js.map +1 -1
- package/node_modules/@murphai/core/dist/mutations.d.ts +2 -1
- package/node_modules/@murphai/core/dist/mutations.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/mutations.js +8 -4
- package/node_modules/@murphai/core/dist/mutations.js.map +1 -1
- package/node_modules/@murphai/core/dist/operations/canonical-write-lock.d.ts +3 -1
- package/node_modules/@murphai/core/dist/operations/canonical-write-lock.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/operations/canonical-write-lock.js +86 -66
- package/node_modules/@murphai/core/dist/operations/canonical-write-lock.js.map +1 -1
- package/node_modules/@murphai/core/dist/public-mutations.d.ts.map +1 -1
- package/node_modules/@murphai/core/dist/public-mutations.js +14 -7
- package/node_modules/@murphai/core/dist/public-mutations.js.map +1 -1
- package/node_modules/@murphai/core/package.json +1 -1
- package/node_modules/@murphai/device-syncd/dist/crypto.d.ts +13 -2
- package/node_modules/@murphai/device-syncd/dist/crypto.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/crypto.js +116 -15
- package/node_modules/@murphai/device-syncd/dist/crypto.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/hosted-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/hosted-runtime.js +1 -1
- package/node_modules/@murphai/device-syncd/dist/hosted-runtime.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/http.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/http.js +6 -5
- package/node_modules/@murphai/device-syncd/dist/http.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/public-ingress.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/public-ingress.js +3 -2
- package/node_modules/@murphai/device-syncd/dist/public-ingress.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/service.d.ts +1 -0
- package/node_modules/@murphai/device-syncd/dist/service.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/service.js +52 -14
- package/node_modules/@murphai/device-syncd/dist/service.js.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/shared.d.ts.map +1 -1
- package/node_modules/@murphai/device-syncd/dist/shared.js +2 -1
- package/node_modules/@murphai/device-syncd/dist/shared.js.map +1 -1
- package/node_modules/@murphai/gateway-local/package.json +1 -1
- package/node_modules/@murphai/importers/dist/core-port.d.ts +5 -2
- package/node_modules/@murphai/importers/dist/core-port.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/core-port.js.map +1 -1
- package/node_modules/@murphai/importers/dist/document-importer.d.ts +2 -1
- package/node_modules/@murphai/importers/dist/document-importer.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/document-importer.js +3 -2
- package/node_modules/@murphai/importers/dist/document-importer.js.map +1 -1
- package/node_modules/@murphai/importers/dist/meal-importer.d.ts +4 -1
- package/node_modules/@murphai/importers/dist/meal-importer.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/meal-importer.js +18 -4
- package/node_modules/@murphai/importers/dist/meal-importer.js.map +1 -1
- package/node_modules/@murphai/importers/dist/shared.d.ts +2 -0
- package/node_modules/@murphai/importers/dist/shared.d.ts.map +1 -1
- package/node_modules/@murphai/importers/dist/shared.js +4 -1
- package/node_modules/@murphai/importers/dist/shared.js.map +1 -1
- package/node_modules/@murphai/importers/package.json +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.js +0 -7
- package/node_modules/@murphai/inbox-services/dist/inbox-app/bootstrap-doctor.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/promotions.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/promotions.js +5 -3
- package/node_modules/@murphai/inbox-services/dist/inbox-app/promotions.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/reads.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/reads.js +4 -4
- package/node_modules/@murphai/inbox-services/dist/inbox-app/reads.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/runtime.js +6 -6
- package/node_modules/@murphai/inbox-services/dist/inbox-app/runtime.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/types.d.ts +20 -151
- package/node_modules/@murphai/inbox-services/dist/inbox-app/types.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-app/types.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/parser.d.ts +3 -8
- package/node_modules/@murphai/inbox-services/dist/inbox-services/parser.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/parser.js +0 -20
- package/node_modules/@murphai/inbox-services/dist/inbox-services/parser.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.d.ts +1 -6
- package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.js +31 -12
- package/node_modules/@murphai/inbox-services/dist/inbox-services/promotions.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/query.d.ts +8 -8
- package/node_modules/@murphai/inbox-services/dist/inbox-services/query.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/query.js +12 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/query.js.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.d.ts.map +1 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.js +12 -1
- package/node_modules/@murphai/inbox-services/dist/inbox-services/shared.js.map +1 -1
- package/node_modules/@murphai/inbox-services/package.json +1 -1
- package/node_modules/@murphai/inboxd/dist/runtime.d.ts +1 -0
- package/node_modules/@murphai/inboxd/dist/runtime.d.ts.map +1 -1
- package/node_modules/@murphai/inboxd/dist/runtime.js.map +1 -1
- package/node_modules/@murphai/inboxd/package.json +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant/hosted-config.d.ts +16 -16
- package/node_modules/@murphai/operator-config/dist/assistant-backend.d.ts +2 -2
- package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.d.ts +86 -124
- package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.js +19 -58
- package/node_modules/@murphai/operator-config/dist/assistant-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.d.ts +6 -66
- package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.js +0 -1
- package/node_modules/@murphai/operator-config/dist/inbox-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/linq-runtime.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/linq-runtime.js +88 -47
- package/node_modules/@murphai/operator-config/dist/linq-runtime.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/operator-config/self-delivery-targets.d.ts +1 -1
- package/node_modules/@murphai/operator-config/dist/operator-config.d.ts +3 -3
- package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.d.ts +4 -34
- package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.js +0 -1
- package/node_modules/@murphai/operator-config/dist/setup-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.d.ts +31 -0
- package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.d.ts.map +1 -1
- package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.js +4 -1
- package/node_modules/@murphai/operator-config/dist/vault-cli-contracts.js.map +1 -1
- package/node_modules/@murphai/operator-config/package.json +2 -2
- package/node_modules/@murphai/parsers/README.md +0 -1
- package/node_modules/@murphai/parsers/dist/index.d.ts +0 -4
- package/node_modules/@murphai/parsers/dist/index.d.ts.map +1 -1
- package/node_modules/@murphai/parsers/dist/index.js +0 -3
- package/node_modules/@murphai/parsers/dist/index.js.map +1 -1
- package/node_modules/@murphai/parsers/dist/toolchain/config.d.ts +1 -1
- package/node_modules/@murphai/parsers/dist/toolchain/config.d.ts.map +1 -1
- package/node_modules/@murphai/parsers/dist/toolchain/config.js +0 -1
- package/node_modules/@murphai/parsers/dist/toolchain/config.js.map +1 -1
- package/node_modules/@murphai/parsers/dist/toolchain/discover.d.ts.map +1 -1
- package/node_modules/@murphai/parsers/dist/toolchain/discover.js +0 -11
- package/node_modules/@murphai/parsers/dist/toolchain/discover.js.map +1 -1
- package/node_modules/@murphai/query/dist/automation.d.ts.map +1 -1
- package/node_modules/@murphai/query/dist/automation.js +8 -2
- package/node_modules/@murphai/query/dist/automation.js.map +1 -1
- package/node_modules/@murphai/query/package.json +1 -1
- package/node_modules/@murphai/runtime-state/README.md +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/assistant-usage.d.ts +2 -0
- package/node_modules/@murphai/runtime-state/dist/node/assistant-usage.d.ts.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/assistant-usage.js +2 -0
- package/node_modules/@murphai/runtime-state/dist/node/assistant-usage.js.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/index.d.ts +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/index.d.ts.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/node/index.js +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/index.js.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/node/runtime-paths.d.ts +2 -0
- package/node_modules/@murphai/runtime-state/dist/node/runtime-paths.d.ts.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/runtime-paths.js +2 -0
- package/node_modules/@murphai/runtime-state/dist/node/runtime-paths.js.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/sqlite-warning-filter.d.ts +2 -0
- package/node_modules/@murphai/runtime-state/dist/node/sqlite-warning-filter.d.ts.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/sqlite-warning-filter.js +2 -0
- package/node_modules/@murphai/runtime-state/dist/node/sqlite-warning-filter.js.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/ulid.d.ts +2 -0
- package/node_modules/@murphai/runtime-state/dist/node/ulid.d.ts.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/node/ulid.js +2 -0
- package/node_modules/@murphai/runtime-state/dist/node/ulid.js.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/sqlite-warning-filter.d.ts +9 -0
- package/node_modules/@murphai/runtime-state/dist/sqlite-warning-filter.d.ts.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/sqlite-warning-filter.js +63 -0
- package/node_modules/@murphai/runtime-state/dist/sqlite-warning-filter.js.map +1 -0
- package/node_modules/@murphai/runtime-state/dist/sqlite.d.ts +2 -1
- package/node_modules/@murphai/runtime-state/dist/sqlite.d.ts.map +1 -1
- package/node_modules/@murphai/runtime-state/dist/sqlite.js +4 -2
- package/node_modules/@murphai/runtime-state/dist/sqlite.js.map +1 -1
- package/node_modules/@murphai/runtime-state/package.json +20 -0
- package/node_modules/@murphai/setup-cli/dist/setup-services/steps.d.ts +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services/steps.d.ts.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services/steps.js +0 -17
- package/node_modules/@murphai/setup-cli/dist/setup-services/steps.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services/tool-provisioning.d.ts +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services/tool-provisioning.js +0 -4
- package/node_modules/@murphai/setup-cli/dist/setup-services/tool-provisioning.js.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services.d.ts.map +1 -1
- package/node_modules/@murphai/setup-cli/dist/setup-services.js +0 -2
- package/node_modules/@murphai/setup-cli/dist/setup-services.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.d.ts +2 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.js +4 -2
- package/node_modules/@murphai/vault-usecases/dist/usecases/food-autolog.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.js +6 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/integrated-services.js.map +1 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/types.d.ts +12 -1
- package/node_modules/@murphai/vault-usecases/dist/usecases/types.d.ts.map +1 -1
- package/node_modules/@murphai/vault-usecases/package.json +1 -1
- package/package.json +4 -4
- package/node_modules/@murphai/parsers/dist/adapters/pdftotext.d.ts +0 -7
- package/node_modules/@murphai/parsers/dist/adapters/pdftotext.d.ts.map +0 -1
- package/node_modules/@murphai/parsers/dist/adapters/pdftotext.js +0 -60
- package/node_modules/@murphai/parsers/dist/adapters/pdftotext.js.map +0 -1
|
@@ -3,7 +3,7 @@ import { loadVault, upsertAutomation } from '@murphai/core';
|
|
|
3
3
|
import { listAutomations as listCanonicalAutomations, showAutomation as showCanonicalAutomation, } from '@murphai/query';
|
|
4
4
|
import { assistantCronJobSchema, assistantCronRunRecordSchema, assistantCronScheduleSchema, assistantCronTargetSchema, } from '@murphai/operator-config/assistant-cli-contracts';
|
|
5
5
|
import { loadRuntimeModule } from '@murphai/vault-usecases/runtime';
|
|
6
|
-
import { renderAutoLoggedFoodMealNote } from '@murphai/vault-usecases/records';
|
|
6
|
+
import { buildDailyFoodCronJobId, buildDailyFoodCronJobName, buildDailyFoodCronPrompt, buildDailyFoodSchedule, renderAutoLoggedFoodMealNote, } from '@murphai/vault-usecases/records';
|
|
7
7
|
import { loadImporterRuntime } from '@murphai/vault-usecases/runtime';
|
|
8
8
|
import { VaultCliError } from '@murphai/operator-config/vault-cli-errors';
|
|
9
9
|
import { withAssistantCronWriteLock } from "./cron/locking.js";
|
|
@@ -11,7 +11,7 @@ import { buildAssistantCronSchedule, computeAssistantCronNextRunAt, } from "./cr
|
|
|
11
11
|
import { getAssistantCronPresetDefinition, listAssistantCronPresets as listBuiltinAssistantCronPresets, renderAssistantCronPreset, } from "./cron/presets.js";
|
|
12
12
|
import { appendAssistantCronRun, assertAssistantCronJobNameIsAvailable, buildAssistantCronTarget, createAssistantCronJobId, createAssistantCronRunId, ensureAssistantCronState, isAssistantCronJobDue, normalizeRequiredAssistantCronText, readAssistantCronRuns, readAssistantCronStore, resolveAssistantCronJobFromStore, resolveAssistantCronJobIndex, resolveAssistantCronRunLookupId, sortAssistantCronJobs, writeAssistantCronStore, } from "./cron/store.js";
|
|
13
13
|
import { buildAssistantCronNotificationDedupeToken } from "./cron/notification-delivery.js";
|
|
14
|
-
import {
|
|
14
|
+
import { createAssistantCronCanonicalRuntimeRecord, findAssistantCronCanonicalRuntimeRecord, readAssistantCronCanonicalRuntimeStore, removeAssistantCronCanonicalRuntimeRecord, upsertAssistantCronCanonicalRuntimeRecord, writeAssistantCronCanonicalRuntimeStore, } from "./cron/runtime-state.js";
|
|
15
15
|
import { sendAssistantNotificationLocal } from "../assistant-service.js";
|
|
16
16
|
import { getAssistantChannelAdapter } from "./channel-adapters.js";
|
|
17
17
|
import { resolveAssistantBindingDelivery } from "./bindings.js";
|
|
@@ -63,11 +63,12 @@ export async function addAssistantCronJob(input) {
|
|
|
63
63
|
const name = normalizeRequiredAssistantCronText(resolvedInput.name, 'name');
|
|
64
64
|
const prompt = normalizeRequiredAssistantCronText(resolvedInput.prompt, 'prompt');
|
|
65
65
|
const enabled = resolvedInput.enabled ?? true;
|
|
66
|
-
const
|
|
66
|
+
const resolvedSchedule = await resolveAssistantCronScheduleForVault(input.vault, resolvedInput.schedule);
|
|
67
|
+
const schedule = assistantCronScheduleSchema.parse(resolvedInput.schedule);
|
|
67
68
|
const keepAfterRun = schedule.kind === 'at'
|
|
68
69
|
? resolvedInput.keepAfterRun ?? false
|
|
69
70
|
: true;
|
|
70
|
-
const nextRunAt = computeAssistantCronNextRunAt(
|
|
71
|
+
const nextRunAt = computeAssistantCronNextRunAt(resolvedSchedule, now);
|
|
71
72
|
if (enabled && nextRunAt === null) {
|
|
72
73
|
throw new VaultCliError('ASSISTANT_CRON_INVALID_SCHEDULE', 'The assistant cron schedule does not produce a future run time.');
|
|
73
74
|
}
|
|
@@ -91,18 +92,19 @@ export async function addAssistantCronJob(input) {
|
|
|
91
92
|
route: buildCanonicalAutomationRoute(target),
|
|
92
93
|
instructions: prompt,
|
|
93
94
|
}));
|
|
94
|
-
const runtimeStore = await
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
|
|
96
|
+
const timeZone = await resolveAssistantCronDefaultTimeZone(input.vault);
|
|
97
|
+
const source = requireCanonicalAssistantCronRecord(created.record, timeZone);
|
|
98
|
+
const runtimeState = createAssistantCronCanonicalRuntimeRecord({
|
|
99
|
+
jobId: source.automationId,
|
|
98
100
|
now: now.toISOString(),
|
|
99
101
|
sessionId: target.sessionId,
|
|
100
102
|
alias: target.alias,
|
|
101
103
|
});
|
|
102
|
-
|
|
103
|
-
await
|
|
104
|
+
upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, runtimeState);
|
|
105
|
+
await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
|
|
104
106
|
return projectCanonicalAssistantCronJob({
|
|
105
|
-
|
|
107
|
+
source,
|
|
106
108
|
runtimeState,
|
|
107
109
|
});
|
|
108
110
|
});
|
|
@@ -163,19 +165,22 @@ async function resolveAssistantCronTargetDefaults(input) {
|
|
|
163
165
|
};
|
|
164
166
|
}
|
|
165
167
|
async function listCanonicalAssistantCronRecords(vault, status = ['active', 'paused']) {
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
168
|
+
const timeZone = await resolveAssistantCronDefaultTimeZone(vault);
|
|
169
|
+
const [automationRecords, foodRecords] = await Promise.all([
|
|
170
|
+
listCanonicalAutomations(vault, {
|
|
171
|
+
status: [...status],
|
|
172
|
+
}),
|
|
173
|
+
listCanonicalFoodAutoLogRecords(vault, timeZone),
|
|
174
|
+
]);
|
|
175
|
+
return [
|
|
176
|
+
...automationRecords.flatMap((record) => {
|
|
177
|
+
const normalized = normalizeCanonicalAssistantCronRecord(record, timeZone);
|
|
178
|
+
return normalized ? [normalized] : [];
|
|
179
|
+
}),
|
|
180
|
+
...(status.includes('active') ? foodRecords : []),
|
|
181
|
+
];
|
|
177
182
|
}
|
|
178
|
-
function normalizeCanonicalAssistantCronRecord(record) {
|
|
183
|
+
function normalizeCanonicalAssistantCronRecord(record, timeZone) {
|
|
179
184
|
if (record.status !== 'active' && record.status !== 'paused') {
|
|
180
185
|
return null;
|
|
181
186
|
}
|
|
@@ -183,67 +188,190 @@ function normalizeCanonicalAssistantCronRecord(record) {
|
|
|
183
188
|
if (typeof instructions !== 'string') {
|
|
184
189
|
throw new VaultCliError('ASSISTANT_CRON_INVALID_AUTOMATION', `Canonical automation "${record.automationId}" is missing scheduled instructions.`);
|
|
185
190
|
}
|
|
186
|
-
const { prompt: _prompt, ...rest } = record;
|
|
187
191
|
return {
|
|
188
|
-
|
|
192
|
+
kind: 'automation',
|
|
193
|
+
automationId: record.automationId,
|
|
194
|
+
continuityPolicy: record.continuityPolicy,
|
|
195
|
+
createdAt: record.createdAt,
|
|
189
196
|
instructions,
|
|
197
|
+
route: record.route,
|
|
198
|
+
schedule: normalizeAssistantCronPublicSchedule(record.schedule),
|
|
199
|
+
slug: record.slug,
|
|
190
200
|
status: record.status,
|
|
201
|
+
summary: record.summary,
|
|
202
|
+
tags: [...record.tags],
|
|
203
|
+
timeZone: record.schedule.kind === 'cron' || record.schedule.kind === 'dailyLocal'
|
|
204
|
+
? timeZone
|
|
205
|
+
: null,
|
|
206
|
+
title: record.title,
|
|
207
|
+
updatedAt: record.updatedAt,
|
|
191
208
|
};
|
|
192
209
|
}
|
|
193
|
-
function requireCanonicalAssistantCronRecord(record) {
|
|
194
|
-
const normalized = normalizeCanonicalAssistantCronRecord(record);
|
|
210
|
+
function requireCanonicalAssistantCronRecord(record, timeZone) {
|
|
211
|
+
const normalized = normalizeCanonicalAssistantCronRecord(record, timeZone);
|
|
195
212
|
if (!normalized) {
|
|
196
213
|
throw new VaultCliError('ASSISTANT_CRON_INVALID_AUTOMATION', `Canonical automation "${record.automationId}" is not active or paused.`);
|
|
197
214
|
}
|
|
198
215
|
return normalized;
|
|
199
216
|
}
|
|
200
|
-
function
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
217
|
+
async function listCanonicalFoodAutoLogRecords(vault, timeZone) {
|
|
218
|
+
const core = await loadFoodAutoLogCoreRuntime();
|
|
219
|
+
if (typeof core.listFoods !== 'function') {
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
const foods = await core.listFoods(vault);
|
|
223
|
+
return foods.flatMap((food) => {
|
|
224
|
+
const localTime = normalizeNullableString(food.autoLogDaily?.time);
|
|
225
|
+
const slug = normalizeNullableString(food.slug);
|
|
226
|
+
if (!localTime || !slug) {
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
return [{
|
|
230
|
+
kind: 'foodAutoLog',
|
|
231
|
+
foodId: food.foodId,
|
|
232
|
+
jobId: buildDailyFoodCronJobId(food.foodId),
|
|
233
|
+
schedule: buildDailyFoodSchedule(localTime),
|
|
234
|
+
slug,
|
|
235
|
+
timeZone,
|
|
236
|
+
title: food.title,
|
|
237
|
+
}];
|
|
208
238
|
});
|
|
209
239
|
}
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
|
|
240
|
+
function resolveCanonicalAssistantCronJobLookupKeys(record) {
|
|
241
|
+
if (record.kind === 'automation') {
|
|
242
|
+
return [record.automationId, record.slug, record.title];
|
|
243
|
+
}
|
|
244
|
+
return [record.jobId, buildDailyFoodCronJobName(record.slug)];
|
|
245
|
+
}
|
|
246
|
+
function findCanonicalAssistantCronRecordInList(records, lookup) {
|
|
247
|
+
const normalizedLookup = normalizeRequiredAssistantCronText(lookup, 'job');
|
|
248
|
+
const foldedLookup = normalizedLookup.toLocaleLowerCase();
|
|
249
|
+
return (records.find((record) => resolveCanonicalAssistantCronJobLookupKeys(record).some((candidate) => typeof candidate === 'string' &&
|
|
250
|
+
candidate.toLocaleLowerCase() === foldedLookup)) ?? null);
|
|
251
|
+
}
|
|
252
|
+
function createInitialCanonicalRuntimeState(source, now) {
|
|
253
|
+
return createAssistantCronCanonicalRuntimeRecord({
|
|
254
|
+
jobId: resolveCanonicalAssistantCronJobId(source),
|
|
255
|
+
now,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
function resolveCanonicalRuntimeState(source, store, legacyLocalJob) {
|
|
259
|
+
return (findAssistantCronCanonicalRuntimeRecord(store, resolveCanonicalAssistantCronJobId(source)) ??
|
|
260
|
+
migrateLegacyLocalFoodRuntimeState(source, legacyLocalJob) ??
|
|
261
|
+
createInitialCanonicalRuntimeState(source, new Date().toISOString()));
|
|
213
262
|
}
|
|
214
263
|
function projectCanonicalAssistantCronJob(input) {
|
|
215
|
-
const continuitySessionId = input.
|
|
264
|
+
const continuitySessionId = input.source.kind === 'automation' &&
|
|
265
|
+
input.source.continuityPolicy === 'preserve'
|
|
216
266
|
? input.runtimeState.sessionId
|
|
217
267
|
: null;
|
|
218
|
-
const continuityAlias = input.
|
|
268
|
+
const continuityAlias = input.source.kind === 'automation' &&
|
|
269
|
+
input.source.continuityPolicy === 'preserve'
|
|
219
270
|
? input.runtimeState.alias
|
|
220
271
|
: null;
|
|
272
|
+
const targetRoute = input.source.kind === 'automation'
|
|
273
|
+
? input.source.route
|
|
274
|
+
: {
|
|
275
|
+
channel: null,
|
|
276
|
+
deliveryTarget: null,
|
|
277
|
+
identityId: null,
|
|
278
|
+
participantId: null,
|
|
279
|
+
sourceThreadId: null,
|
|
280
|
+
};
|
|
221
281
|
const target = assistantCronTargetSchema.parse({
|
|
222
282
|
sessionId: continuitySessionId,
|
|
223
283
|
alias: continuityAlias,
|
|
224
|
-
channel:
|
|
225
|
-
identityId:
|
|
226
|
-
participantId:
|
|
227
|
-
sourceThreadId:
|
|
228
|
-
deliveryTarget:
|
|
284
|
+
channel: targetRoute.channel,
|
|
285
|
+
identityId: targetRoute.identityId,
|
|
286
|
+
participantId: targetRoute.participantId,
|
|
287
|
+
sourceThreadId: targetRoute.sourceThreadId,
|
|
288
|
+
deliveryTarget: targetRoute.deliveryTarget,
|
|
289
|
+
});
|
|
290
|
+
const projectedState = projectCanonicalAssistantCronJobState({
|
|
291
|
+
source: input.source,
|
|
292
|
+
runtimeState: input.runtimeState,
|
|
229
293
|
});
|
|
230
294
|
return assistantCronJobSchema.parse({
|
|
231
295
|
schema: ASSISTANT_CRON_JOB_SCHEMA,
|
|
232
|
-
jobId: input.
|
|
233
|
-
name: input.automation
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
296
|
+
jobId: resolveCanonicalAssistantCronJobId(input.source),
|
|
297
|
+
name: input.source.kind === 'automation'
|
|
298
|
+
? input.source.title
|
|
299
|
+
: buildDailyFoodCronJobName(input.source.slug),
|
|
300
|
+
enabled: isCanonicalAssistantCronSourceEnabled(input.source),
|
|
301
|
+
keepAfterRun: input.source.schedule.kind !== 'at',
|
|
302
|
+
prompt: input.source.kind === 'automation'
|
|
303
|
+
? input.source.instructions
|
|
304
|
+
: buildDailyFoodCronPrompt(input.source.title),
|
|
305
|
+
schedule: input.source.schedule,
|
|
238
306
|
target,
|
|
239
|
-
|
|
240
|
-
|
|
307
|
+
foodAutoLog: input.source.kind === 'foodAutoLog'
|
|
308
|
+
? {
|
|
309
|
+
foodId: input.source.foodId,
|
|
310
|
+
}
|
|
311
|
+
: undefined,
|
|
312
|
+
createdAt: input.source.kind === 'automation'
|
|
313
|
+
? input.source.createdAt
|
|
314
|
+
: input.runtimeState.createdAt,
|
|
315
|
+
updatedAt: input.source.kind === 'automation'
|
|
316
|
+
? input.source.updatedAt
|
|
317
|
+
: input.runtimeState.updatedAt,
|
|
318
|
+
state: projectedState,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
function projectCanonicalAssistantCronJobState(input) {
|
|
322
|
+
const nextRunAt = resolveCanonicalAssistantCronNextRunAt({
|
|
323
|
+
source: input.source,
|
|
241
324
|
state: input.runtimeState.state,
|
|
242
325
|
});
|
|
326
|
+
return {
|
|
327
|
+
nextRunAt,
|
|
328
|
+
lastRunAt: input.runtimeState.state.lastRunAt,
|
|
329
|
+
lastSucceededAt: input.runtimeState.state.lastSucceededAt,
|
|
330
|
+
lastFailedAt: input.runtimeState.state.lastFailedAt,
|
|
331
|
+
consecutiveFailures: input.runtimeState.state.consecutiveFailures,
|
|
332
|
+
lastError: input.runtimeState.state.lastError,
|
|
333
|
+
runningAt: input.runtimeState.state.runningAt,
|
|
334
|
+
runningPid: input.runtimeState.state.runningPid,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function resolveCanonicalAssistantCronJobId(source) {
|
|
338
|
+
return source.kind === 'automation' ? source.automationId : source.jobId;
|
|
339
|
+
}
|
|
340
|
+
function isCanonicalAssistantCronSourceEnabled(source) {
|
|
341
|
+
return source.kind === 'automation' ? source.status === 'active' : true;
|
|
243
342
|
}
|
|
244
|
-
function
|
|
343
|
+
function normalizeAssistantCronPublicSchedule(schedule) {
|
|
344
|
+
if (schedule.kind === 'cron') {
|
|
345
|
+
return assistantCronScheduleSchema.parse({
|
|
346
|
+
kind: 'cron',
|
|
347
|
+
expression: schedule.expression,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
if (schedule.kind === 'dailyLocal') {
|
|
351
|
+
return assistantCronScheduleSchema.parse({
|
|
352
|
+
kind: 'dailyLocal',
|
|
353
|
+
localTime: schedule.localTime,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
245
356
|
return assistantCronScheduleSchema.parse(schedule);
|
|
246
357
|
}
|
|
358
|
+
function resolveAssistantCronResolvedSchedule(input) {
|
|
359
|
+
if (input.schedule.kind === 'cron') {
|
|
360
|
+
return {
|
|
361
|
+
kind: 'cron',
|
|
362
|
+
expression: input.schedule.expression,
|
|
363
|
+
timeZone: input.timeZone ?? 'UTC',
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
if (input.schedule.kind === 'dailyLocal') {
|
|
367
|
+
return {
|
|
368
|
+
kind: 'dailyLocal',
|
|
369
|
+
localTime: input.schedule.localTime,
|
|
370
|
+
timeZone: input.timeZone ?? 'UTC',
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
return input.schedule;
|
|
374
|
+
}
|
|
247
375
|
function buildCanonicalAutomationRoute(target) {
|
|
248
376
|
return {
|
|
249
377
|
channel: target.channel ?? '',
|
|
@@ -270,50 +398,80 @@ function buildCanonicalAutomationUpsertInput(input) {
|
|
|
270
398
|
}
|
|
271
399
|
async function projectResolvedAssistantCronJob(vault, lookup) {
|
|
272
400
|
const paths = resolveAssistantStatePaths(vault);
|
|
273
|
-
const localStore = await
|
|
274
|
-
|
|
401
|
+
const [localStore, canonicalRecords, runtimeStore] = await Promise.all([
|
|
402
|
+
readAssistantCronStore(paths),
|
|
403
|
+
listCanonicalAssistantCronRecords(vault),
|
|
404
|
+
readAssistantCronCanonicalRuntimeStore(paths),
|
|
405
|
+
]);
|
|
406
|
+
const canonicalFoodIds = buildCanonicalFoodIdSet(canonicalRecords);
|
|
407
|
+
const visibleLocalStore = buildVisibleLocalAssistantCronStore(localStore, canonicalFoodIds);
|
|
408
|
+
const localJob = tryResolveLocalAssistantCronJob(visibleLocalStore, lookup);
|
|
275
409
|
if (localJob) {
|
|
276
410
|
return {
|
|
277
411
|
kind: 'local',
|
|
278
412
|
job: localJob,
|
|
279
413
|
};
|
|
280
414
|
}
|
|
281
|
-
const
|
|
282
|
-
if (!
|
|
415
|
+
const source = findCanonicalAssistantCronRecordInList(canonicalRecords, lookup);
|
|
416
|
+
if (!source) {
|
|
283
417
|
throw new VaultCliError('ASSISTANT_CRON_JOB_NOT_FOUND', `Assistant cron job "${normalizeRequiredAssistantCronText(lookup, 'job')}" was not found.`);
|
|
284
418
|
}
|
|
285
|
-
const
|
|
286
|
-
|
|
419
|
+
const legacyFoodJob = source.kind === 'foodAutoLog'
|
|
420
|
+
? tryResolveLocalAssistantCronFoodJobByFoodId(localStore, source.foodId)
|
|
421
|
+
: null;
|
|
422
|
+
const runtimeState = resolveCanonicalRuntimeState(source, runtimeStore, legacyFoodJob);
|
|
287
423
|
return {
|
|
288
|
-
kind: '
|
|
289
|
-
|
|
424
|
+
kind: 'canonical',
|
|
425
|
+
source,
|
|
290
426
|
runtimeState,
|
|
291
427
|
job: projectCanonicalAssistantCronJob({
|
|
292
|
-
|
|
428
|
+
source,
|
|
293
429
|
runtimeState,
|
|
294
430
|
}),
|
|
295
431
|
};
|
|
296
432
|
}
|
|
297
|
-
function tryResolveLocalAssistantCronJob(store, lookup) {
|
|
433
|
+
function tryResolveLocalAssistantCronJob(store, lookup, options = {}) {
|
|
298
434
|
try {
|
|
299
|
-
|
|
435
|
+
const resolved = resolveAssistantCronJobFromStore(store, lookup);
|
|
436
|
+
if (options.allowFoodAutoLog === false && resolved.foodAutoLog) {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
return resolved;
|
|
300
440
|
}
|
|
301
441
|
catch {
|
|
302
442
|
return null;
|
|
303
443
|
}
|
|
304
444
|
}
|
|
445
|
+
function tryResolveLocalAssistantCronFoodJobByFoodId(store, foodId) {
|
|
446
|
+
return store.jobs.find((job) => job.foodAutoLog?.foodId === foodId) ?? null;
|
|
447
|
+
}
|
|
448
|
+
function buildCanonicalFoodIdSet(records) {
|
|
449
|
+
return new Set(records.flatMap((record) => record.kind === 'foodAutoLog' ? [record.foodId] : []));
|
|
450
|
+
}
|
|
451
|
+
function buildVisibleLocalAssistantCronStore(store, canonicalFoodIds) {
|
|
452
|
+
if (canonicalFoodIds.size === 0) {
|
|
453
|
+
return store;
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
...store,
|
|
457
|
+
jobs: store.jobs.filter((job) => !job.foodAutoLog || !canonicalFoodIds.has(job.foodAutoLog.foodId)),
|
|
458
|
+
};
|
|
459
|
+
}
|
|
305
460
|
export async function listAssistantCronJobs(vault) {
|
|
306
461
|
const paths = resolveAssistantStatePaths(vault);
|
|
307
462
|
const [localStore, canonicalRecords, runtimeStore] = await Promise.all([
|
|
308
463
|
readAssistantCronStore(paths),
|
|
309
464
|
listCanonicalAssistantCronRecords(vault),
|
|
310
|
-
|
|
465
|
+
readAssistantCronCanonicalRuntimeStore(paths),
|
|
311
466
|
]);
|
|
467
|
+
const canonicalFoodIds = buildCanonicalFoodIdSet(canonicalRecords);
|
|
312
468
|
return sortAssistantCronJobs([
|
|
313
|
-
...localStore.jobs,
|
|
314
|
-
...canonicalRecords.map((
|
|
315
|
-
|
|
316
|
-
runtimeState:
|
|
469
|
+
...buildVisibleLocalAssistantCronStore(localStore, canonicalFoodIds).jobs,
|
|
470
|
+
...canonicalRecords.map((source) => projectCanonicalAssistantCronJob({
|
|
471
|
+
source,
|
|
472
|
+
runtimeState: resolveCanonicalRuntimeState(source, runtimeStore, source.kind === 'foodAutoLog'
|
|
473
|
+
? tryResolveLocalAssistantCronFoodJobByFoodId(localStore, source.foodId)
|
|
474
|
+
: null),
|
|
317
475
|
})),
|
|
318
476
|
]);
|
|
319
477
|
}
|
|
@@ -329,30 +487,44 @@ export async function removeAssistantCronJob(vault, job) {
|
|
|
329
487
|
await ensureAssistantCronState(paths);
|
|
330
488
|
return withAssistantCronWriteLock(paths, async () => {
|
|
331
489
|
const store = await readAssistantCronStore(paths);
|
|
332
|
-
const
|
|
490
|
+
const canonicalRecords = await listCanonicalAssistantCronRecords(vault);
|
|
491
|
+
const canonicalFoodIds = buildCanonicalFoodIdSet(canonicalRecords);
|
|
492
|
+
const visibleLocalStore = buildVisibleLocalAssistantCronStore(store, canonicalFoodIds);
|
|
493
|
+
const localJob = tryResolveLocalAssistantCronJob(visibleLocalStore, job);
|
|
333
494
|
if (localJob) {
|
|
334
|
-
const index =
|
|
495
|
+
const index = store.jobs.findIndex((entry) => entry.jobId === localJob.jobId);
|
|
335
496
|
const [removed] = store.jobs.splice(index, 1);
|
|
336
497
|
await writeAssistantCronStore(paths, store);
|
|
337
498
|
return removed;
|
|
338
499
|
}
|
|
339
500
|
const resolved = await projectResolvedAssistantCronJob(vault, job);
|
|
340
|
-
if (resolved.kind !== '
|
|
501
|
+
if (resolved.kind !== 'canonical') {
|
|
341
502
|
return resolved.job;
|
|
342
503
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
504
|
+
if (resolved.source.kind === 'automation') {
|
|
505
|
+
await upsertAutomation(buildCanonicalAutomationUpsertInput({
|
|
506
|
+
vault,
|
|
507
|
+
automationId: resolved.source.automationId,
|
|
508
|
+
automation: resolved.source,
|
|
509
|
+
title: resolved.source.title,
|
|
510
|
+
status: 'archived',
|
|
511
|
+
schedule: resolved.source.schedule,
|
|
512
|
+
route: resolved.source.route,
|
|
513
|
+
instructions: resolved.source.instructions,
|
|
514
|
+
}));
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
const foodId = resolved.source.foodId;
|
|
518
|
+
await clearCanonicalFoodAutoLogSchedule(vault, foodId);
|
|
519
|
+
const nextLocalJobs = store.jobs.filter((entry) => entry.foodAutoLog?.foodId !== foodId);
|
|
520
|
+
if (nextLocalJobs.length !== store.jobs.length) {
|
|
521
|
+
store.jobs = nextLocalJobs;
|
|
522
|
+
await writeAssistantCronStore(paths, store);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
|
|
526
|
+
if (removeAssistantCronCanonicalRuntimeRecord(runtimeStore, resolveCanonicalAssistantCronJobId(resolved.source))) {
|
|
527
|
+
await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
|
|
356
528
|
}
|
|
357
529
|
return resolved.job;
|
|
358
530
|
});
|
|
@@ -387,39 +559,47 @@ export async function setAssistantCronJobEnabled(vault, job, enabled) {
|
|
|
387
559
|
return updated;
|
|
388
560
|
}
|
|
389
561
|
const resolved = await projectResolvedAssistantCronJob(vault, job);
|
|
390
|
-
if (resolved.kind !== '
|
|
562
|
+
if (resolved.kind !== 'canonical') {
|
|
391
563
|
return resolved.job;
|
|
392
564
|
}
|
|
565
|
+
if (resolved.source.kind === 'foodAutoLog') {
|
|
566
|
+
throw new VaultCliError('ASSISTANT_CRON_INVALID_STATE', `Recurring food auto-log job "${resolved.job.name}" is controlled by the canonical food record, not assistant cron enable/disable.`);
|
|
567
|
+
}
|
|
393
568
|
const now = new Date();
|
|
394
569
|
const nextRunAt = enabled
|
|
395
|
-
?
|
|
396
|
-
|
|
570
|
+
? computeAssistantCronNextRunAt(resolveAssistantCronResolvedSchedule({
|
|
571
|
+
schedule: resolved.source.schedule,
|
|
572
|
+
timeZone: resolved.source.timeZone,
|
|
573
|
+
}), now)
|
|
574
|
+
: null;
|
|
397
575
|
if (enabled && nextRunAt === null) {
|
|
398
576
|
throw new VaultCliError('ASSISTANT_CRON_INVALID_STATE', `Assistant cron job "${resolved.job.name}" no longer has a future scheduled run. Run it manually or recreate it with a new schedule.`);
|
|
399
577
|
}
|
|
400
578
|
const updatedAutomation = await upsertAutomation(buildCanonicalAutomationUpsertInput({
|
|
401
579
|
vault,
|
|
402
|
-
automationId: resolved.
|
|
403
|
-
automation: resolved.
|
|
404
|
-
title: resolved.
|
|
580
|
+
automationId: resolved.source.automationId,
|
|
581
|
+
automation: resolved.source,
|
|
582
|
+
title: resolved.source.title,
|
|
405
583
|
status: enabled ? 'active' : 'paused',
|
|
406
|
-
schedule:
|
|
407
|
-
route: resolved.
|
|
408
|
-
instructions: resolved.
|
|
584
|
+
schedule: resolved.source.schedule,
|
|
585
|
+
route: resolved.source.route,
|
|
586
|
+
instructions: resolved.source.instructions,
|
|
409
587
|
}));
|
|
410
|
-
const runtimeStore = await
|
|
588
|
+
const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
|
|
411
589
|
const updatedRuntimeState = {
|
|
412
590
|
...resolved.runtimeState,
|
|
413
591
|
updatedAt: now.toISOString(),
|
|
414
592
|
state: {
|
|
415
593
|
...resolved.runtimeState.state,
|
|
416
|
-
|
|
594
|
+
activatedAt: enabled ? now.toISOString() : resolved.runtimeState.state.activatedAt,
|
|
595
|
+
pendingOccurrenceAt: null,
|
|
596
|
+
retryAfterAt: null,
|
|
417
597
|
},
|
|
418
598
|
};
|
|
419
|
-
|
|
420
|
-
await
|
|
599
|
+
upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, updatedRuntimeState);
|
|
600
|
+
await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
|
|
421
601
|
return projectCanonicalAssistantCronJob({
|
|
422
|
-
|
|
602
|
+
source: requireCanonicalAssistantCronRecord(updatedAutomation.record, await resolveAssistantCronDefaultTimeZone(vault)),
|
|
423
603
|
runtimeState: updatedRuntimeState,
|
|
424
604
|
});
|
|
425
605
|
});
|
|
@@ -488,7 +668,7 @@ export async function setAssistantCronJobTarget(input) {
|
|
|
488
668
|
};
|
|
489
669
|
}
|
|
490
670
|
const resolved = await projectResolvedAssistantCronJob(resolvedInput.vault, resolvedInput.job);
|
|
491
|
-
if (resolved.kind !== '
|
|
671
|
+
if (resolved.kind !== 'canonical') {
|
|
492
672
|
return {
|
|
493
673
|
job: resolved.job,
|
|
494
674
|
beforeTarget: buildAssistantCronTargetSnapshot(resolved.job),
|
|
@@ -498,6 +678,9 @@ export async function setAssistantCronJobTarget(input) {
|
|
|
498
678
|
dryRun: Boolean(resolvedInput.dryRun),
|
|
499
679
|
};
|
|
500
680
|
}
|
|
681
|
+
if (resolved.source.kind === 'foodAutoLog') {
|
|
682
|
+
throw new VaultCliError('ASSISTANT_CRON_DELIVERY_REQUIRED', `Recurring food auto-log job "${resolved.job.name}" does not support assistant delivery targeting.`);
|
|
683
|
+
}
|
|
501
684
|
if (resolved.runtimeState.state.runningAt !== null) {
|
|
502
685
|
throw new VaultCliError('ASSISTANT_CRON_JOB_RUNNING', `Assistant cron job "${resolved.job.name}" is already running.`);
|
|
503
686
|
}
|
|
@@ -536,25 +719,25 @@ export async function setAssistantCronJobTarget(input) {
|
|
|
536
719
|
const now = (resolvedInput.now ?? new Date()).toISOString();
|
|
537
720
|
const updatedAutomation = await upsertAutomation(buildCanonicalAutomationUpsertInput({
|
|
538
721
|
vault: resolvedInput.vault,
|
|
539
|
-
automationId: resolved.
|
|
540
|
-
automation: resolved.
|
|
541
|
-
title: resolved.
|
|
542
|
-
status: resolved.
|
|
543
|
-
schedule:
|
|
722
|
+
automationId: resolved.source.automationId,
|
|
723
|
+
automation: resolved.source,
|
|
724
|
+
title: resolved.source.title,
|
|
725
|
+
status: resolved.source.status,
|
|
726
|
+
schedule: resolved.source.schedule,
|
|
544
727
|
route: buildCanonicalAutomationRoute(afterTarget.target),
|
|
545
|
-
instructions: resolved.
|
|
728
|
+
instructions: resolved.source.instructions,
|
|
546
729
|
}));
|
|
547
|
-
const runtimeStore = await
|
|
730
|
+
const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
|
|
548
731
|
const updatedRuntimeState = {
|
|
549
732
|
...resolved.runtimeState,
|
|
550
733
|
alias: afterTarget.target.alias,
|
|
551
734
|
sessionId: afterTarget.target.sessionId,
|
|
552
735
|
updatedAt: now,
|
|
553
736
|
};
|
|
554
|
-
|
|
555
|
-
await
|
|
737
|
+
upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, updatedRuntimeState);
|
|
738
|
+
await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
|
|
556
739
|
const updatedJob = projectCanonicalAssistantCronJob({
|
|
557
|
-
|
|
740
|
+
source: requireCanonicalAssistantCronRecord(updatedAutomation.record, await resolveAssistantCronDefaultTimeZone(resolvedInput.vault)),
|
|
558
741
|
runtimeState: updatedRuntimeState,
|
|
559
742
|
});
|
|
560
743
|
return {
|
|
@@ -638,29 +821,34 @@ export async function runAssistantCronJobNow(input) {
|
|
|
638
821
|
};
|
|
639
822
|
}
|
|
640
823
|
const resolved = await projectResolvedAssistantCronJob(input.vault, input.job);
|
|
641
|
-
if (resolved.kind !== '
|
|
824
|
+
if (resolved.kind !== 'canonical') {
|
|
642
825
|
return resolved;
|
|
643
826
|
}
|
|
644
827
|
if (resolved.runtimeState.state.runningAt !== null) {
|
|
645
828
|
throw new VaultCliError('ASSISTANT_CRON_JOB_RUNNING', `Assistant cron job "${resolved.job.name}" is already running.`);
|
|
646
829
|
}
|
|
647
|
-
const runtimeStore = await
|
|
830
|
+
const runtimeStore = await readAssistantCronCanonicalRuntimeStore(paths);
|
|
831
|
+
const now = new Date().toISOString();
|
|
832
|
+
const occurrenceAt = resolveCanonicalAssistantCronOccurrenceAt(resolved.source, resolved.runtimeState) ??
|
|
833
|
+
now;
|
|
648
834
|
const updatedRuntimeState = {
|
|
649
835
|
...resolved.runtimeState,
|
|
650
|
-
updatedAt:
|
|
836
|
+
updatedAt: now,
|
|
651
837
|
state: {
|
|
652
838
|
...resolved.runtimeState.state,
|
|
653
|
-
|
|
839
|
+
pendingOccurrenceAt: occurrenceAt,
|
|
840
|
+
retryAfterAt: null,
|
|
841
|
+
runningAt: now,
|
|
654
842
|
runningPid: process.pid,
|
|
655
843
|
},
|
|
656
844
|
};
|
|
657
|
-
|
|
658
|
-
await
|
|
845
|
+
upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, updatedRuntimeState);
|
|
846
|
+
await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
|
|
659
847
|
return {
|
|
660
848
|
...resolved,
|
|
661
849
|
runtimeState: updatedRuntimeState,
|
|
662
850
|
job: projectCanonicalAssistantCronJob({
|
|
663
|
-
|
|
851
|
+
source: resolved.source,
|
|
664
852
|
runtimeState: updatedRuntimeState,
|
|
665
853
|
}),
|
|
666
854
|
};
|
|
@@ -755,22 +943,26 @@ async function claimNextDueAssistantCronJob(paths, vault) {
|
|
|
755
943
|
const [store, canonicalRecords, runtimeStore] = await Promise.all([
|
|
756
944
|
readAssistantCronStore(paths),
|
|
757
945
|
listCanonicalAssistantCronRecords(vault, ['active']),
|
|
758
|
-
|
|
946
|
+
readAssistantCronCanonicalRuntimeStore(paths),
|
|
759
947
|
]);
|
|
760
948
|
const now = new Date().toISOString();
|
|
761
|
-
const
|
|
762
|
-
|
|
949
|
+
const canonicalFoodIds = buildCanonicalFoodIdSet(canonicalRecords);
|
|
950
|
+
const visibleLocalStore = buildVisibleLocalAssistantCronStore(store, canonicalFoodIds);
|
|
951
|
+
const canonicalEntries = canonicalRecords.map((source) => {
|
|
952
|
+
const runtimeState = resolveCanonicalRuntimeState(source, runtimeStore, source.kind === 'foodAutoLog'
|
|
953
|
+
? tryResolveLocalAssistantCronFoodJobByFoodId(store, source.foodId)
|
|
954
|
+
: null);
|
|
763
955
|
return {
|
|
764
|
-
|
|
956
|
+
source,
|
|
765
957
|
runtimeState,
|
|
766
958
|
job: projectCanonicalAssistantCronJob({
|
|
767
|
-
|
|
959
|
+
source,
|
|
768
960
|
runtimeState,
|
|
769
961
|
}),
|
|
770
962
|
};
|
|
771
963
|
});
|
|
772
964
|
const candidate = sortAssistantCronJobs([
|
|
773
|
-
...
|
|
965
|
+
...visibleLocalStore.jobs,
|
|
774
966
|
...canonicalEntries.map((entry) => entry.job),
|
|
775
967
|
]).find((job) => isAssistantCronJobDue(job, now));
|
|
776
968
|
if (!candidate) {
|
|
@@ -794,24 +986,27 @@ async function claimNextDueAssistantCronJob(paths, vault) {
|
|
|
794
986
|
job: claimed,
|
|
795
987
|
};
|
|
796
988
|
}
|
|
797
|
-
const canonicalEntry = canonicalEntries.find((entry) => entry.
|
|
989
|
+
const canonicalEntry = canonicalEntries.find((entry) => resolveCanonicalAssistantCronJobId(entry.source) === candidate.jobId);
|
|
990
|
+
const occurrenceAt = resolveCanonicalAssistantCronOccurrenceAt(canonicalEntry.source, canonicalEntry.runtimeState) ?? candidate.state.nextRunAt ?? now;
|
|
798
991
|
const updatedRuntimeState = {
|
|
799
992
|
...canonicalEntry.runtimeState,
|
|
800
993
|
updatedAt: now,
|
|
801
994
|
state: {
|
|
802
995
|
...canonicalEntry.runtimeState.state,
|
|
996
|
+
pendingOccurrenceAt: occurrenceAt,
|
|
997
|
+
retryAfterAt: null,
|
|
803
998
|
runningAt: now,
|
|
804
999
|
runningPid: process.pid,
|
|
805
1000
|
},
|
|
806
1001
|
};
|
|
807
|
-
|
|
808
|
-
await
|
|
1002
|
+
upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, updatedRuntimeState);
|
|
1003
|
+
await writeAssistantCronCanonicalRuntimeStore(paths, runtimeStore);
|
|
809
1004
|
return {
|
|
810
|
-
kind: '
|
|
811
|
-
|
|
1005
|
+
kind: 'canonical',
|
|
1006
|
+
source: canonicalEntry.source,
|
|
812
1007
|
runtimeState: updatedRuntimeState,
|
|
813
1008
|
job: projectCanonicalAssistantCronJob({
|
|
814
|
-
|
|
1009
|
+
source: canonicalEntry.source,
|
|
815
1010
|
runtimeState: updatedRuntimeState,
|
|
816
1011
|
}),
|
|
817
1012
|
};
|
|
@@ -918,57 +1113,65 @@ async function executeClaimedAssistantCronJob(input) {
|
|
|
918
1113
|
removedAfterRun,
|
|
919
1114
|
};
|
|
920
1115
|
}
|
|
921
|
-
const runtimeStore = await
|
|
922
|
-
const currentRuntimeState =
|
|
923
|
-
const
|
|
924
|
-
automation: input.job.automation,
|
|
925
|
-
runtimeState: currentRuntimeState,
|
|
926
|
-
});
|
|
927
|
-
const finalizedJob = finalizeAssistantCronJobAfterRun({
|
|
928
|
-
job: currentJob,
|
|
1116
|
+
const runtimeStore = await readAssistantCronCanonicalRuntimeStore(input.paths);
|
|
1117
|
+
const currentRuntimeState = findAssistantCronCanonicalRuntimeRecord(runtimeStore, resolveCanonicalAssistantCronJobId(input.job.source)) ?? input.job.runtimeState;
|
|
1118
|
+
const updatedRuntimeState = finalizeCanonicalAssistantCronRuntimeAfterRun({
|
|
929
1119
|
finishedAt,
|
|
930
|
-
responseSessionId: input.job.automation.continuityPolicy === 'preserve' ? sessionId : null,
|
|
931
1120
|
run: {
|
|
932
1121
|
...run,
|
|
933
1122
|
status,
|
|
934
1123
|
},
|
|
1124
|
+
runtimeState: currentRuntimeState,
|
|
1125
|
+
responseSessionId: input.job.source.kind === 'automation' &&
|
|
1126
|
+
input.job.source.continuityPolicy === 'preserve'
|
|
1127
|
+
? sessionId
|
|
1128
|
+
: null,
|
|
1129
|
+
source: input.job.source,
|
|
935
1130
|
});
|
|
936
|
-
const
|
|
1131
|
+
const persistedRuntimeState = {
|
|
937
1132
|
...currentRuntimeState,
|
|
938
|
-
alias: input.job.
|
|
939
|
-
|
|
1133
|
+
alias: input.job.source.kind === 'automation' &&
|
|
1134
|
+
input.job.source.continuityPolicy === 'preserve'
|
|
1135
|
+
? updatedRuntimeState.alias
|
|
940
1136
|
: null,
|
|
941
|
-
sessionId: input.job.
|
|
942
|
-
|
|
1137
|
+
sessionId: input.job.source.kind === 'automation' &&
|
|
1138
|
+
input.job.source.continuityPolicy === 'preserve'
|
|
1139
|
+
? updatedRuntimeState.sessionId
|
|
943
1140
|
: null,
|
|
944
1141
|
updatedAt: finishedAt,
|
|
945
|
-
state:
|
|
1142
|
+
state: updatedRuntimeState.state,
|
|
946
1143
|
};
|
|
1144
|
+
const finalizedJob = projectCanonicalAssistantCronJob({
|
|
1145
|
+
source: input.job.source,
|
|
1146
|
+
runtimeState: persistedRuntimeState,
|
|
1147
|
+
});
|
|
947
1148
|
let removedAfterRun = false;
|
|
948
1149
|
if (shouldRemoveAssistantCronJobAfterRun(finalizedJob, run)) {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1150
|
+
if (input.job.source.kind === 'automation') {
|
|
1151
|
+
await upsertAutomation(buildCanonicalAutomationUpsertInput({
|
|
1152
|
+
vault: input.vault,
|
|
1153
|
+
automationId: input.job.source.automationId,
|
|
1154
|
+
automation: input.job.source,
|
|
1155
|
+
title: input.job.source.title,
|
|
1156
|
+
status: 'archived',
|
|
1157
|
+
schedule: input.job.source.schedule,
|
|
1158
|
+
route: input.job.source.route,
|
|
1159
|
+
instructions: input.job.source.instructions,
|
|
1160
|
+
}));
|
|
1161
|
+
}
|
|
1162
|
+
removeAssistantCronCanonicalRuntimeRecord(runtimeStore, resolveCanonicalAssistantCronJobId(input.job.source));
|
|
960
1163
|
removedAfterRun = true;
|
|
961
1164
|
}
|
|
962
1165
|
else {
|
|
963
|
-
|
|
1166
|
+
upsertAssistantCronCanonicalRuntimeRecord(runtimeStore, persistedRuntimeState);
|
|
964
1167
|
}
|
|
965
|
-
await
|
|
1168
|
+
await writeAssistantCronCanonicalRuntimeStore(input.paths, runtimeStore);
|
|
966
1169
|
return {
|
|
967
1170
|
job: removedAfterRun
|
|
968
1171
|
? finalizedJob
|
|
969
1172
|
: projectCanonicalAssistantCronJob({
|
|
970
|
-
|
|
971
|
-
runtimeState:
|
|
1173
|
+
source: input.job.source,
|
|
1174
|
+
runtimeState: persistedRuntimeState,
|
|
972
1175
|
}),
|
|
973
1176
|
removedAfterRun,
|
|
974
1177
|
};
|
|
@@ -1063,14 +1266,125 @@ function resolveAssistantCronFailureBackoffMs(failureCount) {
|
|
|
1063
1266
|
}
|
|
1064
1267
|
return 60 * 60_000;
|
|
1065
1268
|
}
|
|
1269
|
+
function resolveCanonicalAssistantCronOccurrenceAt(source, runtimeState) {
|
|
1270
|
+
if (!isCanonicalAssistantCronSourceEnabled(source)) {
|
|
1271
|
+
return null;
|
|
1272
|
+
}
|
|
1273
|
+
if (runtimeState.state.pendingOccurrenceAt) {
|
|
1274
|
+
return runtimeState.state.pendingOccurrenceAt;
|
|
1275
|
+
}
|
|
1276
|
+
if (source.schedule.kind === 'at') {
|
|
1277
|
+
return source.schedule.at;
|
|
1278
|
+
}
|
|
1279
|
+
const anchorAt = runtimeState.state.lastSucceededAt ?? runtimeState.state.activatedAt;
|
|
1280
|
+
if (!anchorAt) {
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1283
|
+
return computeAssistantCronNextRunAt(resolveAssistantCronResolvedSchedule({
|
|
1284
|
+
schedule: source.schedule,
|
|
1285
|
+
timeZone: source.kind === 'automation' ? source.timeZone : source.timeZone,
|
|
1286
|
+
}), new Date(anchorAt));
|
|
1287
|
+
}
|
|
1288
|
+
function resolveCanonicalAssistantCronNextRunAt(input) {
|
|
1289
|
+
if (!isCanonicalAssistantCronSourceEnabled(input.source)) {
|
|
1290
|
+
return null;
|
|
1291
|
+
}
|
|
1292
|
+
if (input.state.pendingOccurrenceAt) {
|
|
1293
|
+
return input.state.retryAfterAt ?? input.state.pendingOccurrenceAt;
|
|
1294
|
+
}
|
|
1295
|
+
if (input.source.schedule.kind === 'at') {
|
|
1296
|
+
return input.source.schedule.at;
|
|
1297
|
+
}
|
|
1298
|
+
const anchorAt = input.state.lastSucceededAt ?? input.state.activatedAt;
|
|
1299
|
+
if (!anchorAt) {
|
|
1300
|
+
return null;
|
|
1301
|
+
}
|
|
1302
|
+
return computeAssistantCronNextRunAt(resolveAssistantCronResolvedSchedule({
|
|
1303
|
+
schedule: input.source.schedule,
|
|
1304
|
+
timeZone: input.source.kind === 'automation'
|
|
1305
|
+
? input.source.timeZone
|
|
1306
|
+
: input.source.timeZone,
|
|
1307
|
+
}), new Date(anchorAt));
|
|
1308
|
+
}
|
|
1309
|
+
function finalizeCanonicalAssistantCronRuntimeAfterRun(input) {
|
|
1310
|
+
const runningClearedState = {
|
|
1311
|
+
...input.runtimeState.state,
|
|
1312
|
+
runningAt: null,
|
|
1313
|
+
runningPid: null,
|
|
1314
|
+
lastRunAt: input.finishedAt,
|
|
1315
|
+
};
|
|
1316
|
+
if (input.run.status === 'succeeded') {
|
|
1317
|
+
return {
|
|
1318
|
+
...input.runtimeState,
|
|
1319
|
+
sessionId: input.responseSessionId ?? input.runtimeState.sessionId,
|
|
1320
|
+
updatedAt: input.finishedAt,
|
|
1321
|
+
state: {
|
|
1322
|
+
...runningClearedState,
|
|
1323
|
+
pendingOccurrenceAt: null,
|
|
1324
|
+
retryAfterAt: null,
|
|
1325
|
+
lastSucceededAt: input.finishedAt,
|
|
1326
|
+
lastError: null,
|
|
1327
|
+
consecutiveFailures: 0,
|
|
1328
|
+
},
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
const failureCount = input.runtimeState.state.consecutiveFailures + 1;
|
|
1332
|
+
const retryAfterAt = isCanonicalAssistantCronSourceEnabled(input.source)
|
|
1333
|
+
? new Date(Date.parse(input.finishedAt) + resolveAssistantCronFailureBackoffMs(failureCount)).toISOString()
|
|
1334
|
+
: null;
|
|
1335
|
+
return {
|
|
1336
|
+
...input.runtimeState,
|
|
1337
|
+
updatedAt: input.finishedAt,
|
|
1338
|
+
state: {
|
|
1339
|
+
...runningClearedState,
|
|
1340
|
+
pendingOccurrenceAt: input.runtimeState.state.pendingOccurrenceAt ??
|
|
1341
|
+
resolveCanonicalAssistantCronOccurrenceAt(input.source, input.runtimeState),
|
|
1342
|
+
retryAfterAt,
|
|
1343
|
+
lastFailedAt: input.finishedAt,
|
|
1344
|
+
lastError: input.run.error,
|
|
1345
|
+
consecutiveFailures: failureCount,
|
|
1346
|
+
},
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
function migrateLegacyLocalFoodRuntimeState(source, legacyLocalJob) {
|
|
1350
|
+
if (source.kind !== 'foodAutoLog' || !legacyLocalJob) {
|
|
1351
|
+
return null;
|
|
1352
|
+
}
|
|
1353
|
+
return {
|
|
1354
|
+
schema: 'murph.assistant-canonical-cron-runtime-state.v2',
|
|
1355
|
+
jobId: source.jobId,
|
|
1356
|
+
alias: null,
|
|
1357
|
+
sessionId: null,
|
|
1358
|
+
createdAt: legacyLocalJob.createdAt,
|
|
1359
|
+
updatedAt: legacyLocalJob.updatedAt,
|
|
1360
|
+
state: {
|
|
1361
|
+
activatedAt: legacyLocalJob.createdAt,
|
|
1362
|
+
pendingOccurrenceAt: legacyLocalJob.state.runningAt !== null ||
|
|
1363
|
+
legacyLocalJob.state.consecutiveFailures > 0
|
|
1364
|
+
? legacyLocalJob.state.nextRunAt
|
|
1365
|
+
: null,
|
|
1366
|
+
retryAfterAt: legacyLocalJob.state.consecutiveFailures > 0
|
|
1367
|
+
? legacyLocalJob.state.nextRunAt
|
|
1368
|
+
: null,
|
|
1369
|
+
lastRunAt: legacyLocalJob.state.lastRunAt,
|
|
1370
|
+
lastSucceededAt: legacyLocalJob.state.lastSucceededAt,
|
|
1371
|
+
lastFailedAt: legacyLocalJob.state.lastFailedAt,
|
|
1372
|
+
consecutiveFailures: legacyLocalJob.state.consecutiveFailures,
|
|
1373
|
+
lastError: legacyLocalJob.state.lastError,
|
|
1374
|
+
runningAt: legacyLocalJob.state.runningAt,
|
|
1375
|
+
runningPid: legacyLocalJob.state.runningPid,
|
|
1376
|
+
},
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1066
1379
|
async function resolveAssistantCronScheduleForVault(vault, schedule) {
|
|
1067
|
-
|
|
1068
|
-
|
|
1380
|
+
const publicSchedule = assistantCronScheduleSchema.parse(schedule);
|
|
1381
|
+
if (publicSchedule.kind === 'cron' || publicSchedule.kind === 'dailyLocal') {
|
|
1382
|
+
return resolveAssistantCronResolvedSchedule({
|
|
1383
|
+
schedule: publicSchedule,
|
|
1384
|
+
timeZone: await resolveAssistantCronDefaultTimeZone(vault),
|
|
1385
|
+
});
|
|
1069
1386
|
}
|
|
1070
|
-
return
|
|
1071
|
-
...schedule,
|
|
1072
|
-
timeZone: await resolveAssistantCronDefaultTimeZone(vault),
|
|
1073
|
-
});
|
|
1387
|
+
return publicSchedule;
|
|
1074
1388
|
}
|
|
1075
1389
|
async function resolveAssistantCronDefaultTimeZone(vault) {
|
|
1076
1390
|
try {
|
|
@@ -1083,6 +1397,36 @@ async function resolveAssistantCronDefaultTimeZone(vault) {
|
|
|
1083
1397
|
return resolveSystemTimeZone();
|
|
1084
1398
|
}
|
|
1085
1399
|
}
|
|
1400
|
+
async function loadFoodAutoLogCoreRuntime() {
|
|
1401
|
+
return loadRuntimeModule('@murphai/core');
|
|
1402
|
+
}
|
|
1403
|
+
async function clearCanonicalFoodAutoLogSchedule(vault, foodId) {
|
|
1404
|
+
const core = await loadFoodAutoLogCoreRuntime();
|
|
1405
|
+
const existing = await core.readFood({
|
|
1406
|
+
vaultRoot: vault,
|
|
1407
|
+
foodId,
|
|
1408
|
+
});
|
|
1409
|
+
await core.upsertFood({
|
|
1410
|
+
vaultRoot: vault,
|
|
1411
|
+
foodId: existing.foodId,
|
|
1412
|
+
slug: existing.slug,
|
|
1413
|
+
title: existing.title,
|
|
1414
|
+
status: existing.status,
|
|
1415
|
+
summary: existing.summary,
|
|
1416
|
+
kind: existing.kind,
|
|
1417
|
+
brand: existing.brand,
|
|
1418
|
+
vendor: existing.vendor,
|
|
1419
|
+
location: existing.location,
|
|
1420
|
+
serving: existing.serving,
|
|
1421
|
+
nutrition: existing.nutrition,
|
|
1422
|
+
aliases: existing.aliases,
|
|
1423
|
+
ingredients: existing.ingredients,
|
|
1424
|
+
tags: existing.tags,
|
|
1425
|
+
note: existing.note,
|
|
1426
|
+
attachedProtocolIds: existing.attachedProtocolIds,
|
|
1427
|
+
autoLogDaily: null,
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1086
1430
|
function assistantCronJobHasStableSessionLocator(job) {
|
|
1087
1431
|
return Boolean(job.target.sessionId ||
|
|
1088
1432
|
job.target.alias ||
|