@xopcai/xopc 0.0.120 → 0.0.122
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/README.md +23 -3
- package/README.zh-CN.md +23 -3
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/dashscope/src/image-generation-provider.d.ts +6 -5
- package/dist/extensions/dashscope/src/image-generation-provider.js +40 -64
- package/dist/extensions/dashscope/src/image-generation-provider.js.map +1 -1
- package/dist/extensions/dashscope/src/index.d.ts +1 -1
- package/dist/extensions/dashscope/src/index.js +2 -2
- package/dist/extensions/dashscope/xopc.extension.json +3 -2
- package/dist/extensions/minimax/src/image-generation-provider.d.ts +7 -5
- package/dist/extensions/minimax/src/image-generation-provider.js +43 -37
- package/dist/extensions/minimax/src/image-generation-provider.js.map +1 -1
- package/dist/extensions/minimax/src/index.d.ts +1 -1
- package/dist/extensions/minimax/src/index.js +2 -2
- package/dist/extensions/minimax/xopc.extension.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +41 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-APTlX9Sq.js → agent-avatar-dicebear-CK3s5cJo.js} +1 -1
- package/dist/gateway/static/root/assets/agents-SsQrj9B-.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DTKc5HHT.js → app-management-settings-panel-CWsNHtTs.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-BTciFrE9.js → appearance-settings-C4b8y6iZ.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CYb6fame.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-CiHaUMII.js → archive-plugin-DAtNW3Ia.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-t4gSrNjL.js → attachment-load-Dm-RY54y.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-BKHewSVT.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-DpOOq1nk.js +1 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BAbSldW5.js → binary-plugins-BG6Xnk71.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BNr_82xl.js → block-editor-DfndiO3h.js} +28 -28
- package/dist/gateway/static/root/assets/browser-settings-page-9nXxgh4u.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-tzD702Gg.js → capability-presets-api-Cx93GLdw.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-AGhTueAc.js → capability-presets-settings-panel-D528_YFy.js} +1 -1
- package/dist/gateway/static/root/assets/{channel-recipient-api-DL_KzwGE.js → channel-recipient-api-DdPTtEs8.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-Ck-3h5lI.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-DL-fAqE_.js +2 -0
- package/dist/gateway/static/root/assets/directory-picker-path-field-D835EHJd.js +1 -0
- package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +1 -0
- package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +1 -0
- package/dist/gateway/static/root/assets/dreaming-settings-CCa1F7Fg.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-Dl2kO0Sf.js → extension-debug-page-W2ITCPSA.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DmbLPsx_.js → extension-page-DrvUytvn.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-qM8aLT5u.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-B3ME5Eri.js → fetch-ovkvM8KQ.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-DI9_BBTo.js → gateway-config-api-BB3biuD0.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-mmmnIH27.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CSZQTz6K.js → gateway-startup-retry-CanQ8UcR.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-CNqNdEkQ.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-Ceu5zrN6.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-Bhzqrp2w.js → goals-config-api-BBOX6mUl.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-BP1kfvWv.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-Bh3A7OZV.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-YoYgKlfX.js +1 -0
- package/dist/gateway/static/root/assets/index-DdqSO9R2.js +191 -0
- package/dist/gateway/static/root/assets/index-jGB-2nI-.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-kMp08SlX.js → keyboard-shortcuts-settings-B4TKJHla.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-BgVk5DvZ.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-split-Bc0w40vz.js → markdown-split-DcFtdLci.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-DJ_HvgIy.js → media-plugins-B6SmeLVB.js} +1 -1
- package/dist/gateway/static/root/assets/messages-B5O4OIEo.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BU0x8PGP.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-D6JYVP4I.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-mqRJYnJS.js +2 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BbA7sRd_.js → preview-open-alternatives-C29O19s7.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DOTgzoeh.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-DGUIb4y5.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-DVKKUj3u.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-Dividh61.js → save-bar-controls-B4ad9GfB.js} +1 -1
- package/dist/gateway/static/root/assets/schedule-field-DdYncfLR.js +1 -0
- package/dist/gateway/static/root/assets/schema-form-BMTrDE-7.js +1 -0
- package/dist/gateway/static/root/assets/segmented-styles-BL8oLBEp.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-BVbzUWxW.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DrNNoSqE.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BMCOfuE_.js → settings-collapsible-section-MwTW2eK4.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-DBkGwpIN.js → settings-form-section-Dg6LBbcr.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-CMDqgeMR.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-layout-BX4T-OLF.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-Ce1pcFtR.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-DWE-dUFh.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-aKSraR8l.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CS-FU_B-.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-BaF3u0LA.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-CrmEnyX4.js → system-settings-panel-Dd6Y35Cm.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-BAsGn25g.js → typed-models-lib-Cx6XV5A2.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-C7vcAoGb.js → use-channel-catalog-D4sMbmy7.js} +1 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-Bx-hjMQc.js +1 -0
- package/dist/gateway/static/root/assets/{utils-Dl9efgnV.js → utils-D7b_vZnv.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-CkhbRt1q.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel--TdohF5N.js +3 -0
- package/dist/gateway/static/root/assets/workflow-start-dialog-B0lavx_o.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-CZR05Bu_.js +18 -0
- package/dist/gateway/static/root/index.html +7 -8
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +2 -0
- package/dist/src/agent/agent-manager.js +47 -7
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/context/project-context.d.ts +19 -0
- package/dist/src/agent/context/project-context.js +90 -0
- package/dist/src/agent/context/project-context.js.map +1 -0
- package/dist/src/agent/embedded/xopc-auth-storage.d.ts +1 -5
- package/dist/src/agent/embedded/xopc-auth-storage.js +2 -8
- package/dist/src/agent/embedded/xopc-auth-storage.js.map +1 -1
- package/dist/src/agent/embedded/xopc-tools-bridge.js +23 -0
- package/dist/src/agent/embedded/xopc-tools-bridge.js.map +1 -1
- package/dist/src/agent/goals/checklist-judge.js +1 -1
- package/dist/src/agent/goals/checklist-judge.js.map +1 -1
- package/dist/src/agent/goals/goal-locale.js +2 -2
- package/dist/src/agent/goals/judge.js +1 -1
- package/dist/src/agent/goals/judge.js.map +1 -1
- package/dist/src/agent/image/tool-model-config.d.ts +2 -0
- package/dist/src/agent/image/tool-model-config.js +2 -2
- package/dist/src/agent/image/tool-model-config.js.map +1 -1
- package/dist/src/agent/image/understanding/pi-ai-provider.js +1 -1
- package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
- package/dist/src/agent/memory/compaction.d.ts +1 -1
- package/dist/src/agent/memory/compaction.js +1 -1
- package/dist/src/agent/memory/compaction.js.map +1 -1
- package/dist/src/agent/memory/types.d.ts +1 -0
- package/dist/src/agent/middleware/self-verify.d.ts +3 -0
- package/dist/src/agent/middleware/self-verify.js +18 -0
- package/dist/src/agent/middleware/self-verify.js.map +1 -1
- package/dist/src/agent/orchestration/agent-event-handler.js +28 -3
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +21 -5
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.d.ts +1 -0
- package/dist/src/agent/prompt/service-prompt-builder.js +3 -0
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/prompt/system-prompt-params.d.ts +2 -0
- package/dist/src/agent/prompt/system-prompt-params.js +1 -0
- package/dist/src/agent/prompt/system-prompt-params.js.map +1 -1
- package/dist/src/agent/prompt/system-prompt.d.ts +2 -0
- package/dist/src/agent/prompt/system-prompt.js +14 -1
- package/dist/src/agent/prompt/system-prompt.js.map +1 -1
- package/dist/src/agent/sandbox/path-policy.js +30 -6
- package/dist/src/agent/sandbox/path-policy.js.map +1 -1
- package/dist/src/agent/service/btw-query.js +1 -1
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/service.js +4 -3
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/session-config-service.js +6 -1
- package/dist/src/agent/session/session-config-service.js.map +1 -1
- package/dist/src/agent/session/session-hydrator.js +7 -3
- package/dist/src/agent/session/session-hydrator.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +9 -5
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/starter-agents.js +18 -47
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +12 -1
- package/dist/src/agent/tools/image-generate-tool.js.map +1 -1
- package/dist/src/agent/tools/session-search-tool.js +1 -1
- package/dist/src/agent/tools/session-search-tool.js.map +1 -1
- package/dist/src/agent/tools/web-extract.js +1 -1
- package/dist/src/agent/tools/web-extract.js.map +1 -1
- package/dist/src/agent/workflow/index.js +2 -2
- package/dist/src/agent/workflow/runtime.js +1 -1
- package/dist/src/agent-manifest/index.js +2 -2
- package/dist/src/agent-manifest/schema.d.ts +66 -0
- package/dist/src/agent-manifest/schema.js +28 -2
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/automations/api/routes.js +13 -2
- package/dist/src/automations/api/routes.js.map +1 -1
- package/dist/src/automations/domain/types.d.ts +2 -0
- package/dist/src/automations/domain/validation.d.ts +3 -0
- package/dist/src/automations/domain/validation.js +1 -0
- package/dist/src/automations/domain/validation.js.map +1 -1
- package/dist/src/automations/draft/automation-draft-service.js +1 -1
- package/dist/src/automations/draft/automation-draft-service.js.map +1 -1
- package/dist/src/automations/draft/automation-draft-validator.d.ts +1 -0
- package/dist/src/automations/service/action-executor.js +3 -1
- package/dist/src/automations/service/action-executor.js.map +1 -1
- package/dist/src/automations/service/automation-service.d.ts +4 -1
- package/dist/src/automations/service/automation-service.js +2 -2
- package/dist/src/automations/service/automation-service.js.map +1 -1
- package/dist/src/automations/storage/automation-repository.d.ts +3 -1
- package/dist/src/automations/storage/automation-repository.js +7 -5
- package/dist/src/automations/storage/automation-repository.js.map +1 -1
- package/dist/src/automations/storage/automation-run-repository.d.ts +1 -0
- package/dist/src/automations/storage/automation-run-repository.js +12 -1
- package/dist/src/automations/storage/automation-run-repository.js.map +1 -1
- package/dist/src/chat-commands/context.js +2 -1
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/cli/command-loaders.js +1 -0
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +4 -0
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/goal.js +27 -4
- package/dist/src/cli/commands/goal.js.map +1 -1
- package/dist/src/cli/commands/onboard/model.js +161 -11
- package/dist/src/cli/commands/onboard/model.js.map +1 -1
- package/dist/src/cli/commands/project.d.ts +4 -0
- package/dist/src/cli/commands/project.js +239 -0
- package/dist/src/cli/commands/project.js.map +1 -0
- package/dist/src/config/default-model.d.ts +11 -0
- package/dist/src/config/default-model.js +19 -0
- package/dist/src/config/default-model.js.map +1 -0
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/schema.d.ts +71 -11
- package/dist/src/config/schema.js +57 -22
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/connectors/registries/smithery.js +10 -9
- package/dist/src/connectors/registries/smithery.js.map +1 -1
- package/dist/src/daemon/install-plan.js +2 -1
- package/dist/src/daemon/install-plan.js.map +1 -1
- package/dist/src/gateway/global-defaults-admin.js +6 -16
- package/dist/src/gateway/global-defaults-admin.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +24 -0
- package/dist/src/gateway/hono/routes/agents.js +1 -79
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/goals.js +51 -4
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +5 -1
- package/dist/src/gateway/hono/routes/memory.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +132 -14
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/notes.js +5 -0
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/projects.d.ts +3 -0
- package/dist/src/gateway/hono/routes/projects.js +578 -0
- package/dist/src/gateway/hono/routes/projects.js.map +1 -0
- package/dist/src/gateway/hono/routes/sessions.js +47 -7
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/voice.js +1 -1
- package/dist/src/gateway/hono/routes/voice.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +27 -4
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/image-capabilities.d.ts +11 -1
- package/dist/src/gateway/image-capabilities.js +32 -43
- package/dist/src/gateway/image-capabilities.js.map +1 -1
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +10 -3
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-editor-path.js +9 -1
- package/dist/src/gateway/workspace-editor-path.js.map +1 -1
- package/dist/src/generated/bundled-image-generation-providers.d.ts +4 -2
- package/dist/src/generated/bundled-image-generation-providers.js +6 -4
- package/dist/src/generated/bundled-image-generation-providers.js.map +1 -1
- package/dist/src/goals/goal-service.d.ts +1 -1
- package/dist/src/goals/goal-service.js +2 -1
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/goals/goal-store.d.ts +1 -1
- package/dist/src/goals/goal-store.js +12 -6
- package/dist/src/goals/goal-store.js.map +1 -1
- package/dist/src/goals/goal-workflow-judge.js +1 -1
- package/dist/src/goals/types.d.ts +3 -0
- package/dist/src/i18n/goals-bundle.js +1 -1
- package/dist/src/i18n/index.js +1 -1
- package/dist/src/i18n/share-tool-bundle.js +2 -2
- package/dist/src/media/paths.js +3 -4
- package/dist/src/media/paths.js.map +1 -1
- package/dist/src/notes/agent-context.js +2 -2
- package/dist/src/notes/service.js +1 -1
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/projects/automation-bind.d.ts +1 -0
- package/dist/src/projects/automation-bind.js +16 -0
- package/dist/src/projects/automation-bind.js.map +1 -0
- package/dist/src/projects/goal-bind.d.ts +4 -0
- package/dist/src/projects/goal-bind.js +40 -0
- package/dist/src/projects/goal-bind.js.map +1 -0
- package/dist/src/projects/index.d.ts +11 -0
- package/dist/src/projects/index.js +11 -0
- package/dist/src/projects/memory-bind.d.ts +1 -0
- package/dist/src/projects/memory-bind.js +16 -0
- package/dist/src/projects/memory-bind.js.map +1 -0
- package/dist/src/projects/project-agent.d.ts +10 -0
- package/dist/src/projects/project-agent.js +27 -0
- package/dist/src/projects/project-agent.js.map +1 -0
- package/dist/src/projects/project-loop.d.ts +58 -0
- package/dist/src/projects/project-loop.js +118 -0
- package/dist/src/projects/project-loop.js.map +1 -0
- package/dist/src/projects/project-service.d.ts +26 -0
- package/dist/src/projects/project-service.js +94 -0
- package/dist/src/projects/project-service.js.map +1 -0
- package/dist/src/projects/project-store.d.ts +31 -0
- package/dist/src/projects/project-store.js +193 -0
- package/dist/src/projects/project-store.js.map +1 -0
- package/dist/src/projects/session-bind.d.ts +5 -0
- package/dist/src/projects/session-bind.js +46 -0
- package/dist/src/projects/session-bind.js.map +1 -0
- package/dist/src/projects/types.d.ts +60 -0
- package/dist/src/projects/types.js +1 -0
- package/dist/src/projects/workflow-bind.d.ts +1 -0
- package/dist/src/projects/workflow-bind.js +16 -0
- package/dist/src/projects/workflow-bind.js.map +1 -0
- package/dist/src/projects/workspace.d.ts +5 -0
- package/dist/src/projects/workspace.js +25 -0
- package/dist/src/projects/workspace.js.map +1 -0
- package/dist/src/providers/domestic-presets.d.ts +615 -0
- package/dist/src/providers/domestic-presets.js +834 -0
- package/dist/src/providers/domestic-presets.js.map +1 -0
- package/dist/src/providers/env-keys.js +29 -5
- package/dist/src/providers/env-keys.js.map +1 -1
- package/dist/src/providers/extension-stream-bridge.js +1 -1
- package/dist/src/providers/extension-stream-bridge.js.map +1 -1
- package/dist/src/providers/index.d.ts +5 -5
- package/dist/src/providers/index.js +101 -21
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/model-discovery.d.ts +17 -0
- package/dist/src/providers/model-discovery.js +61 -0
- package/dist/src/providers/model-discovery.js.map +1 -0
- package/dist/src/providers/model-registry.d.ts +1 -1
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/providers/model-registry.js.map +1 -1
- package/dist/src/providers/presentation.js +185 -14
- package/dist/src/providers/presentation.js.map +1 -1
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/index.js +3 -3
- package/dist/src/session/session-title.js +1 -1
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/session/session-workspace.d.ts +4 -2
- package/dist/src/session/session-workspace.js +10 -3
- package/dist/src/session/session-workspace.js.map +1 -1
- package/dist/src/session/types.d.ts +3 -0
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +3 -0
- package/dist/src/storage/sqlite/memory-records-repository.js +16 -5
- package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/019_projects.sql +40 -0
- package/dist/src/storage/sqlite/migrations/020_project_default_agent.sql +1 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/notes-repository.js +20 -4
- package/dist/src/storage/sqlite/notes-repository.js.map +1 -1
- package/dist/src/storage/sqlite/row-mappers.d.ts +2 -0
- package/dist/src/storage/sqlite/row-mappers.js +2 -0
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/session-repository.js +10 -5
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/dist/src/storage/sqlite/transcript-repository.js +8 -0
- package/dist/src/storage/sqlite/transcript-repository.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/dist/src/tui/tui-commands.js +145 -0
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/xopc-tui-keybindings.d.ts +1 -1
- package/dist/src/voice/tts/summarize.js +1 -1
- package/dist/src/voice/tts/summarize.js.map +1 -1
- package/dist/src/workflows/domain/run.d.ts +1 -0
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
- package/dist/src/workflows/draft/workflow-draft-service.js.map +1 -1
- package/dist/src/workflows/index.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.d.ts +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +18 -4
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +2 -0
- package/dist/src/workflows/service/workflow-session-bridge.d.ts +1 -0
- package/dist/src/workflows/service/workflow-session-bridge.js +3 -0
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/dist/src/workflows/store/run-index-store.d.ts +1 -0
- package/dist/src/workflows/store/run-index-store.js +13 -3
- package/dist/src/workflows/store/run-index-store.js.map +1 -1
- package/dist/src/workflows/store/run-store.d.ts +3 -1
- package/dist/src/workflows/store/run-store.js +5 -2
- package/dist/src/workflows/store/run-store.js.map +1 -1
- package/package.json +15 -6
- package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +0 -41
- package/dist/gateway/static/root/assets/agents-CFW_FS_V.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-DT52OrbM.js +0 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-CtysjSoQ.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-B2YvT3ES.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-BQEXPhDU.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-DRTutLlN.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DneJVuge.js +0 -2
- package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +0 -1
- package/dist/gateway/static/root/assets/dist-CkobR7mk.js +0 -1
- package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-BEwWA1yf.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-BS2rx40e.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-DAFI_T0W.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DLuz4jC9.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-DTAfv9Ft.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-CWN2iirQ.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CkkkHvOi.js +0 -1
- package/dist/gateway/static/root/assets/index-CnjzMw5i.js +0 -191
- package/dist/gateway/static/root/assets/index-E1QinYKp.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-CDXDlS_W.js +0 -2
- package/dist/gateway/static/root/assets/messages-CISb1HLv.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BTwxMIgZ.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-BBfOeB0m.js +0 -2
- package/dist/gateway/static/root/assets/note-image-lightbox-4zntqpZq.js +0 -1
- package/dist/gateway/static/root/assets/note-time-hm6JO_Wi.js +0 -1
- package/dist/gateway/static/root/assets/notes-page-VocWOjoK.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CXwjuD_Q.js +0 -1
- package/dist/gateway/static/root/assets/schedule-field-pRheF2CO.js +0 -1
- package/dist/gateway/static/root/assets/schema-form-D6PiPxfr.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CpcVySQK.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BVy_TawT.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CZpNyCWn.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-layout-NxoW5Y57.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-MVHLLu_a.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-B0suFCfj.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-C6DBbQGo.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-6hJmhwSn.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-Im1MA0Iw.js +0 -2
- package/dist/gateway/static/root/assets/user-profile-settings-panel-QAQWGelF.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-D-6XueTv.js +0 -1
- package/dist/gateway/static/root/assets/voice-player-store-CMC5NOJp.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DVPllR4k.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-B94WISTW.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../../src/notes/service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport { publishAutomationProductEvent } from '../automations/product-events.js';\nimport type { Config } from '../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../providers/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport { buildNoteAttachmentRef } from './attachment-ref.js';\nimport { partitionAttachmentsByReference } from './note-attachment-sync.js';\nimport { parseNoteMarkdown } from './note-markdown.js';\nimport { buildNoteAgentContextArtifact, getCachedNoteAgentContextArtifact } from './agent-context.js';\nimport { NotesStore } from './store.js';\nimport type {\n CaptureSource,\n CreateNoteParams,\n Note,\n NoteAiPatch,\n NoteAttachment,\n NoteCatalysisAction,\n NoteCatalysisMeta,\n NoteCatalysisReport,\n NoteIndexEntry,\n NoteKind,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesService');\nconst MAX_SNAPSHOTS_PER_NOTE = 50;\nconst SNAPSHOT_THROTTLE_MS = 60_000;\n\nfunction inferKind(markdown?: string, hasAttachments?: boolean, attachments?: NoteAttachment[]): NoteKind {\n if (hasAttachments && attachments?.length && attachments.every((item) => item.type === 'audio')) return 'voice';\n if (hasAttachments) return 'media';\n if (!markdown) return 'thought';\n const lower = markdown.toLowerCase();\n if (/^(todo|task|remind|buy|call|email|meet|finish|submit|send)\\b/i.test(lower) || /\\b(明天|今天|记得|别忘|待办|提醒)\\b/.test(markdown)) return 'todo';\n if (/^https?:\\/\\//.test(markdown.trim())) return 'bookmark';\n return 'thought';\n}\n\nfunction deriveDefaultTitle(markdown?: string): string | undefined {\n const normalized = parseNoteMarkdown(markdown ?? '').plainText.trim().replace(/\\s+/g, ' ');\n return normalized ? Array.from(normalized).slice(0, 10).join('') : undefined;\n}\n\nfunction splitMeaningfulLines(markdown?: string): string[] {\n return parseNoteMarkdown(markdown ?? '').plainText.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n}\n\nfunction summarizeIdea(markdown?: string): string {\n const lines = splitMeaningfulLines(markdown);\n return lines.slice(0, 3).join(';').slice(0, 140);\n}\n\nfunction publishNoteEvent(\n type: 'note.created' | 'note.updated',\n note: Note,\n extra?: Record<string, unknown>,\n): void {\n publishAutomationProductEvent({\n type,\n source: 'notes',\n payload: {\n noteId: note.id,\n kind: note.kind,\n status: note.status,\n title: note.title,\n capturedVia: note.capturedVia,\n tagCount: note.tags?.length ?? 0,\n hasAttachments: Boolean(note.attachments?.length),\n ...extra,\n },\n });\n}\n\nfunction inferCatalysisStage(note: Note): NonNullable<NoteCatalysisMeta['stage']> {\n const text = `${note.title ?? ''}\\n${note.markdown}`;\n if (/上线|发布|launch|ship/i.test(text)) return 'shipped';\n if (/验证|访谈|用户|测试|validate/i.test(text)) return 'validating';\n if (/开发|实现|构建|build|mvp/i.test(text)) return 'developing';\n if (/想法|机会|问题|idea|seed/i.test(text)) return 'seed';\n return 'incubating';\n}\n\nfunction buildCatalysisReport(note: Note): NoteCatalysisReport {\n const summary = summarizeIdea(note.markdown || note.title);\n const title = note.title?.trim() || summary.slice(0, 28) || '未命名想法';\n const actions: NoteCatalysisAction[] = [\n { kind: 'research', text: `验证「${title}」的真实需求和目标用户` },\n { kind: 'task', text: `拆解「${title}」的最小可行下一步` },\n { kind: 'chat', text: `继续和 AI 讨论「${title}」的方案` },\n ];\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title,\n valueHypothesis: summary || '这条笔记可能包含一个待澄清的想法。',\n targetUsers: ['待确认的核心用户'],\n keyQuestions: ['用户为什么现在需要它?', '最小可验证版本是什么?', '如何判断它值得继续投入?'],\n mvpPath: ['定义目标用户', '写出最小场景', '完成一次验证'],\n risks: ['需求不够明确', '执行路径过大'],\n nextActions: actions,\n confidence: summary ? 0.58 : 0.35,\n };\n}\n\nfunction normalizeAiCatalysisReport(note: Note, data: Record<string, unknown>): NoteCatalysisReport {\n const fallback = buildCatalysisReport(note);\n const stringArray = (value: unknown, fallbackValue: string[]) => Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string').slice(0, 12) : fallbackValue;\n const actions = Array.isArray(data.nextActions)\n ? data.nextActions.map((item): NoteCatalysisAction | null => {\n if (!item || typeof item !== 'object') return null;\n const row = item as { kind?: unknown; text?: unknown };\n const kind = row.kind === 'task' || row.kind === 'workflow' || row.kind === 'research' || row.kind === 'share' || row.kind === 'chat' ? row.kind : 'task';\n return typeof row.text === 'string' && row.text.trim() ? { kind, text: row.text.trim() } : null;\n }).filter((item): item is NoteCatalysisAction => Boolean(item)).slice(0, 12)\n : fallback.nextActions;\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title: typeof data.title === 'string' && data.title.trim() ? data.title.trim() : fallback.title,\n valueHypothesis: typeof data.valueHypothesis === 'string' && data.valueHypothesis.trim() ? data.valueHypothesis.trim() : fallback.valueHypothesis,\n targetUsers: stringArray(data.targetUsers, fallback.targetUsers),\n keyQuestions: stringArray(data.keyQuestions, fallback.keyQuestions),\n mvpPath: stringArray(data.mvpPath, fallback.mvpPath),\n risks: stringArray(data.risks, fallback.risks),\n nextActions: actions,\n confidence: typeof data.confidence === 'number' ? Math.max(0, Math.min(1, data.confidence)) : fallback.confidence,\n };\n}\n\nfunction buildCatalysisPrompt(note: Note): string {\n const title = note.title?.trim() || '未命名笔记';\n const markdown = note.markdown.trim() || '(无正文)';\n return `请把下面的 Markdown 笔记催化成可执行的想法报告,输出 JSON:\\n{\\n \"title\": string,\\n \"valueHypothesis\": string,\\n \"targetUsers\": string[],\\n \"keyQuestions\": string[],\\n \"mvpPath\": string[],\\n \"risks\": string[],\\n \"nextActions\": [{\"text\": string, \"kind\": \"task\"|\"workflow\"|\"research\"|\"share\"|\"chat\"}],\\n \"confidence\": number\\n}\\n\\n标题:${title}\\n\\nMarkdown:\\n${markdown}`;\n}\n\nasync function buildAiCatalysisReport(note: Note, config?: Config): Promise<NoteCatalysisReport> {\n const modelRef = getDefaultModelSync(config);\n if (!modelRef) {\n throw new Error('No global default model configured');\n }\n const resolved = resolveModel(modelRef);\n const messages: UserMessage[] = [{ role: 'user', content: buildCatalysisPrompt(note), timestamp: Date.now() }];\n const response = await complete(resolved, { messages }, { temperature: 0.2 });\n let responseText = '';\n if (Array.isArray(response.content)) {\n for (const part of response.content) {\n if (part && typeof part === 'object' && (part as { type?: string }).type === 'text') {\n responseText += String((part as { text?: string }).text || '');\n }\n }\n }\n const raw = responseText.trim().replace(/^```json\\s*/i, '').replace(/```$/i, '').trim();\n return normalizeAiCatalysisReport(note, JSON.parse(raw) as Record<string, unknown>);\n}\n\nexport class NotesService {\n private lastSnapshotAt = new Map<string, number>();\n\n constructor(private readonly store = new NotesStore()) {}\n\n async initialize(): Promise<void> {\n await this.store.initialize();\n }\n\n async quickCapture(markdown: string, source: CaptureSource): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const note: Note = {\n id,\n title: deriveDefaultTitle(markdown),\n kind: inferKind(markdown),\n status: 'inbox',\n markdown,\n createdAt: now,\n updatedAt: now,\n capturedVia: source,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Quick capture');\n return note;\n }\n\n async createNote(params: CreateNoteParams): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const markdown = params.markdown ?? '';\n const note: Note = {\n id,\n title: params.title ?? deriveDefaultTitle(markdown),\n kind: params.kind ?? inferKind(markdown),\n status: 'inbox',\n markdown,\n attachments: [],\n createdAt: now,\n updatedAt: now,\n capturedVia: params.capturedVia,\n tags: params.tags,\n pinned: params.pinned,\n groupId: params.groupId,\n taskMeta: params.taskMeta,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n publishNoteEvent('note.created', note);\n log.debug({ id: note.id, kind: note.kind }, 'Note created');\n return note;\n }\n\n async getNote(id: string): Promise<Note | null> {\n return this.store.getNote(id);\n }\n\n async updateNote(id: string, patch: Partial<Note>, trigger: SnapshotTrigger = 'edit'): Promise<Note | null> {\n const existing = await this.store.getNote(id);\n if (!existing) return null;\n const contentTouched = patch.markdown !== undefined || patch.title !== undefined;\n if (contentTouched) await this.maybeSaveSnapshot(existing, trigger);\n\n const normalizedPatch: Partial<Note> = { ...patch };\n if (patch.markdown !== undefined) {\n normalizedPatch.kind = patch.kind ?? inferKind(patch.markdown, Boolean(existing.attachments?.length), existing.attachments);\n }\n if (contentTouched || patch.attachments) {\n normalizedPatch.remoteVersion = (existing.remoteVersion ?? 1) + 1;\n normalizedPatch.localVersion = patch.localVersion ?? (existing.localVersion ?? 1) + 1;\n }\n\n const updatedRaw = await this.store.updateNote(id, normalizedPatch);\n const updated = updatedRaw ? await this.reconcileAttachments(updatedRaw) : null;\n if (updated) {\n publishNoteEvent('note.updated', updated, {\n contentTouched,\n trigger,\n });\n }\n return updated;\n }\n\n private async reconcileAttachments(note: Note): Promise<Note> {\n const { kept, removed } = partitionAttachmentsByReference(note);\n if (removed.length === 0) return note;\n for (const attachment of removed) await this.store.deleteAttachmentFile(note.id, attachment.relativePath);\n log.debug({ noteId: note.id, removedIds: removed.map((attachment) => attachment.id) }, 'Pruned orphan note attachments');\n const hasAttachments = kept.length > 0;\n const updated = await this.store.updateNote(note.id, { attachments: kept, kind: inferKind(note.markdown, hasAttachments, kept) });\n return updated ?? { ...note, attachments: kept };\n }\n\n async syncNote(id: string, patch: Partial<Note>, baseRemoteVersion?: number): Promise<{ note: Note | null; conflict: boolean }> {\n const existing = await this.store.getNote(id);\n if (!existing) return { note: null, conflict: false };\n if (baseRemoteVersion !== undefined && existing.remoteVersion !== undefined && baseRemoteVersion < existing.remoteVersion) {\n return { note: existing, conflict: true };\n }\n const updated = await this.updateNote(id, patch, 'sync');\n return { note: updated, conflict: false };\n }\n\n async createAiEditPatch(id: string, instruction: string, markdownOverride?: string): Promise<{ message: string; patch: NoteAiPatch } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const source = markdownOverride ?? note.markdown;\n const parsed = parseNoteMarkdown(source, id);\n const wantsTodos = /待办|todo|task|行动|提醒/i.test(instruction);\n const wantsSummary = /摘要|总结|summary|压缩/i.test(instruction);\n let generated = '';\n if (wantsTodos) {\n const lines = source.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n generated = (lines.length ? lines : [parsed.plainText]).slice(0, 12).map((line) => `- [ ] ${line.replace(/^[-*\\d.\\s\\[\\]x]+/i, '').trim()}`).join('\\n');\n } else if (wantsSummary) {\n generated = `> [!SUMMARY]\\n> ${parsed.plainText.slice(0, 220)}`;\n } else {\n generated = `${source.trimEnd()}\\n\\n## AI 整理\\n\\n${instruction.trim()}`;\n }\n return {\n message: 'AI edit patch generated',\n patch: {\n id: randomUUID(),\n summary: instruction,\n operations: [{ type: 'replaceRange', from: 0, to: source.length, markdown: generated || source }],\n },\n };\n }\n\n async catalyzeNote(id: string, config?: Config): Promise<{ note: Note; report: NoteCatalysisReport } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n let report: NoteCatalysisReport;\n try {\n report = await buildAiCatalysisReport(note, config);\n } catch (err) {\n log.warn({ err, noteId: id }, 'AI note catalysis failed; using local fallback report');\n report = buildCatalysisReport(note);\n }\n const updated = await this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: 'catalyzed',\n stage: inferCatalysisStage(note),\n lastCatalyzedAt: Date.now(),\n confidence: report.confidence,\n report,\n ...note.aiDeep?.catalysis,\n },\n },\n ai: { ...note.ai, intent: note.ai?.intent ?? 'idea', summary: note.ai?.summary ?? report.valueHypothesis },\n status: note.status === 'inbox' ? 'processed' : note.status,\n }, 'ai_edit');\n return updated ? { note: updated, report } : null;\n }\n\n async recordCatalysisFeedback(id: string, feedback: 'helpful' | 'not_helpful' | 'neutral'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return this.updateNote(id, { aiDeep: { ...note.aiDeep, processedAt: Date.now(), catalysis: { status: note.aiDeep?.catalysis?.status ?? 'catalyzed', ...note.aiDeep?.catalysis, feedback } } });\n }\n\n async linkNoteThread(id: string, sessionKey: string): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const existingKeys = note.aiDeep?.catalysis?.linkedSessionKeys ?? [];\n return this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: note.aiDeep?.catalysis?.status ?? 'none',\n ...note.aiDeep?.catalysis,\n sourceSessionKey: note.aiDeep?.catalysis?.sourceSessionKey ?? sessionKey,\n linkedSessionKeys: Array.from(new Set([...existingKeys, sessionKey])),\n },\n },\n }, 'sync');\n }\n\n async listNoteThreads(id: string): Promise<string[] | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return Array.from(new Set([note.aiDeep?.catalysis?.sourceSessionKey, ...(note.aiDeep?.catalysis?.linkedSessionKeys ?? [])].filter((key): key is string => Boolean(key))));\n }\n\n async getAgentContextStatus(id: string, config?: Config, force = false): Promise<{ noteUpdatedAt: number; artifact: import('./agent-context.js').NoteAgentContextArtifact | null; stale: boolean } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const cached = getCachedNoteAgentContextArtifact(id);\n if (!force && cached && cached.noteUpdatedAt === note.updatedAt) {\n return { noteUpdatedAt: note.updatedAt, artifact: cached, stale: false };\n }\n const artifact = await buildNoteAgentContextArtifact({ note, notesService: this, config, force });\n return { noteUpdatedAt: note.updatedAt, artifact, stale: false };\n }\n\n async appendTextToNote(id: string, content: string, heading = 'AI 讨论沉淀'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const trimmed = content.trim();\n if (!trimmed) return note;\n const current = note.markdown.trimEnd();\n const nextMarkdown = `${current}${current ? '\\n\\n' : ''}## ${heading}\\n\\n${trimmed}\\n`;\n return this.updateNote(id, { markdown: nextMarkdown }, 'ai_edit');\n }\n\n async deleteNote(id: string): Promise<boolean> {\n const removed = await this.store.deleteNote(id);\n if (removed) await this.store.deleteAllSnapshots(id);\n return removed;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{ items: NoteIndexEntry[]; total: number; limit: number; offset: number; hasMore: boolean }> {\n return this.store.listNotes(query);\n }\n\n async addAttachment(noteId: string, file: { name: string; buffer: Buffer; mimeType: string; duration?: number }): Promise<NoteAttachment | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const { relativePath, size } = await this.store.saveAttachment(noteId, file.name, file.buffer);\n const attachment: NoteAttachment = {\n id: randomUUID(),\n type: file.mimeType.startsWith('image/') ? 'image' : file.mimeType.startsWith('audio/') ? 'audio' : file.mimeType.startsWith('video/') ? 'video' : 'file',\n mimeType: file.mimeType,\n fileName: file.name,\n size,\n relativePath,\n duration: file.duration,\n };\n const attachments = [...(note.attachments || []), attachment];\n const kind = note.kind === 'thought' && attachment.type === 'audio' ? 'voice' : note.kind === 'thought' ? 'media' : note.kind;\n await this.store.updateNote(noteId, { attachments, kind });\n return attachment;\n }\n\n async getAttachmentPath(noteId: string, attachmentId: string): Promise<{ filePath: string; mimeType: string; fileName: string } | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const attachment = note.attachments?.find((a) => a.id === attachmentId);\n if (!attachment) return null;\n return { filePath: this.store.resolveAttachmentPath(noteId, attachment.relativePath), mimeType: attachment.mimeType, fileName: attachment.fileName };\n }\n\n async listNoteHistory(noteId: string): Promise<NoteSnapshotEntry[]> { return this.store.listSnapshots(noteId); }\n async getNoteSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> { return this.store.getSnapshot(noteId, timestamp); }\n\n async restoreNoteSnapshot(noteId: string, timestamp: number): Promise<Note | null> {\n const snapshot = await this.store.getSnapshot(noteId, timestamp);\n const existing = await this.store.getNote(noteId);\n if (!snapshot || !existing) return null;\n await this.maybeSaveSnapshot(existing, 'restore');\n this.lastSnapshotAt.set(noteId, Date.now());\n await this.store.pruneSnapshots(noteId, MAX_SNAPSHOTS_PER_NOTE);\n return this.store.updateNote(noteId, { title: snapshot.title, markdown: snapshot.markdown, tags: snapshot.tags, kind: snapshot.kind, status: snapshot.status });\n }\n\n async flush(): Promise<void> { await this.store.flush(); }\n async moveToGroup(noteId: string, groupId: string | null): Promise<Note | null> { return this.updateNote(noteId, { groupId: groupId ?? undefined }); }\n\n async createTask(title: string, source: CaptureSource, opts: { dueAt?: number; priority?: 'high' | 'medium' | 'low'; sourceSessionKey?: string; sourceNoteId?: string; groupId?: string } = {}): Promise<Note> {\n return this.createNote({\n title,\n markdown: `- [ ] ${title}`,\n kind: 'task',\n capturedVia: source,\n groupId: opts.groupId,\n taskMeta: { done: false, dueAt: opts.dueAt, priority: opts.priority, sourceSessionKey: opts.sourceSessionKey, sourceNoteId: opts.sourceNoteId },\n });\n }\n\n async toggleTaskDone(noteId: string): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n const done = !note.taskMeta?.done;\n const markdown = note.markdown.replace(/^- \\[[ xX]\\]/m, `- [${done ? 'x' : ' '}]`);\n return this.updateNote(noteId, { markdown, taskMeta: { ...note.taskMeta, done } });\n }\n\n async updateTaskMeta(noteId: string, patch: Partial<import('./types.js').NoteTaskMeta>): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n return this.updateNote(noteId, { taskMeta: { ...note.taskMeta, done: note.taskMeta?.done ?? false, ...patch } });\n }\n\n async recordOpen(noteId: string): Promise<Note | null> {\n return this.updateNote(noteId, { lastOpenedAt: Date.now() } as Partial<Note>);\n }\n\n private async maybeSaveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n if (trigger !== 'edit') {\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n return;\n }\n const last = this.lastSnapshotAt.get(note.id) ?? 0;\n if (Date.now() - last < SNAPSHOT_THROTTLE_MS) return;\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n }\n}\n\nexport { buildNoteAttachmentRef };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../../src/notes/service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { complete, type UserMessage } from '@earendil-works/pi-ai/compat';\n\nimport { publishAutomationProductEvent } from '../automations/product-events.js';\nimport type { Config } from '../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../providers/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport { buildNoteAttachmentRef } from './attachment-ref.js';\nimport { partitionAttachmentsByReference } from './note-attachment-sync.js';\nimport { parseNoteMarkdown } from './note-markdown.js';\nimport { buildNoteAgentContextArtifact, getCachedNoteAgentContextArtifact } from './agent-context.js';\nimport { NotesStore } from './store.js';\nimport type {\n CaptureSource,\n CreateNoteParams,\n Note,\n NoteAiPatch,\n NoteAttachment,\n NoteCatalysisAction,\n NoteCatalysisMeta,\n NoteCatalysisReport,\n NoteIndexEntry,\n NoteKind,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesService');\nconst MAX_SNAPSHOTS_PER_NOTE = 50;\nconst SNAPSHOT_THROTTLE_MS = 60_000;\n\nfunction inferKind(markdown?: string, hasAttachments?: boolean, attachments?: NoteAttachment[]): NoteKind {\n if (hasAttachments && attachments?.length && attachments.every((item) => item.type === 'audio')) return 'voice';\n if (hasAttachments) return 'media';\n if (!markdown) return 'thought';\n const lower = markdown.toLowerCase();\n if (/^(todo|task|remind|buy|call|email|meet|finish|submit|send)\\b/i.test(lower) || /\\b(明天|今天|记得|别忘|待办|提醒)\\b/.test(markdown)) return 'todo';\n if (/^https?:\\/\\//.test(markdown.trim())) return 'bookmark';\n return 'thought';\n}\n\nfunction deriveDefaultTitle(markdown?: string): string | undefined {\n const normalized = parseNoteMarkdown(markdown ?? '').plainText.trim().replace(/\\s+/g, ' ');\n return normalized ? Array.from(normalized).slice(0, 10).join('') : undefined;\n}\n\nfunction splitMeaningfulLines(markdown?: string): string[] {\n return parseNoteMarkdown(markdown ?? '').plainText.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n}\n\nfunction summarizeIdea(markdown?: string): string {\n const lines = splitMeaningfulLines(markdown);\n return lines.slice(0, 3).join(';').slice(0, 140);\n}\n\nfunction publishNoteEvent(\n type: 'note.created' | 'note.updated',\n note: Note,\n extra?: Record<string, unknown>,\n): void {\n publishAutomationProductEvent({\n type,\n source: 'notes',\n payload: {\n noteId: note.id,\n kind: note.kind,\n status: note.status,\n title: note.title,\n capturedVia: note.capturedVia,\n tagCount: note.tags?.length ?? 0,\n hasAttachments: Boolean(note.attachments?.length),\n ...extra,\n },\n });\n}\n\nfunction inferCatalysisStage(note: Note): NonNullable<NoteCatalysisMeta['stage']> {\n const text = `${note.title ?? ''}\\n${note.markdown}`;\n if (/上线|发布|launch|ship/i.test(text)) return 'shipped';\n if (/验证|访谈|用户|测试|validate/i.test(text)) return 'validating';\n if (/开发|实现|构建|build|mvp/i.test(text)) return 'developing';\n if (/想法|机会|问题|idea|seed/i.test(text)) return 'seed';\n return 'incubating';\n}\n\nfunction buildCatalysisReport(note: Note): NoteCatalysisReport {\n const summary = summarizeIdea(note.markdown || note.title);\n const title = note.title?.trim() || summary.slice(0, 28) || '未命名想法';\n const actions: NoteCatalysisAction[] = [\n { kind: 'research', text: `验证「${title}」的真实需求和目标用户` },\n { kind: 'task', text: `拆解「${title}」的最小可行下一步` },\n { kind: 'chat', text: `继续和 AI 讨论「${title}」的方案` },\n ];\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title,\n valueHypothesis: summary || '这条笔记可能包含一个待澄清的想法。',\n targetUsers: ['待确认的核心用户'],\n keyQuestions: ['用户为什么现在需要它?', '最小可验证版本是什么?', '如何判断它值得继续投入?'],\n mvpPath: ['定义目标用户', '写出最小场景', '完成一次验证'],\n risks: ['需求不够明确', '执行路径过大'],\n nextActions: actions,\n confidence: summary ? 0.58 : 0.35,\n };\n}\n\nfunction normalizeAiCatalysisReport(note: Note, data: Record<string, unknown>): NoteCatalysisReport {\n const fallback = buildCatalysisReport(note);\n const stringArray = (value: unknown, fallbackValue: string[]) => Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string').slice(0, 12) : fallbackValue;\n const actions = Array.isArray(data.nextActions)\n ? data.nextActions.map((item): NoteCatalysisAction | null => {\n if (!item || typeof item !== 'object') return null;\n const row = item as { kind?: unknown; text?: unknown };\n const kind = row.kind === 'task' || row.kind === 'workflow' || row.kind === 'research' || row.kind === 'share' || row.kind === 'chat' ? row.kind : 'task';\n return typeof row.text === 'string' && row.text.trim() ? { kind, text: row.text.trim() } : null;\n }).filter((item): item is NoteCatalysisAction => Boolean(item)).slice(0, 12)\n : fallback.nextActions;\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title: typeof data.title === 'string' && data.title.trim() ? data.title.trim() : fallback.title,\n valueHypothesis: typeof data.valueHypothesis === 'string' && data.valueHypothesis.trim() ? data.valueHypothesis.trim() : fallback.valueHypothesis,\n targetUsers: stringArray(data.targetUsers, fallback.targetUsers),\n keyQuestions: stringArray(data.keyQuestions, fallback.keyQuestions),\n mvpPath: stringArray(data.mvpPath, fallback.mvpPath),\n risks: stringArray(data.risks, fallback.risks),\n nextActions: actions,\n confidence: typeof data.confidence === 'number' ? Math.max(0, Math.min(1, data.confidence)) : fallback.confidence,\n };\n}\n\nfunction buildCatalysisPrompt(note: Note): string {\n const title = note.title?.trim() || '未命名笔记';\n const markdown = note.markdown.trim() || '(无正文)';\n return `请把下面的 Markdown 笔记催化成可执行的想法报告,输出 JSON:\\n{\\n \"title\": string,\\n \"valueHypothesis\": string,\\n \"targetUsers\": string[],\\n \"keyQuestions\": string[],\\n \"mvpPath\": string[],\\n \"risks\": string[],\\n \"nextActions\": [{\"text\": string, \"kind\": \"task\"|\"workflow\"|\"research\"|\"share\"|\"chat\"}],\\n \"confidence\": number\\n}\\n\\n标题:${title}\\n\\nMarkdown:\\n${markdown}`;\n}\n\nasync function buildAiCatalysisReport(note: Note, config?: Config): Promise<NoteCatalysisReport> {\n const modelRef = getDefaultModelSync(config);\n if (!modelRef) {\n throw new Error('No global default model configured');\n }\n const resolved = resolveModel(modelRef);\n const messages: UserMessage[] = [{ role: 'user', content: buildCatalysisPrompt(note), timestamp: Date.now() }];\n const response = await complete(resolved, { messages }, { temperature: 0.2 });\n let responseText = '';\n if (Array.isArray(response.content)) {\n for (const part of response.content) {\n if (part && typeof part === 'object' && (part as { type?: string }).type === 'text') {\n responseText += String((part as { text?: string }).text || '');\n }\n }\n }\n const raw = responseText.trim().replace(/^```json\\s*/i, '').replace(/```$/i, '').trim();\n return normalizeAiCatalysisReport(note, JSON.parse(raw) as Record<string, unknown>);\n}\n\nexport class NotesService {\n private lastSnapshotAt = new Map<string, number>();\n\n constructor(private readonly store = new NotesStore()) {}\n\n async initialize(): Promise<void> {\n await this.store.initialize();\n }\n\n async quickCapture(markdown: string, source: CaptureSource): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const note: Note = {\n id,\n title: deriveDefaultTitle(markdown),\n kind: inferKind(markdown),\n status: 'inbox',\n markdown,\n createdAt: now,\n updatedAt: now,\n capturedVia: source,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Quick capture');\n return note;\n }\n\n async createNote(params: CreateNoteParams): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const markdown = params.markdown ?? '';\n const note: Note = {\n id,\n title: params.title ?? deriveDefaultTitle(markdown),\n kind: params.kind ?? inferKind(markdown),\n status: 'inbox',\n markdown,\n attachments: [],\n createdAt: now,\n updatedAt: now,\n capturedVia: params.capturedVia,\n tags: params.tags,\n pinned: params.pinned,\n groupId: params.groupId,\n taskMeta: params.taskMeta,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n publishNoteEvent('note.created', note);\n log.debug({ id: note.id, kind: note.kind }, 'Note created');\n return note;\n }\n\n async getNote(id: string): Promise<Note | null> {\n return this.store.getNote(id);\n }\n\n async updateNote(id: string, patch: Partial<Note>, trigger: SnapshotTrigger = 'edit'): Promise<Note | null> {\n const existing = await this.store.getNote(id);\n if (!existing) return null;\n const contentTouched = patch.markdown !== undefined || patch.title !== undefined;\n if (contentTouched) await this.maybeSaveSnapshot(existing, trigger);\n\n const normalizedPatch: Partial<Note> = { ...patch };\n if (patch.markdown !== undefined) {\n normalizedPatch.kind = patch.kind ?? inferKind(patch.markdown, Boolean(existing.attachments?.length), existing.attachments);\n }\n if (contentTouched || patch.attachments) {\n normalizedPatch.remoteVersion = (existing.remoteVersion ?? 1) + 1;\n normalizedPatch.localVersion = patch.localVersion ?? (existing.localVersion ?? 1) + 1;\n }\n\n const updatedRaw = await this.store.updateNote(id, normalizedPatch);\n const updated = updatedRaw ? await this.reconcileAttachments(updatedRaw) : null;\n if (updated) {\n publishNoteEvent('note.updated', updated, {\n contentTouched,\n trigger,\n });\n }\n return updated;\n }\n\n private async reconcileAttachments(note: Note): Promise<Note> {\n const { kept, removed } = partitionAttachmentsByReference(note);\n if (removed.length === 0) return note;\n for (const attachment of removed) await this.store.deleteAttachmentFile(note.id, attachment.relativePath);\n log.debug({ noteId: note.id, removedIds: removed.map((attachment) => attachment.id) }, 'Pruned orphan note attachments');\n const hasAttachments = kept.length > 0;\n const updated = await this.store.updateNote(note.id, { attachments: kept, kind: inferKind(note.markdown, hasAttachments, kept) });\n return updated ?? { ...note, attachments: kept };\n }\n\n async syncNote(id: string, patch: Partial<Note>, baseRemoteVersion?: number): Promise<{ note: Note | null; conflict: boolean }> {\n const existing = await this.store.getNote(id);\n if (!existing) return { note: null, conflict: false };\n if (baseRemoteVersion !== undefined && existing.remoteVersion !== undefined && baseRemoteVersion < existing.remoteVersion) {\n return { note: existing, conflict: true };\n }\n const updated = await this.updateNote(id, patch, 'sync');\n return { note: updated, conflict: false };\n }\n\n async createAiEditPatch(id: string, instruction: string, markdownOverride?: string): Promise<{ message: string; patch: NoteAiPatch } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const source = markdownOverride ?? note.markdown;\n const parsed = parseNoteMarkdown(source, id);\n const wantsTodos = /待办|todo|task|行动|提醒/i.test(instruction);\n const wantsSummary = /摘要|总结|summary|压缩/i.test(instruction);\n let generated = '';\n if (wantsTodos) {\n const lines = source.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n generated = (lines.length ? lines : [parsed.plainText]).slice(0, 12).map((line) => `- [ ] ${line.replace(/^[-*\\d.\\s\\[\\]x]+/i, '').trim()}`).join('\\n');\n } else if (wantsSummary) {\n generated = `> [!SUMMARY]\\n> ${parsed.plainText.slice(0, 220)}`;\n } else {\n generated = `${source.trimEnd()}\\n\\n## AI 整理\\n\\n${instruction.trim()}`;\n }\n return {\n message: 'AI edit patch generated',\n patch: {\n id: randomUUID(),\n summary: instruction,\n operations: [{ type: 'replaceRange', from: 0, to: source.length, markdown: generated || source }],\n },\n };\n }\n\n async catalyzeNote(id: string, config?: Config): Promise<{ note: Note; report: NoteCatalysisReport } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n let report: NoteCatalysisReport;\n try {\n report = await buildAiCatalysisReport(note, config);\n } catch (err) {\n log.warn({ err, noteId: id }, 'AI note catalysis failed; using local fallback report');\n report = buildCatalysisReport(note);\n }\n const updated = await this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: 'catalyzed',\n stage: inferCatalysisStage(note),\n lastCatalyzedAt: Date.now(),\n confidence: report.confidence,\n report,\n ...note.aiDeep?.catalysis,\n },\n },\n ai: { ...note.ai, intent: note.ai?.intent ?? 'idea', summary: note.ai?.summary ?? report.valueHypothesis },\n status: note.status === 'inbox' ? 'processed' : note.status,\n }, 'ai_edit');\n return updated ? { note: updated, report } : null;\n }\n\n async recordCatalysisFeedback(id: string, feedback: 'helpful' | 'not_helpful' | 'neutral'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return this.updateNote(id, { aiDeep: { ...note.aiDeep, processedAt: Date.now(), catalysis: { status: note.aiDeep?.catalysis?.status ?? 'catalyzed', ...note.aiDeep?.catalysis, feedback } } });\n }\n\n async linkNoteThread(id: string, sessionKey: string): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const existingKeys = note.aiDeep?.catalysis?.linkedSessionKeys ?? [];\n return this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: note.aiDeep?.catalysis?.status ?? 'none',\n ...note.aiDeep?.catalysis,\n sourceSessionKey: note.aiDeep?.catalysis?.sourceSessionKey ?? sessionKey,\n linkedSessionKeys: Array.from(new Set([...existingKeys, sessionKey])),\n },\n },\n }, 'sync');\n }\n\n async listNoteThreads(id: string): Promise<string[] | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return Array.from(new Set([note.aiDeep?.catalysis?.sourceSessionKey, ...(note.aiDeep?.catalysis?.linkedSessionKeys ?? [])].filter((key): key is string => Boolean(key))));\n }\n\n async getAgentContextStatus(id: string, config?: Config, force = false): Promise<{ noteUpdatedAt: number; artifact: import('./agent-context.js').NoteAgentContextArtifact | null; stale: boolean } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const cached = getCachedNoteAgentContextArtifact(id);\n if (!force && cached && cached.noteUpdatedAt === note.updatedAt) {\n return { noteUpdatedAt: note.updatedAt, artifact: cached, stale: false };\n }\n const artifact = await buildNoteAgentContextArtifact({ note, notesService: this, config, force });\n return { noteUpdatedAt: note.updatedAt, artifact, stale: false };\n }\n\n async appendTextToNote(id: string, content: string, heading = 'AI 讨论沉淀'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const trimmed = content.trim();\n if (!trimmed) return note;\n const current = note.markdown.trimEnd();\n const nextMarkdown = `${current}${current ? '\\n\\n' : ''}## ${heading}\\n\\n${trimmed}\\n`;\n return this.updateNote(id, { markdown: nextMarkdown }, 'ai_edit');\n }\n\n async deleteNote(id: string): Promise<boolean> {\n const removed = await this.store.deleteNote(id);\n if (removed) await this.store.deleteAllSnapshots(id);\n return removed;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{ items: NoteIndexEntry[]; total: number; limit: number; offset: number; hasMore: boolean }> {\n return this.store.listNotes(query);\n }\n\n async addAttachment(noteId: string, file: { name: string; buffer: Buffer; mimeType: string; duration?: number }): Promise<NoteAttachment | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const { relativePath, size } = await this.store.saveAttachment(noteId, file.name, file.buffer);\n const attachment: NoteAttachment = {\n id: randomUUID(),\n type: file.mimeType.startsWith('image/') ? 'image' : file.mimeType.startsWith('audio/') ? 'audio' : file.mimeType.startsWith('video/') ? 'video' : 'file',\n mimeType: file.mimeType,\n fileName: file.name,\n size,\n relativePath,\n duration: file.duration,\n };\n const attachments = [...(note.attachments || []), attachment];\n const kind = note.kind === 'thought' && attachment.type === 'audio' ? 'voice' : note.kind === 'thought' ? 'media' : note.kind;\n await this.store.updateNote(noteId, { attachments, kind });\n return attachment;\n }\n\n async getAttachmentPath(noteId: string, attachmentId: string): Promise<{ filePath: string; mimeType: string; fileName: string } | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const attachment = note.attachments?.find((a) => a.id === attachmentId);\n if (!attachment) return null;\n return { filePath: this.store.resolveAttachmentPath(noteId, attachment.relativePath), mimeType: attachment.mimeType, fileName: attachment.fileName };\n }\n\n async listNoteHistory(noteId: string): Promise<NoteSnapshotEntry[]> { return this.store.listSnapshots(noteId); }\n async getNoteSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> { return this.store.getSnapshot(noteId, timestamp); }\n\n async restoreNoteSnapshot(noteId: string, timestamp: number): Promise<Note | null> {\n const snapshot = await this.store.getSnapshot(noteId, timestamp);\n const existing = await this.store.getNote(noteId);\n if (!snapshot || !existing) return null;\n await this.maybeSaveSnapshot(existing, 'restore');\n this.lastSnapshotAt.set(noteId, Date.now());\n await this.store.pruneSnapshots(noteId, MAX_SNAPSHOTS_PER_NOTE);\n return this.store.updateNote(noteId, { title: snapshot.title, markdown: snapshot.markdown, tags: snapshot.tags, kind: snapshot.kind, status: snapshot.status });\n }\n\n async flush(): Promise<void> { await this.store.flush(); }\n async moveToGroup(noteId: string, groupId: string | null): Promise<Note | null> { return this.updateNote(noteId, { groupId: groupId ?? undefined }); }\n\n async createTask(title: string, source: CaptureSource, opts: { dueAt?: number; priority?: 'high' | 'medium' | 'low'; sourceSessionKey?: string; sourceNoteId?: string; groupId?: string } = {}): Promise<Note> {\n return this.createNote({\n title,\n markdown: `- [ ] ${title}`,\n kind: 'task',\n capturedVia: source,\n groupId: opts.groupId,\n taskMeta: { done: false, dueAt: opts.dueAt, priority: opts.priority, sourceSessionKey: opts.sourceSessionKey, sourceNoteId: opts.sourceNoteId },\n });\n }\n\n async toggleTaskDone(noteId: string): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n const done = !note.taskMeta?.done;\n const markdown = note.markdown.replace(/^- \\[[ xX]\\]/m, `- [${done ? 'x' : ' '}]`);\n return this.updateNote(noteId, { markdown, taskMeta: { ...note.taskMeta, done } });\n }\n\n async updateTaskMeta(noteId: string, patch: Partial<import('./types.js').NoteTaskMeta>): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n return this.updateNote(noteId, { taskMeta: { ...note.taskMeta, done: note.taskMeta?.done ?? false, ...patch } });\n }\n\n async recordOpen(noteId: string): Promise<Note | null> {\n return this.updateNote(noteId, { lastOpenedAt: Date.now() } as Partial<Note>);\n }\n\n private async maybeSaveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n if (trigger !== 'edit') {\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n return;\n }\n const last = this.lastSnapshotAt.get(note.id) ?? 0;\n if (Date.now() - last < SNAPSHOT_THROTTLE_MS) return;\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n }\n}\n\nexport { buildNoteAttachmentRef };\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function bindAutomationToProject(automationId: string, projectId: string): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
//#region src/projects/automation-bind.ts
|
|
3
|
+
function bindAutomationToProject(automationId, projectId) {
|
|
4
|
+
const db = getSqliteDatabase();
|
|
5
|
+
if (!db.prepare(`SELECT 1 FROM projects WHERE project_id = ?`).get(projectId)) throw new Error(`Project not found: ${projectId}`);
|
|
6
|
+
if (!db.prepare(`SELECT 1 FROM automations WHERE automation_id = ?`).get(automationId)) throw new Error(`Automation not found: ${automationId}`);
|
|
7
|
+
runSqliteWriteTransaction((tx) => {
|
|
8
|
+
const now = Date.now();
|
|
9
|
+
tx.prepare(`UPDATE automations SET project_id = ?, updated_at_ms = ? WHERE automation_id = ?`).run(projectId, now, automationId);
|
|
10
|
+
tx.prepare(`UPDATE projects SET last_active_at = ?, updated_at = ? WHERE project_id = ?`).run(now, now, projectId);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { bindAutomationToProject };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=automation-bind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automation-bind.js","names":[],"sources":["../../../src/projects/automation-bind.ts"],"sourcesContent":["import { getSqliteDatabase, runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\n\nexport function bindAutomationToProject(automationId: string, projectId: string): void {\n const db = getSqliteDatabase();\n if (!db.prepare(`SELECT 1 FROM projects WHERE project_id = ?`).get(projectId)) throw new Error(`Project not found: ${projectId}`);\n if (!db.prepare(`SELECT 1 FROM automations WHERE automation_id = ?`).get(automationId)) throw new Error(`Automation not found: ${automationId}`);\n runSqliteWriteTransaction((tx) => {\n const now = Date.now();\n tx.prepare(`UPDATE automations SET project_id = ?, updated_at_ms = ? WHERE automation_id = ?`).run(projectId, now, automationId);\n tx.prepare(`UPDATE projects SET last_active_at = ?, updated_at = ? WHERE project_id = ?`).run(now, now, projectId);\n });\n}\n"],"mappings":";;AAEA,SAAgB,wBAAwB,cAAsB,WAAyB;CACrF,MAAM,KAAK,mBAAmB;AAC9B,KAAI,CAAC,GAAG,QAAQ,8CAA8C,CAAC,IAAI,UAAU,CAAE,OAAM,IAAI,MAAM,sBAAsB,YAAY;AACjI,KAAI,CAAC,GAAG,QAAQ,oDAAoD,CAAC,IAAI,aAAa,CAAE,OAAM,IAAI,MAAM,yBAAyB,eAAe;AAChJ,4BAA2B,OAAO;EAChC,MAAM,MAAM,KAAK,KAAK;AACtB,KAAG,QAAQ,mFAAmF,CAAC,IAAI,WAAW,KAAK,aAAa;AAChI,KAAG,QAAQ,8EAA8E,CAAC,IAAI,KAAK,KAAK,UAAU;GAClH"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function bindGoalToProject(goalId: string, projectId: string): void;
|
|
2
|
+
export declare function unbindGoalFromProject(goalId: string): void;
|
|
3
|
+
export declare function listProjectGoalIds(projectId: string, limit?: number, offset?: number): string[];
|
|
4
|
+
export declare function bindGoalsToProject(goalIds: string[], projectId: string): void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
//#region src/projects/goal-bind.ts
|
|
3
|
+
function assertProjectExists(projectId) {
|
|
4
|
+
if (!getSqliteDatabase().prepare(`SELECT 1 FROM projects WHERE project_id = ?`).get(projectId)) throw new Error(`Project not found: ${projectId}`);
|
|
5
|
+
}
|
|
6
|
+
function assertGoalExists(goalId) {
|
|
7
|
+
if (!getSqliteDatabase().prepare(`SELECT 1 FROM goals WHERE goal_id = ?`).get(goalId)) throw new Error(`Goal not found: ${goalId}`);
|
|
8
|
+
}
|
|
9
|
+
function bindGoalToProject(goalId, projectId) {
|
|
10
|
+
assertProjectExists(projectId);
|
|
11
|
+
assertGoalExists(goalId);
|
|
12
|
+
runSqliteWriteTransaction((db) => {
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
db.prepare(`UPDATE goals SET project_id = ?, updated_at = ? WHERE goal_id = ?`).run(projectId, now, goalId);
|
|
15
|
+
db.prepare(`UPDATE projects SET last_active_at = ?, updated_at = ? WHERE project_id = ?`).run(now, now, projectId);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function unbindGoalFromProject(goalId) {
|
|
19
|
+
assertGoalExists(goalId);
|
|
20
|
+
runSqliteWriteTransaction((db) => {
|
|
21
|
+
db.prepare(`UPDATE goals SET project_id = NULL, updated_at = ? WHERE goal_id = ?`).run(Date.now(), goalId);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function listProjectGoalIds(projectId, limit = 100, offset = 0) {
|
|
25
|
+
assertProjectExists(projectId);
|
|
26
|
+
return getSqliteDatabase().prepare(`SELECT goal_id FROM goals WHERE project_id = ? ORDER BY updated_at DESC LIMIT ? OFFSET ?`).all(projectId, Math.min(500, Math.max(1, Math.floor(limit))), Math.max(0, Math.floor(offset))).map((row) => row.goal_id);
|
|
27
|
+
}
|
|
28
|
+
function bindGoalsToProject(goalIds, projectId) {
|
|
29
|
+
assertProjectExists(projectId);
|
|
30
|
+
runSqliteWriteTransaction((db) => {
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
const stmt = db.prepare(`UPDATE goals SET project_id = ?, updated_at = ? WHERE goal_id = ?`);
|
|
33
|
+
for (const goalId of goalIds) stmt.run(projectId, now, goalId);
|
|
34
|
+
db.prepare(`UPDATE projects SET last_active_at = ?, updated_at = ? WHERE project_id = ?`).run(now, now, projectId);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { bindGoalToProject, bindGoalsToProject, listProjectGoalIds, unbindGoalFromProject };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=goal-bind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-bind.js","names":[],"sources":["../../../src/projects/goal-bind.ts"],"sourcesContent":["import { getSqliteDatabase, runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\n\nfunction assertProjectExists(projectId: string): void {\n const row = getSqliteDatabase().prepare(`SELECT 1 FROM projects WHERE project_id = ?`).get(projectId);\n if (!row) throw new Error(`Project not found: ${projectId}`);\n}\n\nfunction assertGoalExists(goalId: string): void {\n const row = getSqliteDatabase().prepare(`SELECT 1 FROM goals WHERE goal_id = ?`).get(goalId);\n if (!row) throw new Error(`Goal not found: ${goalId}`);\n}\n\nexport function bindGoalToProject(goalId: string, projectId: string): void {\n assertProjectExists(projectId);\n assertGoalExists(goalId);\n runSqliteWriteTransaction((db) => {\n const now = Date.now();\n db.prepare(`UPDATE goals SET project_id = ?, updated_at = ? WHERE goal_id = ?`).run(projectId, now, goalId);\n db.prepare(`UPDATE projects SET last_active_at = ?, updated_at = ? WHERE project_id = ?`).run(now, now, projectId);\n });\n}\n\nexport function unbindGoalFromProject(goalId: string): void {\n assertGoalExists(goalId);\n runSqliteWriteTransaction((db) => {\n db.prepare(`UPDATE goals SET project_id = NULL, updated_at = ? WHERE goal_id = ?`).run(Date.now(), goalId);\n });\n}\n\nexport function listProjectGoalIds(projectId: string, limit = 100, offset = 0): string[] {\n assertProjectExists(projectId);\n const rows = getSqliteDatabase()\n .prepare(`SELECT goal_id FROM goals WHERE project_id = ? ORDER BY updated_at DESC LIMIT ? OFFSET ?`)\n .all(projectId, Math.min(500, Math.max(1, Math.floor(limit))), Math.max(0, Math.floor(offset))) as Array<{ goal_id: string }>;\n return rows.map((row) => row.goal_id);\n}\n\nexport function bindGoalsToProject(goalIds: string[], projectId: string): void {\n assertProjectExists(projectId);\n runSqliteWriteTransaction((db) => {\n const now = Date.now();\n const stmt = db.prepare(`UPDATE goals SET project_id = ?, updated_at = ? WHERE goal_id = ?`);\n for (const goalId of goalIds) {\n stmt.run(projectId, now, goalId);\n }\n db.prepare(`UPDATE projects SET last_active_at = ?, updated_at = ? WHERE project_id = ?`).run(now, now, projectId);\n });\n}\n"],"mappings":";;AAEA,SAAS,oBAAoB,WAAyB;AAEpD,KAAI,CADQ,mBAAmB,CAAC,QAAQ,8CAA8C,CAAC,IAAI,UACnF,CAAE,OAAM,IAAI,MAAM,sBAAsB,YAAY;;AAG9D,SAAS,iBAAiB,QAAsB;AAE9C,KAAI,CADQ,mBAAmB,CAAC,QAAQ,wCAAwC,CAAC,IAAI,OAC7E,CAAE,OAAM,IAAI,MAAM,mBAAmB,SAAS;;AAGxD,SAAgB,kBAAkB,QAAgB,WAAyB;AACzE,qBAAoB,UAAU;AAC9B,kBAAiB,OAAO;AACxB,4BAA2B,OAAO;EAChC,MAAM,MAAM,KAAK,KAAK;AACtB,KAAG,QAAQ,oEAAoE,CAAC,IAAI,WAAW,KAAK,OAAO;AAC3G,KAAG,QAAQ,8EAA8E,CAAC,IAAI,KAAK,KAAK,UAAU;GAClH;;AAGJ,SAAgB,sBAAsB,QAAsB;AAC1D,kBAAiB,OAAO;AACxB,4BAA2B,OAAO;AAChC,KAAG,QAAQ,uEAAuE,CAAC,IAAI,KAAK,KAAK,EAAE,OAAO;GAC1G;;AAGJ,SAAgB,mBAAmB,WAAmB,QAAQ,KAAK,SAAS,GAAa;AACvF,qBAAoB,UAAU;AAI9B,QAHa,mBAAmB,CAC7B,QAAQ,2FAA2F,CACnG,IAAI,WAAW,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,CAAC,CACrF,CAAC,KAAK,QAAQ,IAAI,QAAQ;;AAGvC,SAAgB,mBAAmB,SAAmB,WAAyB;AAC7E,qBAAoB,UAAU;AAC9B,4BAA2B,OAAO;EAChC,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,OAAO,GAAG,QAAQ,oEAAoE;AAC5F,OAAK,MAAM,UAAU,QACnB,MAAK,IAAI,WAAW,KAAK,OAAO;AAElC,KAAG,QAAQ,8EAA8E,CAAC,IAAI,KAAK,KAAK,UAAU;GAClH"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './project-store.js';
|
|
3
|
+
export * from './project-service.js';
|
|
4
|
+
export * from './project-agent.js';
|
|
5
|
+
export * from './project-loop.js';
|
|
6
|
+
export * from './session-bind.js';
|
|
7
|
+
export * from './goal-bind.js';
|
|
8
|
+
export * from './workflow-bind.js';
|
|
9
|
+
export * from './automation-bind.js';
|
|
10
|
+
export * from './memory-bind.js';
|
|
11
|
+
export * from './workspace.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ProjectStore, slugifyProjectName } from "./project-store.js";
|
|
2
|
+
import { getProjectForSession, getProjectWorkspacePathForSession, resolveProjectWorkspacePath } from "./workspace.js";
|
|
3
|
+
import { bindGoalToProject, bindGoalsToProject, listProjectGoalIds, unbindGoalFromProject } from "./goal-bind.js";
|
|
4
|
+
import { bindSessionToProject, bindSessionsToProject, listProjectSessionKeys, moveSessionToProject, unbindSessionFromProject } from "./session-bind.js";
|
|
5
|
+
import { ProjectService } from "./project-service.js";
|
|
6
|
+
import { isValidProjectAgentId, normalizeProjectAgentId, resolveProjectAgentId } from "./project-agent.js";
|
|
7
|
+
import { buildProjectLoopOverview } from "./project-loop.js";
|
|
8
|
+
import { bindWorkflowRunToProject } from "./workflow-bind.js";
|
|
9
|
+
import { bindAutomationToProject } from "./automation-bind.js";
|
|
10
|
+
import { bindMemoryRecordToProject } from "./memory-bind.js";
|
|
11
|
+
export { ProjectService, ProjectStore, bindAutomationToProject, bindGoalToProject, bindGoalsToProject, bindMemoryRecordToProject, bindSessionToProject, bindSessionsToProject, bindWorkflowRunToProject, buildProjectLoopOverview, getProjectForSession, getProjectWorkspacePathForSession, isValidProjectAgentId, listProjectGoalIds, listProjectSessionKeys, moveSessionToProject, normalizeProjectAgentId, resolveProjectAgentId, resolveProjectWorkspacePath, slugifyProjectName, unbindGoalFromProject, unbindSessionFromProject };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function bindMemoryRecordToProject(recordId: string, projectId: string): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
//#region src/projects/memory-bind.ts
|
|
3
|
+
function bindMemoryRecordToProject(recordId, projectId) {
|
|
4
|
+
const db = getSqliteDatabase();
|
|
5
|
+
if (!db.prepare(`SELECT 1 FROM projects WHERE project_id = ?`).get(projectId)) throw new Error(`Project not found: ${projectId}`);
|
|
6
|
+
if (!db.prepare(`SELECT 1 FROM memory_records WHERE record_id = ?`).get(recordId)) throw new Error(`Memory record not found: ${recordId}`);
|
|
7
|
+
runSqliteWriteTransaction((tx) => {
|
|
8
|
+
const now = Date.now();
|
|
9
|
+
tx.prepare(`UPDATE memory_records SET project_id = ?, updated_at = ? WHERE record_id = ?`).run(projectId, now, recordId);
|
|
10
|
+
tx.prepare(`UPDATE projects SET last_active_at = ?, updated_at = ? WHERE project_id = ?`).run(now, now, projectId);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { bindMemoryRecordToProject };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=memory-bind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-bind.js","names":[],"sources":["../../../src/projects/memory-bind.ts"],"sourcesContent":["import { getSqliteDatabase, runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\n\nexport function bindMemoryRecordToProject(recordId: string, projectId: string): void {\n const db = getSqliteDatabase();\n if (!db.prepare(`SELECT 1 FROM projects WHERE project_id = ?`).get(projectId)) throw new Error(`Project not found: ${projectId}`);\n if (!db.prepare(`SELECT 1 FROM memory_records WHERE record_id = ?`).get(recordId)) throw new Error(`Memory record not found: ${recordId}`);\n runSqliteWriteTransaction((tx) => {\n const now = Date.now();\n tx.prepare(`UPDATE memory_records SET project_id = ?, updated_at = ? WHERE record_id = ?`).run(projectId, now, recordId);\n tx.prepare(`UPDATE projects SET last_active_at = ?, updated_at = ? WHERE project_id = ?`).run(now, now, projectId);\n });\n}\n"],"mappings":";;AAEA,SAAgB,0BAA0B,UAAkB,WAAyB;CACnF,MAAM,KAAK,mBAAmB;AAC9B,KAAI,CAAC,GAAG,QAAQ,8CAA8C,CAAC,IAAI,UAAU,CAAE,OAAM,IAAI,MAAM,sBAAsB,YAAY;AACjI,KAAI,CAAC,GAAG,QAAQ,mDAAmD,CAAC,IAAI,SAAS,CAAE,OAAM,IAAI,MAAM,4BAA4B,WAAW;AAC1I,4BAA2B,OAAO;EAChC,MAAM,MAAM,KAAK,KAAK;AACtB,KAAG,QAAQ,+EAA+E,CAAC,IAAI,WAAW,KAAK,SAAS;AACxH,KAAG,QAAQ,8EAA8E,CAAC,IAAI,KAAK,KAAK,UAAU;GAClH"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
import type { ProjectService } from './project-service.js';
|
|
3
|
+
export declare function resolveProjectAgentId(input: {
|
|
4
|
+
config: Config;
|
|
5
|
+
projects: ProjectService;
|
|
6
|
+
explicitAgentId?: string | null;
|
|
7
|
+
projectId?: string | null;
|
|
8
|
+
}): string;
|
|
9
|
+
export declare function isValidProjectAgentId(config: Config, agentId: string | null | undefined): boolean;
|
|
10
|
+
export declare function normalizeProjectAgentId(agentId: string | null | undefined): string | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
2
|
+
//#region src/projects/project-agent.ts
|
|
3
|
+
init_resolve_route();
|
|
4
|
+
function normalizeAgentId(value) {
|
|
5
|
+
const trimmed = value?.trim();
|
|
6
|
+
return trimmed ? trimmed.toLowerCase() : void 0;
|
|
7
|
+
}
|
|
8
|
+
function resolveProjectAgentId(input) {
|
|
9
|
+
const fallback = getDefaultAgentId(input.config);
|
|
10
|
+
const explicitAgentId = normalizeAgentId(input.explicitAgentId);
|
|
11
|
+
if (explicitAgentId) return agentExists(explicitAgentId, input.config) ? explicitAgentId : fallback;
|
|
12
|
+
const projectId = input.projectId?.trim();
|
|
13
|
+
const projectAgentId = projectId ? normalizeAgentId(input.projects.get(projectId)?.defaultAgentId) : void 0;
|
|
14
|
+
if (projectAgentId && agentExists(projectAgentId, input.config)) return projectAgentId;
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
|
17
|
+
function isValidProjectAgentId(config, agentId) {
|
|
18
|
+
const normalized = normalizeAgentId(agentId);
|
|
19
|
+
return !normalized || agentExists(normalized, config);
|
|
20
|
+
}
|
|
21
|
+
function normalizeProjectAgentId(agentId) {
|
|
22
|
+
return normalizeAgentId(agentId);
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { isValidProjectAgentId, normalizeProjectAgentId, resolveProjectAgentId };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=project-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-agent.js","names":[],"sources":["../../../src/projects/project-agent.ts"],"sourcesContent":["import type { Config } from '../config/schema.js';\nimport { agentExists, getDefaultAgentId } from '../routing/resolve-route.js';\nimport type { ProjectService } from './project-service.js';\n\nfunction normalizeAgentId(value: string | undefined | null): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed.toLowerCase() : undefined;\n}\n\nexport function resolveProjectAgentId(input: {\n config: Config;\n projects: ProjectService;\n explicitAgentId?: string | null;\n projectId?: string | null;\n}): string {\n const fallback = getDefaultAgentId(input.config);\n const explicitAgentId = normalizeAgentId(input.explicitAgentId);\n if (explicitAgentId) {\n return agentExists(explicitAgentId, input.config) ? explicitAgentId : fallback;\n }\n\n const projectId = input.projectId?.trim();\n const projectAgentId = projectId ? normalizeAgentId(input.projects.get(projectId)?.defaultAgentId) : undefined;\n if (projectAgentId && agentExists(projectAgentId, input.config)) {\n return projectAgentId;\n }\n return fallback;\n}\n\nexport function isValidProjectAgentId(config: Config, agentId: string | null | undefined): boolean {\n const normalized = normalizeAgentId(agentId);\n return !normalized || agentExists(normalized, config);\n}\n\nexport function normalizeProjectAgentId(agentId: string | null | undefined): string | undefined {\n return normalizeAgentId(agentId);\n}\n"],"mappings":";;oBAC6E;AAG7E,SAAS,iBAAiB,OAAsD;CAC9E,MAAM,UAAU,OAAO,MAAM;AAC7B,QAAO,UAAU,QAAQ,aAAa,GAAG,KAAA;;AAG3C,SAAgB,sBAAsB,OAK3B;CACT,MAAM,WAAW,kBAAkB,MAAM,OAAO;CAChD,MAAM,kBAAkB,iBAAiB,MAAM,gBAAgB;AAC/D,KAAI,gBACF,QAAO,YAAY,iBAAiB,MAAM,OAAO,GAAG,kBAAkB;CAGxE,MAAM,YAAY,MAAM,WAAW,MAAM;CACzC,MAAM,iBAAiB,YAAY,iBAAiB,MAAM,SAAS,IAAI,UAAU,EAAE,eAAe,GAAG,KAAA;AACrG,KAAI,kBAAkB,YAAY,gBAAgB,MAAM,OAAO,CAC7D,QAAO;AAET,QAAO;;AAGT,SAAgB,sBAAsB,QAAgB,SAA6C;CACjG,MAAM,aAAa,iBAAiB,QAAQ;AAC5C,QAAO,CAAC,cAAc,YAAY,YAAY,OAAO;;AAGvD,SAAgB,wBAAwB,SAAwD;AAC9F,QAAO,iBAAiB,QAAQ"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { GoalWithDetails } from '../goals/index.js';
|
|
2
|
+
import type { MemoryRecord } from '../agent/memory/types.js';
|
|
3
|
+
import type { ProjectWithDetails } from './types.js';
|
|
4
|
+
export type ProjectWorkflowRunBrief = {
|
|
5
|
+
runId: string;
|
|
6
|
+
definitionId: string;
|
|
7
|
+
status: string;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
errorMessage?: string;
|
|
10
|
+
};
|
|
11
|
+
export type ProjectAttentionItem = {
|
|
12
|
+
id: string;
|
|
13
|
+
kind: 'blocked_goal' | 'stale_goal' | 'failed_workflow';
|
|
14
|
+
title: string;
|
|
15
|
+
detail?: string;
|
|
16
|
+
status?: string;
|
|
17
|
+
href?: string;
|
|
18
|
+
updatedAt?: number;
|
|
19
|
+
};
|
|
20
|
+
export type ProjectTimelineItem = {
|
|
21
|
+
id: string;
|
|
22
|
+
kind: 'session' | 'goal' | 'workflow' | 'memory';
|
|
23
|
+
title: string;
|
|
24
|
+
detail?: string;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
status?: string;
|
|
27
|
+
href?: string;
|
|
28
|
+
};
|
|
29
|
+
export type ProjectLoopOverview = {
|
|
30
|
+
activeGoals: GoalWithDetails[];
|
|
31
|
+
blockedGoals: GoalWithDetails[];
|
|
32
|
+
staleGoals: GoalWithDetails[];
|
|
33
|
+
nextActions: Array<{
|
|
34
|
+
goalId: string;
|
|
35
|
+
title: string;
|
|
36
|
+
nextAction?: string;
|
|
37
|
+
status: string;
|
|
38
|
+
updatedAt?: number;
|
|
39
|
+
}>;
|
|
40
|
+
attentionItems: ProjectAttentionItem[];
|
|
41
|
+
timeline: ProjectTimelineItem[];
|
|
42
|
+
digest: {
|
|
43
|
+
status: 'healthy' | 'attention' | 'idle' | 'empty';
|
|
44
|
+
summary: string;
|
|
45
|
+
nextAction?: string;
|
|
46
|
+
};
|
|
47
|
+
failedWorkflowRuns: ProjectWorkflowRunBrief[];
|
|
48
|
+
recommendedAction?: string;
|
|
49
|
+
};
|
|
50
|
+
export declare function buildProjectLoopOverview(input: {
|
|
51
|
+
project: ProjectWithDetails;
|
|
52
|
+
goals: GoalWithDetails[];
|
|
53
|
+
recentWorkflowRuns: ProjectWorkflowRunBrief[];
|
|
54
|
+
failedWorkflowRuns?: ProjectWorkflowRunBrief[];
|
|
55
|
+
memoryRecords?: MemoryRecord[];
|
|
56
|
+
nowMs?: number;
|
|
57
|
+
staleAfterMs?: number;
|
|
58
|
+
}): ProjectLoopOverview;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
//#region src/projects/project-loop.ts
|
|
2
|
+
const ACTIVE_GOAL_STATUSES = new Set([
|
|
3
|
+
"active",
|
|
4
|
+
"paused",
|
|
5
|
+
"blocked",
|
|
6
|
+
"needs_input"
|
|
7
|
+
]);
|
|
8
|
+
const STALE_GOAL_STATUSES = new Set(["active", "paused"]);
|
|
9
|
+
const DEFAULT_STALE_AFTER_MS = 10080 * 60 * 1e3;
|
|
10
|
+
function goalUpdatedAtDesc(left, right) {
|
|
11
|
+
return right.updatedAt - left.updatedAt;
|
|
12
|
+
}
|
|
13
|
+
function compactText(value, max = 180) {
|
|
14
|
+
const trimmed = value?.trim().replace(/\s+/g, " ");
|
|
15
|
+
if (!trimmed) return void 0;
|
|
16
|
+
return trimmed.length <= max ? trimmed : `${trimmed.slice(0, max - 3).trimEnd()}...`;
|
|
17
|
+
}
|
|
18
|
+
function buildProjectLoopOverview(input) {
|
|
19
|
+
const staleCutoff = (input.nowMs ?? Date.now()) - (input.staleAfterMs ?? DEFAULT_STALE_AFTER_MS);
|
|
20
|
+
const projectGoals = [...input.goals].sort(goalUpdatedAtDesc);
|
|
21
|
+
const activeGoals = projectGoals.filter((goal) => ACTIVE_GOAL_STATUSES.has(goal.status)).slice(0, 6);
|
|
22
|
+
const blockedGoals = projectGoals.filter((goal) => goal.status === "blocked" || goal.status === "needs_input").slice(0, 4);
|
|
23
|
+
const staleGoals = projectGoals.filter((goal) => STALE_GOAL_STATUSES.has(goal.status) && goal.updatedAt < staleCutoff).slice(0, 5);
|
|
24
|
+
const nextActions = activeGoals.filter((goal) => goal.nextAction?.trim()).slice(0, 5).map((goal) => ({
|
|
25
|
+
goalId: goal.id,
|
|
26
|
+
title: goal.title,
|
|
27
|
+
nextAction: goal.nextAction,
|
|
28
|
+
status: goal.status,
|
|
29
|
+
updatedAt: goal.updatedAt
|
|
30
|
+
}));
|
|
31
|
+
const failedWorkflowRuns = (input.failedWorkflowRuns ?? input.recentWorkflowRuns.filter((run) => run.status === "failed" || run.status === "timeout" || run.status === "cancelled")).slice(0, 5);
|
|
32
|
+
const attentionItems = [
|
|
33
|
+
...blockedGoals.map((goal) => ({
|
|
34
|
+
id: `goal:${goal.id}:blocked`,
|
|
35
|
+
kind: "blocked_goal",
|
|
36
|
+
title: goal.title,
|
|
37
|
+
detail: compactText(goal.blockedReason || goal.nextAction || goal.description),
|
|
38
|
+
status: goal.status,
|
|
39
|
+
href: `/goals/${encodeURIComponent(goal.id)}`,
|
|
40
|
+
updatedAt: goal.updatedAt
|
|
41
|
+
})),
|
|
42
|
+
...staleGoals.map((goal) => ({
|
|
43
|
+
id: `goal:${goal.id}:stale`,
|
|
44
|
+
kind: "stale_goal",
|
|
45
|
+
title: goal.title,
|
|
46
|
+
detail: compactText(goal.nextAction || goal.description || "Goal has not changed recently."),
|
|
47
|
+
status: goal.status,
|
|
48
|
+
href: `/goals/${encodeURIComponent(goal.id)}`,
|
|
49
|
+
updatedAt: goal.updatedAt
|
|
50
|
+
})),
|
|
51
|
+
...failedWorkflowRuns.map((run) => ({
|
|
52
|
+
id: `workflow:${run.runId}:failed`,
|
|
53
|
+
kind: "failed_workflow",
|
|
54
|
+
title: run.definitionId,
|
|
55
|
+
detail: compactText(run.errorMessage || run.status),
|
|
56
|
+
status: run.status,
|
|
57
|
+
href: `/workflows/runs/${encodeURIComponent(run.runId)}`,
|
|
58
|
+
updatedAt: run.createdAt
|
|
59
|
+
}))
|
|
60
|
+
].slice(0, 8);
|
|
61
|
+
const timeline = [
|
|
62
|
+
...input.project.recentSessions.map((session) => ({
|
|
63
|
+
id: `session:${session.key}`,
|
|
64
|
+
kind: "session",
|
|
65
|
+
title: session.name ?? session.key,
|
|
66
|
+
detail: session.agentId,
|
|
67
|
+
timestamp: Date.parse(session.updatedAt),
|
|
68
|
+
href: `/chat/${encodeURIComponent(session.key)}`
|
|
69
|
+
})),
|
|
70
|
+
...projectGoals.slice(0, 8).map((goal) => ({
|
|
71
|
+
id: `goal:${goal.id}`,
|
|
72
|
+
kind: "goal",
|
|
73
|
+
title: goal.title,
|
|
74
|
+
detail: compactText(goal.nextAction || goal.blockedReason || goal.description),
|
|
75
|
+
timestamp: goal.updatedAt,
|
|
76
|
+
status: goal.status,
|
|
77
|
+
href: `/goals/${encodeURIComponent(goal.id)}`
|
|
78
|
+
})),
|
|
79
|
+
...input.recentWorkflowRuns.map((run) => ({
|
|
80
|
+
id: `workflow:${run.runId}`,
|
|
81
|
+
kind: "workflow",
|
|
82
|
+
title: run.definitionId,
|
|
83
|
+
detail: run.status,
|
|
84
|
+
timestamp: run.createdAt,
|
|
85
|
+
status: run.status,
|
|
86
|
+
href: `/workflows/runs/${encodeURIComponent(run.runId)}`
|
|
87
|
+
})),
|
|
88
|
+
...(input.memoryRecords ?? []).slice(0, 5).map((record) => ({
|
|
89
|
+
id: `memory:${record.id}`,
|
|
90
|
+
kind: "memory",
|
|
91
|
+
title: record.kind,
|
|
92
|
+
detail: compactText(record.content),
|
|
93
|
+
timestamp: Date.parse(record.updatedAt),
|
|
94
|
+
status: record.status
|
|
95
|
+
}))
|
|
96
|
+
].filter((item) => Number.isFinite(item.timestamp)).sort((left, right) => right.timestamp - left.timestamp).slice(0, 12);
|
|
97
|
+
const recommendedAction = nextActions[0]?.nextAction ?? blockedGoals[0]?.blockedReason ?? staleGoals[0]?.nextAction ?? activeGoals[0]?.title ?? (input.project.brief ? "Open a new chat to continue from the project brief." : void 0);
|
|
98
|
+
const digestStatus = attentionItems.length > 0 ? "attention" : activeGoals.length > 0 || input.recentWorkflowRuns.some((run) => run.status === "running" || run.status === "queued") ? "healthy" : timeline.length > 0 ? "idle" : "empty";
|
|
99
|
+
return {
|
|
100
|
+
activeGoals,
|
|
101
|
+
blockedGoals,
|
|
102
|
+
staleGoals,
|
|
103
|
+
nextActions,
|
|
104
|
+
attentionItems,
|
|
105
|
+
timeline,
|
|
106
|
+
digest: {
|
|
107
|
+
status: digestStatus,
|
|
108
|
+
summary: digestStatus === "attention" ? `${attentionItems.length} item(s) need attention: ${blockedGoals.length} blocker(s), ${staleGoals.length} stale goal(s), ${failedWorkflowRuns.length} failed workflow run(s).` : digestStatus === "healthy" ? `${activeGoals.length} active goal(s), ${nextActions.length} next action(s), and ${input.recentWorkflowRuns.length} recent workflow run(s).` : digestStatus === "idle" ? "Recent activity exists, but no active goal is driving the project." : "No project activity has been recorded yet.",
|
|
109
|
+
nextAction: recommendedAction
|
|
110
|
+
},
|
|
111
|
+
failedWorkflowRuns,
|
|
112
|
+
recommendedAction
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
export { buildProjectLoopOverview };
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=project-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-loop.js","names":[],"sources":["../../../src/projects/project-loop.ts"],"sourcesContent":["import type { GoalWithDetails } from '../goals/index.js';\nimport type { MemoryRecord } from '../agent/memory/types.js';\nimport type { ProjectWithDetails } from './types.js';\n\nexport type ProjectWorkflowRunBrief = {\n runId: string;\n definitionId: string;\n status: string;\n createdAt: number;\n errorMessage?: string;\n};\n\nexport type ProjectAttentionItem = {\n id: string;\n kind: 'blocked_goal' | 'stale_goal' | 'failed_workflow';\n title: string;\n detail?: string;\n status?: string;\n href?: string;\n updatedAt?: number;\n};\n\nexport type ProjectTimelineItem = {\n id: string;\n kind: 'session' | 'goal' | 'workflow' | 'memory';\n title: string;\n detail?: string;\n timestamp: number;\n status?: string;\n href?: string;\n};\n\nexport type ProjectLoopOverview = {\n activeGoals: GoalWithDetails[];\n blockedGoals: GoalWithDetails[];\n staleGoals: GoalWithDetails[];\n nextActions: Array<{\n goalId: string;\n title: string;\n nextAction?: string;\n status: string;\n updatedAt?: number;\n }>;\n attentionItems: ProjectAttentionItem[];\n timeline: ProjectTimelineItem[];\n digest: {\n status: 'healthy' | 'attention' | 'idle' | 'empty';\n summary: string;\n nextAction?: string;\n };\n failedWorkflowRuns: ProjectWorkflowRunBrief[];\n recommendedAction?: string;\n};\n\nconst ACTIVE_GOAL_STATUSES = new Set(['active', 'paused', 'blocked', 'needs_input']);\nconst STALE_GOAL_STATUSES = new Set(['active', 'paused']);\nconst DEFAULT_STALE_AFTER_MS = 7 * 24 * 60 * 60 * 1000;\n\nfunction goalUpdatedAtDesc(left: GoalWithDetails, right: GoalWithDetails): number {\n return right.updatedAt - left.updatedAt;\n}\n\nfunction compactText(value: string | undefined, max = 180): string | undefined {\n const trimmed = value?.trim().replace(/\\s+/g, ' ');\n if (!trimmed) return undefined;\n return trimmed.length <= max ? trimmed : `${trimmed.slice(0, max - 3).trimEnd()}...`;\n}\n\nexport function buildProjectLoopOverview(input: {\n project: ProjectWithDetails;\n goals: GoalWithDetails[];\n recentWorkflowRuns: ProjectWorkflowRunBrief[];\n failedWorkflowRuns?: ProjectWorkflowRunBrief[];\n memoryRecords?: MemoryRecord[];\n nowMs?: number;\n staleAfterMs?: number;\n}): ProjectLoopOverview {\n const nowMs = input.nowMs ?? Date.now();\n const staleCutoff = nowMs - (input.staleAfterMs ?? DEFAULT_STALE_AFTER_MS);\n const projectGoals = [...input.goals].sort(goalUpdatedAtDesc);\n const activeGoals = projectGoals.filter((goal) => ACTIVE_GOAL_STATUSES.has(goal.status)).slice(0, 6);\n const blockedGoals = projectGoals.filter((goal) => goal.status === 'blocked' || goal.status === 'needs_input').slice(0, 4);\n const staleGoals = projectGoals\n .filter((goal) => STALE_GOAL_STATUSES.has(goal.status) && goal.updatedAt < staleCutoff)\n .slice(0, 5);\n const nextActions = activeGoals\n .filter((goal) => goal.nextAction?.trim())\n .slice(0, 5)\n .map((goal) => ({\n goalId: goal.id,\n title: goal.title,\n nextAction: goal.nextAction,\n status: goal.status,\n updatedAt: goal.updatedAt,\n }));\n const failedWorkflowRuns = (input.failedWorkflowRuns ?? input.recentWorkflowRuns.filter((run) => (\n run.status === 'failed' || run.status === 'timeout' || run.status === 'cancelled'\n ))).slice(0, 5);\n\n const attentionItems: ProjectAttentionItem[] = [\n ...blockedGoals.map((goal) => ({\n id: `goal:${goal.id}:blocked`,\n kind: 'blocked_goal' as const,\n title: goal.title,\n detail: compactText(goal.blockedReason || goal.nextAction || goal.description),\n status: goal.status,\n href: `/goals/${encodeURIComponent(goal.id)}`,\n updatedAt: goal.updatedAt,\n })),\n ...staleGoals.map((goal) => ({\n id: `goal:${goal.id}:stale`,\n kind: 'stale_goal' as const,\n title: goal.title,\n detail: compactText(goal.nextAction || goal.description || 'Goal has not changed recently.'),\n status: goal.status,\n href: `/goals/${encodeURIComponent(goal.id)}`,\n updatedAt: goal.updatedAt,\n })),\n ...failedWorkflowRuns.map((run) => ({\n id: `workflow:${run.runId}:failed`,\n kind: 'failed_workflow' as const,\n title: run.definitionId,\n detail: compactText(run.errorMessage || run.status),\n status: run.status,\n href: `/workflows/runs/${encodeURIComponent(run.runId)}`,\n updatedAt: run.createdAt,\n })),\n ].slice(0, 8);\n\n const timeline: ProjectTimelineItem[] = [\n ...input.project.recentSessions.map((session) => ({\n id: `session:${session.key}`,\n kind: 'session' as const,\n title: session.name ?? session.key,\n detail: session.agentId,\n timestamp: Date.parse(session.updatedAt),\n href: `/chat/${encodeURIComponent(session.key)}`,\n })),\n ...projectGoals.slice(0, 8).map((goal) => ({\n id: `goal:${goal.id}`,\n kind: 'goal' as const,\n title: goal.title,\n detail: compactText(goal.nextAction || goal.blockedReason || goal.description),\n timestamp: goal.updatedAt,\n status: goal.status,\n href: `/goals/${encodeURIComponent(goal.id)}`,\n })),\n ...input.recentWorkflowRuns.map((run) => ({\n id: `workflow:${run.runId}`,\n kind: 'workflow' as const,\n title: run.definitionId,\n detail: run.status,\n timestamp: run.createdAt,\n status: run.status,\n href: `/workflows/runs/${encodeURIComponent(run.runId)}`,\n })),\n ...(input.memoryRecords ?? []).slice(0, 5).map((record) => ({\n id: `memory:${record.id}`,\n kind: 'memory' as const,\n title: record.kind,\n detail: compactText(record.content),\n timestamp: Date.parse(record.updatedAt),\n status: record.status,\n })),\n ]\n .filter((item) => Number.isFinite(item.timestamp))\n .sort((left, right) => right.timestamp - left.timestamp)\n .slice(0, 12);\n\n const recommendedAction = nextActions[0]?.nextAction\n ?? blockedGoals[0]?.blockedReason\n ?? staleGoals[0]?.nextAction\n ?? activeGoals[0]?.title\n ?? (input.project.brief ? 'Open a new chat to continue from the project brief.' : undefined);\n\n const digestStatus =\n attentionItems.length > 0 ? 'attention'\n : activeGoals.length > 0 || input.recentWorkflowRuns.some((run) => run.status === 'running' || run.status === 'queued') ? 'healthy'\n : timeline.length > 0 ? 'idle'\n : 'empty';\n const digestSummary =\n digestStatus === 'attention'\n ? `${attentionItems.length} item(s) need attention: ${blockedGoals.length} blocker(s), ${staleGoals.length} stale goal(s), ${failedWorkflowRuns.length} failed workflow run(s).`\n : digestStatus === 'healthy'\n ? `${activeGoals.length} active goal(s), ${nextActions.length} next action(s), and ${input.recentWorkflowRuns.length} recent workflow run(s).`\n : digestStatus === 'idle'\n ? 'Recent activity exists, but no active goal is driving the project.'\n : 'No project activity has been recorded yet.';\n\n return {\n activeGoals,\n blockedGoals,\n staleGoals,\n nextActions,\n attentionItems,\n timeline,\n digest: {\n status: digestStatus,\n summary: digestSummary,\n nextAction: recommendedAction,\n },\n failedWorkflowRuns,\n recommendedAction,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ProjectStore } from './project-store.js';
|
|
2
|
+
import type { CreateProjectInput, Project, ProjectListQuery, ProjectListResult, ProjectWithDetails, UpdateProjectInput } from './types.js';
|
|
3
|
+
export type ProjectSuggestion = {
|
|
4
|
+
projectId: string;
|
|
5
|
+
projectName: string;
|
|
6
|
+
score: number;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
export declare class ProjectService {
|
|
10
|
+
private readonly store;
|
|
11
|
+
constructor(store?: ProjectStore);
|
|
12
|
+
create(input: CreateProjectInput): Project;
|
|
13
|
+
get(id: string): Project | null;
|
|
14
|
+
getBySlug(slug: string): Project | null;
|
|
15
|
+
list(query?: ProjectListQuery): ProjectListResult;
|
|
16
|
+
update(id: string, input: UpdateProjectInput): Project;
|
|
17
|
+
delete(id: string): void;
|
|
18
|
+
getWithDetails(id: string): ProjectWithDetails | null;
|
|
19
|
+
attachSession(sessionKey: string, projectId: string): void;
|
|
20
|
+
detachSession(sessionKey: string): void;
|
|
21
|
+
listSessionKeys(projectId: string, limit?: number, offset?: number): string[];
|
|
22
|
+
attachGoal(goalId: string, projectId: string): void;
|
|
23
|
+
detachGoal(goalId: string): void;
|
|
24
|
+
listGoalIds(projectId: string, limit?: number, offset?: number): string[];
|
|
25
|
+
suggestProjectsForSession(sessionKey: string): ProjectSuggestion[];
|
|
26
|
+
}
|