@penclipai/server 2026.704.0 → 2026.714.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/process/execute.d.ts.map +1 -1
- package/dist/adapters/process/execute.js +1 -0
- package/dist/adapters/process/execute.js.map +1 -1
- package/dist/adapters/registry.d.ts.map +1 -1
- package/dist/adapters/registry.js +79 -51
- package/dist/adapters/registry.js.map +1 -1
- package/dist/adapters/utils.d.ts +5 -0
- package/dist/adapters/utils.d.ts.map +1 -1
- package/dist/adapters/utils.js.map +1 -1
- package/dist/agent-auth-jwt.d.ts +5 -1
- package/dist/agent-auth-jwt.d.ts.map +1 -1
- package/dist/agent-auth-jwt.js +72 -20
- package/dist/agent-auth-jwt.js.map +1 -1
- package/dist/app.d.ts +2 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +10 -0
- package/dist/app.js.map +1 -1
- package/dist/built-ins/agents/reflection-coach/AGENTS.md +47 -0
- package/dist/built-ins/agents/reflection-coach/routines/recent-agent-reflection.md +77 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +208 -116
- package/dist/index.js.map +1 -1
- package/dist/middleware/api-compression.d.ts +8 -0
- package/dist/middleware/api-compression.d.ts.map +1 -0
- package/dist/middleware/api-compression.js +207 -0
- package/dist/middleware/api-compression.js.map +1 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +130 -3
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/error-handler.d.ts.map +1 -1
- package/dist/middleware/error-handler.js +27 -0
- package/dist/middleware/error-handler.js.map +1 -1
- package/dist/onboarding-assets/default/AGENTS.md +1 -0
- package/dist/redaction.d.ts.map +1 -1
- package/dist/redaction.js +11 -0
- package/dist/redaction.js.map +1 -1
- package/dist/routes/access.d.ts.map +1 -1
- package/dist/routes/access.js +4 -3
- package/dist/routes/access.js.map +1 -1
- package/dist/routes/adapters.d.ts.map +1 -1
- package/dist/routes/adapters.js +2 -0
- package/dist/routes/adapters.js.map +1 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +222 -87
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/attention.d.ts +3 -0
- package/dist/routes/attention.d.ts.map +1 -0
- package/dist/routes/attention.js +24 -0
- package/dist/routes/attention.js.map +1 -0
- package/dist/routes/authz.d.ts.map +1 -1
- package/dist/routes/authz.js +29 -1
- package/dist/routes/authz.js.map +1 -1
- package/dist/routes/board-chat.d.ts.map +1 -1
- package/dist/routes/board-chat.js +4 -1
- package/dist/routes/board-chat.js.map +1 -1
- package/dist/routes/built-in-agents.d.ts +3 -0
- package/dist/routes/built-in-agents.d.ts.map +1 -0
- package/dist/routes/built-in-agents.js +267 -0
- package/dist/routes/built-in-agents.js.map +1 -0
- package/dist/routes/cases.d.ts +46 -0
- package/dist/routes/cases.d.ts.map +1 -0
- package/dist/routes/cases.js +1395 -0
- package/dist/routes/cases.js.map +1 -0
- package/dist/routes/companies.d.ts.map +1 -1
- package/dist/routes/companies.js +4 -1
- package/dist/routes/companies.js.map +1 -1
- package/dist/routes/company-skills.d.ts.map +1 -1
- package/dist/routes/company-skills.js +453 -33
- package/dist/routes/company-skills.js.map +1 -1
- package/dist/routes/environments.d.ts.map +1 -1
- package/dist/routes/environments.js +71 -8
- package/dist/routes/environments.js.map +1 -1
- package/dist/routes/execution-workspaces.d.ts.map +1 -1
- package/dist/routes/execution-workspaces.js +89 -3
- package/dist/routes/execution-workspaces.js.map +1 -1
- package/dist/routes/health.d.ts +2 -0
- package/dist/routes/health.d.ts.map +1 -1
- package/dist/routes/health.js +30 -0
- package/dist/routes/health.js.map +1 -1
- package/dist/routes/inbox-dismissals.d.ts.map +1 -1
- package/dist/routes/inbox-dismissals.js +80 -19
- package/dist/routes/inbox-dismissals.js.map +1 -1
- package/dist/routes/index.d.ts +2 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +2 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/issues.d.ts +25 -0
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +1455 -46
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/openapi.d.ts.map +1 -1
- package/dist/routes/openapi.js +448 -11
- package/dist/routes/openapi.js.map +1 -1
- package/dist/routes/pipelines.js +2 -2
- package/dist/routes/pipelines.js.map +1 -1
- package/dist/routes/resource-memberships.d.ts.map +1 -1
- package/dist/routes/resource-memberships.js +13 -5
- package/dist/routes/resource-memberships.js.map +1 -1
- package/dist/routes/secrets.d.ts.map +1 -1
- package/dist/routes/secrets.js +261 -1
- package/dist/routes/secrets.js.map +1 -1
- package/dist/routes/sidebar-badges.d.ts.map +1 -1
- package/dist/routes/sidebar-badges.js +18 -2
- package/dist/routes/sidebar-badges.js.map +1 -1
- package/dist/routes/user-profiles.d.ts.map +1 -1
- package/dist/routes/user-profiles.js +5 -4
- package/dist/routes/user-profiles.js.map +1 -1
- package/dist/server-info.d.ts +2 -0
- package/dist/server-info.d.ts.map +1 -1
- package/dist/server-info.js +20 -5
- package/dist/server-info.js.map +1 -1
- package/dist/services/access.d.ts +4 -4
- package/dist/services/access.d.ts.map +1 -1
- package/dist/services/activity.d.ts +3 -3
- package/dist/services/activity.d.ts.map +1 -1
- package/dist/services/activity.js +5 -4
- package/dist/services/activity.js.map +1 -1
- package/dist/services/adapter-registry-bootstrap.reconcile.test.js +1 -0
- package/dist/services/adapter-registry-bootstrap.reconcile.test.js.map +1 -1
- package/dist/services/agent-secret-bindings.d.ts +15 -0
- package/dist/services/agent-secret-bindings.d.ts.map +1 -1
- package/dist/services/agent-secret-bindings.js +43 -0
- package/dist/services/agent-secret-bindings.js.map +1 -1
- package/dist/services/agents.d.ts +194 -133
- package/dist/services/agents.d.ts.map +1 -1
- package/dist/services/agents.js +107 -4
- package/dist/services/agents.js.map +1 -1
- package/dist/services/approvals.d.ts +10 -10
- package/dist/services/approvals.d.ts.map +1 -1
- package/dist/services/approvals.js +9 -1
- package/dist/services/approvals.js.map +1 -1
- package/dist/services/assets.d.ts +5 -5
- package/dist/services/attention.d.ts +11 -0
- package/dist/services/attention.d.ts.map +1 -0
- package/dist/services/attention.js +1024 -0
- package/dist/services/attention.js.map +1 -0
- package/dist/services/authorization.d.ts +15 -2
- package/dist/services/authorization.d.ts.map +1 -1
- package/dist/services/authorization.js +324 -8
- package/dist/services/authorization.js.map +1 -1
- package/dist/services/board-auth.d.ts +2 -2
- package/dist/services/budgets.d.ts.map +1 -1
- package/dist/services/budgets.js +8 -7
- package/dist/services/budgets.js.map +1 -1
- package/dist/services/built-in-agent-metadata.d.ts +9 -0
- package/dist/services/built-in-agent-metadata.d.ts.map +1 -0
- package/dist/services/built-in-agent-metadata.js +39 -0
- package/dist/services/built-in-agent-metadata.js.map +1 -0
- package/dist/services/built-in-agents.d.ts +394 -0
- package/dist/services/built-in-agents.d.ts.map +1 -0
- package/dist/services/built-in-agents.js +1426 -0
- package/dist/services/built-in-agents.js.map +1 -0
- package/dist/services/change-consent-gate.d.ts +18 -0
- package/dist/services/change-consent-gate.d.ts.map +1 -0
- package/dist/services/change-consent-gate.js +170 -0
- package/dist/services/change-consent-gate.js.map +1 -0
- package/dist/services/companies.d.ts +14 -8
- package/dist/services/companies.d.ts.map +1 -1
- package/dist/services/companies.js +6 -1
- package/dist/services/companies.js.map +1 -1
- package/dist/services/company-artifacts.d.ts +4 -1
- package/dist/services/company-artifacts.d.ts.map +1 -1
- package/dist/services/company-artifacts.js +9 -1
- package/dist/services/company-artifacts.js.map +1 -1
- package/dist/services/company-member-roles.d.ts.map +1 -1
- package/dist/services/company-member-roles.js +2 -0
- package/dist/services/company-member-roles.js.map +1 -1
- package/dist/services/company-portability.d.ts +1 -1
- package/dist/services/company-portability.d.ts.map +1 -1
- package/dist/services/company-portability.js +113 -8
- package/dist/services/company-portability.js.map +1 -1
- package/dist/services/company-search.d.ts.map +1 -1
- package/dist/services/company-search.js +843 -294
- package/dist/services/company-search.js.map +1 -1
- package/dist/services/company-skills.d.ts +64 -3
- package/dist/services/company-skills.d.ts.map +1 -1
- package/dist/services/company-skills.js +1205 -20
- package/dist/services/company-skills.js.map +1 -1
- package/dist/services/costs.d.ts +9 -8
- package/dist/services/costs.d.ts.map +1 -1
- package/dist/services/costs.js +9 -2
- package/dist/services/costs.js.map +1 -1
- package/dist/services/dashboard.d.ts +2 -0
- package/dist/services/dashboard.d.ts.map +1 -1
- package/dist/services/dashboard.js +60 -17
- package/dist/services/dashboard.js.map +1 -1
- package/dist/services/database-backup-health.d.ts +34 -0
- package/dist/services/database-backup-health.d.ts.map +1 -0
- package/dist/services/database-backup-health.js +104 -0
- package/dist/services/database-backup-health.js.map +1 -0
- package/dist/services/document-annotations.d.ts +169 -1
- package/dist/services/document-annotations.d.ts.map +1 -1
- package/dist/services/document-annotations.js +272 -1
- package/dist/services/document-annotations.js.map +1 -1
- package/dist/services/documents.d.ts +368 -0
- package/dist/services/documents.d.ts.map +1 -1
- package/dist/services/documents.js +2 -2
- package/dist/services/documents.js.map +1 -1
- package/dist/services/environment-config.d.ts.map +1 -1
- package/dist/services/environment-config.js +6 -0
- package/dist/services/environment-config.js.map +1 -1
- package/dist/services/environment-custom-image-runtime.d.ts +28 -0
- package/dist/services/environment-custom-image-runtime.d.ts.map +1 -1
- package/dist/services/environment-custom-image-runtime.js +106 -7
- package/dist/services/environment-custom-image-runtime.js.map +1 -1
- package/dist/services/environment-custom-images.d.ts +31 -1
- package/dist/services/environment-custom-images.d.ts.map +1 -1
- package/dist/services/environment-custom-images.js +110 -4
- package/dist/services/environment-custom-images.js.map +1 -1
- package/dist/services/environment-execution-target.d.ts.map +1 -1
- package/dist/services/environment-execution-target.js +1 -3
- package/dist/services/environment-execution-target.js.map +1 -1
- package/dist/services/environment-probe.d.ts +1 -0
- package/dist/services/environment-probe.d.ts.map +1 -1
- package/dist/services/environment-probe.js +99 -5
- package/dist/services/environment-probe.js.map +1 -1
- package/dist/services/environments.d.ts +3 -1
- package/dist/services/environments.d.ts.map +1 -1
- package/dist/services/environments.js +98 -3
- package/dist/services/environments.js.map +1 -1
- package/dist/services/execution-workspace-policy.d.ts +29 -3
- package/dist/services/execution-workspace-policy.d.ts.map +1 -1
- package/dist/services/execution-workspace-policy.js +44 -1
- package/dist/services/execution-workspace-policy.js.map +1 -1
- package/dist/services/execution-workspaces.d.ts +64 -1
- package/dist/services/execution-workspaces.d.ts.map +1 -1
- package/dist/services/execution-workspaces.js +634 -3
- package/dist/services/execution-workspaces.js.map +1 -1
- package/dist/services/external-objects.d.ts +26 -26
- package/dist/services/feedback.d.ts +2 -2
- package/dist/services/finance.d.ts +5 -5
- package/dist/services/goals.d.ts +8 -8
- package/dist/services/heartbeat-stop-metadata.d.ts +2 -2
- package/dist/services/heartbeat-stop-metadata.d.ts.map +1 -1
- package/dist/services/heartbeat-stop-metadata.js +4 -0
- package/dist/services/heartbeat-stop-metadata.js.map +1 -1
- package/dist/services/heartbeat-stop-metadata.test.js +9 -0
- package/dist/services/heartbeat-stop-metadata.test.js.map +1 -1
- package/dist/services/heartbeat.d.ts +133 -28
- package/dist/services/heartbeat.d.ts.map +1 -1
- package/dist/services/heartbeat.js +1963 -239
- package/dist/services/heartbeat.js.map +1 -1
- package/dist/services/inbox-dismissals.d.ts +26 -0
- package/dist/services/inbox-dismissals.d.ts.map +1 -1
- package/dist/services/inbox-dismissals.js +33 -18
- package/dist/services/inbox-dismissals.js.map +1 -1
- package/dist/services/index.d.ts +3 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/instance-settings.d.ts +25 -1
- package/dist/services/instance-settings.d.ts.map +1 -1
- package/dist/services/instance-settings.js +103 -5
- package/dist/services/instance-settings.js.map +1 -1
- package/dist/services/issue-continuation-summary.js +1 -1
- package/dist/services/issue-continuation-summary.js.map +1 -1
- package/dist/services/issue-recovery-actions.d.ts +3 -0
- package/dist/services/issue-recovery-actions.d.ts.map +1 -1
- package/dist/services/issue-recovery-actions.js +9 -0
- package/dist/services/issue-recovery-actions.js.map +1 -1
- package/dist/services/issue-rewake-throttle.d.ts +92 -0
- package/dist/services/issue-rewake-throttle.d.ts.map +1 -0
- package/dist/services/issue-rewake-throttle.js +139 -0
- package/dist/services/issue-rewake-throttle.js.map +1 -0
- package/dist/services/issue-thread-interactions.d.ts +8 -1
- package/dist/services/issue-thread-interactions.d.ts.map +1 -1
- package/dist/services/issue-thread-interactions.js +231 -16
- package/dist/services/issue-thread-interactions.js.map +1 -1
- package/dist/services/issue-visibility.d.ts +4 -0
- package/dist/services/issue-visibility.d.ts.map +1 -0
- package/dist/services/issue-visibility.js +9 -0
- package/dist/services/issue-visibility.js.map +1 -0
- package/dist/services/issues.d.ts +225 -105
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.js +540 -18
- package/dist/services/issues.js.map +1 -1
- package/dist/services/local-service-supervisor.d.ts +3 -0
- package/dist/services/local-service-supervisor.d.ts.map +1 -1
- package/dist/services/local-service-supervisor.js +51 -0
- package/dist/services/local-service-supervisor.js.map +1 -1
- package/dist/services/pipeline-case-outputs.d.ts.map +1 -1
- package/dist/services/pipeline-case-outputs.js +2 -1
- package/dist/services/pipeline-case-outputs.js.map +1 -1
- package/dist/services/pipelines-aggregation.d.ts.map +1 -1
- package/dist/services/pipelines-aggregation.js +3 -2
- package/dist/services/pipelines-aggregation.js.map +1 -1
- package/dist/services/pipelines.d.ts +165 -165
- package/dist/services/pipelines.d.ts.map +1 -1
- package/dist/services/pipelines.js +6 -4
- package/dist/services/pipelines.js.map +1 -1
- package/dist/services/plugin-database.d.ts +2 -2
- package/dist/services/plugin-environment-driver.d.ts +1 -1
- package/dist/services/plugin-host-services.d.ts.map +1 -1
- package/dist/services/plugin-host-services.js +3 -1
- package/dist/services/plugin-host-services.js.map +1 -1
- package/dist/services/plugin-managed-routines.d.ts +1 -0
- package/dist/services/plugin-managed-routines.d.ts.map +1 -1
- package/dist/services/plugin-registry.d.ts +21 -21
- package/dist/services/productivity-review.d.ts +1 -0
- package/dist/services/productivity-review.d.ts.map +1 -1
- package/dist/services/productivity-review.js +6 -5
- package/dist/services/productivity-review.js.map +1 -1
- package/dist/services/projects.d.ts +9 -9
- package/dist/services/recovery/service.d.ts +82 -54
- package/dist/services/recovery/service.d.ts.map +1 -1
- package/dist/services/recovery/service.js +200 -35
- package/dist/services/recovery/service.js.map +1 -1
- package/dist/services/recovery/successful-run-handoff.d.ts +1 -0
- package/dist/services/recovery/successful-run-handoff.d.ts.map +1 -1
- package/dist/services/recovery/successful-run-handoff.js +2 -0
- package/dist/services/recovery/successful-run-handoff.js.map +1 -1
- package/dist/services/recovery/successful-run-handoff.test.js +20 -0
- package/dist/services/recovery/successful-run-handoff.test.js.map +1 -1
- package/dist/services/resource-memberships.d.ts +13 -10
- package/dist/services/resource-memberships.d.ts.map +1 -1
- package/dist/services/resource-memberships.js +89 -20
- package/dist/services/resource-memberships.js.map +1 -1
- package/dist/services/responsible-user-denial-run-outcomes.d.ts +60 -0
- package/dist/services/responsible-user-denial-run-outcomes.d.ts.map +1 -0
- package/dist/services/responsible-user-denial-run-outcomes.js +56 -0
- package/dist/services/responsible-user-denial-run-outcomes.js.map +1 -0
- package/dist/services/responsible-user-denial-run-outcomes.test.d.ts +2 -0
- package/dist/services/responsible-user-denial-run-outcomes.test.d.ts.map +1 -0
- package/dist/services/responsible-user-denial-run-outcomes.test.js +75 -0
- package/dist/services/responsible-user-denial-run-outcomes.test.js.map +1 -0
- package/dist/services/routines.d.ts +30 -8
- package/dist/services/routines.d.ts.map +1 -1
- package/dist/services/routines.js +241 -18
- package/dist/services/routines.js.map +1 -1
- package/dist/services/run-liveness.d.ts.map +1 -1
- package/dist/services/run-liveness.js +21 -0
- package/dist/services/run-liveness.js.map +1 -1
- package/dist/services/run-log-store.d.ts +1 -0
- package/dist/services/run-log-store.d.ts.map +1 -1
- package/dist/services/run-log-store.js +4 -0
- package/dist/services/run-log-store.js.map +1 -1
- package/dist/services/run-scratch.d.ts +42 -0
- package/dist/services/run-scratch.d.ts.map +1 -0
- package/dist/services/run-scratch.js +111 -0
- package/dist/services/run-scratch.js.map +1 -0
- package/dist/services/run-scratch.test.d.ts +2 -0
- package/dist/services/run-scratch.test.d.ts.map +1 -0
- package/dist/services/run-scratch.test.js +98 -0
- package/dist/services/run-scratch.test.js.map +1 -0
- package/dist/services/secrets.d.ts +1261 -64
- package/dist/services/secrets.d.ts.map +1 -1
- package/dist/services/secrets.js +1089 -96
- package/dist/services/secrets.js.map +1 -1
- package/dist/services/task-watchdogs.d.ts +1 -0
- package/dist/services/task-watchdogs.d.ts.map +1 -1
- package/dist/services/task-watchdogs.js +78 -9
- package/dist/services/task-watchdogs.js.map +1 -1
- package/dist/services/work-timeline.d.ts.map +1 -1
- package/dist/services/work-timeline.js +34 -2
- package/dist/services/work-timeline.js.map +1 -1
- package/dist/services/workspace-runtime-read-model.d.ts +30 -29
- package/dist/services/workspace-runtime-read-model.d.ts.map +1 -1
- package/dist/services/workspace-runtime-read-model.js.map +1 -1
- package/dist/services/workspace-runtime.d.ts +59 -13
- package/dist/services/workspace-runtime.d.ts.map +1 -1
- package/dist/services/workspace-runtime.js +1121 -102
- package/dist/services/workspace-runtime.js.map +1 -1
- package/dist/skills-catalog/catalog/bundled/paperclip-operations/reflection-coach/SKILL.md +202 -0
- package/dist/skills-catalog/catalog/bundled/product/paperclip-capsules/SKILL.md +1 -1
- package/dist/skills-catalog/catalog/bundled/product/wireframe/SKILL.md +1 -1
- package/dist/skills-catalog/catalog/optional/content/release-announcement/SKILL.md +90 -0
- package/dist/skills-catalog/catalog/optional/finance/ramp/SKILL.md +98 -0
- package/dist/skills-catalog/generated/catalog.json +84 -12
- package/dist/ui-branding.d.ts +7 -0
- package/dist/ui-branding.d.ts.map +1 -1
- package/dist/ui-branding.js +8 -2
- package/dist/ui-branding.js.map +1 -1
- package/dist/version.d.ts +14 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +114 -3
- package/dist/version.js.map +1 -1
- package/package.json +19 -20
- package/skills/paperclip/SKILL.md +45 -10
- package/skills/paperclip/references/api-reference.md +246 -1
- package/skills/paperclip/references/cases.md +295 -0
- package/skills/paperclip/references/company-skills.md +1 -1
- package/skills/paperclip-board/SKILL.md +3 -4
- package/skills/paperclip-converting-plans-to-tasks/SKILL.md +3 -7
- package/skills/para-memory-files/SKILL.md +3 -7
- package/ui-dist/assets/{abnfDiagram-VRR7QNED-BsFz2IiG.js → abnfDiagram-VRR7QNED-Dtgfy1PK.js} +1 -1
- package/ui-dist/assets/{arc-HZhAwbOs.js → arc-BGdvNvs8.js} +1 -1
- package/ui-dist/assets/{architectureDiagram-ZJ3FMSHR-BteMjuOn.js → architectureDiagram-ZJ3FMSHR-CK19SQDx.js} +1 -1
- package/ui-dist/assets/{blockDiagram-677ZJIJ3-Iq66uZjf.js → blockDiagram-677ZJIJ3-Kh4N3XG4.js} +1 -1
- package/ui-dist/assets/{browser-ponyfill-BBsuyZJt.js → browser-ponyfill-B3hXtEFW.js} +1 -1
- package/ui-dist/assets/{c4Diagram-LMCZKHZV-_nlglj7I.js → c4Diagram-LMCZKHZV-CBHpGrgU.js} +1 -1
- package/ui-dist/assets/channel-4fjB8e8N.js +1 -0
- package/ui-dist/assets/{chunk-2Q5K7J3B-Cvz7WwSQ.js → chunk-2Q5K7J3B-BdHbqi7k.js} +1 -1
- package/ui-dist/assets/{chunk-32BRIVSS-LLubniCS.js → chunk-32BRIVSS-DxtzZzpt.js} +1 -1
- package/ui-dist/assets/{chunk-5VM5RSS4-BOst5hcr.js → chunk-5VM5RSS4-DMKxBbgu.js} +1 -1
- package/ui-dist/assets/{chunk-EX3LRPZG-D5WNShVm.js → chunk-EX3LRPZG-BaIOPi4v.js} +1 -1
- package/ui-dist/assets/{chunk-JWPE2WC7-CA07x4av.js → chunk-JWPE2WC7-DGo3MPmr.js} +1 -1
- package/ui-dist/assets/{chunk-MOJQB5TN-Clfi83rK.js → chunk-MOJQB5TN-BEhQg0uD.js} +1 -1
- package/ui-dist/assets/{chunk-RYQCIY6F-BhZ6p7YJ.js → chunk-RYQCIY6F-HPJ6zRpJ.js} +1 -1
- package/ui-dist/assets/{chunk-V7JOEXUC-CdexJGoV.js → chunk-V7JOEXUC-Bl_6cAJD.js} +1 -1
- package/ui-dist/assets/{chunk-VR4S4FIN-8vjmBhr1.js → chunk-VR4S4FIN-KMjgGCsw.js} +1 -1
- package/ui-dist/assets/{chunk-XXDRQBXY-CqmCaplj.js → chunk-XXDRQBXY-oWGAIKjr.js} +1 -1
- package/ui-dist/assets/classDiagram-OUVF2IWQ-CTXxO5l9.js +1 -0
- package/ui-dist/assets/classDiagram-v2-EOCWNBFH-CTXxO5l9.js +1 -0
- package/ui-dist/assets/{cose-bilkent-JH36ORCC-CY-zAygY.js → cose-bilkent-JH36ORCC-Ckqse1pH.js} +1 -1
- package/ui-dist/assets/{cynefin-VYW2F7L2-BQSQ1HKr.js → cynefin-VYW2F7L2-DfZ8Hzqi.js} +1 -1
- package/ui-dist/assets/{cynefinDiagram-TSTJHNR4-NJCuFrZL.js → cynefinDiagram-TSTJHNR4-BkDQo9oi.js} +1 -1
- package/ui-dist/assets/{dagre-VKFMJZFB-DAUPIc8g.js → dagre-VKFMJZFB-ClghXQ6E.js} +1 -1
- package/ui-dist/assets/{diagram-FQU43EPY-DvMwJlCi.js → diagram-FQU43EPY-D5a0CwpV.js} +1 -1
- package/ui-dist/assets/{diagram-G47NLZAW-DPY0Jz_y.js → diagram-G47NLZAW-hVjYR_xl.js} +1 -1
- package/ui-dist/assets/{diagram-NH7WQ7WH-BpopeEhp.js → diagram-NH7WQ7WH-BlDPgD5Z.js} +1 -1
- package/ui-dist/assets/{diagram-OA4YK3LP-Qpu05z9X.js → diagram-OA4YK3LP-D0iZKIS3.js} +1 -1
- package/ui-dist/assets/{diagram-WEI45ONY-DHnvw9XU.js → diagram-WEI45ONY-m6hrfD0J.js} +1 -1
- package/ui-dist/assets/{ebnfDiagram-CCIWWBDH-D61S54_7.js → ebnfDiagram-CCIWWBDH-D4SQYLod.js} +1 -1
- package/ui-dist/assets/{erDiagram-Q63AITRT-pplAN_x2.js → erDiagram-Q63AITRT-Byzb6-I5.js} +1 -1
- package/ui-dist/assets/{flowDiagram-23GEKE2U-BaBcbyDq.js → flowDiagram-23GEKE2U-CaTUkFO6.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-NO4QXBWP-BOJSII2b.js → ganttDiagram-NO4QXBWP-DmdMQ3ES.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-IHSO6WYX-aYAaO4a2.js → gitGraphDiagram-IHSO6WYX-Bt-1g2CS.js} +1 -1
- package/ui-dist/assets/{index-CZxYajxF.js → index-2Dk9yO0W.js} +1 -1
- package/ui-dist/assets/{index-B8H0SHw1.js → index-8jLpgFNU.js} +1 -1
- package/ui-dist/assets/{index-3EKATXgc.js → index-AP_iimxs.js} +1 -1
- package/ui-dist/assets/{index-C2JgdjPa.js → index-BNJasQY9.js} +1 -1
- package/ui-dist/assets/{index-BaiskB3o.js → index-BO-aNmyX.js} +1 -1
- package/ui-dist/assets/{index-B5YenxAQ.js → index-BPCzCn1Y.js} +1 -1
- package/ui-dist/assets/{index-Da2kqT1M.js → index-BSLnLTb2.js} +1 -1
- package/ui-dist/assets/{index-By0oeEvz.js → index-CCZ2qgHN.js} +1 -1
- package/ui-dist/assets/{index-bUFCSEgv.js → index-CLZXR1k9.js} +1 -1
- package/ui-dist/assets/{index-CJlw4l9L.js → index-CTNfrE1s.js} +1 -1
- package/ui-dist/assets/{index-TmpY6Xh_.js → index-ChNd25s7.js} +1 -1
- package/ui-dist/assets/{index-BRgdHUNR.js → index-CjHiMOEO.js} +1 -1
- package/ui-dist/assets/{index-DrL6pHSJ.js → index-CmeJQpXZ.js} +1 -1
- package/ui-dist/assets/index-CyuYtn7U.css +1 -0
- package/ui-dist/assets/{index-CKKytnOd.js → index-CzZjM8eh.js} +1 -1
- package/ui-dist/assets/{index-Dceamza_.js → index-D-6T0Aft.js} +1 -1
- package/ui-dist/assets/{index-CjDqB1SX.js → index-DG_7V1pG.js} +1 -1
- package/ui-dist/assets/index-DIKcgxCt.js +676 -0
- package/ui-dist/assets/{index-BKVeJ3Jh.js → index-DiUerHmi.js} +1 -1
- package/ui-dist/assets/{index-C-nKjFZh.js → index-NZ7v5Fc2.js} +1 -1
- package/ui-dist/assets/{index-CvPPuNs1.js → index-Py70EvBg.js} +1 -1
- package/ui-dist/assets/{index-LHkZdu0h.js → index-R3aYn0qM.js} +1 -1
- package/ui-dist/assets/{index-BT8b79Bd.js → index-YXpm7gW-.js} +1 -1
- package/ui-dist/assets/{index-CemenVOf.js → index-n4q3gzki.js} +1 -1
- package/ui-dist/assets/{index-D3ODiUup.js → index-vlZ3GoYY.js} +1 -1
- package/ui-dist/assets/{infoDiagram-FWYZ7A6U-C7_90qGq.js → infoDiagram-FWYZ7A6U-jdi5ciVg.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-FXEZZL3T-T-nPPdTt.js → ishikawaDiagram-FXEZZL3T-CMz5VvYp.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-5HDEW3XC-C3hqQN0R.js → journeyDiagram-5HDEW3XC-DK6dk2R-.js} +1 -1
- package/ui-dist/assets/{kanban-definition-HUTT4EX6-CPoD9DUm.js → kanban-definition-HUTT4EX6-DX5cZL-D.js} +1 -1
- package/ui-dist/assets/{linear-D-S8yr3Z.js → linear-CI96ABKp.js} +1 -1
- package/ui-dist/assets/{mermaid.core-DhvH8shK.js → mermaid.core-DnsEVfbd.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-LN4V7U3C-CxCIKrKo.js → mindmap-definition-LN4V7U3C-BdDCY7hf.js} +1 -1
- package/ui-dist/assets/{pegDiagram-2B236MQR-D4G-PC6N.js → pegDiagram-2B236MQR-DuY4TF-f.js} +1 -1
- package/ui-dist/assets/{pieDiagram-ENE6RG2P-N4X8UvqY.js → pieDiagram-ENE6RG2P-bgFw7dm3.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-ABIIQ3AL-CZohoDln.js → quadrantDiagram-ABIIQ3AL-BCZVWyWS.js} +1 -1
- package/ui-dist/assets/{railroadDiagram-RFXS5EU6-fMGQVhwF.js → railroadDiagram-RFXS5EU6-D9V5_Cgc.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-TGXJPOKE-CK0IuUmk.js → requirementDiagram-TGXJPOKE-CItsya2r.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-HTMAVEWB-pSfb3CqG.js → sankeyDiagram-HTMAVEWB-Cz9IHsZO.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-DBY2YBRQ-CbhkqIeq.js → sequenceDiagram-DBY2YBRQ-hMSqTiwK.js} +1 -1
- package/ui-dist/assets/{sizeCapture-X5ZJPWSS-B6vqqPx-.js → sizeCapture-X5ZJPWSS-0g9M5wMf.js} +1 -1
- package/ui-dist/assets/{stateDiagram-2N3HPSRC-DIJf9h5C.js → stateDiagram-2N3HPSRC-F8_YhgWl.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-fZImUBtq.js +1 -0
- package/ui-dist/assets/{swimlanes-5IMT3BWC-DIX_LV8O.js → swimlanes-5IMT3BWC-CCZqPbpE.js} +2 -2
- package/ui-dist/assets/swimlanesDiagram-G3AALYLV-9C1UT51R.js +8 -0
- package/ui-dist/assets/{timeline-definition-FHXFAJF6-CD-Pxb_g.js → timeline-definition-FHXFAJF6-BeUIr18x.js} +1 -1
- package/ui-dist/assets/{vennDiagram-L72KCM5P-BAZsWL0R.js → vennDiagram-L72KCM5P-D3d5h_G4.js} +1 -1
- package/ui-dist/assets/{wardleyDiagram-EHGQE667-CnNyfwX5.js → wardleyDiagram-EHGQE667-Bzt-As9A.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-FW5EYKEG-j9YgsD3Y.js → xychartDiagram-FW5EYKEG-C2mly0xf.js} +1 -1
- package/ui-dist/fonts/InterVariable-Italic.woff2 +0 -0
- package/ui-dist/fonts/InterVariable.woff2 +0 -0
- package/ui-dist/fonts/NOTICE.md +17 -0
- package/ui-dist/index.html +2 -2
- package/ui-dist/locales/en/common.json +1142 -5
- package/ui-dist/locales/zh-CN/common.json +1140 -3
- package/ui-dist/assets/channel-CsiI2LYw.js +0 -1
- package/ui-dist/assets/classDiagram-OUVF2IWQ-CBn1Jqo8.js +0 -1
- package/ui-dist/assets/classDiagram-v2-EOCWNBFH-CBn1Jqo8.js +0 -1
- package/ui-dist/assets/index-BsL8K1vL.css +0 -1
- package/ui-dist/assets/index-D__fTsb2.js +0 -643
- package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-DpwLD7YL.js +0 -1
- package/ui-dist/assets/swimlanesDiagram-G3AALYLV-Cklauutg.js +0 -8
|
@@ -0,0 +1,1426 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { readPaperclipSkillSyncPreference, writePaperclipSkillSyncPreference } from "@penclipai/adapter-utils/server-utils";
|
|
7
|
+
import { and, desc, eq, ne } from "drizzle-orm";
|
|
8
|
+
import { agents, builtInManagedResources, companies, issueThreadInteractions, issues, routines, routineTriggers } from "@penclipai/db";
|
|
9
|
+
import { syncRoutineVariablesWithTemplate } from "@penclipai/shared";
|
|
10
|
+
import { conflict, HttpError, notFound, unprocessable } from "../errors.js";
|
|
11
|
+
import { logActivity } from "./activity-log.js";
|
|
12
|
+
import { agentInstructionsService } from "./agent-instructions.js";
|
|
13
|
+
import { agentService } from "./agents.js";
|
|
14
|
+
import { approvalService } from "./approvals.js";
|
|
15
|
+
import { readBuiltInAgentMarker, withBuiltInAgentMarker, } from "./built-in-agent-metadata.js";
|
|
16
|
+
import { companySkillService } from "./company-skills.js";
|
|
17
|
+
import { routineService } from "./routines.js";
|
|
18
|
+
import { accessService } from "./access.js";
|
|
19
|
+
const BUILT_IN_AGENT_KEY_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
20
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const require = createRequire(import.meta.url);
|
|
22
|
+
const BUILT_INS_DIR = path.resolve(moduleDir, "../built-ins/agents");
|
|
23
|
+
const SOURCE_BUILT_INS_DIR = path.resolve(moduleDir, "../../src/built-ins/agents");
|
|
24
|
+
const FALLBACK_REFLECTION_COACH_INSTRUCTIONS = [
|
|
25
|
+
"# Reflection Coach",
|
|
26
|
+
"",
|
|
27
|
+
"You are Paperclip's built-in Reflection Coach.",
|
|
28
|
+
"Review recent agent execution records, identify evidence-backed improvement patterns, and propose the smallest durable instruction, skill, or tool-description change.",
|
|
29
|
+
"Do not apply changes in the same run. Present a reviewable diff and wait for the required Paperclip issue-thread approval before any follow-up applies it.",
|
|
30
|
+
"",
|
|
31
|
+
].join("\n");
|
|
32
|
+
const FALLBACK_REFLECTION_COACH_ROUTINE = [
|
|
33
|
+
"Review recent agent work for coaching opportunities.",
|
|
34
|
+
"",
|
|
35
|
+
"Select recent target agents, inspect their work history and current instructions, then propose small, review-gated improvements that would prevent repeated misses.",
|
|
36
|
+
"",
|
|
37
|
+
].join("\n");
|
|
38
|
+
const FALLBACK_REFLECTION_COACH_SKILL = [
|
|
39
|
+
"---",
|
|
40
|
+
"name: reflection-coach",
|
|
41
|
+
"description: Reflect on another agent's recent execution record and propose the smallest review-gated improvement.",
|
|
42
|
+
"key: paperclipai/bundled/paperclip-operations/reflection-coach",
|
|
43
|
+
"---",
|
|
44
|
+
"",
|
|
45
|
+
"# Reflection Coach",
|
|
46
|
+
"",
|
|
47
|
+
"Review another agent's recent execution record, name evidence-backed patterns, and propose the smallest durable improvement as a reviewable diff. Do not hot-swap instructions or skills in the same run.",
|
|
48
|
+
"",
|
|
49
|
+
].join("\n");
|
|
50
|
+
const warnedBuiltInTextFallbacks = new Set();
|
|
51
|
+
const warnedBuiltInTextReadErrors = new Set();
|
|
52
|
+
function resolvePackageRoot(packageName) {
|
|
53
|
+
try {
|
|
54
|
+
return path.dirname(require.resolve(`${packageName}/package.json`));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function readBuiltInTextWithFallback(label, candidatePaths, fallbackText) {
|
|
61
|
+
const attemptedPaths = candidatePaths.filter((candidatePath) => candidatePath.trim().length > 0);
|
|
62
|
+
for (const candidatePath of attemptedPaths) {
|
|
63
|
+
try {
|
|
64
|
+
return readFileSync(candidatePath, "utf8");
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const code = error.code;
|
|
68
|
+
if (code !== "ENOENT") {
|
|
69
|
+
const codeLabel = code || String(error);
|
|
70
|
+
const warningKey = [label, candidatePath, codeLabel].join(":");
|
|
71
|
+
if (!warnedBuiltInTextReadErrors.has(warningKey)) {
|
|
72
|
+
warnedBuiltInTextReadErrors.add(warningKey);
|
|
73
|
+
console.warn("[paperclip] Built-in agent asset " + label + " read error on " + candidatePath + ": " + codeLabel);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Try every known runtime/source path before falling back to compiled text.
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!warnedBuiltInTextFallbacks.has(label)) {
|
|
80
|
+
warnedBuiltInTextFallbacks.add(label);
|
|
81
|
+
console.warn(`[paperclip] Built-in agent asset ${label} was not readable; using bundled fallback text. `
|
|
82
|
+
+ `Checked: ${attemptedPaths.join(", ")}`);
|
|
83
|
+
}
|
|
84
|
+
return fallbackText;
|
|
85
|
+
}
|
|
86
|
+
function readBuiltInText(relativePath, fallbackText) {
|
|
87
|
+
return readBuiltInTextWithFallback(relativePath, [path.join(BUILT_INS_DIR, relativePath), path.join(SOURCE_BUILT_INS_DIR, relativePath)], fallbackText);
|
|
88
|
+
}
|
|
89
|
+
const skillsCatalogRoot = resolvePackageRoot("@penclipai/skills-catalog");
|
|
90
|
+
const REFLECTION_COACH_INSTRUCTIONS = readBuiltInText("reflection-coach/AGENTS.md", FALLBACK_REFLECTION_COACH_INSTRUCTIONS);
|
|
91
|
+
const REFLECTION_COACH_ROUTINE = readBuiltInText("reflection-coach/routines/recent-agent-reflection.md", FALLBACK_REFLECTION_COACH_ROUTINE);
|
|
92
|
+
const REFLECTION_COACH_SKILL = readBuiltInTextWithFallback("reflection-coach/SKILL.md", [
|
|
93
|
+
path.resolve(moduleDir, "../../../packages/skills-catalog/catalog/bundled/paperclip-operations/reflection-coach/SKILL.md"),
|
|
94
|
+
path.resolve(moduleDir, "../skills-catalog/catalog/bundled/paperclip-operations/reflection-coach/SKILL.md"),
|
|
95
|
+
...(skillsCatalogRoot
|
|
96
|
+
? [path.join(skillsCatalogRoot, "catalog/bundled/paperclip-operations/reflection-coach/SKILL.md")]
|
|
97
|
+
: []),
|
|
98
|
+
], FALLBACK_REFLECTION_COACH_SKILL);
|
|
99
|
+
const DEFINITIONS = validateBuiltInAgentDefinitions([
|
|
100
|
+
{
|
|
101
|
+
key: "briefs",
|
|
102
|
+
displayName: "Briefs Agent",
|
|
103
|
+
featureKeys: ["briefs"],
|
|
104
|
+
shortPurpose: "Prepares concise operational briefs for the board and agent company.",
|
|
105
|
+
defaultInstructions: "You are Paperclip's built-in Briefs agent. Produce concise, sourced operational briefs that help the board understand current company work, risks, and next actions.",
|
|
106
|
+
defaultRole: "general",
|
|
107
|
+
allowedAdapterTypes: ["codex_local", "claude_local", "gemini_local", "opencode_local", "process"],
|
|
108
|
+
defaultBudgetMonthlyCents: 0,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
key: "learning",
|
|
112
|
+
displayName: "Learning Agent",
|
|
113
|
+
featureKeys: ["learning"],
|
|
114
|
+
shortPurpose: "Maintains reusable company learning from completed work and recurring patterns.",
|
|
115
|
+
defaultInstructions: "You are Paperclip's built-in Learning agent. Extract durable lessons from completed work, preserve useful patterns, and keep learning artifacts grounded in source context.",
|
|
116
|
+
defaultRole: "general",
|
|
117
|
+
allowedAdapterTypes: ["codex_local", "claude_local", "gemini_local", "opencode_local", "process"],
|
|
118
|
+
defaultBudgetMonthlyCents: 0,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
key: "reflection-coach",
|
|
122
|
+
displayName: "Reflection Coach",
|
|
123
|
+
featureKeys: ["reflection-coach"],
|
|
124
|
+
shortPurpose: "Runs evidence-backed reflection loops on recent agent work, proposes small instruction and skill improvements, and requests approval before changes are applied.",
|
|
125
|
+
defaultInstructions: REFLECTION_COACH_INSTRUCTIONS,
|
|
126
|
+
defaultRole: "general",
|
|
127
|
+
defaultTitle: "Reflection Coach",
|
|
128
|
+
defaultIcon: "eye",
|
|
129
|
+
defaultPermissions: {
|
|
130
|
+
canCreateAgents: false,
|
|
131
|
+
canCreateSkills: false,
|
|
132
|
+
builtInMutationPolicy: {
|
|
133
|
+
requiresDisplayedDiff: true,
|
|
134
|
+
requiresAcceptedTaskInteraction: true,
|
|
135
|
+
applyInSeparateFollowUpRun: true,
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
defaultStatus: "paused",
|
|
139
|
+
defaultManager: "single_root_agent",
|
|
140
|
+
allowedAdapterTypes: ["claude_local", "codex_local", "gemini_local", "opencode_local", "process"],
|
|
141
|
+
defaultBudgetMonthlyCents: 0,
|
|
142
|
+
bundle: {
|
|
143
|
+
stockVersion: "2026-07-08",
|
|
144
|
+
instructions: {
|
|
145
|
+
entryFile: "AGENTS.md",
|
|
146
|
+
files: {
|
|
147
|
+
"AGENTS.md": REFLECTION_COACH_INSTRUCTIONS,
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
skill: {
|
|
151
|
+
skillKey: "reflection-coach",
|
|
152
|
+
displayName: "Reflection Coach",
|
|
153
|
+
slug: "reflection-coach",
|
|
154
|
+
canonicalKey: "paperclipai/bundled/paperclip-operations/reflection-coach",
|
|
155
|
+
files: {
|
|
156
|
+
"reflection-coach/SKILL.md": REFLECTION_COACH_SKILL,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
routine: {
|
|
160
|
+
routineKey: "recent-agent-reflection",
|
|
161
|
+
title: "Review recent agent trajectories for coaching proposals",
|
|
162
|
+
description: REFLECTION_COACH_ROUTINE,
|
|
163
|
+
status: "paused",
|
|
164
|
+
priority: "medium",
|
|
165
|
+
concurrencyPolicy: "coalesce_if_active",
|
|
166
|
+
catchUpPolicy: "skip_missed",
|
|
167
|
+
variables: [
|
|
168
|
+
{ name: "lookbackDays", label: "Lookback days", type: "number", defaultValue: 7, required: true, options: [] },
|
|
169
|
+
{ name: "maxTargetAgents", label: "Max target agents", type: "number", defaultValue: 8, required: true, options: [] },
|
|
170
|
+
{
|
|
171
|
+
name: "targetAgentMode",
|
|
172
|
+
label: "Target agent mode",
|
|
173
|
+
type: "select",
|
|
174
|
+
defaultValue: "recent_active",
|
|
175
|
+
required: true,
|
|
176
|
+
options: ["recent_active", "recent_blocked", "recent_completed"],
|
|
177
|
+
},
|
|
178
|
+
{ name: "excludeAgentIds", label: "Excluded agent ids", type: "text", defaultValue: "", required: false, options: [] },
|
|
179
|
+
],
|
|
180
|
+
triggers: [
|
|
181
|
+
{
|
|
182
|
+
kind: "schedule",
|
|
183
|
+
label: "Weekly reflection review",
|
|
184
|
+
enabled: false,
|
|
185
|
+
cronExpression: "0 9 * * 1",
|
|
186
|
+
timezone: "UTC",
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
]);
|
|
193
|
+
const DEFINITIONS_BY_KEY = new Map(DEFINITIONS.map((definition) => [definition.key, definition]));
|
|
194
|
+
const ROOT_AGENT_DEFAULT_CHANGE_GRANTS = ["agents:configure", "skills:create"];
|
|
195
|
+
const BUILT_IN_AGENT_DEFAULT_GRANTS = {
|
|
196
|
+
"reflection-coach": ["agents:suggest-changes", "skills:suggest-changes"],
|
|
197
|
+
};
|
|
198
|
+
function isPlainRecord(value) {
|
|
199
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
200
|
+
}
|
|
201
|
+
function nonEmptyString(value) {
|
|
202
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
203
|
+
}
|
|
204
|
+
function uniqueNonEmptyStrings(values) {
|
|
205
|
+
const seen = new Set();
|
|
206
|
+
const result = [];
|
|
207
|
+
for (const value of values) {
|
|
208
|
+
const normalized = value.trim();
|
|
209
|
+
if (!normalized || seen.has(normalized))
|
|
210
|
+
continue;
|
|
211
|
+
seen.add(normalized);
|
|
212
|
+
result.push(normalized);
|
|
213
|
+
}
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
function stableJson(value) {
|
|
217
|
+
if (Array.isArray(value))
|
|
218
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
219
|
+
if (value && typeof value === "object") {
|
|
220
|
+
return `{${Object.entries(value)
|
|
221
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
222
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)
|
|
223
|
+
.join(",")}}`;
|
|
224
|
+
}
|
|
225
|
+
return JSON.stringify(value);
|
|
226
|
+
}
|
|
227
|
+
function stockHash(value) {
|
|
228
|
+
return `sha256:${createHash("sha256").update(stableJson(value)).digest("hex")}`;
|
|
229
|
+
}
|
|
230
|
+
function changedFileList(currentFiles, stockFiles) {
|
|
231
|
+
const paths = new Set([...Object.keys(currentFiles), ...Object.keys(stockFiles)]);
|
|
232
|
+
return [...paths]
|
|
233
|
+
.filter((filePath) => (currentFiles[filePath] ?? null) !== (stockFiles[filePath] ?? null))
|
|
234
|
+
.sort((left, right) => left.localeCompare(right));
|
|
235
|
+
}
|
|
236
|
+
function resourceStatus(input) {
|
|
237
|
+
if (!input.resourceId || !input.currentHash)
|
|
238
|
+
return "missing";
|
|
239
|
+
if (input.currentHash === input.latestStockHash)
|
|
240
|
+
return "stock_current";
|
|
241
|
+
if (input.bindingStockHash && input.currentHash === input.bindingStockHash) {
|
|
242
|
+
return "stock_update_available";
|
|
243
|
+
}
|
|
244
|
+
return "operator_modified";
|
|
245
|
+
}
|
|
246
|
+
function stockState(input) {
|
|
247
|
+
const status = resourceStatus({
|
|
248
|
+
resourceId: input.resourceId,
|
|
249
|
+
currentHash: input.currentHash,
|
|
250
|
+
bindingStockHash: input.bindingStockHash,
|
|
251
|
+
latestStockHash: input.latestStockHash,
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
resourceKind: input.resourceKind,
|
|
255
|
+
resourceKey: input.resourceKey,
|
|
256
|
+
resourceId: input.resourceId,
|
|
257
|
+
stockVersion: input.stockVersion,
|
|
258
|
+
stockHash: input.latestStockHash,
|
|
259
|
+
currentHash: input.currentHash,
|
|
260
|
+
stockStatus: status,
|
|
261
|
+
updateAvailable: status === "stock_update_available" || status === "operator_modified",
|
|
262
|
+
resetAvailable: status !== "stock_current",
|
|
263
|
+
...(input.changedFiles && input.changedFiles.length > 0 ? { changedFiles: input.changedFiles } : {}),
|
|
264
|
+
...(input.scheduleEnabled !== undefined ? { scheduleEnabled: input.scheduleEnabled } : {}),
|
|
265
|
+
...(input.pendingUpdateInteractionId !== undefined
|
|
266
|
+
? { pendingUpdateInteractionId: input.pendingUpdateInteractionId }
|
|
267
|
+
: {}),
|
|
268
|
+
...(input.pendingUpdateIssueId !== undefined ? { pendingUpdateIssueId: input.pendingUpdateIssueId } : {}),
|
|
269
|
+
...(input.pendingUpdateIssueIdentifier !== undefined
|
|
270
|
+
? { pendingUpdateIssueIdentifier: input.pendingUpdateIssueIdentifier }
|
|
271
|
+
: {}),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
export function validateBuiltInAgentDefinitions(definitions) {
|
|
275
|
+
const seenKeys = new Set();
|
|
276
|
+
for (const definition of definitions) {
|
|
277
|
+
if (!BUILT_IN_AGENT_KEY_PATTERN.test(definition.key)) {
|
|
278
|
+
throw new Error(`Invalid built-in agent key: ${definition.key}`);
|
|
279
|
+
}
|
|
280
|
+
if (seenKeys.has(definition.key)) {
|
|
281
|
+
throw new Error(`Duplicate built-in agent key: ${definition.key}`);
|
|
282
|
+
}
|
|
283
|
+
seenKeys.add(definition.key);
|
|
284
|
+
if (!definition.displayName.trim()) {
|
|
285
|
+
throw new Error(`Built-in agent ${definition.key} requires a displayName`);
|
|
286
|
+
}
|
|
287
|
+
if (!definition.shortPurpose.trim()) {
|
|
288
|
+
throw new Error(`Built-in agent ${definition.key} requires a shortPurpose`);
|
|
289
|
+
}
|
|
290
|
+
if (!definition.defaultInstructions.trim()) {
|
|
291
|
+
throw new Error(`Built-in agent ${definition.key} requires defaultInstructions`);
|
|
292
|
+
}
|
|
293
|
+
if (!definition.defaultRole.trim()) {
|
|
294
|
+
throw new Error(`Built-in agent ${definition.key} requires a defaultRole`);
|
|
295
|
+
}
|
|
296
|
+
if (uniqueNonEmptyStrings(definition.featureKeys).length !== definition.featureKeys.length) {
|
|
297
|
+
throw new Error(`Built-in agent ${definition.key} featureKeys must be unique non-empty strings`);
|
|
298
|
+
}
|
|
299
|
+
if (definition.featureKeys.length === 0) {
|
|
300
|
+
throw new Error(`Built-in agent ${definition.key} requires at least one featureKey`);
|
|
301
|
+
}
|
|
302
|
+
if (definition.allowedAdapterTypes
|
|
303
|
+
&& uniqueNonEmptyStrings(definition.allowedAdapterTypes).length !== definition.allowedAdapterTypes.length) {
|
|
304
|
+
throw new Error(`Built-in agent ${definition.key} allowedAdapterTypes must be unique non-empty strings`);
|
|
305
|
+
}
|
|
306
|
+
if (definition.defaultBudgetMonthlyCents !== undefined
|
|
307
|
+
&& (!Number.isInteger(definition.defaultBudgetMonthlyCents) || definition.defaultBudgetMonthlyCents < 0)) {
|
|
308
|
+
throw new Error(`Built-in agent ${definition.key} defaultBudgetMonthlyCents must be a non-negative integer`);
|
|
309
|
+
}
|
|
310
|
+
if (definition.bundle) {
|
|
311
|
+
if (!definition.bundle.stockVersion.trim()) {
|
|
312
|
+
throw new Error(`Built-in agent ${definition.key} bundle requires a stockVersion`);
|
|
313
|
+
}
|
|
314
|
+
if (!definition.bundle.instructions.files[definition.bundle.instructions.entryFile]) {
|
|
315
|
+
throw new Error(`Built-in agent ${definition.key} bundle instructions require the entry file`);
|
|
316
|
+
}
|
|
317
|
+
if (!definition.bundle.skill.files[`${definition.bundle.skill.slug}/SKILL.md`]) {
|
|
318
|
+
throw new Error(`Built-in agent ${definition.key} bundle skill requires SKILL.md`);
|
|
319
|
+
}
|
|
320
|
+
if (!definition.bundle.routine.description.trim()) {
|
|
321
|
+
throw new Error(`Built-in agent ${definition.key} bundle routine requires a description`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return definitions.map((definition) => ({
|
|
326
|
+
...definition,
|
|
327
|
+
featureKeys: [...definition.featureKeys],
|
|
328
|
+
allowedAdapterTypes: definition.allowedAdapterTypes ? [...definition.allowedAdapterTypes] : undefined,
|
|
329
|
+
bundle: definition.bundle ? {
|
|
330
|
+
...definition.bundle,
|
|
331
|
+
instructions: {
|
|
332
|
+
...definition.bundle.instructions,
|
|
333
|
+
files: { ...definition.bundle.instructions.files },
|
|
334
|
+
},
|
|
335
|
+
skill: {
|
|
336
|
+
...definition.bundle.skill,
|
|
337
|
+
files: { ...definition.bundle.skill.files },
|
|
338
|
+
},
|
|
339
|
+
routine: {
|
|
340
|
+
...definition.bundle.routine,
|
|
341
|
+
variables: definition.bundle.routine.variables.map((variable) => ({ ...variable, options: [...variable.options] })),
|
|
342
|
+
triggers: definition.bundle.routine.triggers.map((trigger) => ({ ...trigger })),
|
|
343
|
+
},
|
|
344
|
+
} : undefined,
|
|
345
|
+
}));
|
|
346
|
+
}
|
|
347
|
+
export function listBuiltInAgentDefinitions() {
|
|
348
|
+
return DEFINITIONS.map((definition) => ({ ...definition, featureKeys: [...definition.featureKeys] }));
|
|
349
|
+
}
|
|
350
|
+
export function getBuiltInAgentDefinition(key) {
|
|
351
|
+
return DEFINITIONS_BY_KEY.get(key) ?? null;
|
|
352
|
+
}
|
|
353
|
+
export function requireBuiltInAgentDefinition(key) {
|
|
354
|
+
const definition = getBuiltInAgentDefinition(key);
|
|
355
|
+
if (!definition)
|
|
356
|
+
throw notFound(`Built-in agent definition not found: ${key}`);
|
|
357
|
+
return definition;
|
|
358
|
+
}
|
|
359
|
+
function defaultAdapterType(definition) {
|
|
360
|
+
return definition.allowedAdapterTypes?.[0] ?? "process";
|
|
361
|
+
}
|
|
362
|
+
function normalizeAdapterType(value) {
|
|
363
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
364
|
+
}
|
|
365
|
+
function selectPreferredAdapterType(definition, usage) {
|
|
366
|
+
const fallback = defaultAdapterType(definition);
|
|
367
|
+
const preference = definition.allowedAdapterTypes ?? [];
|
|
368
|
+
if (preference.length === 0)
|
|
369
|
+
return fallback;
|
|
370
|
+
const rank = new Map(preference.map((adapterType, index) => [adapterType, index]));
|
|
371
|
+
let selected = null;
|
|
372
|
+
for (const entry of usage) {
|
|
373
|
+
const adapterRank = rank.get(entry.adapterType);
|
|
374
|
+
if (adapterRank === undefined)
|
|
375
|
+
continue;
|
|
376
|
+
if (!selected || entry.count > selected.count || (entry.count === selected.count && adapterRank < selected.rank)) {
|
|
377
|
+
selected = { ...entry, rank: adapterRank };
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return selected?.adapterType ?? fallback;
|
|
381
|
+
}
|
|
382
|
+
function assertAdapterAllowed(definition, adapterType) {
|
|
383
|
+
if (definition.allowedAdapterTypes && !definition.allowedAdapterTypes.includes(adapterType)) {
|
|
384
|
+
throw unprocessable(`Adapter type ${adapterType} is not allowed for built-in agent ${definition.key}`, {
|
|
385
|
+
code: "built_in_agent_adapter_not_allowed",
|
|
386
|
+
key: definition.key,
|
|
387
|
+
allowedAdapterTypes: definition.allowedAdapterTypes,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function hasCompleteAdapterConfig(adapterType, adapterConfig) {
|
|
392
|
+
if (!isPlainRecord(adapterConfig))
|
|
393
|
+
return false;
|
|
394
|
+
if (["process", "command"].includes(adapterType)) {
|
|
395
|
+
return nonEmptyString(adapterConfig.command) || nonEmptyString(adapterConfig.script);
|
|
396
|
+
}
|
|
397
|
+
if (adapterType === "http") {
|
|
398
|
+
return nonEmptyString(adapterConfig.url) || nonEmptyString(adapterConfig.endpoint) || nonEmptyString(adapterConfig.webhookUrl);
|
|
399
|
+
}
|
|
400
|
+
if (adapterType === "openclaw_gateway" || adapterType === "hermes_gateway") {
|
|
401
|
+
return nonEmptyString(adapterConfig.baseUrl) || nonEmptyString(adapterConfig.url);
|
|
402
|
+
}
|
|
403
|
+
return nonEmptyString(adapterConfig.model);
|
|
404
|
+
}
|
|
405
|
+
export function deriveBuiltInAgentStatus(agent) {
|
|
406
|
+
if (!agent)
|
|
407
|
+
return "not_provisioned";
|
|
408
|
+
if (agent.status === "pending_approval")
|
|
409
|
+
return "pending_approval";
|
|
410
|
+
if (agent.status === "paused" || agent.pausedAt)
|
|
411
|
+
return "paused";
|
|
412
|
+
return hasCompleteAdapterConfig(agent.adapterType, agent.adapterConfig) ? "ready" : "needs_setup";
|
|
413
|
+
}
|
|
414
|
+
function builtInMetadata(definition, existing) {
|
|
415
|
+
return withBuiltInAgentMarker(existing, {
|
|
416
|
+
key: definition.key,
|
|
417
|
+
featureKeys: definition.featureKeys,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
function definitionPatch(definition, input = {}) {
|
|
421
|
+
const adapterType = input.adapterType ?? defaultAdapterType(definition);
|
|
422
|
+
assertAdapterAllowed(definition, adapterType);
|
|
423
|
+
return {
|
|
424
|
+
name: definition.displayName,
|
|
425
|
+
role: definition.defaultRole,
|
|
426
|
+
title: definition.defaultTitle ?? null,
|
|
427
|
+
icon: definition.defaultIcon ?? null,
|
|
428
|
+
capabilities: definition.shortPurpose,
|
|
429
|
+
adapterType,
|
|
430
|
+
adapterConfig: input.adapterConfig ?? {},
|
|
431
|
+
permissions: definition.defaultPermissions ?? {},
|
|
432
|
+
budgetMonthlyCents: input.budgetMonthlyCents ?? definition.defaultBudgetMonthlyCents ?? 0,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function builtInAgentNotConfiguredError(state) {
|
|
436
|
+
return new HttpError(412, `Built-in agent is not configured: ${state.definition.key}`, {
|
|
437
|
+
code: "built_in_agent_not_configured",
|
|
438
|
+
key: state.definition.key,
|
|
439
|
+
status: state.status,
|
|
440
|
+
agentId: state.agentId,
|
|
441
|
+
featureKeys: state.definition.featureKeys,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
function hasProvisionSetupInput(input) {
|
|
445
|
+
return input.adapterType !== undefined || input.adapterConfig !== undefined || input.budgetMonthlyCents !== undefined;
|
|
446
|
+
}
|
|
447
|
+
function rowIsBuiltInAgent(row, key) {
|
|
448
|
+
const marker = readBuiltInAgentMarker(row.metadata);
|
|
449
|
+
return marker?.key === key;
|
|
450
|
+
}
|
|
451
|
+
export function builtInAgentService(db) {
|
|
452
|
+
const agentSvc = agentService(db);
|
|
453
|
+
const accessSvc = accessService(db);
|
|
454
|
+
const approvalSvc = approvalService(db);
|
|
455
|
+
const instructionsSvc = agentInstructionsService();
|
|
456
|
+
const skillSvc = companySkillService(db);
|
|
457
|
+
const routineSvc = routineService(db);
|
|
458
|
+
async function findSingleRootManager(companyId) {
|
|
459
|
+
const roots = await db
|
|
460
|
+
.select()
|
|
461
|
+
.from(agents)
|
|
462
|
+
.where(and(eq(agents.companyId, companyId), ne(agents.status, "terminated")));
|
|
463
|
+
const nonBuiltInRoots = roots.filter((agent) => !readBuiltInAgentMarker(agent.metadata) && !agent.reportsTo);
|
|
464
|
+
return nonBuiltInRoots.length === 1 ? nonBuiltInRoots[0].id : null;
|
|
465
|
+
}
|
|
466
|
+
async function ensureAgentDefaultGrants(companyId, agentId, grantKeys) {
|
|
467
|
+
if (grantKeys.length === 0)
|
|
468
|
+
return 0;
|
|
469
|
+
await accessSvc.ensureMembership(companyId, "agent", agentId, "member", "active");
|
|
470
|
+
let ensured = 0;
|
|
471
|
+
for (const permissionKey of grantKeys) {
|
|
472
|
+
await accessSvc.setPrincipalPermission(companyId, "agent", agentId, permissionKey, true, null);
|
|
473
|
+
ensured += 1;
|
|
474
|
+
}
|
|
475
|
+
return ensured;
|
|
476
|
+
}
|
|
477
|
+
async function ensureBuiltInAgentDefaultGrants(agent, definition) {
|
|
478
|
+
if (agent.status === "pending_approval" || agent.status === "terminated")
|
|
479
|
+
return 0;
|
|
480
|
+
return ensureAgentDefaultGrants(agent.companyId, agent.id, BUILT_IN_AGENT_DEFAULT_GRANTS[definition.key] ?? []);
|
|
481
|
+
}
|
|
482
|
+
async function ensureRootAgentDefaultChangeGrants(companyId) {
|
|
483
|
+
const rows = await db
|
|
484
|
+
.select()
|
|
485
|
+
.from(agents)
|
|
486
|
+
.where(and(eq(agents.companyId, companyId), ne(agents.status, "terminated")));
|
|
487
|
+
const rootCeoRows = rows.filter((agent) => !readBuiltInAgentMarker(agent.metadata) &&
|
|
488
|
+
!agent.reportsTo &&
|
|
489
|
+
agent.role.trim().toLowerCase() === "ceo" &&
|
|
490
|
+
agent.status !== "pending_approval");
|
|
491
|
+
if (rootCeoRows.length !== 1)
|
|
492
|
+
return 0;
|
|
493
|
+
return ensureAgentDefaultGrants(companyId, rootCeoRows[0].id, ROOT_AGENT_DEFAULT_CHANGE_GRANTS);
|
|
494
|
+
}
|
|
495
|
+
async function ensureCompanyDefaultAgentGrants(companyId) {
|
|
496
|
+
let ensured = await ensureRootAgentDefaultChangeGrants(companyId);
|
|
497
|
+
for (const definition of DEFINITIONS) {
|
|
498
|
+
const agent = await findSingleAgent(companyId, definition);
|
|
499
|
+
if (!agent)
|
|
500
|
+
continue;
|
|
501
|
+
ensured += await ensureBuiltInAgentDefaultGrants(agent, definition);
|
|
502
|
+
}
|
|
503
|
+
return ensured;
|
|
504
|
+
}
|
|
505
|
+
async function defaultProvisionInput(companyId, definition, input) {
|
|
506
|
+
if (input.adapterType || input.adapterConfig)
|
|
507
|
+
return input;
|
|
508
|
+
if (!definition.bundle)
|
|
509
|
+
return input;
|
|
510
|
+
const rows = await db
|
|
511
|
+
.select({
|
|
512
|
+
adapterType: agents.adapterType,
|
|
513
|
+
adapterConfig: agents.adapterConfig,
|
|
514
|
+
})
|
|
515
|
+
.from(agents)
|
|
516
|
+
.where(and(eq(agents.companyId, companyId), ne(agents.status, "terminated")));
|
|
517
|
+
const candidate = rows.find((row) => definition.allowedAdapterTypes?.includes(row.adapterType)
|
|
518
|
+
&& hasCompleteAdapterConfig(row.adapterType, row.adapterConfig));
|
|
519
|
+
if (!candidate)
|
|
520
|
+
return input;
|
|
521
|
+
return {
|
|
522
|
+
...input,
|
|
523
|
+
adapterType: candidate.adapterType,
|
|
524
|
+
adapterConfig: {},
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
async function getManagedResourceBinding(companyId, bundleKey, resourceKind, resourceKey) {
|
|
528
|
+
return db
|
|
529
|
+
.select()
|
|
530
|
+
.from(builtInManagedResources)
|
|
531
|
+
.where(and(eq(builtInManagedResources.companyId, companyId), eq(builtInManagedResources.bundleKey, bundleKey), eq(builtInManagedResources.resourceKind, resourceKind), eq(builtInManagedResources.resourceKey, resourceKey)))
|
|
532
|
+
.then((rows) => rows[0] ?? null);
|
|
533
|
+
}
|
|
534
|
+
async function upsertManagedResourceBinding(input) {
|
|
535
|
+
const now = new Date();
|
|
536
|
+
return db
|
|
537
|
+
.insert(builtInManagedResources)
|
|
538
|
+
.values(input)
|
|
539
|
+
.onConflictDoUpdate({
|
|
540
|
+
target: [
|
|
541
|
+
builtInManagedResources.companyId,
|
|
542
|
+
builtInManagedResources.bundleKey,
|
|
543
|
+
builtInManagedResources.resourceKind,
|
|
544
|
+
builtInManagedResources.resourceKey,
|
|
545
|
+
],
|
|
546
|
+
set: {
|
|
547
|
+
resourceId: input.resourceId,
|
|
548
|
+
stockVersion: input.stockVersion,
|
|
549
|
+
stockHash: input.stockHash,
|
|
550
|
+
defaultsJson: input.defaultsJson,
|
|
551
|
+
updatedAt: now,
|
|
552
|
+
},
|
|
553
|
+
})
|
|
554
|
+
.returning()
|
|
555
|
+
.then((rows) => rows[0] ?? null);
|
|
556
|
+
}
|
|
557
|
+
async function currentInstructionFiles(agent, bundle) {
|
|
558
|
+
const currentFiles = {};
|
|
559
|
+
for (const filePath of Object.keys(bundle.instructions.files)) {
|
|
560
|
+
try {
|
|
561
|
+
currentFiles[filePath] = (await instructionsSvc.readFile(agent, filePath)).content;
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
currentFiles[filePath] = null;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return currentFiles;
|
|
568
|
+
}
|
|
569
|
+
async function materializeInstructions(agent, definition, mode) {
|
|
570
|
+
const bundle = definition.bundle;
|
|
571
|
+
const stock = stockHash(bundle.instructions.files);
|
|
572
|
+
const binding = await getManagedResourceBinding(agent.companyId, definition.key, "instructions", "AGENTS.md");
|
|
573
|
+
const currentFiles = await currentInstructionFiles(agent, bundle);
|
|
574
|
+
const currentHash = Object.values(currentFiles).some((value) => value === null) ? null : stockHash(currentFiles);
|
|
575
|
+
const currentState = stockState({
|
|
576
|
+
resourceKind: "instructions",
|
|
577
|
+
resourceKey: "AGENTS.md",
|
|
578
|
+
resourceId: agent.id,
|
|
579
|
+
stockVersion: bundle.stockVersion,
|
|
580
|
+
latestStockHash: stock,
|
|
581
|
+
currentHash,
|
|
582
|
+
bindingStockHash: binding?.stockHash ?? null,
|
|
583
|
+
changedFiles: changedFileList(currentFiles, bundle.instructions.files),
|
|
584
|
+
});
|
|
585
|
+
const shouldWrite = mode === "reset"
|
|
586
|
+
|| currentState.stockStatus === "missing"
|
|
587
|
+
|| currentState.stockStatus === "stock_update_available";
|
|
588
|
+
if (!shouldWrite) {
|
|
589
|
+
if (!binding && currentHash === stock) {
|
|
590
|
+
await upsertManagedResourceBinding({
|
|
591
|
+
companyId: agent.companyId,
|
|
592
|
+
bundleKey: definition.key,
|
|
593
|
+
resourceKind: "instructions",
|
|
594
|
+
resourceKey: "AGENTS.md",
|
|
595
|
+
resourceId: agent.id,
|
|
596
|
+
stockVersion: bundle.stockVersion,
|
|
597
|
+
stockHash: stock,
|
|
598
|
+
defaultsJson: {
|
|
599
|
+
entryFile: bundle.instructions.entryFile,
|
|
600
|
+
files: Object.keys(bundle.instructions.files),
|
|
601
|
+
},
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
return currentState;
|
|
605
|
+
}
|
|
606
|
+
const materialized = await instructionsSvc.materializeManagedBundle(agent, bundle.instructions.files, {
|
|
607
|
+
entryFile: bundle.instructions.entryFile,
|
|
608
|
+
replaceExisting: true,
|
|
609
|
+
clearLegacyPromptTemplate: true,
|
|
610
|
+
});
|
|
611
|
+
const updated = await agentSvc.update(agent.id, {
|
|
612
|
+
adapterConfig: materialized.adapterConfig,
|
|
613
|
+
}, {
|
|
614
|
+
allowBuiltInAgentMetadata: true,
|
|
615
|
+
recordRevision: { source: `built-in-bundle:${mode}:instructions` },
|
|
616
|
+
});
|
|
617
|
+
if (!updated)
|
|
618
|
+
throw notFound("Built-in agent not found");
|
|
619
|
+
await upsertManagedResourceBinding({
|
|
620
|
+
companyId: agent.companyId,
|
|
621
|
+
bundleKey: definition.key,
|
|
622
|
+
resourceKind: "instructions",
|
|
623
|
+
resourceKey: "AGENTS.md",
|
|
624
|
+
resourceId: agent.id,
|
|
625
|
+
stockVersion: bundle.stockVersion,
|
|
626
|
+
stockHash: stock,
|
|
627
|
+
defaultsJson: {
|
|
628
|
+
entryFile: bundle.instructions.entryFile,
|
|
629
|
+
files: Object.keys(bundle.instructions.files),
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
return stockState({
|
|
633
|
+
resourceKind: "instructions",
|
|
634
|
+
resourceKey: "AGENTS.md",
|
|
635
|
+
resourceId: agent.id,
|
|
636
|
+
stockVersion: bundle.stockVersion,
|
|
637
|
+
latestStockHash: stock,
|
|
638
|
+
currentHash: stock,
|
|
639
|
+
bindingStockHash: stock,
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
async function getCurrentSkillFiles(companyId, skill, bundle) {
|
|
643
|
+
const currentFiles = {};
|
|
644
|
+
const stockFiles = bundle.skill.files;
|
|
645
|
+
for (const packagePath of Object.keys(stockFiles)) {
|
|
646
|
+
const relativePath = packagePath.split("/").slice(1).join("/") || "SKILL.md";
|
|
647
|
+
if (!skill) {
|
|
648
|
+
currentFiles[packagePath] = null;
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
if (relativePath === "SKILL.md") {
|
|
652
|
+
currentFiles[packagePath] = skill.markdown;
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
try {
|
|
656
|
+
currentFiles[packagePath] = (await skillSvc.readFile(companyId, skill.id, relativePath))?.content ?? null;
|
|
657
|
+
}
|
|
658
|
+
catch {
|
|
659
|
+
currentFiles[packagePath] = null;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
return currentFiles;
|
|
663
|
+
}
|
|
664
|
+
async function importBundledSkill(companyId, definition) {
|
|
665
|
+
const results = await skillSvc.importPackageFiles(companyId, definition.bundle.skill.files, { onConflict: "replace" });
|
|
666
|
+
const imported = results.find((result) => result.skill.key === definition.bundle.skill.canonicalKey)?.skill
|
|
667
|
+
?? results[0]?.skill
|
|
668
|
+
?? await skillSvc.getByKey(companyId, definition.bundle.skill.canonicalKey);
|
|
669
|
+
if (!imported)
|
|
670
|
+
throw notFound("Built-in bundled skill was not imported");
|
|
671
|
+
return imported;
|
|
672
|
+
}
|
|
673
|
+
async function syncBundledSkillToAgent(agent, skill) {
|
|
674
|
+
const desired = readPaperclipSkillSyncPreference(agent.adapterConfig).desiredSkillEntries;
|
|
675
|
+
const nextDesired = [
|
|
676
|
+
...desired.filter((entry) => entry.key !== skill.key),
|
|
677
|
+
{ key: skill.key, versionId: skill.currentVersionId ?? null },
|
|
678
|
+
];
|
|
679
|
+
const adapterConfig = writePaperclipSkillSyncPreference(agent.adapterConfig, nextDesired);
|
|
680
|
+
const updated = await agentSvc.update(agent.id, { adapterConfig }, {
|
|
681
|
+
allowBuiltInAgentMetadata: true,
|
|
682
|
+
recordRevision: { source: "built-in-bundle:skill-sync" },
|
|
683
|
+
});
|
|
684
|
+
if (!updated)
|
|
685
|
+
throw notFound("Built-in agent not found");
|
|
686
|
+
return updated;
|
|
687
|
+
}
|
|
688
|
+
async function materializeSkill(agent, definition, mode) {
|
|
689
|
+
const bundle = definition.bundle;
|
|
690
|
+
const stock = stockHash(bundle.skill.files);
|
|
691
|
+
const binding = await getManagedResourceBinding(agent.companyId, definition.key, "skill", bundle.skill.skillKey);
|
|
692
|
+
const boundSkill = binding ? await skillSvc.getById(agent.companyId, binding.resourceId) : null;
|
|
693
|
+
const existingByKey = await skillSvc.getByKey(agent.companyId, bundle.skill.canonicalKey);
|
|
694
|
+
const skill = boundSkill ?? existingByKey;
|
|
695
|
+
const currentFiles = await getCurrentSkillFiles(agent.companyId, skill, bundle);
|
|
696
|
+
const currentHash = skill && Object.values(currentFiles).every((value) => value !== null)
|
|
697
|
+
? stockHash(currentFiles)
|
|
698
|
+
: null;
|
|
699
|
+
const currentState = stockState({
|
|
700
|
+
resourceKind: "skill",
|
|
701
|
+
resourceKey: bundle.skill.skillKey,
|
|
702
|
+
resourceId: skill?.id ?? null,
|
|
703
|
+
stockVersion: bundle.stockVersion,
|
|
704
|
+
latestStockHash: stock,
|
|
705
|
+
currentHash,
|
|
706
|
+
bindingStockHash: binding?.stockHash ?? null,
|
|
707
|
+
changedFiles: changedFileList(currentFiles, bundle.skill.files),
|
|
708
|
+
});
|
|
709
|
+
const shouldWrite = mode === "reset"
|
|
710
|
+
|| currentState.stockStatus === "missing"
|
|
711
|
+
|| currentState.stockStatus === "stock_update_available";
|
|
712
|
+
const nextSkill = shouldWrite ? await importBundledSkill(agent.companyId, definition) : skill;
|
|
713
|
+
await upsertManagedResourceBinding({
|
|
714
|
+
companyId: agent.companyId,
|
|
715
|
+
bundleKey: definition.key,
|
|
716
|
+
resourceKind: "skill",
|
|
717
|
+
resourceKey: bundle.skill.skillKey,
|
|
718
|
+
resourceId: nextSkill.id,
|
|
719
|
+
stockVersion: bundle.stockVersion,
|
|
720
|
+
stockHash: shouldWrite ? stock : binding?.stockHash ?? stock,
|
|
721
|
+
defaultsJson: {
|
|
722
|
+
canonicalKey: bundle.skill.canonicalKey,
|
|
723
|
+
slug: bundle.skill.slug,
|
|
724
|
+
files: Object.keys(bundle.skill.files),
|
|
725
|
+
},
|
|
726
|
+
});
|
|
727
|
+
await syncBundledSkillToAgent(agent, nextSkill);
|
|
728
|
+
return stockState({
|
|
729
|
+
resourceKind: "skill",
|
|
730
|
+
resourceKey: bundle.skill.skillKey,
|
|
731
|
+
resourceId: nextSkill.id,
|
|
732
|
+
stockVersion: bundle.stockVersion,
|
|
733
|
+
latestStockHash: stock,
|
|
734
|
+
currentHash: shouldWrite ? stock : currentHash,
|
|
735
|
+
bindingStockHash: shouldWrite ? stock : binding?.stockHash ?? stock,
|
|
736
|
+
changedFiles: shouldWrite ? [] : changedFileList(currentFiles, bundle.skill.files),
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
function normalizeRoutineVariablesForHash(input) {
|
|
740
|
+
return syncRoutineVariablesWithTemplate([input.title, input.description ?? ""], input.variables ?? []).map((variable) => ({
|
|
741
|
+
name: variable.name,
|
|
742
|
+
label: variable.label ?? null,
|
|
743
|
+
type: variable.type ?? "text",
|
|
744
|
+
defaultValue: variable.defaultValue ?? null,
|
|
745
|
+
required: variable.required ?? true,
|
|
746
|
+
options: variable.options ?? [],
|
|
747
|
+
}));
|
|
748
|
+
}
|
|
749
|
+
function normalizeRoutineTriggersForHash(triggers) {
|
|
750
|
+
return triggers
|
|
751
|
+
.filter((trigger) => trigger.kind === "schedule")
|
|
752
|
+
.map((trigger) => ({
|
|
753
|
+
kind: "schedule",
|
|
754
|
+
label: trigger.label ?? null,
|
|
755
|
+
cronExpression: trigger.cronExpression ?? "",
|
|
756
|
+
timezone: trigger.timezone ?? "UTC",
|
|
757
|
+
}))
|
|
758
|
+
.sort((left, right) => stableJson(left).localeCompare(stableJson(right)));
|
|
759
|
+
}
|
|
760
|
+
function routineDefaultsHash(routine, triggers) {
|
|
761
|
+
return stockHash({
|
|
762
|
+
title: routine.title,
|
|
763
|
+
description: routine.description ?? "",
|
|
764
|
+
priority: routine.priority,
|
|
765
|
+
concurrencyPolicy: routine.concurrencyPolicy,
|
|
766
|
+
catchUpPolicy: routine.catchUpPolicy,
|
|
767
|
+
variables: normalizeRoutineVariablesForHash(routine),
|
|
768
|
+
triggers: normalizeRoutineTriggersForHash(triggers),
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
async function getRoutineByBinding(companyId, definition) {
|
|
772
|
+
const binding = await getManagedResourceBinding(companyId, definition.key, "routine", definition.bundle.routine.routineKey);
|
|
773
|
+
const routine = binding
|
|
774
|
+
? await db
|
|
775
|
+
.select()
|
|
776
|
+
.from(routines)
|
|
777
|
+
.where(and(eq(routines.companyId, companyId), eq(routines.id, binding.resourceId)))
|
|
778
|
+
.then((rows) => rows[0] ?? null)
|
|
779
|
+
: await db
|
|
780
|
+
.select()
|
|
781
|
+
.from(routines)
|
|
782
|
+
.where(and(eq(routines.companyId, companyId), eq(routines.originKind, "built_in_agent_bundle"), eq(routines.originId, `${definition.key}:${definition.bundle.routine.routineKey}`)))
|
|
783
|
+
.then((rows) => rows[0] ?? null);
|
|
784
|
+
const triggers = routine
|
|
785
|
+
? await db
|
|
786
|
+
.select()
|
|
787
|
+
.from(routineTriggers)
|
|
788
|
+
.where(eq(routineTriggers.routineId, routine.id))
|
|
789
|
+
.then((rows) => rows)
|
|
790
|
+
: [];
|
|
791
|
+
return { binding, routine, triggers };
|
|
792
|
+
}
|
|
793
|
+
function routineScheduleEnabled(routine, triggers) {
|
|
794
|
+
return Boolean(routine?.status === "active"
|
|
795
|
+
&& triggers.some((trigger) => trigger.kind === "schedule" && trigger.enabled));
|
|
796
|
+
}
|
|
797
|
+
async function pendingUpdateProposal(agent) {
|
|
798
|
+
if (!agent)
|
|
799
|
+
return null;
|
|
800
|
+
return db
|
|
801
|
+
.select({
|
|
802
|
+
interactionId: issueThreadInteractions.id,
|
|
803
|
+
issueId: issues.id,
|
|
804
|
+
issueIdentifier: issues.identifier,
|
|
805
|
+
})
|
|
806
|
+
.from(issueThreadInteractions)
|
|
807
|
+
.innerJoin(issues, eq(issueThreadInteractions.issueId, issues.id))
|
|
808
|
+
.where(and(eq(issueThreadInteractions.companyId, agent.companyId), eq(issueThreadInteractions.createdByAgentId, agent.id), eq(issueThreadInteractions.kind, "request_confirmation"), eq(issueThreadInteractions.status, "pending")))
|
|
809
|
+
.orderBy(desc(issueThreadInteractions.createdAt), desc(issueThreadInteractions.id))
|
|
810
|
+
.limit(1)
|
|
811
|
+
.then((rows) => rows[0] ?? null);
|
|
812
|
+
}
|
|
813
|
+
function withRoutineControls(state, input) {
|
|
814
|
+
if (state.resourceKind !== "routine")
|
|
815
|
+
return state;
|
|
816
|
+
return {
|
|
817
|
+
...state,
|
|
818
|
+
scheduleEnabled: routineScheduleEnabled(input.routine, input.triggers),
|
|
819
|
+
pendingUpdateInteractionId: input.proposal?.interactionId ?? null,
|
|
820
|
+
pendingUpdateIssueId: input.proposal?.issueId ?? null,
|
|
821
|
+
pendingUpdateIssueIdentifier: input.proposal?.issueIdentifier ?? null,
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
async function requireBundleRoutine(companyId, key, routineKey) {
|
|
825
|
+
const definition = requireBuiltInAgentDefinition(key);
|
|
826
|
+
if (!definition.bundle || definition.bundle.routine.routineKey !== routineKey) {
|
|
827
|
+
throw notFound("Built-in routine not found");
|
|
828
|
+
}
|
|
829
|
+
await ensureCompany(companyId);
|
|
830
|
+
const agent = await findSingleAgent(companyId, definition);
|
|
831
|
+
if (!agent)
|
|
832
|
+
throw notFound("Built-in agent is not provisioned");
|
|
833
|
+
const current = await getRoutineByBinding(companyId, definition);
|
|
834
|
+
if (!current.routine)
|
|
835
|
+
throw notFound("Built-in routine not found");
|
|
836
|
+
const schedule = current.triggers.find((trigger) => trigger.kind === "schedule") ?? null;
|
|
837
|
+
return { definition, agent, routine: current.routine, triggers: current.triggers, schedule };
|
|
838
|
+
}
|
|
839
|
+
async function ensureBuiltInAgentAssignable(agent) {
|
|
840
|
+
if (agent.status !== "paused")
|
|
841
|
+
return agent;
|
|
842
|
+
const resumed = await agentSvc.resume(agent.id);
|
|
843
|
+
if (!resumed)
|
|
844
|
+
throw notFound("Built-in agent not found");
|
|
845
|
+
return resumed;
|
|
846
|
+
}
|
|
847
|
+
async function createOrResetRoutine(agent, definition, existing, mode) {
|
|
848
|
+
const routine = definition.bundle.routine;
|
|
849
|
+
const actor = { agentId: null, userId: "built-in-bundles" };
|
|
850
|
+
const nextRoutine = existing
|
|
851
|
+
? await routineSvc.update(existing.id, {
|
|
852
|
+
title: routine.title,
|
|
853
|
+
description: routine.description,
|
|
854
|
+
assigneeAgentId: agent.id,
|
|
855
|
+
priority: routine.priority,
|
|
856
|
+
status: routine.status,
|
|
857
|
+
concurrencyPolicy: routine.concurrencyPolicy,
|
|
858
|
+
catchUpPolicy: routine.catchUpPolicy,
|
|
859
|
+
variables: routine.variables,
|
|
860
|
+
}, actor)
|
|
861
|
+
: await routineSvc.create(agent.companyId, {
|
|
862
|
+
title: routine.title,
|
|
863
|
+
description: routine.description,
|
|
864
|
+
assigneeAgentId: agent.id,
|
|
865
|
+
priority: routine.priority,
|
|
866
|
+
status: routine.status,
|
|
867
|
+
concurrencyPolicy: routine.concurrencyPolicy,
|
|
868
|
+
catchUpPolicy: routine.catchUpPolicy,
|
|
869
|
+
variables: routine.variables,
|
|
870
|
+
}, actor);
|
|
871
|
+
if (!nextRoutine)
|
|
872
|
+
throw notFound("Built-in routine not found");
|
|
873
|
+
await db
|
|
874
|
+
.update(routines)
|
|
875
|
+
.set({
|
|
876
|
+
originKind: "built_in_agent_bundle",
|
|
877
|
+
originId: `${definition.key}:${routine.routineKey}`,
|
|
878
|
+
updatedAt: new Date(),
|
|
879
|
+
})
|
|
880
|
+
.where(eq(routines.id, nextRoutine.id));
|
|
881
|
+
const currentTriggers = await db
|
|
882
|
+
.select()
|
|
883
|
+
.from(routineTriggers)
|
|
884
|
+
.where(eq(routineTriggers.routineId, nextRoutine.id))
|
|
885
|
+
.then((rows) => rows);
|
|
886
|
+
const firstSchedule = currentTriggers.find((trigger) => trigger.kind === "schedule");
|
|
887
|
+
const stockTrigger = routine.triggers[0];
|
|
888
|
+
if (stockTrigger && firstSchedule) {
|
|
889
|
+
await routineSvc.updateTrigger(firstSchedule.id, {
|
|
890
|
+
label: stockTrigger.label,
|
|
891
|
+
enabled: stockTrigger.enabled,
|
|
892
|
+
cronExpression: stockTrigger.cronExpression,
|
|
893
|
+
timezone: stockTrigger.timezone,
|
|
894
|
+
}, actor);
|
|
895
|
+
}
|
|
896
|
+
else if (stockTrigger) {
|
|
897
|
+
await routineSvc.createTrigger(nextRoutine.id, {
|
|
898
|
+
kind: "schedule",
|
|
899
|
+
label: stockTrigger.label,
|
|
900
|
+
enabled: stockTrigger.enabled,
|
|
901
|
+
cronExpression: stockTrigger.cronExpression,
|
|
902
|
+
timezone: stockTrigger.timezone,
|
|
903
|
+
}, actor);
|
|
904
|
+
}
|
|
905
|
+
await logActivity(db, {
|
|
906
|
+
companyId: agent.companyId,
|
|
907
|
+
actorType: "system",
|
|
908
|
+
actorId: "built-in-bundles",
|
|
909
|
+
action: mode === "reset" ? "built_in_agent.routine_reset" : "built_in_agent.routine_reconciled",
|
|
910
|
+
entityType: "routine",
|
|
911
|
+
entityId: nextRoutine.id,
|
|
912
|
+
details: {
|
|
913
|
+
key: definition.key,
|
|
914
|
+
routineKey: routine.routineKey,
|
|
915
|
+
status: routine.status,
|
|
916
|
+
},
|
|
917
|
+
});
|
|
918
|
+
return nextRoutine;
|
|
919
|
+
}
|
|
920
|
+
async function materializeRoutine(agent, definition, mode) {
|
|
921
|
+
const bundle = definition.bundle;
|
|
922
|
+
const stock = routineDefaultsHash(bundle.routine, bundle.routine.triggers);
|
|
923
|
+
const { binding, routine, triggers } = await getRoutineByBinding(agent.companyId, definition);
|
|
924
|
+
const currentHash = routine ? routineDefaultsHash({
|
|
925
|
+
title: routine.title,
|
|
926
|
+
description: routine.description ?? "",
|
|
927
|
+
priority: routine.priority,
|
|
928
|
+
concurrencyPolicy: routine.concurrencyPolicy,
|
|
929
|
+
catchUpPolicy: routine.catchUpPolicy,
|
|
930
|
+
variables: routine.variables ?? [],
|
|
931
|
+
}, triggers) : null;
|
|
932
|
+
const currentState = stockState({
|
|
933
|
+
resourceKind: "routine",
|
|
934
|
+
resourceKey: bundle.routine.routineKey,
|
|
935
|
+
resourceId: routine?.id ?? null,
|
|
936
|
+
stockVersion: bundle.stockVersion,
|
|
937
|
+
latestStockHash: stock,
|
|
938
|
+
currentHash,
|
|
939
|
+
bindingStockHash: binding?.stockHash ?? null,
|
|
940
|
+
});
|
|
941
|
+
const shouldWrite = mode === "reset"
|
|
942
|
+
|| currentState.stockStatus === "missing"
|
|
943
|
+
|| currentState.stockStatus === "stock_update_available";
|
|
944
|
+
const nextRoutine = shouldWrite
|
|
945
|
+
? await createOrResetRoutine(agent, definition, routine, mode)
|
|
946
|
+
: routine;
|
|
947
|
+
await upsertManagedResourceBinding({
|
|
948
|
+
companyId: agent.companyId,
|
|
949
|
+
bundleKey: definition.key,
|
|
950
|
+
resourceKind: "routine",
|
|
951
|
+
resourceKey: bundle.routine.routineKey,
|
|
952
|
+
resourceId: nextRoutine.id,
|
|
953
|
+
stockVersion: bundle.stockVersion,
|
|
954
|
+
stockHash: shouldWrite ? stock : binding?.stockHash ?? stock,
|
|
955
|
+
defaultsJson: {
|
|
956
|
+
title: bundle.routine.title,
|
|
957
|
+
status: bundle.routine.status,
|
|
958
|
+
triggerCount: bundle.routine.triggers.length,
|
|
959
|
+
},
|
|
960
|
+
});
|
|
961
|
+
const next = await getRoutineByBinding(agent.companyId, definition);
|
|
962
|
+
return withRoutineControls(stockState({
|
|
963
|
+
resourceKind: "routine",
|
|
964
|
+
resourceKey: bundle.routine.routineKey,
|
|
965
|
+
resourceId: nextRoutine.id,
|
|
966
|
+
stockVersion: bundle.stockVersion,
|
|
967
|
+
latestStockHash: stock,
|
|
968
|
+
currentHash: shouldWrite ? stock : currentHash,
|
|
969
|
+
bindingStockHash: shouldWrite ? stock : binding?.stockHash ?? stock,
|
|
970
|
+
}), {
|
|
971
|
+
routine: next.routine,
|
|
972
|
+
triggers: next.triggers,
|
|
973
|
+
proposal: await pendingUpdateProposal(agent),
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
async function bundleResourceStates(companyId, definition, agent) {
|
|
977
|
+
if (!definition.bundle || !agent)
|
|
978
|
+
return [];
|
|
979
|
+
const bundle = definition.bundle;
|
|
980
|
+
const [instructionBinding, skillBinding, routineBinding] = await Promise.all([
|
|
981
|
+
getManagedResourceBinding(companyId, definition.key, "instructions", "AGENTS.md"),
|
|
982
|
+
getManagedResourceBinding(companyId, definition.key, "skill", bundle.skill.skillKey),
|
|
983
|
+
getManagedResourceBinding(companyId, definition.key, "routine", bundle.routine.routineKey),
|
|
984
|
+
]);
|
|
985
|
+
const instructionFiles = await currentInstructionFiles(agent, bundle);
|
|
986
|
+
const skill = skillBinding
|
|
987
|
+
? await skillSvc.getById(companyId, skillBinding.resourceId)
|
|
988
|
+
: await skillSvc.getByKey(companyId, bundle.skill.canonicalKey);
|
|
989
|
+
const skillFiles = await getCurrentSkillFiles(companyId, skill, bundle);
|
|
990
|
+
const { routine, triggers } = await getRoutineByBinding(companyId, definition);
|
|
991
|
+
const proposal = await pendingUpdateProposal(agent);
|
|
992
|
+
const instructionHash = Object.values(instructionFiles).every((value) => value !== null)
|
|
993
|
+
? stockHash(instructionFiles)
|
|
994
|
+
: null;
|
|
995
|
+
const skillHash = skill && Object.values(skillFiles).every((value) => value !== null)
|
|
996
|
+
? stockHash(skillFiles)
|
|
997
|
+
: null;
|
|
998
|
+
const routineHash = routine ? routineDefaultsHash({
|
|
999
|
+
title: routine.title,
|
|
1000
|
+
description: routine.description ?? "",
|
|
1001
|
+
priority: routine.priority,
|
|
1002
|
+
concurrencyPolicy: routine.concurrencyPolicy,
|
|
1003
|
+
catchUpPolicy: routine.catchUpPolicy,
|
|
1004
|
+
variables: routine.variables ?? [],
|
|
1005
|
+
}, triggers) : null;
|
|
1006
|
+
return [
|
|
1007
|
+
stockState({
|
|
1008
|
+
resourceKind: "instructions",
|
|
1009
|
+
resourceKey: "AGENTS.md",
|
|
1010
|
+
resourceId: agent.id,
|
|
1011
|
+
stockVersion: bundle.stockVersion,
|
|
1012
|
+
latestStockHash: stockHash(bundle.instructions.files),
|
|
1013
|
+
currentHash: instructionHash,
|
|
1014
|
+
bindingStockHash: instructionBinding?.stockHash ?? null,
|
|
1015
|
+
changedFiles: changedFileList(instructionFiles, bundle.instructions.files),
|
|
1016
|
+
}),
|
|
1017
|
+
stockState({
|
|
1018
|
+
resourceKind: "skill",
|
|
1019
|
+
resourceKey: bundle.skill.skillKey,
|
|
1020
|
+
resourceId: skill?.id ?? null,
|
|
1021
|
+
stockVersion: bundle.stockVersion,
|
|
1022
|
+
latestStockHash: stockHash(bundle.skill.files),
|
|
1023
|
+
currentHash: skillHash,
|
|
1024
|
+
bindingStockHash: skillBinding?.stockHash ?? null,
|
|
1025
|
+
changedFiles: changedFileList(skillFiles, bundle.skill.files),
|
|
1026
|
+
}),
|
|
1027
|
+
withRoutineControls(stockState({
|
|
1028
|
+
resourceKind: "routine",
|
|
1029
|
+
resourceKey: bundle.routine.routineKey,
|
|
1030
|
+
resourceId: routine?.id ?? null,
|
|
1031
|
+
stockVersion: bundle.stockVersion,
|
|
1032
|
+
latestStockHash: routineDefaultsHash(bundle.routine, bundle.routine.triggers),
|
|
1033
|
+
currentHash: routineHash,
|
|
1034
|
+
bindingStockHash: routineBinding?.stockHash ?? null,
|
|
1035
|
+
}), { routine, triggers, proposal }),
|
|
1036
|
+
];
|
|
1037
|
+
}
|
|
1038
|
+
async function reconcileBundleResources(agent, definition, mode, resources) {
|
|
1039
|
+
if (!definition.bundle)
|
|
1040
|
+
return [];
|
|
1041
|
+
const selected = new Set(resources ?? ["instructions", "skill", "routine"]);
|
|
1042
|
+
const existingStates = await bundleResourceStates(agent.companyId, definition, agent);
|
|
1043
|
+
const byKind = new Map(existingStates.map((state) => [state.resourceKind, state]));
|
|
1044
|
+
const instruction = selected.has("instructions")
|
|
1045
|
+
? await materializeInstructions(agent, definition, mode)
|
|
1046
|
+
: byKind.get("instructions");
|
|
1047
|
+
const refreshedAgent = await agentSvc.getById(agent.id);
|
|
1048
|
+
if (!refreshedAgent)
|
|
1049
|
+
throw notFound("Built-in agent not found");
|
|
1050
|
+
const skill = selected.has("skill")
|
|
1051
|
+
? await materializeSkill(refreshedAgent, definition, mode)
|
|
1052
|
+
: byKind.get("skill");
|
|
1053
|
+
const refreshedAfterSkill = await agentSvc.getById(agent.id);
|
|
1054
|
+
if (!refreshedAfterSkill)
|
|
1055
|
+
throw notFound("Built-in agent not found");
|
|
1056
|
+
const routine = selected.has("routine")
|
|
1057
|
+
? await materializeRoutine(refreshedAfterSkill, definition, mode)
|
|
1058
|
+
: byKind.get("routine");
|
|
1059
|
+
return [instruction, skill, routine];
|
|
1060
|
+
}
|
|
1061
|
+
async function ensureCompany(companyId) {
|
|
1062
|
+
const company = await db
|
|
1063
|
+
.select({
|
|
1064
|
+
id: companies.id,
|
|
1065
|
+
requireBoardApprovalForNewAgents: companies.requireBoardApprovalForNewAgents,
|
|
1066
|
+
})
|
|
1067
|
+
.from(companies)
|
|
1068
|
+
.where(eq(companies.id, companyId))
|
|
1069
|
+
.then((rows) => rows[0] ?? null);
|
|
1070
|
+
if (!company)
|
|
1071
|
+
throw notFound("Company not found");
|
|
1072
|
+
return company;
|
|
1073
|
+
}
|
|
1074
|
+
async function findMarkedRows(companyId, key) {
|
|
1075
|
+
const rows = await db
|
|
1076
|
+
.select()
|
|
1077
|
+
.from(agents)
|
|
1078
|
+
.where(and(eq(agents.companyId, companyId), ne(agents.status, "terminated")));
|
|
1079
|
+
return rows
|
|
1080
|
+
.filter((row) => rowIsBuiltInAgent(row, key))
|
|
1081
|
+
.sort((left, right) => left.createdAt.getTime() - right.createdAt.getTime() || left.id.localeCompare(right.id));
|
|
1082
|
+
}
|
|
1083
|
+
async function findSingleAgent(companyId, definition) {
|
|
1084
|
+
const markedRows = await findMarkedRows(companyId, definition.key);
|
|
1085
|
+
if (markedRows.length > 1) {
|
|
1086
|
+
throw conflict(`Multiple built-in agents found for ${definition.key}`, {
|
|
1087
|
+
code: "built_in_agent_duplicate_instance",
|
|
1088
|
+
key: definition.key,
|
|
1089
|
+
agentIds: markedRows.map((row) => row.id),
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
if (markedRows.length === 0)
|
|
1093
|
+
return null;
|
|
1094
|
+
const agent = await agentSvc.getById(markedRows[0].id);
|
|
1095
|
+
return agent;
|
|
1096
|
+
}
|
|
1097
|
+
async function state(definition, agent, resources) {
|
|
1098
|
+
return {
|
|
1099
|
+
definition,
|
|
1100
|
+
status: deriveBuiltInAgentStatus(agent),
|
|
1101
|
+
agentId: agent?.id ?? null,
|
|
1102
|
+
agent,
|
|
1103
|
+
pauseReason: agent?.pauseReason ?? null,
|
|
1104
|
+
resources: resources ?? await bundleResourceStates(agent?.companyId ?? "", definition, agent),
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
async function get(companyId, key) {
|
|
1108
|
+
const definition = requireBuiltInAgentDefinition(key);
|
|
1109
|
+
await ensureCompany(companyId);
|
|
1110
|
+
return state(definition, await findSingleAgent(companyId, definition));
|
|
1111
|
+
}
|
|
1112
|
+
async function ensure(companyId, key, input = {}) {
|
|
1113
|
+
const definition = requireBuiltInAgentDefinition(key);
|
|
1114
|
+
await ensureCompany(companyId);
|
|
1115
|
+
const existing = await findSingleAgent(companyId, definition);
|
|
1116
|
+
const existingPendingApproval = existing?.status === "pending_approval";
|
|
1117
|
+
const preserveExistingAdapter = Boolean(existing
|
|
1118
|
+
&& !existingPendingApproval
|
|
1119
|
+
&& input.adapterType === undefined
|
|
1120
|
+
&& input.adapterConfig === undefined
|
|
1121
|
+
&& hasCompleteAdapterConfig(existing.adapterType, existing.adapterConfig));
|
|
1122
|
+
const resolvedInput = existingPendingApproval || preserveExistingAdapter
|
|
1123
|
+
? input
|
|
1124
|
+
: await defaultProvisionInput(companyId, definition, input);
|
|
1125
|
+
if (existing) {
|
|
1126
|
+
const patch = {
|
|
1127
|
+
metadata: builtInMetadata(definition, existing.metadata),
|
|
1128
|
+
};
|
|
1129
|
+
if (!existingPendingApproval
|
|
1130
|
+
&& (resolvedInput.adapterType !== undefined || resolvedInput.adapterConfig !== undefined)) {
|
|
1131
|
+
const adapterType = resolvedInput.adapterType ?? existing.adapterType;
|
|
1132
|
+
assertAdapterAllowed(definition, adapterType);
|
|
1133
|
+
patch.adapterType = adapterType;
|
|
1134
|
+
patch.adapterConfig = resolvedInput.adapterConfig ?? existing.adapterConfig;
|
|
1135
|
+
}
|
|
1136
|
+
if (!existingPendingApproval && resolvedInput.budgetMonthlyCents !== undefined) {
|
|
1137
|
+
patch.budgetMonthlyCents = resolvedInput.budgetMonthlyCents;
|
|
1138
|
+
}
|
|
1139
|
+
if (!existingPendingApproval
|
|
1140
|
+
&& definition.defaultManager === "single_root_agent"
|
|
1141
|
+
&& !existing.reportsTo) {
|
|
1142
|
+
const reportsTo = await findSingleRootManager(companyId);
|
|
1143
|
+
if (reportsTo)
|
|
1144
|
+
patch.reportsTo = reportsTo;
|
|
1145
|
+
}
|
|
1146
|
+
const updated = await agentSvc.update(existing.id, patch, {
|
|
1147
|
+
allowBuiltInAgentMetadata: true,
|
|
1148
|
+
recordRevision: { source: "built-in-agent:ensure" },
|
|
1149
|
+
});
|
|
1150
|
+
if (!updated)
|
|
1151
|
+
throw notFound("Built-in agent not found");
|
|
1152
|
+
if (existingPendingApproval) {
|
|
1153
|
+
return state(definition, updated);
|
|
1154
|
+
}
|
|
1155
|
+
await ensureBuiltInAgentDefaultGrants(updated, definition);
|
|
1156
|
+
const resources = await reconcileBundleResources(updated, definition, "reconcile");
|
|
1157
|
+
return state(definition, await agentSvc.getById(existing.id), resources);
|
|
1158
|
+
}
|
|
1159
|
+
const reportsTo = definition.defaultManager === "single_root_agent"
|
|
1160
|
+
? await findSingleRootManager(companyId)
|
|
1161
|
+
: null;
|
|
1162
|
+
const created = await agentSvc.create(companyId, {
|
|
1163
|
+
...definitionPatch(definition, resolvedInput),
|
|
1164
|
+
status: definition.defaultStatus ?? "idle",
|
|
1165
|
+
pauseReason: definition.defaultStatus === "paused" ? "Built-in Reflection Coach is disabled until explicitly configured." : null,
|
|
1166
|
+
pausedAt: definition.defaultStatus === "paused" ? new Date() : null,
|
|
1167
|
+
reportsTo,
|
|
1168
|
+
metadata: builtInMetadata(definition),
|
|
1169
|
+
runtimeConfig: {},
|
|
1170
|
+
permissions: definition.defaultPermissions ?? {},
|
|
1171
|
+
spentMonthlyCents: 0,
|
|
1172
|
+
lastHeartbeatAt: null,
|
|
1173
|
+
}, { allowBuiltInAgentMetadata: true });
|
|
1174
|
+
await logActivity(db, {
|
|
1175
|
+
companyId,
|
|
1176
|
+
actorType: "system",
|
|
1177
|
+
actorId: "built-in-agents",
|
|
1178
|
+
action: "built_in_agent.provisioned",
|
|
1179
|
+
entityType: "agent",
|
|
1180
|
+
entityId: created.id,
|
|
1181
|
+
details: {
|
|
1182
|
+
key: definition.key,
|
|
1183
|
+
featureKeys: definition.featureKeys,
|
|
1184
|
+
status: deriveBuiltInAgentStatus(created),
|
|
1185
|
+
},
|
|
1186
|
+
});
|
|
1187
|
+
await ensureBuiltInAgentDefaultGrants(created, definition);
|
|
1188
|
+
const resources = await reconcileBundleResources(created, definition, "reconcile");
|
|
1189
|
+
return state(definition, await agentSvc.getById(created.id), resources);
|
|
1190
|
+
}
|
|
1191
|
+
async function provision(companyId, key, input = {}, actor = {}) {
|
|
1192
|
+
const definition = requireBuiltInAgentDefinition(key);
|
|
1193
|
+
const company = await ensureCompany(companyId);
|
|
1194
|
+
if (!company.requireBoardApprovalForNewAgents) {
|
|
1195
|
+
return { state: await ensure(companyId, key, input), approval: null };
|
|
1196
|
+
}
|
|
1197
|
+
const existing = await findSingleAgent(companyId, definition);
|
|
1198
|
+
if (existing) {
|
|
1199
|
+
if (existing.status === "pending_approval") {
|
|
1200
|
+
if (hasProvisionSetupInput(input)) {
|
|
1201
|
+
throw conflict("Built-in agent setup is already pending board approval.", {
|
|
1202
|
+
code: "built_in_agent_pending_approval",
|
|
1203
|
+
key: definition.key,
|
|
1204
|
+
agentId: existing.id,
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
const approval = await approvalSvc.findOpenHireApprovalForAgent(companyId, existing.id);
|
|
1208
|
+
return {
|
|
1209
|
+
state: await state(definition, existing),
|
|
1210
|
+
approval: approval,
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
if (input.adapterType !== undefined || input.adapterConfig !== undefined) {
|
|
1214
|
+
throw conflict("Built-in agent adapter changes require board approval before they can be applied.", {
|
|
1215
|
+
code: "built_in_agent_reconfiguration_requires_approval",
|
|
1216
|
+
key: definition.key,
|
|
1217
|
+
agentId: existing.id,
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
return { state: await state(definition, existing), approval: null };
|
|
1221
|
+
}
|
|
1222
|
+
const reportsTo = definition.defaultManager === "single_root_agent"
|
|
1223
|
+
? await findSingleRootManager(companyId)
|
|
1224
|
+
: null;
|
|
1225
|
+
const pending = await agentSvc.create(companyId, {
|
|
1226
|
+
...definitionPatch(definition, input),
|
|
1227
|
+
status: "pending_approval",
|
|
1228
|
+
reportsTo,
|
|
1229
|
+
metadata: builtInMetadata(definition),
|
|
1230
|
+
runtimeConfig: {},
|
|
1231
|
+
permissions: definition.defaultPermissions ?? {},
|
|
1232
|
+
spentMonthlyCents: 0,
|
|
1233
|
+
lastHeartbeatAt: null,
|
|
1234
|
+
}, { allowBuiltInAgentMetadata: true });
|
|
1235
|
+
const approval = await approvalSvc.create(companyId, {
|
|
1236
|
+
type: "hire_agent",
|
|
1237
|
+
requestedByAgentId: actor.requestedByAgentId ?? null,
|
|
1238
|
+
requestedByUserId: actor.requestedByUserId ?? null,
|
|
1239
|
+
status: "pending",
|
|
1240
|
+
payload: {
|
|
1241
|
+
name: pending.name,
|
|
1242
|
+
role: pending.role,
|
|
1243
|
+
title: pending.title,
|
|
1244
|
+
icon: pending.icon,
|
|
1245
|
+
reportsTo: pending.reportsTo,
|
|
1246
|
+
capabilities: pending.capabilities,
|
|
1247
|
+
adapterType: pending.adapterType,
|
|
1248
|
+
adapterConfig: pending.adapterConfig,
|
|
1249
|
+
runtimeConfig: pending.runtimeConfig,
|
|
1250
|
+
permissions: pending.permissions,
|
|
1251
|
+
budgetMonthlyCents: pending.budgetMonthlyCents,
|
|
1252
|
+
metadata: pending.metadata,
|
|
1253
|
+
agentId: pending.id,
|
|
1254
|
+
sourceBuiltInAgentKey: definition.key,
|
|
1255
|
+
featureKeys: definition.featureKeys,
|
|
1256
|
+
},
|
|
1257
|
+
decisionNote: null,
|
|
1258
|
+
decidedByUserId: null,
|
|
1259
|
+
decidedAt: null,
|
|
1260
|
+
updatedAt: new Date(),
|
|
1261
|
+
});
|
|
1262
|
+
return { state: await state(definition, pending), approval };
|
|
1263
|
+
}
|
|
1264
|
+
async function list(companyId) {
|
|
1265
|
+
await ensureCompany(companyId);
|
|
1266
|
+
return Promise.all(DEFINITIONS.map(async (definition) => state(definition, await findSingleAgent(companyId, definition))));
|
|
1267
|
+
}
|
|
1268
|
+
async function reconcileDefinitionDefaults(companyId, key) {
|
|
1269
|
+
const definition = requireBuiltInAgentDefinition(key);
|
|
1270
|
+
await ensureCompany(companyId);
|
|
1271
|
+
const existing = await findSingleAgent(companyId, definition);
|
|
1272
|
+
if (!existing)
|
|
1273
|
+
return state(definition, null);
|
|
1274
|
+
const patch = {
|
|
1275
|
+
name: definition.displayName,
|
|
1276
|
+
role: definition.defaultRole,
|
|
1277
|
+
title: definition.defaultTitle ?? null,
|
|
1278
|
+
icon: definition.defaultIcon ?? null,
|
|
1279
|
+
capabilities: definition.shortPurpose,
|
|
1280
|
+
metadata: builtInMetadata(definition, existing.metadata),
|
|
1281
|
+
};
|
|
1282
|
+
const updated = await agentSvc.update(existing.id, patch, {
|
|
1283
|
+
allowBuiltInAgentMetadata: true,
|
|
1284
|
+
recordRevision: { source: "built-in-agent:reconcile-defaults" },
|
|
1285
|
+
});
|
|
1286
|
+
if (!updated)
|
|
1287
|
+
throw notFound("Built-in agent not found");
|
|
1288
|
+
await ensureBuiltInAgentDefaultGrants(updated, definition);
|
|
1289
|
+
return state(definition, updated);
|
|
1290
|
+
}
|
|
1291
|
+
async function reset(companyId, key, input = {}) {
|
|
1292
|
+
const definition = requireBuiltInAgentDefinition(key);
|
|
1293
|
+
const resetAgentDefaults = !input.resources || input.resources.includes("agent");
|
|
1294
|
+
const current = resetAgentDefaults
|
|
1295
|
+
? await reconcileDefinitionDefaults(companyId, key)
|
|
1296
|
+
: await get(companyId, key);
|
|
1297
|
+
if (!current.agent || !definition.bundle)
|
|
1298
|
+
return current;
|
|
1299
|
+
const selectedBundleResources = input.resources?.filter((resource) => resource !== "agent");
|
|
1300
|
+
const resources = await reconcileBundleResources(current.agent, definition, "reset", input.resources ? selectedBundleResources ?? [] : undefined);
|
|
1301
|
+
return state(definition, await agentSvc.getById(current.agent.id), resources);
|
|
1302
|
+
}
|
|
1303
|
+
async function setRoutineSchedule(companyId, key, routineKey, enabled, actor = {}) {
|
|
1304
|
+
const { definition, agent, routine, schedule } = await requireBundleRoutine(companyId, key, routineKey);
|
|
1305
|
+
if (!schedule)
|
|
1306
|
+
throw notFound("Built-in routine schedule not found");
|
|
1307
|
+
if (enabled) {
|
|
1308
|
+
await ensureBuiltInAgentAssignable(agent);
|
|
1309
|
+
await routineSvc.update(routine.id, { status: "active" }, actor);
|
|
1310
|
+
await routineSvc.updateTrigger(schedule.id, { enabled: true }, actor);
|
|
1311
|
+
}
|
|
1312
|
+
else {
|
|
1313
|
+
await routineSvc.updateTrigger(schedule.id, { enabled: false }, actor);
|
|
1314
|
+
await routineSvc.update(routine.id, { status: "paused" }, actor);
|
|
1315
|
+
}
|
|
1316
|
+
return state(definition, await agentSvc.getById(agent.id));
|
|
1317
|
+
}
|
|
1318
|
+
async function runRoutine(companyId, key, routineKey, actor = {}) {
|
|
1319
|
+
const { agent, routine } = await requireBundleRoutine(companyId, key, routineKey);
|
|
1320
|
+
await ensureBuiltInAgentAssignable(agent);
|
|
1321
|
+
return routineSvc.runRoutine(routine.id, { source: "manual" }, { actor });
|
|
1322
|
+
}
|
|
1323
|
+
async function requireBuiltInAgent(companyId, key) {
|
|
1324
|
+
const current = await get(companyId, key);
|
|
1325
|
+
if (!current.agent)
|
|
1326
|
+
throw builtInAgentNotConfiguredError(current);
|
|
1327
|
+
if (current.status === "ready") {
|
|
1328
|
+
return { definition: current.definition, agent: current.agent, warning: null };
|
|
1329
|
+
}
|
|
1330
|
+
if (current.status === "paused") {
|
|
1331
|
+
return {
|
|
1332
|
+
definition: current.definition,
|
|
1333
|
+
agent: current.agent,
|
|
1334
|
+
warning: {
|
|
1335
|
+
code: "built_in_agent_paused",
|
|
1336
|
+
key: current.definition.key,
|
|
1337
|
+
agentId: current.agent.id,
|
|
1338
|
+
message: `Built-in agent ${current.definition.key} is paused; scheduled/background work should be skipped.`,
|
|
1339
|
+
pauseReason: current.pauseReason,
|
|
1340
|
+
},
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
throw builtInAgentNotConfiguredError(current);
|
|
1344
|
+
}
|
|
1345
|
+
async function autoProvisionBundledAgents(companyId) {
|
|
1346
|
+
const company = await ensureCompany(companyId);
|
|
1347
|
+
let autoEnsured = 0;
|
|
1348
|
+
let pendingApprovals = 0;
|
|
1349
|
+
for (const definition of DEFINITIONS.filter((entry) => entry.bundle)) {
|
|
1350
|
+
if (company.requireBoardApprovalForNewAgents) {
|
|
1351
|
+
const result = await provision(companyId, definition.key);
|
|
1352
|
+
if (result.approval)
|
|
1353
|
+
pendingApprovals += 1;
|
|
1354
|
+
}
|
|
1355
|
+
else {
|
|
1356
|
+
await ensure(companyId, definition.key);
|
|
1357
|
+
}
|
|
1358
|
+
autoEnsured += 1;
|
|
1359
|
+
}
|
|
1360
|
+
const defaultGrantsEnsured = await ensureCompanyDefaultAgentGrants(companyId);
|
|
1361
|
+
return { autoEnsured, pendingApprovals, defaultGrantsEnsured };
|
|
1362
|
+
}
|
|
1363
|
+
return {
|
|
1364
|
+
definitions: listBuiltInAgentDefinitions,
|
|
1365
|
+
get,
|
|
1366
|
+
ensure,
|
|
1367
|
+
provision,
|
|
1368
|
+
list,
|
|
1369
|
+
reset,
|
|
1370
|
+
enableRoutineSchedule: (companyId, key, routineKey, actor) => setRoutineSchedule(companyId, key, routineKey, true, actor),
|
|
1371
|
+
disableRoutineSchedule: (companyId, key, routineKey, actor) => setRoutineSchedule(companyId, key, routineKey, false, actor),
|
|
1372
|
+
runRoutine,
|
|
1373
|
+
requireBuiltInAgent,
|
|
1374
|
+
autoProvisionBundledAgents,
|
|
1375
|
+
ensureCompanyDefaultAgentGrants,
|
|
1376
|
+
reconcileDefinitionDefaults,
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
export async function reconcileBuiltInAgentsOnStartup(db) {
|
|
1380
|
+
const svc = builtInAgentService(db);
|
|
1381
|
+
const companyRows = await db
|
|
1382
|
+
.select({ id: companies.id })
|
|
1383
|
+
.from(companies);
|
|
1384
|
+
let autoEnsured = 0;
|
|
1385
|
+
let pendingApprovals = 0;
|
|
1386
|
+
let defaultGrantsEnsured = 0;
|
|
1387
|
+
for (const company of companyRows) {
|
|
1388
|
+
const result = await svc.autoProvisionBundledAgents(company.id);
|
|
1389
|
+
autoEnsured += result.autoEnsured;
|
|
1390
|
+
pendingApprovals += result.pendingApprovals;
|
|
1391
|
+
defaultGrantsEnsured += result.defaultGrantsEnsured;
|
|
1392
|
+
}
|
|
1393
|
+
const rows = await db
|
|
1394
|
+
.select({
|
|
1395
|
+
companyId: agents.companyId,
|
|
1396
|
+
metadata: agents.metadata,
|
|
1397
|
+
status: agents.status,
|
|
1398
|
+
})
|
|
1399
|
+
.from(agents)
|
|
1400
|
+
.where(ne(agents.status, "terminated"));
|
|
1401
|
+
const seen = new Set();
|
|
1402
|
+
let scanned = 0;
|
|
1403
|
+
let reconciled = 0;
|
|
1404
|
+
let unknown = 0;
|
|
1405
|
+
let duplicates = 0;
|
|
1406
|
+
for (const row of rows) {
|
|
1407
|
+
const marker = readBuiltInAgentMarker(row.metadata);
|
|
1408
|
+
if (!marker)
|
|
1409
|
+
continue;
|
|
1410
|
+
scanned += 1;
|
|
1411
|
+
if (!getBuiltInAgentDefinition(marker.key)) {
|
|
1412
|
+
unknown += 1;
|
|
1413
|
+
continue;
|
|
1414
|
+
}
|
|
1415
|
+
const instanceKey = `${row.companyId}:${marker.key}`;
|
|
1416
|
+
if (seen.has(instanceKey)) {
|
|
1417
|
+
duplicates += 1;
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1420
|
+
seen.add(instanceKey);
|
|
1421
|
+
await svc.reconcileDefinitionDefaults(row.companyId, marker.key);
|
|
1422
|
+
reconciled += 1;
|
|
1423
|
+
}
|
|
1424
|
+
return { scanned, reconciled, unknown, duplicates, autoEnsured, pendingApprovals, defaultGrantsEnsured };
|
|
1425
|
+
}
|
|
1426
|
+
//# sourceMappingURL=built-in-agents.js.map
|