kenaz 0.3.11 → 0.3.12
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/core/.collaboration/core/task-2288-followups.test.js +2 -37
- package/core/.collaboration/core/task-2421-replica.test.js +229 -0
- package/core/.collaboration/core/task-api.js +221 -12
- package/core/.collaboration/core/task-replica.js +189 -0
- package/core/.formation/.merge-lock +1 -0
- package/core/.formation/bifrost/codex-doctor.js +12 -2
- package/core/.formation/bifrost/codex-doctor.test.js +15 -0
- package/core/.formation/bifrost/setup-codex.js +84 -16
- package/core/.formation/tools/post-complete/task2420.test.js +129 -0
- package/core/.formation/tools/post-complete.js +129 -8
- package/core/.kenaz/specialist/memory_guard_fired.json +1 -1
- package/core/.kenaz/specialist/memory_guard_trigger_cache.json +1 -1
- package/core/.specialist/tools/__tests__/rea-detect.test.js +10 -0
- package/core/.specialist/tools/rea-detect.js +6 -2
- package/core/.synapse/memory-shared.json.sync +1 -0
- package/core/KENAZ_CORE_VERSION +1 -1
- package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +75 -109
- package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +54 -0
- package/core/dev/specs/peer/setup-codex-hooks.test.js +38 -0
- package/core/dev/spikes/task2145-evidence-20261004/backend-log-excerpt.txt +56 -0
- package/core/dev/spikes/task2145-evidence-20261004/graph.shadow +0 -0
- package/core/dev/spikes/task2145-evidence-20261004/graph.wal +0 -0
- package/core/dev/spikes/task2145-evidence-20261004/graph_corrupt_suspect.marker +1 -0
- package/core/plugins/kenaz/scripts/kenaz.test.js +68 -0
- package/core/plugins/kenaz/scripts/ygg.js +43 -4
- package/lib/cli.js +17 -7
- package/lib/cli.test.js +10 -0
- package/lib/dashboard.test.js +3 -3
- package/package.json +6 -6
- package/vendor/install-kenaz-cli.js +167 -16
- package/core/.collaboration/core/task-2264-single-after-capture.test.js +0 -61
|
@@ -225,7 +225,7 @@ function uninstall(options = {}) {
|
|
|
225
225
|
for (let n = 0; n < segs.length; n++) {
|
|
226
226
|
const [h, body] = segs[n], nx = segs[n + 1];
|
|
227
227
|
if (h && /^\s*\[\[hooks\.\w+\]\]\s*$/.test(h) && nx && nx[0] && /^\s*\[\[hooks\.\w+\.hooks\]\]/.test(nx[0]) &&
|
|
228
|
-
nx
|
|
228
|
+
isKenazHandler(nx)) { n++; res.hooks = 'removed'; continue; } // TASK_2418: any checkout's shim, same identity rule as missingHookEvents
|
|
229
229
|
out.push(...body.filter((l) => !/^# kenaz-dashboard native hooks/.test(l)));
|
|
230
230
|
}
|
|
231
231
|
if (res.hooks === 'removed' && !dryRun) fs.writeFileSync(cfg, out.join('\n').replace(/\n{3,}/g, '\n\n'), 'utf8');
|
|
@@ -283,23 +283,82 @@ function getHookShimPath(_projectRoot) {
|
|
|
283
283
|
return path.resolve(__dirname, '..', '..', HOOK_SHIM_REL);
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
+
// TASK_2418: what counts as a kenaz hook, and what counts as a CURRENT one.
|
|
287
|
+
// A handler is kenaz's when its command runs codex-hook-shim.js (any checkout). It is current only when it
|
|
288
|
+
// runs exactly this core's shim (absolute path, slashes normalized, Windows case-insensitive) and the
|
|
289
|
+
// UserPromptSubmit one carries --pull (TASK_2379). Stale ones are replaced in place, never duplicated; handlers
|
|
290
|
+
// that do not run our shim are never touched.
|
|
291
|
+
const HOOK_SHIM_NAME = path.posix.basename(HOOK_SHIM_REL);
|
|
292
|
+
const HOOK_MARKER = /^# kenaz-dashboard native hooks/;
|
|
293
|
+
const HANDLER_HEADER = /^\s*\[\[hooks\.(\w+)\.hooks\]\]\s*$/;
|
|
294
|
+
const GROUP_HEADER = /^\s*\[\[hooks\.(\w+)\]\]\s*$/;
|
|
295
|
+
const slashes = (s) => String(s).replace(/\\/g, '/');
|
|
296
|
+
const foldCase = (s) => (process.platform === 'win32' ? s.toLowerCase() : s);
|
|
297
|
+
|
|
298
|
+
function parseSegments(text) { // [header line | null, body lines]
|
|
299
|
+
const segs = [];
|
|
300
|
+
for (const line of text.split(/\r?\n/)) {
|
|
301
|
+
if (/^\s*\[/.test(line) || !segs.length) segs.push([/^\s*\[/.test(line) ? line : null, [line]]);
|
|
302
|
+
else segs[segs.length - 1][1].push(line);
|
|
303
|
+
}
|
|
304
|
+
return segs;
|
|
305
|
+
}
|
|
306
|
+
const isKenazHandler = (seg) => slashes(seg[1].join('\n')).includes(HOOK_SHIM_NAME);
|
|
307
|
+
function isCurrentHandler(ev, seg, projectRoot) {
|
|
308
|
+
const m = slashes(seg[1].join('\n')).match(/^\s*command\s*=\s*(.*)$/m);
|
|
309
|
+
if (!m) return false;
|
|
310
|
+
const cmd = foldCase(m[1]);
|
|
311
|
+
const shim = foldCase(slashes(getHookShimPath(projectRoot)));
|
|
312
|
+
const at = cmd.indexOf('"' + shim + '"');
|
|
313
|
+
if (at < 0) return false;
|
|
314
|
+
return ev !== 'UserPromptSubmit' || /(^|\s)--pull(\s|['"]|$)/.test(cmd.slice(at + shim.length + 2));
|
|
315
|
+
}
|
|
316
|
+
/** Per event: segment indexes of kenaz handlers, split into current / stale. */
|
|
317
|
+
function scanKenazHooks(text, projectRoot) {
|
|
318
|
+
const segs = parseSegments(text), found = {};
|
|
319
|
+
segs.forEach((seg, i) => {
|
|
320
|
+
const m = seg[0] && seg[0].match(HANDLER_HEADER);
|
|
321
|
+
if (!m || !HOOK_EVENTS.includes(m[1]) || !isKenazHandler(seg)) return;
|
|
322
|
+
const f = found[m[1]] || (found[m[1]] = { current: [], stale: [] });
|
|
323
|
+
(isCurrentHandler(m[1], seg, projectRoot) ? f.current : f.stale).push(i);
|
|
324
|
+
});
|
|
325
|
+
return { segs, found };
|
|
326
|
+
}
|
|
327
|
+
/** config text without the kenaz handlers of `events` (and the empty group each one leaves behind). */
|
|
328
|
+
function stripKenazHooks(text, events, projectRoot) {
|
|
329
|
+
const { segs, found } = scanKenazHooks(text, projectRoot);
|
|
330
|
+
const drop = new Set();
|
|
331
|
+
for (const ev of events) {
|
|
332
|
+
for (const i of [...(found[ev] ? found[ev].current : []), ...(found[ev] ? found[ev].stale : [])]) {
|
|
333
|
+
drop.add(i);
|
|
334
|
+
const prev = segs[i - 1], next = segs[i + 1];
|
|
335
|
+
const g = prev && prev[0] && prev[0].match(GROUP_HEADER);
|
|
336
|
+
if (g && g[1] === ev && !(next && next[0] && HANDLER_HEADER.test(next[0]) && next[0].includes('.' + ev + '.'))
|
|
337
|
+
&& prev[1].slice(1).every((l) => !l.trim())) drop.add(i - 1);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const out = [];
|
|
341
|
+
segs.forEach((seg, i) => {
|
|
342
|
+
if (!drop.has(i)) { out.push(...seg[1]); return; }
|
|
343
|
+
out.push(...seg[1].slice(1).filter((l) => /^\s*#/.test(l) && !HOOK_MARKER.test(l))); // keep neighbours' comments
|
|
344
|
+
});
|
|
345
|
+
return out.join('\n');
|
|
346
|
+
}
|
|
347
|
+
|
|
286
348
|
function areHooksAlreadyRegistered(projectRoot) {
|
|
287
349
|
const configPath = getCodexConfigPath();
|
|
288
350
|
if (!fs.existsSync(configPath)) return false;
|
|
289
|
-
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
return content.includes(HOOK_SHIM_REL) || content.includes(shimPath.split('\\').join('/'));
|
|
351
|
+
// at least one CURRENT kenaz handler: a block left by an old checkout does not run this core's shim
|
|
352
|
+
const { found } = scanKenazHooks(fs.readFileSync(configPath, 'utf8'), projectRoot);
|
|
353
|
+
return Object.values(found).some((f) => f.current.length > 0);
|
|
293
354
|
}
|
|
294
355
|
|
|
295
|
-
// TASK_2299: HOOK_EVENTS
|
|
296
|
-
|
|
356
|
+
// TASK_2299: HOOK_EVENTS without exactly one current kenaz handler. TASK_2418: stale (old checkout path,
|
|
357
|
+
// UserPromptSubmit without --pull) and duplicated ones count as missing, so registerHooks rewrites them.
|
|
358
|
+
function missingHookEvents(projectRoot) {
|
|
297
359
|
const configPath = getCodexConfigPath();
|
|
298
|
-
const
|
|
299
|
-
return HOOK_EVENTS.filter((ev) =>
|
|
300
|
-
const blocks = content.match(new RegExp('\\[\\[hooks\\.' + ev + '\\.hooks\\]\\][^\\[]*', 'g')) || [];
|
|
301
|
-
return !blocks.some((blk) => blk.includes(HOOK_SHIM_REL));
|
|
302
|
-
});
|
|
360
|
+
const { found } = scanKenazHooks(fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf8') : '', projectRoot);
|
|
361
|
+
return HOOK_EVENTS.filter((ev) => !found[ev] || found[ev].stale.length > 0 || found[ev].current.length !== 1);
|
|
303
362
|
}
|
|
304
363
|
|
|
305
364
|
// True when the codex CLI both supports hooks AND our shim is registered.
|
|
@@ -313,6 +372,7 @@ function nativeHooksActive(projectRoot) {
|
|
|
313
372
|
function registerHooks(log, projectRoot, events) {
|
|
314
373
|
const shimPath = getHookShimPath(projectRoot).split('\\').join('/');
|
|
315
374
|
const configPath = getCodexConfigPath();
|
|
375
|
+
const evs = events || HOOK_EVENTS;
|
|
316
376
|
|
|
317
377
|
// Ensure ~/.codex dir exists
|
|
318
378
|
const codexDir = path.dirname(configPath);
|
|
@@ -322,8 +382,16 @@ function registerHooks(log, projectRoot, events) {
|
|
|
322
382
|
|
|
323
383
|
// [[hooks.X]] array-of-tables entries are additive-safe TOML: appending is valid
|
|
324
384
|
// even if the user already has their own [[hooks.X]] entries from other tools.
|
|
325
|
-
|
|
326
|
-
|
|
385
|
+
// TASK_2418: kenaz handlers already present for these events (stale or not) are dropped first, so each
|
|
386
|
+
// event ends with exactly one current handler.
|
|
387
|
+
let kept = '';
|
|
388
|
+
try {
|
|
389
|
+
kept = fs.existsSync(configPath) ? stripKenazHooks(fs.readFileSync(configPath, 'utf8'), evs, projectRoot) : '';
|
|
390
|
+
if (!Object.keys(scanKenazHooks(kept, projectRoot).found).length) kept = kept.split('\n').filter((l) => !HOOK_MARKER.test(l)).join('\n');
|
|
391
|
+
} catch (err) { log('hook registration failed: ' + err.message); return { success: false, action: 'hooks_failed', error: err.message }; }
|
|
392
|
+
const lines = [''];
|
|
393
|
+
if (!kept.split('\n').some((l) => HOOK_MARKER.test(l))) lines.push('# kenaz-dashboard native hooks (TASK_1733) -- auto-registered by setup-codex.js');
|
|
394
|
+
for (const ev of evs) {
|
|
327
395
|
lines.push(
|
|
328
396
|
'[[hooks.' + ev + ']]',
|
|
329
397
|
'',
|
|
@@ -337,8 +405,8 @@ function registerHooks(log, projectRoot, events) {
|
|
|
337
405
|
const hookBlock = lines.join('\n');
|
|
338
406
|
|
|
339
407
|
try {
|
|
340
|
-
fs.
|
|
341
|
-
log('kenaz hooks
|
|
408
|
+
fs.writeFileSync(configPath, kept + (kept && !kept.endsWith('\n') ? '\n' : '') + hookBlock, 'utf8');
|
|
409
|
+
log('kenaz hooks written to ' + configPath);
|
|
342
410
|
return { success: true, action: 'hooks_registered' };
|
|
343
411
|
} catch (err) {
|
|
344
412
|
log('hook registration failed: ' + err.message);
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TASK_2420 — runtime/config-only completion and truthful outcome reporting.
|
|
3
|
+
*
|
|
4
|
+
* Drives the REAL task-api.js CLI (`complete`) against a temp git repo with a temp
|
|
5
|
+
* .kenaz/tasks store. Never touches ~/.kenaz, ~/.claude or ~/.codex.
|
|
6
|
+
*/
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const test = require('node:test');
|
|
10
|
+
const assert = require('node:assert/strict');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const { execSync, spawnSync } = require('child_process');
|
|
15
|
+
|
|
16
|
+
const ROOT = path.resolve(__dirname, '..', '..', '..');
|
|
17
|
+
const TASK_API = path.join(ROOT, '.collaboration', 'core', 'task-api.js');
|
|
18
|
+
const { summarizePostComplete, spawnFailureCause } = require('../post-complete');
|
|
19
|
+
|
|
20
|
+
function git(cmd, cwd) {
|
|
21
|
+
return execSync(cmd, { cwd, encoding: 'utf8', timeout: 20000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function setup(taskId, scopePaths = []) {
|
|
25
|
+
const tmp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'tn2420-')));
|
|
26
|
+
const repo = path.join(tmp, 'repo');
|
|
27
|
+
fs.mkdirSync(repo);
|
|
28
|
+
git('git init -b userwork', repo);
|
|
29
|
+
git('git config user.email t@t.com', repo);
|
|
30
|
+
git('git config user.name Test', repo);
|
|
31
|
+
git('git config commit.gpgsign false', repo);
|
|
32
|
+
fs.writeFileSync(path.join(repo, 'README.md'), 'init\n');
|
|
33
|
+
fs.writeFileSync(path.join(repo, '.gitignore'), '.kenaz/\n');
|
|
34
|
+
git('git add README.md .gitignore', repo);
|
|
35
|
+
git('git commit --no-verify -m init', repo);
|
|
36
|
+
const dir = path.join(repo, '.kenaz', 'tasks', 'active');
|
|
37
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
38
|
+
fs.writeFileSync(path.join(dir, `${taskId}.yaml`), [
|
|
39
|
+
`id: "${taskId}"`, 'title: "runtime repair"', 'status: in_progress', 'priority: P2',
|
|
40
|
+
scopePaths.length ? `scope_paths:\n${scopePaths.map(p => ` - "${p}"`).join('\n')}` : 'scope_paths: []', '',
|
|
41
|
+
].join('\n'));
|
|
42
|
+
return { tmp, repo };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function complete(repo, taskId, extra = []) {
|
|
46
|
+
return spawnSync('node', [TASK_API, '--project-path', repo, 'complete', taskId, '--skip-archive', ...extra], {
|
|
47
|
+
cwd: ROOT, encoding: 'utf8', timeout: 120000, windowsHide: true,
|
|
48
|
+
env: { ...process.env, KENAZ_INTEGRATION_QUEUE: '' },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const where = (repo, taskId) => ['done', 'active', 'blocked']
|
|
53
|
+
.filter(d => fs.existsSync(path.join(repo, '.kenaz', 'tasks', d, `${taskId}.yaml`)));
|
|
54
|
+
|
|
55
|
+
test('TASK_2420: no-branch task with --no-source completes; git merge/verify reported as skipped', () => {
|
|
56
|
+
const taskId = 'TASK_24201';
|
|
57
|
+
const { tmp, repo } = setup(taskId);
|
|
58
|
+
try {
|
|
59
|
+
const r = complete(repo, taskId, ['--no-source']);
|
|
60
|
+
const out = `${r.stdout}\n${r.stderr}`;
|
|
61
|
+
assert.equal(r.status, 0, out);
|
|
62
|
+
assert.match(r.stdout, /任務已完成/);
|
|
63
|
+
assert.match(out, /no branch: nothing to integrate/);
|
|
64
|
+
assert.doesNotMatch(out, /Git merge failed/);
|
|
65
|
+
assert.deepEqual(where(repo, taskId), ['done']);
|
|
66
|
+
} finally { fs.rmSync(tmp, { recursive: true, force: true }); }
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('TASK_2420: --no-source is refused when the task branch has unmerged commits (work is not silently dropped)', () => {
|
|
70
|
+
const taskId = 'TASK_24202';
|
|
71
|
+
const { tmp, repo } = setup(taskId);
|
|
72
|
+
try {
|
|
73
|
+
git(`git checkout -b task/${taskId.toLowerCase()}`, repo);
|
|
74
|
+
fs.writeFileSync(path.join(repo, 'a.txt'), 'real work\n');
|
|
75
|
+
git('git add a.txt', repo);
|
|
76
|
+
git('git commit --no-verify -m work', repo);
|
|
77
|
+
git('git checkout userwork', repo);
|
|
78
|
+
const r = complete(repo, taskId, ['--no-source']);
|
|
79
|
+
assert.notEqual(r.status, 0, 'must not report success');
|
|
80
|
+
assert.doesNotMatch(r.stdout, /✅ 任務已完成/);
|
|
81
|
+
assert.match(r.stderr, /任務未完成/);
|
|
82
|
+
assert.match(r.stderr, /no_source_but_work_exists/);
|
|
83
|
+
assert.match(r.stderr, /exists with commits not on userwork/);
|
|
84
|
+
assert.ok(!where(repo, taskId).includes('done'), `card must not stay in done/: ${where(repo, taskId)}`);
|
|
85
|
+
} finally { fs.rmSync(tmp, { recursive: true, force: true }); }
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('TASK_2420: branch task whose merge fails is NOT reported as plain success and the cause is shown', () => {
|
|
89
|
+
const taskId = 'TASK_24203';
|
|
90
|
+
const { tmp, repo } = setup(taskId);
|
|
91
|
+
try {
|
|
92
|
+
// Conflicting edits: branch and userwork both change a.txt differently.
|
|
93
|
+
fs.writeFileSync(path.join(repo, 'a.txt'), 'base\n');
|
|
94
|
+
git('git add a.txt', repo); git('git commit --no-verify -m base', repo);
|
|
95
|
+
git(`git checkout -b task/${taskId.toLowerCase()}`, repo);
|
|
96
|
+
fs.writeFileSync(path.join(repo, 'a.txt'), 'branch side\n');
|
|
97
|
+
git('git commit --no-verify -am branch', repo);
|
|
98
|
+
git('git checkout userwork', repo);
|
|
99
|
+
fs.writeFileSync(path.join(repo, 'a.txt'), 'user side\n');
|
|
100
|
+
git('git commit --no-verify -am user', repo);
|
|
101
|
+
const r = complete(repo, taskId);
|
|
102
|
+
assert.notEqual(r.status, 0, `${r.stdout}\n${r.stderr}`);
|
|
103
|
+
assert.doesNotMatch(r.stdout, /✅ 任務已完成/);
|
|
104
|
+
assert.match(r.stderr, /任務未完成/);
|
|
105
|
+
assert.match(r.stderr, /git: failed — \S+/);
|
|
106
|
+
assert.ok(!where(repo, taskId).includes('done'), `card must not stay in done/: ${where(repo, taskId)}`);
|
|
107
|
+
} finally { fs.rmSync(tmp, { recursive: true, force: true }); }
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('TASK_2420: summarize — move/reconcile failures carry their real cause and card is flagged unreconciled', () => {
|
|
111
|
+
const s = summarizePostComplete({
|
|
112
|
+
git: { merged: false, taskBranch: 'task/x', failure_reason: 'merge_conflict', mergeErrorText: 'CONFLICT in a.txt', blockError: 'EBUSY: resource busy' },
|
|
113
|
+
reconcileError: 'ETIMEDOUT: spawnSync node ETIMEDOUT',
|
|
114
|
+
});
|
|
115
|
+
assert.equal(s.outcome, 'not_completed');
|
|
116
|
+
assert.equal(s.cardState, 'done_unreconciled');
|
|
117
|
+
const txt = JSON.stringify(s.steps);
|
|
118
|
+
assert.match(txt, /EBUSY: resource busy/);
|
|
119
|
+
assert.match(txt, /ETIMEDOUT/);
|
|
120
|
+
assert.match(txt, /CONFLICT in a\.txt/);
|
|
121
|
+
assert.doesNotMatch(txt, /unknown error/i);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('TASK_2420: spawnFailureCause never returns "unknown error"', () => {
|
|
125
|
+
assert.match(spawnFailureCause({ status: null, stderr: '', stdout: '', error: Object.assign(new Error('spawnSync node ETIMEDOUT'), { code: 'ETIMEDOUT' }) }), /ETIMEDOUT/);
|
|
126
|
+
assert.match(spawnFailureCause({ status: null, signal: 'SIGTERM', stderr: '', stdout: '' }), /SIGTERM/);
|
|
127
|
+
assert.match(spawnFailureCause({ status: 3, stderr: '', stdout: '' }), /code 3/);
|
|
128
|
+
assert.equal(spawnFailureCause({ status: 1, stderr: 'boom\nmore' }), 'boom');
|
|
129
|
+
});
|
|
@@ -1766,6 +1766,98 @@ function classifyMergeFailureReason(g) {
|
|
|
1766
1766
|
return 'git_step_failed';
|
|
1767
1767
|
}
|
|
1768
1768
|
|
|
1769
|
+
/**
|
|
1770
|
+
* TASK_2420: the real cause of a failed spawnSync. stderr/stdout first, then the spawn
|
|
1771
|
+
* error (ENOENT / ETIMEDOUT), then the signal, then the exit code — never a bare "unknown".
|
|
1772
|
+
*/
|
|
1773
|
+
function spawnFailureCause(res) {
|
|
1774
|
+
if (!res) return 'no result from child process';
|
|
1775
|
+
const text = (res.stderr || res.stdout || '').toString().trim();
|
|
1776
|
+
if (text) return text.split('\n')[0];
|
|
1777
|
+
if (res.error) return `${res.error.code ? res.error.code + ': ' : ''}${res.error.message}`;
|
|
1778
|
+
if (res.signal) return `child killed by signal ${res.signal} (timeout?)`;
|
|
1779
|
+
return `child exited with code ${res.status} and no output`;
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* TASK_2420: git step that has nothing to integrate (task declared source-less: runtime /
|
|
1784
|
+
* config repair). Never skips when real work exists: a worktree or a task/<id> branch that
|
|
1785
|
+
* is ahead of the user branch means there IS something to merge, so that is a failure.
|
|
1786
|
+
*/
|
|
1787
|
+
function buildNoSourceGitResult(taskId, projectPath, worktreePath) {
|
|
1788
|
+
const skipReason = 'no branch: nothing to integrate';
|
|
1789
|
+
const taskBranch = `task/${taskId.toLowerCase()}`;
|
|
1790
|
+
const root = resolveProjectRoot(projectPath);
|
|
1791
|
+
const refuse = (why) => ({
|
|
1792
|
+
taskBranch, userBranch: null, originalBranch: null, committed: false, merged: false,
|
|
1793
|
+
verify_merge_landed: false, failure_reason: 'no_source_but_work_exists', blockedReason: why,
|
|
1794
|
+
});
|
|
1795
|
+
if (worktreePath) return refuse(`--no-source given but worktree ${worktreePath} exists; merge it or drop --no-source`);
|
|
1796
|
+
if (root && branchExists(taskBranch, root)) {
|
|
1797
|
+
const userBranch = resolveUserBranch(root);
|
|
1798
|
+
const ahead = userBranch ? git(`rev-list ${userBranch}..${taskBranch}`, { cwd: root, throws: false }) : null;
|
|
1799
|
+
if (ahead === null || ahead.trim()) {
|
|
1800
|
+
return refuse(`--no-source given but ${taskBranch} exists with commits not on ${userBranch}; merge it or drop --no-source`);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
return { taskBranch: null, userBranch: null, originalBranch: null, committed: false, merged: false,
|
|
1804
|
+
noChanges: true, gitSkipped: true, noSource: true, gitSkipReason: 'no_source', gitSkipDetail: skipReason };
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
/**
|
|
1808
|
+
* TASK_2420: truthful per-step summary of a postComplete() result.
|
|
1809
|
+
* outcome: 'completed' | 'completed_with_warnings' | 'not_completed'.
|
|
1810
|
+
* Semantics: a git step that failed means the card must NOT be reported completed — it is
|
|
1811
|
+
* moved to blocked/ (existing behaviour) and `cardState` says where it really is. Failures
|
|
1812
|
+
* after the merge landed (card bookkeeping) leave code delivered, so they are warnings.
|
|
1813
|
+
*/
|
|
1814
|
+
function summarizePostComplete(result) {
|
|
1815
|
+
const steps = [];
|
|
1816
|
+
const warnings = [];
|
|
1817
|
+
const g = result.git;
|
|
1818
|
+
let gitFailed = false;
|
|
1819
|
+
if (!g) {
|
|
1820
|
+
steps.push({ step: 'git', status: 'skipped', reason: 'git step not run' });
|
|
1821
|
+
} else if (isVerifiedMergeSuccess(g)) {
|
|
1822
|
+
steps.push({ step: 'git', status: 'ok' });
|
|
1823
|
+
} else if (g.noSource) {
|
|
1824
|
+
steps.push({ step: 'git', status: 'skipped', reason: g.gitSkipDetail });
|
|
1825
|
+
steps.push({ step: 'verify_merge', status: 'skipped', reason: g.gitSkipDetail });
|
|
1826
|
+
} else if (g.gitSkipped) {
|
|
1827
|
+
steps.push({ step: 'git', status: 'skipped', reason: g.gitSkipReason || 'git step skipped' });
|
|
1828
|
+
} else if (g.noGitRepo) {
|
|
1829
|
+
steps.push({ step: 'git', status: 'skipped', reason: 'not a git repository' });
|
|
1830
|
+
} else if (g.noChanges) {
|
|
1831
|
+
steps.push({ step: 'git', status: 'skipped', reason: g.memoryOnly ? 'memory-only task' : 'no changes within declared scope' });
|
|
1832
|
+
} else {
|
|
1833
|
+
gitFailed = true;
|
|
1834
|
+
const cause = [classifyMergeFailureReason(g), g.blockedReason, g.mergeErrorText, g.gitException, g.verify_merge_landed_reason]
|
|
1835
|
+
.filter(Boolean).map(s => String(s).split('\n')[0]).filter((s, i, a) => a.indexOf(s) === i).join(' | ');
|
|
1836
|
+
steps.push({ step: 'git', status: 'failed', reason: cause });
|
|
1837
|
+
}
|
|
1838
|
+
let cardState = null;
|
|
1839
|
+
if (gitFailed) {
|
|
1840
|
+
if (result.taskBlocked || result.reconciliationApplied) {
|
|
1841
|
+
cardState = 'blocked';
|
|
1842
|
+
steps.push({ step: 'move_blocked', status: 'ok' });
|
|
1843
|
+
} else if (result.reconciliationChecked) {
|
|
1844
|
+
cardState = 'active';
|
|
1845
|
+
steps.push({ step: 'move_blocked', status: 'failed', reason: g.blockError || 'card is not in done/ but could not be moved to blocked/' });
|
|
1846
|
+
} else {
|
|
1847
|
+
cardState = 'done_unreconciled';
|
|
1848
|
+
steps.push({ step: 'move_blocked', status: 'failed', reason: g.blockError || 'unknown' });
|
|
1849
|
+
steps.push({ step: 'reconcile', status: 'failed', reason: result.reconcileError || 'reconciliation did not run' });
|
|
1850
|
+
}
|
|
1851
|
+
} else if (g && !result.taskCompleted && result.completeError) {
|
|
1852
|
+
warnings.push(`card completion step failed: ${result.completeError || 'see log'}`);
|
|
1853
|
+
}
|
|
1854
|
+
if (result.forsetiL0 && result.forsetiL0.status === 'FAIL') {
|
|
1855
|
+
warnings.push(`Forseti L0: ${result.forsetiL0.failures.map(f => f.message).join('; ')}`);
|
|
1856
|
+
}
|
|
1857
|
+
const outcome = gitFailed ? 'not_completed' : (warnings.length ? 'completed_with_warnings' : 'completed');
|
|
1858
|
+
return { outcome, cardState, steps, warnings };
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1769
1861
|
function blockTaskForMergeFailure(taskId, projectPath, gitResult) {
|
|
1770
1862
|
if (!taskId) return false;
|
|
1771
1863
|
|
|
@@ -1846,7 +1938,9 @@ function blockTaskForMergeFailure(taskId, projectPath, gitResult) {
|
|
|
1846
1938
|
|
|
1847
1939
|
if (updateResult.status !== 0) {
|
|
1848
1940
|
const errMsg = (updateResult.stderr || updateResult.stdout || '').trim();
|
|
1849
|
-
|
|
1941
|
+
const cause = spawnFailureCause(updateResult);
|
|
1942
|
+
console.log(` ⚠️ Failed to move ${taskId} to blocked/: ${cause}`);
|
|
1943
|
+
if (gitResult) gitResult.blockError = cause;
|
|
1850
1944
|
return false;
|
|
1851
1945
|
}
|
|
1852
1946
|
|
|
@@ -2124,6 +2218,7 @@ function postComplete(opts = {}) {
|
|
|
2124
2218
|
formation,
|
|
2125
2219
|
skill,
|
|
2126
2220
|
worktreePath = process.env.FORMATION_WORKTREE_PATH || null,
|
|
2221
|
+
noSource = false,
|
|
2127
2222
|
} = opts;
|
|
2128
2223
|
|
|
2129
2224
|
// B11: opportunistic GC of orphan worktrees from prior failed dispatches
|
|
@@ -2244,7 +2339,13 @@ function postComplete(opts = {}) {
|
|
|
2244
2339
|
// branch commits + the YAML move enter main).
|
|
2245
2340
|
// Flag absent (default) => legacy gitBranchAndMerge path, byte-identical
|
|
2246
2341
|
// to previous behavior — rollback is trivial. Dry runs stay on legacy.
|
|
2247
|
-
if (
|
|
2342
|
+
if (noSource) {
|
|
2343
|
+
// TASK_2420: explicit source-less completion (runtime/config repair, no branch).
|
|
2344
|
+
gitResult = buildNoSourceGitResult(taskId, projectPath, worktreePath);
|
|
2345
|
+
console.log(gitResult.noSource
|
|
2346
|
+
? ` ⏭️ git merge/verify skipped (${gitResult.gitSkipDetail})`
|
|
2347
|
+
: ` ❌ --no-source refused: ${gitResult.blockedReason}`);
|
|
2348
|
+
} else if (process.env.KENAZ_INTEGRATION_QUEUE === '1' && !dryRun) {
|
|
2248
2349
|
gitResult = require('./integration.js').integrateForPostComplete({ taskId, projectPath, message });
|
|
2249
2350
|
} else {
|
|
2250
2351
|
gitResult = gitBranchAndMerge({ taskId, message, dryRun, projectPath, skipTests, testCommands, worktreePath });
|
|
@@ -2380,10 +2481,12 @@ function postComplete(opts = {}) {
|
|
|
2380
2481
|
result.taskCompleted = true;
|
|
2381
2482
|
console.log(` ✅ Task ${taskId} already in done/`);
|
|
2382
2483
|
} else {
|
|
2383
|
-
|
|
2484
|
+
result.completeError = spawnFailureCause(completeResult);
|
|
2485
|
+
console.log(` ⚠️ Failed to complete task: ${result.completeError}`);
|
|
2384
2486
|
}
|
|
2385
2487
|
}
|
|
2386
2488
|
} catch (e) {
|
|
2489
|
+
result.completeError = e.message;
|
|
2387
2490
|
console.log(` ⚠️ Task complete error: ${e.message}`);
|
|
2388
2491
|
}
|
|
2389
2492
|
} else if (taskId && !dryRun && result.git && result.git.noChanges) {
|
|
@@ -2411,10 +2514,12 @@ function postComplete(opts = {}) {
|
|
|
2411
2514
|
result.taskCompleted = true;
|
|
2412
2515
|
console.log(` ✅ Task ${taskId} already in done/`);
|
|
2413
2516
|
} else {
|
|
2414
|
-
|
|
2517
|
+
result.completeError = spawnFailureCause(completeResult);
|
|
2518
|
+
console.log(` ⚠️ Failed to complete task: ${result.completeError}`);
|
|
2415
2519
|
}
|
|
2416
2520
|
}
|
|
2417
2521
|
} catch (e) {
|
|
2522
|
+
result.completeError = e.message;
|
|
2418
2523
|
console.log(` ⚠️ Task complete error: ${e.message}`);
|
|
2419
2524
|
}
|
|
2420
2525
|
} else if (taskId && result.git && !isVerifiedMergeSuccess(result.git) && !result.git.noGitRepo && !result.git.noChanges) {
|
|
@@ -2507,12 +2612,14 @@ function postComplete(opts = {}) {
|
|
|
2507
2612
|
console.log(` 🚨 [TASK_1536] Reconciliation: task ${taskId} was in done/ but merge did not land — moved to blocked/ (failure_reason=${reconcileVitals.failure_reason})`);
|
|
2508
2613
|
} else if (reconcileResult.status === 0) {
|
|
2509
2614
|
// task was not in done/ — already blocked or active, nothing to reconcile
|
|
2615
|
+
result.reconciliationChecked = true;
|
|
2510
2616
|
console.log(` ✅ [TASK_1536] Reconciliation check: task ${taskId} not in done/ — no reconciliation needed`);
|
|
2511
2617
|
} else {
|
|
2512
|
-
|
|
2513
|
-
console.log(` ⚠️ [TASK_1536] Reconciliation failed: ${
|
|
2618
|
+
result.reconcileError = spawnFailureCause(reconcileResult);
|
|
2619
|
+
console.log(` ⚠️ [TASK_1536] Reconciliation failed: ${result.reconcileError}`);
|
|
2514
2620
|
}
|
|
2515
2621
|
} catch (reconcileErr) {
|
|
2622
|
+
result.reconcileError = reconcileErr.message || String(reconcileErr);
|
|
2516
2623
|
console.log(` ⚠️ [TASK_1536] Reconciliation error (non-fatal): ${(reconcileErr.message || '').split('\n')[0]}`);
|
|
2517
2624
|
}
|
|
2518
2625
|
}
|
|
@@ -2544,10 +2651,12 @@ function postComplete(opts = {}) {
|
|
|
2544
2651
|
result.taskCompleted = true;
|
|
2545
2652
|
console.log(` ✅ Task ${taskId} already in done/`);
|
|
2546
2653
|
} else {
|
|
2547
|
-
|
|
2654
|
+
result.completeError = spawnFailureCause(moveResult);
|
|
2655
|
+
console.log(` ⚠️ Safety net move failed: ${result.completeError}`);
|
|
2548
2656
|
}
|
|
2549
2657
|
}
|
|
2550
2658
|
} catch (e) {
|
|
2659
|
+
result.completeError = e.message;
|
|
2551
2660
|
console.log(` ⚠️ Safety net error: ${e.message}`);
|
|
2552
2661
|
}
|
|
2553
2662
|
}
|
|
@@ -3106,6 +3215,14 @@ function postComplete(opts = {}) {
|
|
|
3106
3215
|
updatePostCompleteGuardOutcome(guardFile, taskId, passSucceeded ? 'success' : 'failure');
|
|
3107
3216
|
}
|
|
3108
3217
|
|
|
3218
|
+
// TASK_2420: truthful outcome — never "completed" when a required step failed.
|
|
3219
|
+
result.summary = summarizePostComplete(result);
|
|
3220
|
+
if (taskId && !dryRun && result.summary.outcome !== 'completed') {
|
|
3221
|
+
console.log(`── Outcome: ${result.summary.outcome.toUpperCase()} ──`);
|
|
3222
|
+
for (const st of result.summary.steps) console.log(` ${st.status === 'failed' ? '❌' : st.status === 'skipped' ? '⏭️ ' : '✅'} ${st.step}: ${st.status}${st.reason ? ' — ' + st.reason : ''}`);
|
|
3223
|
+
for (const w of result.summary.warnings) console.log(` ⚠️ ${w}`);
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3109
3226
|
return result;
|
|
3110
3227
|
}
|
|
3111
3228
|
|
|
@@ -3131,6 +3248,7 @@ Options:
|
|
|
3131
3248
|
--keep N 保留最新 N 個 done 任務(預設 10)
|
|
3132
3249
|
--skip-archive 跳過 archive 檢查
|
|
3133
3250
|
--skip-git 跳過 git 分支管理
|
|
3251
|
+
--no-source 無 source 任務(runtime/config 修復,無 branch):git merge/verify 標記 skipped
|
|
3134
3252
|
--skip-tests 跳過回歸測試(PPL-113)
|
|
3135
3253
|
--test-cmd "CMD" Agent 指定的測試指令(可多次指定,PPL-113)
|
|
3136
3254
|
--message "MSG" 自訂 commit message
|
|
@@ -3184,6 +3302,7 @@ Examples:
|
|
|
3184
3302
|
const keep = getArg('--keep') ? parseInt(getArg('--keep'), 10) : CONFIG.DEFAULT_KEEP;
|
|
3185
3303
|
const skipArchive = args.includes('--skip-archive');
|
|
3186
3304
|
const skipGit = args.includes('--skip-git');
|
|
3305
|
+
const noSource = args.includes('--no-source');
|
|
3187
3306
|
const skipTests = args.includes('--skip-tests');
|
|
3188
3307
|
const dryRun = args.includes('--dry-run');
|
|
3189
3308
|
const message = getArg('--message');
|
|
@@ -3206,7 +3325,7 @@ Examples:
|
|
|
3206
3325
|
}
|
|
3207
3326
|
|
|
3208
3327
|
try {
|
|
3209
|
-
postComplete({ taskId, keep, skipArchive, skipGit, skipTests, dryRun, message, projectPath, testCommands, worktreePath });
|
|
3328
|
+
postComplete({ taskId, keep, skipArchive, skipGit, skipTests, dryRun, message, projectPath, testCommands, worktreePath, noSource });
|
|
3210
3329
|
} catch (e) {
|
|
3211
3330
|
console.error(`❌ Post-complete failed: ${e.message}`);
|
|
3212
3331
|
process.exit(1);
|
|
@@ -3217,6 +3336,8 @@ Examples:
|
|
|
3217
3336
|
// ?????????????????????????????????????????????????????????????????????????????
|
|
3218
3337
|
module.exports = {
|
|
3219
3338
|
classifyMergeFailureReason,
|
|
3339
|
+
summarizePostComplete,
|
|
3340
|
+
spawnFailureCause,
|
|
3220
3341
|
postComplete,
|
|
3221
3342
|
archiveCheck,
|
|
3222
3343
|
gitBranchAndMerge,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"28d36a7a-fcf1-488c-a1ed-d794ac52615f":{"files":["reference_worktree_rust_verify_recipe.md","feedback_mcp_default_project_drift.md","feedback_mark_landed_after_scoped_merge.md","feedback_heredoc_template_literal_escapes.md","reference_dashboard_release_procedure.md"],"lastFiredAtMs":1790248806590,"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge"]},"30cd222d-1a83-4617-a267-65ce8ec74a3e":{"files":["feedback_mcp_default_project_drift.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790249042951},"a0067f0e-60c1-4713-bdcb-8a34cd5205fd":{"files":["feedback_heredoc_template_literal_escapes.md","feedback_mcp_default_project_drift.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790259958980},"ee35d32d-321b-47e3-8a30-a8e096995cdd":{"files":["reference_worktree_rust_verify_recipe.md","feedback_never_cd_into_agent_worktrees.md","feedback_agent_tool_worktree_collision.md","feedback_mark_landed_after_scoped_merge.md","feedback_heredoc_template_literal_escapes.md","feedback_mcp_default_project_drift.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness"],"lastFiredAtMs":1790276539381},"1531340e-bf07-4bd6-909c-f22394d60876":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process"],"lastFiredAtMs":1790279018827},"73e6ee82-700b-4cbf-b002-c0b9b79dbab4":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process"],"lastFiredAtMs":1790365961440},"0722c428-a54f-47dc-9c1c-e12c1199dfe3":{"files":["feedback_never_cd_into_agent_worktrees.md","feedback_heredoc_template_literal_escapes.md","feedback_mark_landed_after_scoped_merge.md","feedback_agent_tool_worktree_collision.md","rune_synapse_incremental_index_blind_gap.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process"],"lastFiredAtMs":1790418630509},"f17d4fd3-7d6c-4e5e-9369-2b72a9266f90":{"files":["feedback_never_cd_into_agent_worktrees.md","feedback_heredoc_template_literal_escapes.md","rune_synapse_incremental_index_blind_gap.md","reference_dashboard_release_procedure.md","feedback_scoped_checkout_clobbers_worktree_state.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1790457931617},"6794bd6e-562a-4b58-a746-b5bdcaca0e7c":{"files":["feedback_mark_landed_after_scoped_merge.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge"],"lastFiredAtMs":1790455100260},"75239ce3-f0a2-4792-81f5-d842d132528f":{"files":["feedback_never_cd_into_agent_worktrees.md","feedback_mark_landed_after_scoped_merge.md","feedback_agent_tool_worktree_collision.md","feedback_heredoc_template_literal_escapes.md","reference_dashboard_release_procedure.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1790507402115},"804ea3d7-3de3-4586-b955-e6c8c684ff15":{"files":["feedback_heredoc_template_literal_escapes.md","feedback_never_cd_into_agent_worktrees.md","feedback_mcp_default_project_drift.md","feedback_mark_landed_after_scoped_merge.md","reference_worktree_rust_verify_recipe.md","reference_dashboard_release_procedure.md","feedback_agent_tool_worktree_collision.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness"],"lastFiredAtMs":1790581324936},"3e9b8a3f-882d-45d4-bbe5-a258b2bb3ce4":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790542391812},"3e15f2bf-f80a-4e4d-8960-bcd1a640fdff":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790543837477},"61843060-69da-46a7-b86f-e5a0b342cea8":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790581238348},"5b87c0bf-873f-4d27-a261-fbde5ea03299":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790619871099},"9c6a266c-9db4-4810-a341-5ffcd1de8726":{"files":["reference_dashboard_release_procedure.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790621819503},"12bd9885-66a8-4c0c-9811-0b327d551fc0":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790629466743},"bb010604-4dca-4993-9de0-aecb4754ad8e":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790666206918},"4b12601f-6069-452b-a58c-bf8263400324":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790666901610},"4df219ec-ba5e-4f76-97c5-a43137f300de":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1790713272079},"3eecd2fc-56d7-4ee8-9a4f-2290da3fd123":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790718864114},"a806aaa3-3eaa-46bf-a9f2-f30cfa33acaa":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":[],"lastFiredAtMs":1790786463472},"c699f823-b467-4f50-ab73-e7351250a897":{"files":["reference_dashboard_release_procedure.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1790790894539},"2a1ccb2b-e66f-4b3a-a4e6-2ec48622defe":{"files":["rune_synapse_incremental_index_blind_gap.md","feedback_mcp_default_project_drift.md","reference_worktree_rust_verify_recipe.md","feedback_never_cd_into_agent_worktrees.md","feedback_heredoc_template_literal_escapes.md","feedback_agent_tool_worktree_collision.md","feedback_mark_landed_after_scoped_merge.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness"],"lastFiredAtMs":1790868373263},"9782d641-82fa-4c35-acf6-97758550adbb":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge"],"lastFiredAtMs":1790806751702},"cd5fc5ea-1d77-4c15-8b09-3bcb5da02559":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790863308920}}
|
|
1
|
+
{"28d36a7a-fcf1-488c-a1ed-d794ac52615f":{"files":["reference_worktree_rust_verify_recipe.md","feedback_mcp_default_project_drift.md","feedback_mark_landed_after_scoped_merge.md","feedback_heredoc_template_literal_escapes.md","reference_dashboard_release_procedure.md"],"lastFiredAtMs":1790248806590,"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge"]},"30cd222d-1a83-4617-a267-65ce8ec74a3e":{"files":["feedback_mcp_default_project_drift.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790249042951},"a0067f0e-60c1-4713-bdcb-8a34cd5205fd":{"files":["feedback_heredoc_template_literal_escapes.md","feedback_mcp_default_project_drift.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790259958980},"ee35d32d-321b-47e3-8a30-a8e096995cdd":{"files":["reference_worktree_rust_verify_recipe.md","feedback_never_cd_into_agent_worktrees.md","feedback_agent_tool_worktree_collision.md","feedback_mark_landed_after_scoped_merge.md","feedback_heredoc_template_literal_escapes.md","feedback_mcp_default_project_drift.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness"],"lastFiredAtMs":1790276539381},"1531340e-bf07-4bd6-909c-f22394d60876":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process"],"lastFiredAtMs":1790279018827},"73e6ee82-700b-4cbf-b002-c0b9b79dbab4":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process"],"lastFiredAtMs":1790365961440},"0722c428-a54f-47dc-9c1c-e12c1199dfe3":{"files":["feedback_never_cd_into_agent_worktrees.md","feedback_heredoc_template_literal_escapes.md","feedback_mark_landed_after_scoped_merge.md","feedback_agent_tool_worktree_collision.md","rune_synapse_incremental_index_blind_gap.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process"],"lastFiredAtMs":1790418630509},"f17d4fd3-7d6c-4e5e-9369-2b72a9266f90":{"files":["feedback_never_cd_into_agent_worktrees.md","feedback_heredoc_template_literal_escapes.md","rune_synapse_incremental_index_blind_gap.md","reference_dashboard_release_procedure.md","feedback_scoped_checkout_clobbers_worktree_state.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1790457931617},"6794bd6e-562a-4b58-a746-b5bdcaca0e7c":{"files":["feedback_mark_landed_after_scoped_merge.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge"],"lastFiredAtMs":1790455100260},"75239ce3-f0a2-4792-81f5-d842d132528f":{"files":["feedback_never_cd_into_agent_worktrees.md","feedback_mark_landed_after_scoped_merge.md","feedback_agent_tool_worktree_collision.md","feedback_heredoc_template_literal_escapes.md","reference_dashboard_release_procedure.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1790507402115},"804ea3d7-3de3-4586-b955-e6c8c684ff15":{"files":["feedback_heredoc_template_literal_escapes.md","feedback_never_cd_into_agent_worktrees.md","feedback_mcp_default_project_drift.md","feedback_mark_landed_after_scoped_merge.md","reference_worktree_rust_verify_recipe.md","reference_dashboard_release_procedure.md","feedback_agent_tool_worktree_collision.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness"],"lastFiredAtMs":1790581324936},"3e9b8a3f-882d-45d4-bbe5-a258b2bb3ce4":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790542391812},"3e15f2bf-f80a-4e4d-8960-bcd1a640fdff":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790543837477},"61843060-69da-46a7-b86f-e5a0b342cea8":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790581238348},"5b87c0bf-873f-4d27-a261-fbde5ea03299":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790619871099},"9c6a266c-9db4-4810-a341-5ffcd1de8726":{"files":["reference_dashboard_release_procedure.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790621819503},"12bd9885-66a8-4c0c-9811-0b327d551fc0":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790629466743},"bb010604-4dca-4993-9de0-aecb4754ad8e":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790666206918},"4b12601f-6069-452b-a58c-bf8263400324":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790666901610},"4df219ec-ba5e-4f76-97c5-a43137f300de":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1790713272079},"3eecd2fc-56d7-4ee8-9a4f-2290da3fd123":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790718864114},"a806aaa3-3eaa-46bf-a9f2-f30cfa33acaa":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":[],"lastFiredAtMs":1790786463472},"c699f823-b467-4f50-ab73-e7351250a897":{"files":["reference_dashboard_release_procedure.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1790790894539},"2a1ccb2b-e66f-4b3a-a4e6-2ec48622defe":{"files":["rune_synapse_incremental_index_blind_gap.md","feedback_mcp_default_project_drift.md","reference_worktree_rust_verify_recipe.md","feedback_never_cd_into_agent_worktrees.md","feedback_heredoc_template_literal_escapes.md","feedback_agent_tool_worktree_collision.md","feedback_mark_landed_after_scoped_merge.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Yggdrasil, Alaya, relay & products","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Ansuz cognition & process","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Hooks & Claude Code harness"],"lastFiredAtMs":1790868373263},"9782d641-82fa-4c35-acf6-97758550adbb":{"files":["feedback_heredoc_template_literal_escapes.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge"],"lastFiredAtMs":1790806751702},"cd5fc5ea-1d77-4c15-8b09-3bcb5da02559":{"files":[],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Synapse, KuzuDB & recall"],"lastFiredAtMs":1790863308920},"566fcb6b-3fdb-4c39-801c-824eaeeadfbc":{"files":["feedback_agent_tool_worktree_collision.md","feedback_mark_landed_after_scoped_merge.md","feedback_worktree_remove_junction_empties_main.md","feedback_never_cd_into_agent_worktrees.md","feedback_heredoc_template_literal_escapes.md","feedback_rust_merge_restarts_live_dashboard.md","reference_worktree_rust_verify_recipe.md","feedback_never_truncate_tsc_output.md","reference_dashboard_release_procedure.md","feedback_cargo_feature_change_verify_tauri_dev.md","feedback_eprintln_not_in_backend_log.md"],"areas":["C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Worktree, dispatch & merge","C:\\Users\\user\\.claude\\projects\\c--Users-user-Documents-GitHub-KenazAI\\memory\\KNOWLEDGE.md::Tauri, Rust build & release"],"lastFiredAtMs":1791717483417}}
|