spine-framework 0.4.3 → 0.5.0-rc.4
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/.env.example +13 -3
- package/.framework/cli/commands/bootstrap.ts +392 -0
- package/.framework/cli/commands/dev.ts +91 -218
- package/.framework/cli/commands/doctor.ts +132 -26
- package/.framework/cli/commands/generate.ts +38 -298
- package/.framework/cli/commands/init.ts +20 -1
- package/.framework/cli/commands/migrate.ts +36 -30
- package/.framework/cli/commands/migrations.ts +16 -56
- package/.framework/cli/commands/upgrade.ts +35 -0
- package/.framework/cli/commands/validate-schema.ts +147 -0
- package/.framework/cli/context.ts +223 -110
- package/.framework/cli/index.ts +6 -0
- package/.framework/cli/lib/project-files.ts +241 -1
- package/.framework/functions/_shared/agent-runner.ts +1000 -81
- package/.framework/functions/_shared/cil.ts +2 -1
- package/.framework/functions/_shared/db.ts +3 -6
- package/.framework/functions/_shared/hash-api-key.ts +183 -79
- package/.framework/functions/_shared/kb.ts +61 -7
- package/.framework/functions/_shared/logging.ts +562 -224
- package/.framework/functions/_shared/message-sequence.ts +53 -0
- package/.framework/functions/_shared/middleware.ts +47 -44
- package/.framework/functions/_shared/pipeline-runner.ts +150 -37
- package/.framework/functions/_shared/principal.ts +9 -6
- package/.framework/functions/_shared/trigger-engine.ts +149 -40
- package/.framework/functions/admin-data.ts +48 -31
- package/.framework/functions/ai-agents.ts +103 -33
- package/.framework/functions/api-keys.ts +301 -122
- package/.framework/functions/apps.ts +43 -26
- package/.framework/functions/cil-ingest.ts +48 -15
- package/.framework/functions/debug-auth.ts +14 -8
- package/.framework/functions/deliveries.ts +39 -12
- package/.framework/functions/embeddings.ts +145 -76
- package/.framework/functions/integration-outbound.ts +67 -27
- package/.framework/functions/integrations.ts +254 -127
- package/.framework/functions/logs.ts +273 -133
- package/.framework/functions/observability.ts +277 -147
- package/.framework/functions/pipeline-executions.ts +1 -1
- package/.framework/functions/pipeline-runner-background.ts +120 -0
- package/.framework/functions/pipelines.ts +14 -9
- package/.framework/functions/prompt-configs.ts +7 -4
- package/.framework/functions/roles.ts +8 -5
- package/.framework/functions/security.ts +30 -17
- package/.framework/functions/system-cron.ts +250 -128
- package/.framework/functions/tests.ts +7 -6
- package/.framework/functions/timers.ts +310 -107
- package/.framework/functions/trigger-scheduler.ts +65 -5
- package/.framework/functions/triggers.ts +28 -13
- package/.framework/functions/types.ts +13 -10
- package/.framework/migrations/064_episode_leases.sql +196 -0
- package/.framework/migrations/065_execution_tables_updated_at.sql +20 -0
- package/.framework/migrations/066_episode_steal_thread_merge.sql +148 -0
- package/.framework/migrations/067_episode_lease_stale_steal.sql +93 -0
- package/.framework/migrations/068_cron_schedule_timer_rpcs.sql +251 -0
- package/.framework/migrations/069_log_stats_window.sql +54 -0
- package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
- package/.framework/migrations/071_timer_interval_keys.sql +96 -0
- package/.framework/migrations/072_slug_autofill.sql +77 -0
- package/.framework/migrations/073_seed_member_roles.sql +26 -0
- package/.framework/schemas/spine.config.schema.json +62 -0
- package/.framework/src/App.tsx +3 -1
- package/.framework/src/apps/admin/index.tsx +1141 -775
- package/.framework/src/components/ErrorBoundary.tsx +136 -0
- package/.framework/src/components/admin/AdminListPage.tsx +81 -73
- package/.framework/src/components/admin/AdminSidebar.tsx +92 -81
- package/.framework/src/components/admin/EntitySelect.tsx +181 -0
- package/.framework/src/components/admin/PageInstructions.tsx +86 -127
- package/.framework/src/components/app-shell/GenericAppShell.tsx +3 -1
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
- package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
- package/.framework/src/components/auth/TurnstileWidget.tsx +9 -6
- package/.framework/src/components/kb/KBArticleEditor.tsx +49 -6
- package/.framework/src/components/layout/Layout.tsx +4 -2
- package/.framework/src/components/layout/Sidebar.tsx +304 -179
- package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
- package/.framework/src/components/runtime/DataHeader.tsx +96 -48
- package/.framework/src/components/runtime/DataListPage.tsx +3 -26
- package/.framework/src/components/runtime/DataStats.tsx +10 -10
- package/.framework/src/components/runtime/DataTable.tsx +12 -10
- package/.framework/src/components/ui/sheet.tsx +24 -26
- package/.framework/src/components/ui/textarea.tsx +74 -48
- package/.framework/src/hooks/useBranding.ts +47 -0
- package/.framework/src/hooks/useEntityList.ts +12 -9
- package/.framework/src/hooks/useListSchema.ts +108 -58
- package/.framework/src/instructions/README.md +57 -0
- package/.framework/src/instructions/ai-agents.md +69 -0
- package/.framework/src/instructions/alerts.md +80 -0
- package/.framework/src/instructions/api-keys.md +87 -0
- package/.framework/src/instructions/apps.md +77 -0
- package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
- package/.framework/src/instructions/concepts/apps-and-renderers.md +162 -0
- package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
- package/.framework/src/instructions/concepts/automation.md +186 -0
- package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
- package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
- package/.framework/src/instructions/concepts/design-schema.md +152 -0
- package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
- package/.framework/src/instructions/concepts/observability.md +116 -0
- package/.framework/src/instructions/concepts/permissions.md +150 -0
- package/.framework/src/instructions/concepts/runtime-records.md +111 -0
- package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
- package/.framework/src/instructions/concepts/spine-way.md +172 -0
- package/.framework/src/instructions/deliveries.md +59 -0
- package/.framework/src/instructions/guide/00-orientation.md +106 -0
- package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
- package/.framework/src/instructions/guide/02-project-map.md +147 -0
- package/.framework/src/instructions/guide/03-domain-model.md +223 -0
- package/.framework/src/instructions/guide/04-first-app.md +227 -0
- package/.framework/src/instructions/guide/05-glossary.md +183 -0
- package/.framework/src/instructions/integrations.md +96 -0
- package/.framework/src/instructions/internal/cil-markers.md +83 -0
- package/.framework/src/instructions/invites.md +60 -0
- package/.framework/src/instructions/kb.md +80 -0
- package/.framework/src/instructions/logs.md +77 -0
- package/.framework/src/instructions/observability.md +61 -0
- package/.framework/src/instructions/operations/deployment.md +115 -0
- package/.framework/src/instructions/operations/migrations.md +125 -0
- package/.framework/src/instructions/operations/security-checklist.md +148 -0
- package/.framework/src/instructions/operations/troubleshooting.md +170 -0
- package/.framework/src/instructions/operations/upgrade.md +116 -0
- package/.framework/src/instructions/pipeline-executions.md +62 -0
- package/.framework/src/instructions/pipelines.md +78 -0
- package/.framework/src/instructions/prompts.md +95 -0
- package/.framework/src/instructions/reference/api/admin-data.md +162 -0
- package/.framework/src/instructions/reference/api/auth.md +113 -0
- package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
- package/.framework/src/instructions/reference/app-manifest.md +150 -0
- package/.framework/src/instructions/reference/cli.md +124 -0
- package/.framework/src/instructions/reference/database.md +132 -0
- package/.framework/src/instructions/reference/design-schema.md +280 -0
- package/.framework/src/instructions/reference/env-vars.md +133 -0
- package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
- package/.framework/src/instructions/reference/functions/admin-data.md +195 -0
- package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
- package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
- package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
- package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
- package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
- package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
- package/.framework/src/instructions/reference/functions/apps.md +140 -0
- package/.framework/src/instructions/reference/functions/auth.md +99 -0
- package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
- package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
- package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
- package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
- package/.framework/src/instructions/reference/functions/index.md +103 -0
- package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
- package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
- package/.framework/src/instructions/reference/functions/integrations.md +130 -0
- package/.framework/src/instructions/reference/functions/invites.md +182 -0
- package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
- package/.framework/src/instructions/reference/functions/kb.md +166 -0
- package/.framework/src/instructions/reference/functions/logs.md +141 -0
- package/.framework/src/instructions/reference/functions/observability.md +105 -0
- package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
- package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
- package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
- package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
- package/.framework/src/instructions/reference/functions/roles.md +121 -0
- package/.framework/src/instructions/reference/functions/security.md +140 -0
- package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
- package/.framework/src/instructions/reference/functions/system.md +106 -0
- package/.framework/src/instructions/reference/functions/tests.md +97 -0
- package/.framework/src/instructions/reference/functions/timers.md +117 -0
- package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
- package/.framework/src/instructions/reference/functions/triggers.md +140 -0
- package/.framework/src/instructions/reference/functions/types.md +146 -0
- package/.framework/src/instructions/reference/seeds.md +126 -0
- package/.framework/src/instructions/reference/shared-modules.md +127 -0
- package/.framework/src/instructions/reference/spine-config.md +114 -0
- package/.framework/src/instructions/roles.md +80 -0
- package/.framework/src/instructions/runtime-detail.md +70 -0
- package/.framework/src/instructions/runtime-list.md +77 -0
- package/.framework/src/instructions/security.md +67 -0
- package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
- package/.framework/src/instructions/tasks/add-a-role.md +96 -0
- package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
- package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
- package/.framework/src/instructions/tasks/add-a-type.md +151 -0
- package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
- package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
- package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
- package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
- package/.framework/src/instructions/tasks/package-and-install-an-app.md +127 -0
- package/.framework/src/instructions/tasks/test-your-code.md +108 -0
- package/.framework/src/instructions/tasks/write-a-function.md +132 -0
- package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
- package/.framework/src/instructions/testing.md +59 -0
- package/.framework/src/instructions/timers.md +82 -0
- package/.framework/src/instructions/triggers.md +69 -0
- package/.framework/src/instructions/types.md +93 -0
- package/.framework/src/lib/branding.ts +128 -0
- package/.framework/src/pages/NoAppPage.tsx +3 -1
- package/.framework/src/pages/NotFoundPage.tsx +62 -31
- package/.framework/src/pages/SetupPage.tsx +5 -2
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
- package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
- package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
- package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
- package/.framework/src/pages/admin/AppsPage.tsx +104 -66
- package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
- package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
- package/.framework/src/pages/admin/LogsPage.tsx +144 -76
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
- package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
- package/.framework/src/pages/admin/RolesPage.tsx +86 -43
- package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
- package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
- package/.framework/src/pages/admin/TimersPage.tsx +90 -62
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
- package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
- package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
- package/.framework/src/pages/admin/TypesPage.tsx +90 -48
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
- package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
- package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
- package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +3 -1
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +3 -1
- package/.framework/src/pages/auth/LoginPage.tsx +4 -2
- package/.framework/src/pages/auth/RegisterPage.tsx +3 -1
- package/.framework/templates/agent/AGENTS.md +150 -0
- package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
- package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
- package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
- package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
- package/.framework/templates/agent/skills/spine-install-app/SKILL.md +72 -0
- package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
- package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
- package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
- package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -0
- package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
- package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
- package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
- package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
- package/.framework/templates/project.json +5 -1
- package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
- package/.framework/tests/unit/agent-files.test.ts +355 -0
- package/.framework/tests/unit/agent-runner.test.ts +496 -47
- package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
- package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
- package/.framework/tests/unit/bootstrap.test.ts +242 -0
- package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
- package/.framework/tests/unit/debug-auth.test.ts +38 -0
- package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
- package/.framework/tests/unit/episode-lease.test.ts +695 -0
- package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
- package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
- package/.framework/tests/unit/kb-ingest-lease.test.ts +19 -0
- package/.framework/tests/unit/logging-app-id.test.ts +75 -0
- package/.framework/tests/unit/pipeline-runner-background.test.ts +120 -0
- package/.framework/tests/unit/pipeline-runner.test.ts +153 -1
- package/.framework/tests/unit/principal-cache.test.ts +15 -0
- package/.framework/tests/unit/system-context-denial.test.ts +145 -0
- package/.framework/tests/unit/system-cron.test.ts +240 -0
- package/.framework/tests/unit/timers.test.ts +159 -0
- package/.framework/tests/unit/trigger-engine.test.ts +278 -91
- package/.framework/tests/unit/trigger-scheduler.test.ts +78 -0
- package/README.md +125 -166
- package/config/tsconfig.cli.json +2 -2
- package/netlify.toml +5 -0
- package/package.json +15 -4
- package/templates/project/package-lock.json +2 -2
- package/.framework/docs/admin-routes.md +0 -76
- package/.framework/docs/api-docs-progress.md +0 -38
- package/.framework/docs/api-governance.md +0 -146
- package/.framework/docs/api-testing-results.md +0 -212
- package/.framework/docs/assembly-launch-guide.md +0 -138
- package/.framework/docs/audit-results.md +0 -590
- package/.framework/docs/db-api-inventory.md +0 -95
- package/.framework/docs/gap-remediation-backlog.md +0 -103
- package/.framework/docs/ui-adoption-verification.md +0 -111
- package/.framework/docs/ui-api-coverage.md +0 -84
- package/.framework/docs/v2-compatibility-audit.md +0 -228
- package/.framework/mcp/index.ts +0 -133
- package/.framework/mcp/load-env.ts +0 -60
- package/.framework/mcp/shared/app-manifest.ts +0 -275
- package/.framework/mcp/shared/db.ts +0 -477
- package/.framework/mcp/shared/kb.ts +0 -118
- package/.framework/mcp/tools/architect.ts +0 -431
- package/.framework/mcp/tools/cil/context.ts +0 -345
- package/.framework/mcp/tools/cil/graph.ts +0 -242
- package/.framework/mcp/tools/cil/ingest.ts +0 -1217
- package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
- package/.framework/mcp/tools/cil/pipeline.ts +0 -767
- package/.framework/mcp/tools/cil/project.ts +0 -791
- package/.framework/mcp/tools/cil/retrieval.ts +0 -336
- package/.framework/mcp/tools/cil/search-core.ts +0 -454
- package/.framework/mcp/tools/cil/search.ts +0 -97
- package/.framework/mcp/tools/cil/suggest.ts +0 -186
- package/.framework/mcp/tools/cil/validate.ts +0 -1369
- package/.framework/mcp/tools/kb/delete.ts +0 -139
- package/.framework/mcp/tools/kb/index.ts +0 -52
- package/.framework/mcp/tools/kb/ingest.ts +0 -84
- package/.framework/mcp/tools/kb/list-types.ts +0 -102
- package/.framework/mcp/tools/kb/publish.ts +0 -100
- package/.framework/mcp/tools/kb/reindex.ts +0 -86
- package/.framework/mcp/tools/kb/revoke.ts +0 -85
- package/.framework/mcp/tools/kb/search.ts +0 -101
- package/.framework/mcp/tools/kb/upsert.ts +0 -125
- package/.framework/mcp/tools/observability.ts +0 -510
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/admin-data.ts"]
|
|
1
2
|
/**
|
|
2
3
|
* @module admin-data
|
|
3
4
|
* @audience internal
|
|
@@ -13,7 +14,6 @@
|
|
|
13
14
|
*
|
|
14
15
|
* @cil-generated
|
|
15
16
|
*/
|
|
16
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/admin-data.ts"]
|
|
17
17
|
// CIL[DOC-MACRO purpose="This module handles administrative data operations within the system, providing essential functionalities for managing records and permissions."]
|
|
18
18
|
// CIL[DOC-RESPONSIBILITY responsibility="This module handles administrative data operations within the system, providing essential functionalities for managing records and permissions. It serves as an API handler for various administrative actions, ensuring that only authorized users can perform updates and access sensitive data. INVARIANT: Only users with system admin privileges can execute these operations."]
|
|
19
19
|
// CIL[DOC-CONTEXT module="admin-data" layer="app-specific" related_files="middleware.ts (provides request handling logic).,permissions.ts (manages access control and validation).,db.ts (interfaces with the database for data operations).,principal.ts (determines user roles and permissions)."]
|
|
@@ -62,7 +62,6 @@ import { checkTypeSlugRateLimit } from './_shared/security'
|
|
|
62
62
|
* @stability stable
|
|
63
63
|
* @cil-generated
|
|
64
64
|
*/
|
|
65
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:permissions_all:constant" type="constant" identity="PERMISSIONS_ALL" parent="~/.framework/functions/admin-data.ts"]
|
|
66
65
|
// CIL[DOC-MACRO purpose="PERMISSIONS_ALL constant"]
|
|
67
66
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the PERMISSIONS_ALL constant."]
|
|
68
67
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -70,11 +69,12 @@ import { checkTypeSlugRateLimit } from './_shared/security'
|
|
|
70
69
|
// CIL[DOC-MICRO logic_summary="Implements the PERMISSIONS_ALL constant." notable_decisions="[]"]
|
|
71
70
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
72
71
|
// CIL[DOC-STABILITY stability="stable"]
|
|
72
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:PERMISSIONS_ALL:constant" type="constant" identity="PERMISSIONS_ALL" parent="~/.framework/functions/admin-data.ts"]
|
|
73
73
|
const PERMISSIONS_ALL = {
|
|
74
74
|
record_permissions: { all: ['create', 'read', 'update', 'delete'] },
|
|
75
75
|
fields: {}
|
|
76
76
|
}
|
|
77
|
-
// CIL[END stable_id="~/.framework/functions/admin-data.ts:
|
|
77
|
+
// CIL[END stable_id="~/.framework/functions/admin-data.ts:PERMISSIONS_ALL:constant"]
|
|
78
78
|
// CIL[DOC-VECTOR type="context" content="purpose='PERMISSIONS_ALL defines a comprehensive set of permissions for record management, including create, read, update, and delete actions.'; No verified external callers" status="ready"]
|
|
79
79
|
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only" status="ready"]
|
|
80
80
|
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
|
|
@@ -96,7 +96,6 @@ const PERMISSIONS_ALL = {
|
|
|
96
96
|
* @stability stable
|
|
97
97
|
* @cil-generated
|
|
98
98
|
*/
|
|
99
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:valid_entities:constant" type="constant" identity="VALID_ENTITIES" parent="~/.framework/functions/admin-data.ts"]
|
|
100
99
|
// CIL[DOC-MACRO purpose="VALID_ENTITIES constant"]
|
|
101
100
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the VALID_ENTITIES constant."]
|
|
102
101
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -104,8 +103,9 @@ const PERMISSIONS_ALL = {
|
|
|
104
103
|
// CIL[DOC-MICRO logic_summary="Implements the VALID_ENTITIES constant." notable_decisions="[]"]
|
|
105
104
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
106
105
|
// CIL[DOC-STABILITY stability="stable"]
|
|
106
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:VALID_ENTITIES:constant" type="constant" identity="VALID_ENTITIES" parent="~/.framework/functions/admin-data.ts"]
|
|
107
107
|
const VALID_ENTITIES = ['accounts', 'people', 'items', 'threads', 'messages', 'links', 'attachments', 'watchers', 'item_progress', 'logs', 'test_runs', 'observability', 'test_cases', 'types', 'link_types', 'ai_agents', 'prompt_configs']
|
|
108
|
-
// CIL[END stable_id="~/.framework/functions/admin-data.ts:
|
|
108
|
+
// CIL[END stable_id="~/.framework/functions/admin-data.ts:VALID_ENTITIES:constant"]
|
|
109
109
|
// CIL[DOC-MACRO purpose="VALID_ENTITIES constant"]
|
|
110
110
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the VALID_ENTITIES constant."]
|
|
111
111
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -134,7 +134,6 @@ const VALID_ENTITIES = ['accounts', 'people', 'items', 'threads', 'messages', 'l
|
|
|
134
134
|
* @stability stable
|
|
135
135
|
* @cil-generated
|
|
136
136
|
*/
|
|
137
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:raw_entities:constant" type="constant" identity="RAW_ENTITIES" parent="~/.framework/functions/admin-data.ts"]
|
|
138
137
|
// CIL[DOC-MACRO purpose="RAW_ENTITIES constant"]
|
|
139
138
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the RAW_ENTITIES constant."]
|
|
140
139
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -142,11 +141,14 @@ const VALID_ENTITIES = ['accounts', 'people', 'items', 'threads', 'messages', 'l
|
|
|
142
141
|
// CIL[DOC-MICRO logic_summary="Implements the RAW_ENTITIES constant." notable_decisions="[]"]
|
|
143
142
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
144
143
|
// CIL[DOC-STABILITY stability="stable"]
|
|
144
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:RAW_ENTITIES:constant" type="constant" identity="RAW_ENTITIES" parent="~/.framework/functions/admin-data.ts"]
|
|
145
145
|
const RAW_ENTITIES = ['logs', 'test_runs', 'observability', 'test_cases']
|
|
146
|
+
// CIL[END stable_id="~/.framework/functions/admin-data.ts:RAW_ENTITIES:constant"]
|
|
146
147
|
// Entities with no created_by/updated_by columns — audit stamps must be
|
|
147
148
|
// omitted or writes fail with schema-cache errors.
|
|
149
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:UNAUDITED_ENTITIES:constant" type="constant" identity="UNAUDITED_ENTITIES" parent="~/.framework/functions/admin-data.ts"]
|
|
148
150
|
const UNAUDITED_ENTITIES = ['types', 'link_types']
|
|
149
|
-
// CIL[END stable_id="~/.framework/functions/admin-data.ts:
|
|
151
|
+
// CIL[END stable_id="~/.framework/functions/admin-data.ts:UNAUDITED_ENTITIES:constant"]
|
|
150
152
|
// CIL[DOC-MACRO purpose="RAW_ENTITIES constant"]
|
|
151
153
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the RAW_ENTITIES constant."]
|
|
152
154
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -175,7 +177,6 @@ const UNAUDITED_ENTITIES = ['types', 'link_types']
|
|
|
175
177
|
* @stability stable
|
|
176
178
|
* @cil-generated
|
|
177
179
|
*/
|
|
178
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:entity_to_kind:constant" type="constant" identity="ENTITY_TO_KIND" parent="~/.framework/functions/admin-data.ts"]
|
|
179
180
|
// CIL[DOC-MACRO purpose="ENTITY_TO_KIND constant"]
|
|
180
181
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the ENTITY_TO_KIND constant."]
|
|
181
182
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -183,6 +184,7 @@ const UNAUDITED_ENTITIES = ['types', 'link_types']
|
|
|
183
184
|
// CIL[DOC-MICRO logic_summary="Implements the ENTITY_TO_KIND constant." notable_decisions="[]"]
|
|
184
185
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
185
186
|
// CIL[DOC-STABILITY stability="stable"]
|
|
187
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:ENTITY_TO_KIND:constant" type="constant" identity="ENTITY_TO_KIND" parent="~/.framework/functions/admin-data.ts"]
|
|
186
188
|
const ENTITY_TO_KIND: Record<string, string> = {
|
|
187
189
|
accounts: 'account',
|
|
188
190
|
people: 'person',
|
|
@@ -194,7 +196,7 @@ const ENTITY_TO_KIND: Record<string, string> = {
|
|
|
194
196
|
watchers: 'watcher',
|
|
195
197
|
item_progress: 'item_progress'
|
|
196
198
|
}
|
|
197
|
-
// CIL[END stable_id="~/.framework/functions/admin-data.ts:
|
|
199
|
+
// CIL[END stable_id="~/.framework/functions/admin-data.ts:ENTITY_TO_KIND:constant"]
|
|
198
200
|
// CIL[DOC-VECTOR type="context" content="purpose='ENTITY_TO_KIND is a mapping of entity names to their corresponding kind identifiers.'; No verified external callers" status="ready"]
|
|
199
201
|
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only" status="ready"]
|
|
200
202
|
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
|
|
@@ -217,7 +219,6 @@ const ENTITY_TO_KIND: Record<string, string> = {
|
|
|
217
219
|
* @calls withAdminLogging, resolveTypeIds, getSearchField
|
|
218
220
|
* @cil-generated
|
|
219
221
|
*/
|
|
220
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:list:constant" type="constant" identity="list" parent="~/.framework/functions/admin-data.ts"]
|
|
221
222
|
// CIL[DOC-MACRO purpose="list constant"]
|
|
222
223
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the list constant."]
|
|
223
224
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -225,8 +226,9 @@ const ENTITY_TO_KIND: Record<string, string> = {
|
|
|
225
226
|
// CIL[DOC-MICRO logic_summary="Implements the list constant." notable_decisions="[]"]
|
|
226
227
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
227
228
|
// CIL[DOC-STABILITY stability="stable"]
|
|
229
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:list:constant" type="constant" identity="list" parent="~/.framework/functions/admin-data.ts"]
|
|
228
230
|
export const list = createHandler(async (ctx, _body) => {
|
|
229
|
-
const { entity, action, method, search, sort_field = 'created_at', sort_direction = 'desc', limit = 50, offset = 0, type_slug, type_slugs, view: viewSlug, flag_only, exclude_flag, ...filters } = ctx.query || {}
|
|
231
|
+
const { entity, action, method, search, sort_field = 'created_at', sort_direction = 'desc', limit = 50, offset = 0, type_slug, type_slugs, view: viewSlug, flag_only, exclude_flag, include_inactive, ...filters } = ctx.query || {}
|
|
230
232
|
|
|
231
233
|
return await withAdminLogging(
|
|
232
234
|
ctx,
|
|
@@ -292,6 +294,12 @@ export const list = createHandler(async (ctx, _body) => {
|
|
|
292
294
|
}
|
|
293
295
|
})
|
|
294
296
|
|
|
297
|
+
// Soft-deleted rows are hidden by default — pass is_active=false or
|
|
298
|
+
// include_inactive=true to see them.
|
|
299
|
+
if (filters.is_active === undefined && include_inactive !== 'true') {
|
|
300
|
+
query = query.eq('is_active', true)
|
|
301
|
+
}
|
|
302
|
+
|
|
295
303
|
// Generic record-flag filters on the row's data jsonb. flag_only=<field>
|
|
296
304
|
// returns only rows where data->>field is 'true'; exclude_flag=<field>
|
|
297
305
|
// hides them (null counts as unset). Flag fields are stamped server-side
|
|
@@ -405,7 +413,6 @@ export const list = createHandler(async (ctx, _body) => {
|
|
|
405
413
|
* @errorHandling returns null on error during data fetching.
|
|
406
414
|
* @cil-generated
|
|
407
415
|
*/
|
|
408
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:attachlineage:function" type="function" identity="attachLineage" parent="~/.framework/functions/admin-data.ts"]
|
|
409
416
|
// CIL[DOC-MACRO purpose="attachLineage function"]
|
|
410
417
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the attachLineage function from type-declared lineage config."]
|
|
411
418
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -413,6 +420,7 @@ export const list = createHandler(async (ctx, _body) => {
|
|
|
413
420
|
// CIL[DOC-MICRO logic_summary="Reads functionality.lineage off the record's type design_schema; parents walk declared link_type then parent_fields (5-hop, visited-set cycle guard); children resolve via reverse link_type edges plus per-child-type data field lookups." notable_decisions="['link_type queries are guarded by the declared link_type, parent scan by declared parent_fields, child field lookups by declared children — a type with no lineage block attaches empty arrays with no link/data queries']"]
|
|
414
421
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
415
422
|
// CIL[DOC-STABILITY stability="stable"]
|
|
423
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:attachLineage:function" type="function" identity="attachLineage" parent="~/.framework/functions/admin-data.ts"]
|
|
416
424
|
async function attachLineage(record: any, ctx: any): Promise<void> {
|
|
417
425
|
// Lineage is declared per item type in design_schema.functionality.lineage:
|
|
418
426
|
// { parent_fields: string[], link_type: string, children: { [childTypeSlug]: field } }
|
|
@@ -516,7 +524,7 @@ async function attachLineage(record: any, ctx: any): Promise<void> {
|
|
|
516
524
|
record.parents = parents
|
|
517
525
|
record.children = children
|
|
518
526
|
}
|
|
519
|
-
// CIL[END stable_id="~/.framework/functions/admin-data.ts:
|
|
527
|
+
// CIL[END stable_id="~/.framework/functions/admin-data.ts:attachLineage:function"]
|
|
520
528
|
// CIL[DOC-VECTOR type="context" content="purpose='The attachLineage function retrieves and attaches parent and child records to a given record based on its lineage in a hierarchical structure.'; No verified external callers" status="ready"]
|
|
521
529
|
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only" status="ready"]
|
|
522
530
|
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
|
|
@@ -540,7 +548,6 @@ async function attachLineage(record: any, ctx: any): Promise<void> {
|
|
|
540
548
|
* @calls withAdminLogging, ctx.db.from, sanitizeRecordData, adminDb.from, attachLineage, projectMessageForCustomer
|
|
541
549
|
* @cil-generated
|
|
542
550
|
*/
|
|
543
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:get:constant" type="constant" identity="get" parent="~/.framework/functions/admin-data.ts"]
|
|
544
551
|
// CIL[DOC-MACRO purpose="get constant"]
|
|
545
552
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the get constant."]
|
|
546
553
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -548,6 +555,7 @@ async function attachLineage(record: any, ctx: any): Promise<void> {
|
|
|
548
555
|
// CIL[DOC-MICRO logic_summary="Implements the get constant." notable_decisions="[]"]
|
|
549
556
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
550
557
|
// CIL[DOC-STABILITY stability="stable"]
|
|
558
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:get:constant" type="constant" identity="get" parent="~/.framework/functions/admin-data.ts"]
|
|
551
559
|
export const get = createHandler(async (ctx, _body) => {
|
|
552
560
|
const { entity, id, view: viewSlug } = ctx.query || {}
|
|
553
561
|
const method = ctx.query?.method || 'GET'
|
|
@@ -639,7 +647,6 @@ export const get = createHandler(async (ctx, _body) => {
|
|
|
639
647
|
* @calls withAdminLogging, ctx.db.from, fireCreateTriggers, sanitizeRecordData
|
|
640
648
|
* @cil-generated
|
|
641
649
|
*/
|
|
642
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:create:constant" type="constant" identity="create" parent="~/.framework/functions/admin-data.ts"]
|
|
643
650
|
// CIL[DOC-MACRO purpose="create constant"]
|
|
644
651
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the create constant."]
|
|
645
652
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -647,6 +654,7 @@ export const get = createHandler(async (ctx, _body) => {
|
|
|
647
654
|
// CIL[DOC-MICRO logic_summary="Implements the create constant." notable_decisions="[]"]
|
|
648
655
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
649
656
|
// CIL[DOC-STABILITY stability="stable"]
|
|
657
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:create:constant" type="constant" identity="create" parent="~/.framework/functions/admin-data.ts"]
|
|
650
658
|
export const create = createHandler(async (ctx, body) => {
|
|
651
659
|
const entity = body?.entity || ctx.query?.entity
|
|
652
660
|
const type_slug = body?.type_slug
|
|
@@ -686,9 +694,14 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
686
694
|
if (entity === 'observability' && (!raw.metric_name || raw.metric_value === undefined)) { const e: any = new Error('metric_name and metric_value are required for observability'); e.statusCode = 400; throw e }
|
|
687
695
|
if (entity === 'test_cases' && (!raw.slug || !raw.name)) { const e: any = new Error('slug and name are required for test_cases'); e.statusCode = 400; throw e }
|
|
688
696
|
|
|
689
|
-
const
|
|
697
|
+
const rawInsertDb = (ctx.principal?.isInternal || isSystemAdmin(ctx.principal)) ? adminDb : ctx.db
|
|
698
|
+
const { data, error: err } = await rawInsertDb.from(entity).insert(raw).select().single()
|
|
690
699
|
if (err) throw err
|
|
691
|
-
|
|
700
|
+
// Await the trigger check: the heavy work already offloads to
|
|
701
|
+
// pipeline-runner-background, so this only adds eval + queue insert
|
|
702
|
+
// + dispatch. Detached post-response work is CPU-frozen on Netlify
|
|
703
|
+
// and silently dropped trigger fires in production.
|
|
704
|
+
await fireCreateTriggers(entity, data.id, raw, ctx).catch(console.error)
|
|
692
705
|
return await sanitizeRecordData(ctx, data, entity)
|
|
693
706
|
}
|
|
694
707
|
|
|
@@ -798,7 +811,9 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
798
811
|
throw e
|
|
799
812
|
}
|
|
800
813
|
|
|
801
|
-
|
|
814
|
+
// Function-side permission check already ran — write via service role.
|
|
815
|
+
// ctx.db is PostgREST `authenticated` for humans, which holds SELECT only.
|
|
816
|
+
const insertDb = adminDb
|
|
802
817
|
|
|
803
818
|
const { data, error: err } = await insertDb.from(entity)
|
|
804
819
|
.insert(dataToInsert)
|
|
@@ -808,7 +823,7 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
808
823
|
if (err) throw err
|
|
809
824
|
|
|
810
825
|
const entityData = { ...dataToInsert, id: data.id }
|
|
811
|
-
fireCreateTriggers(entity, data.id, entityData, ctx).catch(console.error)
|
|
826
|
+
await fireCreateTriggers(entity, data.id, entityData, ctx).catch(console.error)
|
|
812
827
|
|
|
813
828
|
return await sanitizeRecordData(ctx, data, entity)
|
|
814
829
|
}
|
|
@@ -837,7 +852,6 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
837
852
|
* @calls withAdminLogging, validateUpdatePermissions, ctx.db.from, fireUpdateTriggers, sanitizeRecordData
|
|
838
853
|
* @cil-generated
|
|
839
854
|
*/
|
|
840
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:update:constant" type="constant" identity="update" parent="~/.framework/functions/admin-data.ts"]
|
|
841
855
|
// CIL[DOC-MACRO purpose="update constant"]
|
|
842
856
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the update constant."]
|
|
843
857
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -845,6 +859,7 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
845
859
|
// CIL[DOC-MICRO logic_summary="Implements the update constant." notable_decisions="[]"]
|
|
846
860
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
847
861
|
// CIL[DOC-STABILITY stability="stable"]
|
|
862
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:update:constant" type="constant" identity="update" parent="~/.framework/functions/admin-data.ts"]
|
|
848
863
|
export const update = createHandler(async (ctx, body) => {
|
|
849
864
|
const { entity, id } = ctx.query || {}
|
|
850
865
|
const method = ctx.query?.method || 'PATCH'
|
|
@@ -906,7 +921,7 @@ export const update = createHandler(async (ctx, body) => {
|
|
|
906
921
|
updated_at: new Date().toISOString()
|
|
907
922
|
}
|
|
908
923
|
|
|
909
|
-
const { data, error: err } = await
|
|
924
|
+
const { data, error: err } = await adminDb.from(entity)
|
|
910
925
|
.update(dataToUpdate)
|
|
911
926
|
.eq('id', id)
|
|
912
927
|
.select()
|
|
@@ -915,7 +930,9 @@ export const update = createHandler(async (ctx, body) => {
|
|
|
915
930
|
if (err) throw err
|
|
916
931
|
|
|
917
932
|
const entityData = { ...data, ...dataToUpdate }
|
|
918
|
-
|
|
933
|
+
// Await the trigger check — see note in the create path. Detached
|
|
934
|
+
// post-response work is CPU-frozen on Netlify and drops trigger fires.
|
|
935
|
+
await fireUpdateTriggers(entity, id, entityData, ctx, existing).catch(console.error)
|
|
919
936
|
|
|
920
937
|
return await sanitizeRecordData(ctx, data, entity)
|
|
921
938
|
}
|
|
@@ -944,7 +961,6 @@ export const update = createHandler(async (ctx, body) => {
|
|
|
944
961
|
* @calls withAdminLogging, ctx.db.from, resolveFirstSurfacePermissions, entitySupportsSoftDelete, sanitizeRecordData
|
|
945
962
|
* @cil-generated
|
|
946
963
|
*/
|
|
947
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:remove:constant" type="constant" identity="remove" parent="~/.framework/functions/admin-data.ts"]
|
|
948
964
|
// CIL[DOC-MACRO purpose="remove constant"]
|
|
949
965
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the remove constant."]
|
|
950
966
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -952,6 +968,7 @@ export const update = createHandler(async (ctx, body) => {
|
|
|
952
968
|
// CIL[DOC-MICRO logic_summary="Implements the remove constant." notable_decisions="[]"]
|
|
953
969
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
954
970
|
// CIL[DOC-STABILITY stability="stable"]
|
|
971
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:remove:constant" type="constant" identity="remove" parent="~/.framework/functions/admin-data.ts"]
|
|
955
972
|
export const remove = createHandler(async (ctx, _body) => {
|
|
956
973
|
const { entity, id, soft = 'true' } = ctx.query || {}
|
|
957
974
|
const method = ctx.query?.method || 'DELETE'
|
|
@@ -1000,7 +1017,7 @@ export const remove = createHandler(async (ctx, _body) => {
|
|
|
1000
1017
|
const isSoftDelete = soft === 'true'
|
|
1001
1018
|
|
|
1002
1019
|
if (isSoftDelete && entitySupportsSoftDelete(entity)) {
|
|
1003
|
-
const { data, error: err } = await
|
|
1020
|
+
const { data, error: err } = await adminDb.from(entity)
|
|
1004
1021
|
.update({
|
|
1005
1022
|
is_active: false,
|
|
1006
1023
|
updated_by: ctx.principal?.type === 'human' ? ctx.principal.id : null,
|
|
@@ -1013,7 +1030,7 @@ export const remove = createHandler(async (ctx, _body) => {
|
|
|
1013
1030
|
if (err) throw err
|
|
1014
1031
|
return { deleted: true, soft: true, data: await sanitizeRecordData(ctx, data, entity) }
|
|
1015
1032
|
} else {
|
|
1016
|
-
const { error: err } = await
|
|
1033
|
+
const { error: err } = await adminDb.from(entity)
|
|
1017
1034
|
.delete()
|
|
1018
1035
|
.eq('id', id)
|
|
1019
1036
|
|
|
@@ -1047,7 +1064,6 @@ export const remove = createHandler(async (ctx, _body) => {
|
|
|
1047
1064
|
* @stability stable
|
|
1048
1065
|
* @cil-generated
|
|
1049
1066
|
*/
|
|
1050
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:getsearchfield:function" type="function" identity="getSearchField" parent="~/.framework/functions/admin-data.ts"]
|
|
1051
1067
|
// CIL[DOC-MACRO purpose="getSearchField function"]
|
|
1052
1068
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the getSearchField function."]
|
|
1053
1069
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -1055,6 +1071,7 @@ export const remove = createHandler(async (ctx, _body) => {
|
|
|
1055
1071
|
// CIL[DOC-MICRO logic_summary="Implements the getSearchField function." notable_decisions="[]"]
|
|
1056
1072
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
1057
1073
|
// CIL[DOC-STABILITY stability="stable"]
|
|
1074
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:getSearchField:function" type="function" identity="getSearchField" parent="~/.framework/functions/admin-data.ts"]
|
|
1058
1075
|
function getSearchField(entity: string): string {
|
|
1059
1076
|
const searchFields: Record<string, string> = {
|
|
1060
1077
|
accounts: 'display_name',
|
|
@@ -1073,7 +1090,7 @@ function getSearchField(entity: string): string {
|
|
|
1073
1090
|
}
|
|
1074
1091
|
return searchFields[entity] || 'id'
|
|
1075
1092
|
}
|
|
1076
|
-
// CIL[END stable_id="~/.framework/functions/admin-data.ts:
|
|
1093
|
+
// CIL[END stable_id="~/.framework/functions/admin-data.ts:getSearchField:function"]
|
|
1077
1094
|
// CIL[DOC-VECTOR type="context" content="purpose='Retrieves the appropriate search field name for a given entity type.'; No verified external callers" status="ready"]
|
|
1078
1095
|
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only" status="ready"]
|
|
1079
1096
|
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
|
|
@@ -1097,7 +1114,6 @@ function getSearchField(entity: string): string {
|
|
|
1097
1114
|
* @stability stable
|
|
1098
1115
|
* @cil-generated
|
|
1099
1116
|
*/
|
|
1100
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:entitysupportssoftdelete:function" type="function" identity="entitySupportsSoftDelete" parent="~/.framework/functions/admin-data.ts"]
|
|
1101
1117
|
// CIL[DOC-MACRO purpose="entitySupportsSoftDelete function"]
|
|
1102
1118
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the entitySupportsSoftDelete function."]
|
|
1103
1119
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -1105,11 +1121,12 @@ function getSearchField(entity: string): string {
|
|
|
1105
1121
|
// CIL[DOC-MICRO logic_summary="Implements the entitySupportsSoftDelete function." notable_decisions="[]"]
|
|
1106
1122
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
1107
1123
|
// CIL[DOC-STABILITY stability="stable"]
|
|
1124
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:entitySupportsSoftDelete:function" type="function" identity="entitySupportsSoftDelete" parent="~/.framework/functions/admin-data.ts"]
|
|
1108
1125
|
function entitySupportsSoftDelete(entity: string): boolean {
|
|
1109
1126
|
const softDeleteEntities = ['accounts', 'people', 'items', 'threads', 'messages', 'watchers', 'item_progress', 'test_cases']
|
|
1110
1127
|
return softDeleteEntities.includes(entity)
|
|
1111
1128
|
}
|
|
1112
|
-
// CIL[END stable_id="~/.framework/functions/admin-data.ts:
|
|
1129
|
+
// CIL[END stable_id="~/.framework/functions/admin-data.ts:entitySupportsSoftDelete:function"]
|
|
1113
1130
|
// CIL[DOC-VECTOR type="context" content="purpose='Determines if a given entity supports soft deletion by checking against a predefined list of entities.'; No verified external callers" status="ready"]
|
|
1114
1131
|
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only" status="ready"]
|
|
1115
1132
|
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
|
|
@@ -1132,7 +1149,6 @@ function entitySupportsSoftDelete(entity: string): boolean {
|
|
|
1132
1149
|
* @calls withAdminLogging, ctx.db.from
|
|
1133
1150
|
* @cil-generated
|
|
1134
1151
|
*/
|
|
1135
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:stats:constant" type="constant" identity="stats" parent="~/.framework/functions/admin-data.ts"]
|
|
1136
1152
|
// CIL[DOC-MACRO purpose="stats constant"]
|
|
1137
1153
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the stats constant."]
|
|
1138
1154
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -1140,6 +1156,7 @@ function entitySupportsSoftDelete(entity: string): boolean {
|
|
|
1140
1156
|
// CIL[DOC-MICRO logic_summary="Implements the stats constant." notable_decisions="[]"]
|
|
1141
1157
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
1142
1158
|
// CIL[DOC-STABILITY stability="stable"]
|
|
1159
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:stats:constant" type="constant" identity="stats" parent="~/.framework/functions/admin-data.ts"]
|
|
1143
1160
|
export const stats = createHandler(async (ctx, _body) => {
|
|
1144
1161
|
const { entity } = ctx.query || {}
|
|
1145
1162
|
const method = ctx.query?.method || 'GET'
|
|
@@ -1188,7 +1205,6 @@ export const stats = createHandler(async (ctx, _body) => {
|
|
|
1188
1205
|
* @calls list, get, stats, create, update, remove
|
|
1189
1206
|
* @cil-generated
|
|
1190
1207
|
*/
|
|
1191
|
-
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/admin-data.ts"]
|
|
1192
1208
|
// CIL[DOC-MACRO purpose="handler constant"]
|
|
1193
1209
|
// CIL[DOC-RESPONSIBILITY responsibility="Implements the handler constant."]
|
|
1194
1210
|
// CIL[DOC-CONTEXT module=".framework/functions/admin-data.ts" layer="app-specific" related_files=""]
|
|
@@ -1196,6 +1212,7 @@ export const stats = createHandler(async (ctx, _body) => {
|
|
|
1196
1212
|
// CIL[DOC-MICRO logic_summary="Implements the handler constant." notable_decisions="[]"]
|
|
1197
1213
|
// CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
|
|
1198
1214
|
// CIL[DOC-STABILITY stability="stable"]
|
|
1215
|
+
// CIL[BEGIN stable_id="~/.framework/functions/admin-data.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/admin-data.ts"]
|
|
1199
1216
|
export const handler = createHandler(async (ctx, body) => {
|
|
1200
1217
|
const { action } = ctx.query || {}
|
|
1201
1218
|
const method = ctx.query?.method || 'GET'
|
|
@@ -30,7 +30,7 @@ import { adminDb } from './_shared/db'
|
|
|
30
30
|
import { emitLog } from './_shared/audit'
|
|
31
31
|
import { isSystemAdmin } from './_shared/principal'
|
|
32
32
|
import { PermissionEngine, sanitizeRecordData } from './_shared/permissions'
|
|
33
|
-
import { runAgent,
|
|
33
|
+
import { runAgent, claimAgentEpisode, acquireEpisodeLease } from './_shared/agent-runner'
|
|
34
34
|
import { checkRateLimit } from './_shared/rate-limit'
|
|
35
35
|
import { detectInjection, emitSecurityEvent, getAppSecurityConfig } from './_shared/security'
|
|
36
36
|
// CIL[END stable_id="~/.framework/functions/ai-agents.ts:module_header:module_header"]
|
|
@@ -244,7 +244,8 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
244
244
|
throw new Error('User context (person and account) required')
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
const
|
|
247
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
248
|
+
const { data, error: err } = await db
|
|
248
249
|
.from('ai_agents')
|
|
249
250
|
.insert({
|
|
250
251
|
app_id: app_id || null,
|
|
@@ -258,7 +259,7 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
258
259
|
capabilities: capabilities || [],
|
|
259
260
|
constraints: constraints || {},
|
|
260
261
|
metadata: metadata || {},
|
|
261
|
-
created_by: ctx.principal.id
|
|
262
|
+
created_by: ctx.principal.type === 'human' ? ctx.principal.id : null
|
|
262
263
|
})
|
|
263
264
|
.select()
|
|
264
265
|
.single()
|
|
@@ -325,7 +326,8 @@ export const update = createHandler(async (ctx, body) => {
|
|
|
325
326
|
if (updates[key] !== undefined) updateData[key] = updates[key]
|
|
326
327
|
}
|
|
327
328
|
|
|
328
|
-
const
|
|
329
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
330
|
+
const { data, error: err } = await db
|
|
329
331
|
.from('ai_agents')
|
|
330
332
|
.update(updateData)
|
|
331
333
|
.eq('id', id)
|
|
@@ -383,7 +385,8 @@ export const remove = createHandler(async (ctx, _body) => {
|
|
|
383
385
|
throw new Error('Agent ID is required')
|
|
384
386
|
}
|
|
385
387
|
|
|
386
|
-
const
|
|
388
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
389
|
+
const { data: current } = await db
|
|
387
390
|
.from('ai_agents')
|
|
388
391
|
.select('id, name')
|
|
389
392
|
.eq('id', id)
|
|
@@ -391,7 +394,7 @@ export const remove = createHandler(async (ctx, _body) => {
|
|
|
391
394
|
|
|
392
395
|
if (!current) throw new Error('Agent not found')
|
|
393
396
|
|
|
394
|
-
const { error: err } = await
|
|
397
|
+
const { error: err } = await db
|
|
395
398
|
.from('ai_agents')
|
|
396
399
|
.delete()
|
|
397
400
|
.eq('id', id)
|
|
@@ -449,7 +452,8 @@ export const run = createHandler(async (ctx, body) => {
|
|
|
449
452
|
throw new Error('User context (person and account) required')
|
|
450
453
|
}
|
|
451
454
|
|
|
452
|
-
const
|
|
455
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
456
|
+
const { data, error: err } = await db
|
|
453
457
|
.from('threads')
|
|
454
458
|
.select('*, type:types(*)')
|
|
455
459
|
.eq('id', thread_id)
|
|
@@ -479,20 +483,27 @@ export const run = createHandler(async (ctx, body) => {
|
|
|
479
483
|
}
|
|
480
484
|
}
|
|
481
485
|
|
|
486
|
+
// Episode mode runs inline up to this budget — the first turns execute
|
|
487
|
+
// at full request CPU, then the client's step loop continues the
|
|
488
|
+
// episode under the same lease. Sized to leave headroom under the
|
|
489
|
+
// platform's synchronous request limit (~26s) even with a slow turn.
|
|
490
|
+
const EPISODE_INLINE_BUDGET_MS = 8000
|
|
491
|
+
|
|
482
492
|
const runMode = (mode as 'step' | 'complete' | 'episode') || 'complete'
|
|
483
493
|
|
|
484
|
-
// Episode single-flight:
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
|
|
494
|
+
// Episode single-flight: arbitration is the atomic episode_leases RPC
|
|
495
|
+
// (migration 063) — a claim INSERTs/locks the thread's lease row in one
|
|
496
|
+
// statement, so two entry paths can never both pass. The same driver
|
|
497
|
+
// re-acquiring renews; a different live driver is refused 'running';
|
|
498
|
+
// an expired lease is taken over so a crashed driver can't wedge the
|
|
499
|
+
// thread. When the RPC is absent (un-migrated deployment) the legacy
|
|
500
|
+
// non-atomic research_state check below runs instead.
|
|
491
501
|
const existingState = (data as any)?.data?.research_state
|
|
492
502
|
const heartbeatAt = Date.parse(existingState?.driver_heartbeat_at || '')
|
|
493
503
|
const leaseHolder = existingState?.driver_id
|
|
494
504
|
const callerToken = (body?.driver_token as string) || null
|
|
495
505
|
const callerId = callerToken || ctx.requestId
|
|
506
|
+
const DRIVER_LEASE_MS = 60000
|
|
496
507
|
const leaseLive =
|
|
497
508
|
!!leaseHolder &&
|
|
498
509
|
leaseHolder !== callerId &&
|
|
@@ -501,32 +512,91 @@ export const run = createHandler(async (ctx, body) => {
|
|
|
501
512
|
Number.isFinite(heartbeatAt) &&
|
|
502
513
|
Date.now() - heartbeatAt < DRIVER_LEASE_MS
|
|
503
514
|
|
|
504
|
-
if ((runMode === 'step' || runMode === 'complete') && leaseLive) {
|
|
505
|
-
return { ok: true, thread_id, status: 'running', driver_id: leaseHolder }
|
|
506
|
-
}
|
|
507
|
-
|
|
508
515
|
if (runMode === 'episode') {
|
|
509
|
-
|
|
510
|
-
|
|
516
|
+
// Episode mode claims the lease and runs the first turns INLINE
|
|
517
|
+
// (deadline-bounded complete mode) — detached 'void runAgent' work is
|
|
518
|
+
// CPU-throttled after the response flush on serverless platforms
|
|
519
|
+
// (~37s dead window observed before its first persisted message),
|
|
520
|
+
// which is exactly the stall the caller's quiet-window then "rescues"
|
|
521
|
+
// by double-driving. stealDetached lets this request take over from
|
|
522
|
+
// a 'detached:' background kick instantly; the fenced driver aborts
|
|
523
|
+
// at its next heartbeat without side effects.
|
|
524
|
+
const kick = await claimAgentEpisode(thread_id, user_message || '', ctx, callerId, (data as any)?.data, { stealDetached: true })
|
|
525
|
+
if (!kick.claimed && kick.already_done) {
|
|
526
|
+
// Replay of an already-answered question — return the episode's
|
|
527
|
+
// existing final rather than 'running' so callers don't poll for
|
|
528
|
+
// work that isn't coming.
|
|
529
|
+
const { data: lastOutbound } = await adminDb
|
|
530
|
+
.from('messages')
|
|
531
|
+
.select('id, content, data')
|
|
532
|
+
.eq('thread_id', thread_id)
|
|
533
|
+
.eq('direction', 'outbound')
|
|
534
|
+
.order('created_at', { ascending: false })
|
|
535
|
+
.limit(1)
|
|
536
|
+
const final = Array.isArray(lastOutbound) ? lastOutbound[0] : lastOutbound
|
|
537
|
+
return {
|
|
538
|
+
ok: true,
|
|
539
|
+
thread_id,
|
|
540
|
+
status: 'complete',
|
|
541
|
+
already_done: true,
|
|
542
|
+
driver_id: kick.driver_id,
|
|
543
|
+
message_id: final?.id || null,
|
|
544
|
+
content: final?.content || '',
|
|
545
|
+
message_type: final?.data?.message_type || null,
|
|
546
|
+
data: final?.data || null,
|
|
547
|
+
agent_id: final?.data?.agent_id || (data as any)?.data?.agent_id || null,
|
|
548
|
+
prompt_config_id: final?.data?.prompt_config_id || (data as any)?.data?.prompt_config_id || null,
|
|
549
|
+
}
|
|
511
550
|
}
|
|
512
|
-
// Debit agent_step only when a new driver will actually start work —
|
|
513
|
-
// lease-refused requests and ticket-creation kicks already debited or
|
|
514
|
-
// started nothing, and counting them would double-charge each episode.
|
|
515
|
-
await checkRateLimit(ctx, 'agent_step')
|
|
516
|
-
// Claim the lease before detaching so a step request landing during
|
|
517
|
-
// resolveAgentConfig still sees a live driver. Shared implementation lives
|
|
518
|
-
// in kickAgentEpisode (also used by ticket-creation handlers).
|
|
519
|
-
const leaseId = callerToken || ctx.requestId
|
|
520
|
-
const kick = await kickAgentEpisode(thread_id, user_message || '', ctx, leaseId, (data as any)?.data)
|
|
521
551
|
if (!kick.claimed) {
|
|
522
|
-
return { ok: true, thread_id, status: 'running',
|
|
552
|
+
return { ok: true, thread_id, status: 'running', already_running: true, driver_id: kick.driver_id }
|
|
553
|
+
}
|
|
554
|
+
// Debit agent_step only after a claim — refused requests start
|
|
555
|
+
// nothing and must not double-charge the episode.
|
|
556
|
+
await checkRateLimit(ctx, 'agent_step')
|
|
557
|
+
const message = await runAgent(thread_id, user_message || '', ctx, 'complete', kick.driver_id || callerToken || undefined, kick.lease_token, { deadlineMs: EPISODE_INLINE_BUDGET_MS })
|
|
558
|
+
|
|
559
|
+
const { data: updatedThread } = await adminDb
|
|
560
|
+
.from('threads')
|
|
561
|
+
.select('data')
|
|
562
|
+
.eq('id', thread_id)
|
|
563
|
+
.single()
|
|
564
|
+
const state = updatedThread?.data?.research_state || {}
|
|
565
|
+
return {
|
|
566
|
+
ok: true,
|
|
567
|
+
thread_id,
|
|
568
|
+
detached: false,
|
|
569
|
+
message_id: message?.id || null,
|
|
570
|
+
status: state.status || (message ? 'complete' : 'failed'),
|
|
571
|
+
turn_count: state.turn_count ?? 0,
|
|
572
|
+
content: message?.content || '',
|
|
573
|
+
message_type: message?.data?.message_type || null,
|
|
574
|
+
data: message?.data || null,
|
|
575
|
+
agent_id: message?.data?.agent_id || updatedThread?.data?.agent_id || null,
|
|
576
|
+
prompt_config_id: message?.data?.prompt_config_id || updatedThread?.data?.prompt_config_id || null,
|
|
523
577
|
}
|
|
524
|
-
return { ok: true, thread_id, status: 'running', detached: true }
|
|
525
578
|
}
|
|
526
579
|
|
|
527
|
-
// step/complete
|
|
580
|
+
// step/complete: claim the episode lease for this driver. 'held' means
|
|
581
|
+
// another live driver owns the episode — the caller watches persisted
|
|
582
|
+
// state instead of interleaving writes. A claimed lease survives a
|
|
583
|
+
// nonterminal step return so the same driver's next call renews it.
|
|
584
|
+
// stealDetached lets a request driver take over from a 'detached:'
|
|
585
|
+
// background kick without waiting out the TTL.
|
|
586
|
+
const claim = await acquireEpisodeLease(thread_id, ctx.accountId, callerId, undefined, true)
|
|
587
|
+
let leaseToken: string | undefined
|
|
588
|
+
if (claim?.outcome === 'held') {
|
|
589
|
+
return { ok: true, thread_id, status: 'running', driver_id: claim.holder_driver_id }
|
|
590
|
+
}
|
|
591
|
+
if (claim === null && leaseLive) {
|
|
592
|
+
return { ok: true, thread_id, status: 'running', driver_id: leaseHolder }
|
|
593
|
+
}
|
|
594
|
+
if (claim?.outcome === 'claimed') leaseToken = claim.lease_token
|
|
595
|
+
|
|
596
|
+
// step/complete modes debit here — only when work will start, so
|
|
597
|
+
// lease-refused requests never double-charge an episode.
|
|
528
598
|
await checkRateLimit(ctx, 'agent_step')
|
|
529
|
-
const message = await runAgent(thread_id, user_message || '', ctx, runMode,
|
|
599
|
+
const message = await runAgent(thread_id, user_message || '', ctx, runMode, callerId, leaseToken)
|
|
530
600
|
|
|
531
601
|
const { data: updatedThread } = await adminDb
|
|
532
602
|
.from('threads')
|