@cleocode/cleo 2026.3.2-beta.1 → 2026.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +319 -142
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +283 -110
- package/dist/mcp/index.js.map +4 -4
- package/package.json +1 -1
- package/packages/ct-skills/skills/ct-grade/SKILL.md +214 -0
- package/templates/CLEO-INJECTION.md +13 -0
package/dist/mcp/index.js
CHANGED
|
@@ -895,8 +895,8 @@ function openNativeDatabase(path, options) {
|
|
|
895
895
|
return db;
|
|
896
896
|
}
|
|
897
897
|
function createDrizzleCallback(db) {
|
|
898
|
-
return async (
|
|
899
|
-
const stmt = db.prepare(
|
|
898
|
+
return async (sql5, params, method) => {
|
|
899
|
+
const stmt = db.prepare(sql5);
|
|
900
900
|
const p = params;
|
|
901
901
|
switch (method) {
|
|
902
902
|
case "run": {
|
|
@@ -6963,9 +6963,13 @@ function createAudit() {
|
|
|
6963
6963
|
},
|
|
6964
6964
|
`${entry.metadata.gateway ?? "dispatch"} ${entry.domain}.${entry.operation}`
|
|
6965
6965
|
);
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
}
|
|
6966
|
+
if (isGradeSession) {
|
|
6967
|
+
await writeToSqlite(entry, req.requestId);
|
|
6968
|
+
} else {
|
|
6969
|
+
writeToSqlite(entry, req.requestId).catch((err) => {
|
|
6970
|
+
log4.error({ err }, "Failed to persist audit entry to SQLite");
|
|
6971
|
+
});
|
|
6972
|
+
}
|
|
6969
6973
|
return response;
|
|
6970
6974
|
};
|
|
6971
6975
|
}
|
|
@@ -6973,16 +6977,16 @@ async function queryAudit(options) {
|
|
|
6973
6977
|
try {
|
|
6974
6978
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
6975
6979
|
const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
6976
|
-
const { and:
|
|
6980
|
+
const { and: and4, eq: eq12, gte: gte2, or } = await import("drizzle-orm");
|
|
6977
6981
|
const db = await getDb2(process.cwd());
|
|
6978
6982
|
const conditions = [];
|
|
6979
|
-
if (options?.sessionId) conditions.push(
|
|
6980
|
-
if (options?.domain) conditions.push(
|
|
6981
|
-
if (options?.operation) conditions.push(or(
|
|
6982
|
-
if (options?.taskId) conditions.push(
|
|
6983
|
-
if (options?.since) conditions.push(
|
|
6983
|
+
if (options?.sessionId) conditions.push(eq12(auditLog2.sessionId, options.sessionId));
|
|
6984
|
+
if (options?.domain) conditions.push(eq12(auditLog2.domain, options.domain));
|
|
6985
|
+
if (options?.operation) conditions.push(or(eq12(auditLog2.operation, options.operation), eq12(auditLog2.action, options.operation)));
|
|
6986
|
+
if (options?.taskId) conditions.push(eq12(auditLog2.taskId, options.taskId));
|
|
6987
|
+
if (options?.since) conditions.push(gte2(auditLog2.timestamp, options.since));
|
|
6984
6988
|
const limit = options?.limit ?? 1e3;
|
|
6985
|
-
const rows = await db.select().from(auditLog2).where(conditions.length > 0 ?
|
|
6989
|
+
const rows = await db.select().from(auditLog2).where(conditions.length > 0 ? and4(...conditions) : void 0).orderBy(auditLog2.timestamp).limit(limit);
|
|
6986
6990
|
return rows.map((row) => ({
|
|
6987
6991
|
timestamp: row.timestamp,
|
|
6988
6992
|
sessionId: row.sessionId,
|
|
@@ -7114,8 +7118,8 @@ async function gradeSession(sessionId, cwd) {
|
|
|
7114
7118
|
);
|
|
7115
7119
|
let hygieneScore = 20;
|
|
7116
7120
|
for (const addCall of addCalls) {
|
|
7117
|
-
const
|
|
7118
|
-
if (!
|
|
7121
|
+
const desc3 = addCall.params?.description;
|
|
7122
|
+
if (!desc3 || desc3.trim().length === 0) {
|
|
7119
7123
|
hygieneScore -= 5;
|
|
7120
7124
|
result.flags.push(
|
|
7121
7125
|
`tasks.add without description (taskId: ${addCall.metadata?.taskId ?? "unknown"})`
|
|
@@ -7276,6 +7280,8 @@ var QUERY_OPERATIONS = {
|
|
|
7276
7280
|
// List all sessions
|
|
7277
7281
|
"show",
|
|
7278
7282
|
// Session details
|
|
7283
|
+
"find",
|
|
7284
|
+
// Lightweight session discovery (T5119)
|
|
7279
7285
|
"history",
|
|
7280
7286
|
// Session history
|
|
7281
7287
|
"decision.log",
|
|
@@ -10053,12 +10059,12 @@ function compose(middlewares) {
|
|
|
10053
10059
|
return async (_req, next) => next();
|
|
10054
10060
|
}
|
|
10055
10061
|
return async (request, next) => {
|
|
10056
|
-
let
|
|
10062
|
+
let index3 = -1;
|
|
10057
10063
|
async function dispatch(i) {
|
|
10058
|
-
if (i <=
|
|
10064
|
+
if (i <= index3) {
|
|
10059
10065
|
throw new Error("next() called multiple times in middleware");
|
|
10060
10066
|
}
|
|
10061
|
-
|
|
10067
|
+
index3 = i;
|
|
10062
10068
|
let fn = middlewares[i];
|
|
10063
10069
|
if (i === middlewares.length) {
|
|
10064
10070
|
fn = async (_req, nxt) => nxt();
|
|
@@ -12255,9 +12261,9 @@ init_json();
|
|
|
12255
12261
|
init_errors();
|
|
12256
12262
|
init_exit_codes();
|
|
12257
12263
|
init_paths();
|
|
12258
|
-
function fuzzyScore(query,
|
|
12264
|
+
function fuzzyScore(query, text3) {
|
|
12259
12265
|
const q = query.toLowerCase();
|
|
12260
|
-
const t =
|
|
12266
|
+
const t = text3.toLowerCase();
|
|
12261
12267
|
if (t === q) return 100;
|
|
12262
12268
|
if (t.includes(q)) return 80;
|
|
12263
12269
|
const words = t.split(/\s+/);
|
|
@@ -14054,6 +14060,46 @@ function computePipelineStage(current) {
|
|
|
14054
14060
|
return void 0;
|
|
14055
14061
|
}
|
|
14056
14062
|
|
|
14063
|
+
// src/core/sessions/find.ts
|
|
14064
|
+
async function findSessions(accessor, params) {
|
|
14065
|
+
let sessions2 = await accessor.loadSessions();
|
|
14066
|
+
if (params?.status) {
|
|
14067
|
+
sessions2 = sessions2.filter((s) => s.status === params.status);
|
|
14068
|
+
}
|
|
14069
|
+
if (params?.scope) {
|
|
14070
|
+
const scopeParts = params.scope.split(":");
|
|
14071
|
+
const scopeType = scopeParts[0];
|
|
14072
|
+
const scopeId = scopeParts[1];
|
|
14073
|
+
sessions2 = sessions2.filter((s) => {
|
|
14074
|
+
if (s.scope.type !== scopeType) return false;
|
|
14075
|
+
if (scopeId && s.scope.rootTaskId !== scopeId && s.scope.epicId !== scopeId) return false;
|
|
14076
|
+
return true;
|
|
14077
|
+
});
|
|
14078
|
+
}
|
|
14079
|
+
if (params?.query) {
|
|
14080
|
+
const q = params.query.toLowerCase();
|
|
14081
|
+
sessions2 = sessions2.filter(
|
|
14082
|
+
(s) => s.id.toLowerCase().includes(q) || s.name.toLowerCase().includes(q)
|
|
14083
|
+
);
|
|
14084
|
+
}
|
|
14085
|
+
sessions2.sort(
|
|
14086
|
+
(a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime()
|
|
14087
|
+
);
|
|
14088
|
+
if (params?.limit && params.limit > 0) {
|
|
14089
|
+
sessions2 = sessions2.slice(0, params.limit);
|
|
14090
|
+
}
|
|
14091
|
+
return sessions2.map(toMinimal);
|
|
14092
|
+
}
|
|
14093
|
+
function toMinimal(s) {
|
|
14094
|
+
return {
|
|
14095
|
+
id: s.id,
|
|
14096
|
+
name: s.name,
|
|
14097
|
+
status: s.status,
|
|
14098
|
+
startedAt: s.startedAt,
|
|
14099
|
+
scope: s.scope
|
|
14100
|
+
};
|
|
14101
|
+
}
|
|
14102
|
+
|
|
14057
14103
|
// src/core/sessions/session-id.ts
|
|
14058
14104
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
14059
14105
|
function generateSessionId() {
|
|
@@ -14183,6 +14229,7 @@ async function sessionStatus(projectRoot) {
|
|
|
14183
14229
|
return engineError("E_NOT_INITIALIZED", "Task database not initialized");
|
|
14184
14230
|
}
|
|
14185
14231
|
}
|
|
14232
|
+
var SESSION_LIST_DEFAULT_LIMIT = 10;
|
|
14186
14233
|
async function sessionList(projectRoot, params) {
|
|
14187
14234
|
try {
|
|
14188
14235
|
const accessor = await getAccessor(projectRoot);
|
|
@@ -14192,9 +14239,25 @@ async function sessionList(projectRoot, params) {
|
|
|
14192
14239
|
} else if (params?.active === false) {
|
|
14193
14240
|
result = result.filter((s) => s.status !== "active");
|
|
14194
14241
|
}
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14242
|
+
const total = result.length;
|
|
14243
|
+
const limit = params?.limit && params.limit > 0 ? params.limit : SESSION_LIST_DEFAULT_LIMIT;
|
|
14244
|
+
const truncated = total > limit;
|
|
14245
|
+
result = result.slice(0, limit);
|
|
14246
|
+
return {
|
|
14247
|
+
success: true,
|
|
14248
|
+
data: {
|
|
14249
|
+
sessions: result,
|
|
14250
|
+
_meta: { truncated, total }
|
|
14251
|
+
}
|
|
14252
|
+
};
|
|
14253
|
+
} catch {
|
|
14254
|
+
return engineError("E_NOT_INITIALIZED", "Task database not initialized");
|
|
14255
|
+
}
|
|
14256
|
+
}
|
|
14257
|
+
async function sessionFind(projectRoot, params) {
|
|
14258
|
+
try {
|
|
14259
|
+
const accessor = await getAccessor(projectRoot);
|
|
14260
|
+
const result = await findSessions(accessor, params);
|
|
14198
14261
|
return { success: true, data: result };
|
|
14199
14262
|
} catch {
|
|
14200
14263
|
return engineError("E_NOT_INITIALIZED", "Task database not initialized");
|
|
@@ -14354,6 +14417,7 @@ async function sessionStart(projectRoot, params) {
|
|
|
14354
14417
|
if (params.grade) {
|
|
14355
14418
|
process.env.CLEO_SESSION_GRADE = "true";
|
|
14356
14419
|
process.env.CLEO_SESSION_ID = sessionId;
|
|
14420
|
+
process.env.CLEO_SESSION_GRADE_ID = sessionId;
|
|
14357
14421
|
}
|
|
14358
14422
|
let briefing = null;
|
|
14359
14423
|
let previousDebrief = null;
|
|
@@ -14396,10 +14460,6 @@ async function sessionEnd(projectRoot, notes) {
|
|
|
14396
14460
|
const taskData = await accessor.loadTaskFile();
|
|
14397
14461
|
const sessionId = taskData._meta?.activeSession || "default";
|
|
14398
14462
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
14399
|
-
if (process.env.CLEO_SESSION_GRADE === "true") {
|
|
14400
|
-
delete process.env.CLEO_SESSION_GRADE;
|
|
14401
|
-
delete process.env.CLEO_SESSION_ID;
|
|
14402
|
-
}
|
|
14403
14463
|
if (taskData.focus) {
|
|
14404
14464
|
taskData.focus.currentTask = null;
|
|
14405
14465
|
if (notes) {
|
|
@@ -14561,11 +14621,14 @@ async function sessionHandoff(projectRoot, scope) {
|
|
|
14561
14621
|
const result = await getLastHandoff(projectRoot, scope);
|
|
14562
14622
|
return { success: true, data: result };
|
|
14563
14623
|
} catch (err) {
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14624
|
+
if (err instanceof CleoError) {
|
|
14625
|
+
const stringCode = `E_${getExitCodeName(err.code)}`;
|
|
14626
|
+
return engineError(stringCode, err.message, {
|
|
14627
|
+
...err.fix && { fix: err.fix }
|
|
14628
|
+
});
|
|
14629
|
+
}
|
|
14630
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14631
|
+
return engineError("E_GENERAL", message);
|
|
14569
14632
|
}
|
|
14570
14633
|
}
|
|
14571
14634
|
async function sessionComputeHandoff(projectRoot, sessionId, options) {
|
|
@@ -15508,32 +15571,32 @@ async function queryAuditLogSqlite(projectRoot, filters) {
|
|
|
15508
15571
|
if (!existsSync51(dbPath)) return null;
|
|
15509
15572
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
15510
15573
|
const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
15511
|
-
const { sql:
|
|
15574
|
+
const { sql: sql5 } = await import("drizzle-orm");
|
|
15512
15575
|
const db = await getDb2(projectRoot);
|
|
15513
15576
|
try {
|
|
15514
15577
|
const conditions = [];
|
|
15515
15578
|
if (filters?.operation) {
|
|
15516
|
-
conditions.push(
|
|
15579
|
+
conditions.push(sql5`(${auditLog2.action} = ${filters.operation} OR ${auditLog2.operation} = ${filters.operation})`);
|
|
15517
15580
|
}
|
|
15518
15581
|
if (filters?.taskId) {
|
|
15519
|
-
conditions.push(
|
|
15582
|
+
conditions.push(sql5`${auditLog2.taskId} = ${filters.taskId}`);
|
|
15520
15583
|
}
|
|
15521
15584
|
if (filters?.since) {
|
|
15522
|
-
conditions.push(
|
|
15585
|
+
conditions.push(sql5`${auditLog2.timestamp} >= ${filters.since}`);
|
|
15523
15586
|
}
|
|
15524
15587
|
if (filters?.until) {
|
|
15525
|
-
conditions.push(
|
|
15588
|
+
conditions.push(sql5`${auditLog2.timestamp} <= ${filters.until}`);
|
|
15526
15589
|
}
|
|
15527
|
-
const whereClause = conditions.length > 0 ?
|
|
15590
|
+
const whereClause = conditions.length > 0 ? sql5.join(conditions, sql5` AND `) : sql5`1=1`;
|
|
15528
15591
|
const countResult = await db.all(
|
|
15529
|
-
|
|
15592
|
+
sql5`SELECT count(*) as cnt FROM ${auditLog2} WHERE ${whereClause}`
|
|
15530
15593
|
);
|
|
15531
15594
|
const total = countResult[0]?.cnt ?? 0;
|
|
15532
15595
|
if (total === 0) return null;
|
|
15533
15596
|
const offset = filters?.offset ?? 0;
|
|
15534
15597
|
const limit = filters?.limit ?? 20;
|
|
15535
15598
|
const rows = await db.all(
|
|
15536
|
-
|
|
15599
|
+
sql5`SELECT * FROM ${auditLog2}
|
|
15537
15600
|
WHERE ${whereClause}
|
|
15538
15601
|
ORDER BY ${auditLog2.timestamp} DESC
|
|
15539
15602
|
LIMIT ${limit} OFFSET ${offset}`
|
|
@@ -17806,7 +17869,7 @@ async function validateSqliteRows(type, projectRoot) {
|
|
|
17806
17869
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
17807
17870
|
const schemaTable = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
17808
17871
|
const zodSchemas = await Promise.resolve().then(() => (init_validation_schemas(), validation_schemas_exports));
|
|
17809
|
-
const { ne: ne3, eq:
|
|
17872
|
+
const { ne: ne3, eq: eq12 } = await import("drizzle-orm");
|
|
17810
17873
|
const db = await getDb2(projectRoot);
|
|
17811
17874
|
const errors = [];
|
|
17812
17875
|
switch (type) {
|
|
@@ -17818,7 +17881,7 @@ async function validateSqliteRows(type, projectRoot) {
|
|
|
17818
17881
|
break;
|
|
17819
17882
|
}
|
|
17820
17883
|
case "archive": {
|
|
17821
|
-
const rows = await db.select().from(schemaTable.tasks).where(
|
|
17884
|
+
const rows = await db.select().from(schemaTable.tasks).where(eq12(schemaTable.tasks.status, "archived"));
|
|
17822
17885
|
for (const row of rows) {
|
|
17823
17886
|
errors.push(...collectZodErrors(zodSchemas.selectTaskSchema.safeParse(row), row.id));
|
|
17824
17887
|
}
|
|
@@ -18624,9 +18687,9 @@ function autoDispatch(task) {
|
|
|
18624
18687
|
}
|
|
18625
18688
|
}
|
|
18626
18689
|
if (task.type === "epic") return "decomposition";
|
|
18627
|
-
const
|
|
18690
|
+
const text3 = `${task.title} ${task.description ?? ""}`.toLowerCase();
|
|
18628
18691
|
for (const [protocol, config] of Object.entries(DISPATCH_MAP)) {
|
|
18629
|
-
if (config.keywords.some((kw) =>
|
|
18692
|
+
if (config.keywords.some((kw) => text3.includes(kw))) {
|
|
18630
18693
|
return protocol;
|
|
18631
18694
|
}
|
|
18632
18695
|
}
|
|
@@ -19631,37 +19694,110 @@ init_atomic();
|
|
|
19631
19694
|
init_errors();
|
|
19632
19695
|
init_exit_codes();
|
|
19633
19696
|
init_paths();
|
|
19634
|
-
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
|
|
19638
|
-
|
|
19639
|
-
|
|
19640
|
-
|
|
19641
|
-
|
|
19642
|
-
|
|
19643
|
-
|
|
19644
|
-
|
|
19645
|
-
|
|
19646
|
-
|
|
19647
|
-
|
|
19648
|
-
|
|
19649
|
-
|
|
19650
|
-
|
|
19651
|
-
|
|
19652
|
-
|
|
19653
|
-
|
|
19654
|
-
|
|
19655
|
-
|
|
19656
|
-
|
|
19657
|
-
|
|
19658
|
-
|
|
19659
|
-
|
|
19660
|
-
|
|
19661
|
-
|
|
19662
|
-
}
|
|
19663
|
-
|
|
19664
|
-
|
|
19697
|
+
|
|
19698
|
+
// src/store/brain-accessor.ts
|
|
19699
|
+
import { eq as eq11, and as and3, gte, desc, asc as asc2 } from "drizzle-orm";
|
|
19700
|
+
|
|
19701
|
+
// src/store/brain-sqlite.ts
|
|
19702
|
+
import { readMigrationFiles as readMigrationFiles2 } from "drizzle-orm/migrator";
|
|
19703
|
+
import { drizzle as drizzle2 } from "drizzle-orm/sqlite-proxy";
|
|
19704
|
+
import { migrate as migrate2 } from "drizzle-orm/sqlite-proxy/migrator";
|
|
19705
|
+
|
|
19706
|
+
// src/store/brain-schema.ts
|
|
19707
|
+
import {
|
|
19708
|
+
sqliteTable as sqliteTable2,
|
|
19709
|
+
text as text2,
|
|
19710
|
+
integer as integer2,
|
|
19711
|
+
real,
|
|
19712
|
+
index as index2,
|
|
19713
|
+
primaryKey as primaryKey2
|
|
19714
|
+
} from "drizzle-orm/sqlite-core";
|
|
19715
|
+
import { sql as sql4 } from "drizzle-orm";
|
|
19716
|
+
var BRAIN_DECISION_TYPES = ["architecture", "technical", "process", "strategic", "tactical"];
|
|
19717
|
+
var BRAIN_CONFIDENCE_LEVELS = ["low", "medium", "high"];
|
|
19718
|
+
var BRAIN_OUTCOME_TYPES = ["success", "failure", "mixed", "pending"];
|
|
19719
|
+
var BRAIN_PATTERN_TYPES = ["workflow", "blocker", "success", "failure", "optimization"];
|
|
19720
|
+
var BRAIN_IMPACT_LEVELS = ["low", "medium", "high"];
|
|
19721
|
+
var BRAIN_LINK_TYPES = ["produced_by", "applies_to", "informed_by", "contradicts"];
|
|
19722
|
+
var BRAIN_MEMORY_TYPES = ["decision", "pattern", "learning"];
|
|
19723
|
+
var brainDecisions = sqliteTable2("brain_decisions", {
|
|
19724
|
+
id: text2("id").primaryKey(),
|
|
19725
|
+
type: text2("type", { enum: BRAIN_DECISION_TYPES }).notNull(),
|
|
19726
|
+
decision: text2("decision").notNull(),
|
|
19727
|
+
rationale: text2("rationale").notNull(),
|
|
19728
|
+
confidence: text2("confidence", { enum: BRAIN_CONFIDENCE_LEVELS }).notNull(),
|
|
19729
|
+
outcome: text2("outcome", { enum: BRAIN_OUTCOME_TYPES }),
|
|
19730
|
+
alternativesJson: text2("alternatives_json"),
|
|
19731
|
+
contextEpicId: text2("context_epic_id"),
|
|
19732
|
+
// soft FK to tasks.id in tasks.db
|
|
19733
|
+
contextTaskId: text2("context_task_id"),
|
|
19734
|
+
// soft FK to tasks.id in tasks.db
|
|
19735
|
+
contextPhase: text2("context_phase"),
|
|
19736
|
+
createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`),
|
|
19737
|
+
updatedAt: text2("updated_at")
|
|
19738
|
+
}, (table) => [
|
|
19739
|
+
index2("idx_brain_decisions_type").on(table.type),
|
|
19740
|
+
index2("idx_brain_decisions_confidence").on(table.confidence),
|
|
19741
|
+
index2("idx_brain_decisions_outcome").on(table.outcome),
|
|
19742
|
+
index2("idx_brain_decisions_context_epic").on(table.contextEpicId),
|
|
19743
|
+
index2("idx_brain_decisions_context_task").on(table.contextTaskId)
|
|
19744
|
+
]);
|
|
19745
|
+
var brainPatterns = sqliteTable2("brain_patterns", {
|
|
19746
|
+
id: text2("id").primaryKey(),
|
|
19747
|
+
type: text2("type", { enum: BRAIN_PATTERN_TYPES }).notNull(),
|
|
19748
|
+
pattern: text2("pattern").notNull(),
|
|
19749
|
+
context: text2("context").notNull(),
|
|
19750
|
+
frequency: integer2("frequency").notNull().default(1),
|
|
19751
|
+
successRate: real("success_rate"),
|
|
19752
|
+
impact: text2("impact", { enum: BRAIN_IMPACT_LEVELS }),
|
|
19753
|
+
antiPattern: text2("anti_pattern"),
|
|
19754
|
+
mitigation: text2("mitigation"),
|
|
19755
|
+
examplesJson: text2("examples_json").default("[]"),
|
|
19756
|
+
extractedAt: text2("extracted_at").notNull().default(sql4`(datetime('now'))`),
|
|
19757
|
+
updatedAt: text2("updated_at")
|
|
19758
|
+
}, (table) => [
|
|
19759
|
+
index2("idx_brain_patterns_type").on(table.type),
|
|
19760
|
+
index2("idx_brain_patterns_impact").on(table.impact),
|
|
19761
|
+
index2("idx_brain_patterns_frequency").on(table.frequency)
|
|
19762
|
+
]);
|
|
19763
|
+
var brainLearnings = sqliteTable2("brain_learnings", {
|
|
19764
|
+
id: text2("id").primaryKey(),
|
|
19765
|
+
insight: text2("insight").notNull(),
|
|
19766
|
+
source: text2("source").notNull(),
|
|
19767
|
+
confidence: real("confidence").notNull(),
|
|
19768
|
+
// 0.0-1.0
|
|
19769
|
+
actionable: integer2("actionable", { mode: "boolean" }).notNull().default(false),
|
|
19770
|
+
application: text2("application"),
|
|
19771
|
+
applicableTypesJson: text2("applicable_types_json"),
|
|
19772
|
+
createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`),
|
|
19773
|
+
updatedAt: text2("updated_at")
|
|
19774
|
+
}, (table) => [
|
|
19775
|
+
index2("idx_brain_learnings_confidence").on(table.confidence),
|
|
19776
|
+
index2("idx_brain_learnings_actionable").on(table.actionable)
|
|
19777
|
+
]);
|
|
19778
|
+
var brainMemoryLinks = sqliteTable2("brain_memory_links", {
|
|
19779
|
+
memoryType: text2("memory_type", { enum: BRAIN_MEMORY_TYPES }).notNull(),
|
|
19780
|
+
memoryId: text2("memory_id").notNull(),
|
|
19781
|
+
taskId: text2("task_id").notNull(),
|
|
19782
|
+
// soft FK to tasks.id in tasks.db
|
|
19783
|
+
linkType: text2("link_type", { enum: BRAIN_LINK_TYPES }).notNull(),
|
|
19784
|
+
createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`)
|
|
19785
|
+
}, (table) => [
|
|
19786
|
+
primaryKey2({ columns: [table.memoryType, table.memoryId, table.taskId, table.linkType] }),
|
|
19787
|
+
index2("idx_brain_links_task").on(table.taskId),
|
|
19788
|
+
index2("idx_brain_links_memory").on(table.memoryType, table.memoryId)
|
|
19789
|
+
]);
|
|
19790
|
+
var brainSchemaMeta = sqliteTable2("brain_schema_meta", {
|
|
19791
|
+
key: text2("key").primaryKey(),
|
|
19792
|
+
value: text2("value").notNull()
|
|
19793
|
+
});
|
|
19794
|
+
|
|
19795
|
+
// src/store/brain-sqlite.ts
|
|
19796
|
+
init_paths();
|
|
19797
|
+
init_node_sqlite_adapter();
|
|
19798
|
+
|
|
19799
|
+
// src/core/memory/decisions.ts
|
|
19800
|
+
import { desc as desc2 } from "drizzle-orm";
|
|
19665
19801
|
|
|
19666
19802
|
// src/core/memory/patterns.ts
|
|
19667
19803
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
@@ -19914,6 +20050,39 @@ function learningStats(projectRoot) {
|
|
|
19914
20050
|
};
|
|
19915
20051
|
}
|
|
19916
20052
|
|
|
20053
|
+
// src/core/memory/index.ts
|
|
20054
|
+
function filterManifestEntries(entries, filter) {
|
|
20055
|
+
let filtered = entries;
|
|
20056
|
+
if (filter.taskId) {
|
|
20057
|
+
const taskId = filter.taskId;
|
|
20058
|
+
filtered = filtered.filter(
|
|
20059
|
+
(e) => e.id.startsWith(taskId) || e.linked_tasks?.includes(taskId)
|
|
20060
|
+
);
|
|
20061
|
+
}
|
|
20062
|
+
if (filter.status) {
|
|
20063
|
+
filtered = filtered.filter((e) => e.status === filter.status);
|
|
20064
|
+
}
|
|
20065
|
+
if (filter.agent_type) {
|
|
20066
|
+
filtered = filtered.filter((e) => e.agent_type === filter.agent_type);
|
|
20067
|
+
}
|
|
20068
|
+
if (filter.topic) {
|
|
20069
|
+
filtered = filtered.filter((e) => e.topics.includes(filter.topic));
|
|
20070
|
+
}
|
|
20071
|
+
if (filter.actionable !== void 0) {
|
|
20072
|
+
filtered = filtered.filter((e) => e.actionable === filter.actionable);
|
|
20073
|
+
}
|
|
20074
|
+
if (filter.dateAfter) {
|
|
20075
|
+
filtered = filtered.filter((e) => e.date > filter.dateAfter);
|
|
20076
|
+
}
|
|
20077
|
+
if (filter.dateBefore) {
|
|
20078
|
+
filtered = filtered.filter((e) => e.date < filter.dateBefore);
|
|
20079
|
+
}
|
|
20080
|
+
if (filter.limit && filter.limit > 0) {
|
|
20081
|
+
filtered = filtered.slice(0, filter.limit);
|
|
20082
|
+
}
|
|
20083
|
+
return filtered;
|
|
20084
|
+
}
|
|
20085
|
+
|
|
19917
20086
|
// src/core/memory/engine-compat.ts
|
|
19918
20087
|
function getManifestPath2(projectRoot) {
|
|
19919
20088
|
return getManifestPath(projectRoot);
|
|
@@ -20327,13 +20496,13 @@ async function readReleases(cwd) {
|
|
|
20327
20496
|
const data = await readJson(getReleasesPath(cwd));
|
|
20328
20497
|
return data ?? { releases: [] };
|
|
20329
20498
|
}
|
|
20330
|
-
async function writeReleases(
|
|
20499
|
+
async function writeReleases(index3, cwd) {
|
|
20331
20500
|
const releasesPath = getReleasesPath(cwd);
|
|
20332
20501
|
const dir = dirname12(releasesPath);
|
|
20333
20502
|
if (!existsSync41(dir)) {
|
|
20334
20503
|
mkdirSync15(dir, { recursive: true });
|
|
20335
20504
|
}
|
|
20336
|
-
await saveJson(releasesPath,
|
|
20505
|
+
await saveJson(releasesPath, index3);
|
|
20337
20506
|
}
|
|
20338
20507
|
function isValidVersion(version) {
|
|
20339
20508
|
return /^v?\d+\.\d+\.\d+(-[\w.]+)?(\+[\w.]+)?$/.test(version);
|
|
@@ -20349,8 +20518,8 @@ async function prepareRelease(version, tasks2, notes, loadTasksFn, cwd) {
|
|
|
20349
20518
|
throw new Error(`Invalid version format: ${version} (expected X.Y.Z or YYYY.M.patch)`);
|
|
20350
20519
|
}
|
|
20351
20520
|
const normalizedVersion = normalizeVersion(version);
|
|
20352
|
-
const
|
|
20353
|
-
const existing =
|
|
20521
|
+
const index3 = await readReleases(cwd);
|
|
20522
|
+
const existing = index3.releases.find((r) => r.version === normalizedVersion);
|
|
20354
20523
|
if (existing) {
|
|
20355
20524
|
throw new Error(`Release ${normalizedVersion} already exists (status: ${existing.status})`);
|
|
20356
20525
|
}
|
|
@@ -20371,10 +20540,10 @@ async function prepareRelease(version, tasks2, notes, loadTasksFn, cwd) {
|
|
|
20371
20540
|
preparedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20372
20541
|
tasks: releaseTasks,
|
|
20373
20542
|
notes,
|
|
20374
|
-
previousVersion:
|
|
20543
|
+
previousVersion: index3.latest
|
|
20375
20544
|
};
|
|
20376
|
-
|
|
20377
|
-
await writeReleases(
|
|
20545
|
+
index3.releases.push(release2);
|
|
20546
|
+
await writeReleases(index3, cwd);
|
|
20378
20547
|
return {
|
|
20379
20548
|
version: normalizedVersion,
|
|
20380
20549
|
status: "prepared",
|
|
@@ -20387,8 +20556,8 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
20387
20556
|
throw new Error("version is required");
|
|
20388
20557
|
}
|
|
20389
20558
|
const normalizedVersion = normalizeVersion(version);
|
|
20390
|
-
const
|
|
20391
|
-
const release2 =
|
|
20559
|
+
const index3 = await readReleases(cwd);
|
|
20560
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
20392
20561
|
if (!release2) {
|
|
20393
20562
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
20394
20563
|
}
|
|
@@ -20459,7 +20628,7 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
20459
20628
|
}
|
|
20460
20629
|
const changelog = sections.join("\n");
|
|
20461
20630
|
release2.changelog = changelog;
|
|
20462
|
-
await writeReleases(
|
|
20631
|
+
await writeReleases(index3, cwd);
|
|
20463
20632
|
return {
|
|
20464
20633
|
version: normalizedVersion,
|
|
20465
20634
|
changelog,
|
|
@@ -20479,8 +20648,8 @@ async function showManifestRelease(version, cwd) {
|
|
|
20479
20648
|
throw new Error("version is required");
|
|
20480
20649
|
}
|
|
20481
20650
|
const normalizedVersion = normalizeVersion(version);
|
|
20482
|
-
const
|
|
20483
|
-
const release2 =
|
|
20651
|
+
const index3 = await readReleases(cwd);
|
|
20652
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
20484
20653
|
if (!release2) {
|
|
20485
20654
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
20486
20655
|
}
|
|
@@ -20491,8 +20660,8 @@ async function commitRelease(version, cwd) {
|
|
|
20491
20660
|
throw new Error("version is required");
|
|
20492
20661
|
}
|
|
20493
20662
|
const normalizedVersion = normalizeVersion(version);
|
|
20494
|
-
const
|
|
20495
|
-
const release2 =
|
|
20663
|
+
const index3 = await readReleases(cwd);
|
|
20664
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
20496
20665
|
if (!release2) {
|
|
20497
20666
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
20498
20667
|
}
|
|
@@ -20501,7 +20670,7 @@ async function commitRelease(version, cwd) {
|
|
|
20501
20670
|
}
|
|
20502
20671
|
release2.status = "committed";
|
|
20503
20672
|
release2.committedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20504
|
-
await writeReleases(
|
|
20673
|
+
await writeReleases(index3, cwd);
|
|
20505
20674
|
return {
|
|
20506
20675
|
version: normalizedVersion,
|
|
20507
20676
|
status: "committed",
|
|
@@ -20513,15 +20682,15 @@ async function tagRelease(version, cwd) {
|
|
|
20513
20682
|
throw new Error("version is required");
|
|
20514
20683
|
}
|
|
20515
20684
|
const normalizedVersion = normalizeVersion(version);
|
|
20516
|
-
const
|
|
20517
|
-
const release2 =
|
|
20685
|
+
const index3 = await readReleases(cwd);
|
|
20686
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
20518
20687
|
if (!release2) {
|
|
20519
20688
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
20520
20689
|
}
|
|
20521
20690
|
release2.status = "tagged";
|
|
20522
20691
|
release2.taggedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20523
|
-
|
|
20524
|
-
await writeReleases(
|
|
20692
|
+
index3.latest = normalizedVersion;
|
|
20693
|
+
await writeReleases(index3, cwd);
|
|
20525
20694
|
return {
|
|
20526
20695
|
version: normalizedVersion,
|
|
20527
20696
|
status: "tagged",
|
|
@@ -20533,8 +20702,8 @@ async function runReleaseGates(version, loadTasksFn, cwd) {
|
|
|
20533
20702
|
throw new Error("version is required");
|
|
20534
20703
|
}
|
|
20535
20704
|
const normalizedVersion = normalizeVersion(version);
|
|
20536
|
-
const
|
|
20537
|
-
const release2 =
|
|
20705
|
+
const index3 = await readReleases(cwd);
|
|
20706
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
20538
20707
|
if (!release2) {
|
|
20539
20708
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
20540
20709
|
}
|
|
@@ -20578,18 +20747,18 @@ async function rollbackRelease(version, reason, cwd) {
|
|
|
20578
20747
|
throw new Error("version is required");
|
|
20579
20748
|
}
|
|
20580
20749
|
const normalizedVersion = normalizeVersion(version);
|
|
20581
|
-
const
|
|
20582
|
-
const release2 =
|
|
20750
|
+
const index3 = await readReleases(cwd);
|
|
20751
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
20583
20752
|
if (!release2) {
|
|
20584
20753
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
20585
20754
|
}
|
|
20586
20755
|
const previousStatus = release2.status;
|
|
20587
20756
|
release2.status = "rolled_back";
|
|
20588
|
-
if (
|
|
20589
|
-
const otherReleases =
|
|
20590
|
-
|
|
20757
|
+
if (index3.latest === normalizedVersion) {
|
|
20758
|
+
const otherReleases = index3.releases.filter((r) => r.version !== normalizedVersion && r.status !== "rolled_back").sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
20759
|
+
index3.latest = otherReleases[0]?.version;
|
|
20591
20760
|
}
|
|
20592
|
-
await writeReleases(
|
|
20761
|
+
await writeReleases(index3, cwd);
|
|
20593
20762
|
return {
|
|
20594
20763
|
version: normalizedVersion,
|
|
20595
20764
|
previousStatus,
|
|
@@ -20659,12 +20828,12 @@ async function pushRelease(version, remote, cwd, opts) {
|
|
|
20659
20828
|
}
|
|
20660
20829
|
async function markReleasePushed(version, pushedAt, cwd) {
|
|
20661
20830
|
const normalizedVersion = normalizeVersion(version);
|
|
20662
|
-
const
|
|
20663
|
-
const release2 =
|
|
20831
|
+
const index3 = await readReleases(cwd);
|
|
20832
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
20664
20833
|
if (release2) {
|
|
20665
20834
|
release2.status = "pushed";
|
|
20666
20835
|
release2.pushedAt = pushedAt;
|
|
20667
|
-
await writeReleases(
|
|
20836
|
+
await writeReleases(index3, cwd);
|
|
20668
20837
|
}
|
|
20669
20838
|
}
|
|
20670
20839
|
|
|
@@ -21431,6 +21600,10 @@ var SessionHandler = class {
|
|
|
21431
21600
|
const result = await sessionChainShow(this.projectRoot, chainSessionId);
|
|
21432
21601
|
return this.wrapEngineResult(result, "query", "session", operation, startTime);
|
|
21433
21602
|
}
|
|
21603
|
+
case "find": {
|
|
21604
|
+
const result = await sessionFind(this.projectRoot, params);
|
|
21605
|
+
return this.wrapEngineResult(result, "query", "session", operation, startTime);
|
|
21606
|
+
}
|
|
21434
21607
|
default:
|
|
21435
21608
|
return this.unsupported("query", "session", operation, startTime);
|
|
21436
21609
|
}
|
|
@@ -21551,7 +21724,7 @@ var SessionHandler = class {
|
|
|
21551
21724
|
// -----------------------------------------------------------------------
|
|
21552
21725
|
getSupportedOperations() {
|
|
21553
21726
|
return {
|
|
21554
|
-
query: ["status", "list", "show", "history", "decision.log", "context.drift", "handoff.show", "briefing.show", "debrief.show", "chain.show"],
|
|
21727
|
+
query: ["status", "list", "show", "find", "history", "decision.log", "context.drift", "handoff.show", "briefing.show", "debrief.show", "chain.show"],
|
|
21555
21728
|
mutate: ["start", "end", "resume", "suspend", "gc", "record.decision", "record.assumption"]
|
|
21556
21729
|
};
|
|
21557
21730
|
}
|
|
@@ -25626,8 +25799,8 @@ var DECOMPOSITION_RULES = [
|
|
|
25626
25799
|
validate: (entry) => {
|
|
25627
25800
|
const title = entry.title;
|
|
25628
25801
|
const description = entry.description;
|
|
25629
|
-
const
|
|
25630
|
-
return !/\b\d+\s*(hour|day|week|minute|hr|min)s?\b/i.test(
|
|
25802
|
+
const text3 = `${title} ${description}`;
|
|
25803
|
+
return !/\b\d+\s*(hour|day|week|minute|hr|min)s?\b/i.test(text3);
|
|
25631
25804
|
}
|
|
25632
25805
|
},
|
|
25633
25806
|
{
|
|
@@ -25636,9 +25809,9 @@ var DECOMPOSITION_RULES = [
|
|
|
25636
25809
|
message: "Must include acceptance criteria in task description",
|
|
25637
25810
|
fix: "Add clear acceptance criteria: what must be true when the task is done",
|
|
25638
25811
|
validate: (entry) => {
|
|
25639
|
-
const
|
|
25640
|
-
if (!
|
|
25641
|
-
return /\b(must|should|acceptance|criteria|verify|test|passes when|done when|complete when)\b/i.test(
|
|
25812
|
+
const desc3 = entry.description;
|
|
25813
|
+
if (!desc3) return false;
|
|
25814
|
+
return /\b(must|should|acceptance|criteria|verify|test|passes when|done when|complete when)\b/i.test(desc3);
|
|
25642
25815
|
}
|
|
25643
25816
|
},
|
|
25644
25817
|
{
|