@vpxa/aikit 0.1.145 → 0.1.146
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 +1 -1
- package/packages/server/dist/index.js +1 -1
- package/packages/server/dist/{server-Mioq3dZQ.js → server-3YlZan29.js} +164 -164
- package/packages/store/dist/index.js +2 -2
- package/packages/store/dist/{sqlite-vec-store-C-GvCcJH.js → sqlite-vec-store-CrvQ06f8.js} +6 -6
- package/scaffold/dist/definitions/bodies.mjs +12 -0
- package/scaffold/dist/definitions/flows.mjs +114 -3
- package/scaffold/dist/definitions/hooks.mjs +1 -1
- package/scaffold/dist/definitions/skills/requirements-clarity.mjs +81 -297
- package/scaffold/dist/definitions/skills/session-handoff.mjs +258 -64
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{i as e,r as t,t as n}from"./sqlite-vec-store-
|
|
1
|
+
import{i as e,r as t,t as n}from"./sqlite-vec-store-CrvQ06f8.js";import{existsSync as r,mkdirSync as i}from"node:fs";import{dirname as a,join as o}from"node:path";import{AIKIT_PATHS as s}from"../../core/dist/index.js";var c=class{adapter=null;reopenPromise=null;dbPath;externalAdapter;constructor(e={}){if(e.adapter)this.adapter=e.adapter,this.externalAdapter=!0,this.dbPath=``;else{let t=e.path??s.data;this.dbPath=o(t,`graph.db`),this.externalAdapter=!1}}async initialize(){if(this.externalAdapter){let e=this.getAdapter();this.createTables(e),this.migrateSchema(e),e.flush();return}let t=a(this.dbPath);r(t)||i(t,{recursive:!0}),this.adapter=await e(this.dbPath),this.configureAdapter(this.adapter),this.createTables(this.adapter),this.migrateSchema(this.adapter),this.adapter.flush()}configureAdapter(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,
|
|
@@ -87,4 +87,4 @@ import{i as e,r as t,t as n}from"./sqlite-vec-store-C-GvCcJH.js";import{existsSy
|
|
|
87
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`),s.flush()}catch(e){throw s.exec(`ROLLBACK`),e}return{id:a,entryNodeId:e,label:t,properties:{},steps:n,createdAt:o}}async getProcesses(e){await this.ensureOpen();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:l(e.properties),steps:t.map(e=>e.node_id),createdAt:e.created_at})}return n}async deleteProcess(e){await this.ensureOpen();let t=this.getAdapter();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`),t.flush()}catch(e){throw t.exec(`ROLLBACK`),e}}async depthGroupedTraversal(e,t=3,n){await this.ensureOpen();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){await this.ensureOpen();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}}releaseMemory(){if(this.adapter)try{this.adapter.exec(`PRAGMA shrink_memory`),this.adapter.exec(`PRAGMA wal_checkpoint(TRUNCATE)`)}catch{}}async close(){this.adapter&&=(this.externalAdapter||this.adapter.close(),null)}};function l(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function u(e){return{id:e.id,type:e.type,name:e.name,properties:l(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 d(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:l(e.properties)}}function f(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:l(e.edge_props??`{}`)}}function p(e){return{id:e.node_id,type:e.node_type,name:e.node_name,properties:l(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 m(e){switch(e.backend){case`lancedb`:{let{LanceStore:t}=await import(`./lance-store-DZkqHpPW.js`);return new t({path:e.path})}case`sqlite-vec`:{let{SqliteVecStore:t}=await import(`./sqlite-vec-store-
|
|
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:l(e.properties),steps:t.map(e=>e.node_id),createdAt:e.created_at})}return n}async deleteProcess(e){await this.ensureOpen();let t=this.getAdapter();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`),t.flush()}catch(e){throw t.exec(`ROLLBACK`),e}}async depthGroupedTraversal(e,t=3,n){await this.ensureOpen();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){await this.ensureOpen();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}}releaseMemory(){if(this.adapter)try{this.adapter.exec(`PRAGMA shrink_memory`),this.adapter.exec(`PRAGMA wal_checkpoint(TRUNCATE)`)}catch{}}async close(){this.adapter&&=(this.externalAdapter||this.adapter.close(),null)}};function l(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function u(e){return{id:e.id,type:e.type,name:e.name,properties:l(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 d(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:l(e.properties)}}function f(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:l(e.edge_props??`{}`)}}function p(e){return{id:e.node_id,type:e.node_type,name:e.node_name,properties:l(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 m(e){switch(e.backend){case`lancedb`:{let{LanceStore:t}=await import(`./lance-store-DZkqHpPW.js`);return new t({path:e.path})}case`sqlite-vec`:{let{SqliteVecStore:t}=await import(`./sqlite-vec-store-CrvQ06f8.js`).then(e=>e.n);return new t({path:e.path,adapter:e.adapter,embeddingDim:e.embeddingDim})}default:{let t=e.backend;throw Error(`Unknown store backend: "${t}". Supported: lancedb, sqlite-vec`)}}}export{c as SqliteGraphStore,n as SqliteVecStore,t as createSqlJsAdapter,e as createSqliteAdapter,m as createStore};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as n,readFileSync as r,renameSync as i,unlinkSync as a,writeFileSync as o}from"node:fs";import{EMBEDDING_DEFAULTS as
|
|
1
|
+
import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as n,readFileSync as r,renameSync as i,unlinkSync as a,writeFileSync as o}from"node:fs";import{dirname as s}from"node:path";import{EMBEDDING_DEFAULTS as c,SEARCH_DEFAULTS as l,STORE_DEFAULTS as u,createLogger as d,serializeError as f,sourceTypeContentTypes as p}from"../../core/dist/index.js";var m=Object.defineProperty,h=(e,t)=>{let n={};for(var r in e)m(n,r,{get:e[r],enumerable:!0});return t||m(n,Symbol.toStringTag,{value:`Module`}),n},g=e(import.meta.url);const _=d(`sqlite-adapter`),v=e(import.meta.url);var y=class{type=`better-sqlite3`;vectorCapable=!1;db=null;stmtCache=new Map;async open(e){let t;try{t=v(`better-sqlite3`)}catch(e){throw Error(`better-sqlite3 native binding unavailable: ${e instanceof Error?e.message:String(e)}`)}this.db=new t(e),this.db.pragma(`journal_mode = WAL`),this.db.pragma(`foreign_keys = ON`),this.db.pragma(`synchronous = NORMAL`);try{v(`sqlite-vec`).load(this.db),this.vectorCapable=!0,_.info(`sqlite-vec extension loaded`)}catch(e){this.vectorCapable=!1,_.warn(`sqlite-vec extension failed to load; vector search disabled`,f(e))}}exec(e){this.getDb().exec(e)}pragma(e){this.getDb().pragma(e)}queryAll(e,t=[]){let n=this.prepareCached(e);return t.length>0?n.all(...t):n.all()}run(e,t=[]){let n=this.prepareCached(e);t.length>0?n.run(...t):n.run()}flush(){}close(){this.db&&=(this.stmtCache.clear(),this.db.close(),null)}getDb(){if(!this.db)throw Error(`BetterSqlite3Adapter: database not opened`);return this.db}prepareCached(e){let t=this.stmtCache.get(e);if(t)return t;let n=this.getDb().prepare(e);return this.stmtCache.set(e,n),n}};function b(e){return v.resolve(`sql.js/dist/${e}`)}var x=class{type=`sql.js`;vectorCapable=!1;db=null;dbPath=``;dirty=!1;inTransaction=!1;async open(e){this.dbPath=e;let n=(await import(`sql.js`)).default,i=await n({locateFile:e=>b(e)});if(t(e)){let t=r(e);this.db=new i.Database(t)}else this.db=new i.Database}exec(e){let t=e.trimStart().toUpperCase();this.getDb().run(e),t.startsWith(`BEGIN`)?this.inTransaction=!0:(t.startsWith(`COMMIT`)||t.startsWith(`ROLLBACK`))&&(this.inTransaction=!1),this.dirty=!0}pragma(e){this.getDb().exec(`PRAGMA ${e}`)}queryAll(e,t=[]){let n=this.getDb().prepare(e);try{t.length>0&&n.bind(t);let e=[];for(;n.step();)e.push(n.getAsObject());return e}finally{n.free()}}run(e,t=[]){let n=this.getDb(),r=e.trimStart().toUpperCase(),i=!this.inTransaction&&(r.startsWith(`INSERT`)||r.startsWith(`UPDATE`));i&&n.run(`SAVEPOINT fk_check`);try{if(t.length>0){let r=n.prepare(e);try{r.bind(t),r.step()}finally{r.free()}}else n.run(e);if(i){if(n.exec(`PRAGMA foreign_key_check`).length>0)throw n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`),Error(`FOREIGN KEY constraint failed`);n.run(`RELEASE fk_check`)}}catch(e){if(i)try{n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`)}catch{}throw e}this.dirty=!0}flush(){if(!this.dirty||!this.db)return;let e=this.db.export(),r=`${this.dbPath}.tmp`,a=s(this.dbPath);a&&!t(a)&&n(a,{recursive:!0}),o(r,Buffer.from(e)),i(r,this.dbPath),this.dirty=!1}close(){if(this.db){let e=this.db,t;try{this.flush()}catch(e){t=e;try{a(`${this.dbPath}.tmp`)}catch{}}try{e.close()}finally{this.db=null}if(t)throw t}}getDb(){if(!this.db)throw Error(`SqlJsAdapter: database not opened`);return this.db}};async function S(){try{let{execSync:e}=await import(`node:child_process`),{createRequire:t}=await import(`node:module`),n=t(import.meta.url).resolve(`better-sqlite3/package.json`).replace(/[\\/]package\.json$/,``).replace(/[\\/]node_modules[\\/]better-sqlite3$/,``);return _.info(`Attempting native module rebuild for better-sqlite3`,{cwd:n}),e(`npm rebuild better-sqlite3`,{cwd:n,stdio:`pipe`,timeout:6e4}),_.info(`Native module rebuild completed successfully`),!0}catch(e){return _.warn(`Native module rebuild failed — continuing with sql.js fallback`,f(e)),!1}}let C=!1;async function w(e){let t=new y;try{return await t.open(e),t}catch(t){let n=t instanceof Error?t.message:String(t);if(/NODE_MODULE_VERSION/.test(n)&&await S()){let t=new y;try{return await t.open(e),_.info(`better-sqlite3 recovered after native module rebuild`),t}catch{}}C||(C=!0,_.warn(`[aikit] better-sqlite3 unavailable — falling back to sql.js (vector search disabled). Reinstall with prebuild support or rebuild from source to enable vector search.`,f(t)))}let n=new x;try{return await n.open(e),n}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`[aikit] SQLite adapter "sql.js" failed to load: ${t}`)}}async function T(e){let t=new x;return await t.open(e),t}var E=h({SqliteVecStore:()=>M});function D(e){let t=0;for(let n=0;n<e.length;n++){let r=e[n]<0?-e[n]:e[n];r>t&&(t=r)}let n=new Int8Array(e.length);if(t===0)return Buffer.from(n.buffer,n.byteOffset,n.byteLength);let r=127/t;for(let t=0;t<e.length;t++){let i=Math.round(e[t]*r);n[t]=i<-127?-127:i>127?127:i}return Buffer.from(n.buffer,n.byteOffset,n.byteLength)}const O=/^[\w.\-/ ]+$/,k=d(`sqlite-vec-store`);function A(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function j(e,t){if(!O.test(e))throw Error(`Invalid ${t} filter value: contains disallowed characters`);return e}var M=class{adapter=null;externalAdapter;dbPath;embeddingDim;coarseDim;vectorEnabled=!1;ftsEnabled=!1;warnedVectorDisabled=!1;_draining=!1;_priorityQueue=[];_normalQueue=[];_onCloseHooks=[];constructor(e={}){this.embeddingDim=e.embeddingDim??c.dimensions,this.coarseDim=Math.min(128,this.embeddingDim),e.adapter?(this.adapter=e.adapter,this.externalAdapter=!0,this.dbPath=``):(this.dbPath=e.path??`${u.path}/aikit.db`,this.externalAdapter=!1)}async initialize(){if(!this.adapter){let e=s(this.dbPath);t(e)||n(e,{recursive:!0}),this.adapter=await w(this.dbPath)}this.vectorEnabled=this.adapter.vectorCapable,this.createKnowledgeTable(),this.createFtsTable(),this.vectorEnabled?this.ensureVecTable():this.warnedVectorDisabled||(this.warnedVectorDisabled=!0,k.warn(`SqliteVecStore: vector search disabled (sqlite-vec extension not loaded). Hybrid search will return FTS-only results.`))}getDiagnostics(){let e=this.adapter,t=e?e.constructor.name:`unknown`,n=null,r=this.externalAdapter?``:this.dbPath;if(r)try{let{statSync:e}=g(`node:fs`);n=e(r).size}catch{n=null}return{adapterType:t,vectorSearchEnabled:this.vectorEnabled,ftsEnabled:this.ftsEnabled,degradedMode:!this.vectorEnabled,dbPath:r,dbSizeBytes:n,embeddingDim:this.embeddingDim,vectorDtype:`int8`}}createKnowledgeTable(){let e=this.getAdapter();e.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS knowledge (
|
|
3
3
|
id TEXT PRIMARY KEY,
|
|
4
4
|
content TEXT NOT NULL,
|
|
@@ -23,7 +23,7 @@ import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as
|
|
|
23
23
|
content,
|
|
24
24
|
tokenize = 'unicode61 remove_diacritics 2'
|
|
25
25
|
)
|
|
26
|
-
`),this.ftsEnabled=!0}catch(e){this.ftsEnabled=!1,k.warn(`FTS5 unavailable — keyword search disabled`,
|
|
26
|
+
`),this.ftsEnabled=!0}catch(e){this.ftsEnabled=!1,k.warn(`FTS5 unavailable — keyword search disabled`,f(e))}}ensureVecTable(){let e=this.getAdapter(),t=e.queryAll(`SELECT name, sql FROM sqlite_master WHERE type='table' AND name='vec_knowledge'`);if(t.length>0){let n=t[0].sql??``,r=n.match(/(?:float|int8)\[(\d+)\]/i),i=r?Number(r[1]):null,a=/int8\[/i.test(n);(i!==null&&i!==this.embeddingDim||!a)&&(k.warn(`Vec table schema mismatch — dropping for recreation`,{existingDim:i,newDim:this.embeddingDim,wasInt8:a}),e.exec(`DROP TABLE vec_knowledge`))}e.exec(`
|
|
27
27
|
CREATE VIRTUAL TABLE IF NOT EXISTS vec_knowledge USING vec0(
|
|
28
28
|
embedding int8[${this.embeddingDim}] distance_metric=cosine,
|
|
29
29
|
+knowledge_id TEXT
|
|
@@ -51,7 +51,7 @@ import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as
|
|
|
51
51
|
origin = excluded.origin,
|
|
52
52
|
tags = excluded.tags,
|
|
53
53
|
category = excluded.category,
|
|
54
|
-
version = excluded.version`,[e.id,e.content,e.sourcePath,e.contentType,e.headingPath??``,e.chunkIndex,e.totalChunks,e.startLine,e.endLine,e.fileHash,e.contentHash??``,e.indexedAt,e.origin,JSON.stringify(e.tags??[]),e.category??``,e.version])}async _upsertImpl(e,t){let n=this.getAdapter();n.exec(`BEGIN`);try{for(let r=0;r<e.length;r++){let i=e[r];if(this.upsertKnowledgeRow(i),this.ftsEnabled&&(n.run(`DELETE FROM knowledge_fts WHERE id = ?`,[i.id]),n.run(`INSERT INTO knowledge_fts (id, content) VALUES (?, ?)`,[i.id,i.content])),this.vectorEnabled&&(n.run(`DELETE FROM vec_knowledge WHERE knowledge_id = ?`,[i.id]),n.run(`INSERT INTO vec_knowledge (embedding, knowledge_id) VALUES (vec_int8(?), ?)`,[D(t[r]),i.id]),this.coarseDim<this.embeddingDim)){let e=t[r].subarray(0,this.coarseDim);n.run(`DELETE FROM vec_knowledge_coarse WHERE knowledge_id = ?`,[i.id]),n.run(`INSERT INTO vec_knowledge_coarse (embedding, knowledge_id) VALUES (vec_int8(?), ?)`,[D(e),i.id])}}n.exec(`COMMIT`)}catch(e){try{n.exec(`ROLLBACK`)}catch{}throw e}n.flush()}async search(e,t){if(e.length===0)return[];if(!this.vectorEnabled)return this.warnedVectorDisabled||(this.warnedVectorDisabled=!0,k.warn(`search() called but vector backend is disabled — returning []`)),[];let n=this.getAdapter(),r=t?.limit??
|
|
54
|
+
version = excluded.version`,[e.id,e.content,e.sourcePath,e.contentType,e.headingPath??``,e.chunkIndex,e.totalChunks,e.startLine,e.endLine,e.fileHash,e.contentHash??``,e.indexedAt,e.origin,JSON.stringify(e.tags??[]),e.category??``,e.version])}async _upsertImpl(e,t){let n=this.getAdapter();n.exec(`BEGIN`);try{for(let r=0;r<e.length;r++){let i=e[r];if(this.upsertKnowledgeRow(i),this.ftsEnabled&&(n.run(`DELETE FROM knowledge_fts WHERE id = ?`,[i.id]),n.run(`INSERT INTO knowledge_fts (id, content) VALUES (?, ?)`,[i.id,i.content])),this.vectorEnabled&&(n.run(`DELETE FROM vec_knowledge WHERE knowledge_id = ?`,[i.id]),n.run(`INSERT INTO vec_knowledge (embedding, knowledge_id) VALUES (vec_int8(?), ?)`,[D(t[r]),i.id]),this.coarseDim<this.embeddingDim)){let e=t[r].subarray(0,this.coarseDim);n.run(`DELETE FROM vec_knowledge_coarse WHERE knowledge_id = ?`,[i.id]),n.run(`INSERT INTO vec_knowledge_coarse (embedding, knowledge_id) VALUES (vec_int8(?), ?)`,[D(e),i.id])}}n.exec(`COMMIT`)}catch(e){try{n.exec(`ROLLBACK`)}catch{}throw e}n.flush()}async search(e,t){if(e.length===0)return[];if(!this.vectorEnabled)return this.warnedVectorDisabled||(this.warnedVectorDisabled=!0,k.warn(`search() called but vector backend is disabled — returning []`)),[];let n=this.getAdapter(),r=t?.limit??l.maxResults,i=t?.minScore??l.minScore,a=r*4,o=`
|
|
55
55
|
SELECT k.*, v.distance AS _distance
|
|
56
56
|
FROM (
|
|
57
57
|
SELECT knowledge_id, distance
|
|
@@ -64,7 +64,7 @@ import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as
|
|
|
64
64
|
${this.buildFilterSqlSuffix(t)}
|
|
65
65
|
ORDER BY v.distance ASC
|
|
66
66
|
LIMIT ?
|
|
67
|
-
`,s;try{s=n.queryAll(o,[D(e),a,r])}catch(e){return k.warn(`vector search failed`,
|
|
67
|
+
`,s;try{s=n.queryAll(o,[D(e),a,r])}catch(e){return k.warn(`vector search failed`,f(e)),[]}return s.map(e=>({record:this.fromRow(e),score:1-(e._distance??1)})).filter(e=>e.score>=i).slice(0,r)}async coarseSearch(e,t){if(!this.vectorEnabled||this.coarseDim>=this.embeddingDim)return this.search(e,t);let n=this.getAdapter(),r=t?.limit??l.maxResults,i=t?.minScore??l.minScore,a=r*4,o=e.subarray(0,this.coarseDim),s=`
|
|
68
68
|
SELECT k.*, v.distance AS _distance
|
|
69
69
|
FROM (
|
|
70
70
|
SELECT knowledge_id, distance
|
|
@@ -77,7 +77,7 @@ import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as
|
|
|
77
77
|
${this.buildFilterSqlSuffix(t)}
|
|
78
78
|
ORDER BY v.distance ASC
|
|
79
79
|
LIMIT ?
|
|
80
|
-
`,
|
|
80
|
+
`,c;try{c=n.queryAll(s,[D(o),a,r])}catch(n){return k.warn(`coarse vector search failed, falling back to full search`,f(n)),this.search(e,t)}return c.length===0?this.search(e,t):c.map(e=>({record:this.fromRow(e),score:1-(e._distance??1)})).filter(e=>e.score>=i).slice(0,r)}async ftsSearch(e,t){if(!e||e.trim().length===0||!this.ftsEnabled)return[];let n=this.getAdapter(),r=t?.limit??l.maxResults,i=`
|
|
81
81
|
SELECT k.*, bm25(knowledge_fts) AS _bm25
|
|
82
82
|
FROM knowledge_fts
|
|
83
83
|
JOIN knowledge k ON k.id = knowledge_fts.id
|
|
@@ -85,4 +85,4 @@ import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as
|
|
|
85
85
|
${this.buildFilterSqlSuffix(t,!0)}
|
|
86
86
|
ORDER BY _bm25 ASC
|
|
87
87
|
LIMIT ?
|
|
88
|
-
`,a;try{let t=N(e);a=n.queryAll(i,[t,r])}catch(e){return k.warn(`fts search failed`,
|
|
88
|
+
`,a;try{let t=N(e);a=n.queryAll(i,[t,r])}catch(e){return k.warn(`fts search failed`,f(e)),[]}return a.map(e=>({record:this.fromRow(e),score:P(e._bm25)}))}async getById(e){let t=this.getAdapter().queryAll(`SELECT * FROM knowledge WHERE id = ? LIMIT 1`,[e]);return t.length===0?null:this.fromRow(t[0])}async deleteBySourcePath(e){return this.enqueueWrite(()=>this._deleteBySourcePathImpl(e))}async _deleteBySourcePathImpl(e){let t=this.getAdapter(),n=t.queryAll(`SELECT id FROM knowledge WHERE sourcePath = ?`,[e]);if(n.length===0)return 0;t.exec(`BEGIN`);try{for(let{id:e}of n)this.vectorEnabled&&(t.run(`DELETE FROM vec_knowledge WHERE knowledge_id = ?`,[e]),this.coarseDim<this.embeddingDim&&t.run(`DELETE FROM vec_knowledge_coarse WHERE knowledge_id = ?`,[e])),this.ftsEnabled&&t.run(`DELETE FROM knowledge_fts WHERE id = ?`,[e]);t.run(`DELETE FROM knowledge WHERE sourcePath = ?`,[e]),t.exec(`COMMIT`)}catch(e){try{t.exec(`ROLLBACK`)}catch{}throw e}return t.flush(),n.length}async deleteById(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e))}async deleteByIdInteractive(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e),!0)}async _deleteByIdImpl(e){let t=this.getAdapter();if(t.queryAll(`SELECT id FROM knowledge WHERE id = ? LIMIT 1`,[e]).length===0)return!1;t.exec(`BEGIN`);try{this.vectorEnabled&&(t.run(`DELETE FROM vec_knowledge WHERE knowledge_id = ?`,[e]),this.coarseDim<this.embeddingDim&&t.run(`DELETE FROM vec_knowledge_coarse WHERE knowledge_id = ?`,[e])),this.ftsEnabled&&t.run(`DELETE FROM knowledge_fts WHERE id = ?`,[e]),t.run(`DELETE FROM knowledge WHERE id = ?`,[e]),t.exec(`COMMIT`)}catch(e){try{t.exec(`ROLLBACK`)}catch{}throw e}return t.flush(),!0}async getBySourcePath(e){return this.getAdapter().queryAll(`SELECT * FROM knowledge WHERE sourcePath = ? ORDER BY chunkIndex ASC`,[e]).map(e=>this.fromRow(e))}async getStats(){let e=this.getAdapter(),t=e.queryAll(`SELECT COUNT(*) AS n FROM knowledge`)[0]?.n??0;if(t===0)return{totalRecords:0,totalFiles:0,contentTypeBreakdown:{},lastIndexedAt:null,storeBackend:`sqlite-vec`,embeddingModel:c.model};let n=e.queryAll(`SELECT COUNT(DISTINCT sourcePath) AS n FROM knowledge`),r=e.queryAll(`SELECT contentType, COUNT(*) AS n FROM knowledge GROUP BY contentType`),i=e.queryAll(`SELECT MAX(indexedAt) AS ts FROM knowledge`),a={};for(let e of r)a[e.contentType]=e.n;return{totalRecords:t,totalFiles:n[0]?.n??0,contentTypeBreakdown:a,lastIndexedAt:i[0]?.ts??null,storeBackend:`sqlite-vec`,embeddingModel:c.model}}async listSourcePaths(){return this.getAdapter().queryAll(`SELECT DISTINCT sourcePath FROM knowledge ORDER BY sourcePath`).map(e=>e.sourcePath)}async createFtsIndex(){this.createFtsTable()}async dropTable(){return this.enqueueWrite(()=>this._dropTableImpl())}async _dropTableImpl(){let e=this.getAdapter();this.ftsEnabled&&e.exec(`DROP TABLE IF EXISTS knowledge_fts`),this.vectorEnabled&&(this.coarseDim<this.embeddingDim&&e.exec(`DROP TABLE IF EXISTS vec_knowledge_coarse`),e.exec(`DROP TABLE IF EXISTS vec_knowledge`)),e.exec(`DROP TABLE IF EXISTS knowledge`),e.flush(),this.createKnowledgeTable(),this.createFtsTable(),this.vectorEnabled&&this.ensureVecTable()}releaseMemory(){if(this.adapter)try{this.adapter.exec(`PRAGMA shrink_memory`),this.adapter.exec(`PRAGMA wal_checkpoint(TRUNCATE)`)}catch{}}onBeforeClose(e){this._onCloseHooks.push(e)}async close(){for(let e of this._onCloseHooks)try{e()}catch{}for(this._onCloseHooks.length=0;this._priorityQueue.length>0||this._normalQueue.length>0||this._draining;)await new Promise(e=>setTimeout(e,5));this.adapter&&!this.externalAdapter&&this.adapter.close(),this.adapter=null}getAdapter(){if(!this.adapter)throw Error(`SqliteVecStore: not initialized — call initialize() first`);return this.adapter}buildFilterSqlSuffix(e,t=!1){if(!e)return``;let n=[];if(e.contentType&&n.push(`k.contentType = '${j(e.contentType,`contentType`)}'`),e.sourceType){let t=p(e.sourceType);if(t.length>0){let e=t.map(e=>`'${j(e,`sourceType`)}'`).join(`, `);n.push(`k.contentType IN (${e})`)}}if(e.origin&&n.push(`k.origin = '${j(e.origin,`origin`)}'`),e.category&&n.push(`k.category = '${j(e.category,`category`)}'`),e.tags&&e.tags.length>0){let t=e.tags.map(e=>`k.tags LIKE '%' || '${j(e,`tag`)}' || '%'`);n.push(`(${t.join(` OR `)})`)}if(n.length===0)return``;let r=n.join(` AND `);return t?`AND ${r}`:`WHERE ${r}`}fromRow(e){return{id:e.id,content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath||void 0,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,contentHash:e.content_hash||void 0,indexedAt:e.indexedAt,origin:e.origin,tags:A(e.tags),category:e.category||void 0,version:e.version}}};function N(e){let t=e.replace(/["'()*:^-]/g,` `).trim();return t?t.split(/\s+/).filter(e=>e.length>0).map(e=>`"${e}"`).join(` OR `):`""`}function P(e){return e==null||Number.isNaN(e)?0:1-Math.exp(-Math.abs(e)/5)}export{w as i,E as n,T as r,M as t};
|
|
@@ -391,6 +391,18 @@ search({ query: "SESSION CHECKPOINT", origin: "curated" }) # Resume prior wo
|
|
|
391
391
|
| Pattern discovered | \`knowledge({ action: "remember", title, content, category: "patterns" })\` |
|
|
392
392
|
| About to propose new approach | \`search({ query })\` — check if already decided |
|
|
393
393
|
|
|
394
|
+
### Context Pressure Response
|
|
395
|
+
|
|
396
|
+
After any \`status()\` call, check the \`contextPressure\` value (0-100):
|
|
397
|
+
|
|
398
|
+
| Pressure | Action |
|
|
399
|
+
|----------|--------|
|
|
400
|
+
| **≤ 70** | Normal operation — no action needed |
|
|
401
|
+
| **> 70** | Proactive suggestion: "Context filling ({X}%). Consider \`session-handoff\` to preserve continuity." |
|
|
402
|
+
| **> 85** | **HARD RULE** — MUST create session-handoff before any further major action. Load \`session-handoff\` skill. Create compact handoff: \`knowledge({ action: "remember", scope: "flow", category: "session", title: "Session Handoff: <topic>" })\`. Write full file to \`.flows/{slug}/.handoffs/\`. Present summary to user. |
|
|
403
|
+
|
|
404
|
+
**This is a HARD RULE like repo-access.** Do not ignore context pressure signals. A lost context with no handoff means the next session starts from zero.
|
|
405
|
+
|
|
394
406
|
### End (MUST do)
|
|
395
407
|
|
|
396
408
|
\`session_digest({ persist: true })\` # Auto-capture session activity
|
|
@@ -117,7 +117,57 @@ If the flow's changes don't warrant doc updates (e.g., pure bug fix with no reve
|
|
|
117
117
|
- [ ] \`docs/\` bootstrapped with tool outputs if it didn't exist
|
|
118
118
|
- [ ] Relevant docs created or updated (or skipped with reason)
|
|
119
119
|
- [ ] \`docs/README.md\` index is current
|
|
120
|
-
- [ ] No placeholder/empty docs created — all content tool-generated or hand-written with purpose`}
|
|
120
|
+
- [ ] No placeholder/empty docs created — all content tool-generated or hand-written with purpose`},{file:`steps/lesson-learned/README.md`,content:`---
|
|
121
|
+
name: _lesson-learned
|
|
122
|
+
description: Extract engineering principles from the completed flow
|
|
123
|
+
skills: [lesson-learned]
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
# Epilogue: Lesson Learned
|
|
127
|
+
|
|
128
|
+
## Condition Check (MUST evaluate first)
|
|
129
|
+
|
|
130
|
+
Before extracting lessons, check if this flow produced learnable outcomes:
|
|
131
|
+
|
|
132
|
+
**Skip this step (advance with 'skip') when ALL of these are true:**
|
|
133
|
+
- Flow was Floor-tier (trivial change)
|
|
134
|
+
- blast_radius ≤ 2 for all changes
|
|
135
|
+
- Flow completed in a single batch with no iteration
|
|
136
|
+
- No agent returned BLOCKED or DONE_WITH_CONCERNS
|
|
137
|
+
- evidence_map never reached HOLD state
|
|
138
|
+
|
|
139
|
+
**Proceed when ANY of these are true:**
|
|
140
|
+
- An agent returned BLOCKED or DONE_WITH_CONCERNS during the flow
|
|
141
|
+
- evidence_map had HOLD before reaching YIELD (required iteration to pass)
|
|
142
|
+
- Multi-model decision protocol was invoked (architectural learning)
|
|
143
|
+
- blast_radius > 5 (complex change with systemic implications)
|
|
144
|
+
- A novel pattern or anti-pattern was discovered
|
|
145
|
+
- A debugging session revealed non-obvious root cause
|
|
146
|
+
|
|
147
|
+
If skip condition met → \`flow({ action: 'step', advance: 'skip' })\` with note: "No lesson signals detected."
|
|
148
|
+
|
|
149
|
+
## Extraction Protocol
|
|
150
|
+
|
|
151
|
+
1. **Load the \`lesson-learned\` skill** — follow its full protocol
|
|
152
|
+
2. Run \`git_context({ include_diff: true, commit_count: 10 })\` to see what changed
|
|
153
|
+
3. Review flow artifacts in \`{{artifacts_path}}\` for decisions made
|
|
154
|
+
4. Extract 1-3 principles using the skill's framework:
|
|
155
|
+
- What went wrong → What we learned → What we'll do differently
|
|
156
|
+
- OR: What went right → Why it worked → How to replicate
|
|
157
|
+
5. Store each principle: \`knowledge({ action: "remember", title: "Lesson: <principle>", content: "<context + evidence>", category: "patterns" })\`
|
|
158
|
+
|
|
159
|
+
## Quality Bar
|
|
160
|
+
|
|
161
|
+
A good lesson:
|
|
162
|
+
- Is **generalizable** (applies beyond this specific task)
|
|
163
|
+
- Has **evidence** (references specific files, errors, or decisions)
|
|
164
|
+
- Is **actionable** (tells future agents what to do or avoid)
|
|
165
|
+
|
|
166
|
+
A bad lesson (skip these):
|
|
167
|
+
- Restates what was done without insight
|
|
168
|
+
- Is too specific to be reusable ("file X had a typo on line 42")
|
|
169
|
+
- Captures a convention already documented elsewhere
|
|
170
|
+
`}],"aikit-advanced":[{file:`README.md`,content:"# aikit:advanced — Full Development Flow\n\nFull development flow for **new features, API design, and architecture changes**.\n\n## Steps\n\n| # | Step | Skill | Produces | Requires | Agents |\n|---|------|-------|----------|----------|--------|\n| 1 | **Design Gate** | `steps/design/README.md` | `design-decisions.md` | — | Researcher-Alpha/Beta/Gamma/Delta |\n| 2 | **Specification** | `steps/spec/README.md` | `spec.md` | `design-decisions.md` | Researcher-Alpha |\n| 3 | **Planning** | `steps/plan/README.md` | `plan.md` | `spec.md` | Planner, Explorer |\n| 4 | **Task Breakdown** | `steps/task/README.md` | `tasks.md` | `plan.md` | Planner, Architect-Reviewer-Alpha |\n| 5 | **Execution** | `steps/execute/README.md` | `progress.md` | `tasks.md` | Orchestrator, Implementer, Frontend, Refactor |\n| 6 | **Verification** | `steps/verify/README.md` | `verify-report.md` | `progress.md` | Code-Reviewer-Alpha/Beta, Architect-Reviewer-Alpha/Beta, Security |\n\n## How It Works\n\nEach step has a **README.md** file that contains the detailed instructions for the agent(s) executing that step. The Orchestrator reads the README.md via `flow({ action: 'read' })` and delegates work accordingly.\n\n### Step 1: Design Gate\n- Full brainstorming session for new features and architectural changes\n- FORGE classification (`forge_classify`) + grounding (`forge_ground`) for complex tasks\n- Full 3-phase multi-model decision protocol for non-trivial technical decisions (see Orchestrator's inlined Multi-Model Decision Protocol)\n- ADR generation for critical-tier tasks\n- **Mandatory user stop** before proceeding — design decisions must be approved\n- Read `steps/design/README.md` for the full protocol\n\n### Step 2: Specification\n- Elicit requirements from the user, clarify scope\n- Define acceptance criteria and constraints\n- Build on design decisions from the previous step\n\n### Step 3: Planning\n- Deep codebase analysis using `search`, `scope_map`, `trace`, `analyze_*`\n- Design architecture based on spec and design decisions\n- Create comprehensive implementation plan with file-level changes\n\n### Step 4: Task Breakdown\n- Break the plan into ordered, atomic implementation tasks\n- Define dependencies between tasks\n- Identify parallel batches for multi-agent execution\n- Architecture review of the task structure\n\n### Step 5: Execution\n- Orchestrator dispatches agents in parallel batches per the task breakdown\n- Each agent gets a scoped task (1-3 files) with clear acceptance criteria\n- TDD: write tests first, then implement\n- Per-batch review cycle: Code Review (dual) → Arch Review → Security → Evidence Gate\n\n### Step 6: Verification\n- Dual code review (Code-Reviewer-Alpha + Beta)\n- Architecture review (Architect-Reviewer-Alpha + Beta)\n- Security review\n- Run `check({})` + `test_run({})` + `blast_radius({})`\n- `evidence_map({ action: \"gate\" })` for final quality gate\n\n## Using Skills Inside Steps\n\nWhen the Orchestrator activates a step:\n\n1. **Read the instruction first** — `flow({ action: 'read' })` returns the README.md for the current step\n2. **Follow step instructions** — the README.md is the primary guide for what to do\n3. **Delegate to listed agents** — each step lists which agents are appropriate\n4. **Produce the required artifact** — the step's `produces` field specifies what file to create in the artifacts directory\n5. **Check dependencies** — the step's `requires` field lists artifacts from previous steps that must exist\n6. **Report status** — agents report `DONE` | `DONE_WITH_CONCERNS` | `NEEDS_CONTEXT` | `BLOCKED` to the Orchestrator\n\n## Artifacts\n\nAll artifacts are stored in the run directory under `.flows/{topic}/`. The template variable `{{artifacts_path}}` resolves to the actual path at runtime.\n"},{file:`steps/design/README.md`,content:`# Design Gate — Advanced Flow
|
|
121
171
|
|
|
122
172
|
Full design gate for new features, API design, and architecture changes. Runs brainstorming, decision protocol, and FORGE classification before specification begins.
|
|
123
173
|
|
|
@@ -478,6 +528,13 @@ Translate the specification into a concrete, phased implementation plan with arc
|
|
|
478
528
|
|
|
479
529
|
- \`{{artifacts_path}}/spec.md\` — the validated specification
|
|
480
530
|
|
|
531
|
+
## Requirements Alignment
|
|
532
|
+
|
|
533
|
+
Before implementation, verify alignment with requirements:
|
|
534
|
+
- Read \`{{artifacts_path}}/requirements.md\` if it exists
|
|
535
|
+
- Ensure all acceptance criteria from requirements are covered by the implementation plan
|
|
536
|
+
- Flag any requirement that cannot be met and explain why
|
|
537
|
+
|
|
481
538
|
## Process
|
|
482
539
|
|
|
483
540
|
1. **Load spec** — Read and internalize all requirements and acceptance criteria
|
|
@@ -605,6 +662,18 @@ Transform a vague or broad feature request into a precise, testable specificatio
|
|
|
605
662
|
- User's feature request, issue, or idea
|
|
606
663
|
- Codebase context (accessed via aikit MCP tools)
|
|
607
664
|
|
|
665
|
+
### Input Artifacts
|
|
666
|
+
|
|
667
|
+
Read these from \`{{artifacts_path}}/\` before writing the spec:
|
|
668
|
+
1. \`requirements.md\` — Requirements clarity output (score, criteria, constraints). **If this file exists, the spec MUST address all requirements and acceptance criteria listed in it.**
|
|
669
|
+
2. \`design-decisions.md\` — Design decisions from the design step
|
|
670
|
+
|
|
671
|
+
If \`requirements.md\` is not found in artifacts, check flow-scoped knowledge:
|
|
672
|
+
\`\`\`
|
|
673
|
+
knowledge({ action: "withdraw", scope: "flow", profile: "implementer", budget: 4000 })
|
|
674
|
+
\`\`\`
|
|
675
|
+
Look for a "Requirements:" entry in the withdrawn context.
|
|
676
|
+
|
|
608
677
|
## Process
|
|
609
678
|
|
|
610
679
|
1. **Understand intent** — Parse what the user wants and why
|
|
@@ -617,6 +686,27 @@ Transform a vague or broad feature request into a precise, testable specificatio
|
|
|
617
686
|
4. **Score clarity** — Use the \`requirements-clarity\` skill to score 0–100. Iterate questions until ≥ 90.
|
|
618
687
|
5. **Draft specification** — Write formal spec with all requirements resolved
|
|
619
688
|
|
|
689
|
+
## Requirements Clarity Gate (MANDATORY)
|
|
690
|
+
|
|
691
|
+
Before producing any spec.md or design document:
|
|
692
|
+
|
|
693
|
+
1. **Load the \`requirements-clarity\` skill**
|
|
694
|
+
2. **Score the current requirements** using the skill's 0-100 rubric
|
|
695
|
+
3. **If score < 90:** Ask clarifying questions, iterate with user until ≥ 90
|
|
696
|
+
4. **If score ≥ 90:** Proceed to spec writing
|
|
697
|
+
|
|
698
|
+
**HARD RULE:** A spec.md produced without requirements-clarity score ≥ 90 is INVALID and will be rejected in review. The score MUST be documented in the spec header:
|
|
699
|
+
|
|
700
|
+
\`\`\`yaml
|
|
701
|
+
# In spec.md frontmatter or header:
|
|
702
|
+
Requirements Clarity Score: [score]/100
|
|
703
|
+
Scoring Date: [date]
|
|
704
|
+
Key Clarifications:
|
|
705
|
+
- [question asked → answer received]
|
|
706
|
+
\`\`\`
|
|
707
|
+
|
|
708
|
+
This gate ensures we don't design solutions for misunderstood problems.
|
|
709
|
+
|
|
620
710
|
## Outputs
|
|
621
711
|
|
|
622
712
|
Write \`{{artifacts_path}}/spec.md\` to disk. **You MUST create this file** using \`create_file\` or equivalent — do not just present content in chat.
|
|
@@ -626,6 +716,11 @@ Template:
|
|
|
626
716
|
\`\`\`markdown
|
|
627
717
|
# Specification: <feature title>
|
|
628
718
|
|
|
719
|
+
Requirements Clarity Score: <N>/100
|
|
720
|
+
Scoring Date: <YYYY-MM-DD>
|
|
721
|
+
Key Clarifications:
|
|
722
|
+
- <question asked -> answer received>
|
|
723
|
+
|
|
629
724
|
## Summary
|
|
630
725
|
<1-2 sentence description>
|
|
631
726
|
|
|
@@ -654,8 +749,6 @@ Template:
|
|
|
654
749
|
|
|
655
750
|
## Open Questions
|
|
656
751
|
<none — all resolved during elicitation>
|
|
657
|
-
|
|
658
|
-
## Clarity Score: <N>/100
|
|
659
752
|
\`\`\`
|
|
660
753
|
|
|
661
754
|
## Agents
|
|
@@ -1005,6 +1098,15 @@ If any prerequisites are missing or incomplete:
|
|
|
1005
1098
|
2. Recommend \`flow({ action: 'step', advance: 'redo' })\` on the **design** step
|
|
1006
1099
|
3. Do NOT proceed with partial inputs — quality degrades downstream
|
|
1007
1100
|
|
|
1101
|
+
### Requirements Input (if available)
|
|
1102
|
+
|
|
1103
|
+
If \`{{artifacts_path}}/requirements.md\` exists (produced by requirements-clarity in the Design Gate):
|
|
1104
|
+
- Use its acceptance criteria as the test plan basis
|
|
1105
|
+
- Ensure the implementation addresses all listed requirements
|
|
1106
|
+
- The quality score must be ≥ 90 — if it's lower, the Design Gate should not have advanced
|
|
1107
|
+
|
|
1108
|
+
If no requirements.md exists (Design Gate was auto-skipped for bug fix/refactor), proceed without it.
|
|
1109
|
+
|
|
1008
1110
|
## Process
|
|
1009
1111
|
|
|
1010
1112
|
1. **Parse the goal** — Extract what needs to change, success criteria, and constraints
|
|
@@ -1119,6 +1221,15 @@ Then report \`DONE\` to the Orchestrator so the flow advances.
|
|
|
1119
1221
|
|
|
1120
1222
|
For small features that need minimal design:
|
|
1121
1223
|
|
|
1224
|
+
#### For Small Features (requires design):
|
|
1225
|
+
|
|
1226
|
+
1. **If requirements are unclear** (ambiguous scope, multiple possible interpretations, or cross-component):
|
|
1227
|
+
- Load \`requirements-clarity\` skill
|
|
1228
|
+
- Score requirements, iterate until ≥ 90
|
|
1229
|
+
- Output: \`{{artifacts_path}}/requirements.md\`
|
|
1230
|
+
2. **If requirements are clear** (single concern, obvious scope, clear acceptance):
|
|
1231
|
+
- Skip requirements-clarity, proceed to Quick Design directly
|
|
1232
|
+
|
|
1122
1233
|
1. **FORGE Classify** — Run \`forge_classify({ task: "<task description>", files: [<relevant files>] })\` to determine complexity tier
|
|
1123
1234
|
2. **Brainstorming** (if tier ≥ Standard) — Load the \`brainstorming\` skill and run a focused brainstorming session:
|
|
1124
1235
|
- What is the user trying to achieve?
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={sessionStart:{description:`Run at the start of every agent session`,actions:[`status({})`,`knowledge({ action: "list" })`,`search({ query: "SESSION CHECKPOINT", origin: "curated" })`],rationale:`Resume prior work, load existing knowledge`},sessionEnd:{description:`Run at the end of every agent session`,actions:[`knowledge({ action: "remember", title: "Session
|
|
1
|
+
const e={sessionStart:{description:`Run at the start of every agent session`,actions:[`status({})`,`knowledge({ action: "list" })`,`search({ query: "SESSION CHECKPOINT", origin: "curated" })`],rationale:`Resume prior work, load existing knowledge`},sessionEnd:{description:`Run at the end of every agent session with context-pressure-aware handoff behavior`,actions:["Check context pressure from the last `status({})` response before writing the checkpoint","If `contextPressure > 70` and a flow is active: load the `session-handoff` skill",'Create compact handoff: `knowledge({ action: "remember", scope: "flow", category: "session", title: "Session Handoff: <flow-topic>", content: "<compact format: State + Decisions + Next Steps + Blockers + Assumptions>" })`',"If possible, also write the full handoff file to `.flows/{flow-slug}/.handoffs/` using the skill's create protocol","If `contextPressure > 85`: this handoff is MANDATORY before ending the session, and present the handoff summary to the user for confirmation",'If `contextPressure <= 70` or no flow is active: use the standard session checkpoint `knowledge({ action: "remember", title: "Session checkpoint: <topic>", content: "Done: ... / Decisions: ... / Next: ...", category: "session" })`'],rationale:`Persist decisions for future sessions and prevent context loss when pressure is high`},beforeCodeChange:{description:`Run before modifying any code`,actions:[`search({ query: "<what you are changing>" })`,`scope_map({ task: "<description>" })`],rationale:`Check for prior decisions and understand impact`},beforeCommit:{description:`Run before committing changes`,actions:[`check({})`,`test_run({})`,`blast_radius({ changed_files: ["..."] })`],rationale:`Validate changes before they enter version control`}};export{e as HOOKS};
|