@vpxa/aikit 0.1.78 → 0.1.80
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/package.json +3 -2
- package/packages/dashboard/dist/assets/index-C6D-PCp0.js +1 -2
- package/packages/server/dist/index.js +1 -1
- package/packages/settings-ui/dist/assets/index-BlJqzH2g.js +1 -2
- package/packages/store/dist/index.d.ts +1 -6
- package/packages/store/dist/index.js +15 -15
- package/scaffold/definitions/exclusions.mjs +58 -0
- package/packages/dashboard/dist/assets/index-C6D-PCp0.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{t as e}from"./lance-store-jdHZp-V4.js";import{AIKIT_PATHS as t}from"../../core/dist/index.js";import{existsSync as n,mkdirSync as r
|
|
1
|
+
import{t as e}from"./lance-store-jdHZp-V4.js";import{AIKIT_PATHS as t}from"../../core/dist/index.js";import{existsSync as n,mkdirSync as r}from"node:fs";import{dirname as i,join as a}from"node:path";import o from"better-sqlite3";var s=class{db=null;dbPath;constructor(e){let n=e?.path??t.data;this.dbPath=a(n,`graph.db`)}async initialize(){let e=i(this.dbPath);n(e)||r(e,{recursive:!0}),this.db=new o(this.dbPath),this.configureDb(this.db),this.createTables(this.db),this.migrateSchema(this.db)}configureDb(e){e.pragma(`journal_mode = WAL`),e.pragma(`foreign_keys = ON`)}createTables(e){e.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
3
3
|
id TEXT PRIMARY KEY,
|
|
4
4
|
type TEXT NOT NULL,
|
|
@@ -9,7 +9,7 @@ import{t as e}from"./lance-store-jdHZp-V4.js";import{AIKIT_PATHS as t}from"../..
|
|
|
9
9
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
10
10
|
community TEXT
|
|
11
11
|
)
|
|
12
|
-
`),e.
|
|
12
|
+
`),e.exec(`
|
|
13
13
|
CREATE TABLE IF NOT EXISTS edges (
|
|
14
14
|
id TEXT PRIMARY KEY,
|
|
15
15
|
from_id TEXT NOT NULL,
|
|
@@ -21,7 +21,7 @@ import{t as e}from"./lance-store-jdHZp-V4.js";import{AIKIT_PATHS as t}from"../..
|
|
|
21
21
|
FOREIGN KEY (from_id) REFERENCES nodes(id) ON DELETE CASCADE,
|
|
22
22
|
FOREIGN KEY (to_id) REFERENCES nodes(id) ON DELETE CASCADE
|
|
23
23
|
)
|
|
24
|
-
`),e.
|
|
24
|
+
`),e.exec(`CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type)`),e.exec(`CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name)`),e.exec(`CREATE INDEX IF NOT EXISTS idx_nodes_source_path ON nodes(source_path)`),e.exec(`CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id)`),e.exec(`CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id)`),e.exec(`CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type)`),e.exec(`
|
|
25
25
|
CREATE TABLE IF NOT EXISTS processes (
|
|
26
26
|
id TEXT PRIMARY KEY,
|
|
27
27
|
entry_node_id TEXT NOT NULL,
|
|
@@ -30,7 +30,7 @@ import{t as e}from"./lance-store-jdHZp-V4.js";import{AIKIT_PATHS as t}from"../..
|
|
|
30
30
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
31
31
|
FOREIGN KEY (entry_node_id) REFERENCES nodes(id) ON DELETE CASCADE
|
|
32
32
|
)
|
|
33
|
-
`),e.
|
|
33
|
+
`),e.exec(`
|
|
34
34
|
CREATE TABLE IF NOT EXISTS process_steps (
|
|
35
35
|
process_id TEXT NOT NULL,
|
|
36
36
|
node_id TEXT NOT NULL,
|
|
@@ -39,37 +39,37 @@ import{t as e}from"./lance-store-jdHZp-V4.js";import{AIKIT_PATHS as t}from"../..
|
|
|
39
39
|
FOREIGN KEY (process_id) REFERENCES processes(id) ON DELETE CASCADE,
|
|
40
40
|
FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE
|
|
41
41
|
)
|
|
42
|
-
`),e.
|
|
42
|
+
`),e.exec(`CREATE INDEX IF NOT EXISTS idx_process_steps_node ON process_steps(node_id)`)}migrateSchema(e){for(let t of[`ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0`,`ALTER TABLE nodes ADD COLUMN community TEXT`])try{e.exec(t)}catch{}e.exec(`CREATE INDEX IF NOT EXISTS idx_nodes_community ON nodes(community)`)}getDb(){return this.db||(this.db=new o(this.dbPath),this.configureDb(this.db)),this.db}query(e,t=[]){return this.getDb().prepare(e).all(...t)}run(e,t=[]){this.getDb().prepare(e).run(...t)}async upsertNode(e){this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at, community)
|
|
43
43
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
44
44
|
ON CONFLICT(id) DO UPDATE SET
|
|
45
45
|
type = excluded.type, name = excluded.name, properties = excluded.properties,
|
|
46
46
|
source_record_id = excluded.source_record_id, source_path = excluded.source_path,
|
|
47
|
-
community = excluded.community`,[e.id,e.type,e.name,JSON.stringify(e.properties),e.sourceRecordId??null,e.sourcePath??null,e.createdAt??new Date().toISOString(),e.community??null])
|
|
47
|
+
community = excluded.community`,[e.id,e.type,e.name,JSON.stringify(e.properties),e.sourceRecordId??null,e.sourcePath??null,e.createdAt??new Date().toISOString(),e.community??null])}async upsertEdge(e){this.run(`INSERT INTO edges (id, from_id, to_id, type, weight, confidence, properties)
|
|
48
48
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
49
49
|
ON CONFLICT(id) DO UPDATE SET
|
|
50
50
|
from_id = excluded.from_id, to_id = excluded.to_id,
|
|
51
|
-
type = excluded.type, weight = excluded.weight, confidence = excluded.confidence, properties = excluded.properties`,[e.id,e.fromId,e.toId,e.type,e.weight??1,e.confidence??1,JSON.stringify(e.properties??{})])
|
|
51
|
+
type = excluded.type, weight = excluded.weight, confidence = excluded.confidence, properties = excluded.properties`,[e.id,e.fromId,e.toId,e.type,e.weight??1,e.confidence??1,JSON.stringify(e.properties??{})])}async upsertNodes(e){if(e.length===0)return;let t=this.getDb();t.exec(`BEGIN TRANSACTION`);try{for(let t of e)this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at, community)
|
|
52
52
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
53
53
|
ON CONFLICT(id) DO UPDATE SET
|
|
54
54
|
type = excluded.type, name = excluded.name, properties = excluded.properties,
|
|
55
55
|
source_record_id = excluded.source_record_id, source_path = excluded.source_path,
|
|
56
|
-
community = excluded.community`,[t.id,t.type,t.name,JSON.stringify(t.properties),t.sourceRecordId??null,t.sourcePath??null,t.createdAt??new Date().toISOString(),t.community??null]);t.
|
|
56
|
+
community = excluded.community`,[t.id,t.type,t.name,JSON.stringify(t.properties),t.sourceRecordId??null,t.sourcePath??null,t.createdAt??new Date().toISOString(),t.community??null]);t.exec(`COMMIT`)}catch(e){throw t.exec(`ROLLBACK`),e}}async upsertEdges(e){if(e.length===0)return;let t=this.getDb();t.pragma(`foreign_keys = OFF`),t.exec(`BEGIN TRANSACTION`);try{for(let t of e)this.run(`INSERT INTO edges (id, from_id, to_id, type, weight, confidence, properties)
|
|
57
57
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
58
58
|
ON CONFLICT(id) DO UPDATE SET
|
|
59
59
|
from_id = excluded.from_id, to_id = excluded.to_id,
|
|
60
|
-
type = excluded.type, weight = excluded.weight, confidence = excluded.confidence, properties = excluded.properties`,[t.id,t.fromId,t.toId,t.type,t.weight??1,t.confidence??1,JSON.stringify(t.properties??{})]);t.
|
|
60
|
+
type = excluded.type, weight = excluded.weight, confidence = excluded.confidence, properties = excluded.properties`,[t.id,t.fromId,t.toId,t.type,t.weight??1,t.confidence??1,JSON.stringify(t.properties??{})]);t.exec(`COMMIT`)}catch(e){throw t.exec(`ROLLBACK`),e}finally{t.pragma(`foreign_keys = ON`)}}async getNode(e){let t=this.query(`SELECT * FROM nodes WHERE id = ?`,[e]);return t.length>0?l(t[0]):null}async getNeighbors(e,t){let n=t?.direction??`both`,r=t?.edgeType,i=t?.limit??50,a=[],o=[],s=new Set;if(n===`outgoing`||n===`both`){let t=`
|
|
61
61
|
SELECT e.id AS edge_id, e.from_id, e.to_id, e.type AS edge_type, e.weight,
|
|
62
62
|
e.confidence AS edge_confidence, e.properties AS edge_props,
|
|
63
63
|
n.id AS node_id, n.type AS node_type, n.name AS node_name, n.properties AS node_props,
|
|
64
64
|
n.source_record_id AS node_src_rec, n.source_path AS node_src_path,
|
|
65
65
|
n.created_at AS node_created, n.community AS node_community
|
|
66
|
-
FROM edges e JOIN nodes n ON e.to_id = n.id WHERE e.from_id = ?`,n=[e];r&&(t+=` AND e.type = ?`,n.push(r)),t+=` LIMIT ?`,n.push(i);let c=this.query(t,n);for(let e of c)o.push(
|
|
66
|
+
FROM edges e JOIN nodes n ON e.to_id = n.id WHERE e.from_id = ?`,n=[e];r&&(t+=` AND e.type = ?`,n.push(r)),t+=` LIMIT ?`,n.push(i);let c=this.query(t,n);for(let e of c)o.push(d(e)),s.has(e.node_id)||(s.add(e.node_id),a.push(f(e)))}if(n===`incoming`||n===`both`){let t=`
|
|
67
67
|
SELECT e.id AS edge_id, e.from_id, e.to_id, e.type AS edge_type, e.weight,
|
|
68
68
|
e.confidence AS edge_confidence, e.properties AS edge_props,
|
|
69
69
|
n.id AS node_id, n.type AS node_type, n.name AS node_name, n.properties AS node_props,
|
|
70
70
|
n.source_record_id AS node_src_rec, n.source_path AS node_src_path,
|
|
71
71
|
n.created_at AS node_created, n.community AS node_community
|
|
72
|
-
FROM edges e JOIN nodes n ON e.from_id = n.id WHERE e.to_id = ?`,n=[e];r&&(t+=` AND e.type = ?`,n.push(r)),t+=` LIMIT ?`,n.push(i);let c=this.query(t,n);for(let e of c)o.push(
|
|
72
|
+
FROM edges e JOIN nodes n ON e.from_id = n.id WHERE e.to_id = ?`,n=[e];r&&(t+=` AND e.type = ?`,n.push(r)),t+=` LIMIT ?`,n.push(i);let c=this.query(t,n);for(let e of c)o.push(d(e)),s.has(e.node_id)||(s.add(e.node_id),a.push(f(e)))}return{nodes:a,edges:o}}async traverse(e,t){let n=t?.maxDepth??2,r=t?.direction??`both`,i=t?.edgeType,a=t?.limit??50,o=new Map,s=new Map,c=new Set,l=[{nodeId:e,depth:0}];for(;l.length>0&&o.size<a;){let e=l.shift();if(!e||c.has(e.nodeId)||e.depth>n)continue;c.add(e.nodeId);let t=await this.getNeighbors(e.nodeId,{direction:r,edgeType:i,limit:a-o.size});for(let r of t.nodes)o.has(r.id)||(o.set(r.id,r),e.depth+1<n&&l.push({nodeId:r.id,depth:e.depth+1}));for(let e of t.edges)s.set(e.id,e)}return{nodes:[...o.values()],edges:[...s.values()]}}async findNodes(e){let t=[],n=[];e.type&&(t.push(`type = ?`),n.push(e.type)),e.namePattern&&(t.push(`name LIKE ?`),n.push(`%${e.namePattern}%`)),e.sourcePath&&(t.push(`source_path = ?`),n.push(e.sourcePath));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit??100;return this.query(`SELECT * FROM nodes ${r} LIMIT ?`,[...n,i]).map(e=>l(e))}async findEdges(e){let t=[],n=[];e.type&&(t.push(`type = ?`),n.push(e.type)),e.fromId&&(t.push(`from_id = ?`),n.push(e.fromId)),e.toId&&(t.push(`to_id = ?`),n.push(e.toId));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit??100;return this.query(`SELECT * FROM edges ${r} LIMIT ?`,[...n,i]).map(e=>u(e))}async deleteNode(e){let t=this.getDb();t.exec(`BEGIN TRANSACTION`);try{this.run(`DELETE FROM edges WHERE from_id = ? OR to_id = ?`,[e,e]),this.run(`DELETE FROM nodes WHERE id = ?`,[e]),t.exec(`COMMIT`)}catch(e){throw t.exec(`ROLLBACK`),e}}async deleteBySourcePath(e){let t=this.query(`SELECT id FROM nodes WHERE source_path = ?`,[e]);if(t.length===0)return 0;let n=this.getDb();n.exec(`BEGIN TRANSACTION`);try{for(let e of t)this.run(`DELETE FROM edges WHERE from_id = ? OR to_id = ?`,[e.id,e.id]);this.run(`DELETE FROM nodes WHERE source_path = ?`,[e]),n.exec(`COMMIT`)}catch(e){throw n.exec(`ROLLBACK`),e}return t.length}async clear(){this.run(`DELETE FROM process_steps`),this.run(`DELETE FROM processes`),this.run(`DELETE FROM edges`),this.run(`DELETE FROM nodes`)}async getStats(){let e=this.query(`SELECT COUNT(*) as count FROM nodes`)[0]?.count??0,t=this.query(`SELECT COUNT(*) as count FROM edges`)[0]?.count??0,n=this.query(`SELECT type, COUNT(*) as count FROM nodes GROUP BY type`),r={};for(let e of n)r[e.type]=e.count;let i=this.query(`SELECT type, COUNT(*) as count FROM edges GROUP BY type`),a={};for(let e of i)a[e.type]=e.count;return{nodeCount:e,edgeCount:t,nodeTypes:r,edgeTypes:a}}async validate(){let e=await this.getStats(),t=this.query(`SELECT e.id AS edgeId,
|
|
73
73
|
CASE
|
|
74
74
|
WHEN n1.id IS NULL THEN e.from_id
|
|
75
75
|
WHEN n2.id IS NULL THEN e.to_id
|
|
@@ -81,10 +81,10 @@ import{t as e}from"./lance-store-jdHZp-V4.js";import{AIKIT_PATHS as t}from"../..
|
|
|
81
81
|
FROM nodes n
|
|
82
82
|
LEFT JOIN edges e1 ON n.id = e1.from_id
|
|
83
83
|
LEFT JOIN edges e2 ON n.id = e2.to_id
|
|
84
|
-
WHERE e1.id IS NULL AND e2.id IS NULL`).map(e=>e.id);return{valid:t.length===0,orphanNodes:n,danglingEdges:t,stats:e}}async setNodeCommunity(e,t){this.run(`UPDATE nodes SET community = ? WHERE id = ?`,[t,e])
|
|
84
|
+
WHERE e1.id IS NULL AND e2.id IS NULL`).map(e=>e.id);return{valid:t.length===0,orphanNodes:n,danglingEdges:t,stats:e}}async setNodeCommunity(e,t){this.run(`UPDATE nodes SET community = ? WHERE id = ?`,[t,e])}async detectCommunities(){let e=this.query(`SELECT id FROM nodes`),t=new Map;for(let n of e)t.set(n.id,n.id);for(let n=0;n<10;n++){let n=!1,r=new Map(t);for(let i of e){let e=this.query(`SELECT to_id AS neighbor_id FROM edges WHERE from_id = ?
|
|
85
85
|
UNION
|
|
86
|
-
SELECT from_id AS neighbor_id FROM edges WHERE to_id = ?`,[i.id,i.id]),a=new Map,o=t.get(i.id)??i.id;a.set(o,1);for(let n of e){let e=t.get(n.neighbor_id)??n.neighbor_id;a.set(e,(a.get(e)??0)+1)}let s=o,c=0;for(let[e,t]of a)(t>c||t===c&&e<s)&&(c=t,s=e);o!==s&&(r.set(i.id,s),n=!0)}t.clear();for(let[e,n]of r)t.set(e,n);if(!n)break}let n=this.
|
|
87
|
-
VALUES (?, ?, ?, '{}', ?)`,[a,e,t,o]);for(let e=0;e<n.length;e++)this.run(`INSERT INTO process_steps (process_id, node_id, step_order) VALUES (?, ?, ?)`,[a,n[e],e]);s.
|
|
86
|
+
SELECT from_id AS neighbor_id FROM edges WHERE to_id = ?`,[i.id,i.id]),a=new Map,o=t.get(i.id)??i.id;a.set(o,1);for(let n of e){let e=t.get(n.neighbor_id)??n.neighbor_id;a.set(e,(a.get(e)??0)+1)}let s=o,c=0;for(let[e,t]of a)(t>c||t===c&&e<s)&&(c=t,s=e);o!==s&&(r.set(i.id,s),n=!0)}t.clear();for(let[e,n]of r)t.set(e,n);if(!n)break}let n=this.getDb();n.exec(`BEGIN TRANSACTION`);try{for(let[e,n]of t)this.run(`UPDATE nodes SET community = ? WHERE id = ?`,[n,e]);n.exec(`COMMIT`)}catch(e){throw n.exec(`ROLLBACK`),e}let r={};for(let[e,n]of t)r[n]||(r[n]=[]),r[n].push(e);return r}async traceProcess(e,t){let n=[],r=new Set,i=[e];for(;i.length>0;){let e=i.shift();if(!e||r.has(e))continue;r.add(e),n.push(e);let t=this.query(`SELECT to_id FROM edges WHERE from_id = ? AND type = 'calls'`,[e]);for(let e of t)r.has(e.to_id)||i.push(e.to_id)}let a=`proc_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,o=new Date().toISOString(),s=this.getDb();s.exec(`BEGIN TRANSACTION`);try{this.run(`INSERT INTO processes (id, entry_node_id, label, properties, created_at)
|
|
87
|
+
VALUES (?, ?, ?, '{}', ?)`,[a,e,t,o]);for(let e=0;e<n.length;e++)this.run(`INSERT INTO process_steps (process_id, node_id, step_order) VALUES (?, ?, ?)`,[a,n[e],e]);s.exec(`COMMIT`)}catch(e){throw s.exec(`ROLLBACK`),e}return{id:a,entryNodeId:e,label:t,properties:{},steps:n,createdAt:o}}async getProcesses(e){let t;t=e?this.query(`SELECT DISTINCT p.id, p.entry_node_id, p.label, p.properties, p.created_at
|
|
88
88
|
FROM processes p
|
|
89
89
|
JOIN process_steps ps ON p.id = ps.process_id
|
|
90
|
-
WHERE ps.node_id = ?`,[e]):this.query(`SELECT * FROM processes`);let n=[];for(let e of t){let t=this.query(`SELECT node_id FROM process_steps WHERE process_id = ? ORDER BY step_order`,[e.id]);n.push({id:e.id,entryNodeId:e.entry_node_id,label:e.label,properties:
|
|
90
|
+
WHERE ps.node_id = ?`,[e]):this.query(`SELECT * FROM processes`);let n=[];for(let e of t){let t=this.query(`SELECT node_id FROM process_steps WHERE process_id = ? ORDER BY step_order`,[e.id]);n.push({id:e.id,entryNodeId:e.entry_node_id,label:e.label,properties:c(e.properties),steps:t.map(e=>e.node_id),createdAt:e.created_at})}return n}async deleteProcess(e){let t=this.getDb();t.exec(`BEGIN TRANSACTION`);try{this.run(`DELETE FROM process_steps WHERE process_id = ?`,[e]),this.run(`DELETE FROM processes WHERE id = ?`,[e]),t.exec(`COMMIT`)}catch(e){throw t.exec(`ROLLBACK`),e}}async depthGroupedTraversal(e,t=3,n){let r=n?.direction??`both`,i=n?.edgeType,a=n?.limit??100,o={},s=new Set;s.add(e);let c=[e];for(let e=1;e<=t;e++){let t=[],n=[];for(let e of c){let o=await this.getNeighbors(e,{direction:r,edgeType:i,limit:a});for(let e of o.nodes)s.has(e.id)||(s.add(e.id),t.push(e.id),n.push(e))}if(n.length>0&&(o[e]=n),c=t,c.length===0||s.size>=a)break}return o}async getCohesionScore(e){let t=this.query(`SELECT id FROM nodes WHERE community = ?`,[e]);if(t.length===0)return 0;let n=new Set(t.map(e=>e.id)),r=t.map(()=>`?`).join(`,`),i=t.map(e=>e.id),a=this.query(`SELECT from_id, to_id FROM edges WHERE from_id IN (${r}) OR to_id IN (${r})`,[...i,...i]);if(a.length===0)return 0;let o=0;for(let e of a)n.has(e.from_id)&&n.has(e.to_id)&&o++;return o/a.length}async getSymbol360(e){let t=await this.getNode(e);if(!t)throw Error(`Node '${e}' not found`);let n=await this.findEdges({toId:e}),r=await this.findEdges({fromId:e}),i=await this.getProcesses(e);return{node:t,incoming:n,outgoing:r,community:t.community??null,processes:i}}async close(){this.db&&=(this.db.close(),null)}};function c(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function l(e){return{id:e.id,type:e.type,name:e.name,properties:c(e.properties),sourceRecordId:e.source_record_id??void 0,sourcePath:e.source_path??void 0,createdAt:e.created_at,community:e.community??void 0}}function u(e){return{id:e.id,fromId:e.from_id,toId:e.to_id,type:e.type,weight:e.weight??1,confidence:e.confidence??1,properties:c(e.properties)}}function d(e){return{id:e.edge_id,fromId:e.from_id,toId:e.to_id,type:e.edge_type,weight:e.weight??1,confidence:e.edge_confidence??1,properties:c(e.edge_props??`{}`)}}function f(e){return{id:e.node_id,type:e.node_type,name:e.node_name,properties:c(e.node_props??`{}`),sourceRecordId:e.node_src_rec??void 0,sourcePath:e.node_src_path??void 0,createdAt:e.node_created,community:e.node_community??void 0}}async function p(e){switch(e.backend){case`lancedb`:{let{LanceStore:t}=await import(`./lance-store-jdHZp-V4.js`).then(e=>e.n);return new t({path:e.path})}default:throw Error(`Unknown store backend: "${e.backend}". Supported: lancedb`)}}export{e as LanceStore,s as SqliteGraphStore,p as createStore};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permanent Exclusions — things aikit intentionally will NOT do.
|
|
3
|
+
*
|
|
4
|
+
* Each exclusion includes rationale grounded in the Bitter Lesson:
|
|
5
|
+
* systems should leverage computation over hand-crafted features.
|
|
6
|
+
* These exclusions are injected into copilot-instructions.md.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const PERMANENT_EXCLUSIONS = [
|
|
10
|
+
{
|
|
11
|
+
name: 'Hard-coded lint rules',
|
|
12
|
+
rationale:
|
|
13
|
+
'Project-specific linting belongs in ESLint or Biome config, not baked into agent instructions. Configurable tooling and automated checks scale better than hand-crafted rules embedded in prompts.',
|
|
14
|
+
bitterLessonSafe: true,
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
name: 'Framework-specific boilerplate generation',
|
|
19
|
+
rationale:
|
|
20
|
+
'Framework CLIs and IDE scaffolds already generate boilerplate from evolving upstream knowledge. Delegating to those computational systems is safer than freezing hand-written templates into aikit instructions.',
|
|
21
|
+
bitterLessonSafe: true,
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
{
|
|
25
|
+
name: 'Git workflow enforcement',
|
|
26
|
+
rationale:
|
|
27
|
+
'Branch policies, commit formatting, and merge gates belong in git hooks and CI where they can be enforced automatically. Reliable computation beats informal agent-side reminders and hand-crafted behavior rules.',
|
|
28
|
+
bitterLessonSafe: true,
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
name: 'IDE-specific keybinding and config guidance',
|
|
33
|
+
rationale:
|
|
34
|
+
'Editor shortcuts, panel layouts, and workspace settings are IDE concerns that change across clients and teams. Runtime tooling and local editor config are the right computational layer, not static agent instructions.',
|
|
35
|
+
bitterLessonSafe: true,
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
{
|
|
39
|
+
name: 'Package manager lock file manipulation',
|
|
40
|
+
rationale:
|
|
41
|
+
'Lock files should be produced by the package manager and verified in CI or release pipelines, not manually curated by agent policy. Deterministic tool execution is more robust than hand-crafted lockfile guidance.',
|
|
42
|
+
bitterLessonSafe: true,
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
name: 'Hard-coded file naming conventions',
|
|
47
|
+
rationale:
|
|
48
|
+
'Naming rules vary by repository and should live in project generators, linters, or review automation. Letting configurable computation enforce conventions scales better than embedding brittle file-name doctrine in prompts.',
|
|
49
|
+
bitterLessonSafe: true,
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
name: 'Runtime environment variable validation',
|
|
54
|
+
rationale:
|
|
55
|
+
'Environment validation belongs in application startup code, schemas, and deployment checks where real runtime state is available. Computed validation with executable code outperforms hand-crafted agent assumptions about env shape.',
|
|
56
|
+
bitterLessonSafe: true,
|
|
57
|
+
},
|
|
58
|
+
];
|