cortex-agents 4.1.2 → 5.0.0
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/README.md +85 -16
- package/dist/cli.js +146 -13
- package/dist/engine/agents.d.ts +19 -0
- package/dist/engine/agents.d.ts.map +1 -0
- package/dist/engine/agents.js +69 -0
- package/dist/engine/db.d.ts +13 -0
- package/dist/engine/db.d.ts.map +1 -0
- package/dist/engine/db.js +28 -0
- package/dist/engine/index.d.ts +50 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +135 -0
- package/dist/engine/models.d.ts +12 -0
- package/dist/engine/models.d.ts.map +1 -0
- package/dist/engine/models.js +23 -0
- package/dist/engine/renderers/claude.d.ts +18 -0
- package/dist/engine/renderers/claude.d.ts.map +1 -0
- package/dist/engine/renderers/claude.js +226 -0
- package/dist/engine/renderers/codex.d.ts +22 -0
- package/dist/engine/renderers/codex.d.ts.map +1 -0
- package/dist/engine/renderers/codex.js +115 -0
- package/dist/engine/renderers/gemini.d.ts +18 -0
- package/dist/engine/renderers/gemini.d.ts.map +1 -0
- package/dist/engine/renderers/gemini.js +203 -0
- package/dist/engine/renderers/index.d.ts +21 -0
- package/dist/engine/renderers/index.d.ts.map +1 -0
- package/dist/engine/renderers/index.js +13 -0
- package/dist/engine/renderers/opencode.d.ts +18 -0
- package/dist/engine/renderers/opencode.d.ts.map +1 -0
- package/dist/engine/renderers/opencode.js +119 -0
- package/dist/engine/schema.d.ts +13 -0
- package/dist/engine/schema.d.ts.map +1 -0
- package/dist/engine/schema.js +125 -0
- package/dist/engine/seed.d.ts +14 -0
- package/dist/engine/seed.d.ts.map +1 -0
- package/dist/engine/seed.js +398 -0
- package/dist/engine/skills.d.ts +11 -0
- package/dist/engine/skills.d.ts.map +1 -0
- package/dist/engine/skills.js +24 -0
- package/dist/engine/targets.d.ts +17 -0
- package/dist/engine/targets.d.ts.map +1 -0
- package/dist/engine/targets.js +79 -0
- package/dist/engine/types.d.ts +100 -0
- package/dist/engine/types.d.ts.map +1 -0
- package/dist/engine/types.js +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -0
- package/dist/tools/engine.d.ts +22 -0
- package/dist/tools/engine.d.ts.map +1 -0
- package/dist/tools/engine.js +56 -0
- package/dist/utils/cortex-code-bridge.d.ts +21 -0
- package/dist/utils/cortex-code-bridge.d.ts.map +1 -0
- package/dist/utils/cortex-code-bridge.js +104 -0
- package/package.json +4 -2
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// CortexEngine — Facade class
|
|
3
|
+
// Single entry point for all engine operations: DB lifecycle, CRUD, rendering.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { createDatabase, getDefaultDbPath } from "./db.js";
|
|
8
|
+
import { initializeSchema } from "./schema.js";
|
|
9
|
+
import { seedDatabase } from "./seed.js";
|
|
10
|
+
import { AgentStore } from "./agents.js";
|
|
11
|
+
import { SkillStore } from "./skills.js";
|
|
12
|
+
import { ModelStore } from "./models.js";
|
|
13
|
+
import { TargetStore } from "./targets.js";
|
|
14
|
+
import { getRenderer } from "./renderers/index.js";
|
|
15
|
+
// Side-effect imports: register renderers
|
|
16
|
+
import "./renderers/claude.js";
|
|
17
|
+
import "./renderers/opencode.js";
|
|
18
|
+
import "./renderers/codex.js";
|
|
19
|
+
import "./renderers/gemini.js";
|
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
+
const __dirname = path.dirname(__filename);
|
|
22
|
+
/** Path to the .opencode/ directory shipped with the package. */
|
|
23
|
+
const PACKAGE_OPENCODE_DIR = path.resolve(__dirname, "..", "..", ".opencode");
|
|
24
|
+
export class CortexEngine {
|
|
25
|
+
db;
|
|
26
|
+
_agents;
|
|
27
|
+
_skills;
|
|
28
|
+
_models;
|
|
29
|
+
_targets;
|
|
30
|
+
constructor(dbPath) {
|
|
31
|
+
this.db = createDatabase(dbPath ?? getDefaultDbPath());
|
|
32
|
+
this._agents = new AgentStore(this.db);
|
|
33
|
+
this._skills = new SkillStore(this.db);
|
|
34
|
+
this._models = new ModelStore(this.db);
|
|
35
|
+
this._targets = new TargetStore(this.db);
|
|
36
|
+
}
|
|
37
|
+
// ---- Lifecycle -----------------------------------------------------------
|
|
38
|
+
/** Create tables, run migrations, seed if empty. */
|
|
39
|
+
initialize() {
|
|
40
|
+
initializeSchema(this.db);
|
|
41
|
+
// Seed only if agents table is empty (first run)
|
|
42
|
+
const count = this._agents.list().length;
|
|
43
|
+
if (count === 0) {
|
|
44
|
+
return this.seed();
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
/** Re-seed the database from .opencode/ files. */
|
|
49
|
+
seed(opencodeDir) {
|
|
50
|
+
return seedDatabase(this.db, opencodeDir ?? PACKAGE_OPENCODE_DIR);
|
|
51
|
+
}
|
|
52
|
+
/** Close the database connection. */
|
|
53
|
+
close() {
|
|
54
|
+
this.db.close();
|
|
55
|
+
}
|
|
56
|
+
// ---- Agents --------------------------------------------------------------
|
|
57
|
+
getAgent(id) {
|
|
58
|
+
return this._agents.get(id);
|
|
59
|
+
}
|
|
60
|
+
listAgents(filter) {
|
|
61
|
+
return this._agents.list(filter);
|
|
62
|
+
}
|
|
63
|
+
upsertAgent(agent) {
|
|
64
|
+
this._agents.upsert(agent);
|
|
65
|
+
}
|
|
66
|
+
getAgentTools(agentId) {
|
|
67
|
+
return this._agents.getTools(agentId);
|
|
68
|
+
}
|
|
69
|
+
getAgentBashPermissions(agentId) {
|
|
70
|
+
return this._agents.getBashPermissions(agentId);
|
|
71
|
+
}
|
|
72
|
+
// ---- Skills --------------------------------------------------------------
|
|
73
|
+
getSkill(id) {
|
|
74
|
+
return this._skills.get(id);
|
|
75
|
+
}
|
|
76
|
+
listSkills() {
|
|
77
|
+
return this._skills.list();
|
|
78
|
+
}
|
|
79
|
+
getSkillContent(id) {
|
|
80
|
+
return this._skills.getContent(id);
|
|
81
|
+
}
|
|
82
|
+
upsertSkill(skill) {
|
|
83
|
+
this._skills.upsert(skill);
|
|
84
|
+
}
|
|
85
|
+
getAgentSkills(agentId) {
|
|
86
|
+
return this._agents.getSkills(agentId);
|
|
87
|
+
}
|
|
88
|
+
// ---- Targets -------------------------------------------------------------
|
|
89
|
+
getTarget(id) {
|
|
90
|
+
return this._targets.getTarget(id);
|
|
91
|
+
}
|
|
92
|
+
listTargets() {
|
|
93
|
+
return this._targets.listTargets();
|
|
94
|
+
}
|
|
95
|
+
getAgentTargetConfig(agentId, targetId) {
|
|
96
|
+
return this._targets.getAgentTargetConfig(agentId, targetId);
|
|
97
|
+
}
|
|
98
|
+
// ---- Rendering & Sync ----------------------------------------------------
|
|
99
|
+
renderAgent(agentId, targetId) {
|
|
100
|
+
const renderer = getRenderer(targetId, this.db);
|
|
101
|
+
if (!renderer)
|
|
102
|
+
throw new Error(`No renderer for target: ${targetId}`);
|
|
103
|
+
return renderer.renderAgent(agentId);
|
|
104
|
+
}
|
|
105
|
+
renderInstructions(targetId) {
|
|
106
|
+
const renderer = getRenderer(targetId, this.db);
|
|
107
|
+
if (!renderer)
|
|
108
|
+
throw new Error(`No renderer for target: ${targetId}`);
|
|
109
|
+
return renderer.renderInstructions();
|
|
110
|
+
}
|
|
111
|
+
syncTarget(targetId, opts) {
|
|
112
|
+
const renderer = getRenderer(targetId, this.db);
|
|
113
|
+
if (!renderer)
|
|
114
|
+
throw new Error(`No renderer for target: ${targetId}`);
|
|
115
|
+
return renderer.sync(opts);
|
|
116
|
+
}
|
|
117
|
+
// ---- Models --------------------------------------------------------------
|
|
118
|
+
listModels(filter) {
|
|
119
|
+
return this._models.list(filter);
|
|
120
|
+
}
|
|
121
|
+
// ---- Config --------------------------------------------------------------
|
|
122
|
+
getConfig(key) {
|
|
123
|
+
return this._targets.getConfig(key);
|
|
124
|
+
}
|
|
125
|
+
setConfig(key, value) {
|
|
126
|
+
this._targets.setConfig(key, value);
|
|
127
|
+
}
|
|
128
|
+
// ---- Installation tracking -----------------------------------------------
|
|
129
|
+
recordInstallation(targetId, scope, path, version) {
|
|
130
|
+
this._targets.recordInstallation(targetId, scope, path, version);
|
|
131
|
+
}
|
|
132
|
+
getInstallations() {
|
|
133
|
+
return this._targets.getInstallations();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type BetterSqlite3 from "better-sqlite3";
|
|
2
|
+
import type { Model } from "./types.js";
|
|
3
|
+
export declare class ModelStore {
|
|
4
|
+
private db;
|
|
5
|
+
constructor(db: BetterSqlite3.Database);
|
|
6
|
+
get(id: string): Model | null;
|
|
7
|
+
list(filter?: {
|
|
8
|
+
tier?: string;
|
|
9
|
+
}): Model[];
|
|
10
|
+
upsert(model: Model): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/engine/models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,qBAAa,UAAU;IACT,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,aAAa,CAAC,QAAQ;IAE9C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAK7B,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,KAAK,EAAE;IAazC,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAO3B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class ModelStore {
|
|
2
|
+
db;
|
|
3
|
+
constructor(db) {
|
|
4
|
+
this.db = db;
|
|
5
|
+
}
|
|
6
|
+
get(id) {
|
|
7
|
+
const stmt = this.db.prepare("SELECT * FROM models WHERE id = ?");
|
|
8
|
+
return stmt.get(id) ?? null;
|
|
9
|
+
}
|
|
10
|
+
list(filter) {
|
|
11
|
+
if (filter?.tier) {
|
|
12
|
+
const stmt = this.db.prepare("SELECT * FROM models WHERE tier = ? ORDER BY provider, name");
|
|
13
|
+
return stmt.all(filter.tier);
|
|
14
|
+
}
|
|
15
|
+
const stmt = this.db.prepare("SELECT * FROM models ORDER BY provider, name");
|
|
16
|
+
return stmt.all();
|
|
17
|
+
}
|
|
18
|
+
upsert(model) {
|
|
19
|
+
const stmt = this.db.prepare(`INSERT OR REPLACE INTO models (id, name, provider, tier, description)
|
|
20
|
+
VALUES (?, ?, ?, ?, ?)`);
|
|
21
|
+
stmt.run(model.id, model.name, model.provider, model.tier, model.description);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type BetterSqlite3 from "better-sqlite3";
|
|
2
|
+
import type { Renderer } from "./index.js";
|
|
3
|
+
import type { SyncResult } from "../types.js";
|
|
4
|
+
declare class ClaudeRenderer implements Renderer {
|
|
5
|
+
private db;
|
|
6
|
+
private agents;
|
|
7
|
+
private skills;
|
|
8
|
+
private targets;
|
|
9
|
+
constructor(db: BetterSqlite3.Database);
|
|
10
|
+
renderAgent(agentId: string): string;
|
|
11
|
+
renderInstructions(): string;
|
|
12
|
+
sync(opts?: {
|
|
13
|
+
scope?: string;
|
|
14
|
+
projectPath?: string;
|
|
15
|
+
}): SyncResult;
|
|
16
|
+
}
|
|
17
|
+
export { ClaudeRenderer };
|
|
18
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../../src/engine/renderers/claude.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA2E9C,cAAM,cAAe,YAAW,QAAQ;IAK1B,OAAO,CAAC,EAAE;IAJtB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAc;gBAET,EAAE,EAAE,aAAa,CAAC,QAAQ;IAQ9C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IA4EpC,kBAAkB,IAAI,MAAM;IA0C5B,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU;CA4ClE;AAKD,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Cortex Engine — Claude Code renderer
|
|
3
|
+
// Produces ~/.claude/agents/*.md files (YAML frontmatter + system prompt)
|
|
4
|
+
// and a CLAUDE.md instructions file.
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import * as os from "os";
|
|
9
|
+
import { AgentStore } from "../agents.js";
|
|
10
|
+
import { SkillStore } from "../skills.js";
|
|
11
|
+
import { TargetStore } from "../targets.js";
|
|
12
|
+
import { registerRenderer } from "./index.js";
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Tool-name mapping: OpenCode name -> Claude PascalCase name
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const NATIVE_TOOL_MAP = {
|
|
17
|
+
read: "Read",
|
|
18
|
+
write: "Write",
|
|
19
|
+
edit: "Edit",
|
|
20
|
+
bash: "Bash",
|
|
21
|
+
glob: "Glob",
|
|
22
|
+
grep: "Grep",
|
|
23
|
+
skill: "Skill",
|
|
24
|
+
task: "Agent",
|
|
25
|
+
};
|
|
26
|
+
const NATIVE_TOOL_NAMES = new Set(Object.keys(NATIVE_TOOL_MAP));
|
|
27
|
+
/**
|
|
28
|
+
* Map an OpenCode tool name to its Claude representation.
|
|
29
|
+
*
|
|
30
|
+
* - Native tools (read, write, ...) become PascalCase (Read, Write, ...).
|
|
31
|
+
* - The special `task` tool maps to `Agent`.
|
|
32
|
+
* - Everything else is a Cortex MCP tool: `mcp__cortex-agents__{name}`.
|
|
33
|
+
*/
|
|
34
|
+
function mapToolName(toolName) {
|
|
35
|
+
if (NATIVE_TOOL_NAMES.has(toolName)) {
|
|
36
|
+
return NATIVE_TOOL_MAP[toolName];
|
|
37
|
+
}
|
|
38
|
+
return `mcp__cortex-agents__${toolName}`;
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// YAML helpers — lightweight, no external dep
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/** Escape a YAML string value. Wraps in quotes when necessary. */
|
|
44
|
+
function yamlValue(v) {
|
|
45
|
+
// If it contains characters that could confuse a YAML parser, quote it.
|
|
46
|
+
if (v === "" ||
|
|
47
|
+
v.includes(":") ||
|
|
48
|
+
v.includes("#") ||
|
|
49
|
+
v.includes("{") ||
|
|
50
|
+
v.includes("}") ||
|
|
51
|
+
v.includes("[") ||
|
|
52
|
+
v.includes("]") ||
|
|
53
|
+
v.includes(",") ||
|
|
54
|
+
v.includes("&") ||
|
|
55
|
+
v.includes("*") ||
|
|
56
|
+
v.includes("!") ||
|
|
57
|
+
v.includes("|") ||
|
|
58
|
+
v.includes(">") ||
|
|
59
|
+
v.includes("'") ||
|
|
60
|
+
v.includes('"') ||
|
|
61
|
+
v.includes("%") ||
|
|
62
|
+
v.includes("@") ||
|
|
63
|
+
v.includes("`") ||
|
|
64
|
+
v.startsWith(" ") ||
|
|
65
|
+
v.endsWith(" ")) {
|
|
66
|
+
return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
67
|
+
}
|
|
68
|
+
return v;
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// ClaudeRenderer
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
class ClaudeRenderer {
|
|
74
|
+
db;
|
|
75
|
+
agents;
|
|
76
|
+
skills;
|
|
77
|
+
targets;
|
|
78
|
+
constructor(db) {
|
|
79
|
+
this.db = db;
|
|
80
|
+
this.agents = new AgentStore(db);
|
|
81
|
+
this.skills = new SkillStore(db);
|
|
82
|
+
this.targets = new TargetStore(db);
|
|
83
|
+
}
|
|
84
|
+
// ---- renderAgent ----------------------------------------------------------
|
|
85
|
+
renderAgent(agentId) {
|
|
86
|
+
const agent = this.agents.get(agentId);
|
|
87
|
+
if (!agent)
|
|
88
|
+
throw new Error(`Agent not found: ${agentId}`);
|
|
89
|
+
const targetConfig = this.targets.getAgentTargetConfig(agentId, "claude");
|
|
90
|
+
const agentTools = this.agents.getTools(agentId);
|
|
91
|
+
// ----- Determine tools and disallowedTools lists -----
|
|
92
|
+
let toolsList;
|
|
93
|
+
let disallowedList;
|
|
94
|
+
if (targetConfig?.tools_override) {
|
|
95
|
+
// Explicit override from the agent_target_config table — use as-is.
|
|
96
|
+
toolsList = targetConfig.tools_override;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Derive from agent_tools: every tool where allowed = true.
|
|
100
|
+
toolsList = agentTools
|
|
101
|
+
.filter((t) => t.allowed)
|
|
102
|
+
.map((t) => mapToolName(t.tool_name));
|
|
103
|
+
}
|
|
104
|
+
if (targetConfig?.disallowed_tools) {
|
|
105
|
+
disallowedList = targetConfig.disallowed_tools;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// Derive from agent_tools: every tool where allowed = false,
|
|
109
|
+
// but only native tools make sense in disallowedTools.
|
|
110
|
+
disallowedList = agentTools
|
|
111
|
+
.filter((t) => !t.allowed && NATIVE_TOOL_NAMES.has(t.tool_name))
|
|
112
|
+
.map((t) => NATIVE_TOOL_MAP[t.tool_name]);
|
|
113
|
+
}
|
|
114
|
+
// ----- Model -----
|
|
115
|
+
const model = targetConfig?.model_override ?? "inherit";
|
|
116
|
+
// ----- Description -----
|
|
117
|
+
const description = targetConfig?.native_name ?? agent.description;
|
|
118
|
+
// ----- Build frontmatter -----
|
|
119
|
+
const lines = ["---"];
|
|
120
|
+
lines.push(`name: ${yamlValue(agentId)}`);
|
|
121
|
+
lines.push(`description: ${yamlValue(description)}`);
|
|
122
|
+
if (toolsList.length > 0) {
|
|
123
|
+
lines.push(`tools: ${toolsList.map(yamlValue).join(", ")}`);
|
|
124
|
+
}
|
|
125
|
+
if (disallowedList.length > 0) {
|
|
126
|
+
lines.push(`disallowedTools: ${disallowedList.map(yamlValue).join(", ")}`);
|
|
127
|
+
}
|
|
128
|
+
lines.push(`model: ${yamlValue(model)}`);
|
|
129
|
+
// Extra frontmatter from target config (arbitrary keys).
|
|
130
|
+
// Seed stores mcpServers here; fall back to default if absent.
|
|
131
|
+
const extra = targetConfig?.extra_frontmatter ?? {};
|
|
132
|
+
if (!("mcpServers" in extra)) {
|
|
133
|
+
lines.push("mcpServers: cortex-agents");
|
|
134
|
+
}
|
|
135
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
136
|
+
lines.push(`${key}: ${yamlValue(String(value))}`);
|
|
137
|
+
}
|
|
138
|
+
lines.push("---");
|
|
139
|
+
// ----- System prompt body -----
|
|
140
|
+
return lines.join("\n") + "\n" + agent.system_prompt;
|
|
141
|
+
}
|
|
142
|
+
// ---- renderInstructions ---------------------------------------------------
|
|
143
|
+
renderInstructions() {
|
|
144
|
+
const skills = this.skills.list();
|
|
145
|
+
const agents = this.agents.list();
|
|
146
|
+
const subagents = agents.filter((a) => a.mode === "subagent");
|
|
147
|
+
return `# Cortex Agents — Global Configuration
|
|
148
|
+
|
|
149
|
+
> Auto-generated by \`npx cortex-agents install --target claude --global\`. Do not edit manually.
|
|
150
|
+
|
|
151
|
+
## Overview
|
|
152
|
+
|
|
153
|
+
Cortex Agents provides structured development workflows: plan \u2192 build \u2192 quality gate \u2192 ship.
|
|
154
|
+
All 33 tools are available via MCP server (\`npx cortex-agents mcp\`).
|
|
155
|
+
|
|
156
|
+
## Default Workflow
|
|
157
|
+
|
|
158
|
+
When starting a new task or session, always default to the \`/architect\` workflow first to plan the work before implementing. Only skip planning for trivial changes (typo fixes, single-line edits).
|
|
159
|
+
|
|
160
|
+
1. **Plan** \u2014 Use \`/architect\` to analyze requirements and create an implementation plan
|
|
161
|
+
2. **Implement** \u2014 Use \`/implement\` to execute the plan with iterative build+test verification
|
|
162
|
+
3. **Fix** \u2014 Use \`/fix\` for quick bug fixes with minimal changes
|
|
163
|
+
|
|
164
|
+
## Available Skills
|
|
165
|
+
|
|
166
|
+
${skills.map((s) => ` - ${s.id}`).join("\n")}
|
|
167
|
+
|
|
168
|
+
## Custom Agents (available in /agents)
|
|
169
|
+
|
|
170
|
+
${subagents.map((a) => a.id).join(", ")}
|
|
171
|
+
|
|
172
|
+
## Quality Gate
|
|
173
|
+
|
|
174
|
+
After implementation, assess change scope and launch parallel Agent tool calls:
|
|
175
|
+
- **Trivial** (docs only): Skip quality gate
|
|
176
|
+
- **Low** (tests/config): Testing agent only
|
|
177
|
+
- **Standard** (normal code): Testing + Security + Audit + Docs agents
|
|
178
|
+
- **High** (auth/payments/infra): All agents including Perf and DevOps
|
|
179
|
+
`;
|
|
180
|
+
}
|
|
181
|
+
// ---- sync -----------------------------------------------------------------
|
|
182
|
+
sync(opts) {
|
|
183
|
+
const target = this.targets.getTarget("claude");
|
|
184
|
+
if (!target)
|
|
185
|
+
throw new Error("Claude target not configured");
|
|
186
|
+
const configDir = target.config_dir.replace("~", os.homedir());
|
|
187
|
+
const agentsDir = path.join(configDir, "agents");
|
|
188
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
189
|
+
const result = {
|
|
190
|
+
target: "claude",
|
|
191
|
+
agentsWritten: [],
|
|
192
|
+
skillsWritten: [],
|
|
193
|
+
instructionsWritten: false,
|
|
194
|
+
errors: [],
|
|
195
|
+
};
|
|
196
|
+
// Render each agent
|
|
197
|
+
const agents = this.agents.list();
|
|
198
|
+
for (const agent of agents) {
|
|
199
|
+
try {
|
|
200
|
+
const content = this.renderAgent(agent.id);
|
|
201
|
+
const filePath = path.join(agentsDir, `${agent.id}.md`);
|
|
202
|
+
fs.writeFileSync(filePath, content);
|
|
203
|
+
result.agentsWritten.push(agent.id);
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
result.errors.push(`Agent ${agent.id}: ${err.message}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Render instructions file
|
|
210
|
+
if (target.instructions_file) {
|
|
211
|
+
try {
|
|
212
|
+
const content = this.renderInstructions();
|
|
213
|
+
const filePath = path.join(configDir, target.instructions_file);
|
|
214
|
+
fs.writeFileSync(filePath, content);
|
|
215
|
+
result.instructionsWritten = true;
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
result.errors.push(`Instructions: ${err.message}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Self-register on import.
|
|
225
|
+
registerRenderer("claude", (db) => new ClaudeRenderer(db));
|
|
226
|
+
export { ClaudeRenderer };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type BetterSqlite3 from "better-sqlite3";
|
|
2
|
+
import type { Renderer } from "./index.js";
|
|
3
|
+
import type { SyncResult } from "../types.js";
|
|
4
|
+
declare class CodexRenderer implements Renderer {
|
|
5
|
+
private db;
|
|
6
|
+
private agents;
|
|
7
|
+
private skills;
|
|
8
|
+
private targets;
|
|
9
|
+
constructor(db: BetterSqlite3.Database);
|
|
10
|
+
/**
|
|
11
|
+
* Codex doesn't use per-agent .md files (agents are configured in TOML).
|
|
12
|
+
* Returns the agent's system prompt as plain text for API consumers.
|
|
13
|
+
*/
|
|
14
|
+
renderAgent(agentId: string): string;
|
|
15
|
+
renderInstructions(): string;
|
|
16
|
+
sync(opts?: {
|
|
17
|
+
scope?: string;
|
|
18
|
+
projectPath?: string;
|
|
19
|
+
}): SyncResult;
|
|
20
|
+
}
|
|
21
|
+
export { CodexRenderer };
|
|
22
|
+
//# sourceMappingURL=codex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../../src/engine/renderers/codex.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAU9C,cAAM,aAAc,YAAW,QAAQ;IAKzB,OAAO,CAAC,EAAE;IAJtB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAc;gBAET,EAAE,EAAE,aAAa,CAAC,QAAQ;IAQ9C;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAQpC,kBAAkB,IAAI,MAAM;IA+C5B,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU;CAgClE;AAKD,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Cortex Engine — Codex CLI renderer
|
|
3
|
+
// Produces ~/.codex/agents/AGENTS.md instructions file.
|
|
4
|
+
// Codex agents are configured via TOML (user-specific), so we only render
|
|
5
|
+
// the instructions markdown file here.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import * as os from "os";
|
|
10
|
+
import { AgentStore } from "../agents.js";
|
|
11
|
+
import { SkillStore } from "../skills.js";
|
|
12
|
+
import { TargetStore } from "../targets.js";
|
|
13
|
+
import { registerRenderer } from "./index.js";
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// CodexRenderer
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
class CodexRenderer {
|
|
18
|
+
db;
|
|
19
|
+
agents;
|
|
20
|
+
skills;
|
|
21
|
+
targets;
|
|
22
|
+
constructor(db) {
|
|
23
|
+
this.db = db;
|
|
24
|
+
this.agents = new AgentStore(db);
|
|
25
|
+
this.skills = new SkillStore(db);
|
|
26
|
+
this.targets = new TargetStore(db);
|
|
27
|
+
}
|
|
28
|
+
// ---- renderAgent ----------------------------------------------------------
|
|
29
|
+
/**
|
|
30
|
+
* Codex doesn't use per-agent .md files (agents are configured in TOML).
|
|
31
|
+
* Returns the agent's system prompt as plain text for API consumers.
|
|
32
|
+
*/
|
|
33
|
+
renderAgent(agentId) {
|
|
34
|
+
const agent = this.agents.get(agentId);
|
|
35
|
+
if (!agent)
|
|
36
|
+
throw new Error(`Agent not found: ${agentId}`);
|
|
37
|
+
return agent.system_prompt;
|
|
38
|
+
}
|
|
39
|
+
// ---- renderInstructions ---------------------------------------------------
|
|
40
|
+
renderInstructions() {
|
|
41
|
+
const skills = this.skills.list();
|
|
42
|
+
const agents = this.agents.list();
|
|
43
|
+
const subagents = agents.filter((a) => a.mode === "subagent");
|
|
44
|
+
const agentList = agents
|
|
45
|
+
.map((a) => `- **${a.id}**: ${a.description}`)
|
|
46
|
+
.join("\n");
|
|
47
|
+
return `# Cortex Agents — Project Instructions
|
|
48
|
+
|
|
49
|
+
> Auto-generated by \`npx cortex-agents install --target codex\`. Do not edit manually.
|
|
50
|
+
|
|
51
|
+
## Overview
|
|
52
|
+
|
|
53
|
+
Cortex Agents provides structured development workflows: plan \u2192 build \u2192 quality gate \u2192 ship.
|
|
54
|
+
|
|
55
|
+
## Default Workflow
|
|
56
|
+
|
|
57
|
+
1. **Plan** \u2014 Analyze requirements and create an implementation plan
|
|
58
|
+
2. **Implement** \u2014 Execute the plan with iterative build+test verification
|
|
59
|
+
3. **Fix** \u2014 Quick bug fixes with minimal changes
|
|
60
|
+
|
|
61
|
+
## Available Agents
|
|
62
|
+
|
|
63
|
+
${agentList}
|
|
64
|
+
|
|
65
|
+
## Available Skills
|
|
66
|
+
|
|
67
|
+
${skills.map((s) => ` - ${s.id}`).join("\n")}
|
|
68
|
+
|
|
69
|
+
## Custom Agents
|
|
70
|
+
|
|
71
|
+
${subagents.map((a) => a.id).join(", ")}
|
|
72
|
+
|
|
73
|
+
## Quality Gate
|
|
74
|
+
|
|
75
|
+
After implementation, assess change scope and launch parallel tool calls:
|
|
76
|
+
- **Trivial** (docs only): Skip quality gate
|
|
77
|
+
- **Low** (tests/config): Testing agent only
|
|
78
|
+
- **Standard** (normal code): Testing + Security + Audit + Docs agents
|
|
79
|
+
- **High** (auth/payments/infra): All agents including Perf and DevOps
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
// ---- sync -----------------------------------------------------------------
|
|
83
|
+
sync(opts) {
|
|
84
|
+
const target = this.targets.getTarget("codex");
|
|
85
|
+
if (!target)
|
|
86
|
+
throw new Error("Codex target not configured");
|
|
87
|
+
const configDir = target.config_dir.replace("~", os.homedir());
|
|
88
|
+
const agentsDir = path.join(configDir, "agents");
|
|
89
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
90
|
+
const result = {
|
|
91
|
+
target: "codex",
|
|
92
|
+
agentsWritten: [],
|
|
93
|
+
skillsWritten: [],
|
|
94
|
+
instructionsWritten: false,
|
|
95
|
+
errors: [],
|
|
96
|
+
};
|
|
97
|
+
// Render instructions file (agents/AGENTS.md)
|
|
98
|
+
if (target.instructions_file) {
|
|
99
|
+
try {
|
|
100
|
+
const content = this.renderInstructions();
|
|
101
|
+
const filePath = path.join(configDir, target.instructions_file);
|
|
102
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
103
|
+
fs.writeFileSync(filePath, content);
|
|
104
|
+
result.instructionsWritten = true;
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
result.errors.push(`Instructions: ${err.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Self-register on import.
|
|
114
|
+
registerRenderer("codex", (db) => new CodexRenderer(db));
|
|
115
|
+
export { CodexRenderer };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type BetterSqlite3 from "better-sqlite3";
|
|
2
|
+
import type { Renderer } from "./index.js";
|
|
3
|
+
import type { SyncResult } from "../types.js";
|
|
4
|
+
declare class GeminiRenderer implements Renderer {
|
|
5
|
+
private db;
|
|
6
|
+
private agents;
|
|
7
|
+
private skills;
|
|
8
|
+
private targets;
|
|
9
|
+
constructor(db: BetterSqlite3.Database);
|
|
10
|
+
renderAgent(agentId: string): string;
|
|
11
|
+
renderInstructions(): string;
|
|
12
|
+
sync(opts?: {
|
|
13
|
+
scope?: string;
|
|
14
|
+
projectPath?: string;
|
|
15
|
+
}): SyncResult;
|
|
16
|
+
}
|
|
17
|
+
export { GeminiRenderer };
|
|
18
|
+
//# sourceMappingURL=gemini.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../../src/engine/renderers/gemini.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAuE9C,cAAM,cAAe,YAAW,QAAQ;IAK1B,OAAO,CAAC,EAAE;IAJtB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAc;gBAET,EAAE,EAAE,aAAa,CAAC,QAAQ;IAQ9C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAoDpC,kBAAkB,IAAI,MAAM;IA0C5B,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU;CA4ClE;AAKD,OAAO,EAAE,cAAc,EAAE,CAAC"}
|