@cleocode/cleo 2026.3.4 → 2026.3.6
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 +2277 -609
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +1838 -443
- package/dist/mcp/index.js.map +4 -4
- package/package.json +1 -1
- package/packages/ct-skills/index.js +1 -1
- package/packages/ct-skills/package.json +0 -2
- package/packages/ct-skills/profiles/core.json +1 -1
- package/packages/ct-skills/profiles/full.json +4 -5
- package/packages/ct-skills/profiles/minimal.json +3 -3
- package/packages/ct-skills/profiles/recommended.json +2 -2
- package/packages/ct-skills/provider-skills-map.json +97 -0
- package/packages/ct-skills/skills/_shared/skill-chaining-patterns.md +23 -26
- package/packages/ct-skills/skills/_shared/testing-framework-config.md +9 -9
- package/packages/ct-skills/skills/ct-cleo/SKILL.md +21 -1
- package/packages/ct-skills/skills/ct-dev-workflow/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-documentor/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-epic-architect/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-orchestrator/SKILL.md +119 -43
- package/packages/ct-skills/skills/ct-orchestrator/orchestrator-prompt.txt +17 -0
- package/packages/ct-skills/skills/ct-orchestrator/references/orchestrator-patterns.md +1 -1
- package/packages/ct-skills/skills/ct-research-agent/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-spec-writer/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-task-executor/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-validator/SKILL.md +1 -1
- package/packages/ct-skills/skills/manifest.json +217 -947
- package/packages/ct-skills/skills.json +244 -3
- package/templates/CLEO-INJECTION.md +24 -0
- package/packages/ct-skills/protocols/agent-protocol.md +0 -260
- package/packages/ct-skills/protocols/artifact-publish.md +0 -587
- package/packages/ct-skills/protocols/consensus.md +0 -309
- package/packages/ct-skills/protocols/contribution.md +0 -375
- package/packages/ct-skills/protocols/decomposition.md +0 -352
- package/packages/ct-skills/protocols/implementation.md +0 -344
- package/packages/ct-skills/protocols/provenance.md +0 -600
- package/packages/ct-skills/protocols/release.md +0 -635
- package/packages/ct-skills/protocols/research.md +0 -248
- package/packages/ct-skills/protocols/specification.md +0 -287
- package/packages/ct-skills/protocols/testing.md +0 -346
- package/packages/ct-skills/protocols/validation.md +0 -229
- package/packages/ct-skills/skills/ct-gitbook/SKILL.md +0 -516
- package/packages/ct-skills/skills/ct-gitbook/assets/SUMMARY.md +0 -28
- package/packages/ct-skills/skills/ct-gitbook/assets/gitbook.yaml +0 -14
- package/packages/ct-skills/skills/ct-gitbook/references/api-sdk.md +0 -318
- package/packages/ct-skills/skills/ct-gitbook/references/auth-sso.md +0 -208
- package/packages/ct-skills/skills/ct-gitbook/references/change-requests.md +0 -169
- package/packages/ct-skills/skills/ct-gitbook/references/content-blocks.md +0 -230
- package/packages/ct-skills/skills/ct-gitbook/references/docs-sites.md +0 -202
- package/packages/ct-skills/skills/ct-gitbook/references/git-sync.md +0 -175
- package/packages/ct-skills/skills/ct-gitbook/references/llm-ready.md +0 -178
- package/packages/ct-skills/skills/ct-gitbook/references/migration.md +0 -263
- package/packages/ct-skills/skills/ct-library-implementer-bash/SKILL.md +0 -316
- package/packages/ct-skills/skills/ct-skill-lookup/SKILL.md +0 -179
- package/packages/ct-skills/skills/ct-test-writer-bats/SKILL.md +0 -347
- package/packages/ct-skills/skills/railway-platform/SKILL.md +0 -506
- package/packages/ct-skills/skills/railway-platform/_shared/scripts/railway-api.sh +0 -180
- package/packages/ct-skills/skills/railway-platform/_shared/scripts/railway-common.sh +0 -262
- package/packages/ct-skills/skills/railway-platform/references/01-getting-started.md +0 -149
- package/packages/ct-skills/skills/railway-platform/references/02-projects.md +0 -116
- package/packages/ct-skills/skills/railway-platform/references/03-services.md +0 -147
- package/packages/ct-skills/skills/railway-platform/references/04-deployments.md +0 -210
- package/packages/ct-skills/skills/railway-platform/references/05-databases.md +0 -142
- package/packages/ct-skills/skills/railway-platform/references/06-environments.md +0 -261
- package/packages/ct-skills/skills/railway-platform/references/07-domains.md +0 -139
- package/packages/ct-skills/skills/railway-platform/references/08-volumes.md +0 -533
- package/packages/ct-skills/skills/railway-platform/references/09-networking.md +0 -592
- package/packages/ct-skills/skills/railway-platform/references/10-cron.md +0 -488
- package/packages/ct-skills/skills/railway-platform/references/11-functions.md +0 -170
- package/packages/ct-skills/skills/railway-platform/references/12-monorepo.md +0 -294
- package/packages/ct-skills/skills/railway-platform/references/13-troubleshooting.md +0 -335
- package/packages/ct-skills/skills/railway-platform/references/14-railway-metal.md +0 -197
package/dist/mcp/index.js
CHANGED
|
@@ -3850,6 +3850,1338 @@ var init_handoff = __esm({
|
|
|
3850
3850
|
}
|
|
3851
3851
|
});
|
|
3852
3852
|
|
|
3853
|
+
// src/store/brain-schema.ts
|
|
3854
|
+
var brain_schema_exports = {};
|
|
3855
|
+
__export(brain_schema_exports, {
|
|
3856
|
+
BRAIN_CONFIDENCE_LEVELS: () => BRAIN_CONFIDENCE_LEVELS,
|
|
3857
|
+
BRAIN_DECISION_TYPES: () => BRAIN_DECISION_TYPES,
|
|
3858
|
+
BRAIN_IMPACT_LEVELS: () => BRAIN_IMPACT_LEVELS,
|
|
3859
|
+
BRAIN_LINK_TYPES: () => BRAIN_LINK_TYPES,
|
|
3860
|
+
BRAIN_MEMORY_TYPES: () => BRAIN_MEMORY_TYPES,
|
|
3861
|
+
BRAIN_OBSERVATION_SOURCE_TYPES: () => BRAIN_OBSERVATION_SOURCE_TYPES,
|
|
3862
|
+
BRAIN_OBSERVATION_TYPES: () => BRAIN_OBSERVATION_TYPES,
|
|
3863
|
+
BRAIN_OUTCOME_TYPES: () => BRAIN_OUTCOME_TYPES,
|
|
3864
|
+
BRAIN_PATTERN_TYPES: () => BRAIN_PATTERN_TYPES,
|
|
3865
|
+
brainDecisions: () => brainDecisions,
|
|
3866
|
+
brainLearnings: () => brainLearnings,
|
|
3867
|
+
brainMemoryLinks: () => brainMemoryLinks,
|
|
3868
|
+
brainObservations: () => brainObservations,
|
|
3869
|
+
brainPatterns: () => brainPatterns,
|
|
3870
|
+
brainSchemaMeta: () => brainSchemaMeta
|
|
3871
|
+
});
|
|
3872
|
+
import {
|
|
3873
|
+
sqliteTable as sqliteTable2,
|
|
3874
|
+
text as text2,
|
|
3875
|
+
integer as integer2,
|
|
3876
|
+
real,
|
|
3877
|
+
index as index2,
|
|
3878
|
+
primaryKey as primaryKey2
|
|
3879
|
+
} from "drizzle-orm/sqlite-core";
|
|
3880
|
+
import { sql as sql3 } from "drizzle-orm";
|
|
3881
|
+
var BRAIN_DECISION_TYPES, BRAIN_CONFIDENCE_LEVELS, BRAIN_OUTCOME_TYPES, BRAIN_PATTERN_TYPES, BRAIN_IMPACT_LEVELS, BRAIN_LINK_TYPES, BRAIN_OBSERVATION_TYPES, BRAIN_OBSERVATION_SOURCE_TYPES, BRAIN_MEMORY_TYPES, brainDecisions, brainPatterns, brainLearnings, brainObservations, brainMemoryLinks, brainSchemaMeta;
|
|
3882
|
+
var init_brain_schema = __esm({
|
|
3883
|
+
"src/store/brain-schema.ts"() {
|
|
3884
|
+
"use strict";
|
|
3885
|
+
BRAIN_DECISION_TYPES = ["architecture", "technical", "process", "strategic", "tactical"];
|
|
3886
|
+
BRAIN_CONFIDENCE_LEVELS = ["low", "medium", "high"];
|
|
3887
|
+
BRAIN_OUTCOME_TYPES = ["success", "failure", "mixed", "pending"];
|
|
3888
|
+
BRAIN_PATTERN_TYPES = ["workflow", "blocker", "success", "failure", "optimization"];
|
|
3889
|
+
BRAIN_IMPACT_LEVELS = ["low", "medium", "high"];
|
|
3890
|
+
BRAIN_LINK_TYPES = ["produced_by", "applies_to", "informed_by", "contradicts"];
|
|
3891
|
+
BRAIN_OBSERVATION_TYPES = ["discovery", "change", "feature", "bugfix", "decision", "refactor"];
|
|
3892
|
+
BRAIN_OBSERVATION_SOURCE_TYPES = ["agent", "session-debrief", "claude-mem", "manual"];
|
|
3893
|
+
BRAIN_MEMORY_TYPES = ["decision", "pattern", "learning", "observation"];
|
|
3894
|
+
brainDecisions = sqliteTable2("brain_decisions", {
|
|
3895
|
+
id: text2("id").primaryKey(),
|
|
3896
|
+
type: text2("type", { enum: BRAIN_DECISION_TYPES }).notNull(),
|
|
3897
|
+
decision: text2("decision").notNull(),
|
|
3898
|
+
rationale: text2("rationale").notNull(),
|
|
3899
|
+
confidence: text2("confidence", { enum: BRAIN_CONFIDENCE_LEVELS }).notNull(),
|
|
3900
|
+
outcome: text2("outcome", { enum: BRAIN_OUTCOME_TYPES }),
|
|
3901
|
+
alternativesJson: text2("alternatives_json"),
|
|
3902
|
+
contextEpicId: text2("context_epic_id"),
|
|
3903
|
+
// soft FK to tasks.id in tasks.db
|
|
3904
|
+
contextTaskId: text2("context_task_id"),
|
|
3905
|
+
// soft FK to tasks.id in tasks.db
|
|
3906
|
+
contextPhase: text2("context_phase"),
|
|
3907
|
+
createdAt: text2("created_at").notNull().default(sql3`(datetime('now'))`),
|
|
3908
|
+
updatedAt: text2("updated_at")
|
|
3909
|
+
}, (table) => [
|
|
3910
|
+
index2("idx_brain_decisions_type").on(table.type),
|
|
3911
|
+
index2("idx_brain_decisions_confidence").on(table.confidence),
|
|
3912
|
+
index2("idx_brain_decisions_outcome").on(table.outcome),
|
|
3913
|
+
index2("idx_brain_decisions_context_epic").on(table.contextEpicId),
|
|
3914
|
+
index2("idx_brain_decisions_context_task").on(table.contextTaskId)
|
|
3915
|
+
]);
|
|
3916
|
+
brainPatterns = sqliteTable2("brain_patterns", {
|
|
3917
|
+
id: text2("id").primaryKey(),
|
|
3918
|
+
type: text2("type", { enum: BRAIN_PATTERN_TYPES }).notNull(),
|
|
3919
|
+
pattern: text2("pattern").notNull(),
|
|
3920
|
+
context: text2("context").notNull(),
|
|
3921
|
+
frequency: integer2("frequency").notNull().default(1),
|
|
3922
|
+
successRate: real("success_rate"),
|
|
3923
|
+
impact: text2("impact", { enum: BRAIN_IMPACT_LEVELS }),
|
|
3924
|
+
antiPattern: text2("anti_pattern"),
|
|
3925
|
+
mitigation: text2("mitigation"),
|
|
3926
|
+
examplesJson: text2("examples_json").default("[]"),
|
|
3927
|
+
extractedAt: text2("extracted_at").notNull().default(sql3`(datetime('now'))`),
|
|
3928
|
+
updatedAt: text2("updated_at")
|
|
3929
|
+
}, (table) => [
|
|
3930
|
+
index2("idx_brain_patterns_type").on(table.type),
|
|
3931
|
+
index2("idx_brain_patterns_impact").on(table.impact),
|
|
3932
|
+
index2("idx_brain_patterns_frequency").on(table.frequency)
|
|
3933
|
+
]);
|
|
3934
|
+
brainLearnings = sqliteTable2("brain_learnings", {
|
|
3935
|
+
id: text2("id").primaryKey(),
|
|
3936
|
+
insight: text2("insight").notNull(),
|
|
3937
|
+
source: text2("source").notNull(),
|
|
3938
|
+
confidence: real("confidence").notNull(),
|
|
3939
|
+
// 0.0-1.0
|
|
3940
|
+
actionable: integer2("actionable", { mode: "boolean" }).notNull().default(false),
|
|
3941
|
+
application: text2("application"),
|
|
3942
|
+
applicableTypesJson: text2("applicable_types_json"),
|
|
3943
|
+
createdAt: text2("created_at").notNull().default(sql3`(datetime('now'))`),
|
|
3944
|
+
updatedAt: text2("updated_at")
|
|
3945
|
+
}, (table) => [
|
|
3946
|
+
index2("idx_brain_learnings_confidence").on(table.confidence),
|
|
3947
|
+
index2("idx_brain_learnings_actionable").on(table.actionable)
|
|
3948
|
+
]);
|
|
3949
|
+
brainObservations = sqliteTable2("brain_observations", {
|
|
3950
|
+
id: text2("id").primaryKey(),
|
|
3951
|
+
type: text2("type", { enum: BRAIN_OBSERVATION_TYPES }).notNull(),
|
|
3952
|
+
title: text2("title").notNull(),
|
|
3953
|
+
subtitle: text2("subtitle"),
|
|
3954
|
+
narrative: text2("narrative"),
|
|
3955
|
+
factsJson: text2("facts_json"),
|
|
3956
|
+
// JSON array of fact strings
|
|
3957
|
+
conceptsJson: text2("concepts_json"),
|
|
3958
|
+
// JSON array of concept strings
|
|
3959
|
+
project: text2("project"),
|
|
3960
|
+
filesReadJson: text2("files_read_json"),
|
|
3961
|
+
// JSON array of file paths
|
|
3962
|
+
filesModifiedJson: text2("files_modified_json"),
|
|
3963
|
+
// JSON array of file paths
|
|
3964
|
+
sourceSessionId: text2("source_session_id"),
|
|
3965
|
+
// soft FK to sessions
|
|
3966
|
+
sourceType: text2("source_type", { enum: BRAIN_OBSERVATION_SOURCE_TYPES }).notNull().default("agent"),
|
|
3967
|
+
contentHash: text2("content_hash"),
|
|
3968
|
+
// SHA-256 prefix for dedup
|
|
3969
|
+
discoveryTokens: integer2("discovery_tokens"),
|
|
3970
|
+
// cost to produce this observation
|
|
3971
|
+
createdAt: text2("created_at").notNull().default(sql3`(datetime('now'))`),
|
|
3972
|
+
updatedAt: text2("updated_at")
|
|
3973
|
+
}, (table) => [
|
|
3974
|
+
index2("idx_brain_observations_type").on(table.type),
|
|
3975
|
+
index2("idx_brain_observations_project").on(table.project),
|
|
3976
|
+
index2("idx_brain_observations_created_at").on(table.createdAt),
|
|
3977
|
+
index2("idx_brain_observations_source_type").on(table.sourceType),
|
|
3978
|
+
index2("idx_brain_observations_source_session").on(table.sourceSessionId),
|
|
3979
|
+
index2("idx_brain_observations_content_hash").on(table.contentHash)
|
|
3980
|
+
]);
|
|
3981
|
+
brainMemoryLinks = sqliteTable2("brain_memory_links", {
|
|
3982
|
+
memoryType: text2("memory_type", { enum: BRAIN_MEMORY_TYPES }).notNull(),
|
|
3983
|
+
memoryId: text2("memory_id").notNull(),
|
|
3984
|
+
taskId: text2("task_id").notNull(),
|
|
3985
|
+
// soft FK to tasks.id in tasks.db
|
|
3986
|
+
linkType: text2("link_type", { enum: BRAIN_LINK_TYPES }).notNull(),
|
|
3987
|
+
createdAt: text2("created_at").notNull().default(sql3`(datetime('now'))`)
|
|
3988
|
+
}, (table) => [
|
|
3989
|
+
primaryKey2({ columns: [table.memoryType, table.memoryId, table.taskId, table.linkType] }),
|
|
3990
|
+
index2("idx_brain_links_task").on(table.taskId),
|
|
3991
|
+
index2("idx_brain_links_memory").on(table.memoryType, table.memoryId)
|
|
3992
|
+
]);
|
|
3993
|
+
brainSchemaMeta = sqliteTable2("brain_schema_meta", {
|
|
3994
|
+
key: text2("key").primaryKey(),
|
|
3995
|
+
value: text2("value").notNull()
|
|
3996
|
+
});
|
|
3997
|
+
}
|
|
3998
|
+
});
|
|
3999
|
+
|
|
4000
|
+
// src/store/brain-sqlite.ts
|
|
4001
|
+
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
4002
|
+
import { dirname as dirname6, join as join11 } from "node:path";
|
|
4003
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
4004
|
+
import { readMigrationFiles as readMigrationFiles2 } from "drizzle-orm/migrator";
|
|
4005
|
+
import { drizzle as drizzle2 } from "drizzle-orm/sqlite-proxy";
|
|
4006
|
+
import { migrate as migrate2 } from "drizzle-orm/sqlite-proxy/migrator";
|
|
4007
|
+
function getBrainDbPath(cwd) {
|
|
4008
|
+
return join11(getCleoDirAbsolute(cwd), DB_FILENAME2);
|
|
4009
|
+
}
|
|
4010
|
+
function resolveBrainMigrationsFolder() {
|
|
4011
|
+
const __filename = fileURLToPath2(import.meta.url);
|
|
4012
|
+
const __dirname = dirname6(__filename);
|
|
4013
|
+
return join11(__dirname, "..", "..", "drizzle-brain");
|
|
4014
|
+
}
|
|
4015
|
+
function tableExists2(nativeDb, tableName) {
|
|
4016
|
+
const result = nativeDb.prepare(
|
|
4017
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name=?"
|
|
4018
|
+
).get(tableName);
|
|
4019
|
+
return !!result;
|
|
4020
|
+
}
|
|
4021
|
+
async function runBrainMigrations(nativeDb, db) {
|
|
4022
|
+
const migrationsFolder = resolveBrainMigrationsFolder();
|
|
4023
|
+
if (tableExists2(nativeDb, "brain_decisions") && !tableExists2(nativeDb, "__drizzle_migrations")) {
|
|
4024
|
+
const migrations = readMigrationFiles2({ migrationsFolder });
|
|
4025
|
+
const baseline = migrations[0];
|
|
4026
|
+
if (baseline) {
|
|
4027
|
+
nativeDb.exec(`
|
|
4028
|
+
CREATE TABLE IF NOT EXISTS "__drizzle_migrations" (
|
|
4029
|
+
id SERIAL PRIMARY KEY,
|
|
4030
|
+
hash text NOT NULL,
|
|
4031
|
+
created_at numeric
|
|
4032
|
+
)
|
|
4033
|
+
`);
|
|
4034
|
+
nativeDb.exec(
|
|
4035
|
+
`INSERT INTO "__drizzle_migrations" ("hash", "created_at") VALUES ('${baseline.hash}', ${baseline.folderMillis})`
|
|
4036
|
+
);
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
await migrate2(db, async (queries) => {
|
|
4040
|
+
nativeDb.prepare("BEGIN IMMEDIATE").run();
|
|
4041
|
+
try {
|
|
4042
|
+
for (const query of queries) {
|
|
4043
|
+
nativeDb.prepare(query).run();
|
|
4044
|
+
}
|
|
4045
|
+
nativeDb.prepare("COMMIT").run();
|
|
4046
|
+
} catch (err) {
|
|
4047
|
+
nativeDb.prepare("ROLLBACK").run();
|
|
4048
|
+
throw err;
|
|
4049
|
+
}
|
|
4050
|
+
}, { migrationsFolder });
|
|
4051
|
+
}
|
|
4052
|
+
async function getBrainDb(cwd) {
|
|
4053
|
+
const requestedPath = getBrainDbPath(cwd);
|
|
4054
|
+
if (_db2 && _dbPath2 !== requestedPath) {
|
|
4055
|
+
resetBrainDbState();
|
|
4056
|
+
}
|
|
4057
|
+
if (_db2) return _db2;
|
|
4058
|
+
if (_initPromise2) return _initPromise2;
|
|
4059
|
+
_initPromise2 = (async () => {
|
|
4060
|
+
const dbPath = requestedPath;
|
|
4061
|
+
_dbPath2 = dbPath;
|
|
4062
|
+
mkdirSync6(dirname6(dbPath), { recursive: true });
|
|
4063
|
+
const nativeDb = openNativeDatabase(dbPath);
|
|
4064
|
+
_nativeDb2 = nativeDb;
|
|
4065
|
+
const callback = createDrizzleCallback(nativeDb);
|
|
4066
|
+
const batchCb = createBatchCallback(nativeDb);
|
|
4067
|
+
const db = drizzle2(callback, batchCb, { schema: brain_schema_exports });
|
|
4068
|
+
await runBrainMigrations(nativeDb, db);
|
|
4069
|
+
nativeDb.exec(
|
|
4070
|
+
`INSERT OR IGNORE INTO brain_schema_meta (key, value) VALUES ('schemaVersion', '${BRAIN_SCHEMA_VERSION}')`
|
|
4071
|
+
);
|
|
4072
|
+
_db2 = db;
|
|
4073
|
+
return db;
|
|
4074
|
+
})();
|
|
4075
|
+
try {
|
|
4076
|
+
return await _initPromise2;
|
|
4077
|
+
} finally {
|
|
4078
|
+
_initPromise2 = null;
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
function resetBrainDbState() {
|
|
4082
|
+
if (_nativeDb2) {
|
|
4083
|
+
try {
|
|
4084
|
+
if (_nativeDb2.isOpen) {
|
|
4085
|
+
_nativeDb2.close();
|
|
4086
|
+
}
|
|
4087
|
+
} catch {
|
|
4088
|
+
}
|
|
4089
|
+
_nativeDb2 = null;
|
|
4090
|
+
}
|
|
4091
|
+
_db2 = null;
|
|
4092
|
+
_dbPath2 = null;
|
|
4093
|
+
_initPromise2 = null;
|
|
4094
|
+
}
|
|
4095
|
+
function getBrainNativeDb() {
|
|
4096
|
+
return _nativeDb2;
|
|
4097
|
+
}
|
|
4098
|
+
var DB_FILENAME2, BRAIN_SCHEMA_VERSION, _db2, _nativeDb2, _dbPath2, _initPromise2;
|
|
4099
|
+
var init_brain_sqlite = __esm({
|
|
4100
|
+
"src/store/brain-sqlite.ts"() {
|
|
4101
|
+
"use strict";
|
|
4102
|
+
init_brain_schema();
|
|
4103
|
+
init_paths();
|
|
4104
|
+
init_node_sqlite_adapter();
|
|
4105
|
+
DB_FILENAME2 = "brain.db";
|
|
4106
|
+
BRAIN_SCHEMA_VERSION = "1.0.0";
|
|
4107
|
+
_db2 = null;
|
|
4108
|
+
_nativeDb2 = null;
|
|
4109
|
+
_dbPath2 = null;
|
|
4110
|
+
_initPromise2 = null;
|
|
4111
|
+
}
|
|
4112
|
+
});
|
|
4113
|
+
|
|
4114
|
+
// src/core/memory/brain-search.ts
|
|
4115
|
+
function checkFts5Available(nativeDb) {
|
|
4116
|
+
if (_fts5Available !== null) return _fts5Available;
|
|
4117
|
+
try {
|
|
4118
|
+
nativeDb.prepare("CREATE VIRTUAL TABLE IF NOT EXISTS _fts5_check USING fts5(test)").run();
|
|
4119
|
+
nativeDb.prepare("DROP TABLE IF EXISTS _fts5_check").run();
|
|
4120
|
+
_fts5Available = true;
|
|
4121
|
+
} catch {
|
|
4122
|
+
_fts5Available = false;
|
|
4123
|
+
}
|
|
4124
|
+
return _fts5Available;
|
|
4125
|
+
}
|
|
4126
|
+
function execDDL(nativeDb, sql5) {
|
|
4127
|
+
nativeDb.prepare(sql5).run();
|
|
4128
|
+
}
|
|
4129
|
+
function ensureFts5Tables(nativeDb) {
|
|
4130
|
+
if (!checkFts5Available(nativeDb)) {
|
|
4131
|
+
return false;
|
|
4132
|
+
}
|
|
4133
|
+
execDDL(nativeDb, `
|
|
4134
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS brain_decisions_fts
|
|
4135
|
+
USING fts5(id, decision, rationale, content=brain_decisions, content_rowid=rowid)
|
|
4136
|
+
`);
|
|
4137
|
+
execDDL(nativeDb, `
|
|
4138
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS brain_patterns_fts
|
|
4139
|
+
USING fts5(id, pattern, context, content=brain_patterns, content_rowid=rowid)
|
|
4140
|
+
`);
|
|
4141
|
+
execDDL(nativeDb, `
|
|
4142
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS brain_learnings_fts
|
|
4143
|
+
USING fts5(id, insight, source, content=brain_learnings, content_rowid=rowid)
|
|
4144
|
+
`);
|
|
4145
|
+
execDDL(nativeDb, `
|
|
4146
|
+
CREATE TRIGGER IF NOT EXISTS brain_decisions_ai AFTER INSERT ON brain_decisions BEGIN
|
|
4147
|
+
INSERT INTO brain_decisions_fts(rowid, id, decision, rationale)
|
|
4148
|
+
VALUES (new.rowid, new.id, new.decision, new.rationale);
|
|
4149
|
+
END
|
|
4150
|
+
`);
|
|
4151
|
+
execDDL(nativeDb, `
|
|
4152
|
+
CREATE TRIGGER IF NOT EXISTS brain_decisions_ad AFTER DELETE ON brain_decisions BEGIN
|
|
4153
|
+
INSERT INTO brain_decisions_fts(brain_decisions_fts, rowid, id, decision, rationale)
|
|
4154
|
+
VALUES('delete', old.rowid, old.id, old.decision, old.rationale);
|
|
4155
|
+
END
|
|
4156
|
+
`);
|
|
4157
|
+
execDDL(nativeDb, `
|
|
4158
|
+
CREATE TRIGGER IF NOT EXISTS brain_decisions_au AFTER UPDATE ON brain_decisions BEGIN
|
|
4159
|
+
INSERT INTO brain_decisions_fts(brain_decisions_fts, rowid, id, decision, rationale)
|
|
4160
|
+
VALUES('delete', old.rowid, old.id, old.decision, old.rationale);
|
|
4161
|
+
INSERT INTO brain_decisions_fts(rowid, id, decision, rationale)
|
|
4162
|
+
VALUES (new.rowid, new.id, new.decision, new.rationale);
|
|
4163
|
+
END
|
|
4164
|
+
`);
|
|
4165
|
+
execDDL(nativeDb, `
|
|
4166
|
+
CREATE TRIGGER IF NOT EXISTS brain_patterns_ai AFTER INSERT ON brain_patterns BEGIN
|
|
4167
|
+
INSERT INTO brain_patterns_fts(rowid, id, pattern, context)
|
|
4168
|
+
VALUES (new.rowid, new.id, new.pattern, new.context);
|
|
4169
|
+
END
|
|
4170
|
+
`);
|
|
4171
|
+
execDDL(nativeDb, `
|
|
4172
|
+
CREATE TRIGGER IF NOT EXISTS brain_patterns_ad AFTER DELETE ON brain_patterns BEGIN
|
|
4173
|
+
INSERT INTO brain_patterns_fts(brain_patterns_fts, rowid, id, pattern, context)
|
|
4174
|
+
VALUES('delete', old.rowid, old.id, old.pattern, old.context);
|
|
4175
|
+
END
|
|
4176
|
+
`);
|
|
4177
|
+
execDDL(nativeDb, `
|
|
4178
|
+
CREATE TRIGGER IF NOT EXISTS brain_patterns_au AFTER UPDATE ON brain_patterns BEGIN
|
|
4179
|
+
INSERT INTO brain_patterns_fts(brain_patterns_fts, rowid, id, pattern, context)
|
|
4180
|
+
VALUES('delete', old.rowid, old.id, old.pattern, old.context);
|
|
4181
|
+
INSERT INTO brain_patterns_fts(rowid, id, pattern, context)
|
|
4182
|
+
VALUES (new.rowid, new.id, new.pattern, new.context);
|
|
4183
|
+
END
|
|
4184
|
+
`);
|
|
4185
|
+
execDDL(nativeDb, `
|
|
4186
|
+
CREATE TRIGGER IF NOT EXISTS brain_learnings_ai AFTER INSERT ON brain_learnings BEGIN
|
|
4187
|
+
INSERT INTO brain_learnings_fts(rowid, id, insight, source)
|
|
4188
|
+
VALUES (new.rowid, new.id, new.insight, new.source);
|
|
4189
|
+
END
|
|
4190
|
+
`);
|
|
4191
|
+
execDDL(nativeDb, `
|
|
4192
|
+
CREATE TRIGGER IF NOT EXISTS brain_learnings_ad AFTER DELETE ON brain_learnings BEGIN
|
|
4193
|
+
INSERT INTO brain_learnings_fts(brain_learnings_fts, rowid, id, insight, source)
|
|
4194
|
+
VALUES('delete', old.rowid, old.id, old.insight, old.source);
|
|
4195
|
+
END
|
|
4196
|
+
`);
|
|
4197
|
+
execDDL(nativeDb, `
|
|
4198
|
+
CREATE TRIGGER IF NOT EXISTS brain_learnings_au AFTER UPDATE ON brain_learnings BEGIN
|
|
4199
|
+
INSERT INTO brain_learnings_fts(brain_learnings_fts, rowid, id, insight, source)
|
|
4200
|
+
VALUES('delete', old.rowid, old.id, old.insight, old.source);
|
|
4201
|
+
INSERT INTO brain_learnings_fts(rowid, id, insight, source)
|
|
4202
|
+
VALUES (new.rowid, new.id, new.insight, new.source);
|
|
4203
|
+
END
|
|
4204
|
+
`);
|
|
4205
|
+
execDDL(nativeDb, `
|
|
4206
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS brain_observations_fts
|
|
4207
|
+
USING fts5(id, title, narrative, content=brain_observations, content_rowid=rowid)
|
|
4208
|
+
`);
|
|
4209
|
+
execDDL(nativeDb, `
|
|
4210
|
+
CREATE TRIGGER IF NOT EXISTS brain_observations_ai AFTER INSERT ON brain_observations BEGIN
|
|
4211
|
+
INSERT INTO brain_observations_fts(rowid, id, title, narrative)
|
|
4212
|
+
VALUES (new.rowid, new.id, new.title, new.narrative);
|
|
4213
|
+
END
|
|
4214
|
+
`);
|
|
4215
|
+
execDDL(nativeDb, `
|
|
4216
|
+
CREATE TRIGGER IF NOT EXISTS brain_observations_ad AFTER DELETE ON brain_observations BEGIN
|
|
4217
|
+
INSERT INTO brain_observations_fts(brain_observations_fts, rowid, id, title, narrative)
|
|
4218
|
+
VALUES('delete', old.rowid, old.id, old.title, old.narrative);
|
|
4219
|
+
END
|
|
4220
|
+
`);
|
|
4221
|
+
execDDL(nativeDb, `
|
|
4222
|
+
CREATE TRIGGER IF NOT EXISTS brain_observations_au AFTER UPDATE ON brain_observations BEGIN
|
|
4223
|
+
INSERT INTO brain_observations_fts(brain_observations_fts, rowid, id, title, narrative)
|
|
4224
|
+
VALUES('delete', old.rowid, old.id, old.title, old.narrative);
|
|
4225
|
+
INSERT INTO brain_observations_fts(rowid, id, title, narrative)
|
|
4226
|
+
VALUES (new.rowid, new.id, new.title, new.narrative);
|
|
4227
|
+
END
|
|
4228
|
+
`);
|
|
4229
|
+
return true;
|
|
4230
|
+
}
|
|
4231
|
+
function rebuildFts5Index(nativeDb) {
|
|
4232
|
+
if (!checkFts5Available(nativeDb)) {
|
|
4233
|
+
return;
|
|
4234
|
+
}
|
|
4235
|
+
nativeDb.prepare("INSERT INTO brain_decisions_fts(brain_decisions_fts) VALUES('rebuild')").run();
|
|
4236
|
+
nativeDb.prepare("INSERT INTO brain_patterns_fts(brain_patterns_fts) VALUES('rebuild')").run();
|
|
4237
|
+
nativeDb.prepare("INSERT INTO brain_learnings_fts(brain_learnings_fts) VALUES('rebuild')").run();
|
|
4238
|
+
try {
|
|
4239
|
+
nativeDb.prepare("INSERT INTO brain_observations_fts(brain_observations_fts) VALUES('rebuild')").run();
|
|
4240
|
+
} catch {
|
|
4241
|
+
}
|
|
4242
|
+
}
|
|
4243
|
+
async function searchBrain(projectRoot, query, options) {
|
|
4244
|
+
if (!query || !query.trim()) {
|
|
4245
|
+
return { decisions: [], patterns: [], learnings: [], observations: [] };
|
|
4246
|
+
}
|
|
4247
|
+
await getBrainDb(projectRoot);
|
|
4248
|
+
const nativeDb = getBrainNativeDb();
|
|
4249
|
+
if (!nativeDb) {
|
|
4250
|
+
return { decisions: [], patterns: [], learnings: [], observations: [] };
|
|
4251
|
+
}
|
|
4252
|
+
const limit = options?.limit ?? 10;
|
|
4253
|
+
const tables = options?.tables ?? ["decisions", "patterns", "learnings", "observations"];
|
|
4254
|
+
const ftsAvailable = ensureFts5Tables(nativeDb);
|
|
4255
|
+
if (ftsAvailable) {
|
|
4256
|
+
if (!_fts5Initialized) {
|
|
4257
|
+
_fts5Initialized = true;
|
|
4258
|
+
rebuildFts5Index(nativeDb);
|
|
4259
|
+
}
|
|
4260
|
+
return searchWithFts5(nativeDb, query, tables, limit);
|
|
4261
|
+
}
|
|
4262
|
+
return searchWithLike(nativeDb, query, tables, limit);
|
|
4263
|
+
}
|
|
4264
|
+
function searchWithFts5(nativeDb, query, tables, limit) {
|
|
4265
|
+
const result = {
|
|
4266
|
+
decisions: [],
|
|
4267
|
+
patterns: [],
|
|
4268
|
+
learnings: [],
|
|
4269
|
+
observations: []
|
|
4270
|
+
};
|
|
4271
|
+
const safeQuery = escapeFts5Query(query);
|
|
4272
|
+
if (tables.includes("decisions")) {
|
|
4273
|
+
try {
|
|
4274
|
+
const rows = nativeDb.prepare(`
|
|
4275
|
+
SELECT d.*
|
|
4276
|
+
FROM brain_decisions_fts fts
|
|
4277
|
+
JOIN brain_decisions d ON d.rowid = fts.rowid
|
|
4278
|
+
WHERE brain_decisions_fts MATCH ?
|
|
4279
|
+
ORDER BY bm25(brain_decisions_fts)
|
|
4280
|
+
LIMIT ?
|
|
4281
|
+
`).all(safeQuery, limit);
|
|
4282
|
+
result.decisions = rows;
|
|
4283
|
+
} catch {
|
|
4284
|
+
result.decisions = likeSearchDecisions(nativeDb, query, limit);
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
if (tables.includes("patterns")) {
|
|
4288
|
+
try {
|
|
4289
|
+
const rows = nativeDb.prepare(`
|
|
4290
|
+
SELECT p.*
|
|
4291
|
+
FROM brain_patterns_fts fts
|
|
4292
|
+
JOIN brain_patterns p ON p.rowid = fts.rowid
|
|
4293
|
+
WHERE brain_patterns_fts MATCH ?
|
|
4294
|
+
ORDER BY bm25(brain_patterns_fts)
|
|
4295
|
+
LIMIT ?
|
|
4296
|
+
`).all(safeQuery, limit);
|
|
4297
|
+
result.patterns = rows;
|
|
4298
|
+
} catch {
|
|
4299
|
+
result.patterns = likeSearchPatterns(nativeDb, query, limit);
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
if (tables.includes("learnings")) {
|
|
4303
|
+
try {
|
|
4304
|
+
const rows = nativeDb.prepare(`
|
|
4305
|
+
SELECT l.*
|
|
4306
|
+
FROM brain_learnings_fts fts
|
|
4307
|
+
JOIN brain_learnings l ON l.rowid = fts.rowid
|
|
4308
|
+
WHERE brain_learnings_fts MATCH ?
|
|
4309
|
+
ORDER BY bm25(brain_learnings_fts)
|
|
4310
|
+
LIMIT ?
|
|
4311
|
+
`).all(safeQuery, limit);
|
|
4312
|
+
result.learnings = rows;
|
|
4313
|
+
} catch {
|
|
4314
|
+
result.learnings = likeSearchLearnings(nativeDb, query, limit);
|
|
4315
|
+
}
|
|
4316
|
+
}
|
|
4317
|
+
if (tables.includes("observations")) {
|
|
4318
|
+
try {
|
|
4319
|
+
const rows = nativeDb.prepare(`
|
|
4320
|
+
SELECT o.*
|
|
4321
|
+
FROM brain_observations_fts fts
|
|
4322
|
+
JOIN brain_observations o ON o.rowid = fts.rowid
|
|
4323
|
+
WHERE brain_observations_fts MATCH ?
|
|
4324
|
+
ORDER BY bm25(brain_observations_fts)
|
|
4325
|
+
LIMIT ?
|
|
4326
|
+
`).all(safeQuery, limit);
|
|
4327
|
+
result.observations = rows;
|
|
4328
|
+
} catch {
|
|
4329
|
+
result.observations = likeSearchObservations(nativeDb, query, limit);
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
return result;
|
|
4333
|
+
}
|
|
4334
|
+
function searchWithLike(nativeDb, query, tables, limit) {
|
|
4335
|
+
const result = {
|
|
4336
|
+
decisions: [],
|
|
4337
|
+
patterns: [],
|
|
4338
|
+
learnings: [],
|
|
4339
|
+
observations: []
|
|
4340
|
+
};
|
|
4341
|
+
if (tables.includes("decisions")) {
|
|
4342
|
+
result.decisions = likeSearchDecisions(nativeDb, query, limit);
|
|
4343
|
+
}
|
|
4344
|
+
if (tables.includes("patterns")) {
|
|
4345
|
+
result.patterns = likeSearchPatterns(nativeDb, query, limit);
|
|
4346
|
+
}
|
|
4347
|
+
if (tables.includes("learnings")) {
|
|
4348
|
+
result.learnings = likeSearchLearnings(nativeDb, query, limit);
|
|
4349
|
+
}
|
|
4350
|
+
if (tables.includes("observations")) {
|
|
4351
|
+
result.observations = likeSearchObservations(nativeDb, query, limit);
|
|
4352
|
+
}
|
|
4353
|
+
return result;
|
|
4354
|
+
}
|
|
4355
|
+
function likeSearchDecisions(nativeDb, query, limit) {
|
|
4356
|
+
const likePattern = `%${query}%`;
|
|
4357
|
+
return nativeDb.prepare(`
|
|
4358
|
+
SELECT * FROM brain_decisions
|
|
4359
|
+
WHERE decision LIKE ? OR rationale LIKE ?
|
|
4360
|
+
ORDER BY created_at DESC
|
|
4361
|
+
LIMIT ?
|
|
4362
|
+
`).all(likePattern, likePattern, limit);
|
|
4363
|
+
}
|
|
4364
|
+
function likeSearchPatterns(nativeDb, query, limit) {
|
|
4365
|
+
const likePattern = `%${query}%`;
|
|
4366
|
+
return nativeDb.prepare(`
|
|
4367
|
+
SELECT * FROM brain_patterns
|
|
4368
|
+
WHERE pattern LIKE ? OR context LIKE ?
|
|
4369
|
+
ORDER BY frequency DESC
|
|
4370
|
+
LIMIT ?
|
|
4371
|
+
`).all(likePattern, likePattern, limit);
|
|
4372
|
+
}
|
|
4373
|
+
function likeSearchLearnings(nativeDb, query, limit) {
|
|
4374
|
+
const likePattern = `%${query}%`;
|
|
4375
|
+
return nativeDb.prepare(`
|
|
4376
|
+
SELECT * FROM brain_learnings
|
|
4377
|
+
WHERE insight LIKE ? OR source LIKE ?
|
|
4378
|
+
ORDER BY confidence DESC
|
|
4379
|
+
LIMIT ?
|
|
4380
|
+
`).all(likePattern, likePattern, limit);
|
|
4381
|
+
}
|
|
4382
|
+
function likeSearchObservations(nativeDb, query, limit) {
|
|
4383
|
+
const likePattern = `%${query}%`;
|
|
4384
|
+
return nativeDb.prepare(`
|
|
4385
|
+
SELECT * FROM brain_observations
|
|
4386
|
+
WHERE title LIKE ? OR narrative LIKE ?
|
|
4387
|
+
ORDER BY created_at DESC
|
|
4388
|
+
LIMIT ?
|
|
4389
|
+
`).all(likePattern, likePattern, limit);
|
|
4390
|
+
}
|
|
4391
|
+
function escapeFts5Query(query) {
|
|
4392
|
+
const tokens = query.trim().split(/\s+/).filter(Boolean);
|
|
4393
|
+
if (tokens.length === 0) return '""';
|
|
4394
|
+
return tokens.map((t) => `"${t.replace(/"/g, '""')}"`).join(" ");
|
|
4395
|
+
}
|
|
4396
|
+
var _fts5Available, _fts5Initialized;
|
|
4397
|
+
var init_brain_search = __esm({
|
|
4398
|
+
"src/core/memory/brain-search.ts"() {
|
|
4399
|
+
"use strict";
|
|
4400
|
+
init_brain_sqlite();
|
|
4401
|
+
_fts5Available = null;
|
|
4402
|
+
_fts5Initialized = false;
|
|
4403
|
+
}
|
|
4404
|
+
});
|
|
4405
|
+
|
|
4406
|
+
// src/store/brain-accessor.ts
|
|
4407
|
+
import { eq as eq7, and as and2, gte, desc, asc as asc2 } from "drizzle-orm";
|
|
4408
|
+
async function getBrainAccessor(cwd) {
|
|
4409
|
+
const db = await getBrainDb(cwd);
|
|
4410
|
+
return new BrainDataAccessor(db);
|
|
4411
|
+
}
|
|
4412
|
+
var BrainDataAccessor;
|
|
4413
|
+
var init_brain_accessor = __esm({
|
|
4414
|
+
"src/store/brain-accessor.ts"() {
|
|
4415
|
+
"use strict";
|
|
4416
|
+
init_brain_sqlite();
|
|
4417
|
+
init_brain_schema();
|
|
4418
|
+
BrainDataAccessor = class {
|
|
4419
|
+
constructor(db) {
|
|
4420
|
+
this.db = db;
|
|
4421
|
+
}
|
|
4422
|
+
// =========================================================================
|
|
4423
|
+
// Decisions CRUD
|
|
4424
|
+
// =========================================================================
|
|
4425
|
+
async addDecision(row) {
|
|
4426
|
+
await this.db.insert(brainDecisions).values(row);
|
|
4427
|
+
const result = await this.db.select().from(brainDecisions).where(eq7(brainDecisions.id, row.id));
|
|
4428
|
+
return result[0];
|
|
4429
|
+
}
|
|
4430
|
+
async getDecision(id) {
|
|
4431
|
+
const result = await this.db.select().from(brainDecisions).where(eq7(brainDecisions.id, id));
|
|
4432
|
+
return result[0] ?? null;
|
|
4433
|
+
}
|
|
4434
|
+
async findDecisions(params = {}) {
|
|
4435
|
+
const conditions = [];
|
|
4436
|
+
if (params.type) {
|
|
4437
|
+
conditions.push(eq7(brainDecisions.type, params.type));
|
|
4438
|
+
}
|
|
4439
|
+
if (params.confidence) {
|
|
4440
|
+
conditions.push(eq7(brainDecisions.confidence, params.confidence));
|
|
4441
|
+
}
|
|
4442
|
+
if (params.outcome) {
|
|
4443
|
+
conditions.push(eq7(brainDecisions.outcome, params.outcome));
|
|
4444
|
+
}
|
|
4445
|
+
if (params.contextTaskId) {
|
|
4446
|
+
conditions.push(eq7(brainDecisions.contextTaskId, params.contextTaskId));
|
|
4447
|
+
}
|
|
4448
|
+
let query = this.db.select().from(brainDecisions).orderBy(desc(brainDecisions.createdAt));
|
|
4449
|
+
if (conditions.length > 0) {
|
|
4450
|
+
query = query.where(and2(...conditions));
|
|
4451
|
+
}
|
|
4452
|
+
if (params.limit) {
|
|
4453
|
+
query = query.limit(params.limit);
|
|
4454
|
+
}
|
|
4455
|
+
return query;
|
|
4456
|
+
}
|
|
4457
|
+
async updateDecision(id, updates) {
|
|
4458
|
+
await this.db.update(brainDecisions).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainDecisions.id, id));
|
|
4459
|
+
}
|
|
4460
|
+
// =========================================================================
|
|
4461
|
+
// Patterns CRUD
|
|
4462
|
+
// =========================================================================
|
|
4463
|
+
async addPattern(row) {
|
|
4464
|
+
await this.db.insert(brainPatterns).values(row);
|
|
4465
|
+
const result = await this.db.select().from(brainPatterns).where(eq7(brainPatterns.id, row.id));
|
|
4466
|
+
return result[0];
|
|
4467
|
+
}
|
|
4468
|
+
async getPattern(id) {
|
|
4469
|
+
const result = await this.db.select().from(brainPatterns).where(eq7(brainPatterns.id, id));
|
|
4470
|
+
return result[0] ?? null;
|
|
4471
|
+
}
|
|
4472
|
+
async findPatterns(params = {}) {
|
|
4473
|
+
const conditions = [];
|
|
4474
|
+
if (params.type) {
|
|
4475
|
+
conditions.push(eq7(brainPatterns.type, params.type));
|
|
4476
|
+
}
|
|
4477
|
+
if (params.impact) {
|
|
4478
|
+
conditions.push(eq7(brainPatterns.impact, params.impact));
|
|
4479
|
+
}
|
|
4480
|
+
if (params.minFrequency !== void 0) {
|
|
4481
|
+
conditions.push(gte(brainPatterns.frequency, params.minFrequency));
|
|
4482
|
+
}
|
|
4483
|
+
let query = this.db.select().from(brainPatterns).orderBy(desc(brainPatterns.frequency));
|
|
4484
|
+
if (conditions.length > 0) {
|
|
4485
|
+
query = query.where(and2(...conditions));
|
|
4486
|
+
}
|
|
4487
|
+
if (params.limit) {
|
|
4488
|
+
query = query.limit(params.limit);
|
|
4489
|
+
}
|
|
4490
|
+
return query;
|
|
4491
|
+
}
|
|
4492
|
+
async updatePattern(id, updates) {
|
|
4493
|
+
await this.db.update(brainPatterns).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainPatterns.id, id));
|
|
4494
|
+
}
|
|
4495
|
+
// =========================================================================
|
|
4496
|
+
// Learnings CRUD
|
|
4497
|
+
// =========================================================================
|
|
4498
|
+
async addLearning(row) {
|
|
4499
|
+
await this.db.insert(brainLearnings).values(row);
|
|
4500
|
+
const result = await this.db.select().from(brainLearnings).where(eq7(brainLearnings.id, row.id));
|
|
4501
|
+
return result[0];
|
|
4502
|
+
}
|
|
4503
|
+
async getLearning(id) {
|
|
4504
|
+
const result = await this.db.select().from(brainLearnings).where(eq7(brainLearnings.id, id));
|
|
4505
|
+
return result[0] ?? null;
|
|
4506
|
+
}
|
|
4507
|
+
async findLearnings(params = {}) {
|
|
4508
|
+
const conditions = [];
|
|
4509
|
+
if (params.minConfidence !== void 0) {
|
|
4510
|
+
conditions.push(gte(brainLearnings.confidence, params.minConfidence));
|
|
4511
|
+
}
|
|
4512
|
+
if (params.actionable !== void 0) {
|
|
4513
|
+
conditions.push(eq7(brainLearnings.actionable, params.actionable));
|
|
4514
|
+
}
|
|
4515
|
+
let query = this.db.select().from(brainLearnings).orderBy(desc(brainLearnings.confidence));
|
|
4516
|
+
if (conditions.length > 0) {
|
|
4517
|
+
query = query.where(and2(...conditions));
|
|
4518
|
+
}
|
|
4519
|
+
if (params.limit) {
|
|
4520
|
+
query = query.limit(params.limit);
|
|
4521
|
+
}
|
|
4522
|
+
return query;
|
|
4523
|
+
}
|
|
4524
|
+
async updateLearning(id, updates) {
|
|
4525
|
+
await this.db.update(brainLearnings).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainLearnings.id, id));
|
|
4526
|
+
}
|
|
4527
|
+
// =========================================================================
|
|
4528
|
+
// Observations CRUD
|
|
4529
|
+
// =========================================================================
|
|
4530
|
+
async addObservation(row) {
|
|
4531
|
+
await this.db.insert(brainObservations).values(row);
|
|
4532
|
+
const result = await this.db.select().from(brainObservations).where(eq7(brainObservations.id, row.id));
|
|
4533
|
+
return result[0];
|
|
4534
|
+
}
|
|
4535
|
+
async getObservation(id) {
|
|
4536
|
+
const result = await this.db.select().from(brainObservations).where(eq7(brainObservations.id, id));
|
|
4537
|
+
return result[0] ?? null;
|
|
4538
|
+
}
|
|
4539
|
+
async findObservations(params = {}) {
|
|
4540
|
+
const conditions = [];
|
|
4541
|
+
if (params.type) {
|
|
4542
|
+
conditions.push(eq7(brainObservations.type, params.type));
|
|
4543
|
+
}
|
|
4544
|
+
if (params.project) {
|
|
4545
|
+
conditions.push(eq7(brainObservations.project, params.project));
|
|
4546
|
+
}
|
|
4547
|
+
if (params.sourceType) {
|
|
4548
|
+
conditions.push(eq7(brainObservations.sourceType, params.sourceType));
|
|
4549
|
+
}
|
|
4550
|
+
if (params.sourceSessionId) {
|
|
4551
|
+
conditions.push(eq7(brainObservations.sourceSessionId, params.sourceSessionId));
|
|
4552
|
+
}
|
|
4553
|
+
let query = this.db.select().from(brainObservations).orderBy(desc(brainObservations.createdAt));
|
|
4554
|
+
if (conditions.length > 0) {
|
|
4555
|
+
query = query.where(and2(...conditions));
|
|
4556
|
+
}
|
|
4557
|
+
if (params.limit) {
|
|
4558
|
+
query = query.limit(params.limit);
|
|
4559
|
+
}
|
|
4560
|
+
return query;
|
|
4561
|
+
}
|
|
4562
|
+
async updateObservation(id, updates) {
|
|
4563
|
+
await this.db.update(brainObservations).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainObservations.id, id));
|
|
4564
|
+
}
|
|
4565
|
+
// =========================================================================
|
|
4566
|
+
// Memory Links CRUD
|
|
4567
|
+
// =========================================================================
|
|
4568
|
+
async addLink(row) {
|
|
4569
|
+
await this.db.insert(brainMemoryLinks).values(row);
|
|
4570
|
+
}
|
|
4571
|
+
async getLinksForMemory(memoryType, memoryId) {
|
|
4572
|
+
return this.db.select().from(brainMemoryLinks).where(
|
|
4573
|
+
and2(
|
|
4574
|
+
eq7(brainMemoryLinks.memoryType, memoryType),
|
|
4575
|
+
eq7(brainMemoryLinks.memoryId, memoryId)
|
|
4576
|
+
)
|
|
4577
|
+
).orderBy(asc2(brainMemoryLinks.createdAt));
|
|
4578
|
+
}
|
|
4579
|
+
async getLinksForTask(taskId) {
|
|
4580
|
+
return this.db.select().from(brainMemoryLinks).where(eq7(brainMemoryLinks.taskId, taskId)).orderBy(asc2(brainMemoryLinks.createdAt));
|
|
4581
|
+
}
|
|
4582
|
+
async removeLink(memoryType, memoryId, taskId, linkType) {
|
|
4583
|
+
await this.db.delete(brainMemoryLinks).where(
|
|
4584
|
+
and2(
|
|
4585
|
+
eq7(brainMemoryLinks.memoryType, memoryType),
|
|
4586
|
+
eq7(brainMemoryLinks.memoryId, memoryId),
|
|
4587
|
+
eq7(brainMemoryLinks.taskId, taskId),
|
|
4588
|
+
eq7(brainMemoryLinks.linkType, linkType)
|
|
4589
|
+
)
|
|
4590
|
+
);
|
|
4591
|
+
}
|
|
4592
|
+
};
|
|
4593
|
+
}
|
|
4594
|
+
});
|
|
4595
|
+
|
|
4596
|
+
// src/core/memory/brain-retrieval.ts
|
|
4597
|
+
var brain_retrieval_exports = {};
|
|
4598
|
+
__export(brain_retrieval_exports, {
|
|
4599
|
+
fetchBrainEntries: () => fetchBrainEntries,
|
|
4600
|
+
observeBrain: () => observeBrain,
|
|
4601
|
+
searchBrainCompact: () => searchBrainCompact,
|
|
4602
|
+
timelineBrain: () => timelineBrain
|
|
4603
|
+
});
|
|
4604
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
4605
|
+
async function searchBrainCompact(projectRoot, params) {
|
|
4606
|
+
const { query, limit, tables, dateStart, dateEnd } = params;
|
|
4607
|
+
if (!query || !query.trim()) {
|
|
4608
|
+
return { results: [], total: 0, tokensEstimated: 0 };
|
|
4609
|
+
}
|
|
4610
|
+
const searchResult = await searchBrain(projectRoot, query, {
|
|
4611
|
+
limit: limit ?? 10,
|
|
4612
|
+
tables
|
|
4613
|
+
});
|
|
4614
|
+
let results = [];
|
|
4615
|
+
for (const d of searchResult.decisions) {
|
|
4616
|
+
const raw = d;
|
|
4617
|
+
results.push({
|
|
4618
|
+
id: d.id,
|
|
4619
|
+
type: "decision",
|
|
4620
|
+
title: d.decision.slice(0, 80),
|
|
4621
|
+
date: (d.createdAt ?? raw["created_at"]) || ""
|
|
4622
|
+
});
|
|
4623
|
+
}
|
|
4624
|
+
for (const p of searchResult.patterns) {
|
|
4625
|
+
const raw = p;
|
|
4626
|
+
results.push({
|
|
4627
|
+
id: p.id,
|
|
4628
|
+
type: "pattern",
|
|
4629
|
+
title: p.pattern.slice(0, 80),
|
|
4630
|
+
date: (p.extractedAt ?? raw["extracted_at"]) || ""
|
|
4631
|
+
});
|
|
4632
|
+
}
|
|
4633
|
+
for (const l of searchResult.learnings) {
|
|
4634
|
+
const raw = l;
|
|
4635
|
+
results.push({
|
|
4636
|
+
id: l.id,
|
|
4637
|
+
type: "learning",
|
|
4638
|
+
title: l.insight.slice(0, 80),
|
|
4639
|
+
date: (l.createdAt ?? raw["created_at"]) || ""
|
|
4640
|
+
});
|
|
4641
|
+
}
|
|
4642
|
+
for (const o of searchResult.observations) {
|
|
4643
|
+
const raw = o;
|
|
4644
|
+
results.push({
|
|
4645
|
+
id: o.id,
|
|
4646
|
+
type: "observation",
|
|
4647
|
+
title: o.title.slice(0, 80),
|
|
4648
|
+
date: (o.createdAt ?? raw["created_at"]) || ""
|
|
4649
|
+
});
|
|
4650
|
+
}
|
|
4651
|
+
if (dateStart) {
|
|
4652
|
+
results = results.filter((r) => r.date >= dateStart);
|
|
4653
|
+
}
|
|
4654
|
+
if (dateEnd) {
|
|
4655
|
+
results = results.filter((r) => r.date <= dateEnd);
|
|
4656
|
+
}
|
|
4657
|
+
return {
|
|
4658
|
+
results,
|
|
4659
|
+
total: results.length,
|
|
4660
|
+
tokensEstimated: results.length * 50
|
|
4661
|
+
};
|
|
4662
|
+
}
|
|
4663
|
+
function parseIdPrefix(id) {
|
|
4664
|
+
if (id.startsWith("D-") || /^D\d/.test(id)) return "decision";
|
|
4665
|
+
if (id.startsWith("P-") || /^P\d/.test(id)) return "pattern";
|
|
4666
|
+
if (id.startsWith("L-") || /^L\d/.test(id)) return "learning";
|
|
4667
|
+
if (id.startsWith("O-") || id.startsWith("O") || id.startsWith("CM-")) return "observation";
|
|
4668
|
+
return null;
|
|
4669
|
+
}
|
|
4670
|
+
async function timelineBrain(projectRoot, params) {
|
|
4671
|
+
const { anchor: anchorId, depthBefore = 3, depthAfter = 3 } = params;
|
|
4672
|
+
await getBrainDb(projectRoot);
|
|
4673
|
+
const nativeDb = getBrainNativeDb();
|
|
4674
|
+
if (!nativeDb) {
|
|
4675
|
+
return { anchor: null, before: [], after: [] };
|
|
4676
|
+
}
|
|
4677
|
+
const anchorType = parseIdPrefix(anchorId);
|
|
4678
|
+
if (!anchorType) {
|
|
4679
|
+
return { anchor: null, before: [], after: [] };
|
|
4680
|
+
}
|
|
4681
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4682
|
+
let anchorData = null;
|
|
4683
|
+
let anchorDate = null;
|
|
4684
|
+
switch (anchorType) {
|
|
4685
|
+
case "decision": {
|
|
4686
|
+
const row = await accessor.getDecision(anchorId);
|
|
4687
|
+
if (row) {
|
|
4688
|
+
anchorData = row;
|
|
4689
|
+
anchorDate = row.createdAt;
|
|
4690
|
+
}
|
|
4691
|
+
break;
|
|
4692
|
+
}
|
|
4693
|
+
case "pattern": {
|
|
4694
|
+
const row = await accessor.getPattern(anchorId);
|
|
4695
|
+
if (row) {
|
|
4696
|
+
anchorData = row;
|
|
4697
|
+
anchorDate = row.extractedAt;
|
|
4698
|
+
}
|
|
4699
|
+
break;
|
|
4700
|
+
}
|
|
4701
|
+
case "learning": {
|
|
4702
|
+
const row = await accessor.getLearning(anchorId);
|
|
4703
|
+
if (row) {
|
|
4704
|
+
anchorData = row;
|
|
4705
|
+
anchorDate = row.createdAt;
|
|
4706
|
+
}
|
|
4707
|
+
break;
|
|
4708
|
+
}
|
|
4709
|
+
case "observation": {
|
|
4710
|
+
const row = await accessor.getObservation(anchorId);
|
|
4711
|
+
if (row) {
|
|
4712
|
+
anchorData = row;
|
|
4713
|
+
anchorDate = row.createdAt;
|
|
4714
|
+
}
|
|
4715
|
+
break;
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
if (!anchorData || !anchorDate) {
|
|
4719
|
+
return { anchor: null, before: [], after: [] };
|
|
4720
|
+
}
|
|
4721
|
+
const beforeRows = nativeDb.prepare(`
|
|
4722
|
+
SELECT id, 'decision' AS type, created_at AS date FROM brain_decisions WHERE created_at < ? AND id != ?
|
|
4723
|
+
UNION ALL
|
|
4724
|
+
SELECT id, 'pattern' AS type, extracted_at AS date FROM brain_patterns WHERE extracted_at < ? AND id != ?
|
|
4725
|
+
UNION ALL
|
|
4726
|
+
SELECT id, 'learning' AS type, created_at AS date FROM brain_learnings WHERE created_at < ? AND id != ?
|
|
4727
|
+
UNION ALL
|
|
4728
|
+
SELECT id, 'observation' AS type, created_at AS date FROM brain_observations WHERE created_at < ? AND id != ?
|
|
4729
|
+
ORDER BY date DESC
|
|
4730
|
+
LIMIT ?
|
|
4731
|
+
`).all(
|
|
4732
|
+
anchorDate,
|
|
4733
|
+
anchorId,
|
|
4734
|
+
anchorDate,
|
|
4735
|
+
anchorId,
|
|
4736
|
+
anchorDate,
|
|
4737
|
+
anchorId,
|
|
4738
|
+
anchorDate,
|
|
4739
|
+
anchorId,
|
|
4740
|
+
depthBefore
|
|
4741
|
+
);
|
|
4742
|
+
const afterRows = nativeDb.prepare(`
|
|
4743
|
+
SELECT id, 'decision' AS type, created_at AS date FROM brain_decisions WHERE created_at > ? AND id != ?
|
|
4744
|
+
UNION ALL
|
|
4745
|
+
SELECT id, 'pattern' AS type, extracted_at AS date FROM brain_patterns WHERE extracted_at > ? AND id != ?
|
|
4746
|
+
UNION ALL
|
|
4747
|
+
SELECT id, 'learning' AS type, created_at AS date FROM brain_learnings WHERE created_at > ? AND id != ?
|
|
4748
|
+
UNION ALL
|
|
4749
|
+
SELECT id, 'observation' AS type, created_at AS date FROM brain_observations WHERE created_at > ? AND id != ?
|
|
4750
|
+
ORDER BY date ASC
|
|
4751
|
+
LIMIT ?
|
|
4752
|
+
`).all(
|
|
4753
|
+
anchorDate,
|
|
4754
|
+
anchorId,
|
|
4755
|
+
anchorDate,
|
|
4756
|
+
anchorId,
|
|
4757
|
+
anchorDate,
|
|
4758
|
+
anchorId,
|
|
4759
|
+
anchorDate,
|
|
4760
|
+
anchorId,
|
|
4761
|
+
depthAfter
|
|
4762
|
+
);
|
|
4763
|
+
return {
|
|
4764
|
+
anchor: { id: anchorId, type: anchorType, data: anchorData },
|
|
4765
|
+
before: beforeRows.map((r) => ({ id: r.id, type: r.type, date: r.date })),
|
|
4766
|
+
after: afterRows.map((r) => ({ id: r.id, type: r.type, date: r.date }))
|
|
4767
|
+
};
|
|
4768
|
+
}
|
|
4769
|
+
async function fetchBrainEntries(projectRoot, params) {
|
|
4770
|
+
const { ids } = params;
|
|
4771
|
+
if (!ids || ids.length === 0) {
|
|
4772
|
+
return { results: [], notFound: [], tokensEstimated: 0 };
|
|
4773
|
+
}
|
|
4774
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4775
|
+
const decisionIds = [];
|
|
4776
|
+
const patternIds = [];
|
|
4777
|
+
const learningIds = [];
|
|
4778
|
+
const observationIds = [];
|
|
4779
|
+
const unknownIds = [];
|
|
4780
|
+
for (const id of ids) {
|
|
4781
|
+
const type = parseIdPrefix(id);
|
|
4782
|
+
switch (type) {
|
|
4783
|
+
case "decision":
|
|
4784
|
+
decisionIds.push(id);
|
|
4785
|
+
break;
|
|
4786
|
+
case "pattern":
|
|
4787
|
+
patternIds.push(id);
|
|
4788
|
+
break;
|
|
4789
|
+
case "learning":
|
|
4790
|
+
learningIds.push(id);
|
|
4791
|
+
break;
|
|
4792
|
+
case "observation":
|
|
4793
|
+
observationIds.push(id);
|
|
4794
|
+
break;
|
|
4795
|
+
default:
|
|
4796
|
+
unknownIds.push(id);
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4799
|
+
const results = [];
|
|
4800
|
+
const notFound = [...unknownIds];
|
|
4801
|
+
for (const id of decisionIds) {
|
|
4802
|
+
const row = await accessor.getDecision(id);
|
|
4803
|
+
if (row) {
|
|
4804
|
+
results.push({ id, type: "decision", data: row });
|
|
4805
|
+
} else {
|
|
4806
|
+
notFound.push(id);
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
for (const id of patternIds) {
|
|
4810
|
+
const row = await accessor.getPattern(id);
|
|
4811
|
+
if (row) {
|
|
4812
|
+
results.push({ id, type: "pattern", data: row });
|
|
4813
|
+
} else {
|
|
4814
|
+
notFound.push(id);
|
|
4815
|
+
}
|
|
4816
|
+
}
|
|
4817
|
+
for (const id of learningIds) {
|
|
4818
|
+
const row = await accessor.getLearning(id);
|
|
4819
|
+
if (row) {
|
|
4820
|
+
results.push({ id, type: "learning", data: row });
|
|
4821
|
+
} else {
|
|
4822
|
+
notFound.push(id);
|
|
4823
|
+
}
|
|
4824
|
+
}
|
|
4825
|
+
for (const id of observationIds) {
|
|
4826
|
+
const row = await accessor.getObservation(id);
|
|
4827
|
+
if (row) {
|
|
4828
|
+
results.push({ id, type: "observation", data: row });
|
|
4829
|
+
} else {
|
|
4830
|
+
notFound.push(id);
|
|
4831
|
+
}
|
|
4832
|
+
}
|
|
4833
|
+
return {
|
|
4834
|
+
results,
|
|
4835
|
+
notFound,
|
|
4836
|
+
tokensEstimated: results.length * 500
|
|
4837
|
+
};
|
|
4838
|
+
}
|
|
4839
|
+
function classifyObservationType(text3) {
|
|
4840
|
+
const lower = text3.toLowerCase();
|
|
4841
|
+
for (const { keywords, type } of TYPE_KEYWORDS) {
|
|
4842
|
+
for (const keyword of keywords) {
|
|
4843
|
+
if (lower.includes(keyword)) {
|
|
4844
|
+
return type;
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
return "discovery";
|
|
4849
|
+
}
|
|
4850
|
+
async function observeBrain(projectRoot, params) {
|
|
4851
|
+
const { text: text3, title: titleParam, type: typeParam, project, sourceSessionId, sourceType } = params;
|
|
4852
|
+
if (!text3 || !text3.trim()) {
|
|
4853
|
+
throw new Error("Observation text is required");
|
|
4854
|
+
}
|
|
4855
|
+
const type = typeParam ?? classifyObservationType(text3);
|
|
4856
|
+
const title = titleParam ?? text3.slice(0, 120);
|
|
4857
|
+
const now = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
4858
|
+
const contentHash = createHash3("sha256").update(title + text3).digest("hex").slice(0, 16);
|
|
4859
|
+
const nativeDb = getBrainNativeDb();
|
|
4860
|
+
if (nativeDb) {
|
|
4861
|
+
const cutoff = new Date(Date.now() - 3e4).toISOString().replace("T", " ").slice(0, 19);
|
|
4862
|
+
const existing = nativeDb.prepare(
|
|
4863
|
+
"SELECT id, type, created_at FROM brain_observations WHERE content_hash = ? AND created_at > ?"
|
|
4864
|
+
).all(contentHash, cutoff);
|
|
4865
|
+
if (existing.length > 0) {
|
|
4866
|
+
return {
|
|
4867
|
+
id: existing[0].id,
|
|
4868
|
+
type: existing[0].type,
|
|
4869
|
+
createdAt: existing[0].created_at
|
|
4870
|
+
};
|
|
4871
|
+
}
|
|
4872
|
+
}
|
|
4873
|
+
const id = `O-${Date.now().toString(36)}`;
|
|
4874
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4875
|
+
const row = await accessor.addObservation({
|
|
4876
|
+
id,
|
|
4877
|
+
type,
|
|
4878
|
+
title,
|
|
4879
|
+
narrative: text3,
|
|
4880
|
+
contentHash,
|
|
4881
|
+
project: project ?? null,
|
|
4882
|
+
sourceSessionId: sourceSessionId ?? null,
|
|
4883
|
+
sourceType: sourceType ?? "agent",
|
|
4884
|
+
createdAt: now
|
|
4885
|
+
});
|
|
4886
|
+
return {
|
|
4887
|
+
id: row.id,
|
|
4888
|
+
type: row.type,
|
|
4889
|
+
createdAt: row.createdAt
|
|
4890
|
+
};
|
|
4891
|
+
}
|
|
4892
|
+
var TYPE_KEYWORDS;
|
|
4893
|
+
var init_brain_retrieval = __esm({
|
|
4894
|
+
"src/core/memory/brain-retrieval.ts"() {
|
|
4895
|
+
"use strict";
|
|
4896
|
+
init_brain_search();
|
|
4897
|
+
init_brain_accessor();
|
|
4898
|
+
init_brain_sqlite();
|
|
4899
|
+
TYPE_KEYWORDS = [
|
|
4900
|
+
{ keywords: ["bug", "fix", "error", "crash"], type: "bugfix" },
|
|
4901
|
+
{ keywords: ["refactor", "rename", "extract", "move"], type: "refactor" },
|
|
4902
|
+
{ keywords: ["add", "create", "implement", "new"], type: "feature" },
|
|
4903
|
+
{ keywords: ["decide", "chose", "pick", "instead"], type: "decision" },
|
|
4904
|
+
{ keywords: ["update", "change", "modify", "upgrade"], type: "change" }
|
|
4905
|
+
];
|
|
4906
|
+
}
|
|
4907
|
+
});
|
|
4908
|
+
|
|
4909
|
+
// src/core/memory/brain-links.ts
|
|
4910
|
+
var brain_links_exports = {};
|
|
4911
|
+
__export(brain_links_exports, {
|
|
4912
|
+
bulkLink: () => bulkLink,
|
|
4913
|
+
getLinkedDecisions: () => getLinkedDecisions,
|
|
4914
|
+
getLinkedLearnings: () => getLinkedLearnings,
|
|
4915
|
+
getLinkedPatterns: () => getLinkedPatterns,
|
|
4916
|
+
getMemoryLinks: () => getMemoryLinks,
|
|
4917
|
+
getTaskLinks: () => getTaskLinks,
|
|
4918
|
+
linkMemoryToTask: () => linkMemoryToTask,
|
|
4919
|
+
unlinkMemoryFromTask: () => unlinkMemoryFromTask
|
|
4920
|
+
});
|
|
4921
|
+
async function linkMemoryToTask(projectRoot, memoryType, memoryId, taskId, linkType) {
|
|
4922
|
+
if (!memoryId || !taskId) {
|
|
4923
|
+
throw new Error("memoryId and taskId are required");
|
|
4924
|
+
}
|
|
4925
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4926
|
+
const existingLinks = await accessor.getLinksForMemory(memoryType, memoryId);
|
|
4927
|
+
const duplicate = existingLinks.find(
|
|
4928
|
+
(l) => l.taskId === taskId && l.linkType === linkType
|
|
4929
|
+
);
|
|
4930
|
+
if (duplicate) {
|
|
4931
|
+
return duplicate;
|
|
4932
|
+
}
|
|
4933
|
+
await accessor.addLink({
|
|
4934
|
+
memoryType,
|
|
4935
|
+
memoryId,
|
|
4936
|
+
taskId,
|
|
4937
|
+
linkType
|
|
4938
|
+
});
|
|
4939
|
+
const links = await accessor.getLinksForMemory(memoryType, memoryId);
|
|
4940
|
+
return links.find(
|
|
4941
|
+
(l) => l.taskId === taskId && l.linkType === linkType
|
|
4942
|
+
);
|
|
4943
|
+
}
|
|
4944
|
+
async function unlinkMemoryFromTask(projectRoot, memoryType, memoryId, taskId, linkType) {
|
|
4945
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4946
|
+
await accessor.removeLink(memoryType, memoryId, taskId, linkType);
|
|
4947
|
+
}
|
|
4948
|
+
async function getTaskLinks(projectRoot, taskId) {
|
|
4949
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4950
|
+
return accessor.getLinksForTask(taskId);
|
|
4951
|
+
}
|
|
4952
|
+
async function getMemoryLinks(projectRoot, memoryType, memoryId) {
|
|
4953
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4954
|
+
return accessor.getLinksForMemory(memoryType, memoryId);
|
|
4955
|
+
}
|
|
4956
|
+
async function bulkLink(projectRoot, links) {
|
|
4957
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4958
|
+
let created = 0;
|
|
4959
|
+
let skipped = 0;
|
|
4960
|
+
for (const link of links) {
|
|
4961
|
+
const existing = await accessor.getLinksForMemory(link.memoryType, link.memoryId);
|
|
4962
|
+
const duplicate = existing.find(
|
|
4963
|
+
(l) => l.taskId === link.taskId && l.linkType === link.linkType
|
|
4964
|
+
);
|
|
4965
|
+
if (duplicate) {
|
|
4966
|
+
skipped++;
|
|
4967
|
+
continue;
|
|
4968
|
+
}
|
|
4969
|
+
await accessor.addLink({
|
|
4970
|
+
memoryType: link.memoryType,
|
|
4971
|
+
memoryId: link.memoryId,
|
|
4972
|
+
taskId: link.taskId,
|
|
4973
|
+
linkType: link.linkType
|
|
4974
|
+
});
|
|
4975
|
+
created++;
|
|
4976
|
+
}
|
|
4977
|
+
return { created, skipped };
|
|
4978
|
+
}
|
|
4979
|
+
async function getLinkedDecisions(projectRoot, taskId) {
|
|
4980
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4981
|
+
const links = await accessor.getLinksForTask(taskId);
|
|
4982
|
+
const decisionLinks = links.filter((l) => l.memoryType === "decision");
|
|
4983
|
+
const decisions = [];
|
|
4984
|
+
for (const link of decisionLinks) {
|
|
4985
|
+
const decision = await accessor.getDecision(link.memoryId);
|
|
4986
|
+
if (decision) {
|
|
4987
|
+
decisions.push(decision);
|
|
4988
|
+
}
|
|
4989
|
+
}
|
|
4990
|
+
return decisions;
|
|
4991
|
+
}
|
|
4992
|
+
async function getLinkedPatterns(projectRoot, taskId) {
|
|
4993
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
4994
|
+
const links = await accessor.getLinksForTask(taskId);
|
|
4995
|
+
const patternLinks = links.filter((l) => l.memoryType === "pattern");
|
|
4996
|
+
const patterns = [];
|
|
4997
|
+
for (const link of patternLinks) {
|
|
4998
|
+
const pattern = await accessor.getPattern(link.memoryId);
|
|
4999
|
+
if (pattern) {
|
|
5000
|
+
patterns.push(pattern);
|
|
5001
|
+
}
|
|
5002
|
+
}
|
|
5003
|
+
return patterns;
|
|
5004
|
+
}
|
|
5005
|
+
async function getLinkedLearnings(projectRoot, taskId) {
|
|
5006
|
+
const accessor = await getBrainAccessor(projectRoot);
|
|
5007
|
+
const links = await accessor.getLinksForTask(taskId);
|
|
5008
|
+
const learningLinks = links.filter((l) => l.memoryType === "learning");
|
|
5009
|
+
const learnings = [];
|
|
5010
|
+
for (const link of learningLinks) {
|
|
5011
|
+
const learning = await accessor.getLearning(link.memoryId);
|
|
5012
|
+
if (learning) {
|
|
5013
|
+
learnings.push(learning);
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
return learnings;
|
|
5017
|
+
}
|
|
5018
|
+
var init_brain_links = __esm({
|
|
5019
|
+
"src/core/memory/brain-links.ts"() {
|
|
5020
|
+
"use strict";
|
|
5021
|
+
init_brain_accessor();
|
|
5022
|
+
}
|
|
5023
|
+
});
|
|
5024
|
+
|
|
5025
|
+
// src/core/memory/session-memory.ts
|
|
5026
|
+
var session_memory_exports = {};
|
|
5027
|
+
__export(session_memory_exports, {
|
|
5028
|
+
extractMemoryItems: () => extractMemoryItems,
|
|
5029
|
+
getSessionMemoryContext: () => getSessionMemoryContext,
|
|
5030
|
+
persistSessionMemory: () => persistSessionMemory
|
|
5031
|
+
});
|
|
5032
|
+
function extractMemoryItems(sessionId, debrief) {
|
|
5033
|
+
if (!debrief) return [];
|
|
5034
|
+
const items = [];
|
|
5035
|
+
if (Array.isArray(debrief.decisions)) {
|
|
5036
|
+
for (const d of debrief.decisions) {
|
|
5037
|
+
const decision = d;
|
|
5038
|
+
if (!decision.decision) continue;
|
|
5039
|
+
const text3 = `Decision: ${decision.decision}
|
|
5040
|
+
Rationale: ${decision.rationale ?? "N/A"}`;
|
|
5041
|
+
items.push({
|
|
5042
|
+
text: text3,
|
|
5043
|
+
title: decision.decision.slice(0, 120),
|
|
5044
|
+
type: "decision",
|
|
5045
|
+
sourceSessionId: sessionId,
|
|
5046
|
+
sourceType: "session-debrief",
|
|
5047
|
+
linkTaskId: decision.taskId || void 0
|
|
5048
|
+
});
|
|
5049
|
+
}
|
|
5050
|
+
}
|
|
5051
|
+
const tasksCompleted = debrief.handoff?.tasksCompleted;
|
|
5052
|
+
if (Array.isArray(tasksCompleted) && tasksCompleted.length > 0) {
|
|
5053
|
+
const taskList2 = tasksCompleted.join(", ");
|
|
5054
|
+
const nextSuggested = debrief.handoff?.nextSuggested;
|
|
5055
|
+
const nextPart = Array.isArray(nextSuggested) && nextSuggested.length > 0 ? ` Next suggested: ${nextSuggested.join(", ")}` : "";
|
|
5056
|
+
const text3 = `Session ${sessionId} completed ${tasksCompleted.length} tasks: ${taskList2}.${nextPart}`;
|
|
5057
|
+
items.push({
|
|
5058
|
+
text: text3,
|
|
5059
|
+
title: `Session ${sessionId} summary: ${tasksCompleted.length} tasks completed`.slice(0, 120),
|
|
5060
|
+
type: "change",
|
|
5061
|
+
sourceSessionId: sessionId,
|
|
5062
|
+
sourceType: "session-debrief"
|
|
5063
|
+
});
|
|
5064
|
+
}
|
|
5065
|
+
const note = debrief.handoff?.note;
|
|
5066
|
+
if (typeof note === "string" && note.trim()) {
|
|
5067
|
+
items.push({
|
|
5068
|
+
text: note,
|
|
5069
|
+
title: `Session note: ${note.slice(0, 100)}`.slice(0, 120),
|
|
5070
|
+
type: "discovery",
|
|
5071
|
+
sourceSessionId: sessionId,
|
|
5072
|
+
sourceType: "session-debrief"
|
|
5073
|
+
});
|
|
5074
|
+
}
|
|
5075
|
+
return items;
|
|
5076
|
+
}
|
|
5077
|
+
async function persistSessionMemory(projectRoot, sessionId, debrief) {
|
|
5078
|
+
const result = {
|
|
5079
|
+
observationsCreated: 0,
|
|
5080
|
+
linksCreated: 0,
|
|
5081
|
+
observationIds: [],
|
|
5082
|
+
errors: []
|
|
5083
|
+
};
|
|
5084
|
+
if (!debrief) return result;
|
|
5085
|
+
const items = extractMemoryItems(sessionId, debrief);
|
|
5086
|
+
if (items.length === 0) return result;
|
|
5087
|
+
let observeBrain2;
|
|
5088
|
+
let linkMemoryToTask2;
|
|
5089
|
+
try {
|
|
5090
|
+
const retrieval = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
5091
|
+
observeBrain2 = retrieval.observeBrain;
|
|
5092
|
+
const links = await Promise.resolve().then(() => (init_brain_links(), brain_links_exports));
|
|
5093
|
+
linkMemoryToTask2 = links.linkMemoryToTask;
|
|
5094
|
+
} catch (err) {
|
|
5095
|
+
result.errors.push(`Failed to load brain modules: ${err instanceof Error ? err.message : String(err)}`);
|
|
5096
|
+
return result;
|
|
5097
|
+
}
|
|
5098
|
+
for (const item of items) {
|
|
5099
|
+
let obsResult = null;
|
|
5100
|
+
try {
|
|
5101
|
+
obsResult = await observeBrain2(projectRoot, {
|
|
5102
|
+
text: item.text,
|
|
5103
|
+
title: item.title,
|
|
5104
|
+
type: item.type,
|
|
5105
|
+
sourceSessionId: item.sourceSessionId,
|
|
5106
|
+
sourceType: item.sourceType
|
|
5107
|
+
});
|
|
5108
|
+
result.observationsCreated++;
|
|
5109
|
+
result.observationIds.push(obsResult.id);
|
|
5110
|
+
} catch (err) {
|
|
5111
|
+
result.errors.push(`Failed to create observation: ${err instanceof Error ? err.message : String(err)}`);
|
|
5112
|
+
continue;
|
|
5113
|
+
}
|
|
5114
|
+
if (item.linkTaskId && obsResult) {
|
|
5115
|
+
try {
|
|
5116
|
+
await linkMemoryToTask2(
|
|
5117
|
+
projectRoot,
|
|
5118
|
+
"observation",
|
|
5119
|
+
obsResult.id,
|
|
5120
|
+
item.linkTaskId,
|
|
5121
|
+
"produced_by"
|
|
5122
|
+
);
|
|
5123
|
+
result.linksCreated++;
|
|
5124
|
+
} catch (err) {
|
|
5125
|
+
result.errors.push(`Failed to link observation ${obsResult.id} to task ${item.linkTaskId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5126
|
+
}
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
5129
|
+
return result;
|
|
5130
|
+
}
|
|
5131
|
+
async function getSessionMemoryContext(projectRoot, scope, options) {
|
|
5132
|
+
const emptyContext = {
|
|
5133
|
+
recentDecisions: [],
|
|
5134
|
+
relevantPatterns: [],
|
|
5135
|
+
recentObservations: [],
|
|
5136
|
+
tokensEstimated: 0
|
|
5137
|
+
};
|
|
5138
|
+
let searchBrainCompact2;
|
|
5139
|
+
try {
|
|
5140
|
+
const retrieval = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
5141
|
+
searchBrainCompact2 = retrieval.searchBrainCompact;
|
|
5142
|
+
} catch {
|
|
5143
|
+
return emptyContext;
|
|
5144
|
+
}
|
|
5145
|
+
const limit = options?.limit ?? 5;
|
|
5146
|
+
const scopeQuery = scope?.rootTaskId ?? scope?.epicId ?? "";
|
|
5147
|
+
try {
|
|
5148
|
+
const [decisionsResult, patternsResult, observationsResult] = await Promise.all([
|
|
5149
|
+
// Decisions: scope-filtered if we have a task ID, otherwise recent
|
|
5150
|
+
scopeQuery ? searchBrainCompact2(projectRoot, {
|
|
5151
|
+
query: scopeQuery,
|
|
5152
|
+
limit,
|
|
5153
|
+
tables: ["decisions"]
|
|
5154
|
+
}) : Promise.resolve({ results: [], total: 0, tokensEstimated: 0 }),
|
|
5155
|
+
// Patterns: recent patterns
|
|
5156
|
+
searchBrainCompact2(projectRoot, {
|
|
5157
|
+
query: scopeQuery || "pattern",
|
|
5158
|
+
limit: Math.min(limit, 3),
|
|
5159
|
+
tables: ["patterns"]
|
|
5160
|
+
}),
|
|
5161
|
+
// Observations: recent session-debrief observations
|
|
5162
|
+
searchBrainCompact2(projectRoot, {
|
|
5163
|
+
query: scopeQuery || "session",
|
|
5164
|
+
limit,
|
|
5165
|
+
tables: ["observations"]
|
|
5166
|
+
})
|
|
5167
|
+
]);
|
|
5168
|
+
const tokensEstimated = decisionsResult.tokensEstimated + patternsResult.tokensEstimated + observationsResult.tokensEstimated;
|
|
5169
|
+
return {
|
|
5170
|
+
recentDecisions: decisionsResult.results,
|
|
5171
|
+
relevantPatterns: patternsResult.results,
|
|
5172
|
+
recentObservations: observationsResult.results,
|
|
5173
|
+
tokensEstimated
|
|
5174
|
+
};
|
|
5175
|
+
} catch {
|
|
5176
|
+
return emptyContext;
|
|
5177
|
+
}
|
|
5178
|
+
}
|
|
5179
|
+
var init_session_memory = __esm({
|
|
5180
|
+
"src/core/memory/session-memory.ts"() {
|
|
5181
|
+
"use strict";
|
|
5182
|
+
}
|
|
5183
|
+
});
|
|
5184
|
+
|
|
3853
5185
|
// src/core/platform.ts
|
|
3854
5186
|
var platform_exports = {};
|
|
3855
5187
|
__export(platform_exports, {
|
|
@@ -3877,9 +5209,9 @@ __export(platform_exports, {
|
|
|
3877
5209
|
});
|
|
3878
5210
|
import { execFileSync } from "node:child_process";
|
|
3879
5211
|
import { tmpdir } from "node:os";
|
|
3880
|
-
import { join as
|
|
5212
|
+
import { join as join12 } from "node:path";
|
|
3881
5213
|
import { existsSync as existsSync11, statSync as statSync2 } from "node:fs";
|
|
3882
|
-
import { createHash as
|
|
5214
|
+
import { createHash as createHash4, randomBytes as randomBytes6 } from "node:crypto";
|
|
3883
5215
|
function detectPlatform() {
|
|
3884
5216
|
switch (process.platform) {
|
|
3885
5217
|
case "linux":
|
|
@@ -3948,11 +5280,11 @@ function generateRandomHex(bytes = 6) {
|
|
|
3948
5280
|
return randomBytes6(bytes).toString("hex");
|
|
3949
5281
|
}
|
|
3950
5282
|
function sha256(data) {
|
|
3951
|
-
return
|
|
5283
|
+
return createHash4("sha256").update(data).digest("hex");
|
|
3952
5284
|
}
|
|
3953
5285
|
function createTempFilePath(prefix = "cleo-", suffix = ".tmp") {
|
|
3954
5286
|
const random = generateRandomHex(8);
|
|
3955
|
-
return
|
|
5287
|
+
return join12(tmpdir(), `${prefix}${random}${suffix}`);
|
|
3956
5288
|
}
|
|
3957
5289
|
function getNodeVersionInfo() {
|
|
3958
5290
|
const version = process.version.replace("v", "");
|
|
@@ -4021,7 +5353,7 @@ var init_platform = __esm({
|
|
|
4021
5353
|
|
|
4022
5354
|
// src/core/migration/preflight.ts
|
|
4023
5355
|
import { existsSync as existsSync13, readFileSync as readFileSync7, statSync as statSync3 } from "node:fs";
|
|
4024
|
-
import { join as
|
|
5356
|
+
import { join as join14 } from "node:path";
|
|
4025
5357
|
function checkStorageMigration(cwd) {
|
|
4026
5358
|
const cleoDir = getCleoDirAbsolute(cwd);
|
|
4027
5359
|
const details = {
|
|
@@ -4036,7 +5368,7 @@ function checkStorageMigration(cwd) {
|
|
|
4036
5368
|
tasksDbSize: 0,
|
|
4037
5369
|
configEngine: null
|
|
4038
5370
|
};
|
|
4039
|
-
const configPath =
|
|
5371
|
+
const configPath = join14(cleoDir, "config.json");
|
|
4040
5372
|
if (existsSync13(configPath)) {
|
|
4041
5373
|
try {
|
|
4042
5374
|
const config = JSON.parse(readFileSync7(configPath, "utf-8"));
|
|
@@ -4044,7 +5376,7 @@ function checkStorageMigration(cwd) {
|
|
|
4044
5376
|
} catch {
|
|
4045
5377
|
}
|
|
4046
5378
|
}
|
|
4047
|
-
const todoPath =
|
|
5379
|
+
const todoPath = join14(cleoDir, "todo.json");
|
|
4048
5380
|
if (existsSync13(todoPath)) {
|
|
4049
5381
|
details.todoJsonExists = true;
|
|
4050
5382
|
try {
|
|
@@ -4053,7 +5385,7 @@ function checkStorageMigration(cwd) {
|
|
|
4053
5385
|
} catch {
|
|
4054
5386
|
}
|
|
4055
5387
|
}
|
|
4056
|
-
const archivePath =
|
|
5388
|
+
const archivePath = join14(cleoDir, "todo-archive.json");
|
|
4057
5389
|
if (existsSync13(archivePath)) {
|
|
4058
5390
|
details.archiveJsonExists = true;
|
|
4059
5391
|
try {
|
|
@@ -4062,7 +5394,7 @@ function checkStorageMigration(cwd) {
|
|
|
4062
5394
|
} catch {
|
|
4063
5395
|
}
|
|
4064
5396
|
}
|
|
4065
|
-
const sessionsPath =
|
|
5397
|
+
const sessionsPath = join14(cleoDir, "sessions.json");
|
|
4066
5398
|
if (existsSync13(sessionsPath)) {
|
|
4067
5399
|
details.sessionsJsonExists = true;
|
|
4068
5400
|
try {
|
|
@@ -4071,11 +5403,11 @@ function checkStorageMigration(cwd) {
|
|
|
4071
5403
|
} catch {
|
|
4072
5404
|
}
|
|
4073
5405
|
}
|
|
4074
|
-
const tasksJsonPath =
|
|
5406
|
+
const tasksJsonPath = join14(cleoDir, "tasks.json");
|
|
4075
5407
|
if (existsSync13(tasksJsonPath)) {
|
|
4076
5408
|
details.tasksJsonExists = true;
|
|
4077
5409
|
}
|
|
4078
|
-
const dbPath =
|
|
5410
|
+
const dbPath = join14(cleoDir, "tasks.db");
|
|
4079
5411
|
if (existsSync13(dbPath)) {
|
|
4080
5412
|
details.tasksDbExists = true;
|
|
4081
5413
|
try {
|
|
@@ -4123,17 +5455,17 @@ import {
|
|
|
4123
5455
|
existsSync as existsSync14,
|
|
4124
5456
|
readFileSync as readFileSync8,
|
|
4125
5457
|
writeFileSync as writeFileSync2,
|
|
4126
|
-
mkdirSync as
|
|
5458
|
+
mkdirSync as mkdirSync7,
|
|
4127
5459
|
readdirSync as readdirSync3,
|
|
4128
5460
|
copyFileSync as copyFileSync2,
|
|
4129
5461
|
statSync as statSync4,
|
|
4130
5462
|
rmSync
|
|
4131
5463
|
} from "node:fs";
|
|
4132
|
-
import { join as
|
|
5464
|
+
import { join as join15 } from "node:path";
|
|
4133
5465
|
function detectLegacyAgentOutputs(projectRoot, cleoDir) {
|
|
4134
|
-
const hasResearchOutputs = existsSync14(
|
|
4135
|
-
const hasLegacyAgentOutputs = existsSync14(
|
|
4136
|
-
const hasCanonical = existsSync14(
|
|
5466
|
+
const hasResearchOutputs = existsSync14(join15(projectRoot, "claudedocs", "research-outputs"));
|
|
5467
|
+
const hasLegacyAgentOutputs = existsSync14(join15(projectRoot, "claudedocs", "agent-outputs"));
|
|
5468
|
+
const hasCanonical = existsSync14(join15(cleoDir, "agent-outputs"));
|
|
4137
5469
|
const legacyPaths = [];
|
|
4138
5470
|
if (hasResearchOutputs) legacyPaths.push("claudedocs/research-outputs/");
|
|
4139
5471
|
if (hasLegacyAgentOutputs) legacyPaths.push("claudedocs/agent-outputs/");
|
|
@@ -4156,15 +5488,15 @@ function migrateAgentOutputs(projectRoot, cleoDir) {
|
|
|
4156
5488
|
summary: "No legacy output directories found"
|
|
4157
5489
|
};
|
|
4158
5490
|
}
|
|
4159
|
-
const newDir =
|
|
5491
|
+
const newDir = join15(cleoDir, "agent-outputs");
|
|
4160
5492
|
const hadCanonical = detection.hasCanonical;
|
|
4161
|
-
|
|
5493
|
+
mkdirSync7(newDir, { recursive: true });
|
|
4162
5494
|
let totalCopied = 0;
|
|
4163
5495
|
const mergedManifestLines = [];
|
|
4164
5496
|
const copiedFiles = /* @__PURE__ */ new Set();
|
|
4165
5497
|
const legacySources = [
|
|
4166
|
-
{ path:
|
|
4167
|
-
{ path:
|
|
5498
|
+
{ path: join15(projectRoot, "claudedocs", "research-outputs"), exists: detection.hasResearchOutputs },
|
|
5499
|
+
{ path: join15(projectRoot, "claudedocs", "agent-outputs"), exists: detection.hasLegacyAgentOutputs }
|
|
4168
5500
|
];
|
|
4169
5501
|
for (const source of legacySources) {
|
|
4170
5502
|
if (!source.exists) continue;
|
|
@@ -4189,19 +5521,19 @@ function copyDirContents(srcDir, dstDir, manifestLines, copiedFiles) {
|
|
|
4189
5521
|
const entries = readdirSync3(srcDir);
|
|
4190
5522
|
for (const entry of entries) {
|
|
4191
5523
|
if (entry === "MANIFEST.jsonl") {
|
|
4192
|
-
collectManifestLines(
|
|
5524
|
+
collectManifestLines(join15(srcDir, entry), manifestLines);
|
|
4193
5525
|
continue;
|
|
4194
5526
|
}
|
|
4195
|
-
const srcPath =
|
|
4196
|
-
const dstPath =
|
|
5527
|
+
const srcPath = join15(srcDir, entry);
|
|
5528
|
+
const dstPath = join15(dstDir, entry);
|
|
4197
5529
|
try {
|
|
4198
5530
|
const st = statSync4(srcPath);
|
|
4199
5531
|
if (st.isDirectory()) {
|
|
4200
|
-
|
|
5532
|
+
mkdirSync7(dstPath, { recursive: true });
|
|
4201
5533
|
for (const sf of readdirSync3(srcPath)) {
|
|
4202
5534
|
if (!copiedFiles.has(sf)) {
|
|
4203
5535
|
try {
|
|
4204
|
-
copyFileSync2(
|
|
5536
|
+
copyFileSync2(join15(srcPath, sf), join15(dstPath, sf));
|
|
4205
5537
|
copiedFiles.add(sf);
|
|
4206
5538
|
count2++;
|
|
4207
5539
|
} catch {
|
|
@@ -4233,7 +5565,7 @@ function collectManifestLines(manifestPath, out) {
|
|
|
4233
5565
|
}
|
|
4234
5566
|
}
|
|
4235
5567
|
function mergeManifests(newDir, hadCanonical, legacyLines) {
|
|
4236
|
-
const manifestPath =
|
|
5568
|
+
const manifestPath = join15(newDir, "MANIFEST.jsonl");
|
|
4237
5569
|
const existingLines = [];
|
|
4238
5570
|
if (hadCanonical && existsSync14(manifestPath)) {
|
|
4239
5571
|
try {
|
|
@@ -4269,7 +5601,7 @@ function mergeManifests(newDir, hadCanonical, legacyLines) {
|
|
|
4269
5601
|
return finalLines.length;
|
|
4270
5602
|
}
|
|
4271
5603
|
function updateConfigPaths(cleoDir) {
|
|
4272
|
-
const configPath =
|
|
5604
|
+
const configPath = join15(cleoDir, "config.json");
|
|
4273
5605
|
if (!existsSync14(configPath)) return;
|
|
4274
5606
|
try {
|
|
4275
5607
|
const config = JSON.parse(readFileSync8(configPath, "utf-8"));
|
|
@@ -4295,19 +5627,19 @@ function removeLegacyDirs(projectRoot, detection) {
|
|
|
4295
5627
|
const removed = [];
|
|
4296
5628
|
if (detection.hasResearchOutputs) {
|
|
4297
5629
|
try {
|
|
4298
|
-
rmSync(
|
|
5630
|
+
rmSync(join15(projectRoot, "claudedocs", "research-outputs"), { recursive: true, force: true });
|
|
4299
5631
|
removed.push("claudedocs/research-outputs/");
|
|
4300
5632
|
} catch {
|
|
4301
5633
|
}
|
|
4302
5634
|
}
|
|
4303
5635
|
if (detection.hasLegacyAgentOutputs) {
|
|
4304
5636
|
try {
|
|
4305
|
-
rmSync(
|
|
5637
|
+
rmSync(join15(projectRoot, "claudedocs", "agent-outputs"), { recursive: true, force: true });
|
|
4306
5638
|
removed.push("claudedocs/agent-outputs/");
|
|
4307
5639
|
} catch {
|
|
4308
5640
|
}
|
|
4309
5641
|
}
|
|
4310
|
-
const claudedocsDir =
|
|
5642
|
+
const claudedocsDir = join15(projectRoot, "claudedocs");
|
|
4311
5643
|
if (existsSync14(claudedocsDir)) {
|
|
4312
5644
|
try {
|
|
4313
5645
|
if (readdirSync3(claudedocsDir).length === 0) {
|
|
@@ -4413,15 +5745,15 @@ __export(schema_management_exports, {
|
|
|
4413
5745
|
listInstalledSchemas: () => listInstalledSchemas,
|
|
4414
5746
|
resolveSchemaPath: () => resolveSchemaPath
|
|
4415
5747
|
});
|
|
4416
|
-
import { existsSync as existsSync15, readFileSync as readFileSync9, readdirSync as readdirSync4, mkdirSync as
|
|
4417
|
-
import { join as
|
|
5748
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9, readdirSync as readdirSync4, mkdirSync as mkdirSync8, copyFileSync as copyFileSync3, renameSync as renameSync5, statSync as statSync5 } from "node:fs";
|
|
5749
|
+
import { join as join16 } from "node:path";
|
|
4418
5750
|
function resolveSchemaPath(schemaName) {
|
|
4419
|
-
const globalPath =
|
|
5751
|
+
const globalPath = join16(getCleoSchemasDir(), schemaName);
|
|
4420
5752
|
if (existsSync15(globalPath)) {
|
|
4421
5753
|
return globalPath;
|
|
4422
5754
|
}
|
|
4423
5755
|
const packageRoot = getPackageRoot();
|
|
4424
|
-
const bundledPath =
|
|
5756
|
+
const bundledPath = join16(packageRoot, "schemas", schemaName);
|
|
4425
5757
|
if (existsSync15(bundledPath)) {
|
|
4426
5758
|
return bundledPath;
|
|
4427
5759
|
}
|
|
@@ -4445,7 +5777,7 @@ function getSchemaVersion2(schemaName) {
|
|
|
4445
5777
|
}
|
|
4446
5778
|
function listBundledSchemas() {
|
|
4447
5779
|
const packageRoot = getPackageRoot();
|
|
4448
|
-
const schemasDir =
|
|
5780
|
+
const schemasDir = join16(packageRoot, "schemas");
|
|
4449
5781
|
if (!existsSync15(schemasDir)) return [];
|
|
4450
5782
|
try {
|
|
4451
5783
|
return readdirSync4(schemasDir).filter((f) => f.endsWith(".schema.json"));
|
|
@@ -4469,7 +5801,7 @@ function readVersionFromPath(schemaPath) {
|
|
|
4469
5801
|
}
|
|
4470
5802
|
function ensureGlobalSchemas(_opts) {
|
|
4471
5803
|
const packageRoot = getPackageRoot();
|
|
4472
|
-
const bundledDir =
|
|
5804
|
+
const bundledDir = join16(packageRoot, "schemas");
|
|
4473
5805
|
const globalDir = getCleoSchemasDir();
|
|
4474
5806
|
const bundledFiles = listBundledSchemas();
|
|
4475
5807
|
let installed = 0;
|
|
@@ -4478,11 +5810,11 @@ function ensureGlobalSchemas(_opts) {
|
|
|
4478
5810
|
return { installed: 0, updated: 0, total: 0 };
|
|
4479
5811
|
}
|
|
4480
5812
|
if (!existsSync15(globalDir)) {
|
|
4481
|
-
|
|
5813
|
+
mkdirSync8(globalDir, { recursive: true });
|
|
4482
5814
|
}
|
|
4483
5815
|
for (const file of bundledFiles) {
|
|
4484
|
-
const source =
|
|
4485
|
-
const target =
|
|
5816
|
+
const source = join16(bundledDir, file);
|
|
5817
|
+
const target = join16(globalDir, file);
|
|
4486
5818
|
if (!existsSync15(target)) {
|
|
4487
5819
|
copyFileSync3(source, target);
|
|
4488
5820
|
installed++;
|
|
@@ -4508,15 +5840,15 @@ function checkGlobalSchemas() {
|
|
|
4508
5840
|
const stale = [];
|
|
4509
5841
|
let installedCount = 0;
|
|
4510
5842
|
const packageRoot = getPackageRoot();
|
|
4511
|
-
const bundledDir =
|
|
5843
|
+
const bundledDir = join16(packageRoot, "schemas");
|
|
4512
5844
|
for (const file of bundledFiles) {
|
|
4513
|
-
const globalPath =
|
|
5845
|
+
const globalPath = join16(globalDir, file);
|
|
4514
5846
|
if (!existsSync15(globalPath)) {
|
|
4515
5847
|
missing.push(file);
|
|
4516
5848
|
continue;
|
|
4517
5849
|
}
|
|
4518
5850
|
installedCount++;
|
|
4519
|
-
const bundledVersion = readVersionFromPath(
|
|
5851
|
+
const bundledVersion = readVersionFromPath(join16(bundledDir, file));
|
|
4520
5852
|
const globalVersion = readVersionFromPath(globalPath);
|
|
4521
5853
|
if (bundledVersion !== null && bundledVersion !== globalVersion) {
|
|
4522
5854
|
stale.push(file);
|
|
@@ -4537,14 +5869,14 @@ function checkSchemaStaleness() {
|
|
|
4537
5869
|
const current = [];
|
|
4538
5870
|
const missing = [];
|
|
4539
5871
|
const packageRoot = getPackageRoot();
|
|
4540
|
-
const bundledDir =
|
|
5872
|
+
const bundledDir = join16(packageRoot, "schemas");
|
|
4541
5873
|
for (const file of bundledFiles) {
|
|
4542
|
-
const globalPath =
|
|
5874
|
+
const globalPath = join16(globalDir, file);
|
|
4543
5875
|
if (!existsSync15(globalPath)) {
|
|
4544
5876
|
missing.push(file);
|
|
4545
5877
|
continue;
|
|
4546
5878
|
}
|
|
4547
|
-
const bundledVersion = readVersionFromPath(
|
|
5879
|
+
const bundledVersion = readVersionFromPath(join16(bundledDir, file));
|
|
4548
5880
|
const globalVersion = readVersionFromPath(globalPath);
|
|
4549
5881
|
if (bundledVersion !== null && bundledVersion !== globalVersion) {
|
|
4550
5882
|
stale.push(file);
|
|
@@ -4564,7 +5896,7 @@ function listInstalledSchemas() {
|
|
|
4564
5896
|
return [];
|
|
4565
5897
|
}
|
|
4566
5898
|
return files.map((name) => {
|
|
4567
|
-
const fullPath =
|
|
5899
|
+
const fullPath = join16(globalDir, name);
|
|
4568
5900
|
return {
|
|
4569
5901
|
name,
|
|
4570
5902
|
path: fullPath,
|
|
@@ -4573,7 +5905,7 @@ function listInstalledSchemas() {
|
|
|
4573
5905
|
});
|
|
4574
5906
|
}
|
|
4575
5907
|
async function cleanProjectSchemas(projectRoot) {
|
|
4576
|
-
const projectSchemasDir =
|
|
5908
|
+
const projectSchemasDir = join16(projectRoot, ".cleo", "schemas");
|
|
4577
5909
|
if (!existsSync15(projectSchemasDir)) {
|
|
4578
5910
|
return { cleaned: false };
|
|
4579
5911
|
}
|
|
@@ -4586,10 +5918,10 @@ async function cleanProjectSchemas(projectRoot) {
|
|
|
4586
5918
|
return { cleaned: false };
|
|
4587
5919
|
}
|
|
4588
5920
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
4589
|
-
const backupDir =
|
|
4590
|
-
const backupTarget =
|
|
5921
|
+
const backupDir = join16(projectRoot, ".cleo", "backups", "schemas");
|
|
5922
|
+
const backupTarget = join16(backupDir, `schemas-${timestamp}`);
|
|
4591
5923
|
if (!existsSync15(backupDir)) {
|
|
4592
|
-
|
|
5924
|
+
mkdirSync8(backupDir, { recursive: true });
|
|
4593
5925
|
}
|
|
4594
5926
|
renameSync5(projectSchemasDir, backupTarget);
|
|
4595
5927
|
return { cleaned: true };
|
|
@@ -4609,7 +5941,7 @@ __export(schema_integrity_exports, {
|
|
|
4609
5941
|
readSchemaVersionFromFile: () => readSchemaVersionFromFile
|
|
4610
5942
|
});
|
|
4611
5943
|
import { existsSync as existsSync16, readFileSync as readFileSync10 } from "node:fs";
|
|
4612
|
-
import { join as
|
|
5944
|
+
import { join as join17 } from "node:path";
|
|
4613
5945
|
function readSchemaVersionFromFile(schemaName) {
|
|
4614
5946
|
return getSchemaVersion2(schemaName);
|
|
4615
5947
|
}
|
|
@@ -4710,28 +6042,28 @@ var init_schema_integrity = __esm({
|
|
|
4710
6042
|
INTEGRITY_TARGETS = [
|
|
4711
6043
|
{
|
|
4712
6044
|
label: "config.json",
|
|
4713
|
-
filePath: (d) =>
|
|
6045
|
+
filePath: (d) => join17(d, "config.json"),
|
|
4714
6046
|
schemaName: "config.schema.json",
|
|
4715
6047
|
required: true,
|
|
4716
6048
|
versionKey: "schemaVersion"
|
|
4717
6049
|
},
|
|
4718
6050
|
{
|
|
4719
6051
|
label: "project-info.json",
|
|
4720
|
-
filePath: (d) =>
|
|
6052
|
+
filePath: (d) => join17(d, "project-info.json"),
|
|
4721
6053
|
schemaName: "project-info.schema.json",
|
|
4722
6054
|
required: false,
|
|
4723
6055
|
versionKey: "schemaVersion"
|
|
4724
6056
|
},
|
|
4725
6057
|
{
|
|
4726
6058
|
label: "project-context.json",
|
|
4727
|
-
filePath: (d) =>
|
|
6059
|
+
filePath: (d) => join17(d, "project-context.json"),
|
|
4728
6060
|
schemaName: "project-context.schema.json",
|
|
4729
6061
|
required: false,
|
|
4730
6062
|
versionKey: "schemaVersion"
|
|
4731
6063
|
},
|
|
4732
6064
|
{
|
|
4733
6065
|
label: ".context-state.json",
|
|
4734
|
-
filePath: (d) =>
|
|
6066
|
+
filePath: (d) => join17(d, ".context-state.json"),
|
|
4735
6067
|
schemaName: "context-state.schema.json",
|
|
4736
6068
|
required: false,
|
|
4737
6069
|
versionKey: "version"
|
|
@@ -4746,9 +6078,9 @@ __export(project_detect_exports, {
|
|
|
4746
6078
|
detectProjectType: () => detectProjectType
|
|
4747
6079
|
});
|
|
4748
6080
|
import { existsSync as existsSync17, readdirSync as readdirSync5 } from "node:fs";
|
|
4749
|
-
import { join as
|
|
6081
|
+
import { join as join18 } from "node:path";
|
|
4750
6082
|
function detectProjectType(projectDir) {
|
|
4751
|
-
const exists = (f) => existsSync17(
|
|
6083
|
+
const exists = (f) => existsSync17(join18(projectDir, f));
|
|
4752
6084
|
const info = {
|
|
4753
6085
|
type: "unknown",
|
|
4754
6086
|
testFramework: "unknown",
|
|
@@ -4837,9 +6169,9 @@ __export(scaffold_exports, {
|
|
|
4837
6169
|
});
|
|
4838
6170
|
import { mkdir as mkdir4, access, writeFile as writeFile3, readFile as readFile3 } from "node:fs/promises";
|
|
4839
6171
|
import { constants as fsConstants, existsSync as existsSync18, readFileSync as readFileSync11, statSync as statSync6 } from "node:fs";
|
|
4840
|
-
import { join as
|
|
4841
|
-
import { fileURLToPath as
|
|
4842
|
-
import { createHash as
|
|
6172
|
+
import { join as join19, resolve as resolve5, dirname as dirname7 } from "node:path";
|
|
6173
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
6174
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
4843
6175
|
import { execFile as execFile3 } from "node:child_process";
|
|
4844
6176
|
import { promisify as promisify3 } from "node:util";
|
|
4845
6177
|
async function fileExists(path) {
|
|
@@ -4860,7 +6192,7 @@ async function stripCLEOBlocks(filePath) {
|
|
|
4860
6192
|
if (stripped !== content) await writeFile3(filePath, stripped, "utf8");
|
|
4861
6193
|
}
|
|
4862
6194
|
async function removeCleoFromRootGitignore(projectRoot) {
|
|
4863
|
-
const rootGitignorePath =
|
|
6195
|
+
const rootGitignorePath = join19(projectRoot, ".gitignore");
|
|
4864
6196
|
if (!await fileExists(rootGitignorePath)) {
|
|
4865
6197
|
return { removed: false };
|
|
4866
6198
|
}
|
|
@@ -4877,16 +6209,16 @@ async function removeCleoFromRootGitignore(projectRoot) {
|
|
|
4877
6209
|
return { removed: true };
|
|
4878
6210
|
}
|
|
4879
6211
|
function generateProjectHash(projectPath) {
|
|
4880
|
-
return
|
|
6212
|
+
return createHash5("sha256").update(projectPath).digest("hex").substring(0, 12);
|
|
4881
6213
|
}
|
|
4882
6214
|
function getPackageRoot() {
|
|
4883
|
-
const thisFile =
|
|
4884
|
-
return resolve5(
|
|
6215
|
+
const thisFile = fileURLToPath3(import.meta.url);
|
|
6216
|
+
return resolve5(dirname7(thisFile), "..", "..");
|
|
4885
6217
|
}
|
|
4886
6218
|
function getGitignoreContent() {
|
|
4887
6219
|
try {
|
|
4888
6220
|
const packageRoot = getPackageRoot();
|
|
4889
|
-
const templatePath =
|
|
6221
|
+
const templatePath = join19(packageRoot, "templates", "cleo-gitignore");
|
|
4890
6222
|
if (existsSync18(templatePath)) {
|
|
4891
6223
|
return readFileSync11(templatePath, "utf-8");
|
|
4892
6224
|
}
|
|
@@ -4896,7 +6228,7 @@ function getGitignoreContent() {
|
|
|
4896
6228
|
}
|
|
4897
6229
|
function getCleoVersion() {
|
|
4898
6230
|
try {
|
|
4899
|
-
const pkgPath =
|
|
6231
|
+
const pkgPath = join19(getPackageRoot(), "package.json");
|
|
4900
6232
|
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
4901
6233
|
return pkg.version ?? "0.0.0";
|
|
4902
6234
|
} catch {
|
|
@@ -4934,7 +6266,7 @@ async function ensureCleoStructure(projectRoot) {
|
|
|
4934
6266
|
const alreadyExists = existsSync18(cleoDir);
|
|
4935
6267
|
await mkdir4(cleoDir, { recursive: true });
|
|
4936
6268
|
for (const subdir of REQUIRED_CLEO_SUBDIRS) {
|
|
4937
|
-
await mkdir4(
|
|
6269
|
+
await mkdir4(join19(cleoDir, subdir), { recursive: true });
|
|
4938
6270
|
}
|
|
4939
6271
|
return {
|
|
4940
6272
|
action: alreadyExists ? "skipped" : "created",
|
|
@@ -4944,7 +6276,7 @@ async function ensureCleoStructure(projectRoot) {
|
|
|
4944
6276
|
}
|
|
4945
6277
|
async function ensureGitignore(projectRoot) {
|
|
4946
6278
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
4947
|
-
const gitignorePath =
|
|
6279
|
+
const gitignorePath = join19(cleoDir, ".gitignore");
|
|
4948
6280
|
const templateContent = getGitignoreContent();
|
|
4949
6281
|
if (existsSync18(gitignorePath)) {
|
|
4950
6282
|
const existing = readFileSync11(gitignorePath, "utf-8");
|
|
@@ -4971,7 +6303,7 @@ async function ensureConfig(projectRoot, opts) {
|
|
|
4971
6303
|
}
|
|
4972
6304
|
async function ensureProjectInfo(projectRoot, opts) {
|
|
4973
6305
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
4974
|
-
const projectInfoPath =
|
|
6306
|
+
const projectInfoPath = join19(cleoDir, "project-info.json");
|
|
4975
6307
|
if (existsSync18(projectInfoPath) && !opts?.force) {
|
|
4976
6308
|
return { action: "skipped", path: projectInfoPath, details: "Already exists" };
|
|
4977
6309
|
}
|
|
@@ -5012,7 +6344,7 @@ async function ensureProjectInfo(projectRoot, opts) {
|
|
|
5012
6344
|
}
|
|
5013
6345
|
async function ensureProjectContext(projectRoot, opts) {
|
|
5014
6346
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
5015
|
-
const contextPath =
|
|
6347
|
+
const contextPath = join19(cleoDir, "project-context.json");
|
|
5016
6348
|
const staleDays = opts?.staleDays ?? 30;
|
|
5017
6349
|
if (existsSync18(contextPath) && !opts?.force) {
|
|
5018
6350
|
try {
|
|
@@ -5042,7 +6374,7 @@ async function ensureProjectContext(projectRoot, opts) {
|
|
|
5042
6374
|
}
|
|
5043
6375
|
async function ensureCleoGitRepo(projectRoot) {
|
|
5044
6376
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
5045
|
-
const cleoGitDir =
|
|
6377
|
+
const cleoGitDir = join19(cleoDir, ".git");
|
|
5046
6378
|
if (existsSync18(cleoGitDir)) {
|
|
5047
6379
|
return { action: "skipped", path: cleoGitDir, details: "Already initialized" };
|
|
5048
6380
|
}
|
|
@@ -5058,7 +6390,7 @@ async function ensureCleoGitRepo(projectRoot) {
|
|
|
5058
6390
|
}
|
|
5059
6391
|
async function ensureSqliteDb(projectRoot) {
|
|
5060
6392
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
5061
|
-
const dbPath =
|
|
6393
|
+
const dbPath = join19(cleoDir, "tasks.db");
|
|
5062
6394
|
if (existsSync18(dbPath)) {
|
|
5063
6395
|
return { action: "skipped", path: dbPath, details: "tasks.db already exists" };
|
|
5064
6396
|
}
|
|
@@ -5088,7 +6420,7 @@ function checkCleoStructure(projectRoot) {
|
|
|
5088
6420
|
};
|
|
5089
6421
|
}
|
|
5090
6422
|
for (const subdir of REQUIRED_CLEO_SUBDIRS) {
|
|
5091
|
-
if (!existsSync18(
|
|
6423
|
+
if (!existsSync18(join19(cleoDir, subdir))) {
|
|
5092
6424
|
missing.push(subdir);
|
|
5093
6425
|
}
|
|
5094
6426
|
}
|
|
@@ -5113,7 +6445,7 @@ function checkCleoStructure(projectRoot) {
|
|
|
5113
6445
|
}
|
|
5114
6446
|
function checkGitignore(projectRoot) {
|
|
5115
6447
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
5116
|
-
const gitignorePath =
|
|
6448
|
+
const gitignorePath = join19(cleoDir, ".gitignore");
|
|
5117
6449
|
if (!existsSync18(gitignorePath)) {
|
|
5118
6450
|
return {
|
|
5119
6451
|
id: "cleo_gitignore",
|
|
@@ -5172,7 +6504,7 @@ function checkConfig(projectRoot) {
|
|
|
5172
6504
|
}
|
|
5173
6505
|
function checkProjectInfo(projectRoot) {
|
|
5174
6506
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
5175
|
-
const infoPath =
|
|
6507
|
+
const infoPath = join19(cleoDir, "project-info.json");
|
|
5176
6508
|
if (!existsSync18(infoPath)) {
|
|
5177
6509
|
return {
|
|
5178
6510
|
id: "cleo_project_info",
|
|
@@ -5218,7 +6550,7 @@ function checkProjectInfo(projectRoot) {
|
|
|
5218
6550
|
}
|
|
5219
6551
|
function checkProjectContext(projectRoot, staleDays = 30) {
|
|
5220
6552
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
5221
|
-
const contextPath =
|
|
6553
|
+
const contextPath = join19(cleoDir, "project-context.json");
|
|
5222
6554
|
if (!existsSync18(contextPath)) {
|
|
5223
6555
|
return {
|
|
5224
6556
|
id: "cleo_project_context",
|
|
@@ -5275,7 +6607,7 @@ function checkProjectContext(projectRoot, staleDays = 30) {
|
|
|
5275
6607
|
}
|
|
5276
6608
|
function checkCleoGitRepo(projectRoot) {
|
|
5277
6609
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
5278
|
-
const cleoGitDir =
|
|
6610
|
+
const cleoGitDir = join19(cleoDir, ".git");
|
|
5279
6611
|
if (!existsSync18(cleoGitDir)) {
|
|
5280
6612
|
return {
|
|
5281
6613
|
id: "cleo_git_repo",
|
|
@@ -5297,7 +6629,7 @@ function checkCleoGitRepo(projectRoot) {
|
|
|
5297
6629
|
}
|
|
5298
6630
|
function checkSqliteDb(projectRoot) {
|
|
5299
6631
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
5300
|
-
const dbPath =
|
|
6632
|
+
const dbPath = join19(cleoDir, "tasks.db");
|
|
5301
6633
|
if (!existsSync18(dbPath)) {
|
|
5302
6634
|
return {
|
|
5303
6635
|
id: "sqlite_db",
|
|
@@ -5390,11 +6722,11 @@ backups/
|
|
|
5390
6722
|
// src/core/validation/doctor/checks.ts
|
|
5391
6723
|
import { existsSync as existsSync19, readFileSync as readFileSync12, accessSync, constants, statSync as statSync7 } from "node:fs";
|
|
5392
6724
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
5393
|
-
import { join as
|
|
6725
|
+
import { join as join20 } from "node:path";
|
|
5394
6726
|
import { homedir as homedir2 } from "node:os";
|
|
5395
6727
|
function checkCleoGitignore(projectRoot) {
|
|
5396
6728
|
const root = projectRoot ?? process.cwd();
|
|
5397
|
-
const gitignorePath =
|
|
6729
|
+
const gitignorePath = join20(root, ".cleo", ".gitignore");
|
|
5398
6730
|
if (!existsSync19(gitignorePath)) {
|
|
5399
6731
|
return {
|
|
5400
6732
|
id: "cleo_gitignore",
|
|
@@ -5424,8 +6756,8 @@ function checkCleoGitignore(projectRoot) {
|
|
|
5424
6756
|
} catch {
|
|
5425
6757
|
try {
|
|
5426
6758
|
const templatePaths = [
|
|
5427
|
-
|
|
5428
|
-
|
|
6759
|
+
join20(root, "templates", "cleo-gitignore"),
|
|
6760
|
+
join20(homedir2(), ".cleo", "templates", "cleo-gitignore")
|
|
5429
6761
|
];
|
|
5430
6762
|
for (const tp of templatePaths) {
|
|
5431
6763
|
if (existsSync19(tp)) {
|
|
@@ -5466,7 +6798,7 @@ function detectStorageEngine(_projectRoot) {
|
|
|
5466
6798
|
}
|
|
5467
6799
|
function checkVitalFilesTracked(projectRoot) {
|
|
5468
6800
|
const root = projectRoot ?? process.cwd();
|
|
5469
|
-
const gitDir =
|
|
6801
|
+
const gitDir = join20(root, ".git");
|
|
5470
6802
|
if (!existsSync19(gitDir)) {
|
|
5471
6803
|
return {
|
|
5472
6804
|
id: "vital_files_tracked",
|
|
@@ -5481,7 +6813,7 @@ function checkVitalFilesTracked(projectRoot) {
|
|
|
5481
6813
|
const vitalFiles = CORE_PROTECTED_FILES.map((f) => `.cleo/${f}`);
|
|
5482
6814
|
const untracked = [];
|
|
5483
6815
|
for (const file of vitalFiles) {
|
|
5484
|
-
const fullPath =
|
|
6816
|
+
const fullPath = join20(root, file);
|
|
5485
6817
|
if (!existsSync19(fullPath)) continue;
|
|
5486
6818
|
try {
|
|
5487
6819
|
execFileSync2("git", ["ls-files", "--error-unmatch", file], {
|
|
@@ -5513,7 +6845,7 @@ function checkVitalFilesTracked(projectRoot) {
|
|
|
5513
6845
|
}
|
|
5514
6846
|
function checkCoreFilesNotIgnored(projectRoot) {
|
|
5515
6847
|
const root = projectRoot ?? process.cwd();
|
|
5516
|
-
const gitDir =
|
|
6848
|
+
const gitDir = join20(root, ".git");
|
|
5517
6849
|
if (!existsSync19(gitDir)) {
|
|
5518
6850
|
return {
|
|
5519
6851
|
id: "core_files_not_ignored",
|
|
@@ -5527,7 +6859,7 @@ function checkCoreFilesNotIgnored(projectRoot) {
|
|
|
5527
6859
|
const ignoredFiles = [];
|
|
5528
6860
|
for (const file of CORE_PROTECTED_FILES) {
|
|
5529
6861
|
const relPath = `.cleo/${file}`;
|
|
5530
|
-
const fullPath =
|
|
6862
|
+
const fullPath = join20(root, relPath);
|
|
5531
6863
|
if (!existsSync19(fullPath)) continue;
|
|
5532
6864
|
try {
|
|
5533
6865
|
execFileSync2("git", ["check-ignore", "-q", relPath], {
|
|
@@ -5559,7 +6891,7 @@ function checkCoreFilesNotIgnored(projectRoot) {
|
|
|
5559
6891
|
}
|
|
5560
6892
|
function checkLegacyAgentOutputs(projectRoot) {
|
|
5561
6893
|
const root = projectRoot ?? process.cwd();
|
|
5562
|
-
const cleoDir =
|
|
6894
|
+
const cleoDir = join20(root, ".cleo");
|
|
5563
6895
|
const detection = detectLegacyAgentOutputs(root, cleoDir);
|
|
5564
6896
|
if (detection.hasLegacy) {
|
|
5565
6897
|
return {
|
|
@@ -5632,10 +6964,10 @@ __export(hooks_exports, {
|
|
|
5632
6964
|
});
|
|
5633
6965
|
import { chmod, mkdir as mkdir5, copyFile as copyFile2, readFile as readFile4 } from "node:fs/promises";
|
|
5634
6966
|
import { existsSync as existsSync20 } from "node:fs";
|
|
5635
|
-
import { join as
|
|
6967
|
+
import { join as join21 } from "node:path";
|
|
5636
6968
|
async function ensureGitHooks(projectRoot, opts) {
|
|
5637
|
-
const gitDir =
|
|
5638
|
-
const gitHooksDir =
|
|
6969
|
+
const gitDir = join21(projectRoot, ".git");
|
|
6970
|
+
const gitHooksDir = join21(gitDir, "hooks");
|
|
5639
6971
|
if (!existsSync20(gitDir)) {
|
|
5640
6972
|
return {
|
|
5641
6973
|
action: "skipped",
|
|
@@ -5644,7 +6976,7 @@ async function ensureGitHooks(projectRoot, opts) {
|
|
|
5644
6976
|
};
|
|
5645
6977
|
}
|
|
5646
6978
|
const packageRoot = getPackageRoot();
|
|
5647
|
-
const sourceDir =
|
|
6979
|
+
const sourceDir = join21(packageRoot, "templates", "git-hooks");
|
|
5648
6980
|
if (!existsSync20(sourceDir)) {
|
|
5649
6981
|
return {
|
|
5650
6982
|
action: "skipped",
|
|
@@ -5657,8 +6989,8 @@ async function ensureGitHooks(projectRoot, opts) {
|
|
|
5657
6989
|
let installedCount = 0;
|
|
5658
6990
|
const errors = [];
|
|
5659
6991
|
for (const hook of MANAGED_HOOKS) {
|
|
5660
|
-
const sourcePath =
|
|
5661
|
-
const destPath =
|
|
6992
|
+
const sourcePath = join21(sourceDir, hook);
|
|
6993
|
+
const destPath = join21(gitHooksDir, hook);
|
|
5662
6994
|
if (!existsSync20(sourcePath)) {
|
|
5663
6995
|
continue;
|
|
5664
6996
|
}
|
|
@@ -5694,13 +7026,13 @@ async function ensureGitHooks(projectRoot, opts) {
|
|
|
5694
7026
|
};
|
|
5695
7027
|
}
|
|
5696
7028
|
async function checkGitHooks(projectRoot) {
|
|
5697
|
-
const gitHooksDir =
|
|
7029
|
+
const gitHooksDir = join21(projectRoot, ".git", "hooks");
|
|
5698
7030
|
const packageRoot = getPackageRoot();
|
|
5699
|
-
const sourceDir =
|
|
7031
|
+
const sourceDir = join21(packageRoot, "templates", "git-hooks");
|
|
5700
7032
|
const results = [];
|
|
5701
7033
|
for (const hook of MANAGED_HOOKS) {
|
|
5702
|
-
const sourcePath =
|
|
5703
|
-
const installedPath =
|
|
7034
|
+
const sourcePath = join21(sourceDir, hook);
|
|
7035
|
+
const installedPath = join21(gitHooksDir, hook);
|
|
5704
7036
|
const result = {
|
|
5705
7037
|
hook,
|
|
5706
7038
|
installed: false,
|
|
@@ -5748,18 +7080,18 @@ __export(injection_exports, {
|
|
|
5748
7080
|
});
|
|
5749
7081
|
import { mkdir as mkdir6, writeFile as writeFile4, rm } from "node:fs/promises";
|
|
5750
7082
|
import { existsSync as existsSync21, readFileSync as readFileSync13 } from "node:fs";
|
|
5751
|
-
import { join as
|
|
7083
|
+
import { join as join22, basename as basename3 } from "node:path";
|
|
5752
7084
|
import { homedir as homedir3 } from "node:os";
|
|
5753
7085
|
function getInjectionTemplateContent() {
|
|
5754
7086
|
const packageRoot = getPackageRoot();
|
|
5755
|
-
const packageTemplatePath =
|
|
7087
|
+
const packageTemplatePath = join22(packageRoot, "templates", "CLEO-INJECTION.md");
|
|
5756
7088
|
if (existsSync21(packageTemplatePath)) {
|
|
5757
7089
|
return readFileSync13(packageTemplatePath, "utf-8");
|
|
5758
7090
|
}
|
|
5759
7091
|
return null;
|
|
5760
7092
|
}
|
|
5761
7093
|
async function removeStaleAgentInjection(projectRoot) {
|
|
5762
|
-
const stalePath =
|
|
7094
|
+
const stalePath = join22(projectRoot, ".cleo", "templates", "AGENT-INJECTION.md");
|
|
5763
7095
|
if (!existsSync21(stalePath)) return false;
|
|
5764
7096
|
await rm(stalePath, { force: true });
|
|
5765
7097
|
return true;
|
|
@@ -5771,7 +7103,7 @@ async function ensureInjection(projectRoot) {
|
|
|
5771
7103
|
} catch {
|
|
5772
7104
|
return {
|
|
5773
7105
|
action: "skipped",
|
|
5774
|
-
path:
|
|
7106
|
+
path: join22(projectRoot, "AGENTS.md"),
|
|
5775
7107
|
details: "@cleocode/caamp not installed, skipping injection"
|
|
5776
7108
|
};
|
|
5777
7109
|
}
|
|
@@ -5780,16 +7112,16 @@ async function ensureInjection(projectRoot) {
|
|
|
5780
7112
|
if (providers.length === 0) {
|
|
5781
7113
|
return {
|
|
5782
7114
|
action: "skipped",
|
|
5783
|
-
path:
|
|
7115
|
+
path: join22(projectRoot, "AGENTS.md"),
|
|
5784
7116
|
details: "No AI agent providers detected, skipping injection"
|
|
5785
7117
|
};
|
|
5786
7118
|
}
|
|
5787
7119
|
const actions = [];
|
|
5788
7120
|
for (const provider of providers) {
|
|
5789
|
-
const instructFile =
|
|
7121
|
+
const instructFile = join22(projectRoot, provider.pathProject, provider.instructFile);
|
|
5790
7122
|
await stripCLEOBlocks(instructFile);
|
|
5791
7123
|
}
|
|
5792
|
-
await stripCLEOBlocks(
|
|
7124
|
+
await stripCLEOBlocks(join22(projectRoot, "AGENTS.md"));
|
|
5793
7125
|
const removedStale = await removeStaleAgentInjection(projectRoot);
|
|
5794
7126
|
if (removedStale) {
|
|
5795
7127
|
actions.push("removed deprecated AGENT-INJECTION.md");
|
|
@@ -5800,9 +7132,9 @@ async function ensureInjection(projectRoot) {
|
|
|
5800
7132
|
const fileName = basename3(filePath);
|
|
5801
7133
|
actions.push(`${fileName} (${action})`);
|
|
5802
7134
|
}
|
|
5803
|
-
const agentsMdPath =
|
|
7135
|
+
const agentsMdPath = join22(projectRoot, "AGENTS.md");
|
|
5804
7136
|
const agentsMdLines = ["@~/.cleo/templates/CLEO-INJECTION.md"];
|
|
5805
|
-
const projectContextPath =
|
|
7137
|
+
const projectContextPath = join22(projectRoot, ".cleo", "project-context.json");
|
|
5806
7138
|
if (existsSync21(projectContextPath)) {
|
|
5807
7139
|
agentsMdLines.push("@.cleo/project-context.json");
|
|
5808
7140
|
}
|
|
@@ -5810,17 +7142,17 @@ async function ensureInjection(projectRoot) {
|
|
|
5810
7142
|
actions.push(`AGENTS.md CLEO content (${agentsAction})`);
|
|
5811
7143
|
const content = getInjectionTemplateContent();
|
|
5812
7144
|
if (content) {
|
|
5813
|
-
const globalTemplatesDir =
|
|
7145
|
+
const globalTemplatesDir = join22(getCleoHome(), "templates");
|
|
5814
7146
|
await mkdir6(globalTemplatesDir, { recursive: true });
|
|
5815
|
-
const globalPath =
|
|
7147
|
+
const globalPath = join22(globalTemplatesDir, "CLEO-INJECTION.md");
|
|
5816
7148
|
if (!existsSync21(globalPath)) {
|
|
5817
7149
|
await writeFile4(globalPath, content);
|
|
5818
7150
|
actions.push("installed global CLEO-INJECTION.md");
|
|
5819
7151
|
}
|
|
5820
7152
|
}
|
|
5821
7153
|
try {
|
|
5822
|
-
const globalAgentsDir =
|
|
5823
|
-
const globalAgentsMd =
|
|
7154
|
+
const globalAgentsDir = join22(homedir3(), ".agents");
|
|
7155
|
+
const globalAgentsMd = join22(globalAgentsDir, "AGENTS.md");
|
|
5824
7156
|
await mkdir6(globalAgentsDir, { recursive: true });
|
|
5825
7157
|
await inject(globalAgentsMd, "@~/.cleo/templates/CLEO-INJECTION.md");
|
|
5826
7158
|
} catch {
|
|
@@ -5832,7 +7164,7 @@ async function ensureInjection(projectRoot) {
|
|
|
5832
7164
|
};
|
|
5833
7165
|
}
|
|
5834
7166
|
function checkInjection(projectRoot) {
|
|
5835
|
-
const agentsMdPath =
|
|
7167
|
+
const agentsMdPath = join22(projectRoot, "AGENTS.md");
|
|
5836
7168
|
if (!existsSync21(agentsMdPath)) {
|
|
5837
7169
|
return {
|
|
5838
7170
|
id: "injection_health",
|
|
@@ -5885,7 +7217,7 @@ function checkInjection(projectRoot) {
|
|
|
5885
7217
|
const missing = [];
|
|
5886
7218
|
for (const ref of refs) {
|
|
5887
7219
|
const rawPath = ref.slice(1).trim();
|
|
5888
|
-
const resolvedPath = rawPath.startsWith("~/") ?
|
|
7220
|
+
const resolvedPath = rawPath.startsWith("~/") ? join22(homedir3(), rawPath.slice(2)) : join22(projectRoot, rawPath);
|
|
5889
7221
|
if (!existsSync21(resolvedPath)) {
|
|
5890
7222
|
missing.push(rawPath);
|
|
5891
7223
|
}
|
|
@@ -5901,7 +7233,7 @@ function checkInjection(projectRoot) {
|
|
|
5901
7233
|
};
|
|
5902
7234
|
}
|
|
5903
7235
|
}
|
|
5904
|
-
const claudeMdPath =
|
|
7236
|
+
const claudeMdPath = join22(projectRoot, "CLAUDE.md");
|
|
5905
7237
|
if (existsSync21(claudeMdPath)) {
|
|
5906
7238
|
try {
|
|
5907
7239
|
const claudeContent = readFileSync13(claudeMdPath, "utf-8");
|
|
@@ -5956,19 +7288,19 @@ __export(health_exports, {
|
|
|
5956
7288
|
runDoctorFixes: () => runDoctorFixes
|
|
5957
7289
|
});
|
|
5958
7290
|
import { existsSync as existsSync22, readFileSync as readFileSync14, statSync as statSync8 } from "node:fs";
|
|
5959
|
-
import { join as
|
|
7291
|
+
import { join as join23 } from "node:path";
|
|
5960
7292
|
import { execFile as execFile4 } from "node:child_process";
|
|
5961
7293
|
import { promisify as promisify4 } from "node:util";
|
|
5962
7294
|
import { homedir as homedir4 } from "node:os";
|
|
5963
7295
|
function getSystemHealth(projectRoot, opts) {
|
|
5964
|
-
const cleoDir =
|
|
7296
|
+
const cleoDir = join23(projectRoot, ".cleo");
|
|
5965
7297
|
const checks = [];
|
|
5966
7298
|
if (existsSync22(cleoDir)) {
|
|
5967
7299
|
checks.push({ name: "cleo_dir", status: "pass", message: ".cleo directory exists" });
|
|
5968
7300
|
} else {
|
|
5969
7301
|
checks.push({ name: "cleo_dir", status: "fail", message: ".cleo directory not found" });
|
|
5970
7302
|
}
|
|
5971
|
-
const dbPath =
|
|
7303
|
+
const dbPath = join23(cleoDir, "tasks.db");
|
|
5972
7304
|
if (existsSync22(dbPath)) {
|
|
5973
7305
|
try {
|
|
5974
7306
|
const dbSize = statSync8(dbPath).size;
|
|
@@ -5983,7 +7315,7 @@ function getSystemHealth(projectRoot, opts) {
|
|
|
5983
7315
|
} else {
|
|
5984
7316
|
checks.push({ name: "tasks_db", status: "fail", message: "tasks.db not found" });
|
|
5985
7317
|
}
|
|
5986
|
-
const configPath =
|
|
7318
|
+
const configPath = join23(cleoDir, "config.json");
|
|
5987
7319
|
if (existsSync22(configPath)) {
|
|
5988
7320
|
try {
|
|
5989
7321
|
JSON.parse(readFileSync14(configPath, "utf-8"));
|
|
@@ -5995,7 +7327,7 @@ function getSystemHealth(projectRoot, opts) {
|
|
|
5995
7327
|
checks.push({ name: "config_json", status: "warn", message: "config.json not found" });
|
|
5996
7328
|
}
|
|
5997
7329
|
if (existsSync22(dbPath)) {
|
|
5998
|
-
const staleFiles = STALE_JSON_FILES.filter((f) => existsSync22(
|
|
7330
|
+
const staleFiles = STALE_JSON_FILES.filter((f) => existsSync22(join23(cleoDir, f)));
|
|
5999
7331
|
if (staleFiles.length > 0) {
|
|
6000
7332
|
checks.push({
|
|
6001
7333
|
name: "stale_json",
|
|
@@ -6005,13 +7337,13 @@ function getSystemHealth(projectRoot, opts) {
|
|
|
6005
7337
|
}
|
|
6006
7338
|
}
|
|
6007
7339
|
if (opts?.detailed) {
|
|
6008
|
-
const logPath =
|
|
7340
|
+
const logPath = join23(cleoDir, "todo-log.jsonl");
|
|
6009
7341
|
if (existsSync22(logPath)) {
|
|
6010
7342
|
checks.push({ name: "log_file", status: "pass", message: "todo-log.jsonl exists" });
|
|
6011
7343
|
} else {
|
|
6012
7344
|
checks.push({ name: "log_file", status: "warn", message: "todo-log.jsonl not found" });
|
|
6013
7345
|
}
|
|
6014
|
-
const backupDir =
|
|
7346
|
+
const backupDir = join23(cleoDir, ".backups");
|
|
6015
7347
|
if (existsSync22(backupDir)) {
|
|
6016
7348
|
checks.push({ name: "backups_dir", status: "pass", message: ".backups directory exists" });
|
|
6017
7349
|
} else {
|
|
@@ -6020,7 +7352,7 @@ function getSystemHealth(projectRoot, opts) {
|
|
|
6020
7352
|
}
|
|
6021
7353
|
let version = "unknown";
|
|
6022
7354
|
try {
|
|
6023
|
-
const pkgPath =
|
|
7355
|
+
const pkgPath = join23(projectRoot, "package.json");
|
|
6024
7356
|
if (existsSync22(pkgPath)) {
|
|
6025
7357
|
const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
6026
7358
|
version = pkg.version || "unknown";
|
|
@@ -6056,8 +7388,8 @@ async function getSystemDiagnostics(projectRoot, opts) {
|
|
|
6056
7388
|
details: preflight.summary
|
|
6057
7389
|
});
|
|
6058
7390
|
}
|
|
6059
|
-
const cleoDir =
|
|
6060
|
-
const dbPath =
|
|
7391
|
+
const cleoDir = join23(projectRoot, ".cleo");
|
|
7392
|
+
const dbPath = join23(cleoDir, "tasks.db");
|
|
6061
7393
|
if (existsSync22(dbPath)) {
|
|
6062
7394
|
try {
|
|
6063
7395
|
const accessor = await getAccessor(projectRoot);
|
|
@@ -6181,14 +7513,14 @@ async function coreDoctorReport(projectRoot) {
|
|
|
6181
7513
|
status: gitPath ? "ok" : "warning",
|
|
6182
7514
|
message: gitPath ? `git found: ${gitPath}` : "git not found (optional, needed for version control features)"
|
|
6183
7515
|
});
|
|
6184
|
-
const cleoDir =
|
|
7516
|
+
const cleoDir = join23(projectRoot, ".cleo");
|
|
6185
7517
|
const dirExists = existsSync22(cleoDir);
|
|
6186
7518
|
checks.push({
|
|
6187
7519
|
check: "project_dir",
|
|
6188
7520
|
status: dirExists ? "ok" : "error",
|
|
6189
7521
|
message: dirExists ? `Project dir: ${cleoDir}` : `Project dir not found: ${cleoDir}. Run: cleo init`
|
|
6190
7522
|
});
|
|
6191
|
-
const dbPath =
|
|
7523
|
+
const dbPath = join23(cleoDir, "tasks.db");
|
|
6192
7524
|
const dbExists2 = existsSync22(dbPath);
|
|
6193
7525
|
const dbSize = await fileSize(dbPath);
|
|
6194
7526
|
checks.push({
|
|
@@ -6232,14 +7564,14 @@ async function coreDoctorReport(projectRoot) {
|
|
|
6232
7564
|
} catch {
|
|
6233
7565
|
}
|
|
6234
7566
|
}
|
|
6235
|
-
const configPath =
|
|
7567
|
+
const configPath = join23(cleoDir, "config.json");
|
|
6236
7568
|
const configExists = existsSync22(configPath);
|
|
6237
7569
|
checks.push({
|
|
6238
7570
|
check: "config_file",
|
|
6239
7571
|
status: configExists ? "ok" : "warning",
|
|
6240
7572
|
message: configExists ? "config.json present" : "config.json not found (using defaults)"
|
|
6241
7573
|
});
|
|
6242
|
-
const staleJsonFiles = STALE_JSON_FILES.filter((f) => existsSync22(
|
|
7574
|
+
const staleJsonFiles = STALE_JSON_FILES.filter((f) => existsSync22(join23(cleoDir, f)));
|
|
6243
7575
|
if (dbExists2 && staleJsonFiles.length > 0) {
|
|
6244
7576
|
checks.push({
|
|
6245
7577
|
check: "stale_json",
|
|
@@ -6248,14 +7580,14 @@ async function coreDoctorReport(projectRoot) {
|
|
|
6248
7580
|
details: { files: staleJsonFiles }
|
|
6249
7581
|
});
|
|
6250
7582
|
}
|
|
6251
|
-
const logPath =
|
|
7583
|
+
const logPath = join23(cleoDir, "todo-log.jsonl");
|
|
6252
7584
|
const logExists = existsSync22(logPath);
|
|
6253
7585
|
checks.push({
|
|
6254
7586
|
check: "log_file",
|
|
6255
7587
|
status: logExists ? "ok" : "warning",
|
|
6256
7588
|
message: logExists ? "log file present" : "log file not found"
|
|
6257
7589
|
});
|
|
6258
|
-
const rootGitignorePath =
|
|
7590
|
+
const rootGitignorePath = join23(projectRoot, ".gitignore");
|
|
6259
7591
|
if (existsSync22(rootGitignorePath)) {
|
|
6260
7592
|
try {
|
|
6261
7593
|
const gitignoreContent = readFileSync14(rootGitignorePath, "utf-8");
|
|
@@ -6277,7 +7609,7 @@ async function coreDoctorReport(projectRoot) {
|
|
|
6277
7609
|
checks.push(mapCheckResult(checkVitalFilesTracked(projectRoot)));
|
|
6278
7610
|
checks.push(mapCheckResult(checkCoreFilesNotIgnored(projectRoot)));
|
|
6279
7611
|
checks.push(mapCheckResult(checkLegacyAgentOutputs(projectRoot)));
|
|
6280
|
-
const cleoGitHeadExists = existsSync22(
|
|
7612
|
+
const cleoGitHeadExists = existsSync22(join23(cleoDir, ".git", "HEAD"));
|
|
6281
7613
|
checks.push({
|
|
6282
7614
|
check: "cleo_git_repo",
|
|
6283
7615
|
status: cleoGitHeadExists ? "ok" : "warning",
|
|
@@ -6289,7 +7621,7 @@ async function coreDoctorReport(projectRoot) {
|
|
|
6289
7621
|
checks.push(mapCheckResult(checkProjectInfo(projectRoot)));
|
|
6290
7622
|
checks.push(mapCheckResult(checkProjectContext(projectRoot)));
|
|
6291
7623
|
checks.push(mapCheckResult(checkInjection(projectRoot)));
|
|
6292
|
-
const agentDefPath =
|
|
7624
|
+
const agentDefPath = join23(homedir4(), ".agents", "agents", "cleo-subagent");
|
|
6293
7625
|
checks.push({
|
|
6294
7626
|
check: "agent_definition",
|
|
6295
7627
|
status: existsSync22(agentDefPath) ? "ok" : "warning",
|
|
@@ -6397,11 +7729,11 @@ __export(mcp_exports, {
|
|
|
6397
7729
|
generateMcpServerEntry: () => generateMcpServerEntry
|
|
6398
7730
|
});
|
|
6399
7731
|
import { readFileSync as readFileSync20 } from "node:fs";
|
|
6400
|
-
import { join as
|
|
7732
|
+
import { join as join30 } from "node:path";
|
|
6401
7733
|
import { homedir as homedir6 } from "node:os";
|
|
6402
7734
|
function detectEnvMode() {
|
|
6403
|
-
const versionPath =
|
|
6404
|
-
process.env["CLEO_HOME"] ??
|
|
7735
|
+
const versionPath = join30(
|
|
7736
|
+
process.env["CLEO_HOME"] ?? join30(homedir6(), ".cleo"),
|
|
6405
7737
|
"VERSION"
|
|
6406
7738
|
);
|
|
6407
7739
|
let content;
|
|
@@ -6429,7 +7761,7 @@ function generateMcpServerEntry(env) {
|
|
|
6429
7761
|
if (env.mode === "dev-ts" && env.source) {
|
|
6430
7762
|
return {
|
|
6431
7763
|
command: "node",
|
|
6432
|
-
args: [
|
|
7764
|
+
args: [join30(env.source, "dist", "mcp", "index.js")],
|
|
6433
7765
|
env: {}
|
|
6434
7766
|
};
|
|
6435
7767
|
}
|
|
@@ -6467,21 +7799,21 @@ __export(registry_exports, {
|
|
|
6467
7799
|
readRegistry: () => readRegistry,
|
|
6468
7800
|
readRegistryRequired: () => readRegistryRequired
|
|
6469
7801
|
});
|
|
6470
|
-
import { createHash as
|
|
6471
|
-
import { join as
|
|
7802
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
7803
|
+
import { join as join31 } from "node:path";
|
|
6472
7804
|
import { mkdir as mkdir7, access as access2, readFile as readFile6 } from "node:fs/promises";
|
|
6473
7805
|
import { z } from "zod";
|
|
6474
7806
|
function getNexusHome() {
|
|
6475
|
-
return process.env["NEXUS_HOME"] ??
|
|
7807
|
+
return process.env["NEXUS_HOME"] ?? join31(getCleoHome(), "nexus");
|
|
6476
7808
|
}
|
|
6477
7809
|
function getNexusCacheDir() {
|
|
6478
|
-
return process.env["NEXUS_CACHE_DIR"] ??
|
|
7810
|
+
return process.env["NEXUS_CACHE_DIR"] ?? join31(getNexusHome(), "cache");
|
|
6479
7811
|
}
|
|
6480
7812
|
function getRegistryPath() {
|
|
6481
|
-
return process.env["NEXUS_REGISTRY_FILE"] ??
|
|
7813
|
+
return process.env["NEXUS_REGISTRY_FILE"] ?? join31(getCleoHome(), "projects-registry.json");
|
|
6482
7814
|
}
|
|
6483
7815
|
function generateProjectHash2(projectPath) {
|
|
6484
|
-
const hash =
|
|
7816
|
+
const hash = createHash6("sha256").update(projectPath).digest("hex");
|
|
6485
7817
|
return hash.substring(0, 12);
|
|
6486
7818
|
}
|
|
6487
7819
|
async function readRegistry() {
|
|
@@ -6520,7 +7852,7 @@ async function nexusInit() {
|
|
|
6520
7852
|
}
|
|
6521
7853
|
async function isCleoProject(projectPath) {
|
|
6522
7854
|
try {
|
|
6523
|
-
await access2(
|
|
7855
|
+
await access2(join31(projectPath, ".cleo", "todo.json"));
|
|
6524
7856
|
return true;
|
|
6525
7857
|
} catch {
|
|
6526
7858
|
return false;
|
|
@@ -6530,9 +7862,9 @@ async function readProjectMeta(projectPath) {
|
|
|
6530
7862
|
try {
|
|
6531
7863
|
let raw;
|
|
6532
7864
|
try {
|
|
6533
|
-
raw = await readFile6(
|
|
7865
|
+
raw = await readFile6(join31(projectPath, ".cleo", "tasks.json"), "utf-8");
|
|
6534
7866
|
} catch {
|
|
6535
|
-
raw = await readFile6(
|
|
7867
|
+
raw = await readFile6(join31(projectPath, ".cleo", "todo.json"), "utf-8");
|
|
6536
7868
|
}
|
|
6537
7869
|
const data = JSON.parse(raw);
|
|
6538
7870
|
const tasks2 = data.tasks ?? [];
|
|
@@ -7025,7 +8357,7 @@ __export(session_grade_exports, {
|
|
|
7025
8357
|
gradeSession: () => gradeSession,
|
|
7026
8358
|
readGrades: () => readGrades
|
|
7027
8359
|
});
|
|
7028
|
-
import { join as
|
|
8360
|
+
import { join as join49 } from "node:path";
|
|
7029
8361
|
import { existsSync as existsSync47 } from "node:fs";
|
|
7030
8362
|
import { readFile as readFile9, appendFile, mkdir as mkdir9 } from "node:fs/promises";
|
|
7031
8363
|
async function gradeSession(sessionId, cwd) {
|
|
@@ -7206,9 +8538,9 @@ function detectDuplicateCreates(entries) {
|
|
|
7206
8538
|
async function appendGradeResult(result, cwd) {
|
|
7207
8539
|
try {
|
|
7208
8540
|
const cleoDir = getCleoDirAbsolute(cwd);
|
|
7209
|
-
const metricsDir =
|
|
8541
|
+
const metricsDir = join49(cleoDir, "metrics");
|
|
7210
8542
|
await mkdir9(metricsDir, { recursive: true });
|
|
7211
|
-
const gradesPath =
|
|
8543
|
+
const gradesPath = join49(metricsDir, "GRADES.jsonl");
|
|
7212
8544
|
const line = JSON.stringify({ ...result, evaluator: "auto" }) + "\n";
|
|
7213
8545
|
await appendFile(gradesPath, line, "utf8");
|
|
7214
8546
|
} catch {
|
|
@@ -7217,7 +8549,7 @@ async function appendGradeResult(result, cwd) {
|
|
|
7217
8549
|
async function readGrades(sessionId, cwd) {
|
|
7218
8550
|
try {
|
|
7219
8551
|
const cleoDir = getCleoDirAbsolute(cwd);
|
|
7220
|
-
const gradesPath =
|
|
8552
|
+
const gradesPath = join49(cleoDir, "metrics", "GRADES.jsonl");
|
|
7221
8553
|
if (!existsSync47(gradesPath)) return [];
|
|
7222
8554
|
const content = await readFile9(gradesPath, "utf8");
|
|
7223
8555
|
const results = content.split("\n").filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
@@ -7341,8 +8673,14 @@ var QUERY_OPERATIONS = {
|
|
|
7341
8673
|
// Pattern memory statistics
|
|
7342
8674
|
"learning.search",
|
|
7343
8675
|
// Search BRAIN learning memory
|
|
7344
|
-
"learning.stats"
|
|
8676
|
+
"learning.stats",
|
|
7345
8677
|
// Learning memory statistics
|
|
8678
|
+
"brain.search",
|
|
8679
|
+
// 3-layer retrieval step 1: search index
|
|
8680
|
+
"brain.timeline",
|
|
8681
|
+
// 3-layer retrieval step 2: context around anchor
|
|
8682
|
+
"brain.fetch"
|
|
8683
|
+
// 3-layer retrieval step 3: full details for filtered IDs
|
|
7346
8684
|
],
|
|
7347
8685
|
// ── Canonical: check (validate alias) ──────────────────────────────
|
|
7348
8686
|
check: [
|
|
@@ -7681,8 +9019,10 @@ var MUTATE_OPERATIONS = {
|
|
|
7681
9019
|
// Archive old entries
|
|
7682
9020
|
"pattern.store",
|
|
7683
9021
|
// Store BRAIN pattern memory
|
|
7684
|
-
"learning.store"
|
|
9022
|
+
"learning.store",
|
|
7685
9023
|
// Store BRAIN learning memory
|
|
9024
|
+
"brain.observe"
|
|
9025
|
+
// Save observation to brain.db
|
|
7686
9026
|
],
|
|
7687
9027
|
// ── Canonical: check (validate alias) ──────────────────────────────
|
|
7688
9028
|
check: [
|
|
@@ -13798,6 +15138,12 @@ async function computeBriefing(projectRoot, options = {}) {
|
|
|
13798
15138
|
scopeTaskIds
|
|
13799
15139
|
});
|
|
13800
15140
|
const pipelineStage = computePipelineStage(current);
|
|
15141
|
+
let memoryContext;
|
|
15142
|
+
try {
|
|
15143
|
+
const { getSessionMemoryContext: getSessionMemoryContext2 } = await Promise.resolve().then(() => (init_session_memory(), session_memory_exports));
|
|
15144
|
+
memoryContext = await getSessionMemoryContext2(projectRoot, scopeFilter);
|
|
15145
|
+
} catch {
|
|
15146
|
+
}
|
|
13801
15147
|
const warnings = [];
|
|
13802
15148
|
if (currentTaskInfo?.blockedBy?.length) {
|
|
13803
15149
|
warnings.push(
|
|
@@ -13812,7 +15158,8 @@ async function computeBriefing(projectRoot, options = {}) {
|
|
|
13812
15158
|
blockedTasks,
|
|
13813
15159
|
activeEpics,
|
|
13814
15160
|
...pipelineStage && { pipelineStage },
|
|
13815
|
-
...warnings.length > 0 && { warnings }
|
|
15161
|
+
...warnings.length > 0 && { warnings },
|
|
15162
|
+
...memoryContext && { memoryContext }
|
|
13816
15163
|
};
|
|
13817
15164
|
}
|
|
13818
15165
|
function parseScope(scopeStr, current) {
|
|
@@ -14518,7 +15865,23 @@ async function sessionResume(projectRoot, sessionId) {
|
|
|
14518
15865
|
taskData.lastUpdated = now;
|
|
14519
15866
|
await accessor.saveTaskFile(taskData);
|
|
14520
15867
|
await accessor.saveSessions(sessions2);
|
|
14521
|
-
|
|
15868
|
+
let memoryContext;
|
|
15869
|
+
try {
|
|
15870
|
+
const { getSessionMemoryContext: getSessionMemoryContext2 } = await Promise.resolve().then(() => (init_session_memory(), session_memory_exports));
|
|
15871
|
+
const scopeType = session.scope?.type;
|
|
15872
|
+
const rootTaskId = session.scope?.rootTaskId;
|
|
15873
|
+
memoryContext = await getSessionMemoryContext2(projectRoot, {
|
|
15874
|
+
type: scopeType ?? "global",
|
|
15875
|
+
rootTaskId,
|
|
15876
|
+
epicId: rootTaskId
|
|
15877
|
+
});
|
|
15878
|
+
} catch {
|
|
15879
|
+
}
|
|
15880
|
+
const enrichedSession = {
|
|
15881
|
+
...session,
|
|
15882
|
+
...memoryContext && { memoryContext }
|
|
15883
|
+
};
|
|
15884
|
+
return { success: true, data: enrichedSession };
|
|
14522
15885
|
} catch {
|
|
14523
15886
|
return engineError("E_NOT_INITIALIZED", "Task database not initialized");
|
|
14524
15887
|
}
|
|
@@ -14768,7 +16131,7 @@ async function sessionChainShow(projectRoot, sessionId) {
|
|
|
14768
16131
|
init_platform();
|
|
14769
16132
|
init_data_accessor();
|
|
14770
16133
|
import { readFileSync as readFileSync19, existsSync as existsSync28, readdirSync as readdirSync7 } from "node:fs";
|
|
14771
|
-
import { join as
|
|
16134
|
+
import { join as join29, basename as basename5 } from "node:path";
|
|
14772
16135
|
|
|
14773
16136
|
// src/core/stats/index.ts
|
|
14774
16137
|
init_json();
|
|
@@ -14897,11 +16260,11 @@ init_paths();
|
|
|
14897
16260
|
init_json();
|
|
14898
16261
|
init_paths();
|
|
14899
16262
|
import { readFileSync as readFileSync6, existsSync as existsSync12 } from "node:fs";
|
|
14900
|
-
import { join as
|
|
16263
|
+
import { join as join13 } from "node:path";
|
|
14901
16264
|
async function generateInjection(projectRoot, accessor) {
|
|
14902
16265
|
let version = "unknown";
|
|
14903
16266
|
try {
|
|
14904
|
-
const pkgPath =
|
|
16267
|
+
const pkgPath = join13(projectRoot, "package.json");
|
|
14905
16268
|
if (existsSync12(pkgPath)) {
|
|
14906
16269
|
const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
|
|
14907
16270
|
version = pkg.version || "unknown";
|
|
@@ -15009,23 +16372,23 @@ init_paths();
|
|
|
15009
16372
|
// src/core/system/backup.ts
|
|
15010
16373
|
init_errors();
|
|
15011
16374
|
init_exit_codes();
|
|
15012
|
-
import { readFileSync as readFileSync15, writeFileSync as writeFileSync3, existsSync as existsSync23, mkdirSync as
|
|
15013
|
-
import { join as
|
|
16375
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync3, existsSync as existsSync23, mkdirSync as mkdirSync9 } from "node:fs";
|
|
16376
|
+
import { join as join24 } from "node:path";
|
|
15014
16377
|
function createBackup2(projectRoot, opts) {
|
|
15015
|
-
const cleoDir =
|
|
16378
|
+
const cleoDir = join24(projectRoot, ".cleo");
|
|
15016
16379
|
const btype = opts?.type || "snapshot";
|
|
15017
16380
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15018
16381
|
const backupId = `${btype}-${timestamp.replace(/[:.]/g, "-")}`;
|
|
15019
|
-
const backupDir =
|
|
16382
|
+
const backupDir = join24(cleoDir, "backups", btype);
|
|
15020
16383
|
if (!existsSync23(backupDir)) {
|
|
15021
|
-
|
|
16384
|
+
mkdirSync9(backupDir, { recursive: true });
|
|
15022
16385
|
}
|
|
15023
16386
|
const filesToBackup = ["todo.json", "todo-archive.json", "sessions.json", "config.json", "todo-log.jsonl"];
|
|
15024
16387
|
const backedUp = [];
|
|
15025
16388
|
for (const file of filesToBackup) {
|
|
15026
|
-
const src =
|
|
16389
|
+
const src = join24(cleoDir, file);
|
|
15027
16390
|
if (existsSync23(src)) {
|
|
15028
|
-
const dest =
|
|
16391
|
+
const dest = join24(backupDir, `${file}.${backupId}`);
|
|
15029
16392
|
try {
|
|
15030
16393
|
const content = readFileSync15(src, "utf-8");
|
|
15031
16394
|
writeFileSync3(dest, content, "utf-8");
|
|
@@ -15034,7 +16397,7 @@ function createBackup2(projectRoot, opts) {
|
|
|
15034
16397
|
}
|
|
15035
16398
|
}
|
|
15036
16399
|
}
|
|
15037
|
-
const metaPath =
|
|
16400
|
+
const metaPath = join24(backupDir, `${backupId}.meta.json`);
|
|
15038
16401
|
try {
|
|
15039
16402
|
writeFileSync3(metaPath, JSON.stringify({
|
|
15040
16403
|
backupId,
|
|
@@ -15051,15 +16414,15 @@ function restoreBackup(projectRoot, params) {
|
|
|
15051
16414
|
if (!params.backupId) {
|
|
15052
16415
|
throw new CleoError(2 /* INVALID_INPUT */, "backupId is required");
|
|
15053
16416
|
}
|
|
15054
|
-
const cleoDir =
|
|
16417
|
+
const cleoDir = join24(projectRoot, ".cleo");
|
|
15055
16418
|
const backupTypes = ["snapshot", "safety", "migration"];
|
|
15056
16419
|
let metaPath = null;
|
|
15057
16420
|
let backupDir = null;
|
|
15058
16421
|
for (const btype of backupTypes) {
|
|
15059
|
-
const candidateMeta =
|
|
16422
|
+
const candidateMeta = join24(cleoDir, "backups", btype, `${params.backupId}.meta.json`);
|
|
15060
16423
|
if (existsSync23(candidateMeta)) {
|
|
15061
16424
|
metaPath = candidateMeta;
|
|
15062
|
-
backupDir =
|
|
16425
|
+
backupDir = join24(cleoDir, "backups", btype);
|
|
15063
16426
|
break;
|
|
15064
16427
|
}
|
|
15065
16428
|
}
|
|
@@ -15074,11 +16437,11 @@ function restoreBackup(projectRoot, params) {
|
|
|
15074
16437
|
}
|
|
15075
16438
|
const restored = [];
|
|
15076
16439
|
for (const file of meta.files ?? []) {
|
|
15077
|
-
const backupFile =
|
|
16440
|
+
const backupFile = join24(backupDir, `${file}.${params.backupId}`);
|
|
15078
16441
|
if (existsSync23(backupFile)) {
|
|
15079
16442
|
try {
|
|
15080
16443
|
const content = readFileSync15(backupFile, "utf-8");
|
|
15081
|
-
writeFileSync3(
|
|
16444
|
+
writeFileSync3(join24(cleoDir, file), content, "utf-8");
|
|
15082
16445
|
restored.push(file);
|
|
15083
16446
|
} catch {
|
|
15084
16447
|
}
|
|
@@ -15096,9 +16459,9 @@ function restoreBackup(projectRoot, params) {
|
|
|
15096
16459
|
init_errors();
|
|
15097
16460
|
init_exit_codes();
|
|
15098
16461
|
import { readFileSync as readFileSync16, existsSync as existsSync24 } from "node:fs";
|
|
15099
|
-
import { join as
|
|
16462
|
+
import { join as join25 } from "node:path";
|
|
15100
16463
|
function getMigrationStatus(projectRoot, opts) {
|
|
15101
|
-
const taskPath =
|
|
16464
|
+
const taskPath = join25(projectRoot, ".cleo", "tasks.json");
|
|
15102
16465
|
let currentVersion = "unknown";
|
|
15103
16466
|
if (existsSync24(taskPath)) {
|
|
15104
16467
|
try {
|
|
@@ -15123,17 +16486,17 @@ function getMigrationStatus(projectRoot, opts) {
|
|
|
15123
16486
|
init_errors();
|
|
15124
16487
|
init_exit_codes();
|
|
15125
16488
|
import { readFileSync as readFileSync17, writeFileSync as writeFileSync4, existsSync as existsSync25, readdirSync as readdirSync6, unlinkSync as unlinkSync4 } from "node:fs";
|
|
15126
|
-
import { join as
|
|
16489
|
+
import { join as join26 } from "node:path";
|
|
15127
16490
|
function cleanupSystem(projectRoot, params) {
|
|
15128
16491
|
if (!params.target) {
|
|
15129
16492
|
throw new CleoError(2 /* INVALID_INPUT */, "target is required (sessions|backups|logs|archive)");
|
|
15130
16493
|
}
|
|
15131
|
-
const cleoDir =
|
|
16494
|
+
const cleoDir = join26(projectRoot, ".cleo");
|
|
15132
16495
|
const dryRun = params.dryRun ?? false;
|
|
15133
16496
|
const items = [];
|
|
15134
16497
|
switch (params.target) {
|
|
15135
16498
|
case "sessions": {
|
|
15136
|
-
const sessPath =
|
|
16499
|
+
const sessPath = join26(cleoDir, "sessions.json");
|
|
15137
16500
|
if (existsSync25(sessPath)) {
|
|
15138
16501
|
try {
|
|
15139
16502
|
const data = JSON.parse(readFileSync17(sessPath, "utf-8"));
|
|
@@ -15160,14 +16523,14 @@ function cleanupSystem(projectRoot, params) {
|
|
|
15160
16523
|
break;
|
|
15161
16524
|
}
|
|
15162
16525
|
case "backups": {
|
|
15163
|
-
const backupBaseDir =
|
|
16526
|
+
const backupBaseDir = join26(cleoDir, "backups");
|
|
15164
16527
|
if (existsSync25(backupBaseDir)) {
|
|
15165
16528
|
for (const typeDir of readdirSync6(backupBaseDir)) {
|
|
15166
|
-
const fullDir =
|
|
16529
|
+
const fullDir = join26(backupBaseDir, typeDir);
|
|
15167
16530
|
try {
|
|
15168
16531
|
for (const file of readdirSync6(fullDir)) {
|
|
15169
16532
|
if (file.endsWith(".meta.json")) {
|
|
15170
|
-
const metaFilePath =
|
|
16533
|
+
const metaFilePath = join26(fullDir, file);
|
|
15171
16534
|
try {
|
|
15172
16535
|
const meta = JSON.parse(readFileSync17(metaFilePath, "utf-8"));
|
|
15173
16536
|
if (params.olderThan && meta.timestamp < params.olderThan) {
|
|
@@ -15177,7 +16540,7 @@ function cleanupSystem(projectRoot, params) {
|
|
|
15177
16540
|
for (const bf of readdirSync6(fullDir)) {
|
|
15178
16541
|
if (bf.includes(meta.backupId)) {
|
|
15179
16542
|
try {
|
|
15180
|
-
unlinkSync4(
|
|
16543
|
+
unlinkSync4(join26(fullDir, bf));
|
|
15181
16544
|
} catch {
|
|
15182
16545
|
}
|
|
15183
16546
|
}
|
|
@@ -15202,7 +16565,7 @@ function cleanupSystem(projectRoot, params) {
|
|
|
15202
16565
|
items.push(file);
|
|
15203
16566
|
if (!dryRun) {
|
|
15204
16567
|
try {
|
|
15205
|
-
unlinkSync4(
|
|
16568
|
+
unlinkSync4(join26(cleoDir, file));
|
|
15206
16569
|
} catch {
|
|
15207
16570
|
}
|
|
15208
16571
|
}
|
|
@@ -15221,13 +16584,13 @@ function cleanupSystem(projectRoot, params) {
|
|
|
15221
16584
|
init_errors();
|
|
15222
16585
|
init_exit_codes();
|
|
15223
16586
|
import { readFileSync as readFileSync18, writeFileSync as writeFileSync5, existsSync as existsSync26 } from "node:fs";
|
|
15224
|
-
import { join as
|
|
16587
|
+
import { join as join27 } from "node:path";
|
|
15225
16588
|
function safestop(projectRoot, opts) {
|
|
15226
16589
|
const dryRun = opts?.dryRun ?? false;
|
|
15227
16590
|
const reason = opts?.reason ?? "Manual safestop";
|
|
15228
16591
|
let sessionEnded = false;
|
|
15229
16592
|
if (!dryRun && !opts?.noSessionEnd) {
|
|
15230
|
-
const sessPath =
|
|
16593
|
+
const sessPath = join27(projectRoot, ".cleo", "sessions.json");
|
|
15231
16594
|
if (existsSync26(sessPath)) {
|
|
15232
16595
|
try {
|
|
15233
16596
|
const data = JSON.parse(readFileSync18(sessPath, "utf-8"));
|
|
@@ -15258,7 +16621,7 @@ init_sequence();
|
|
|
15258
16621
|
// src/core/system/runtime.ts
|
|
15259
16622
|
import { existsSync as existsSync27 } from "node:fs";
|
|
15260
16623
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
15261
|
-
import { basename as basename4, join as
|
|
16624
|
+
import { basename as basename4, join as join28 } from "node:path";
|
|
15262
16625
|
import { homedir as homedir5 } from "node:os";
|
|
15263
16626
|
import { execFile as execFile5 } from "node:child_process";
|
|
15264
16627
|
import { promisify as promisify5 } from "node:util";
|
|
@@ -15292,7 +16655,7 @@ function getExpectedNaming(channel) {
|
|
|
15292
16655
|
}
|
|
15293
16656
|
}
|
|
15294
16657
|
async function parseVersionFile(dataRoot) {
|
|
15295
|
-
const versionPath =
|
|
16658
|
+
const versionPath = join28(dataRoot, "VERSION");
|
|
15296
16659
|
if (!existsSync27(versionPath)) return null;
|
|
15297
16660
|
let content;
|
|
15298
16661
|
try {
|
|
@@ -15322,9 +16685,9 @@ async function parseVersionFile(dataRoot) {
|
|
|
15322
16685
|
async function getPackageInfo(sourceDir) {
|
|
15323
16686
|
const candidates = [];
|
|
15324
16687
|
if (sourceDir && sourceDir !== "unknown" && sourceDir !== "npm") {
|
|
15325
|
-
candidates.push(
|
|
16688
|
+
candidates.push(join28(sourceDir, "package.json"));
|
|
15326
16689
|
}
|
|
15327
|
-
candidates.push(
|
|
16690
|
+
candidates.push(join28(process.cwd(), "package.json"));
|
|
15328
16691
|
for (const candidate of candidates) {
|
|
15329
16692
|
try {
|
|
15330
16693
|
const raw = await readFile5(candidate, "utf-8");
|
|
@@ -15350,7 +16713,7 @@ async function getRuntimeDiagnostics(options) {
|
|
|
15350
16713
|
const scriptPath = process.argv[1] ?? "";
|
|
15351
16714
|
const invocationName = basename4(scriptPath || process.argv0 || "cleo");
|
|
15352
16715
|
const envChannel = normalizeChannel(process.env["CLEO_CHANNEL"]);
|
|
15353
|
-
const dataRoot = process.env["CLEO_HOME"] ??
|
|
16716
|
+
const dataRoot = process.env["CLEO_HOME"] ?? join28(homedir5(), ".cleo");
|
|
15354
16717
|
const versionInfo = await parseVersionFile(dataRoot);
|
|
15355
16718
|
const packageInfo = await getPackageInfo(versionInfo?.source);
|
|
15356
16719
|
const channel = envChannel ?? detectFromInvocation(invocationName) ?? normalizeChannel(versionInfo?.version.includes("-beta") ? "beta" : void 0) ?? detectFromDataRoot(dataRoot) ?? normalizeChannel(versionInfo?.mode.startsWith("dev") ? "dev" : void 0) ?? "stable";
|
|
@@ -15565,9 +16928,9 @@ async function systemLog(projectRoot, filters) {
|
|
|
15565
16928
|
}
|
|
15566
16929
|
async function queryAuditLogSqlite(projectRoot, filters) {
|
|
15567
16930
|
try {
|
|
15568
|
-
const { join:
|
|
16931
|
+
const { join: join53 } = await import("node:path");
|
|
15569
16932
|
const { existsSync: existsSync51 } = await import("node:fs");
|
|
15570
|
-
const dbPath =
|
|
16933
|
+
const dbPath = join53(projectRoot, ".cleo", "tasks.db");
|
|
15571
16934
|
if (!existsSync51(dbPath)) return null;
|
|
15572
16935
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
15573
16936
|
const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
@@ -15663,32 +17026,32 @@ function queryAuditLogJsonl(projectRoot, filters) {
|
|
|
15663
17026
|
}
|
|
15664
17027
|
function systemContext(projectRoot, params) {
|
|
15665
17028
|
try {
|
|
15666
|
-
const cleoDir =
|
|
17029
|
+
const cleoDir = join29(projectRoot, ".cleo");
|
|
15667
17030
|
let stateFile;
|
|
15668
17031
|
if (params?.session) {
|
|
15669
|
-
const sessionFile =
|
|
15670
|
-
stateFile = existsSync28(sessionFile) ? sessionFile :
|
|
17032
|
+
const sessionFile = join29(cleoDir, "context-states", `context-state-${params.session}.json`);
|
|
17033
|
+
stateFile = existsSync28(sessionFile) ? sessionFile : join29(cleoDir, ".context-state.json");
|
|
15671
17034
|
} else {
|
|
15672
|
-
const currentSessionPath =
|
|
17035
|
+
const currentSessionPath = join29(cleoDir, ".current-session");
|
|
15673
17036
|
if (existsSync28(currentSessionPath)) {
|
|
15674
17037
|
const currentSession = readFileSync19(currentSessionPath, "utf-8").trim();
|
|
15675
17038
|
if (currentSession) {
|
|
15676
|
-
const sessionFile =
|
|
15677
|
-
stateFile = existsSync28(sessionFile) ? sessionFile :
|
|
17039
|
+
const sessionFile = join29(cleoDir, "context-states", `context-state-${currentSession}.json`);
|
|
17040
|
+
stateFile = existsSync28(sessionFile) ? sessionFile : join29(cleoDir, ".context-state.json");
|
|
15678
17041
|
} else {
|
|
15679
|
-
stateFile =
|
|
17042
|
+
stateFile = join29(cleoDir, ".context-state.json");
|
|
15680
17043
|
}
|
|
15681
17044
|
} else {
|
|
15682
|
-
stateFile =
|
|
17045
|
+
stateFile = join29(cleoDir, ".context-state.json");
|
|
15683
17046
|
}
|
|
15684
17047
|
}
|
|
15685
17048
|
const sessions2 = [];
|
|
15686
|
-
const statesDir =
|
|
17049
|
+
const statesDir = join29(cleoDir, "context-states");
|
|
15687
17050
|
if (existsSync28(statesDir)) {
|
|
15688
17051
|
for (const file of readdirSync7(statesDir)) {
|
|
15689
17052
|
if (file.startsWith("context-state-") && file.endsWith(".json")) {
|
|
15690
17053
|
try {
|
|
15691
|
-
const state = JSON.parse(readFileSync19(
|
|
17054
|
+
const state = JSON.parse(readFileSync19(join29(statesDir, file), "utf-8"));
|
|
15692
17055
|
sessions2.push({
|
|
15693
17056
|
file: basename5(file),
|
|
15694
17057
|
sessionId: state.sessionId ?? null,
|
|
@@ -15701,7 +17064,7 @@ function systemContext(projectRoot, params) {
|
|
|
15701
17064
|
}
|
|
15702
17065
|
}
|
|
15703
17066
|
}
|
|
15704
|
-
const singletonFile =
|
|
17067
|
+
const singletonFile = join29(cleoDir, ".context-state.json");
|
|
15705
17068
|
if (existsSync28(singletonFile)) {
|
|
15706
17069
|
try {
|
|
15707
17070
|
const state = JSON.parse(readFileSync19(singletonFile, "utf-8"));
|
|
@@ -15949,18 +17312,18 @@ init_schema_management();
|
|
|
15949
17312
|
init_injection();
|
|
15950
17313
|
import { mkdir as mkdir8, copyFile as copyFile3, symlink, lstat, unlink as unlink3 } from "node:fs/promises";
|
|
15951
17314
|
import { existsSync as existsSync29, readFileSync as readFileSync21, readdirSync as readdirSync8 } from "node:fs";
|
|
15952
|
-
import { join as
|
|
17315
|
+
import { join as join32, dirname as dirname8, basename as basename6 } from "node:path";
|
|
15953
17316
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
15954
17317
|
import { homedir as homedir7 } from "node:os";
|
|
15955
17318
|
async function initAgentDefinition(created, warnings) {
|
|
15956
17319
|
const packageRoot = getPackageRoot();
|
|
15957
|
-
const agentSourceDir =
|
|
17320
|
+
const agentSourceDir = join32(packageRoot, "agents", "cleo-subagent");
|
|
15958
17321
|
if (!existsSync29(agentSourceDir)) {
|
|
15959
17322
|
warnings.push("agents/cleo-subagent/ not found in package, skipping agent definition install");
|
|
15960
17323
|
return;
|
|
15961
17324
|
}
|
|
15962
|
-
const globalAgentsDir =
|
|
15963
|
-
await mkdir8(
|
|
17325
|
+
const globalAgentsDir = join32(homedir7(), ".agents", "agents", "cleo-subagent");
|
|
17326
|
+
await mkdir8(dirname8(globalAgentsDir), { recursive: true });
|
|
15964
17327
|
try {
|
|
15965
17328
|
try {
|
|
15966
17329
|
const stat2 = await lstat(globalAgentsDir);
|
|
@@ -15976,7 +17339,7 @@ async function initAgentDefinition(created, warnings) {
|
|
|
15976
17339
|
await mkdir8(globalAgentsDir, { recursive: true });
|
|
15977
17340
|
const files = readdirSync8(agentSourceDir);
|
|
15978
17341
|
for (const file of files) {
|
|
15979
|
-
await copyFile3(
|
|
17342
|
+
await copyFile3(join32(agentSourceDir, file), join32(globalAgentsDir, file));
|
|
15980
17343
|
}
|
|
15981
17344
|
created.push("agent: cleo-subagent (copied)");
|
|
15982
17345
|
} catch (copyErr) {
|
|
@@ -16028,12 +17391,12 @@ async function initCoreSkills(created, warnings) {
|
|
|
16028
17391
|
const packageRoot = getPackageRoot();
|
|
16029
17392
|
let ctSkillsRoot = null;
|
|
16030
17393
|
try {
|
|
16031
|
-
const bundledPath =
|
|
16032
|
-
if (existsSync29(
|
|
17394
|
+
const bundledPath = join32(packageRoot, "packages", "ct-skills");
|
|
17395
|
+
if (existsSync29(join32(bundledPath, "skills.json"))) {
|
|
16033
17396
|
ctSkillsRoot = bundledPath;
|
|
16034
17397
|
} else {
|
|
16035
|
-
const ctSkillsPath =
|
|
16036
|
-
if (existsSync29(
|
|
17398
|
+
const ctSkillsPath = join32(packageRoot, "node_modules", "@cleocode", "ct-skills");
|
|
17399
|
+
if (existsSync29(join32(ctSkillsPath, "skills.json"))) {
|
|
16037
17400
|
ctSkillsRoot = ctSkillsPath;
|
|
16038
17401
|
}
|
|
16039
17402
|
}
|
|
@@ -16048,13 +17411,13 @@ async function initCoreSkills(created, warnings) {
|
|
|
16048
17411
|
} catch {
|
|
16049
17412
|
warnings.push("Failed to register skill library with CAAMP");
|
|
16050
17413
|
}
|
|
16051
|
-
const catalogPath =
|
|
17414
|
+
const catalogPath = join32(ctSkillsRoot, "skills.json");
|
|
16052
17415
|
const catalog2 = JSON.parse(readFileSync21(catalogPath, "utf-8"));
|
|
16053
17416
|
const skills = catalog2.skills ?? [];
|
|
16054
17417
|
const coreSkills = skills.filter((s) => s.tier <= 2);
|
|
16055
17418
|
const installed = [];
|
|
16056
17419
|
for (const skill of coreSkills) {
|
|
16057
|
-
const skillSourceDir =
|
|
17420
|
+
const skillSourceDir = dirname8(join32(ctSkillsRoot, skill.path));
|
|
16058
17421
|
if (!existsSync29(skillSourceDir)) {
|
|
16059
17422
|
continue;
|
|
16060
17423
|
}
|
|
@@ -16131,7 +17494,7 @@ async function initProject(opts = {}) {
|
|
|
16131
17494
|
}
|
|
16132
17495
|
try {
|
|
16133
17496
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
16134
|
-
await getDb2(
|
|
17497
|
+
await getDb2(join32(cleoDir, ".."));
|
|
16135
17498
|
created.push("tasks.db");
|
|
16136
17499
|
} catch (err) {
|
|
16137
17500
|
created.push(`tasks.db (deferred: ${err instanceof Error ? err.message : String(err)})`);
|
|
@@ -16144,7 +17507,7 @@ async function initProject(opts = {}) {
|
|
|
16144
17507
|
created.push(".gitignore");
|
|
16145
17508
|
}
|
|
16146
17509
|
} else {
|
|
16147
|
-
const gitignorePath =
|
|
17510
|
+
const gitignorePath = join32(cleoDir, ".gitignore");
|
|
16148
17511
|
if (existsSync29(gitignorePath)) {
|
|
16149
17512
|
skipped.push(".gitignore");
|
|
16150
17513
|
} else {
|
|
@@ -16156,12 +17519,12 @@ async function initProject(opts = {}) {
|
|
|
16156
17519
|
}
|
|
16157
17520
|
}
|
|
16158
17521
|
}
|
|
16159
|
-
const legacySequencePath =
|
|
17522
|
+
const legacySequencePath = join32(cleoDir, ".sequence");
|
|
16160
17523
|
try {
|
|
16161
17524
|
await unlink3(legacySequencePath);
|
|
16162
17525
|
} catch {
|
|
16163
17526
|
}
|
|
16164
|
-
const legacySequenceJsonPath =
|
|
17527
|
+
const legacySequenceJsonPath = join32(cleoDir, ".sequence.json");
|
|
16165
17528
|
try {
|
|
16166
17529
|
await unlink3(legacySequenceJsonPath);
|
|
16167
17530
|
} catch {
|
|
@@ -16256,8 +17619,8 @@ async function initProject(opts = {}) {
|
|
|
16256
17619
|
async function getVersion(projectRoot) {
|
|
16257
17620
|
const root = projectRoot ?? getProjectRoot();
|
|
16258
17621
|
const versionPaths = [
|
|
16259
|
-
|
|
16260
|
-
|
|
17622
|
+
join32(root, "VERSION"),
|
|
17623
|
+
join32(root, "..", "VERSION")
|
|
16261
17624
|
];
|
|
16262
17625
|
for (const versionPath of versionPaths) {
|
|
16263
17626
|
try {
|
|
@@ -16269,7 +17632,7 @@ async function getVersion(projectRoot) {
|
|
|
16269
17632
|
} catch {
|
|
16270
17633
|
}
|
|
16271
17634
|
}
|
|
16272
|
-
const pkg = await readJson(
|
|
17635
|
+
const pkg = await readJson(join32(root, "package.json"));
|
|
16273
17636
|
if (pkg?.version) {
|
|
16274
17637
|
return { version: pkg.version };
|
|
16275
17638
|
}
|
|
@@ -16316,17 +17679,17 @@ init_paths();
|
|
|
16316
17679
|
init_schema();
|
|
16317
17680
|
init_sqlite();
|
|
16318
17681
|
init_schema();
|
|
16319
|
-
import { eq as
|
|
17682
|
+
import { eq as eq11 } from "drizzle-orm";
|
|
16320
17683
|
|
|
16321
17684
|
// src/core/lifecycle/stage-artifacts.ts
|
|
16322
17685
|
import { existsSync as existsSync31 } from "node:fs";
|
|
16323
17686
|
import { readFile as readFile8, writeFile as writeFile5 } from "node:fs/promises";
|
|
16324
|
-
import { dirname as
|
|
17687
|
+
import { dirname as dirname9, join as join34, relative } from "node:path";
|
|
16325
17688
|
|
|
16326
17689
|
// src/core/lifecycle/rcasd-paths.ts
|
|
16327
17690
|
init_paths();
|
|
16328
|
-
import { join as
|
|
16329
|
-
import { existsSync as existsSync30, mkdirSync as
|
|
17691
|
+
import { join as join33 } from "node:path";
|
|
17692
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync10, readdirSync as readdirSync9 } from "node:fs";
|
|
16330
17693
|
var STAGE_SUBDIRS = {
|
|
16331
17694
|
research: "research",
|
|
16332
17695
|
consensus: "consensus",
|
|
@@ -16343,16 +17706,16 @@ function normalizeEpicId(dirName) {
|
|
|
16343
17706
|
}
|
|
16344
17707
|
function getEpicDir(epicId, cwd) {
|
|
16345
17708
|
const normalized = normalizeEpicId(epicId);
|
|
16346
|
-
return
|
|
17709
|
+
return join33(getCleoDirAbsolute(cwd), DEFAULT_DIR, normalized);
|
|
16347
17710
|
}
|
|
16348
17711
|
function getStagePath(epicId, stage, cwd) {
|
|
16349
17712
|
const subdir = STAGE_SUBDIRS[stage] ?? stage;
|
|
16350
|
-
return
|
|
17713
|
+
return join33(getEpicDir(epicId, cwd), subdir);
|
|
16351
17714
|
}
|
|
16352
17715
|
function ensureStagePath(epicId, stage, cwd) {
|
|
16353
17716
|
const path = getStagePath(epicId, stage, cwd);
|
|
16354
17717
|
if (!existsSync30(path)) {
|
|
16355
|
-
|
|
17718
|
+
mkdirSync10(path, { recursive: true });
|
|
16356
17719
|
}
|
|
16357
17720
|
return path;
|
|
16358
17721
|
}
|
|
@@ -16728,10 +18091,10 @@ function toWorkspaceRelative(path, cwd) {
|
|
|
16728
18091
|
function buildRelatedLinks(epicId, stage, absolutePath, cwd) {
|
|
16729
18092
|
const prereqs = STAGE_PREREQUISITES[stage] ?? [];
|
|
16730
18093
|
const related = [{ type: "task", id: epicId }];
|
|
16731
|
-
const artifactDir =
|
|
18094
|
+
const artifactDir = dirname9(absolutePath);
|
|
16732
18095
|
for (const prereq of prereqs) {
|
|
16733
18096
|
const prereqDir = getStagePath(epicId, prereq, cwd);
|
|
16734
|
-
const prereqFile =
|
|
18097
|
+
const prereqFile = join34(prereqDir, `${epicId}-${stageSlug(prereq)}.md`);
|
|
16735
18098
|
if (!existsSync31(prereqFile)) {
|
|
16736
18099
|
continue;
|
|
16737
18100
|
}
|
|
@@ -16745,7 +18108,7 @@ function buildRelatedLinks(epicId, stage, absolutePath, cwd) {
|
|
|
16745
18108
|
async function ensureStageArtifact(epicId, stage, cwd) {
|
|
16746
18109
|
const stageDir = ensureStagePath(epicId, stage, cwd);
|
|
16747
18110
|
const fileName = `${epicId}-${stageSlug(stage)}.md`;
|
|
16748
|
-
const absolutePath =
|
|
18111
|
+
const absolutePath = join34(stageDir, fileName);
|
|
16749
18112
|
const outputFile = toWorkspaceRelative(absolutePath, cwd);
|
|
16750
18113
|
const currentContent = existsSync31(absolutePath) ? await readFile8(absolutePath, "utf-8") : buildDefaultBody(epicId, stage);
|
|
16751
18114
|
const related = buildRelatedLinks(epicId, stage, absolutePath, cwd);
|
|
@@ -16766,7 +18129,7 @@ async function ensureStageArtifact(epicId, stage, cwd) {
|
|
|
16766
18129
|
init_sqlite();
|
|
16767
18130
|
init_schema();
|
|
16768
18131
|
init_paths();
|
|
16769
|
-
import { eq as
|
|
18132
|
+
import { eq as eq8, like } from "drizzle-orm";
|
|
16770
18133
|
import { relative as relative2, basename as basename7 } from "node:path";
|
|
16771
18134
|
async function recordEvidence(epicId, stage, uri, type, options) {
|
|
16772
18135
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -16811,12 +18174,12 @@ async function linkProvenance(epicId, stage, filePath, cwd) {
|
|
|
16811
18174
|
init_sqlite();
|
|
16812
18175
|
init_schema();
|
|
16813
18176
|
import { readFileSync as readFileSync23, readdirSync as readdirSync10, writeFileSync as writeFileSync6, existsSync as existsSync32 } from "node:fs";
|
|
16814
|
-
import { join as
|
|
16815
|
-
import { eq as
|
|
18177
|
+
import { join as join36 } from "node:path";
|
|
18178
|
+
import { eq as eq9 } from "drizzle-orm";
|
|
16816
18179
|
|
|
16817
18180
|
// src/core/adrs/parse.ts
|
|
16818
18181
|
import { readFileSync as readFileSync22 } from "node:fs";
|
|
16819
|
-
import { join as
|
|
18182
|
+
import { join as join35 } from "node:path";
|
|
16820
18183
|
function extractAdrId(filename) {
|
|
16821
18184
|
const match = filename.match(/^(ADR-\d+)/);
|
|
16822
18185
|
return match ? match[1] : filename.replace(".md", "");
|
|
@@ -16838,7 +18201,7 @@ function extractTitle(content) {
|
|
|
16838
18201
|
return match ? match[1].trim() : "Untitled";
|
|
16839
18202
|
}
|
|
16840
18203
|
function parseAdrFile(filePath, projectRoot) {
|
|
16841
|
-
const absolutePath = filePath.startsWith("/") ? filePath :
|
|
18204
|
+
const absolutePath = filePath.startsWith("/") ? filePath : join35(projectRoot, filePath);
|
|
16842
18205
|
const content = readFileSync22(absolutePath, "utf-8");
|
|
16843
18206
|
const filename = filePath.split("/").pop();
|
|
16844
18207
|
return {
|
|
@@ -16861,7 +18224,7 @@ function collectAdrFiles(dir) {
|
|
|
16861
18224
|
const results = [];
|
|
16862
18225
|
for (const entry of readdirSync10(dir, { withFileTypes: true })) {
|
|
16863
18226
|
if (entry.isDirectory()) {
|
|
16864
|
-
const sub =
|
|
18227
|
+
const sub = join36(dir, entry.name);
|
|
16865
18228
|
for (const f of readdirSync10(sub)) {
|
|
16866
18229
|
if (f.endsWith(".md") && /^ADR-\d+/.test(f)) {
|
|
16867
18230
|
results.push({ file: f, relPath: `${entry.name}/${f}` });
|
|
@@ -16874,7 +18237,7 @@ function collectAdrFiles(dir) {
|
|
|
16874
18237
|
return results.sort((a, b) => a.file.localeCompare(b.file));
|
|
16875
18238
|
}
|
|
16876
18239
|
async function syncAdrsToDb(projectRoot) {
|
|
16877
|
-
const adrsDir =
|
|
18240
|
+
const adrsDir = join36(projectRoot, ".cleo", "adrs");
|
|
16878
18241
|
const result = { inserted: 0, updated: 0, skipped: 0, errors: [] };
|
|
16879
18242
|
if (!existsSync32(adrsDir)) {
|
|
16880
18243
|
return result;
|
|
@@ -16886,7 +18249,7 @@ async function syncAdrsToDb(projectRoot) {
|
|
|
16886
18249
|
const manifestEntries2 = [];
|
|
16887
18250
|
for (const { file, relPath } of activeFiles) {
|
|
16888
18251
|
try {
|
|
16889
|
-
const filePath =
|
|
18252
|
+
const filePath = join36(adrsDir, relPath);
|
|
16890
18253
|
const record = parseAdrFile(filePath, projectRoot);
|
|
16891
18254
|
const fm = record.frontmatter;
|
|
16892
18255
|
const dbRelPath = `.cleo/adrs/${relPath}`;
|
|
@@ -16912,15 +18275,15 @@ async function syncAdrsToDb(projectRoot) {
|
|
|
16912
18275
|
topics: fm.Topics ?? null,
|
|
16913
18276
|
updatedAt: now
|
|
16914
18277
|
};
|
|
16915
|
-
const existing = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(
|
|
18278
|
+
const existing = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq9(architectureDecisions.id, record.id)).all();
|
|
16916
18279
|
if (existing.length > 0) {
|
|
16917
|
-
await db.update(architectureDecisions).set(rowBase).where(
|
|
18280
|
+
await db.update(architectureDecisions).set(rowBase).where(eq9(architectureDecisions.id, record.id));
|
|
16918
18281
|
result.updated++;
|
|
16919
18282
|
} else {
|
|
16920
18283
|
await db.insert(architectureDecisions).values({ ...rowBase, createdAt: now });
|
|
16921
18284
|
result.inserted++;
|
|
16922
18285
|
}
|
|
16923
|
-
await db.delete(adrTaskLinks).where(
|
|
18286
|
+
await db.delete(adrTaskLinks).where(eq9(adrTaskLinks.adrId, record.id));
|
|
16924
18287
|
if (fm["Related Tasks"]) {
|
|
16925
18288
|
for (const taskId of parseTaskIds(fm["Related Tasks"])) {
|
|
16926
18289
|
await db.insert(adrTaskLinks).values({ adrId: record.id, taskId, linkType: "related" });
|
|
@@ -16932,7 +18295,7 @@ async function syncAdrsToDb(projectRoot) {
|
|
|
16932
18295
|
}
|
|
16933
18296
|
for (const { relPath } of allFiles) {
|
|
16934
18297
|
try {
|
|
16935
|
-
const filePath =
|
|
18298
|
+
const filePath = join36(adrsDir, relPath);
|
|
16936
18299
|
const record = parseAdrFile(filePath, projectRoot);
|
|
16937
18300
|
const fm = record.frontmatter;
|
|
16938
18301
|
const entry = {
|
|
@@ -16960,7 +18323,7 @@ async function syncAdrsToDb(projectRoot) {
|
|
|
16960
18323
|
}
|
|
16961
18324
|
}
|
|
16962
18325
|
writeFileSync6(
|
|
16963
|
-
|
|
18326
|
+
join36(adrsDir, "MANIFEST.jsonl"),
|
|
16964
18327
|
manifestEntries2.map((e) => JSON.stringify(e)).join("\n") + "\n",
|
|
16965
18328
|
"utf-8"
|
|
16966
18329
|
);
|
|
@@ -16971,8 +18334,8 @@ async function syncAdrsToDb(projectRoot) {
|
|
|
16971
18334
|
init_sqlite();
|
|
16972
18335
|
init_schema();
|
|
16973
18336
|
import { readdirSync as readdirSync11, readFileSync as readFileSync24, existsSync as existsSync33 } from "node:fs";
|
|
16974
|
-
import { join as
|
|
16975
|
-
import { eq as
|
|
18337
|
+
import { join as join37 } from "node:path";
|
|
18338
|
+
import { eq as eq10, and as and3 } from "drizzle-orm";
|
|
16976
18339
|
function parseTaskIds2(raw) {
|
|
16977
18340
|
if (!raw) return [];
|
|
16978
18341
|
return raw.split(",").map((t) => t.trim()).filter((t) => /^T\d{1,5}$/.test(t));
|
|
@@ -16981,7 +18344,7 @@ function findAdrsForTask(adrsDir, taskId) {
|
|
|
16981
18344
|
if (!existsSync33(adrsDir)) return [];
|
|
16982
18345
|
return readdirSync11(adrsDir).filter((f) => f.endsWith(".md") && /^ADR-\d+/.test(f)).filter((file) => {
|
|
16983
18346
|
try {
|
|
16984
|
-
const content = readFileSync24(
|
|
18347
|
+
const content = readFileSync24(join37(adrsDir, file), "utf-8");
|
|
16985
18348
|
const relatedTasksMatch = content.match(/^\*\*Related Tasks\*\*:\s*(.+)$/m);
|
|
16986
18349
|
if (!relatedTasksMatch) return false;
|
|
16987
18350
|
const taskIds = parseTaskIds2(relatedTasksMatch[1]);
|
|
@@ -16989,7 +18352,7 @@ function findAdrsForTask(adrsDir, taskId) {
|
|
|
16989
18352
|
} catch {
|
|
16990
18353
|
return false;
|
|
16991
18354
|
}
|
|
16992
|
-
}).map((f) =>
|
|
18355
|
+
}).map((f) => join37(adrsDir, f));
|
|
16993
18356
|
}
|
|
16994
18357
|
async function linkPipelineAdr(projectRoot, taskId) {
|
|
16995
18358
|
const result = {
|
|
@@ -16998,7 +18361,7 @@ async function linkPipelineAdr(projectRoot, taskId) {
|
|
|
16998
18361
|
skipped: 0,
|
|
16999
18362
|
errors: []
|
|
17000
18363
|
};
|
|
17001
|
-
const adrsDir =
|
|
18364
|
+
const adrsDir = join37(projectRoot, ".cleo", "adrs");
|
|
17002
18365
|
const matchingFiles = findAdrsForTask(adrsDir, taskId);
|
|
17003
18366
|
if (matchingFiles.length === 0) {
|
|
17004
18367
|
return result;
|
|
@@ -17012,7 +18375,7 @@ async function linkPipelineAdr(projectRoot, taskId) {
|
|
|
17012
18375
|
const fm = record.frontmatter;
|
|
17013
18376
|
const content = readFileSync24(filePath, "utf-8");
|
|
17014
18377
|
const relativePath = `.cleo/adrs/${filename}`;
|
|
17015
|
-
const existing = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(
|
|
18378
|
+
const existing = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq10(architectureDecisions.id, record.id)).all();
|
|
17016
18379
|
const rowBase = {
|
|
17017
18380
|
id: record.id,
|
|
17018
18381
|
title: record.title,
|
|
@@ -17032,15 +18395,15 @@ async function linkPipelineAdr(projectRoot, taskId) {
|
|
|
17032
18395
|
updatedAt: now
|
|
17033
18396
|
};
|
|
17034
18397
|
if (existing.length > 0) {
|
|
17035
|
-
await db.update(architectureDecisions).set(rowBase).where(
|
|
18398
|
+
await db.update(architectureDecisions).set(rowBase).where(eq10(architectureDecisions.id, record.id));
|
|
17036
18399
|
} else {
|
|
17037
18400
|
await db.insert(architectureDecisions).values({ ...rowBase, createdAt: now });
|
|
17038
18401
|
}
|
|
17039
18402
|
result.synced++;
|
|
17040
18403
|
await db.delete(adrTaskLinks).where(
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
18404
|
+
and3(
|
|
18405
|
+
eq10(adrTaskLinks.adrId, record.id),
|
|
18406
|
+
eq10(adrTaskLinks.taskId, taskId)
|
|
17044
18407
|
)
|
|
17045
18408
|
);
|
|
17046
18409
|
await db.insert(adrTaskLinks).values({ adrId: record.id, taskId, linkType: "implements" });
|
|
@@ -17049,7 +18412,7 @@ async function linkPipelineAdr(projectRoot, taskId) {
|
|
|
17049
18412
|
const relatedIds = fm["Related ADRs"].split(",").map((r) => r.trim()).filter((r) => /^ADR-\d+$/.test(r));
|
|
17050
18413
|
for (const toId of relatedIds) {
|
|
17051
18414
|
try {
|
|
17052
|
-
const targetExists = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(
|
|
18415
|
+
const targetExists = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq10(architectureDecisions.id, toId)).all();
|
|
17053
18416
|
if (targetExists.length > 0) {
|
|
17054
18417
|
await db.insert(adrRelations).values({ fromAdrId: record.id, toAdrId: toId, relationType: "related" }).onConflictDoNothing();
|
|
17055
18418
|
}
|
|
@@ -17071,7 +18434,7 @@ async function getLifecycleStatus(epicId, cwd) {
|
|
|
17071
18434
|
const pipelineResult = await db.select({
|
|
17072
18435
|
pipeline: lifecyclePipelines,
|
|
17073
18436
|
task: tasks
|
|
17074
|
-
}).from(lifecyclePipelines).innerJoin(tasks,
|
|
18437
|
+
}).from(lifecyclePipelines).innerJoin(tasks, eq11(lifecyclePipelines.taskId, tasks.id)).where(eq11(lifecyclePipelines.taskId, epicId)).limit(1);
|
|
17075
18438
|
if (pipelineResult.length === 0) {
|
|
17076
18439
|
return {
|
|
17077
18440
|
epicId,
|
|
@@ -17084,7 +18447,7 @@ async function getLifecycleStatus(epicId, cwd) {
|
|
|
17084
18447
|
}
|
|
17085
18448
|
const task = pipelineResult[0].task;
|
|
17086
18449
|
const pipelineId = `pipeline-${epicId}`;
|
|
17087
|
-
const stageRows = await db.select().from(lifecycleStages).where(
|
|
18450
|
+
const stageRows = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.pipelineId, pipelineId)).orderBy(lifecycleStages.sequence);
|
|
17088
18451
|
const stageDataMap = /* @__PURE__ */ new Map();
|
|
17089
18452
|
for (const row of stageRows) {
|
|
17090
18453
|
let parsedChain;
|
|
@@ -17154,7 +18517,7 @@ async function getLifecycleStatus(epicId, cwd) {
|
|
|
17154
18517
|
async function getLifecycleHistory(epicId, cwd) {
|
|
17155
18518
|
const db = await getDb(cwd);
|
|
17156
18519
|
const pipelineId = `pipeline-${epicId}`;
|
|
17157
|
-
const stages = await db.select().from(lifecycleStages).where(
|
|
18520
|
+
const stages = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.pipelineId, pipelineId));
|
|
17158
18521
|
if (stages.length === 0) {
|
|
17159
18522
|
return { epicId, history: [] };
|
|
17160
18523
|
}
|
|
@@ -17184,7 +18547,7 @@ async function getLifecycleHistory(epicId, cwd) {
|
|
|
17184
18547
|
}
|
|
17185
18548
|
const stageIds = stages.map((s) => s.id);
|
|
17186
18549
|
if (stageIds.length > 0) {
|
|
17187
|
-
const gateResults = await db.select().from(lifecycleGateResults).where(
|
|
18550
|
+
const gateResults = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.stageId, stageIds[0]));
|
|
17188
18551
|
for (const gate of gateResults) {
|
|
17189
18552
|
const stageName = stageIdToName.get(gate.stageId);
|
|
17190
18553
|
if (stageName) {
|
|
@@ -17197,7 +18560,7 @@ async function getLifecycleHistory(epicId, cwd) {
|
|
|
17197
18560
|
}
|
|
17198
18561
|
}
|
|
17199
18562
|
for (let i = 1; i < stageIds.length; i++) {
|
|
17200
|
-
const additionalGates = await db.select().from(lifecycleGateResults).where(
|
|
18563
|
+
const additionalGates = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.stageId, stageIds[i]));
|
|
17201
18564
|
for (const gate of additionalGates) {
|
|
17202
18565
|
const stageName = stageIdToName.get(gate.stageId);
|
|
17203
18566
|
if (stageName) {
|
|
@@ -17217,13 +18580,13 @@ async function getLifecycleHistory(epicId, cwd) {
|
|
|
17217
18580
|
async function getLifecycleGates(epicId, cwd) {
|
|
17218
18581
|
const db = await getDb(cwd);
|
|
17219
18582
|
const pipelineId = `pipeline-${epicId}`;
|
|
17220
|
-
const stages = await db.select().from(lifecycleStages).where(
|
|
18583
|
+
const stages = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.pipelineId, pipelineId));
|
|
17221
18584
|
if (stages.length === 0) {
|
|
17222
18585
|
return {};
|
|
17223
18586
|
}
|
|
17224
18587
|
const gates = {};
|
|
17225
18588
|
for (const stage of stages) {
|
|
17226
|
-
const gateRows = await db.select().from(lifecycleGateResults).where(
|
|
18589
|
+
const gateRows = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.stageId, stage.id));
|
|
17227
18590
|
if (gateRows.length > 0) {
|
|
17228
18591
|
gates[stage.stageName] = {};
|
|
17229
18592
|
for (const gateRow of gateRows) {
|
|
@@ -17295,7 +18658,7 @@ async function ensureLifecycleContext(epicId, stageName, cwd, options) {
|
|
|
17295
18658
|
getNativeDb2().prepare(
|
|
17296
18659
|
`INSERT OR IGNORE INTO tasks (id, title, status, priority, created_at) VALUES (?, ?, 'pending', 'medium', datetime('now'))`
|
|
17297
18660
|
).run(epicId, `Task ${epicId}`);
|
|
17298
|
-
const existingPipeline = await db.select().from(lifecyclePipelines).where(
|
|
18661
|
+
const existingPipeline = await db.select().from(lifecyclePipelines).where(eq11(lifecyclePipelines.id, pipelineId)).limit(1).all();
|
|
17299
18662
|
if (existingPipeline.length === 0) {
|
|
17300
18663
|
await db.insert(lifecyclePipelines).values({
|
|
17301
18664
|
id: pipelineId,
|
|
@@ -17305,7 +18668,7 @@ async function ensureLifecycleContext(epicId, stageName, cwd, options) {
|
|
|
17305
18668
|
startedAt: options.now
|
|
17306
18669
|
}).run();
|
|
17307
18670
|
}
|
|
17308
|
-
const existingStage = await db.select().from(lifecycleStages).where(
|
|
18671
|
+
const existingStage = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.id, stageId)).limit(1).all();
|
|
17309
18672
|
if (existingStage.length === 0) {
|
|
17310
18673
|
const sequence = isValidStage(stageName) ? STAGE_ORDER[stageName] : 0;
|
|
17311
18674
|
await db.insert(lifecycleStages).values({
|
|
@@ -17318,7 +18681,7 @@ async function ensureLifecycleContext(epicId, stageName, cwd, options) {
|
|
|
17318
18681
|
}).run();
|
|
17319
18682
|
}
|
|
17320
18683
|
if (options.updateCurrentStage) {
|
|
17321
|
-
await db.update(lifecyclePipelines).set({ currentStageId: stageId }).where(
|
|
18684
|
+
await db.update(lifecyclePipelines).set({ currentStageId: stageId }).where(eq11(lifecyclePipelines.id, pipelineId)).run();
|
|
17322
18685
|
}
|
|
17323
18686
|
return { db, pipelineId, stageId };
|
|
17324
18687
|
}
|
|
@@ -17348,7 +18711,7 @@ async function recordStageProgress(epicId, stage, status, notes, cwd) {
|
|
|
17348
18711
|
status,
|
|
17349
18712
|
related: artifact.related
|
|
17350
18713
|
};
|
|
17351
|
-
const existingStage = await db.select().from(lifecycleStages).where(
|
|
18714
|
+
const existingStage = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.id, stageId)).limit(1).all();
|
|
17352
18715
|
const sequence = STAGE_ORDER[stage];
|
|
17353
18716
|
const stageValues = {
|
|
17354
18717
|
status,
|
|
@@ -17375,7 +18738,7 @@ async function recordStageProgress(epicId, stage, status, notes, cwd) {
|
|
|
17375
18738
|
provenanceChainJson: JSON.stringify(provenanceChain)
|
|
17376
18739
|
}).run();
|
|
17377
18740
|
} else {
|
|
17378
|
-
await db.update(lifecycleStages).set(stageValues).where(
|
|
18741
|
+
await db.update(lifecycleStages).set(stageValues).where(eq11(lifecycleStages.id, stageId)).run();
|
|
17379
18742
|
}
|
|
17380
18743
|
if (status === "completed") {
|
|
17381
18744
|
await linkProvenance(epicId, stageName, artifact.absolutePath, cwd);
|
|
@@ -17407,7 +18770,7 @@ async function resetStage(epicId, stage, reason, cwd) {
|
|
|
17407
18770
|
skippedAt: null,
|
|
17408
18771
|
skipReason: null,
|
|
17409
18772
|
notesJson: JSON.stringify([`Reset: ${reason}`])
|
|
17410
|
-
}).where(
|
|
18773
|
+
}).where(eq11(lifecycleStages.id, stageId)).run();
|
|
17411
18774
|
return { epicId, stage, reason };
|
|
17412
18775
|
}
|
|
17413
18776
|
async function passGate(epicId, gateName, agent, notes, cwd) {
|
|
@@ -17419,7 +18782,7 @@ async function passGate(epicId, gateName, agent, notes, cwd) {
|
|
|
17419
18782
|
stageStatusOnCreate: "in_progress",
|
|
17420
18783
|
updateCurrentStage: true
|
|
17421
18784
|
});
|
|
17422
|
-
const existingGate = await db.select().from(lifecycleGateResults).where(
|
|
18785
|
+
const existingGate = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.id, gateId)).limit(1).all();
|
|
17423
18786
|
const gateValues = {
|
|
17424
18787
|
id: gateId,
|
|
17425
18788
|
stageId,
|
|
@@ -17431,7 +18794,7 @@ async function passGate(epicId, gateName, agent, notes, cwd) {
|
|
|
17431
18794
|
reason: null
|
|
17432
18795
|
};
|
|
17433
18796
|
if (existingGate.length > 0) {
|
|
17434
|
-
await db.update(lifecycleGateResults).set(gateValues).where(
|
|
18797
|
+
await db.update(lifecycleGateResults).set(gateValues).where(eq11(lifecycleGateResults.id, gateId)).run();
|
|
17435
18798
|
} else {
|
|
17436
18799
|
await db.insert(lifecycleGateResults).values(gateValues).run();
|
|
17437
18800
|
}
|
|
@@ -17446,7 +18809,7 @@ async function failGate(epicId, gateName, reason, cwd) {
|
|
|
17446
18809
|
stageStatusOnCreate: "in_progress",
|
|
17447
18810
|
updateCurrentStage: true
|
|
17448
18811
|
});
|
|
17449
|
-
const existingGate = await db.select().from(lifecycleGateResults).where(
|
|
18812
|
+
const existingGate = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.id, gateId)).limit(1).all();
|
|
17450
18813
|
const gateValues = {
|
|
17451
18814
|
id: gateId,
|
|
17452
18815
|
stageId,
|
|
@@ -17458,7 +18821,7 @@ async function failGate(epicId, gateName, reason, cwd) {
|
|
|
17458
18821
|
reason: reason ?? null
|
|
17459
18822
|
};
|
|
17460
18823
|
if (existingGate.length > 0) {
|
|
17461
|
-
await db.update(lifecycleGateResults).set(gateValues).where(
|
|
18824
|
+
await db.update(lifecycleGateResults).set(gateValues).where(eq11(lifecycleGateResults.id, gateId)).run();
|
|
17462
18825
|
} else {
|
|
17463
18826
|
await db.insert(lifecycleGateResults).values(gateValues).run();
|
|
17464
18827
|
}
|
|
@@ -17607,9 +18970,9 @@ init_platform();
|
|
|
17607
18970
|
// src/core/validation/validate-ops.ts
|
|
17608
18971
|
init_paths();
|
|
17609
18972
|
init_data_accessor();
|
|
17610
|
-
import { readFileSync as readFileSync26, existsSync as existsSync34, appendFileSync as appendFileSync3, mkdirSync as
|
|
18973
|
+
import { readFileSync as readFileSync26, existsSync as existsSync34, appendFileSync as appendFileSync3, mkdirSync as mkdirSync11 } from "node:fs";
|
|
17611
18974
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
17612
|
-
import { join as
|
|
18975
|
+
import { join as join38, dirname as dirname10, resolve as resolve6 } from "node:path";
|
|
17613
18976
|
|
|
17614
18977
|
// src/core/validation/schema-validator.ts
|
|
17615
18978
|
init_validation_schemas();
|
|
@@ -17826,7 +19189,7 @@ init_json();
|
|
|
17826
19189
|
init_status_registry();
|
|
17827
19190
|
|
|
17828
19191
|
// src/core/repair.ts
|
|
17829
|
-
import { isNull as isNull2, sql as
|
|
19192
|
+
import { isNull as isNull2, sql as sql4 } from "drizzle-orm";
|
|
17830
19193
|
|
|
17831
19194
|
// src/core/validation/validate-ops.ts
|
|
17832
19195
|
function readJsonFile2(filePath) {
|
|
@@ -17846,7 +19209,7 @@ async function coreValidateSchema(type, data, projectRoot) {
|
|
|
17846
19209
|
throw new Error(`Unknown schema type: ${type}. Valid types: ${validTypes.join(", ")}`);
|
|
17847
19210
|
}
|
|
17848
19211
|
if (type === "config") {
|
|
17849
|
-
const filePath =
|
|
19212
|
+
const filePath = join38(projectRoot, ".cleo", "config.json");
|
|
17850
19213
|
if (!existsSync34(filePath)) {
|
|
17851
19214
|
throw new Error("File not found: .cleo/config.json");
|
|
17852
19215
|
}
|
|
@@ -18058,7 +19421,7 @@ function coreValidateOutput(filePath, taskId, projectRoot) {
|
|
|
18058
19421
|
};
|
|
18059
19422
|
}
|
|
18060
19423
|
function parseComplianceEntries(projectRoot) {
|
|
18061
|
-
const compliancePath =
|
|
19424
|
+
const compliancePath = join38(projectRoot, ".cleo", "metrics", "COMPLIANCE.jsonl");
|
|
18062
19425
|
if (!existsSync34(compliancePath)) {
|
|
18063
19426
|
return [];
|
|
18064
19427
|
}
|
|
@@ -18122,10 +19485,10 @@ function coreComplianceRecord(taskId, result, protocol, violations, projectRoot)
|
|
|
18122
19485
|
if (!validResults.includes(result)) {
|
|
18123
19486
|
throw new Error(`Invalid result: ${result}. Valid: ${validResults.join(", ")}`);
|
|
18124
19487
|
}
|
|
18125
|
-
const compliancePath =
|
|
18126
|
-
const dir =
|
|
19488
|
+
const compliancePath = join38(projectRoot, ".cleo", "metrics", "COMPLIANCE.jsonl");
|
|
19489
|
+
const dir = dirname10(compliancePath);
|
|
18127
19490
|
if (!existsSync34(dir)) {
|
|
18128
|
-
|
|
19491
|
+
mkdirSync11(dir, { recursive: true });
|
|
18129
19492
|
}
|
|
18130
19493
|
const entry = {
|
|
18131
19494
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -18144,8 +19507,8 @@ function coreComplianceRecord(taskId, result, protocol, violations, projectRoot)
|
|
|
18144
19507
|
};
|
|
18145
19508
|
}
|
|
18146
19509
|
function coreTestStatus(projectRoot) {
|
|
18147
|
-
const testDir =
|
|
18148
|
-
const mcpTestDir =
|
|
19510
|
+
const testDir = join38(projectRoot, "tests");
|
|
19511
|
+
const mcpTestDir = join38(projectRoot, "src", "mcp", "__tests__");
|
|
18149
19512
|
const hasBatsTests = existsSync34(testDir);
|
|
18150
19513
|
const hasMcpTests = existsSync34(mcpTestDir);
|
|
18151
19514
|
return {
|
|
@@ -18289,8 +19652,8 @@ async function coreCoherenceCheck(projectRoot) {
|
|
|
18289
19652
|
};
|
|
18290
19653
|
}
|
|
18291
19654
|
function coreTestRun(params, projectRoot) {
|
|
18292
|
-
const hasVitest = existsSync34(
|
|
18293
|
-
const hasBats = existsSync34(
|
|
19655
|
+
const hasVitest = existsSync34(join38(projectRoot, "node_modules", ".bin", "vitest"));
|
|
19656
|
+
const hasBats = existsSync34(join38(projectRoot, "tests"));
|
|
18294
19657
|
if (!hasVitest && !hasBats) {
|
|
18295
19658
|
return {
|
|
18296
19659
|
ran: false,
|
|
@@ -18336,7 +19699,7 @@ function coreTestRun(params, projectRoot) {
|
|
|
18336
19699
|
}
|
|
18337
19700
|
}
|
|
18338
19701
|
function coreTestCoverage(projectRoot) {
|
|
18339
|
-
const coveragePath =
|
|
19702
|
+
const coveragePath = join38(projectRoot, "coverage", "coverage-summary.json");
|
|
18340
19703
|
if (!existsSync34(coveragePath)) {
|
|
18341
19704
|
return {
|
|
18342
19705
|
available: false,
|
|
@@ -18985,12 +20348,12 @@ async function getUnblockOpportunities(cwd, accessor) {
|
|
|
18985
20348
|
// src/core/orchestration/parallel.ts
|
|
18986
20349
|
init_errors();
|
|
18987
20350
|
init_exit_codes();
|
|
18988
|
-
import { readFileSync as readFileSync27, writeFileSync as writeFileSync7, existsSync as existsSync35, mkdirSync as
|
|
18989
|
-
import { join as
|
|
20351
|
+
import { readFileSync as readFileSync27, writeFileSync as writeFileSync7, existsSync as existsSync35, mkdirSync as mkdirSync12 } from "node:fs";
|
|
20352
|
+
import { join as join39, dirname as dirname11 } from "node:path";
|
|
18990
20353
|
init_json();
|
|
18991
20354
|
init_paths();
|
|
18992
20355
|
function getParallelStatePath(projectRoot) {
|
|
18993
|
-
return
|
|
20356
|
+
return join39(projectRoot, ".cleo", "parallel-state.json");
|
|
18994
20357
|
}
|
|
18995
20358
|
function readParallelState(projectRoot) {
|
|
18996
20359
|
const statePath = getParallelStatePath(projectRoot);
|
|
@@ -19003,8 +20366,8 @@ function readParallelState(projectRoot) {
|
|
|
19003
20366
|
}
|
|
19004
20367
|
function writeParallelState(state, projectRoot) {
|
|
19005
20368
|
const statePath = getParallelStatePath(projectRoot);
|
|
19006
|
-
const dir =
|
|
19007
|
-
if (!existsSync35(dir))
|
|
20369
|
+
const dir = dirname11(statePath);
|
|
20370
|
+
if (!existsSync35(dir)) mkdirSync12(dir, { recursive: true });
|
|
19008
20371
|
writeFileSync7(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
19009
20372
|
}
|
|
19010
20373
|
async function startParallelExecution(epicId, wave, cwd, accessor) {
|
|
@@ -19141,7 +20504,7 @@ async function validateSpawnReadiness(taskId, cwd, accessor) {
|
|
|
19141
20504
|
init_json();
|
|
19142
20505
|
init_paths();
|
|
19143
20506
|
import { readFileSync as readFileSync28, existsSync as existsSync36 } from "node:fs";
|
|
19144
|
-
import { join as
|
|
20507
|
+
import { join as join40 } from "node:path";
|
|
19145
20508
|
async function buildBrainState(projectRoot, opts, accessor) {
|
|
19146
20509
|
const speed = opts?.speed || "fast";
|
|
19147
20510
|
const brain = {
|
|
@@ -19209,7 +20572,7 @@ async function buildBrainState(projectRoot, opts, accessor) {
|
|
|
19209
20572
|
blockedBy: b.depends || []
|
|
19210
20573
|
}));
|
|
19211
20574
|
try {
|
|
19212
|
-
const decisionLogPath =
|
|
20575
|
+
const decisionLogPath = join40(projectRoot, ".cleo", "decision-log.jsonl");
|
|
19213
20576
|
if (existsSync36(decisionLogPath)) {
|
|
19214
20577
|
const content = readFileSync28(decisionLogPath, "utf-8").trim();
|
|
19215
20578
|
if (content) {
|
|
@@ -19231,7 +20594,7 @@ async function buildBrainState(projectRoot, opts, accessor) {
|
|
|
19231
20594
|
} catch {
|
|
19232
20595
|
}
|
|
19233
20596
|
try {
|
|
19234
|
-
const contextStatePath =
|
|
20597
|
+
const contextStatePath = join40(projectRoot, ".cleo", ".context-state.json");
|
|
19235
20598
|
if (existsSync36(contextStatePath)) {
|
|
19236
20599
|
const state = JSON.parse(readFileSync28(contextStatePath, "utf-8"));
|
|
19237
20600
|
const percentage = state.contextWindow?.percentage ?? 0;
|
|
@@ -19685,8 +21048,8 @@ async function orchestrateCheck(projectRoot) {
|
|
|
19685
21048
|
|
|
19686
21049
|
// src/core/memory/engine-compat.ts
|
|
19687
21050
|
init_paths();
|
|
19688
|
-
import { readFileSync as readFileSync32, writeFileSync as writeFileSync10, appendFileSync as appendFileSync6, existsSync as existsSync40, mkdirSync as
|
|
19689
|
-
import { resolve as resolve7, dirname as
|
|
21051
|
+
import { readFileSync as readFileSync32, writeFileSync as writeFileSync10, appendFileSync as appendFileSync6, existsSync as existsSync40, mkdirSync as mkdirSync15 } from "node:fs";
|
|
21052
|
+
import { resolve as resolve7, dirname as dirname12 } from "node:path";
|
|
19690
21053
|
|
|
19691
21054
|
// src/core/memory/index.ts
|
|
19692
21055
|
init_json();
|
|
@@ -19695,123 +21058,32 @@ init_errors();
|
|
|
19695
21058
|
init_exit_codes();
|
|
19696
21059
|
init_paths();
|
|
19697
21060
|
|
|
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
21061
|
// src/core/memory/decisions.ts
|
|
21062
|
+
init_brain_accessor();
|
|
21063
|
+
init_brain_sqlite();
|
|
21064
|
+
init_brain_schema();
|
|
19800
21065
|
import { desc as desc2 } from "drizzle-orm";
|
|
19801
21066
|
|
|
21067
|
+
// src/core/memory/brain-migration.ts
|
|
21068
|
+
init_brain_accessor();
|
|
21069
|
+
|
|
21070
|
+
// src/core/memory/index.ts
|
|
21071
|
+
init_brain_search();
|
|
21072
|
+
init_brain_links();
|
|
21073
|
+
|
|
19802
21074
|
// src/core/memory/patterns.ts
|
|
19803
21075
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
19804
|
-
import { readFileSync as readFileSync30, writeFileSync as writeFileSync8, appendFileSync as appendFileSync4, mkdirSync as
|
|
19805
|
-
import { join as
|
|
21076
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync8, appendFileSync as appendFileSync4, mkdirSync as mkdirSync13, existsSync as existsSync38 } from "node:fs";
|
|
21077
|
+
import { join as join41 } from "node:path";
|
|
19806
21078
|
function getMemoryDir(projectRoot) {
|
|
19807
|
-
const memDir =
|
|
21079
|
+
const memDir = join41(projectRoot, ".cleo", "memory");
|
|
19808
21080
|
if (!existsSync38(memDir)) {
|
|
19809
|
-
|
|
21081
|
+
mkdirSync13(memDir, { recursive: true });
|
|
19810
21082
|
}
|
|
19811
21083
|
return memDir;
|
|
19812
21084
|
}
|
|
19813
21085
|
function getPatternsPath(projectRoot) {
|
|
19814
|
-
return
|
|
21086
|
+
return join41(getMemoryDir(projectRoot), "patterns.jsonl");
|
|
19815
21087
|
}
|
|
19816
21088
|
function generatePatternId() {
|
|
19817
21089
|
return `P${randomBytes7(4).toString("hex")}`;
|
|
@@ -19928,17 +21200,17 @@ function patternStats(projectRoot) {
|
|
|
19928
21200
|
|
|
19929
21201
|
// src/core/memory/learnings.ts
|
|
19930
21202
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
19931
|
-
import { readFileSync as readFileSync31, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, mkdirSync as
|
|
19932
|
-
import { join as
|
|
21203
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, mkdirSync as mkdirSync14, existsSync as existsSync39 } from "node:fs";
|
|
21204
|
+
import { join as join42 } from "node:path";
|
|
19933
21205
|
function getMemoryDir2(projectRoot) {
|
|
19934
|
-
const memDir =
|
|
21206
|
+
const memDir = join42(projectRoot, ".cleo", "memory");
|
|
19935
21207
|
if (!existsSync39(memDir)) {
|
|
19936
|
-
|
|
21208
|
+
mkdirSync14(memDir, { recursive: true });
|
|
19937
21209
|
}
|
|
19938
21210
|
return memDir;
|
|
19939
21211
|
}
|
|
19940
21212
|
function getLearningsPath(projectRoot) {
|
|
19941
|
-
return
|
|
21213
|
+
return join42(getMemoryDir2(projectRoot), "learnings.jsonl");
|
|
19942
21214
|
}
|
|
19943
21215
|
function generateLearningId() {
|
|
19944
21216
|
return `L${randomBytes8(4).toString("hex")}`;
|
|
@@ -20051,6 +21323,7 @@ function learningStats(projectRoot) {
|
|
|
20051
21323
|
}
|
|
20052
21324
|
|
|
20053
21325
|
// src/core/memory/index.ts
|
|
21326
|
+
init_brain_retrieval();
|
|
20054
21327
|
function filterManifestEntries(entries, filter) {
|
|
20055
21328
|
let filtered = entries;
|
|
20056
21329
|
if (filter.taskId) {
|
|
@@ -20084,6 +21357,7 @@ function filterManifestEntries(entries, filter) {
|
|
|
20084
21357
|
}
|
|
20085
21358
|
|
|
20086
21359
|
// src/core/memory/engine-compat.ts
|
|
21360
|
+
init_brain_retrieval();
|
|
20087
21361
|
function getManifestPath2(projectRoot) {
|
|
20088
21362
|
return getManifestPath(projectRoot);
|
|
20089
21363
|
}
|
|
@@ -20278,9 +21552,9 @@ function memoryManifestAppend(entry, projectRoot) {
|
|
|
20278
21552
|
return { success: false, error: { code: "E_VALIDATION_FAILED", message: `Invalid manifest entry: ${errors.join(", ")}` } };
|
|
20279
21553
|
}
|
|
20280
21554
|
const manifestPath = getManifestPath2(projectRoot);
|
|
20281
|
-
const dir =
|
|
21555
|
+
const dir = dirname12(manifestPath);
|
|
20282
21556
|
if (!existsSync40(dir)) {
|
|
20283
|
-
|
|
21557
|
+
mkdirSync15(dir, { recursive: true });
|
|
20284
21558
|
}
|
|
20285
21559
|
const serialized = JSON.stringify(entry);
|
|
20286
21560
|
appendFileSync6(manifestPath, serialized + "\n", "utf-8");
|
|
@@ -20299,9 +21573,9 @@ function memoryManifestArchive(beforeDate, projectRoot) {
|
|
|
20299
21573
|
if (toArchive.length === 0) {
|
|
20300
21574
|
return { success: true, data: { archived: 0, remaining: entries.length, message: "No entries found before the specified date" } };
|
|
20301
21575
|
}
|
|
20302
|
-
const archiveDir =
|
|
21576
|
+
const archiveDir = dirname12(archivePath);
|
|
20303
21577
|
if (!existsSync40(archiveDir)) {
|
|
20304
|
-
|
|
21578
|
+
mkdirSync15(archiveDir, { recursive: true });
|
|
20305
21579
|
}
|
|
20306
21580
|
const archiveContent = toArchive.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
20307
21581
|
appendFileSync6(archivePath, archiveContent, "utf-8");
|
|
@@ -20408,7 +21682,7 @@ function memoryInject(protocolType, params, projectRoot) {
|
|
|
20408
21682
|
if (!protocolContent) {
|
|
20409
21683
|
return {
|
|
20410
21684
|
success: false,
|
|
20411
|
-
error: { code: "E_NOT_FOUND", message: `Protocol '${protocolType}' not found in protocols/, skills/_shared/, or agents/cleo-subagent/protocols/` }
|
|
21685
|
+
error: { code: "E_NOT_FOUND", message: `Protocol '${protocolType}' not found in src/protocols/, skills/_shared/, or agents/cleo-subagent/protocols/` }
|
|
20412
21686
|
};
|
|
20413
21687
|
}
|
|
20414
21688
|
return {
|
|
@@ -20478,6 +21752,59 @@ function memoryLearningStats(projectRoot) {
|
|
|
20478
21752
|
return { success: false, error: { code: "E_LEARNING_STATS", message: error instanceof Error ? error.message : String(error) } };
|
|
20479
21753
|
}
|
|
20480
21754
|
}
|
|
21755
|
+
async function memoryBrainSearch(params, projectRoot) {
|
|
21756
|
+
try {
|
|
21757
|
+
const root = resolveRoot(projectRoot);
|
|
21758
|
+
const result = await searchBrainCompact(root, {
|
|
21759
|
+
query: params.query,
|
|
21760
|
+
limit: params.limit,
|
|
21761
|
+
tables: params.tables,
|
|
21762
|
+
dateStart: params.dateStart,
|
|
21763
|
+
dateEnd: params.dateEnd
|
|
21764
|
+
});
|
|
21765
|
+
return { success: true, data: result };
|
|
21766
|
+
} catch (error) {
|
|
21767
|
+
return { success: false, error: { code: "E_BRAIN_SEARCH", message: error instanceof Error ? error.message : String(error) } };
|
|
21768
|
+
}
|
|
21769
|
+
}
|
|
21770
|
+
async function memoryBrainTimeline(params, projectRoot) {
|
|
21771
|
+
try {
|
|
21772
|
+
const root = resolveRoot(projectRoot);
|
|
21773
|
+
const result = await timelineBrain(root, {
|
|
21774
|
+
anchor: params.anchor,
|
|
21775
|
+
depthBefore: params.depthBefore,
|
|
21776
|
+
depthAfter: params.depthAfter
|
|
21777
|
+
});
|
|
21778
|
+
return { success: true, data: result };
|
|
21779
|
+
} catch (error) {
|
|
21780
|
+
return { success: false, error: { code: "E_BRAIN_TIMELINE", message: error instanceof Error ? error.message : String(error) } };
|
|
21781
|
+
}
|
|
21782
|
+
}
|
|
21783
|
+
async function memoryBrainFetch(params, projectRoot) {
|
|
21784
|
+
try {
|
|
21785
|
+
const root = resolveRoot(projectRoot);
|
|
21786
|
+
const result = await fetchBrainEntries(root, { ids: params.ids });
|
|
21787
|
+
return { success: true, data: result };
|
|
21788
|
+
} catch (error) {
|
|
21789
|
+
return { success: false, error: { code: "E_BRAIN_FETCH", message: error instanceof Error ? error.message : String(error) } };
|
|
21790
|
+
}
|
|
21791
|
+
}
|
|
21792
|
+
async function memoryBrainObserve(params, projectRoot) {
|
|
21793
|
+
try {
|
|
21794
|
+
const root = resolveRoot(projectRoot);
|
|
21795
|
+
const result = await observeBrain(root, {
|
|
21796
|
+
text: params.text,
|
|
21797
|
+
title: params.title,
|
|
21798
|
+
type: params.type,
|
|
21799
|
+
project: params.project,
|
|
21800
|
+
sourceSessionId: params.sourceSessionId,
|
|
21801
|
+
sourceType: params.sourceType
|
|
21802
|
+
});
|
|
21803
|
+
return { success: true, data: result };
|
|
21804
|
+
} catch (error) {
|
|
21805
|
+
return { success: false, error: { code: "E_BRAIN_OBSERVE", message: error instanceof Error ? error.message : String(error) } };
|
|
21806
|
+
}
|
|
21807
|
+
}
|
|
20481
21808
|
|
|
20482
21809
|
// src/dispatch/engines/release-engine.ts
|
|
20483
21810
|
init_platform();
|
|
@@ -20486,11 +21813,11 @@ init_data_accessor();
|
|
|
20486
21813
|
// src/core/release/release-manifest.ts
|
|
20487
21814
|
init_json();
|
|
20488
21815
|
init_paths();
|
|
20489
|
-
import { existsSync as existsSync41, mkdirSync as
|
|
21816
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync16 } from "node:fs";
|
|
20490
21817
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
20491
|
-
import { dirname as
|
|
21818
|
+
import { dirname as dirname13, join as join43 } from "node:path";
|
|
20492
21819
|
function getReleasesPath(cwd) {
|
|
20493
|
-
return
|
|
21820
|
+
return join43(getCleoDirAbsolute(cwd), "releases.json");
|
|
20494
21821
|
}
|
|
20495
21822
|
async function readReleases(cwd) {
|
|
20496
21823
|
const data = await readJson(getReleasesPath(cwd));
|
|
@@ -20498,9 +21825,9 @@ async function readReleases(cwd) {
|
|
|
20498
21825
|
}
|
|
20499
21826
|
async function writeReleases(index3, cwd) {
|
|
20500
21827
|
const releasesPath = getReleasesPath(cwd);
|
|
20501
|
-
const dir =
|
|
21828
|
+
const dir = dirname13(releasesPath);
|
|
20502
21829
|
if (!existsSync41(dir)) {
|
|
20503
|
-
|
|
21830
|
+
mkdirSync16(dir, { recursive: true });
|
|
20504
21831
|
}
|
|
20505
21832
|
await saveJson(releasesPath, index3);
|
|
20506
21833
|
}
|
|
@@ -20767,7 +22094,7 @@ async function rollbackRelease(version, reason, cwd) {
|
|
|
20767
22094
|
};
|
|
20768
22095
|
}
|
|
20769
22096
|
async function readPushPolicy(cwd) {
|
|
20770
|
-
const configPath =
|
|
22097
|
+
const configPath = join43(getCleoDirAbsolute(cwd), "config.json");
|
|
20771
22098
|
const config = await readJson(configPath);
|
|
20772
22099
|
if (!config) return void 0;
|
|
20773
22100
|
const release2 = config.release;
|
|
@@ -20983,7 +22310,7 @@ async function releasePush(version, remote, projectRoot, opts) {
|
|
|
20983
22310
|
// src/dispatch/engines/template-parser.ts
|
|
20984
22311
|
init_platform();
|
|
20985
22312
|
import { readFileSync as readFileSync33, readdirSync as readdirSync12, existsSync as existsSync42 } from "fs";
|
|
20986
|
-
import { join as
|
|
22313
|
+
import { join as join44 } from "path";
|
|
20987
22314
|
import { parse as parseYaml } from "yaml";
|
|
20988
22315
|
var SUFFIX_PATTERNS = ["_report", "_request", "_question"];
|
|
20989
22316
|
function deriveSubcommand(filename) {
|
|
@@ -20998,7 +22325,7 @@ function deriveSubcommand(filename) {
|
|
|
20998
22325
|
return firstWord.toLowerCase();
|
|
20999
22326
|
}
|
|
21000
22327
|
function parseTemplateFile(templateDir, filename) {
|
|
21001
|
-
const filePath =
|
|
22328
|
+
const filePath = join44(templateDir, filename);
|
|
21002
22329
|
const raw = readFileSync33(filePath, "utf-8");
|
|
21003
22330
|
const parsed = parseYaml(raw);
|
|
21004
22331
|
const name = typeof parsed.name === "string" ? parsed.name : filename;
|
|
@@ -21048,7 +22375,7 @@ function parseTemplateFile(templateDir, filename) {
|
|
|
21048
22375
|
};
|
|
21049
22376
|
}
|
|
21050
22377
|
function parseIssueTemplates(projectRoot) {
|
|
21051
|
-
const templateDir =
|
|
22378
|
+
const templateDir = join44(projectRoot, ".github", "ISSUE_TEMPLATE");
|
|
21052
22379
|
if (!existsSync42(templateDir)) {
|
|
21053
22380
|
return engineError("E_NOT_FOUND", `Issue template directory not found: ${templateDir}`);
|
|
21054
22381
|
}
|
|
@@ -21654,8 +22981,9 @@ var SessionHandler = class {
|
|
|
21654
22981
|
if (endResult.success && endResult.data) {
|
|
21655
22982
|
const sessionId = endResult.data.sessionId;
|
|
21656
22983
|
if (sessionId) {
|
|
22984
|
+
let debriefResult = null;
|
|
21657
22985
|
try {
|
|
21658
|
-
await sessionComputeDebrief(this.projectRoot, sessionId, {
|
|
22986
|
+
debriefResult = await sessionComputeDebrief(this.projectRoot, sessionId, {
|
|
21659
22987
|
note: params?.note,
|
|
21660
22988
|
nextAction: params?.nextAction
|
|
21661
22989
|
});
|
|
@@ -21668,6 +22996,13 @@ var SessionHandler = class {
|
|
|
21668
22996
|
} catch {
|
|
21669
22997
|
}
|
|
21670
22998
|
}
|
|
22999
|
+
if (debriefResult?.success && debriefResult.data) {
|
|
23000
|
+
try {
|
|
23001
|
+
const { persistSessionMemory: persistSessionMemory2 } = await Promise.resolve().then(() => (init_session_memory(), session_memory_exports));
|
|
23002
|
+
await persistSessionMemory2(this.projectRoot, sessionId, debriefResult.data);
|
|
23003
|
+
} catch {
|
|
23004
|
+
}
|
|
23005
|
+
}
|
|
21671
23006
|
}
|
|
21672
23007
|
unbindSession();
|
|
21673
23008
|
}
|
|
@@ -21956,12 +23291,12 @@ init_logger();
|
|
|
21956
23291
|
|
|
21957
23292
|
// src/core/adrs/validate.ts
|
|
21958
23293
|
import { readFileSync as readFileSync34, readdirSync as readdirSync13, existsSync as existsSync43 } from "node:fs";
|
|
21959
|
-
import { join as
|
|
23294
|
+
import { join as join45 } from "node:path";
|
|
21960
23295
|
import AjvModule3 from "ajv";
|
|
21961
23296
|
var Ajv3 = AjvModule3.default ?? AjvModule3;
|
|
21962
23297
|
async function validateAllAdrs(projectRoot) {
|
|
21963
|
-
const adrsDir =
|
|
21964
|
-
const schemaPath =
|
|
23298
|
+
const adrsDir = join45(projectRoot, ".cleo", "adrs");
|
|
23299
|
+
const schemaPath = join45(projectRoot, "schemas", "adr-frontmatter.schema.json");
|
|
21965
23300
|
if (!existsSync43(schemaPath)) {
|
|
21966
23301
|
return {
|
|
21967
23302
|
valid: false,
|
|
@@ -21975,7 +23310,7 @@ async function validateAllAdrs(projectRoot) {
|
|
|
21975
23310
|
const schema = JSON.parse(readFileSync34(schemaPath, "utf-8"));
|
|
21976
23311
|
const ajv = new Ajv3({ allErrors: true });
|
|
21977
23312
|
const validate = ajv.compile(schema);
|
|
21978
|
-
const files = readdirSync13(adrsDir).filter((f) => f.endsWith(".md") && f.startsWith("ADR-")).map((f) =>
|
|
23313
|
+
const files = readdirSync13(adrsDir).filter((f) => f.endsWith(".md") && f.startsWith("ADR-")).map((f) => join45(adrsDir, f));
|
|
21979
23314
|
const errors = [];
|
|
21980
23315
|
for (const filePath of files) {
|
|
21981
23316
|
const record = parseAdrFile(filePath, projectRoot);
|
|
@@ -21995,14 +23330,14 @@ async function validateAllAdrs(projectRoot) {
|
|
|
21995
23330
|
|
|
21996
23331
|
// src/core/adrs/list.ts
|
|
21997
23332
|
import { readdirSync as readdirSync14, existsSync as existsSync44 } from "node:fs";
|
|
21998
|
-
import { join as
|
|
23333
|
+
import { join as join46 } from "node:path";
|
|
21999
23334
|
async function listAdrs(projectRoot, opts) {
|
|
22000
|
-
const adrsDir =
|
|
23335
|
+
const adrsDir = join46(projectRoot, ".cleo", "adrs");
|
|
22001
23336
|
if (!existsSync44(adrsDir)) {
|
|
22002
23337
|
return { adrs: [], total: 0 };
|
|
22003
23338
|
}
|
|
22004
23339
|
const files = readdirSync14(adrsDir).filter((f) => f.endsWith(".md") && f.startsWith("ADR-")).sort();
|
|
22005
|
-
const records = files.map((f) => parseAdrFile(
|
|
23340
|
+
const records = files.map((f) => parseAdrFile(join46(adrsDir, f), projectRoot));
|
|
22006
23341
|
const filtered = records.filter((r) => {
|
|
22007
23342
|
if (opts?.status && r.frontmatter.Status !== opts.status) return false;
|
|
22008
23343
|
if (opts?.since && r.frontmatter.Date < opts.since) return false;
|
|
@@ -22022,19 +23357,19 @@ async function listAdrs(projectRoot, opts) {
|
|
|
22022
23357
|
|
|
22023
23358
|
// src/core/adrs/show.ts
|
|
22024
23359
|
import { existsSync as existsSync45, readdirSync as readdirSync15 } from "node:fs";
|
|
22025
|
-
import { join as
|
|
23360
|
+
import { join as join47 } from "node:path";
|
|
22026
23361
|
async function showAdr(projectRoot, adrId) {
|
|
22027
|
-
const adrsDir =
|
|
23362
|
+
const adrsDir = join47(projectRoot, ".cleo", "adrs");
|
|
22028
23363
|
if (!existsSync45(adrsDir)) return null;
|
|
22029
23364
|
const files = readdirSync15(adrsDir).filter((f) => f.startsWith(adrId) && f.endsWith(".md"));
|
|
22030
23365
|
if (files.length === 0) return null;
|
|
22031
|
-
const filePath =
|
|
23366
|
+
const filePath = join47(adrsDir, files[0]);
|
|
22032
23367
|
return parseAdrFile(filePath, projectRoot);
|
|
22033
23368
|
}
|
|
22034
23369
|
|
|
22035
23370
|
// src/core/adrs/find.ts
|
|
22036
23371
|
import { readdirSync as readdirSync16, existsSync as existsSync46 } from "node:fs";
|
|
22037
|
-
import { join as
|
|
23372
|
+
import { join as join48 } from "node:path";
|
|
22038
23373
|
function normalise(s) {
|
|
22039
23374
|
return s.toLowerCase().replace(/[^a-z0-9\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
22040
23375
|
}
|
|
@@ -22051,7 +23386,7 @@ function matchedTerms(target, terms) {
|
|
|
22051
23386
|
return terms.filter((term) => t.includes(term));
|
|
22052
23387
|
}
|
|
22053
23388
|
async function findAdrs(projectRoot, query, opts) {
|
|
22054
|
-
const adrsDir =
|
|
23389
|
+
const adrsDir = join48(projectRoot, ".cleo", "adrs");
|
|
22055
23390
|
if (!existsSync46(adrsDir)) {
|
|
22056
23391
|
return { adrs: [], query, total: 0 };
|
|
22057
23392
|
}
|
|
@@ -22061,7 +23396,7 @@ async function findAdrs(projectRoot, query, opts) {
|
|
|
22061
23396
|
const filterKeywords = opts?.keywords ? parseTags(opts.keywords) : null;
|
|
22062
23397
|
const results = [];
|
|
22063
23398
|
for (const file of files) {
|
|
22064
|
-
const record = parseAdrFile(
|
|
23399
|
+
const record = parseAdrFile(join48(adrsDir, file), projectRoot);
|
|
22065
23400
|
const fm = record.frontmatter;
|
|
22066
23401
|
if (opts?.status && fm.Status !== opts.status) continue;
|
|
22067
23402
|
if (filterTopics && filterTopics.length > 0) {
|
|
@@ -22613,6 +23948,47 @@ var MemoryHandler = class {
|
|
|
22613
23948
|
const result = memoryLearningStats(this.projectRoot);
|
|
22614
23949
|
return this.wrapEngineResult(result, "query", "memory", operation, startTime);
|
|
22615
23950
|
}
|
|
23951
|
+
// BRAIN retrieval query operations (T5131-T5135)
|
|
23952
|
+
case "brain.search": {
|
|
23953
|
+
const query = params?.query;
|
|
23954
|
+
if (!query) {
|
|
23955
|
+
return this.errorResponse("query", "memory", operation, "E_INVALID_INPUT", "query is required", startTime);
|
|
23956
|
+
}
|
|
23957
|
+
const result = await memoryBrainSearch(
|
|
23958
|
+
{
|
|
23959
|
+
query,
|
|
23960
|
+
limit: params?.limit,
|
|
23961
|
+
tables: params?.tables,
|
|
23962
|
+
dateStart: params?.dateStart,
|
|
23963
|
+
dateEnd: params?.dateEnd
|
|
23964
|
+
},
|
|
23965
|
+
this.projectRoot
|
|
23966
|
+
);
|
|
23967
|
+
return this.wrapEngineResult(result, "query", "memory", operation, startTime);
|
|
23968
|
+
}
|
|
23969
|
+
case "brain.timeline": {
|
|
23970
|
+
const anchor = params?.anchor;
|
|
23971
|
+
if (!anchor) {
|
|
23972
|
+
return this.errorResponse("query", "memory", operation, "E_INVALID_INPUT", "anchor is required", startTime);
|
|
23973
|
+
}
|
|
23974
|
+
const result = await memoryBrainTimeline(
|
|
23975
|
+
{
|
|
23976
|
+
anchor,
|
|
23977
|
+
depthBefore: params?.depthBefore,
|
|
23978
|
+
depthAfter: params?.depthAfter
|
|
23979
|
+
},
|
|
23980
|
+
this.projectRoot
|
|
23981
|
+
);
|
|
23982
|
+
return this.wrapEngineResult(result, "query", "memory", operation, startTime);
|
|
23983
|
+
}
|
|
23984
|
+
case "brain.fetch": {
|
|
23985
|
+
const ids = params?.ids;
|
|
23986
|
+
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
|
23987
|
+
return this.errorResponse("query", "memory", operation, "E_INVALID_INPUT", "ids is required (non-empty array)", startTime);
|
|
23988
|
+
}
|
|
23989
|
+
const result = await memoryBrainFetch({ ids }, this.projectRoot);
|
|
23990
|
+
return this.wrapEngineResult(result, "query", "memory", operation, startTime);
|
|
23991
|
+
}
|
|
22616
23992
|
default:
|
|
22617
23993
|
return this.unsupported("query", "memory", operation, startTime);
|
|
22618
23994
|
}
|
|
@@ -22705,6 +24081,25 @@ var MemoryHandler = class {
|
|
|
22705
24081
|
);
|
|
22706
24082
|
return this.wrapEngineResult(result, "mutate", "memory", operation, startTime);
|
|
22707
24083
|
}
|
|
24084
|
+
// BRAIN retrieval mutate operations (T5131-T5135)
|
|
24085
|
+
case "brain.observe": {
|
|
24086
|
+
const text3 = params?.text;
|
|
24087
|
+
if (!text3) {
|
|
24088
|
+
return this.errorResponse("mutate", "memory", operation, "E_INVALID_INPUT", "text is required", startTime);
|
|
24089
|
+
}
|
|
24090
|
+
const result = await memoryBrainObserve(
|
|
24091
|
+
{
|
|
24092
|
+
text: text3,
|
|
24093
|
+
title: params?.title,
|
|
24094
|
+
type: params?.type,
|
|
24095
|
+
project: params?.project,
|
|
24096
|
+
sourceSessionId: params?.sourceSessionId,
|
|
24097
|
+
sourceType: params?.sourceType
|
|
24098
|
+
},
|
|
24099
|
+
this.projectRoot
|
|
24100
|
+
);
|
|
24101
|
+
return this.wrapEngineResult(result, "mutate", "memory", operation, startTime);
|
|
24102
|
+
}
|
|
22708
24103
|
default:
|
|
22709
24104
|
return this.unsupported("mutate", "memory", operation, startTime);
|
|
22710
24105
|
}
|
|
@@ -22717,8 +24112,8 @@ var MemoryHandler = class {
|
|
|
22717
24112
|
// -----------------------------------------------------------------------
|
|
22718
24113
|
getSupportedOperations() {
|
|
22719
24114
|
return {
|
|
22720
|
-
query: ["show", "list", "find", "pending", "stats", "manifest.read", "contradictions", "superseded", "pattern.search", "pattern.stats", "learning.search", "learning.stats"],
|
|
22721
|
-
mutate: ["inject", "link", "manifest.append", "manifest.archive", "pattern.store", "learning.store"]
|
|
24115
|
+
query: ["show", "list", "find", "pending", "stats", "manifest.read", "contradictions", "superseded", "pattern.search", "pattern.stats", "learning.search", "learning.stats", "brain.search", "brain.timeline", "brain.fetch"],
|
|
24116
|
+
mutate: ["inject", "link", "manifest.append", "manifest.archive", "pattern.store", "learning.store", "brain.observe"]
|
|
22722
24117
|
};
|
|
22723
24118
|
}
|
|
22724
24119
|
// -----------------------------------------------------------------------
|
|
@@ -23519,7 +24914,7 @@ import { execFileSync as execFileSync6 } from "node:child_process";
|
|
|
23519
24914
|
// src/core/issue/template-parser.ts
|
|
23520
24915
|
init_paths();
|
|
23521
24916
|
import { existsSync as existsSync48, readFileSync as readFileSync35, readdirSync as readdirSync17, writeFileSync as writeFileSync11 } from "node:fs";
|
|
23522
|
-
import { join as
|
|
24917
|
+
import { join as join50, basename as basename8 } from "node:path";
|
|
23523
24918
|
var TEMPLATE_DIR = ".github/ISSUE_TEMPLATE";
|
|
23524
24919
|
var CACHE_FILE = "issue-templates.json";
|
|
23525
24920
|
var SUBCOMMAND_MAP = {
|
|
@@ -23594,12 +24989,12 @@ function parseTemplateFile2(filePath) {
|
|
|
23594
24989
|
}
|
|
23595
24990
|
function parseIssueTemplates2(projectDir) {
|
|
23596
24991
|
const dir = projectDir ?? getProjectRoot();
|
|
23597
|
-
const templateDir =
|
|
24992
|
+
const templateDir = join50(dir, TEMPLATE_DIR);
|
|
23598
24993
|
if (!existsSync48(templateDir)) return [];
|
|
23599
24994
|
const templates = [];
|
|
23600
24995
|
for (const file of readdirSync17(templateDir)) {
|
|
23601
24996
|
if (!file.endsWith(".yml") && !file.endsWith(".yaml")) continue;
|
|
23602
|
-
const template = parseTemplateFile2(
|
|
24997
|
+
const template = parseTemplateFile2(join50(templateDir, file));
|
|
23603
24998
|
if (template) templates.push(template);
|
|
23604
24999
|
}
|
|
23605
25000
|
return templates;
|
|
@@ -23608,7 +25003,7 @@ function getTemplateConfig(cwd) {
|
|
|
23608
25003
|
const projectDir = cwd ?? getProjectRoot();
|
|
23609
25004
|
const liveTemplates = parseIssueTemplates2(projectDir);
|
|
23610
25005
|
if (liveTemplates.length > 0) return liveTemplates;
|
|
23611
|
-
const cachePath =
|
|
25006
|
+
const cachePath = join50(getCleoDir(cwd), CACHE_FILE);
|
|
23612
25007
|
if (existsSync48(cachePath)) {
|
|
23613
25008
|
try {
|
|
23614
25009
|
const cached = JSON.parse(readFileSync35(cachePath, "utf-8"));
|
|
@@ -24418,7 +25813,7 @@ init_logger();
|
|
|
24418
25813
|
// src/core/sharing/index.ts
|
|
24419
25814
|
import { readFile as readFile10, writeFile as writeFile6 } from "node:fs/promises";
|
|
24420
25815
|
import { existsSync as existsSync49, readdirSync as readdirSync18, statSync as statSync9 } from "node:fs";
|
|
24421
|
-
import { join as
|
|
25816
|
+
import { join as join51, relative as relative3 } from "node:path";
|
|
24422
25817
|
init_paths();
|
|
24423
25818
|
var GITIGNORE_START = "# CLEO:SHARING:START - Auto-managed by cleo sharing sync";
|
|
24424
25819
|
var GITIGNORE_END = "# CLEO:SHARING:END";
|
|
@@ -24446,7 +25841,7 @@ function collectCleoFiles(cleoDir) {
|
|
|
24446
25841
|
const entries = readdirSync18(dir);
|
|
24447
25842
|
for (const entry of entries) {
|
|
24448
25843
|
if (entry === ".git") continue;
|
|
24449
|
-
const fullPath =
|
|
25844
|
+
const fullPath = join51(dir, entry);
|
|
24450
25845
|
const relPath = relative3(cleoDir, fullPath);
|
|
24451
25846
|
try {
|
|
24452
25847
|
const stat2 = statSync9(fullPath);
|
|
@@ -24506,7 +25901,7 @@ function generateGitignoreEntries(sharing) {
|
|
|
24506
25901
|
async function syncGitignore(cwd) {
|
|
24507
25902
|
const config = await loadConfig2(cwd);
|
|
24508
25903
|
const projectRoot = getProjectRoot(cwd);
|
|
24509
|
-
const gitignorePath =
|
|
25904
|
+
const gitignorePath = join51(projectRoot, ".gitignore");
|
|
24510
25905
|
const entries = generateGitignoreEntries(config.sharing);
|
|
24511
25906
|
const managedSection = [
|
|
24512
25907
|
"",
|
|
@@ -24539,10 +25934,10 @@ async function syncGitignore(cwd) {
|
|
|
24539
25934
|
// src/core/snapshot/index.ts
|
|
24540
25935
|
init_data_accessor();
|
|
24541
25936
|
init_paths();
|
|
24542
|
-
import { createHash as
|
|
25937
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
24543
25938
|
import { readFile as readFile11, writeFile as writeFile7, mkdir as mkdir10 } from "node:fs/promises";
|
|
24544
25939
|
import { existsSync as existsSync50 } from "node:fs";
|
|
24545
|
-
import { join as
|
|
25940
|
+
import { join as join52, dirname as dirname14 } from "node:path";
|
|
24546
25941
|
var SNAPSHOT_FORMAT_VERSION = "1.0.0";
|
|
24547
25942
|
function toSnapshotTask(task) {
|
|
24548
25943
|
return {
|
|
@@ -24563,7 +25958,7 @@ function toSnapshotTask(task) {
|
|
|
24563
25958
|
};
|
|
24564
25959
|
}
|
|
24565
25960
|
function computeChecksum2(tasks2) {
|
|
24566
|
-
const hash =
|
|
25961
|
+
const hash = createHash7("sha256");
|
|
24567
25962
|
hash.update(JSON.stringify(tasks2));
|
|
24568
25963
|
return hash.digest("hex").slice(0, 16);
|
|
24569
25964
|
}
|
|
@@ -24595,7 +25990,7 @@ async function exportSnapshot(cwd) {
|
|
|
24595
25990
|
};
|
|
24596
25991
|
}
|
|
24597
25992
|
async function writeSnapshot(snapshot, outputPath) {
|
|
24598
|
-
const dir =
|
|
25993
|
+
const dir = dirname14(outputPath);
|
|
24599
25994
|
if (!existsSync50(dir)) {
|
|
24600
25995
|
await mkdir10(dir, { recursive: true });
|
|
24601
25996
|
}
|
|
@@ -24612,7 +26007,7 @@ async function readSnapshot(inputPath) {
|
|
|
24612
26007
|
function getDefaultSnapshotPath(cwd) {
|
|
24613
26008
|
const cleoDir = getCleoDirAbsolute(cwd);
|
|
24614
26009
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
24615
|
-
return
|
|
26010
|
+
return join52(cleoDir, "snapshots", `snapshot-${timestamp}.json`);
|
|
24616
26011
|
}
|
|
24617
26012
|
async function importSnapshot(snapshot, cwd) {
|
|
24618
26013
|
const accessor = await getAccessor(cwd);
|