@tacuchi/agent-workflow-cli 25.6.0 → 25.7.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/CHANGELOG.md +4368 -0
- package/README.md +1 -1
- package/dist/adapters/git-cli.js +74 -6
- package/dist/adapters/git-cli.js.map +1 -1
- package/dist/adapters/node-file-system.js +39 -2
- package/dist/adapters/node-file-system.js.map +1 -1
- package/dist/application/branch-resolver.js +34 -1
- package/dist/application/branch-resolver.js.map +1 -1
- package/dist/application/checkpoint-write-service.js +161 -39
- package/dist/application/checkpoint-write-service.js.map +1 -1
- package/dist/application/dates.js +12 -0
- package/dist/application/dates.js.map +1 -1
- package/dist/application/fix-git-service.js +83 -13
- package/dist/application/fix-git-service.js.map +1 -1
- package/dist/application/flow/advance.js +24 -3
- package/dist/application/flow/advance.js.map +1 -1
- package/dist/application/flow/annul-service.js +159 -0
- package/dist/application/flow/annul-service.js.map +1 -0
- package/dist/application/flow/flow-service.js +212 -49
- package/dist/application/flow/flow-service.js.map +1 -1
- package/dist/application/flow/internal-actions.js +23 -3
- package/dist/application/flow/internal-actions.js.map +1 -1
- package/dist/application/flow/internal-drive.js +51 -19
- package/dist/application/flow/internal-drive.js.map +1 -1
- package/dist/application/flow/run-projection.js +21 -5
- package/dist/application/flow/run-projection.js.map +1 -1
- package/dist/application/flow/run-state-service.js +108 -35
- package/dist/application/flow/run-state-service.js.map +1 -1
- package/dist/application/flow/submit.js +63 -144
- package/dist/application/flow/submit.js.map +1 -1
- package/dist/application/git-flow-service.js +325 -72
- package/dist/application/git-flow-service.js.map +1 -1
- package/dist/application/hook-sql-mutation-guard.js +155 -27
- package/dist/application/hook-sql-mutation-guard.js.map +1 -1
- package/dist/application/host-memory/claude-code.js +65 -0
- package/dist/application/host-memory/claude-code.js.map +1 -0
- package/dist/application/host-memory/codex.js +225 -0
- package/dist/application/host-memory/codex.js.map +1 -0
- package/dist/application/host-memory/destination.js +52 -0
- package/dist/application/host-memory/destination.js.map +1 -0
- package/dist/application/host-memory/reader.js +9 -0
- package/dist/application/host-memory/reader.js.map +1 -0
- package/dist/application/host-memory/report.js +136 -0
- package/dist/application/host-memory/report.js.map +1 -0
- package/dist/application/lifecycle-target.js +3 -1
- package/dist/application/lifecycle-target.js.map +1 -1
- package/dist/application/local-proposal.js +13 -3
- package/dist/application/local-proposal.js.map +1 -1
- package/dist/application/logging/log-events.js +22 -0
- package/dist/application/logging/log-events.js.map +1 -1
- package/dist/application/parsers/spec-relation.js +20 -7
- package/dist/application/parsers/spec-relation.js.map +1 -1
- package/dist/application/persist-service.js +45 -1
- package/dist/application/persist-service.js.map +1 -1
- package/dist/application/plan-exec-batch-service.js +47 -2
- package/dist/application/plan-exec-batch-service.js.map +1 -1
- package/dist/application/plan-lineage-seal.js +93 -0
- package/dist/application/plan-lineage-seal.js.map +1 -0
- package/dist/application/plan-lint-service.js +153 -0
- package/dist/application/plan-lint-service.js.map +1 -0
- package/dist/application/prod-consent.js +75 -0
- package/dist/application/prod-consent.js.map +1 -0
- package/dist/application/reseal-service.js +9 -3
- package/dist/application/reseal-service.js.map +1 -1
- package/dist/application/self/install-skill.js +5 -1
- package/dist/application/self/install-skill.js.map +1 -1
- package/dist/application/self/update-self.js +204 -8
- package/dist/application/self/update-self.js.map +1 -1
- package/dist/application/session-create-service.js +49 -0
- package/dist/application/session-create-service.js.map +1 -1
- package/dist/application/session-custody-recorder.js +4 -0
- package/dist/application/session-custody-recorder.js.map +1 -1
- package/dist/application/session-narrative.js +27 -0
- package/dist/application/session-narrative.js.map +1 -1
- package/dist/application/session-resolver.js +28 -9
- package/dist/application/session-resolver.js.map +1 -1
- package/dist/application/source-boundary-policy.js +168 -34
- package/dist/application/source-boundary-policy.js.map +1 -1
- package/dist/application/working-branch-service.js +68 -0
- package/dist/application/working-branch-service.js.map +1 -0
- package/dist/application/workline-graph.js +7 -2
- package/dist/application/workline-graph.js.map +1 -1
- package/dist/cli/commands/checkpoint-write.js +18 -8
- package/dist/cli/commands/checkpoint-write.js.map +1 -1
- package/dist/cli/commands/fix-git.js +45 -6
- package/dist/cli/commands/fix-git.js.map +1 -1
- package/dist/cli/commands/flow.js +50 -5
- package/dist/cli/commands/flow.js.map +1 -1
- package/dist/cli/commands/git-flow.js +103 -29
- package/dist/cli/commands/git-flow.js.map +1 -1
- package/dist/cli/commands/host-memory.js +33 -0
- package/dist/cli/commands/host-memory.js.map +1 -0
- package/dist/cli/commands/index.js +6 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/persist.js +5 -0
- package/dist/cli/commands/persist.js.map +1 -1
- package/dist/cli/commands/plan.js +50 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/resume-summary.js +4 -2
- package/dist/cli/commands/resume-summary.js.map +1 -1
- package/dist/cli/commands/set-branch.js +40 -6
- package/dist/cli/commands/set-branch.js.map +1 -1
- package/dist/cli/help-groups.js +6 -0
- package/dist/cli/help-groups.js.map +1 -1
- package/dist/cli/main.js +6 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/parser.js +20 -1
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/tui/components/git-flow-actions.js +65 -20
- package/dist/cli/tui/components/git-flow-actions.js.map +1 -1
- package/dist/cli/tui/tabs/project-tab.js +101 -12
- package/dist/cli/tui/tabs/project-tab.js.map +1 -1
- package/dist/domain/changelog-contract.js +172 -0
- package/dist/domain/changelog-contract.js.map +1 -0
- package/dist/domain/database-tools.js +1 -189
- package/dist/domain/database-tools.js.map +1 -1
- package/dist/domain/flow/answer.js +3 -0
- package/dist/domain/flow/answer.js.map +1 -1
- package/dist/domain/flow/authority.js +12 -0
- package/dist/domain/flow/authority.js.map +1 -1
- package/dist/domain/flow/journey-baseline.js +131 -0
- package/dist/domain/flow/journey-baseline.js.map +1 -0
- package/dist/domain/flow/run-state.js +257 -62
- package/dist/domain/flow/run-state.js.map +1 -1
- package/dist/domain/host-memory/model.js +2 -0
- package/dist/domain/host-memory/model.js.map +1 -0
- package/dist/domain/host-memory/provenance.js +43 -0
- package/dist/domain/host-memory/provenance.js.map +1 -0
- package/dist/domain/host-memory/topic.js +26 -0
- package/dist/domain/host-memory/topic.js.map +1 -0
- package/dist/domain/lineage.js +11 -3
- package/dist/domain/lineage.js.map +1 -1
- package/dist/domain/proposal.js +7 -0
- package/dist/domain/proposal.js.map +1 -1
- package/dist/domain/session/custody.js.map +1 -1
- package/dist/domain/sql-lexer.js +227 -0
- package/dist/domain/sql-lexer.js.map +1 -0
- package/package.json +2 -2
- package/skills/w/SKILL.md +9 -9
- package/skills/w/commands/README.md +2 -1
- package/skills/w/commands/recall.md +39 -0
- package/skills/w/context/MANIFEST.json +4 -0
- package/skills/w/harness/HARNESS.md +9 -5
- package/skills/w/hooks/README.md +27 -16
- package/skills/w/loops/CHASSIS.md +16 -12
- package/skills/w/loops/CODE-POLICIES.md +11 -6
- package/skills/w/loops/plan-exec-loop/LOOP.md +9 -9
- package/skills/w/modules/COMPACTION.md +1 -1
|
@@ -1,20 +1,26 @@
|
|
|
1
|
+
// Patterns and display name are read from the runtime config (Phase 3 agnostic CLI).
|
|
2
|
+
import { scanSql } from "../domain/sql-lexer.js";
|
|
1
3
|
import { parseHookPayload } from "./hook-common.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
4
|
+
// The spec's closed list of reads (S051/AC-12): anything else is blocked, even
|
|
5
|
+
// without a mutation keyword, because a mutation list lets through what it omits.
|
|
6
|
+
const READ_STATEMENTS = new Set(["SELECT", "VALUES", "TABLE", "SHOW"]);
|
|
7
|
+
const EXPLAIN_LEGACY_OPTIONS = new Set(["ANALYZE", "ANALYSE", "VERBOSE"]);
|
|
8
|
+
const STATEMENT_DISPLAY_CHARS = 120;
|
|
9
|
+
const REASONS = {
|
|
10
|
+
undelimited: "el SQL no se puede delimitar: hay un literal, un identificador o un comentario sin cerrar",
|
|
11
|
+
into: "lleva INTO: SELECT … INTO crea una tabla, no la lee",
|
|
12
|
+
noRead: "no empieza con una lectura",
|
|
13
|
+
withShape: "el WITH no tiene la forma nombre AS (…)",
|
|
14
|
+
explainShape: "las opciones de EXPLAIN no cierran su paréntesis",
|
|
15
|
+
};
|
|
16
|
+
// PostgreSQL reads these differently than MySQL; an execute_sql tool may talk
|
|
17
|
+
// to either, and the other reading could hide a second statement.
|
|
18
|
+
const MARK_REASONS = {
|
|
19
|
+
hash: "tiene un # fuera de un literal, que otro motor lee como comentario",
|
|
20
|
+
backtick: "tiene un backtick fuera de un literal, que otro motor lee como identificador",
|
|
21
|
+
"backslash-quote": "tiene una \\ antes de una comilla, que otro motor lee como escape y cierra el literal en otro lugar",
|
|
22
|
+
"executable-comment": "tiene un comentario /*! … */, que MySQL ejecuta como SQL",
|
|
23
|
+
};
|
|
18
24
|
export function runSqlMutationGuard(input) {
|
|
19
25
|
const patterns = input.runtime.mcpGuards?.sqlMutation;
|
|
20
26
|
if (!patterns) {
|
|
@@ -41,11 +47,11 @@ export function runSqlMutationGuard(input) {
|
|
|
41
47
|
const sql = extractSql(payload.tool_input);
|
|
42
48
|
if (!sql)
|
|
43
49
|
return { exitCode: 0 };
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
50
|
+
const blocked = findNonRead(sql);
|
|
51
|
+
if (blocked === null)
|
|
46
52
|
return { exitCode: 0 };
|
|
47
53
|
const display = input.runtime.displayName ?? "agent-workflow";
|
|
48
|
-
const msg = formatBlockMessage(toolName, serverFull,
|
|
54
|
+
const msg = formatBlockMessage(toolName, serverFull, blocked, display);
|
|
49
55
|
return { exitCode: 2, stderr: msg };
|
|
50
56
|
}
|
|
51
57
|
function compilePatterns(patterns) {
|
|
@@ -78,21 +84,143 @@ function extractSql(toolInput) {
|
|
|
78
84
|
}
|
|
79
85
|
return "";
|
|
80
86
|
}
|
|
81
|
-
function
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
function findNonRead(sql) {
|
|
88
|
+
const scan = scanSql(sql);
|
|
89
|
+
if (!scan.ok) {
|
|
90
|
+
return {
|
|
91
|
+
statement: `entrada completa · ${displayStatement(sql)}`,
|
|
92
|
+
reason: REASONS.undelimited,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// An empty or comment-only statement runs nothing; it is neither counted nor classified.
|
|
96
|
+
const statements = scan.statements.filter((s) => s.tokens.length > 0 || s.marks.length > 0);
|
|
97
|
+
for (const [position, statement] of statements.entries()) {
|
|
98
|
+
const reason = classifyStatement(statement);
|
|
99
|
+
if (reason === null)
|
|
100
|
+
continue;
|
|
101
|
+
const text = displayStatement(sql.slice(statement.start, statement.end));
|
|
102
|
+
return { statement: `${position + 1} de ${statements.length} · ${text}`, reason };
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
/** Returns why the statement is not a read, or null when it reads. */
|
|
107
|
+
function classifyStatement(statement) {
|
|
108
|
+
const mark = statement.marks[0];
|
|
109
|
+
if (mark !== undefined)
|
|
110
|
+
return MARK_REASONS[mark];
|
|
111
|
+
const { tokens } = statement;
|
|
112
|
+
const shape = classifyRange(tokens, 0, tokens.length);
|
|
113
|
+
if (shape !== null)
|
|
114
|
+
return shape;
|
|
115
|
+
return tokens.includes("INTO") ? REASONS.into : null;
|
|
116
|
+
}
|
|
117
|
+
function classifyRange(tokens, start, end) {
|
|
118
|
+
let index = start;
|
|
119
|
+
while (index < end && tokens[index] === "(")
|
|
120
|
+
index += 1;
|
|
121
|
+
const first = index < end ? tokens[index] : undefined;
|
|
122
|
+
if (first === undefined || first === ")" || first === ",")
|
|
123
|
+
return REASONS.noRead;
|
|
124
|
+
if (READ_STATEMENTS.has(first))
|
|
125
|
+
return null;
|
|
126
|
+
if (first === "WITH")
|
|
127
|
+
return classifyWith(tokens, index + 1, end);
|
|
128
|
+
if (first === "EXPLAIN")
|
|
129
|
+
return classifyExplain(tokens, index + 1, end);
|
|
130
|
+
return `${first} no es una lectura`;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Only a top-level WITH may hold data-modifying parts, so each part's body and
|
|
134
|
+
* the main statement are classified; nested WITHs recurse through classifyRange.
|
|
135
|
+
*/
|
|
136
|
+
function classifyWith(tokens, start, end) {
|
|
137
|
+
let index = tokens[start] === "RECURSIVE" ? start + 1 : start;
|
|
138
|
+
for (;;) {
|
|
139
|
+
const part = classifyWithPart(tokens, index, end);
|
|
140
|
+
if (typeof part === "string")
|
|
141
|
+
return part;
|
|
142
|
+
index = part.next;
|
|
143
|
+
if (tokens[index] !== ",")
|
|
144
|
+
break;
|
|
145
|
+
index += 1;
|
|
146
|
+
}
|
|
147
|
+
const main = classifyRange(tokens, index, end);
|
|
148
|
+
return main === null ? null : `la sentencia principal del WITH: ${main}`;
|
|
149
|
+
}
|
|
150
|
+
/** Reads `name [(columns)] AS [NOT] [MATERIALIZED] (body)`; returns why it fails or where it ends. */
|
|
151
|
+
function classifyWithPart(tokens, start, end) {
|
|
152
|
+
const as = indexAtDepth(tokens, "AS", start, end);
|
|
153
|
+
if (as < 0)
|
|
154
|
+
return REASONS.withShape;
|
|
155
|
+
let open = as + 1;
|
|
156
|
+
if (tokens[open] === "NOT")
|
|
157
|
+
open += 1;
|
|
158
|
+
if (tokens[open] === "MATERIALIZED")
|
|
159
|
+
open += 1;
|
|
160
|
+
const close = tokens[open] === "(" ? matchingParen(tokens, open, end) : -1;
|
|
161
|
+
if (close < 0)
|
|
162
|
+
return REASONS.withShape;
|
|
163
|
+
const body = classifyRange(tokens, open + 1, close);
|
|
164
|
+
return body === null ? { next: close + 1 } : `una parte del WITH: ${body}`;
|
|
165
|
+
}
|
|
166
|
+
/** EXPLAIN is classified by what it explains, with or without ANALYZE. */
|
|
167
|
+
function classifyExplain(tokens, start, end) {
|
|
168
|
+
let index = start;
|
|
169
|
+
if (tokens[index] === "(") {
|
|
170
|
+
const close = matchingParen(tokens, index, end);
|
|
171
|
+
if (close < 0)
|
|
172
|
+
return REASONS.explainShape;
|
|
173
|
+
index = close + 1;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
while (EXPLAIN_LEGACY_OPTIONS.has(tokens[index] ?? ""))
|
|
177
|
+
index += 1;
|
|
178
|
+
}
|
|
179
|
+
const target = classifyRange(tokens, index, end);
|
|
180
|
+
return target === null ? null : `EXPLAIN de otra sentencia: ${target}`;
|
|
181
|
+
}
|
|
182
|
+
function indexAtDepth(tokens, word, start, end) {
|
|
183
|
+
let depth = 0;
|
|
184
|
+
for (let index = start; index < end; index += 1) {
|
|
185
|
+
const token = tokens[index];
|
|
186
|
+
if (token === "(")
|
|
187
|
+
depth += 1;
|
|
188
|
+
else if (token === ")")
|
|
189
|
+
depth -= 1;
|
|
190
|
+
else if (depth === 0 && token === word)
|
|
191
|
+
return index;
|
|
192
|
+
if (depth < 0)
|
|
193
|
+
return -1;
|
|
194
|
+
}
|
|
195
|
+
return -1;
|
|
196
|
+
}
|
|
197
|
+
function matchingParen(tokens, open, end) {
|
|
198
|
+
let depth = 0;
|
|
199
|
+
for (let index = open; index < end; index += 1) {
|
|
200
|
+
if (tokens[index] === "(")
|
|
201
|
+
depth += 1;
|
|
202
|
+
else if (tokens[index] === ")")
|
|
203
|
+
depth -= 1;
|
|
204
|
+
if (depth === 0)
|
|
205
|
+
return index;
|
|
206
|
+
}
|
|
207
|
+
return -1;
|
|
85
208
|
}
|
|
86
|
-
function
|
|
87
|
-
|
|
209
|
+
function displayStatement(text) {
|
|
210
|
+
const compact = text.replace(/\s+/g, " ").trim();
|
|
211
|
+
return compact.length > STATEMENT_DISPLAY_CHARS
|
|
212
|
+
? `${compact.slice(0, STATEMENT_DISPLAY_CHARS)}…`
|
|
213
|
+
: compact;
|
|
88
214
|
}
|
|
89
|
-
function formatBlockMessage(toolName, server,
|
|
215
|
+
function formatBlockMessage(toolName, server, blocked, display) {
|
|
90
216
|
return `${[
|
|
91
217
|
`[${display} sql-mutation-guard] Bloqueado por shared-contract §30 (política BD universal).`,
|
|
92
218
|
` Tool : ${toolName}`,
|
|
93
219
|
` Servidor : ${server}`,
|
|
94
|
-
`
|
|
220
|
+
` Sentencia : ${blocked.statement}`,
|
|
221
|
+
` Motivo : ${blocked.reason}`,
|
|
95
222
|
"",
|
|
223
|
+
"Sólo pasan lecturas: SELECT sin INTO, WITH de lecturas, EXPLAIN de una lectura, SHOW, VALUES y TABLE.",
|
|
96
224
|
"Las mutaciones a BD (DML/DDL) NO se ejecutan desde una sesión.",
|
|
97
225
|
"Materializá el cambio como script SQL en docs/scripts/ del workspace",
|
|
98
226
|
"de la fuente y pedile al usuario que lo aplique manualmente.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-sql-mutation-guard.js","sourceRoot":"","sources":["../../src/application/hook-sql-mutation-guard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hook-sql-mutation-guard.js","sourceRoot":"","sources":["../../src/application/hook-sql-mutation-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { parseSkillFrontmatter } from "../../domain/skill-frontmatter.js";
|
|
3
|
+
import { isoDay, sortedEntries } from "./reader.js";
|
|
4
|
+
/** The index Claude Code loads each session; it points at the notes and is not one. */
|
|
5
|
+
const INDEX_FILE = "MEMORY.md";
|
|
6
|
+
/**
|
|
7
|
+
* Claude Code keeps one note per fact in `~/.claude/projects/<key>/memory/`, with
|
|
8
|
+
* a frontmatter `description` (the brief form) and, on newer notes, a
|
|
9
|
+
* `metadata.modified` date. Every project folder is read: a learning about
|
|
10
|
+
* Workline can live in any of them.
|
|
11
|
+
*/
|
|
12
|
+
export async function readClaudeCodeMemory(fs, home) {
|
|
13
|
+
const projects = join(home, ".claude", "projects");
|
|
14
|
+
if (!(await fs.exists(projects)))
|
|
15
|
+
return { state: "absent", reason: `no existe ${projects}` };
|
|
16
|
+
const items = [];
|
|
17
|
+
const skipped = [];
|
|
18
|
+
let memoryDirs = 0;
|
|
19
|
+
for (const project of await sortedEntries(fs, projects)) {
|
|
20
|
+
const memory = join(project.path, "memory");
|
|
21
|
+
if (project.type !== "dir" || !(await fs.exists(memory)))
|
|
22
|
+
continue;
|
|
23
|
+
memoryDirs++;
|
|
24
|
+
await readMemoryDir(fs, memory, project.name, items, skipped);
|
|
25
|
+
}
|
|
26
|
+
if (memoryDirs === 0) {
|
|
27
|
+
return { state: "absent", reason: `ninguna carpeta memory/ bajo ${projects}` };
|
|
28
|
+
}
|
|
29
|
+
return { state: "read", items, skipped };
|
|
30
|
+
}
|
|
31
|
+
async function readMemoryDir(fs, memory, project, items, skipped) {
|
|
32
|
+
for (const file of await sortedEntries(fs, memory)) {
|
|
33
|
+
if (file.type !== "file" || !file.name.endsWith(".md") || file.name === INDEX_FILE)
|
|
34
|
+
continue;
|
|
35
|
+
const note = await readNote(fs, file.path, `${project}/${file.name}`);
|
|
36
|
+
if ("reason" in note)
|
|
37
|
+
skipped.push(note);
|
|
38
|
+
else
|
|
39
|
+
items.push(note);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function readNote(fs, path, key) {
|
|
43
|
+
let content;
|
|
44
|
+
try {
|
|
45
|
+
content = await fs.readText(path);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
return { path, reason: `no se pudo leer: ${err.message}` };
|
|
49
|
+
}
|
|
50
|
+
const frontmatter = parseSkillFrontmatter(content);
|
|
51
|
+
if (frontmatter === null)
|
|
52
|
+
return { path, reason: "sin frontmatter" };
|
|
53
|
+
const description = frontmatter.fields.description?.trim();
|
|
54
|
+
if (!description)
|
|
55
|
+
return { path, reason: "el frontmatter no trae description" };
|
|
56
|
+
return {
|
|
57
|
+
key,
|
|
58
|
+
date: isoDay(frontmatter.metadata.modified),
|
|
59
|
+
text: description,
|
|
60
|
+
topic: content,
|
|
61
|
+
body: content,
|
|
62
|
+
source: { path, section: null },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=claude-code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/application/host-memory/claude-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { parse as parseToml } from "smol-toml";
|
|
3
|
+
import { sortedEntries } from "./reader.js";
|
|
4
|
+
const GROUP_HEADING = /^# Task Group:\s*(.+)$/;
|
|
5
|
+
const GROUP_HEADER_LINE = /^(scope|applies_to):/;
|
|
6
|
+
/** The two sections of a group that hold what was learned; the rest is its record. */
|
|
7
|
+
const LEARNING_SECTIONS = new Set([
|
|
8
|
+
"Reusable knowledge",
|
|
9
|
+
"Failures and how to do differently",
|
|
10
|
+
]);
|
|
11
|
+
const ROLLOUT_DATE = /rollout_summaries\/(\d{4}-\d{2}-\d{2})T/;
|
|
12
|
+
/**
|
|
13
|
+
* Consolidation labels what it derived from an ad-hoc note. Those notes are read
|
|
14
|
+
* directly, so the derived bullet would be the same learning twice.
|
|
15
|
+
*/
|
|
16
|
+
const AD_HOC_TAG = "[ad-hoc note]";
|
|
17
|
+
const AD_HOC_NOTE_NAME = /^(\d{4}-\d{2}-\d{2})T\d{2}-\d{2}-\d{2}-.+\.md$/;
|
|
18
|
+
/**
|
|
19
|
+
* Codex keeps a global memory in `~/.codex/memories/`: a consolidated
|
|
20
|
+
* `MEMORY.md` of `# Task Group` blocks, plus append-only ad-hoc notes. It is only
|
|
21
|
+
* live with `[features] memories = true`.
|
|
22
|
+
*/
|
|
23
|
+
/** The ad-hoc note name Codex's own consolidation reads. */
|
|
24
|
+
export const CODEX_AD_HOC_NAME_FORMAT = "YYYY-MM-DDTHH-MM-SS-<slug>.md";
|
|
25
|
+
export function codexMemoryPaths(home) {
|
|
26
|
+
const root = join(home, ".codex");
|
|
27
|
+
const memories = join(root, "memories");
|
|
28
|
+
return {
|
|
29
|
+
root,
|
|
30
|
+
config: join(root, "config.toml"),
|
|
31
|
+
memories,
|
|
32
|
+
index: join(memories, "MEMORY.md"),
|
|
33
|
+
notesDir: join(memories, "extensions", "ad_hoc", "notes"),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export async function readCodexMemory(fs, home) {
|
|
37
|
+
const { root, config, index, notesDir } = codexMemoryPaths(home);
|
|
38
|
+
if (!(await fs.exists(root)))
|
|
39
|
+
return { state: "absent", reason: `no existe ${root}` };
|
|
40
|
+
const memoriesSwitch = await readCodexMemoriesSwitch(fs, config);
|
|
41
|
+
if (memoriesSwitch !== null)
|
|
42
|
+
return memoriesSwitch;
|
|
43
|
+
const [hasIndex, hasNotes] = await Promise.all([fs.exists(index), fs.exists(notesDir)]);
|
|
44
|
+
if (!hasIndex && !hasNotes) {
|
|
45
|
+
return { state: "absent", reason: `ni ${index} ni ${notesDir} existen` };
|
|
46
|
+
}
|
|
47
|
+
// Index and notes are independent sources: one that cannot be read never hides the other.
|
|
48
|
+
const fromIndex = hasIndex ? await readIndexItems(fs, index) : [];
|
|
49
|
+
const fromNotes = hasNotes ? await readAdHocNotes(fs, notesDir) : { items: [], skipped: [] };
|
|
50
|
+
const indexItems = Array.isArray(fromIndex) ? fromIndex : [];
|
|
51
|
+
const skipped = Array.isArray(fromIndex) ? fromNotes.skipped : [fromIndex, ...fromNotes.skipped];
|
|
52
|
+
const items = [...indexItems, ...fromNotes.items];
|
|
53
|
+
if (items.length === 0 && skipped.length > 0) {
|
|
54
|
+
return { state: "unreadable", reason: skipped.map((s) => `${s.path}: ${s.reason}`).join("; ") };
|
|
55
|
+
}
|
|
56
|
+
return { state: "read", items, skipped };
|
|
57
|
+
}
|
|
58
|
+
/** The index's learnings, or why the index could not be read as one. */
|
|
59
|
+
async function readIndexItems(fs, index) {
|
|
60
|
+
let text;
|
|
61
|
+
try {
|
|
62
|
+
text = await fs.readText(index);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
return { path: index, reason: `no se pudo leer: ${err.message}` };
|
|
66
|
+
}
|
|
67
|
+
const groups = parseIndex(text);
|
|
68
|
+
if (groups.length === 0)
|
|
69
|
+
return { path: index, reason: "no trae ningún bloque '# Task Group'" };
|
|
70
|
+
return groupItems(groups, index);
|
|
71
|
+
}
|
|
72
|
+
async function readAdHocNotes(fs, notesDir) {
|
|
73
|
+
const items = [];
|
|
74
|
+
const skipped = [];
|
|
75
|
+
for (const file of await sortedEntries(fs, notesDir)) {
|
|
76
|
+
if (file.type !== "file" || !file.name.endsWith(".md"))
|
|
77
|
+
continue;
|
|
78
|
+
const note = await readAdHocNote(fs, file.path, file.name);
|
|
79
|
+
if ("reason" in note)
|
|
80
|
+
skipped.push(note);
|
|
81
|
+
else
|
|
82
|
+
items.push(note);
|
|
83
|
+
}
|
|
84
|
+
return { items, skipped };
|
|
85
|
+
}
|
|
86
|
+
/** Null when memory is on; otherwise the state and reason that say why it is off. */
|
|
87
|
+
export async function readCodexMemoriesSwitch(fs, configPath) {
|
|
88
|
+
if (!(await fs.exists(configPath))) {
|
|
89
|
+
return { state: "disabled", reason: `sin ${configPath}: [features] memories no está activado` };
|
|
90
|
+
}
|
|
91
|
+
let config;
|
|
92
|
+
try {
|
|
93
|
+
config = parseToml(await fs.readText(configPath));
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return {
|
|
97
|
+
state: "unreadable",
|
|
98
|
+
reason: `${configPath} no es TOML válido: ${err.message}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const features = config.features;
|
|
102
|
+
if (features?.memories === true)
|
|
103
|
+
return null;
|
|
104
|
+
return { state: "disabled", reason: `[features] memories no es true en ${configPath}` };
|
|
105
|
+
}
|
|
106
|
+
function parseIndex(text) {
|
|
107
|
+
const parser = new IndexParser();
|
|
108
|
+
for (const line of text.split(/\r?\n/))
|
|
109
|
+
parser.read(line);
|
|
110
|
+
return parser.groups;
|
|
111
|
+
}
|
|
112
|
+
/** One pass over `MEMORY.md`, tracking which group, section and bullet a line belongs to. */
|
|
113
|
+
class IndexParser {
|
|
114
|
+
groups = [];
|
|
115
|
+
group = null;
|
|
116
|
+
section = null;
|
|
117
|
+
subsection = null;
|
|
118
|
+
bullet = null;
|
|
119
|
+
read(line) {
|
|
120
|
+
const heading = GROUP_HEADING.exec(line)?.[1];
|
|
121
|
+
if (heading !== undefined) {
|
|
122
|
+
this.startGroup(heading);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const group = this.group;
|
|
126
|
+
if (group === null)
|
|
127
|
+
return;
|
|
128
|
+
if (line.startsWith("## ")) {
|
|
129
|
+
this.enterSection(line.slice(3).trim(), null);
|
|
130
|
+
}
|
|
131
|
+
else if (line.startsWith("### ")) {
|
|
132
|
+
this.enterSection(this.section, line.slice(4).trim());
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
this.readRecord(group, line);
|
|
136
|
+
this.readLearning(group, line);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
startGroup(title) {
|
|
140
|
+
this.group = { title: title.trim(), header: [title], date: null, bullets: [] };
|
|
141
|
+
this.groups.push(this.group);
|
|
142
|
+
this.enterSection(null, null);
|
|
143
|
+
}
|
|
144
|
+
enterSection(section, subsection) {
|
|
145
|
+
this.section = section;
|
|
146
|
+
this.subsection = subsection;
|
|
147
|
+
this.bullet = null;
|
|
148
|
+
}
|
|
149
|
+
/** The lines that say what the group is about and when it was last consolidated. */
|
|
150
|
+
readRecord(group, line) {
|
|
151
|
+
if (GROUP_HEADER_LINE.test(line))
|
|
152
|
+
group.header.push(line);
|
|
153
|
+
if (this.subsection === "keywords" && line.startsWith("- "))
|
|
154
|
+
group.header.push(line);
|
|
155
|
+
const rollout = ROLLOUT_DATE.exec(line)?.[1];
|
|
156
|
+
if (rollout !== undefined && (group.date === null || rollout > group.date)) {
|
|
157
|
+
group.date = rollout;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** A learning bullet, including the indented lines that continue it. */
|
|
161
|
+
readLearning(group, line) {
|
|
162
|
+
const section = this.section;
|
|
163
|
+
if (section === null || this.subsection !== null || !LEARNING_SECTIONS.has(section))
|
|
164
|
+
return;
|
|
165
|
+
if (line.startsWith("- ")) {
|
|
166
|
+
this.bullet = { section, text: line.slice(2).trim() };
|
|
167
|
+
group.bullets.push(this.bullet);
|
|
168
|
+
}
|
|
169
|
+
else if (this.bullet !== null && /^\s+\S/.test(line)) {
|
|
170
|
+
this.bullet.text += ` ${line.trim()}`;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
this.bullet = null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function groupItems(groups, index) {
|
|
178
|
+
return groups.flatMap((group) => group.bullets
|
|
179
|
+
.filter((bullet) => !bullet.text.includes(AD_HOC_TAG))
|
|
180
|
+
.map((bullet) => ({
|
|
181
|
+
// MEMORY.md is rewritten by every consolidation, so no key inside it is
|
|
182
|
+
// stable: a position shifts as much as a wording. The durable source is the
|
|
183
|
+
// append-only ad-hoc note, which is why those are read directly.
|
|
184
|
+
key: `MEMORY.md#${group.title}#${bullet.text}`,
|
|
185
|
+
date: group.date,
|
|
186
|
+
text: bullet.text,
|
|
187
|
+
topic: group.header.join("\n"),
|
|
188
|
+
body: bullet.text,
|
|
189
|
+
source: { path: index, section: `${group.title} › ${bullet.section}` },
|
|
190
|
+
})));
|
|
191
|
+
}
|
|
192
|
+
async function readAdHocNote(fs, path, name) {
|
|
193
|
+
const date = AD_HOC_NOTE_NAME.exec(name)?.[1];
|
|
194
|
+
if (date === undefined) {
|
|
195
|
+
return { path, reason: "el nombre no sigue YYYY-MM-DDTHH-MM-SS-<slug>.md" };
|
|
196
|
+
}
|
|
197
|
+
let content;
|
|
198
|
+
try {
|
|
199
|
+
content = await fs.readText(path);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
return { path, reason: `no se pudo leer: ${err.message}` };
|
|
203
|
+
}
|
|
204
|
+
const text = firstLine(content);
|
|
205
|
+
if (text === null)
|
|
206
|
+
return { path, reason: "la nota está vacía" };
|
|
207
|
+
return {
|
|
208
|
+
key: `ad_hoc/${name}`,
|
|
209
|
+
date,
|
|
210
|
+
text,
|
|
211
|
+
topic: content,
|
|
212
|
+
body: content,
|
|
213
|
+
source: { path, section: null },
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/** The first line with content, without its Markdown heading or bullet mark. */
|
|
217
|
+
function firstLine(content) {
|
|
218
|
+
for (const line of content.split(/\r?\n/)) {
|
|
219
|
+
const text = line.replace(/^\s*(#+|[-*])\s*/, "").trim();
|
|
220
|
+
if (text !== "")
|
|
221
|
+
return text;
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/application/host-memory/codex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import { harnessById } from "../../domain/harnesses.js";
|
|
3
|
+
import { CODEX_AD_HOC_NAME_FORMAT, codexMemoryPaths, readCodexMemoriesSwitch } from "./codex.js";
|
|
4
|
+
/**
|
|
5
|
+
* Where the current host would save a learning. The CLI never saves: it names
|
|
6
|
+
* the place, and the host's agent writes there through its own channel.
|
|
7
|
+
*/
|
|
8
|
+
export async function resolveDestination(host, ctx) {
|
|
9
|
+
const home = ctx.env.homeDir();
|
|
10
|
+
if (host === "claude-code") {
|
|
11
|
+
const root = await gitRootOf(ctx, ctx.env.cwd());
|
|
12
|
+
const path = join(home, ".claude", "projects", claudeProjectKey(root), "memory");
|
|
13
|
+
const destination = { path, channel: "claude-code-memory-note", name_format: null };
|
|
14
|
+
return { destination, reason: null, presenceRoot: path };
|
|
15
|
+
}
|
|
16
|
+
if (host === "codex") {
|
|
17
|
+
const paths = codexMemoryPaths(home);
|
|
18
|
+
const off = await readCodexMemoriesSwitch(ctx.fs, paths.config);
|
|
19
|
+
if (off !== null)
|
|
20
|
+
return nowhere(`la memoria de Codex no está activa: ${off.reason}`);
|
|
21
|
+
const destination = {
|
|
22
|
+
path: paths.notesDir,
|
|
23
|
+
channel: "codex-ad-hoc-note",
|
|
24
|
+
name_format: CODEX_AD_HOC_NAME_FORMAT,
|
|
25
|
+
};
|
|
26
|
+
// Codex's memory is global, and consolidation may carry a note's mark into MEMORY.md.
|
|
27
|
+
return { destination, reason: null, presenceRoot: paths.memories };
|
|
28
|
+
}
|
|
29
|
+
if (host === "unknown") {
|
|
30
|
+
return nowhere("host no reconocido: sin --host ni marcador de entorno no hay memoria propia");
|
|
31
|
+
}
|
|
32
|
+
const label = harnessById(host)?.label ?? host;
|
|
33
|
+
return nowhere(`${label} no guarda memoria curada propia: no tiene dónde guardar`);
|
|
34
|
+
}
|
|
35
|
+
function nowhere(reason) {
|
|
36
|
+
return { destination: null, reason, presenceRoot: null };
|
|
37
|
+
}
|
|
38
|
+
/** Claude Code files a project's memory under its git root, every non-alphanumeric turned into `-`. */
|
|
39
|
+
function claudeProjectKey(root) {
|
|
40
|
+
return root.replace(/[^A-Za-z0-9]/g, "-");
|
|
41
|
+
}
|
|
42
|
+
async function gitRootOf(ctx, dir) {
|
|
43
|
+
// git counts the prefix over the physical path; climbing it from a symlinked
|
|
44
|
+
// spelling of the same directory would land in a folder Claude Code never reads.
|
|
45
|
+
const physical = await ctx.fs.realPath(dir);
|
|
46
|
+
const prefix = await ctx.git.repoPrefix(physical);
|
|
47
|
+
if (prefix === null)
|
|
48
|
+
return physical;
|
|
49
|
+
const depth = prefix.split("/").filter(Boolean).length;
|
|
50
|
+
return resolve(physical, ...Array(depth).fill(".."));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=destination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destination.js","sourceRoot":"","sources":["../../../src/application/host-memory/destination.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const ISO_DAY = /^\d{4}-\d{2}-\d{2}/;
|
|
2
|
+
/** The `YYYY-MM-DD` a memory recorded, or null when what it recorded is not a date. */
|
|
3
|
+
export function isoDay(value) {
|
|
4
|
+
return value?.match(ISO_DAY)?.[0] ?? null;
|
|
5
|
+
}
|
|
6
|
+
export async function sortedEntries(fs, dir) {
|
|
7
|
+
return (await fs.list(dir)).sort((a, b) => a.name.localeCompare(b.name));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../src/application/host-memory/reader.ts"],"names":[],"mappings":"AA0BA,MAAM,OAAO,GAAG,oBAAoB,CAAC;AAErC,uFAAuF;AACvF,MAAM,UAAU,MAAM,CAAC,KAAyB;IAC9C,OAAO,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAkB,EAAE,GAAW;IACjE,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3E,CAAC"}
|