spine-framework 0.3.114 → 0.3.115
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/.framework/functions/_shared/agent-runner.ts +38 -4
- package/.framework/functions/_shared/permissions.ts +44 -14
- package/.framework/migrations/030_messages_updated_by.sql +6 -0
- package/.framework/migrations/031_cil_vector_types.sql +60 -0
- package/.framework/migrations/032_cil_agent_config.sql +122 -0
- package/.framework/migrations/033_cil_chunk_schema_fields.sql +75 -0
- package/.framework/migrations/034_cil_self_seed.sql +116 -0
- package/package.json +9 -2
|
@@ -70,7 +70,7 @@ export interface AgentConfig {
|
|
|
70
70
|
* Structured result from a single LLM inference call.
|
|
71
71
|
*
|
|
72
72
|
* @outputSpec content: string — agent response text
|
|
73
|
-
* @outputSpec confidence: number — 0-1 score; derived from logprobs or 0.
|
|
73
|
+
* @outputSpec confidence: number — 0-1 score; derived from logprobs or 0.70 default
|
|
74
74
|
* @outputSpec tool_calls: ToolCall[] | undefined — tools the model wants to call
|
|
75
75
|
* @outputSpec metadata: { model, usage, finish_reason } | undefined
|
|
76
76
|
*/
|
|
@@ -372,10 +372,14 @@ async function executeAgentInference(
|
|
|
372
372
|
|
|
373
373
|
if (!inferenceResult.tool_calls || inferenceResult.tool_calls.length === 0) {
|
|
374
374
|
// Composite confidence: 60% LLM logprobs + 40% retrieval similarity
|
|
375
|
+
// When logprobs are absent, be conservative: default 0.70 instead of 0.85
|
|
375
376
|
// If mean retrieval similarity < 0.40, cap composite at 0.60
|
|
376
|
-
|
|
377
|
+
// If mean retrieval similarity < 0.25, cap composite at 0.45 (very poor retrieval)
|
|
378
|
+
const llmConf = inferenceResult.confidence ?? 0.70
|
|
377
379
|
let compositeConf: number
|
|
378
|
-
if (meanSimilarity < 0.
|
|
380
|
+
if (meanSimilarity < 0.25 && meanSimilarity > 0) {
|
|
381
|
+
compositeConf = Math.min(llmConf * 0.6 + meanSimilarity * 0.4, 0.45)
|
|
382
|
+
} else if (meanSimilarity < 0.40 && meanSimilarity > 0) {
|
|
379
383
|
compositeConf = Math.min(llmConf * 0.6 + meanSimilarity * 0.4, 0.60)
|
|
380
384
|
} else {
|
|
381
385
|
compositeConf = llmConf * 0.6 + Math.min(meanSimilarity, 1) * 0.4
|
|
@@ -799,9 +803,11 @@ async function callInference(
|
|
|
799
803
|
const message = result.choices?.[0]?.message
|
|
800
804
|
|
|
801
805
|
// Extract confidence from logprobs if available, otherwise estimate
|
|
806
|
+
// Default is conservative (0.70) when logprobs are absent — retrieval quality
|
|
807
|
+
// should drive the final composite confidence, not an arbitrary high default.
|
|
802
808
|
const confidence = result.choices?.[0]?.logprobs?.content?.[0]?.logprob
|
|
803
809
|
? Math.exp(result.choices[0].logprobs.content[0].logprob)
|
|
804
|
-
: 0.
|
|
810
|
+
: 0.70
|
|
805
811
|
|
|
806
812
|
return {
|
|
807
813
|
content: message?.content || '',
|
|
@@ -1195,6 +1201,34 @@ async function handleEscalation(
|
|
|
1195
1201
|
})
|
|
1196
1202
|
.eq('id', threadId)
|
|
1197
1203
|
|
|
1204
|
+
// If the thread targets an item (e.g., a support ticket), mark that item as
|
|
1205
|
+
// human-assigned so it shows up in the human queue and stops AI responses.
|
|
1206
|
+
const { data: thread } = await adminDb
|
|
1207
|
+
.from('threads')
|
|
1208
|
+
.select('target_type, target_id')
|
|
1209
|
+
.eq('id', threadId)
|
|
1210
|
+
.single()
|
|
1211
|
+
if (thread?.target_type === 'items' && thread?.target_id) {
|
|
1212
|
+
const { data: item } = await adminDb
|
|
1213
|
+
.from('items')
|
|
1214
|
+
.select('status, data')
|
|
1215
|
+
.eq('id', thread.target_id)
|
|
1216
|
+
.single()
|
|
1217
|
+
if (item && item.status !== 'human_assigned' && item.status !== 'resolved') {
|
|
1218
|
+
await adminDb
|
|
1219
|
+
.from('items')
|
|
1220
|
+
.update({
|
|
1221
|
+
status: 'human_assigned',
|
|
1222
|
+
data: {
|
|
1223
|
+
...(item.data || {}),
|
|
1224
|
+
aim_escalation_reason: 'low_confidence'
|
|
1225
|
+
},
|
|
1226
|
+
updated_at: new Date().toISOString()
|
|
1227
|
+
})
|
|
1228
|
+
.eq('id', thread.target_id)
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1198
1232
|
// Fire trigger event
|
|
1199
1233
|
await emitAudit(ctx, 'agent.inference.low_confidence', {
|
|
1200
1234
|
type: 'thread',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// ─── CHUNK_START: PERMISSIONS_OVERVIEW ──────────────────────────────────────────────
|
|
1
2
|
/**
|
|
2
3
|
* @module permissions
|
|
3
4
|
* @audience both
|
|
@@ -32,12 +33,13 @@
|
|
|
32
33
|
* @seeAlso index.ts (stable export surface for custom code)
|
|
33
34
|
*/
|
|
34
35
|
|
|
36
|
+
// ─── CHUNK_END: PERMISSIONS_OVERVIEW ────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
// ─── CHUNK_START: PERMISSIONS_TYPES ──────────────────────────────────────────────
|
|
35
39
|
import { adminDb } from './db'
|
|
36
40
|
import { Principal } from './principal'
|
|
37
41
|
import { CoreContext } from './middleware'
|
|
38
42
|
|
|
39
|
-
// ─── TYPES ────────────────────────────────────────────────────────────────────
|
|
40
|
-
|
|
41
43
|
/**
|
|
42
44
|
* Result of a permission resolution for a principal + record + action combination.
|
|
43
45
|
*
|
|
@@ -66,9 +68,9 @@ export interface PermissionResult {
|
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
type RequestContext = CoreContext
|
|
71
|
+
// ─── CHUNK_END: PERMISSIONS_TYPES ────────────────────────────────────────────────
|
|
69
72
|
|
|
70
|
-
// ───
|
|
71
|
-
|
|
73
|
+
// ─── CHUNK_START: PERMISSIONS_ENGINE_CLASS ──────────────────────────────────────────────
|
|
72
74
|
/**
|
|
73
75
|
* The single permission engine for all authorization in Spine.
|
|
74
76
|
*
|
|
@@ -87,11 +89,12 @@ type RequestContext = CoreContext
|
|
|
87
89
|
* @testUnit tests/unit/permissions.test.ts
|
|
88
90
|
* @testIntegration tests/integration/isolation.test.ts, admin-data-accounts.test.ts
|
|
89
91
|
*/
|
|
92
|
+
// ─── CHUNK_END: PERMISSIONS_ENGINE_CLASS ────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
// ─── CHUNK_START: PERMISSIONS_SURFACE_CLASSIFICATION ──────────────────────────────────────────────
|
|
90
95
|
class _PermissionEngineInternal {
|
|
91
96
|
private static instance: _PermissionEngineInternal
|
|
92
97
|
|
|
93
|
-
// ─── SURFACE CLASSIFICATION ───────────────────────────────────────────────
|
|
94
|
-
|
|
95
98
|
// Surface classification tables
|
|
96
99
|
private readonly SECOND_SURFACE_TABLES = new Set([
|
|
97
100
|
'apps', 'app', 'pipelines', 'triggers', 'ai_agents', 'embeddings',
|
|
@@ -189,7 +192,9 @@ class _PermissionEngineInternal {
|
|
|
189
192
|
return _PermissionEngineInternal.instance
|
|
190
193
|
}
|
|
191
194
|
|
|
192
|
-
|
|
195
|
+
// ─── CHUNK_END: PERMISSIONS_SURFACE_CLASSIFICATION ────────────────────────────────────────────────
|
|
196
|
+
|
|
197
|
+
// ─── CHUNK_START: PERMISSIONS_FIRST_SURFACE_RESOLVE ──────────────────────────────────────────────
|
|
193
198
|
|
|
194
199
|
/**
|
|
195
200
|
* Resolves record-level and field-level permissions for a human principal
|
|
@@ -334,7 +339,9 @@ class _PermissionEngineInternal {
|
|
|
334
339
|
}
|
|
335
340
|
}
|
|
336
341
|
|
|
337
|
-
|
|
342
|
+
// ─── CHUNK_END: PERMISSIONS_FIRST_SURFACE_RESOLVE ────────────────────────────────────────────────
|
|
343
|
+
|
|
344
|
+
// ─── CHUNK_START: PERMISSIONS_SECOND_SURFACE_CONFIG_OBJECTS ──────────────────────────────────────────────
|
|
338
345
|
|
|
339
346
|
/**
|
|
340
347
|
* Checks whether the principal in `ctx` may perform `action` on a second-surface
|
|
@@ -465,7 +472,9 @@ class _PermissionEngineInternal {
|
|
|
465
472
|
return { valid: false, error: 'Insufficient permissions for this operation' }
|
|
466
473
|
}
|
|
467
474
|
|
|
468
|
-
|
|
475
|
+
// ─── CHUNK_END: PERMISSIONS_SECOND_SURFACE_CONFIG_OBJECTS ────────────────────────────────────────────────
|
|
476
|
+
|
|
477
|
+
// ─── CHUNK_START: PERMISSIONS_THIRD_SURFACE_SYSTEM_METADATA ──────────────────────────────────────────────
|
|
469
478
|
|
|
470
479
|
/**
|
|
471
480
|
* Checks whether the principal may access a third-surface system metadata record
|
|
@@ -584,7 +593,9 @@ class _PermissionEngineInternal {
|
|
|
584
593
|
return { valid: false, error: 'Insufficient permissions for this operation' }
|
|
585
594
|
}
|
|
586
595
|
|
|
587
|
-
|
|
596
|
+
// ─── CHUNK_END: PERMISSIONS_THIRD_SURFACE_SYSTEM_METADATA ────────────────────────────────────────────────
|
|
597
|
+
|
|
598
|
+
// ─── CHUNK_START: PERMISSIONS_SHARED_HELPERS ──────────────────────────────────────────────
|
|
588
599
|
|
|
589
600
|
/**
|
|
590
601
|
* Returns true if the principal in `ctx` holds the `system_admin` role.
|
|
@@ -608,7 +619,9 @@ class _PermissionEngineInternal {
|
|
|
608
619
|
return ctx.principal?.roles?.includes('system_admin') || false
|
|
609
620
|
}
|
|
610
621
|
|
|
611
|
-
|
|
622
|
+
// ─── CHUNK_END: PERMISSIONS_SHARED_HELPERS ────────────────────────────────────────────────
|
|
623
|
+
|
|
624
|
+
// ─── CHUNK_START: PERMISSIONS_CAN_ACCESS_RECORD ──────────────────────────────────────────────
|
|
612
625
|
|
|
613
626
|
/**
|
|
614
627
|
* Checks whether the principal in `ctx` may perform `action` on `record`.
|
|
@@ -776,6 +789,9 @@ class _PermissionEngineInternal {
|
|
|
776
789
|
* const safe = await sanitizeRecordData(ctx, rawRecord, 'ticket')
|
|
777
790
|
* ```
|
|
778
791
|
*/
|
|
792
|
+
// ─── CHUNK_END: PERMISSIONS_CAN_ACCESS_RECORD ────────────────────────────────────────────────
|
|
793
|
+
|
|
794
|
+
// ─── CHUNK_START: PERMISSIONS_SANITIZE_RECORD_DATA ──────────────────────────────────────────────
|
|
779
795
|
async sanitizeRecordData(
|
|
780
796
|
ctx: RequestContext,
|
|
781
797
|
record: any,
|
|
@@ -803,7 +819,9 @@ class _PermissionEngineInternal {
|
|
|
803
819
|
return this.sanitizeFirstSurfaceRecordData(ctx, record, typeSlug || '')
|
|
804
820
|
}
|
|
805
821
|
}
|
|
822
|
+
// ─── CHUNK_END: PERMISSIONS_SANITIZE_RECORD_DATA ────────────────────────────────────────────────
|
|
806
823
|
|
|
824
|
+
// ─── CHUNK_START: PERMISSIONS_SANITIZE_FIRST_SURFACE ──────────────────────────────────────────────
|
|
807
825
|
/**
|
|
808
826
|
* Field-level filter and formatter for first-surface (runtime data) records.
|
|
809
827
|
*
|
|
@@ -924,7 +942,9 @@ class _PermissionEngineInternal {
|
|
|
924
942
|
|
|
925
943
|
return sanitized
|
|
926
944
|
}
|
|
945
|
+
// ─── CHUNK_END: PERMISSIONS_SANITIZE_FIRST_SURFACE ────────────────────────────────────────────────
|
|
927
946
|
|
|
947
|
+
// ─── CHUNK_START: PERMISSIONS_VALIDATE_UPDATE ──────────────────────────────────────────────
|
|
928
948
|
/**
|
|
929
949
|
* Validates that the principal has write permission for every field in `updateData`,
|
|
930
950
|
* and sanitizes the data using the validation schema before returning it.
|
|
@@ -992,7 +1012,9 @@ class _PermissionEngineInternal {
|
|
|
992
1012
|
return this.validateFirstSurfaceUpdatePermissions(ctx, updateData, existingRecord, typeSlug || '')
|
|
993
1013
|
}
|
|
994
1014
|
}
|
|
1015
|
+
// ─── CHUNK_END: PERMISSIONS_VALIDATE_UPDATE ────────────────────────────────────────────────
|
|
995
1016
|
|
|
1017
|
+
// ─── CHUNK_START: PERMISSIONS_VALIDATE_FIRST_SURFACE ──────────────────────────────────────────────
|
|
996
1018
|
/**
|
|
997
1019
|
* Field-level write validation and sanitization for first-surface update payloads.
|
|
998
1020
|
*
|
|
@@ -1103,8 +1125,9 @@ class _PermissionEngineInternal {
|
|
|
1103
1125
|
|
|
1104
1126
|
return { valid: true, sanitizedData }
|
|
1105
1127
|
}
|
|
1128
|
+
// ─── CHUNK_END: PERMISSIONS_VALIDATE_FIRST_SURFACE ────────────────────────────────────────────────
|
|
1106
1129
|
|
|
1107
|
-
|
|
1130
|
+
// ─── CHUNK_START: PERMISSIONS_CAN_PRINCIPAL_ACCESS_RECORD ──────────────────────────────────────────────
|
|
1108
1131
|
|
|
1109
1132
|
/**
|
|
1110
1133
|
* Unified permission check for all principal types (human, machine, cron, trigger).
|
|
@@ -1180,7 +1203,9 @@ class _PermissionEngineInternal {
|
|
|
1180
1203
|
|
|
1181
1204
|
return false
|
|
1182
1205
|
}
|
|
1183
|
-
|
|
1206
|
+
// ─── CHUNK_END: PERMISSIONS_CAN_PRINCIPAL_ACCESS_RECORD ────────────────────────────────────────────────
|
|
1207
|
+
|
|
1208
|
+
// ─── CHUNK_START: PERMISSIONS_MACHINE_SCOPE ──────────────────────────────────────────────
|
|
1184
1209
|
/**
|
|
1185
1210
|
* Evaluates whether a machine principal's scopes permit the requested action.
|
|
1186
1211
|
*
|
|
@@ -1227,7 +1252,9 @@ class _PermissionEngineInternal {
|
|
|
1227
1252
|
|
|
1228
1253
|
return false
|
|
1229
1254
|
}
|
|
1230
|
-
|
|
1255
|
+
// ─── CHUNK_END: PERMISSIONS_MACHINE_SCOPE ────────────────────────────────────────────────
|
|
1256
|
+
|
|
1257
|
+
// ─── CHUNK_START: PERMISSIONS_PERMISSION_SUMMARY ──────────────────────────────────────────────
|
|
1231
1258
|
/**
|
|
1232
1259
|
* Returns a structured summary of a principal's permission posture for use
|
|
1233
1260
|
* in audit log entries.
|
|
@@ -1274,7 +1301,9 @@ class _PermissionEngineInternal {
|
|
|
1274
1301
|
return { type: 'unknown' }
|
|
1275
1302
|
}
|
|
1276
1303
|
}
|
|
1304
|
+
// ─── CHUNK_END: PERMISSIONS_PERMISSION_SUMMARY ────────────────────────────────────────────────
|
|
1277
1305
|
|
|
1306
|
+
// ─── CHUNK_START: PERMISSIONS_SINGLETON_AND_EXPORTS ──────────────────────────────────────────────
|
|
1278
1307
|
// ─── SINGLETON EXPORT ────────────────────────────────────────────────────────
|
|
1279
1308
|
|
|
1280
1309
|
/**
|
|
@@ -1317,3 +1346,4 @@ export const isSystemAdmin = PermissionEngine.isSystemAdmin.bind(PermissionEngin
|
|
|
1317
1346
|
export const canAccessRecord = PermissionEngine.canAccessRecord.bind(PermissionEngine)
|
|
1318
1347
|
export const sanitizeRecordData = PermissionEngine.sanitizeRecordData.bind(PermissionEngine)
|
|
1319
1348
|
export const validateUpdatePermissions = PermissionEngine.validateUpdatePermissions.bind(PermissionEngine)
|
|
1349
|
+
// ─── CHUNK_END: PERMISSIONS_SINGLETON_AND_EXPORTS ────────────────────────────────────────────────
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- Migration 030: Add missing updated_by column to messages table
|
|
2
|
+
-- The messages table was created without updated_by, causing PATCH requests
|
|
3
|
+
-- via admin-data to fail when the audit stamp tries to set that field.
|
|
4
|
+
|
|
5
|
+
ALTER TABLE public.messages
|
|
6
|
+
ADD COLUMN IF NOT EXISTS updated_by uuid REFERENCES public.people(id) ON DELETE SET NULL;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
-- Migration 031: CIL vector types — patch cil_chunk type design_schema
|
|
2
|
+
--
|
|
3
|
+
-- The seed file (custom/apps/cortex/seed/types.json) defines cil_chunk with
|
|
4
|
+
-- no vector_types because the generate() function in embeddings.ts reads
|
|
5
|
+
-- vector_types from the type's design_schema at runtime.
|
|
6
|
+
--
|
|
7
|
+
-- This migration patches in the three CIL vector types for cil_chunk so that
|
|
8
|
+
-- calls to generate() produce semantic, structural, and contract vectors.
|
|
9
|
+
--
|
|
10
|
+
-- Also adds vector_types for cil_config (semantic only) and cil_project (semantic).
|
|
11
|
+
--
|
|
12
|
+
-- Safe to re-run: uses jsonb_set which is idempotent on the same value.
|
|
13
|
+
--
|
|
14
|
+
-- NOTE: This only patches rows where the type already exists. The seed must
|
|
15
|
+
-- have been applied (via spine install-app) before this migration runs.
|
|
16
|
+
|
|
17
|
+
-- ── cil_chunk: semantic + structural + contract ───────────────────────────────
|
|
18
|
+
UPDATE public.types
|
|
19
|
+
SET design_schema = jsonb_set(
|
|
20
|
+
design_schema,
|
|
21
|
+
'{vector_types}',
|
|
22
|
+
'["semantic", "structural", "contract"]'::jsonb,
|
|
23
|
+
true -- create if missing
|
|
24
|
+
)
|
|
25
|
+
WHERE kind = 'item'
|
|
26
|
+
AND slug = 'cil_chunk';
|
|
27
|
+
|
|
28
|
+
-- ── cil_project: semantic only (project descriptions) ─────────────────────────
|
|
29
|
+
UPDATE public.types
|
|
30
|
+
SET design_schema = jsonb_set(
|
|
31
|
+
design_schema,
|
|
32
|
+
'{vector_types}',
|
|
33
|
+
'["semantic"]'::jsonb,
|
|
34
|
+
true
|
|
35
|
+
)
|
|
36
|
+
WHERE kind = 'item'
|
|
37
|
+
AND slug = 'cil_project';
|
|
38
|
+
|
|
39
|
+
-- ── cil_config: semantic (config field descriptions) ──────────────────────────
|
|
40
|
+
UPDATE public.types
|
|
41
|
+
SET design_schema = jsonb_set(
|
|
42
|
+
design_schema,
|
|
43
|
+
'{vector_types}',
|
|
44
|
+
'["semantic"]'::jsonb,
|
|
45
|
+
true
|
|
46
|
+
)
|
|
47
|
+
WHERE kind = 'item'
|
|
48
|
+
AND slug = 'cil_config';
|
|
49
|
+
|
|
50
|
+
-- ── embedding_fields for cil_chunk structural vector ─────────────────────────
|
|
51
|
+
-- structural vector uses these fields from item.data for its JSON snapshot
|
|
52
|
+
UPDATE public.types
|
|
53
|
+
SET design_schema = jsonb_set(
|
|
54
|
+
design_schema,
|
|
55
|
+
'{embedding_fields,structural}',
|
|
56
|
+
'["chunk_type","file_path","stability","is_dead_code","boundary_confidence","doc_confidence","review_status"]'::jsonb,
|
|
57
|
+
true
|
|
58
|
+
)
|
|
59
|
+
WHERE kind = 'item'
|
|
60
|
+
AND slug = 'cil_chunk';
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
-- Migration 032: CIL AI Agent + Prompt Config
|
|
2
|
+
--
|
|
3
|
+
-- Seeds the Code Intelligence Layer conversational agent so it can answer
|
|
4
|
+
-- questions about the codebase using cil_chunk embeddings as RAG context.
|
|
5
|
+
--
|
|
6
|
+
-- The agent is scoped to the Cortex app (is_system = false so it can be
|
|
7
|
+
-- overridden per-tenant). A second system-level prompt config with
|
|
8
|
+
-- retrieval_policy.item_types = ["cil_chunk"] ensures the agent only pulls
|
|
9
|
+
-- code chunk embeddings rather than KB articles.
|
|
10
|
+
--
|
|
11
|
+
-- Safe to re-run: uses INSERT ... ON CONFLICT DO NOTHING on (app_id, name)
|
|
12
|
+
-- and ON CONFLICT (slug) DO NOTHING for prompt_configs.
|
|
13
|
+
|
|
14
|
+
-- ── CIL Conversational Agent ─────────────────────────────────────────────────
|
|
15
|
+
INSERT INTO public.ai_agents (
|
|
16
|
+
id,
|
|
17
|
+
app_id,
|
|
18
|
+
name,
|
|
19
|
+
description,
|
|
20
|
+
agent_type,
|
|
21
|
+
system_prompt,
|
|
22
|
+
model_config,
|
|
23
|
+
ownership,
|
|
24
|
+
is_system,
|
|
25
|
+
is_active,
|
|
26
|
+
created_at,
|
|
27
|
+
updated_at
|
|
28
|
+
)
|
|
29
|
+
SELECT
|
|
30
|
+
gen_random_uuid(),
|
|
31
|
+
(SELECT id FROM public.apps WHERE slug = 'cortex'),
|
|
32
|
+
'CIL Codebase Assistant',
|
|
33
|
+
'Conversational agent that answers questions about the codebase using the Code Intelligence Layer. Retrieves chunk contracts, call graphs, and documentation via semantic search.',
|
|
34
|
+
'rag',
|
|
35
|
+
'You are a Code Intelligence Layer assistant. Your job is to answer questions about this codebase accurately and concisely.
|
|
36
|
+
|
|
37
|
+
You have access to a semantic index of every named chunk in the codebase. Each chunk record contains:
|
|
38
|
+
- chunk_name: the function / class / component name
|
|
39
|
+
- macro: one-sentence purpose statement
|
|
40
|
+
- micro: implementation detail
|
|
41
|
+
- input_spec: parameter names, types, constraints
|
|
42
|
+
- output_spec: return type and shape
|
|
43
|
+
- side_effects: DB writes, API calls, file I/O
|
|
44
|
+
- stability: stable | internal | experimental
|
|
45
|
+
- file_path: source file location
|
|
46
|
+
|
|
47
|
+
When answering:
|
|
48
|
+
1. Ground your answer in the retrieved chunk contracts — do not invent APIs.
|
|
49
|
+
2. Always cite the chunk_name and file_path when referencing a specific function.
|
|
50
|
+
3. If you cannot find a relevant chunk, say so explicitly — do not guess.
|
|
51
|
+
4. For refactoring questions, always mention callers / blast radius if known.
|
|
52
|
+
5. Keep answers concise. Use markdown code blocks for code examples.
|
|
53
|
+
6. If asked "is X safe to change?", check if stability = stable before confirming.
|
|
54
|
+
|
|
55
|
+
Avoid hallucinating parameter names, return types, or side effects that are not in the retrieved contracts.',
|
|
56
|
+
'{"model": "gpt-4o-mini", "temperature": 0.2, "max_tokens": 1500}',
|
|
57
|
+
'platform',
|
|
58
|
+
false,
|
|
59
|
+
true,
|
|
60
|
+
now(),
|
|
61
|
+
now()
|
|
62
|
+
WHERE NOT EXISTS (
|
|
63
|
+
SELECT 1 FROM public.ai_agents
|
|
64
|
+
WHERE app_id = (SELECT id FROM public.apps WHERE slug = 'cortex')
|
|
65
|
+
AND name = 'CIL Codebase Assistant'
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
-- ── CIL Agent Prompt Config ───────────────────────────────────────────────────
|
|
69
|
+
INSERT INTO public.prompt_configs (
|
|
70
|
+
id,
|
|
71
|
+
app_id,
|
|
72
|
+
slug,
|
|
73
|
+
name,
|
|
74
|
+
context_template,
|
|
75
|
+
model,
|
|
76
|
+
temperature,
|
|
77
|
+
max_tokens,
|
|
78
|
+
is_multi_turn,
|
|
79
|
+
max_history_messages,
|
|
80
|
+
confidence_threshold,
|
|
81
|
+
output_mode,
|
|
82
|
+
knowledge_sources,
|
|
83
|
+
available_tools,
|
|
84
|
+
metadata,
|
|
85
|
+
ownership,
|
|
86
|
+
is_system,
|
|
87
|
+
is_active,
|
|
88
|
+
created_at,
|
|
89
|
+
updated_at
|
|
90
|
+
)
|
|
91
|
+
SELECT
|
|
92
|
+
gen_random_uuid(),
|
|
93
|
+
(SELECT id FROM public.apps WHERE slug = 'cortex'),
|
|
94
|
+
'cil_codebase_assistant',
|
|
95
|
+
'CIL Codebase Assistant',
|
|
96
|
+
'Answer the user''s question about the codebase using the retrieved chunk contracts above.
|
|
97
|
+
If the answer involves a specific function, always include: chunk_name, file_path, and what it does.',
|
|
98
|
+
'gpt-4o-mini',
|
|
99
|
+
0.2,
|
|
100
|
+
1500,
|
|
101
|
+
true,
|
|
102
|
+
10,
|
|
103
|
+
0.3,
|
|
104
|
+
'text',
|
|
105
|
+
'[]'::jsonb,
|
|
106
|
+
'[]'::jsonb,
|
|
107
|
+
jsonb_build_object(
|
|
108
|
+
'retrieval_policy', jsonb_build_object(
|
|
109
|
+
'item_types', jsonb_build_array('cil_chunk'),
|
|
110
|
+
'vector_types', jsonb_build_array('semantic', 'contract'),
|
|
111
|
+
'max_security_level', 'internal',
|
|
112
|
+
'require_approved', true
|
|
113
|
+
)
|
|
114
|
+
),
|
|
115
|
+
'platform',
|
|
116
|
+
false,
|
|
117
|
+
true,
|
|
118
|
+
now(),
|
|
119
|
+
now()
|
|
120
|
+
WHERE NOT EXISTS (
|
|
121
|
+
SELECT 1 FROM public.prompt_configs WHERE slug = 'cil_codebase_assistant'
|
|
122
|
+
);
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
-- Migration 033: Add missing fields to CIL item type design_schemas
|
|
2
|
+
--
|
|
3
|
+
-- Adds fields that are written by the backend functions but were absent from
|
|
4
|
+
-- the design_schema definitions in types.json:
|
|
5
|
+
--
|
|
6
|
+
-- cil_chunk:
|
|
7
|
+
-- - hash_updated_at written by custom_cil-validate ?action=update_hash
|
|
8
|
+
-- - kb_type written by custom_cil-ingest pass2 (discriminator field)
|
|
9
|
+
--
|
|
10
|
+
-- cil_file:
|
|
11
|
+
-- - line_count written by custom_cil-ingest pass1
|
|
12
|
+
-- - existing_marker_names written by custom_cil-ingest pass1
|
|
13
|
+
-- - existing_marker_count written by custom_cil-ingest pass1
|
|
14
|
+
-- - kb_type discriminator field
|
|
15
|
+
--
|
|
16
|
+
-- Safe to re-run: uses jsonb || operator (merge) so existing schema fields are
|
|
17
|
+
-- preserved. Only adds new keys — does not overwrite existing ones.
|
|
18
|
+
|
|
19
|
+
-- ── cil_chunk — add hash_updated_at + kb_type ───────────────────────────────
|
|
20
|
+
UPDATE public.types
|
|
21
|
+
SET design_schema = design_schema || jsonb_build_object(
|
|
22
|
+
'fields', (design_schema->'fields') || jsonb_build_object(
|
|
23
|
+
'hash_updated_at', jsonb_build_object(
|
|
24
|
+
'label', 'Hash Updated At',
|
|
25
|
+
'data_type', 'text'
|
|
26
|
+
),
|
|
27
|
+
'kb_type', jsonb_build_object(
|
|
28
|
+
'label', 'KB Type',
|
|
29
|
+
'data_type', 'text'
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
)
|
|
33
|
+
WHERE slug = 'cil_chunk'
|
|
34
|
+
AND kind = 'item'
|
|
35
|
+
AND NOT (design_schema->'fields' ? 'hash_updated_at');
|
|
36
|
+
|
|
37
|
+
-- ── cil_file — add line_count, existing_marker_names, existing_marker_count, kb_type ─
|
|
38
|
+
UPDATE public.types
|
|
39
|
+
SET design_schema = design_schema || jsonb_build_object(
|
|
40
|
+
'fields', (design_schema->'fields') || jsonb_build_object(
|
|
41
|
+
'line_count', jsonb_build_object(
|
|
42
|
+
'label', 'Line Count',
|
|
43
|
+
'data_type', 'number'
|
|
44
|
+
),
|
|
45
|
+
'existing_marker_names', jsonb_build_object(
|
|
46
|
+
'label', 'Existing Marker Names',
|
|
47
|
+
'data_type', 'text'
|
|
48
|
+
),
|
|
49
|
+
'existing_marker_count', jsonb_build_object(
|
|
50
|
+
'label', 'Existing Marker Count',
|
|
51
|
+
'data_type', 'number'
|
|
52
|
+
),
|
|
53
|
+
'kb_type', jsonb_build_object(
|
|
54
|
+
'label', 'KB Type',
|
|
55
|
+
'data_type', 'text'
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
WHERE slug = 'cil_file'
|
|
60
|
+
AND kind = 'item'
|
|
61
|
+
AND NOT (design_schema->'fields' ? 'kb_type');
|
|
62
|
+
|
|
63
|
+
-- ── cil_project — add kb_type ────────────────────────────────────────────────
|
|
64
|
+
UPDATE public.types
|
|
65
|
+
SET design_schema = design_schema || jsonb_build_object(
|
|
66
|
+
'fields', (design_schema->'fields') || jsonb_build_object(
|
|
67
|
+
'kb_type', jsonb_build_object(
|
|
68
|
+
'label', 'KB Type',
|
|
69
|
+
'data_type', 'text'
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
WHERE slug = 'cil_project'
|
|
74
|
+
AND kind = 'item'
|
|
75
|
+
AND NOT (design_schema->'fields' ? 'kb_type');
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
-- Migration 034: CIL Self-Seed — register spine-ia as a CIL project
|
|
2
|
+
--
|
|
3
|
+
-- Seeds the spine-ia repository itself as a `cil_project` item so that
|
|
4
|
+
-- Pass 1–5 of the Code Intelligence Layer pipeline can be run against it
|
|
5
|
+
-- immediately after install, without needing to create the project via the UI.
|
|
6
|
+
--
|
|
7
|
+
-- The repo_path defaults to the standard CascadeProjects location. Operators
|
|
8
|
+
-- running the app on a different machine should update the repo_path via:
|
|
9
|
+
-- PATCH /api/custom_cil-project?action=update&id=<SPINE_IA_PROJECT_ID>
|
|
10
|
+
-- body: { data: { repo_path: "/path/to/your/spine-ia" } }
|
|
11
|
+
--
|
|
12
|
+
-- Safe to re-run: the INSERT is guarded by WHERE NOT EXISTS on the title.
|
|
13
|
+
-- The hard-coded UUID allows other migrations to reference this project.
|
|
14
|
+
|
|
15
|
+
-- Known stable UUID for the spine-ia CIL project (update if your DB uses a different value)
|
|
16
|
+
DO $$
|
|
17
|
+
DECLARE
|
|
18
|
+
v_cil_project_type_id uuid;
|
|
19
|
+
v_spine_account_id uuid;
|
|
20
|
+
v_cortex_app_id uuid;
|
|
21
|
+
v_existing_id uuid;
|
|
22
|
+
BEGIN
|
|
23
|
+
-- Resolve the cil_project type
|
|
24
|
+
SELECT id INTO v_cil_project_type_id
|
|
25
|
+
FROM public.types
|
|
26
|
+
WHERE slug = 'cil_project' AND kind = 'item'
|
|
27
|
+
LIMIT 1;
|
|
28
|
+
|
|
29
|
+
IF v_cil_project_type_id IS NULL THEN
|
|
30
|
+
RAISE NOTICE 'cil_project type not found — skipping CIL self-seed. Run install-app cortex first.';
|
|
31
|
+
RETURN;
|
|
32
|
+
END IF;
|
|
33
|
+
|
|
34
|
+
-- Resolve the system account (spine-system or the first account if not found)
|
|
35
|
+
SELECT id INTO v_spine_account_id
|
|
36
|
+
FROM public.accounts
|
|
37
|
+
WHERE slug = 'spine-system'
|
|
38
|
+
LIMIT 1;
|
|
39
|
+
|
|
40
|
+
IF v_spine_account_id IS NULL THEN
|
|
41
|
+
SELECT id INTO v_spine_account_id FROM public.accounts ORDER BY created_at LIMIT 1;
|
|
42
|
+
END IF;
|
|
43
|
+
|
|
44
|
+
IF v_spine_account_id IS NULL THEN
|
|
45
|
+
RAISE NOTICE 'No account found — skipping CIL self-seed.';
|
|
46
|
+
RETURN;
|
|
47
|
+
END IF;
|
|
48
|
+
|
|
49
|
+
-- Resolve the cortex app
|
|
50
|
+
SELECT id INTO v_cortex_app_id
|
|
51
|
+
FROM public.apps
|
|
52
|
+
WHERE slug = 'cortex'
|
|
53
|
+
LIMIT 1;
|
|
54
|
+
|
|
55
|
+
-- Check if the project already exists
|
|
56
|
+
SELECT id INTO v_existing_id
|
|
57
|
+
FROM public.items
|
|
58
|
+
WHERE title = 'spine-ia'
|
|
59
|
+
AND type_id = v_cil_project_type_id
|
|
60
|
+
AND account_id = v_spine_account_id
|
|
61
|
+
LIMIT 1;
|
|
62
|
+
|
|
63
|
+
IF v_existing_id IS NOT NULL THEN
|
|
64
|
+
RAISE NOTICE 'spine-ia CIL project already seeded (id: %). Skipping.', v_existing_id;
|
|
65
|
+
RETURN;
|
|
66
|
+
END IF;
|
|
67
|
+
|
|
68
|
+
-- Insert the project item
|
|
69
|
+
INSERT INTO public.items (
|
|
70
|
+
id,
|
|
71
|
+
type_id,
|
|
72
|
+
account_id,
|
|
73
|
+
app_id,
|
|
74
|
+
title,
|
|
75
|
+
description,
|
|
76
|
+
status,
|
|
77
|
+
is_active,
|
|
78
|
+
data,
|
|
79
|
+
created_at,
|
|
80
|
+
updated_at
|
|
81
|
+
) VALUES (
|
|
82
|
+
-- Fixed UUID so other tooling can reference it; change if collision occurs
|
|
83
|
+
'00000001-c11a-4a1e-0000-00000000001a',
|
|
84
|
+
v_cil_project_type_id,
|
|
85
|
+
v_spine_account_id,
|
|
86
|
+
v_cortex_app_id,
|
|
87
|
+
'spine-ia',
|
|
88
|
+
'The spine-ia monorepo — Spine framework core + Cortex CIL app',
|
|
89
|
+
'active',
|
|
90
|
+
true,
|
|
91
|
+
jsonb_build_object(
|
|
92
|
+
'kb_type', 'cil_project',
|
|
93
|
+
'project_id', '00000001-c11a-4a1e-0000-00000000001a',
|
|
94
|
+
'repo_path', '/Users/thistle/CascadeProjects/spine-ia',
|
|
95
|
+
'language_mix', 'TypeScript, SQL',
|
|
96
|
+
'description', 'The spine-ia monorepo — Spine framework core + Cortex CIL app',
|
|
97
|
+
'ingestion_status', 'not_started',
|
|
98
|
+
'file_count', 0,
|
|
99
|
+
'chunk_count', 0,
|
|
100
|
+
'last_ingested_at', NULL,
|
|
101
|
+
'globs', jsonb_build_array(
|
|
102
|
+
'custom/**/*.ts', 'custom/**/*.tsx',
|
|
103
|
+
'.framework/functions/**/*.ts',
|
|
104
|
+
'.framework/migrations/**/*.sql'
|
|
105
|
+
),
|
|
106
|
+
'exclude_globs', jsonb_build_array(
|
|
107
|
+
'node_modules/**', '.assembled/**', 'dist/**', 'build/**',
|
|
108
|
+
'**/*.test.ts', '**/*.spec.ts', '**/*.d.ts'
|
|
109
|
+
)
|
|
110
|
+
),
|
|
111
|
+
now(),
|
|
112
|
+
now()
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
RAISE NOTICE 'spine-ia CIL project seeded successfully (id: 00000001-c11a-4a1e-0000-00000000001a)';
|
|
116
|
+
END $$;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spine-framework",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.115",
|
|
4
4
|
"description": "Multi-tenant, modular application platform for modern SaaS systems",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,6 +36,11 @@
|
|
|
36
36
|
".framework/migrations/027_embedding_lifecycle.sql",
|
|
37
37
|
".framework/migrations/028_fix_message_data_permissions.sql",
|
|
38
38
|
".framework/migrations/029_tighten_support_triage_prompt.sql",
|
|
39
|
+
".framework/migrations/030_messages_updated_by.sql",
|
|
40
|
+
".framework/migrations/031_cil_vector_types.sql",
|
|
41
|
+
".framework/migrations/032_cil_agent_config.sql",
|
|
42
|
+
".framework/migrations/033_cil_chunk_schema_fields.sql",
|
|
43
|
+
".framework/migrations/034_cil_self_seed.sql",
|
|
39
44
|
".framework/public/",
|
|
40
45
|
".framework/scripts/",
|
|
41
46
|
".framework/seeds/",
|
|
@@ -92,7 +97,8 @@
|
|
|
92
97
|
"test:core": "vitest run .framework/tests/unit/core-isolation.test.ts",
|
|
93
98
|
"test:integration": "vitest run .framework/tests/integration",
|
|
94
99
|
"test:boundary": "bash scripts/boundary-check.sh",
|
|
95
|
-
"docs": "typedoc --entryPoints .framework/functions/_shared/index.ts --out docs/generated"
|
|
100
|
+
"docs": "typedoc --entryPoints .framework/functions/_shared/index.ts --out docs/generated",
|
|
101
|
+
"mcp": "tsx custom/apps/cortex/mcp/index.ts"
|
|
96
102
|
},
|
|
97
103
|
"dependencies": {
|
|
98
104
|
"@base-ui/react": "^1.4.1",
|
|
@@ -174,6 +180,7 @@
|
|
|
174
180
|
"ws": "^8.18.0"
|
|
175
181
|
},
|
|
176
182
|
"devDependencies": {
|
|
183
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
177
184
|
"@netlify/functions": "^2.8.2",
|
|
178
185
|
"@supabase/supabase-js": "^2.49.1",
|
|
179
186
|
"@tailwindcss/typography": "^0.5.19",
|