@agfpd/iapeer-memory 0.2.7 → 0.2.8
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/package.json +2 -2
- package/src/cli.ts +9 -7
- package/src/commands/dream-collect.ts +645 -0
- package/src/commands/init.ts +11 -2
- package/src/commands/update.ts +13 -2
- package/src/commands/verify.ts +20 -3
- package/src/fleet.ts +1 -1
- package/src/paths.ts +4 -0
- package/src/provision.ts +14 -0
- package/src/templates/roles-en.ts +82 -56
- package/src/templates/roles-ru.ts +80 -51
- package/src/watcher.ts +56 -14
- package/src/commands/dream-paths.ts +0 -153
package/src/commands/init.ts
CHANGED
|
@@ -51,11 +51,13 @@ import {
|
|
|
51
51
|
} from "../templates/index.js";
|
|
52
52
|
import { packageVersion } from "../version.js";
|
|
53
53
|
import {
|
|
54
|
+
DREAM_TARGET,
|
|
54
55
|
dreamTimerMessage,
|
|
55
56
|
patchWakePolicyEphemeral,
|
|
56
57
|
registerTimer,
|
|
57
58
|
registerWatcher,
|
|
58
59
|
sweepTimerMessage,
|
|
60
|
+
writeDreamGateScript,
|
|
59
61
|
writeLauncherScript,
|
|
60
62
|
writeStaleCheckScript,
|
|
61
63
|
} from "../watcher.js";
|
|
@@ -402,8 +404,15 @@ export async function cmdInit(argv: string[], egress: Egress): Promise<number> {
|
|
|
402
404
|
message: sweepTimerMessage({ checkScriptPath: paths.checkScriptPath }),
|
|
403
405
|
iapeerBin: flags.iapeerBin,
|
|
404
406
|
});
|
|
407
|
+
writeDreamGateScript({
|
|
408
|
+
dreamGateScriptPath: paths.dreamGateScriptPath,
|
|
409
|
+
binaryPath: paths.binaryPath,
|
|
410
|
+
});
|
|
405
411
|
const dream = registerTimer(egress, {
|
|
406
|
-
message: dreamTimerMessage(
|
|
412
|
+
message: dreamTimerMessage({
|
|
413
|
+
cron: process.env.IAPEER_MEMORY_DREAM_CRON,
|
|
414
|
+
dreamGateScriptPath: paths.dreamGateScriptPath,
|
|
415
|
+
}),
|
|
407
416
|
iapeerBin: flags.iapeerBin,
|
|
408
417
|
});
|
|
409
418
|
const timersSandboxed = sweep.suppressed && dream.suppressed;
|
|
@@ -412,7 +421,7 @@ export async function cmdInit(argv: string[], egress: Egress): Promise<number> {
|
|
|
412
421
|
timersSandboxed
|
|
413
422
|
? "skipped (test sandbox — sends suppressed)"
|
|
414
423
|
: sweep.ok && dream.ok
|
|
415
|
-
? `sweep (@every 1h, check ${paths.checkScriptPath}) + dream-tick (weekly
|
|
424
|
+
? `sweep (@every 1h, check ${paths.checkScriptPath}) + dream-tick (weekly, gated, → ${DREAM_TARGET})`
|
|
416
425
|
: `sweep: ${sweep.ok ? "sent" : sweep.detail}; dream: ${dream.ok ? "sent" : dream.detail}`,
|
|
417
426
|
Boolean(timersSandboxed) || (sweep.ok && dream.ok),
|
|
418
427
|
);
|
package/src/commands/update.ts
CHANGED
|
@@ -51,10 +51,12 @@ import { mcpPort } from "./provision-peer.js";
|
|
|
51
51
|
import { guideText, materialiseTemplates } from "../templates/index.js";
|
|
52
52
|
import { packageVersion } from "../version.js";
|
|
53
53
|
import {
|
|
54
|
+
DREAM_TARGET,
|
|
54
55
|
dreamTimerMessage,
|
|
55
56
|
registerTimer,
|
|
56
57
|
registerWatcher,
|
|
57
58
|
sweepTimerMessage,
|
|
59
|
+
writeDreamGateScript,
|
|
58
60
|
writeLauncherScript,
|
|
59
61
|
writeStaleCheckScript,
|
|
60
62
|
} from "../watcher.js";
|
|
@@ -245,18 +247,27 @@ export function cmdUpdate(argv: string[], egress: Egress): number {
|
|
|
245
247
|
} catch {
|
|
246
248
|
// unprovisioned env — registrations below still re-target
|
|
247
249
|
}
|
|
250
|
+
writeDreamGateScript({
|
|
251
|
+
dreamGateScriptPath: paths.dreamGateScriptPath,
|
|
252
|
+
binaryPath: paths.binaryPath,
|
|
253
|
+
});
|
|
248
254
|
const w = registerWatcher(egress, { launcherPath: paths.launcherPath });
|
|
249
255
|
const s = registerTimer(egress, {
|
|
250
256
|
message: sweepTimerMessage({ checkScriptPath: paths.checkScriptPath }),
|
|
251
257
|
});
|
|
252
|
-
const d = registerTimer(egress, {
|
|
258
|
+
const d = registerTimer(egress, {
|
|
259
|
+
message: dreamTimerMessage({
|
|
260
|
+
cron: process.env.IAPEER_MEMORY_DREAM_CRON,
|
|
261
|
+
dreamGateScriptPath: paths.dreamGateScriptPath,
|
|
262
|
+
}),
|
|
263
|
+
});
|
|
253
264
|
const sandboxed = w.suppressed && s.suppressed && d.suppressed;
|
|
254
265
|
step(
|
|
255
266
|
"triggers",
|
|
256
267
|
sandboxed
|
|
257
268
|
? "skipped (test sandbox — sends suppressed)"
|
|
258
269
|
: w.ok && s.ok && d.ok
|
|
259
|
-
? `re-sent: event→scriber, sweep
|
|
270
|
+
? `re-sent: event→scriber, sweep→index, dream→${DREAM_TARGET} (gated; same id = replace); confirm: verify`
|
|
260
271
|
: `event: ${w.ok ? "sent" : w.detail}; sweep: ${s.ok ? "sent" : s.detail}; dream: ${d.ok ? "sent" : d.detail}`,
|
|
261
272
|
Boolean(sandboxed) || (w.ok && s.ok && d.ok),
|
|
262
273
|
);
|
package/src/commands/verify.ts
CHANGED
|
@@ -35,6 +35,7 @@ import { checkFleetSurfaces, sweepProvision } from "../surfaces/sweep.js";
|
|
|
35
35
|
import { mcpPort } from "./provision-peer.js";
|
|
36
36
|
import { packageVersion } from "../version.js";
|
|
37
37
|
import {
|
|
38
|
+
DREAM_TARGET,
|
|
38
39
|
dreamTimerMessage,
|
|
39
40
|
DEFAULT_EVENT_TARGET,
|
|
40
41
|
DREAM_TRIGGER_ID,
|
|
@@ -43,6 +44,7 @@ import {
|
|
|
43
44
|
registerWatcher,
|
|
44
45
|
sweepTimerMessage,
|
|
45
46
|
SWEEP_TRIGGER_ID,
|
|
47
|
+
writeDreamGateScript,
|
|
46
48
|
writeLauncherScript,
|
|
47
49
|
writeStaleCheckScript,
|
|
48
50
|
WATCHER_TRIGGER_ID,
|
|
@@ -385,9 +387,24 @@ export function runVerify(egress: Egress, opts: VerifyOptions = {}): CheckResult
|
|
|
385
387
|
id: DREAM_TRIGGER_ID,
|
|
386
388
|
role: "time",
|
|
387
389
|
expect: (t) =>
|
|
388
|
-
t.target !==
|
|
389
|
-
|
|
390
|
-
|
|
390
|
+
t.target !== DREAM_TARGET
|
|
391
|
+
? `target is ${t.target ?? "?"}, expected ${DREAM_TARGET}`
|
|
392
|
+
: (t as { check?: string }).check !== paths.dreamGateScriptPath
|
|
393
|
+
? `check is ${(t as { check?: string }).check ?? "?"}, expected ${paths.dreamGateScriptPath}`
|
|
394
|
+
: null,
|
|
395
|
+
repairSend: () => {
|
|
396
|
+
writeDreamGateScript({
|
|
397
|
+
dreamGateScriptPath: paths.dreamGateScriptPath,
|
|
398
|
+
binaryPath: paths.binaryPath,
|
|
399
|
+
});
|
|
400
|
+
return registerTimer(egress, {
|
|
401
|
+
message: dreamTimerMessage({
|
|
402
|
+
cron: process.env.IAPEER_MEMORY_DREAM_CRON,
|
|
403
|
+
dreamGateScriptPath: paths.dreamGateScriptPath,
|
|
404
|
+
}),
|
|
405
|
+
iapeerBin: opts.iapeerBin,
|
|
406
|
+
});
|
|
407
|
+
},
|
|
391
408
|
},
|
|
392
409
|
];
|
|
393
410
|
for (const c of checks) {
|
package/src/fleet.ts
CHANGED
|
@@ -80,7 +80,7 @@ export function readFleetMap(fleetMapPath: string): FleetPeer[] | null {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/** Live-registry query — the ONE place `iapeer list --json` is parsed.
|
|
83
|
-
* Shared by writeFleetMap (the persisted map) and dream-
|
|
83
|
+
* Shared by writeFleetMap (the persisted map) and dream-collect (the
|
|
84
84
|
* tick-time resolution; freshness fact: birth does NOT touch fleet.json
|
|
85
85
|
* and the SessionStart kick is heartbeat-gated, so the LIVE registry is
|
|
86
86
|
* the only source that sees a newborn before the next update). */
|
package/src/paths.ts
CHANGED
|
@@ -56,6 +56,9 @@ export type MemoryPaths = {
|
|
|
56
56
|
launcherPath: string;
|
|
57
57
|
/** Sweep check-script — gates the fail-open inbox sweep (ADR-015). */
|
|
58
58
|
checkScriptPath: string;
|
|
59
|
+
/** Dream-tick gate check-script — the notifier `check` for the weekly timer
|
|
60
|
+
* (shells the registry-free `dream-collect --gate`; a dead week wakes no one). */
|
|
61
|
+
dreamGateScriptPath: string;
|
|
59
62
|
/** Fleet map (personality → cwd) — written by init/update/verify --repair
|
|
60
63
|
* from `iapeer list --json`, consumed by memoryd's fragment renderer
|
|
61
64
|
* (docs/05; дыра 10.06: без карты пиры не получали paths-блок и индекс). */
|
|
@@ -99,6 +102,7 @@ export function memoryPaths(
|
|
|
99
102
|
hooksDir: path.join(path.dirname(configFile), "hooks"),
|
|
100
103
|
launcherPath: path.join(path.dirname(configFile), "memoryd-launcher.sh"),
|
|
101
104
|
checkScriptPath: path.join(path.dirname(configFile), "inbox-stale-check.sh"),
|
|
105
|
+
dreamGateScriptPath: path.join(path.dirname(configFile), "dream-tick-gate.sh"),
|
|
102
106
|
fleetMapPath: path.join(stateDir, "fleet.json"),
|
|
103
107
|
};
|
|
104
108
|
}
|
package/src/provision.ts
CHANGED
|
@@ -176,6 +176,20 @@ export function defaultConfigContent(opts: ConfigContentOptions): string {
|
|
|
176
176
|
"# Curator personalities exempt from needs_review stamping (ADR-006).",
|
|
177
177
|
"# IAPEER_MEMORY_CURATOR_SET=index,scriber,dreamweaver",
|
|
178
178
|
"",
|
|
179
|
+
"# Weekly dream-tick (deterministic pre-filter → DreamWeaver). Schedule is",
|
|
180
|
+
"# 5-field cron; the window is days BY TIME (not since-last-tick).",
|
|
181
|
+
"# IAPEER_MEMORY_DREAM_CRON=0 4 * * 1",
|
|
182
|
+
"# IAPEER_MEMORY_DREAM_WINDOW_DAYS=7",
|
|
183
|
+
"# description longer than this many chars → a reformulation candidate.",
|
|
184
|
+
"# IAPEER_MEMORY_DREAM_DESC_MAXLEN=250",
|
|
185
|
+
"# >threshold new notes in a folder → its own subagent; smaller folders are",
|
|
186
|
+
"# grouped up to the cap (sum of per-folder weights).",
|
|
187
|
+
"# IAPEER_MEMORY_DREAM_BATCH_THRESHOLD=20",
|
|
188
|
+
"# IAPEER_MEMORY_DREAM_GROUP_CAP=20",
|
|
189
|
+
"# Per-folder cap on transcripts handed to phase D (most recent N by mtime;",
|
|
190
|
+
"# bounds an ephemeral worker's hundreds of sessions). 0 = uncapped.",
|
|
191
|
+
"# IAPEER_MEMORY_DREAM_TRANSCRIPT_CAP=20",
|
|
192
|
+
"",
|
|
179
193
|
].join("\n");
|
|
180
194
|
}
|
|
181
195
|
|
|
@@ -51,17 +51,12 @@ different world.
|
|
|
51
51
|
scriber thread stalled: place the stale drafts UNVETTED by the usual
|
|
52
52
|
rules; \`needs_review: true\` already travels with each file. The
|
|
53
53
|
Scriber re-vets them with the next PERMANENT_BATCH once alive.
|
|
54
|
-
- **
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
transcripts}\` — copy \`transcripts\` from the verb's output AS IS
|
|
61
|
-
(globs + the codex cwdFilter; path forms are the code's zone, not
|
|
62
|
-
yours). A verb error = report to the owner, never guess the fleet. On
|
|
63
|
-
the consolidation report: archive what it deprecated, act on its
|
|
64
|
-
\`attention\` blocks yourself.
|
|
54
|
+
- **DreamWeaver consolidation report** (weekly) — DreamWeaver now
|
|
55
|
+
orchestrates the tick (a deterministic pre-filter finds the work, it
|
|
56
|
+
fans out subagents); you are OFF the entry and only FINALISE. On its
|
|
57
|
+
report: archive each note it deprecated (move to the archive subfolder),
|
|
58
|
+
build the links section for each new merged note via vault_search, and
|
|
59
|
+
act on its \`attention\` items yourself.
|
|
65
60
|
- **Direct IAP** from agents or the human — structure questions; never
|
|
66
61
|
run searches for others (they have their own vault tools).
|
|
67
62
|
|
|
@@ -114,8 +109,8 @@ it under the usual three conditions.
|
|
|
114
109
|
Never write note content (authors own it); never answer other agents'
|
|
115
110
|
search requests; never dispatch the Scriber (events reach it directly —
|
|
116
111
|
it reports to you); never detect events yourself (memoryd detects, the
|
|
117
|
-
notifier delivers); never
|
|
118
|
-
|
|
112
|
+
notifier delivers); never orchestrate the dream-tick (DreamWeaver owns it
|
|
113
|
+
end to end now — you only finalise on its report).
|
|
119
114
|
`;
|
|
120
115
|
|
|
121
116
|
export const SCRIBER_DOCTRINE_EN = `---
|
|
@@ -233,47 +228,78 @@ locale: en
|
|
|
233
228
|
---
|
|
234
229
|
# DreamWeaver — sleep-cycle memory consolidation
|
|
235
230
|
|
|
236
|
-
You are DreamWeaver: an ephemeral worker peer
|
|
237
|
-
|
|
238
|
-
(never guess it
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
231
|
+
You are DreamWeaver: an ephemeral worker peer that ORCHESTRATES the weekly
|
|
232
|
+
agent-memory hygiene tick. Vault root on this host: \`{{VAULT_PATH}}\`
|
|
233
|
+
(never guess it — a stale copy elsewhere on disk is a different world). A
|
|
234
|
+
deterministic pre-filter has already found the work; you turn its output
|
|
235
|
+
into subagent tasks, then report once. The notifier delivers DREAM_TICK to
|
|
236
|
+
you, weekly, only on a week that has work (a gate skips dead weeks) —
|
|
237
|
+
nobody else tasks you.
|
|
238
|
+
|
|
239
|
+
## Running the tick
|
|
240
|
+
|
|
241
|
+
1. Run \`iapeer-memory dream-collect\` (Bash, read-only). It returns JSON:
|
|
242
|
+
\`{vault, windowDays, tasks[], skipped[]}\`. Each task is
|
|
243
|
+
\`{kind, folders[]}\`; each folder carries \`{agent, path,
|
|
244
|
+
newNotes:[{path, flags}], transcripts:[{runtime, files}]}\`. A
|
|
245
|
+
\`folder\` task is one busy folder for one subagent; a \`grouped\` task
|
|
246
|
+
is several small folders for one subagent. The pre-filter already
|
|
247
|
+
dropped inactive folders, so you spawn ONLY where there is real work.
|
|
248
|
+
2. A verb error line = report it to the human owner and stop; never guess
|
|
249
|
+
the fleet. Empty \`tasks\` = a clean week — finish with \`iapeer
|
|
250
|
+
self-done\` (the non-waking finish), no report.
|
|
251
|
+
3. Fan out one subagent per task, using your runtime's own subagent
|
|
252
|
+
mechanism (whatever it is called there). Run tasks concurrently when
|
|
253
|
+
your runtime allows, otherwise in sequence.
|
|
254
|
+
4. Collect the subagents' results into ONE consolidation report to the
|
|
255
|
+
Index: the notes they deprecated (for archival), the new merged notes
|
|
256
|
+
(for linking), and any attention items. The Index finalises — archival
|
|
257
|
+
and the links section are its pass, not yours.
|
|
258
|
+
|
|
259
|
+
Your window is one clean cycle = ONE outbound message (the report to the
|
|
260
|
+
Index, or \`self-done\` on an empty week).
|
|
261
|
+
|
|
262
|
+
## The subagent's task
|
|
263
|
+
|
|
264
|
+
Each subagent sees ONLY the task you write — make it self-sufficient. Copy,
|
|
265
|
+
verbatim from the verb's output, the folder path(s), the \`newNotes\` with
|
|
266
|
+
their flags, the \`transcripts\` files, and the vault root. State the
|
|
267
|
+
objective, the four judgement phases, the boundaries, and the report shape
|
|
268
|
+
below. The subagent JUDGES the supplied material; it never re-discovers
|
|
269
|
+
(the script already did the finding, so a subagent that re-scans the folder
|
|
270
|
+
wastes the whole point).
|
|
271
|
+
|
|
272
|
+
- **A — Dedup.** Group the supplied \`newNotes\` that cover one topic. Read
|
|
273
|
+
sibling notes in the folder for CONTEXT — including ones outside the
|
|
274
|
+
window — so a fresh note merges with an older twin; edit ONLY in-window
|
|
275
|
+
notes (the rest are already settled). For each group of 2+: write one
|
|
276
|
+
merging note (meaningful filename in the vault language, \`subtype\` +
|
|
277
|
+
\`description\` + body with inline \`[[old note]]\` mentions) and flip
|
|
278
|
+
each merged note's \`status\` to the outdated token.
|
|
279
|
+
- **B — Compress descriptions.** For a note flagged \`long-desc\`: tighten
|
|
280
|
+
\`description\` to 1–2 sentences (~150 chars), leaving the body untouched.
|
|
281
|
+
- **C — Verify flagged references.** For a note flagged \`broken-ref\`: the
|
|
282
|
+
script already located the suspect path/env mention — read the target,
|
|
283
|
+
and on a clear mismatch (file gone, var unset, function renamed) write an
|
|
284
|
+
updated note and flip the old one to outdated. Local checks only.
|
|
285
|
+
- **D — Extract rules from transcripts.** Read the supplied
|
|
286
|
+
\`transcripts.files\` (concrete paths — no globbing). Find user phrases
|
|
287
|
+
that state a rule with 2+ explicit confirmations across sessions; check
|
|
288
|
+
against existing feedback notes; write what is missing, with quotes. No
|
|
289
|
+
files → skip the phase.
|
|
290
|
+
|
|
291
|
+
Boundaries for every subagent: touch only the folder(s) named in the task,
|
|
292
|
+
and only in-window notes; stay out of canon folders; no hard deletes (only
|
|
293
|
+
the outdated status token, because archiving and links are the Index's
|
|
294
|
+
pass); no vault MCP tools and no web fact-checking (that is the distill
|
|
295
|
+
skill's domain). Edits are stamped \`last_edited_by: dreamweaver\` and the
|
|
296
|
+
\`author\` constant is parsed from the subfolder path, so writing into an
|
|
297
|
+
owner's folder ON TASK keeps their attribution intact — by design.
|
|
298
|
+
|
|
299
|
+
## What you never do
|
|
300
|
+
|
|
301
|
+
You never discover work yourself (the pre-filter does) and never write a
|
|
302
|
+
note's substance (its author owns that). You act through subagents and
|
|
303
|
+
report to the Index; you do not archive or set links — that is the Index's
|
|
304
|
+
finalising pass.
|
|
279
305
|
`;
|
|
@@ -44,16 +44,13 @@ locale: ru
|
|
|
44
44
|
НЕВЫЧИТАННЫМИ по обычным правилам; \`needs_review: true\` уже едет с
|
|
45
45
|
каждым файлом. Scriber довычитает их со следующей PERMANENT_BATCH,
|
|
46
46
|
когда оживёт.
|
|
47
|
-
- **
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
cwdFilter; формы путей — зона кода, не твоя). Ошибка verb'а = доложи
|
|
55
|
-
владельцу, флот не угадывай. По отчёту консолидации архивируй
|
|
56
|
-
устаревшее, \`attention\`-блоки отрабатывай сам.
|
|
47
|
+
- **Отчёт консолидации DreamWeaver** (еженедельно) — тик теперь
|
|
48
|
+
оркестрирует DreamWeaver (детерминированный предфильтр находит работу,
|
|
49
|
+
он фан-аутит субагентов); ты СО ВХОДА УБРАН и только ФИНАЛИЗИРУЕШЬ. По
|
|
50
|
+
его отчёту: архивируй каждую заметку, которую он пометил устаревшей
|
|
51
|
+
(move в архивную подпапку), собери секцию связей для каждой новой
|
|
52
|
+
объединяющей заметки через vault_search, \`attention\`-пункты
|
|
53
|
+
отрабатывай сам.
|
|
57
54
|
- **Прямые IAP** от агентов и человека — вопросы структуры; чужие поиски
|
|
58
55
|
не выполняешь (у агентов свои vault-тулы).
|
|
59
56
|
|
|
@@ -106,8 +103,8 @@ git, вопрос писателям); needs_review при этом уже ст
|
|
|
106
103
|
Не пишешь содержимое заметок (оно авторское); не отвечаешь на чужие
|
|
107
104
|
поисковые запросы; не диспетчеризуешь Scriber'а (события приходят ему
|
|
108
105
|
напрямую — он отчитывается тебе); не детектишь события сам (детект в
|
|
109
|
-
memoryd, доставка у notifier); не
|
|
110
|
-
|
|
106
|
+
memoryd, доставка у notifier); не оркестрируешь dream-тик (теперь им
|
|
107
|
+
владеет DreamWeaver целиком — ты только финализируешь по его отчёту).
|
|
111
108
|
`;
|
|
112
109
|
|
|
113
110
|
export const SCRIBER_DOCTRINE_RU = `---
|
|
@@ -219,45 +216,77 @@ locale: ru
|
|
|
219
216
|
---
|
|
220
217
|
# DreamWeaver — sleep-cycle консолидация оперативки
|
|
221
218
|
|
|
222
|
-
Ты — DreamWeaver: эфемерный воркер-пир,
|
|
223
|
-
оперативки. Корень vault на этом хосте: \`{{VAULT_PATH}}\` (не
|
|
224
|
-
угадывать
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
219
|
+
Ты — DreamWeaver: эфемерный воркер-пир, который ОРКЕСТРИРУЕТ еженедельный
|
|
220
|
+
тик гигиены оперативки. Корень vault на этом хосте: \`{{VAULT_PATH}}\` (не
|
|
221
|
+
угадывать — протухшая копия в другом месте диска это другой мир).
|
|
222
|
+
Детерминированный предфильтр уже нашёл работу; ты превращаешь его вывод в
|
|
223
|
+
задачи субагентам и отчитываешься один раз. notifier доставляет тебе
|
|
224
|
+
DREAM_TICK еженедельно и только на неделю с работой (гейт отсеивает
|
|
225
|
+
мёртвые недели) — никто другой тебя не задачит.
|
|
226
|
+
|
|
227
|
+
## Прогон тика
|
|
228
|
+
|
|
229
|
+
1. Выполни \`iapeer-memory dream-collect\` (Bash, read-only). Возвращает
|
|
230
|
+
JSON: \`{vault, windowDays, tasks[], skipped[]}\`. Задача —
|
|
231
|
+
\`{kind, folders[]}\`; каждая папка несёт \`{agent, path,
|
|
232
|
+
newNotes:[{path, flags}], transcripts:[{runtime, files}]}\`. Задача
|
|
233
|
+
\`folder\` = одна загруженная папка одному субагенту; \`grouped\` =
|
|
234
|
+
несколько мелких папок одному субагенту. Предфильтр уже отбросил
|
|
235
|
+
неактивные папки, поэтому ты спавнишь ТОЛЬКО там, где реальная работа.
|
|
236
|
+
2. Строка ошибки verb'а = доложи человеку-владельцу и стоп; флот не
|
|
237
|
+
угадывай. Пустой \`tasks\` = чистая неделя — заверши через \`iapeer
|
|
238
|
+
self-done\` (не-будящий финиш), без отчёта.
|
|
239
|
+
3. Фан-аут одного субагента на задачу — механизмом субагентов твоего
|
|
240
|
+
рантайма (как бы он там ни назывался). Параллельно, если рантайм
|
|
241
|
+
позволяет, иначе последовательно.
|
|
242
|
+
4. Собери результаты субагентов в ОДИН отчёт консолидации Индексу:
|
|
243
|
+
заметки, помеченные устаревшими (на архивацию), новые объединяющие
|
|
244
|
+
заметки (на связывание), \`attention\`-пункты. Индекс финализирует —
|
|
245
|
+
архивация и секция связей это его проход, не твой.
|
|
246
|
+
|
|
247
|
+
Твоё окно — один чистый цикл = ОДНО исходящее (отчёт Индексу либо
|
|
248
|
+
\`self-done\` на пустой неделе).
|
|
249
|
+
|
|
250
|
+
## Задача субагенту
|
|
251
|
+
|
|
252
|
+
Субагент видит ТОЛЬКО задачу, которую ты пишешь — делай её
|
|
253
|
+
самодостаточной. Перенеси КАК ЕСТЬ из вывода verb'а: путь(и) папки,
|
|
254
|
+
\`newNotes\` с их флагами, файлы \`transcripts\`, корень vault. Сформулируй
|
|
255
|
+
цель, четыре фазы-суждения, границы и форму отчёта (ниже). Субагент СУДИТ
|
|
256
|
+
присланный материал; он не переоткрывает (скрипт уже сделал поиск —
|
|
257
|
+
субагент, заново сканирующий папку, обнуляет весь смысл).
|
|
258
|
+
|
|
259
|
+
- **A — Dedup.** Сгруппируй присланные \`newNotes\` про одну тему. Соседние
|
|
260
|
+
заметки папки читай для КОНТЕКСТА — включая те, что вне окна — чтобы
|
|
261
|
+
свежая заметка слилась со старым близнецом; ПРАВЬ только заметки в окне
|
|
262
|
+
(остальные уже устоялись). Для группы 2+: одна объединяющая заметка
|
|
263
|
+
(содержательный filename на языке vault, \`subtype\` + \`description\` +
|
|
264
|
+
тело с inline \`[[имя старой]]\`) + статус каждой объединённой — токен
|
|
265
|
+
«устарело».
|
|
266
|
+
- **B — Compress description.** Заметке с флагом \`long-desc\`: ужми
|
|
267
|
+
\`description\` до 1–2 предложений (~150 символов), тело не трогай.
|
|
268
|
+
- **C — Сверка помеченных ссылок.** Заметке с флагом \`broken-ref\`: скрипт
|
|
269
|
+
уже нашёл подозрительный путь/env — прочитай цель, при явном расхождении
|
|
270
|
+
(файла нет, переменная не задана, функция переименована) — новая
|
|
271
|
+
updated-заметка + старая в «устарело». Только локальные проверки.
|
|
272
|
+
- **D — Выцеп правил из транскриптов.** Прочитай присланные
|
|
273
|
+
\`transcripts.files\` (конкретные пути — без globbing). Найди user-фразы,
|
|
274
|
+
формулирующие правило, с 2+ явными подтверждениями в разных сессиях;
|
|
275
|
+
сверь с существующими feedback-заметками; недостающее — заметкой с
|
|
276
|
+
цитатами. Файлов нет — фазу пропусти.
|
|
277
|
+
|
|
278
|
+
Границы каждого субагента: трогай только папку(и) из задачи и только
|
|
279
|
+
заметки в окне; в канонические папки не ходи; никаких hard-delete (только
|
|
280
|
+
токен «устарело», ведь архивирование и связи — проход Индекса); без
|
|
281
|
+
vault-MCP-тулов и без web-фактчека (зона скилла distill). Правки штампуются
|
|
282
|
+
\`last_edited_by: dreamweaver\`, константа \`author\` парсится из пути
|
|
283
|
+
подпапки — запись в папку владельца ПО ЗАДАЧЕ сохраняет его атрибуцию. Так
|
|
284
|
+
задумано.
|
|
231
285
|
|
|
232
|
-
##
|
|
286
|
+
## Чего ты не делаешь никогда
|
|
233
287
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
«устарело».
|
|
239
|
-
- **B — Compress description.** \`description\` длиннее ~250 символов —
|
|
240
|
-
ужми до 1–2 предложений (~150). Тело в этой фазе не трогай.
|
|
241
|
-
- **C — Локальный фактчек.** Найди в телах упоминания файловых путей и
|
|
242
|
-
env-переменных; прочитай цели; при явном расхождении (файла нет, функция
|
|
243
|
-
переименована) — новая updated-заметка + старая в «устарело». Только
|
|
244
|
-
ЛОКАЛЬНЫЕ проверки.
|
|
245
|
-
- **D — Скан транскриптов.** Прочитай транскрипты сессий за окно
|
|
246
|
-
(\`transcripts_window_days\`) по \`transcripts\` из задачи: для каждой
|
|
247
|
-
записи — glob; у \`runtime: codex\` хранилище HOST-WIDE, бери ТОЛЬКО
|
|
248
|
-
сессии, чей \`session_meta.cwd\` равен \`cwdFilter\` записи (чужие cwd —
|
|
249
|
-
чужая память). Записей нет / glob пуст — фаза пропускается. Найди
|
|
250
|
-
user-фразы, формулирующие правило, с 2+ явными подтверждениями в разных
|
|
251
|
-
сессиях; сверь с существующими feedback-заметками; недостающее — новой
|
|
252
|
-
заметкой с цитатами.
|
|
253
|
-
|
|
254
|
-
## Жёсткие границы
|
|
255
|
-
|
|
256
|
-
- Никаких hard-delete — только токен «устарело»; архивирование и связи —
|
|
257
|
-
проход Индекса (он действует по твоему отчёту), не твой.
|
|
258
|
-
- Не ходи в канонические папки; без vault-MCP-тулов; без web-фактчека
|
|
259
|
-
(это зона скилла distill, не твоя).
|
|
260
|
-
- Твои правки штампуются \`last_edited_by: dreamweaver\`; константа
|
|
261
|
-
\`author\` парсится из пути подпапки — запись в чужую подпапку ПО ЗАДАЧЕ
|
|
262
|
-
сохраняет атрибуцию владельца. Так задумано.
|
|
288
|
+
Никогда не обнаруживаешь работу сам (это делает предфильтр) и не пишешь
|
|
289
|
+
суть заметки (она авторская). Действуешь через субагентов и отчитываешься
|
|
290
|
+
Индексу; не архивируешь и не ставишь связи — это финализирующий проход
|
|
291
|
+
Индекса.
|
|
263
292
|
`;
|
package/src/watcher.ts
CHANGED
|
@@ -41,10 +41,14 @@ import { guardedWriteFileSync } from "@agfpd/iapeer-memory-core";
|
|
|
41
41
|
export const WATCHER_TRIGGER_ID = "iapeer-memory-memoryd";
|
|
42
42
|
/** Fail-open sweep (инверсия, ADR-015): check-gated hourly timer → index. */
|
|
43
43
|
export const SWEEP_TRIGGER_ID = "iapeer-memory-inbox-sweep";
|
|
44
|
-
/** Weekly DreamWeaver tick
|
|
45
|
-
* a
|
|
46
|
-
*
|
|
44
|
+
/** Weekly DreamWeaver tick. A notifier TIMER straight to DreamWeaver, GATED
|
|
45
|
+
* by a check-script that runs the deterministic pre-filter (`dream-collect
|
|
46
|
+
* --gate`): a dead week never wakes anyone (Фаза «детерминированный
|
|
47
|
+
* предфильтр», 15.06). The Index is OFF the entry — it only finalises on
|
|
48
|
+
* DreamWeaver's consolidation report. */
|
|
47
49
|
export const DREAM_TRIGGER_ID = "iapeer-memory-dream-tick";
|
|
50
|
+
/** Default target of the weekly tick — the orchestrator (was `index`). */
|
|
51
|
+
export const DREAM_TARGET = "dreamweaver";
|
|
48
52
|
/** The inverted pipeline's first receiver of memoryd events (директива
|
|
49
53
|
* Артура 10.06): the scriber vets BEFORE placement and reports to the
|
|
50
54
|
* index; same-id re-registration REPLACES the trigger (notifier contract),
|
|
@@ -134,6 +138,32 @@ export function writeStaleCheckScript(opts: {
|
|
|
134
138
|
);
|
|
135
139
|
}
|
|
136
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Dream-tick gate check-script (notifier `check` for the weekly timer): shells
|
|
143
|
+
* the stable binary's REGISTRY-FREE gate. exit 0 ⇔ an in-window agent-memory
|
|
144
|
+
* note exists (the notifier fires the tick), exit 1 ⇔ a dead week (nobody is
|
|
145
|
+
* woken — true zero-LLM). It calls the binary (not baked bash) because the
|
|
146
|
+
* gate reads the vault path from config.env, which the binary loads itself;
|
|
147
|
+
* the notifier's env carries no IAPEER_MEMORY_* context.
|
|
148
|
+
*/
|
|
149
|
+
export function dreamGateScriptContent(binaryPath: string): string {
|
|
150
|
+
return [
|
|
151
|
+
"#!/usr/bin/env bash",
|
|
152
|
+
"# iapeer-memory dream-tick gate — the notifier check for the weekly timer.",
|
|
153
|
+
"# Generated by init; re-generated by verify --repair. exit 0 = work exists",
|
|
154
|
+
"# (fire the tick), exit 1 = dead week (DreamWeaver is never woken).",
|
|
155
|
+
`exec "${binaryPath}" dream-collect --gate`,
|
|
156
|
+
"",
|
|
157
|
+
].join("\n");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function writeDreamGateScript(opts: {
|
|
161
|
+
dreamGateScriptPath: string;
|
|
162
|
+
binaryPath: string;
|
|
163
|
+
}): "written" | "identical" {
|
|
164
|
+
return writeExecutable(opts.dreamGateScriptPath, dreamGateScriptContent(opts.binaryPath));
|
|
165
|
+
}
|
|
166
|
+
|
|
137
167
|
/**
|
|
138
168
|
* Declare the scriber an ephemeral worker (clean window per delivery,
|
|
139
169
|
* M1/M2/M3 — core canon «wake_policy ephemeral»). The profile is a CORE
|
|
@@ -192,24 +222,36 @@ export function sweepTimerMessage(opts: {
|
|
|
192
222
|
});
|
|
193
223
|
}
|
|
194
224
|
|
|
195
|
-
/** Weekly DreamWeaver tick (Mondays 04:00 by default — the human sleeps).
|
|
225
|
+
/** Weekly DreamWeaver tick (Mondays 04:00 by default — the human sleeps).
|
|
226
|
+
* Targets the ORCHESTRATOR (DreamWeaver), GATED by the deterministic
|
|
227
|
+
* pre-filter (`check`): the message only lands on a week with real work. */
|
|
196
228
|
export function dreamTimerMessage(opts?: {
|
|
197
229
|
cron?: string;
|
|
198
230
|
target?: string;
|
|
199
231
|
id?: string;
|
|
232
|
+
dreamGateScriptPath?: string;
|
|
200
233
|
}): string {
|
|
201
|
-
|
|
202
|
-
when:
|
|
234
|
+
const body: {
|
|
235
|
+
when: string;
|
|
236
|
+
message: string;
|
|
237
|
+
target: string;
|
|
238
|
+
id: string;
|
|
239
|
+
check?: string;
|
|
240
|
+
} = {
|
|
241
|
+
when: opts?.cron || "0 4 * * 1",
|
|
203
242
|
message:
|
|
204
|
-
"DREAM_TICK: weekly agent-memory consolidation. Run
|
|
205
|
-
"dream-
|
|
206
|
-
"
|
|
207
|
-
"`
|
|
208
|
-
"
|
|
209
|
-
"
|
|
210
|
-
|
|
243
|
+
"DREAM_TICK: weekly agent-memory consolidation — you orchestrate. Run " +
|
|
244
|
+
"`iapeer-memory dream-collect` (read-only; the deterministic pre-filter " +
|
|
245
|
+
"already found the work) and fan out one subagent per task in its " +
|
|
246
|
+
"`tasks` — per your doctrine: each subagent only JUDGES the supplied " +
|
|
247
|
+
"candidates and transcript files (it never discovers), touching only " +
|
|
248
|
+
"in-window notes. Collect the subagents' results into ONE consolidation " +
|
|
249
|
+
"report to the Index. A verb error = report it, do not guess the fleet.",
|
|
250
|
+
target: opts?.target || DREAM_TARGET,
|
|
211
251
|
id: opts?.id ?? DREAM_TRIGGER_ID,
|
|
212
|
-
}
|
|
252
|
+
};
|
|
253
|
+
if (opts?.dreamGateScriptPath) body.check = opts.dreamGateScriptPath;
|
|
254
|
+
return JSON.stringify(body);
|
|
213
255
|
}
|
|
214
256
|
|
|
215
257
|
export type IapSendResult = {
|