@ikon85/agent-workflow-kit 0.22.0 → 0.23.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/.agents/skills/setup-workflow/SKILL.md +41 -2
- package/.claude/skills/setup-workflow/SKILL.md +41 -2
- package/README.md +9 -0
- package/agent-workflow-kit.package.json +25 -4
- package/assets/memory-templates/meta_decision_layer_choice.md +25 -0
- package/assets/memory-templates/meta_memory_lifecycle.md +25 -0
- package/package.json +2 -1
- package/scripts/memory-lifecycle/index.mjs +2 -0
- package/scripts/memory-lifecycle/setup.mjs +167 -0
- package/src/lib/bundle.mjs +4 -2
|
@@ -26,7 +26,7 @@ This is a prompt-driven skill, not a deterministic script. Explore, present what
|
|
|
26
26
|
| `## Agent skills` + `## Prod` in CLAUDE.md **and** AGENTS.md | one-line pointers + deploy target (Sections C/G + Write) |
|
|
27
27
|
| `.github/workflows/agent-workflow-kit-update.yml` | optional tested Kit update pull request for GitHub consumers (Section A2) |
|
|
28
28
|
| `docs/agents/census.md` | optional-census choice, paths, state, and safe disable contract seeded from [census.md](./census.md) (Section A3) |
|
|
29
|
-
| `docs/agents/workflow-capabilities.json` | consumer-owned
|
|
29
|
+
| `docs/agents/workflow-capabilities.json` + capability assets | consumer-owned Worktree Lifecycle activation and one-time Memory Lifecycle policy seeds (Sections A4–A5) |
|
|
30
30
|
|
|
31
31
|
## Idempotency contract — read before writing anything
|
|
32
32
|
|
|
@@ -57,7 +57,8 @@ Read the current state; don't assume. For every target file, read its first line
|
|
|
57
57
|
- `CONTEXT.md`, `CONTEXT-MAP.md`, `docs/adr/` — domain-doc layout.
|
|
58
58
|
- `docs/agents/`, `docs/agents/skills/`, `docs/conventions/` — prior output of this skill.
|
|
59
59
|
- `docs/agents/census.md`, `.census/profile.json`, `.census/active.json` — an existing census choice or consumer-owned census to adopt.
|
|
60
|
-
- `docs/agents/workflow-capabilities.json`, `.claude/settings.json` —
|
|
60
|
+
- `docs/agents/workflow-capabilities.json`, `.claude/settings.json` — existing capability choices/profile and Worktree Lifecycle hook wiring to adopt.
|
|
61
|
+
- `.memory/active/`, `.memory/archive/`, and `.memory/receipts/` — consumer-owned Memory Lifecycle policies or recovery evidence to adopt without normalization.
|
|
61
62
|
- `gh auth status` (if GitHub) — is `gh` authenticated, and with which scopes?
|
|
62
63
|
|
|
63
64
|
### 2. Section A — Issue tracker
|
|
@@ -165,6 +166,39 @@ The default setup entry is
|
|
|
165
166
|
may remain the configured `setupEntry` for parity. The handoff advisory always
|
|
166
167
|
reads that configured entry and never hardcodes a project script.
|
|
167
168
|
|
|
169
|
+
### 2d. Section A5 — Optional Memory Lifecycle
|
|
170
|
+
|
|
171
|
+
> Memory Lifecycle keeps project memories inside consumer-owned roots and makes
|
|
172
|
+
> restore operations previewable, collision-safe, and reversible. The policy
|
|
173
|
+
> templates become fully consumer-owned after their first seed.
|
|
174
|
+
|
|
175
|
+
Read the `memoryLifecycle` section of
|
|
176
|
+
`docs/agents/workflow-capabilities.json` before offering anything. Missing or
|
|
177
|
+
disabled configuration remains unchanged on an ordinary setup rerun. An
|
|
178
|
+
existing enabled section is adopted byte-for-byte; preserve unknown profile
|
|
179
|
+
keys, placement/retention settings, restore grants, and consumer-specific memory
|
|
180
|
+
rows.
|
|
181
|
+
If no section exists, explain the capability and offer an explicit opt-in. Only
|
|
182
|
+
an affirmative consumer decision may run:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
node scripts/memory-lifecycle/setup.mjs --enable
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
That command adds the minimal enabled section while preserving every existing
|
|
189
|
+
top-level profile key, sets restore and pruning approval to `false` unless the
|
|
190
|
+
consumer already recorded values, and seeds
|
|
191
|
+
`meta_decision_layer_choice.md` plus `meta_memory_lifecycle.md` into the
|
|
192
|
+
configured active root exactly once. Existing files are adopted and never
|
|
193
|
+
overwritten. The profile's `templatesSeeded` marker transfers full ownership:
|
|
194
|
+
later setup runs do not recreate a template the consumer edited, moved, or
|
|
195
|
+
deleted.
|
|
196
|
+
Choosing later, declining, or merely running `init`, `update`, or ordinary
|
|
197
|
+
`setup-workflow` performs no Memory Lifecycle write and never changes
|
|
198
|
+
activation, roots, retention, restore, or pruning grants. Template files have
|
|
199
|
+
no kit-managed or `append-managed` region; a future bounded-region contract
|
|
200
|
+
requires a separate decision.
|
|
201
|
+
|
|
168
202
|
### 3. Section B — Triage labels
|
|
169
203
|
|
|
170
204
|
> When `triage` processes an incoming issue it applies labels (or your tracker's equivalent). It needs strings you've actually configured, or it creates duplicates.
|
|
@@ -256,6 +290,11 @@ Lifecycle, Worktree Lifecycle, future sections, and unknown consumer keys share
|
|
|
256
290
|
this profile. Apply the Worktree Lifecycle transition and hook ownership rules
|
|
257
291
|
from [worktree-lifecycle.md](./worktree-lifecycle.md) transactionally.
|
|
258
292
|
|
|
293
|
+
For Memory Lifecycle, use only the deterministic setup helper from Section A5.
|
|
294
|
+
Do not copy templates with shell commands or edit the capability profile by
|
|
295
|
+
hand. Report `seeded · adopted · skipped`; do not print memory contents or
|
|
296
|
+
receipt contents.
|
|
297
|
+
|
|
259
298
|
For the **`## Workflow`**, **`## Agent skills`**, and **`## Prod`** blocks, reconcile per section in **both** CLAUDE.md and AGENTS.md that exist:
|
|
260
299
|
|
|
261
300
|
- If **both** files exist → write/update the block in **both** (keep them coherent — Codex is a first-class surface).
|
|
@@ -26,7 +26,7 @@ This is a prompt-driven skill, not a deterministic script. Explore, present what
|
|
|
26
26
|
| `## Agent skills` + `## Prod` in CLAUDE.md **and** AGENTS.md | one-line pointers + deploy target (Sections C/G + Write) |
|
|
27
27
|
| `.github/workflows/agent-workflow-kit-update.yml` | optional tested Kit update pull request for GitHub consumers (Section A2) |
|
|
28
28
|
| `docs/agents/census.md` | optional-census choice, paths, state, and safe disable contract seeded from [census.md](./census.md) (Section A3) |
|
|
29
|
-
| `docs/agents/workflow-capabilities.json` | consumer-owned
|
|
29
|
+
| `docs/agents/workflow-capabilities.json` + capability assets | consumer-owned Worktree Lifecycle activation and one-time Memory Lifecycle policy seeds (Sections A4–A5) |
|
|
30
30
|
|
|
31
31
|
## Idempotency contract — read before writing anything
|
|
32
32
|
|
|
@@ -57,7 +57,8 @@ Read the current state; don't assume. For every target file, read its first line
|
|
|
57
57
|
- `CONTEXT.md`, `CONTEXT-MAP.md`, `docs/adr/` — domain-doc layout.
|
|
58
58
|
- `docs/agents/`, `docs/agents/skills/`, `docs/conventions/` — prior output of this skill.
|
|
59
59
|
- `docs/agents/census.md`, `.census/profile.json`, `.census/active.json` — an existing census choice or consumer-owned census to adopt.
|
|
60
|
-
- `docs/agents/workflow-capabilities.json`, `.claude/settings.json` —
|
|
60
|
+
- `docs/agents/workflow-capabilities.json`, `.claude/settings.json` — existing capability choices/profile and Worktree Lifecycle hook wiring to adopt.
|
|
61
|
+
- `.memory/active/`, `.memory/archive/`, and `.memory/receipts/` — consumer-owned Memory Lifecycle policies or recovery evidence to adopt without normalization.
|
|
61
62
|
- `gh auth status` (if GitHub) — is `gh` authenticated, and with which scopes?
|
|
62
63
|
|
|
63
64
|
### 2. Section A — Issue tracker
|
|
@@ -165,6 +166,39 @@ The default setup entry is
|
|
|
165
166
|
may remain the configured `setupEntry` for parity. The handoff advisory always
|
|
166
167
|
reads that configured entry and never hardcodes a project script.
|
|
167
168
|
|
|
169
|
+
### 2d. Section A5 — Optional Memory Lifecycle
|
|
170
|
+
|
|
171
|
+
> Memory Lifecycle keeps project memories inside consumer-owned roots and makes
|
|
172
|
+
> restore operations previewable, collision-safe, and reversible. The policy
|
|
173
|
+
> templates become fully consumer-owned after their first seed.
|
|
174
|
+
|
|
175
|
+
Read the `memoryLifecycle` section of
|
|
176
|
+
`docs/agents/workflow-capabilities.json` before offering anything. Missing or
|
|
177
|
+
disabled configuration remains unchanged on an ordinary setup rerun. An
|
|
178
|
+
existing enabled section is adopted byte-for-byte; preserve unknown profile
|
|
179
|
+
keys, placement/retention settings, restore grants, and consumer-specific memory
|
|
180
|
+
rows.
|
|
181
|
+
If no section exists, explain the capability and offer an explicit opt-in. Only
|
|
182
|
+
an affirmative consumer decision may run:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
node scripts/memory-lifecycle/setup.mjs --enable
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
That command adds the minimal enabled section while preserving every existing
|
|
189
|
+
top-level profile key, sets restore and pruning approval to `false` unless the
|
|
190
|
+
consumer already recorded values, and seeds
|
|
191
|
+
`meta_decision_layer_choice.md` plus `meta_memory_lifecycle.md` into the
|
|
192
|
+
configured active root exactly once. Existing files are adopted and never
|
|
193
|
+
overwritten. The profile's `templatesSeeded` marker transfers full ownership:
|
|
194
|
+
later setup runs do not recreate a template the consumer edited, moved, or
|
|
195
|
+
deleted.
|
|
196
|
+
Choosing later, declining, or merely running `init`, `update`, or ordinary
|
|
197
|
+
`setup-workflow` performs no Memory Lifecycle write and never changes
|
|
198
|
+
activation, roots, retention, restore, or pruning grants. Template files have
|
|
199
|
+
no kit-managed or `append-managed` region; a future bounded-region contract
|
|
200
|
+
requires a separate decision.
|
|
201
|
+
|
|
168
202
|
### 3. Section B — Triage labels
|
|
169
203
|
|
|
170
204
|
> When `triage` processes an incoming issue it applies labels (or your tracker's equivalent). It needs strings you've actually configured, or it creates duplicates.
|
|
@@ -256,6 +290,11 @@ Lifecycle, Worktree Lifecycle, future sections, and unknown consumer keys share
|
|
|
256
290
|
this profile. Apply the Worktree Lifecycle transition and hook ownership rules
|
|
257
291
|
from [worktree-lifecycle.md](./worktree-lifecycle.md) transactionally.
|
|
258
292
|
|
|
293
|
+
For Memory Lifecycle, use only the deterministic setup helper from Section A5.
|
|
294
|
+
Do not copy templates with shell commands or edit the capability profile by
|
|
295
|
+
hand. Report `seeded · adopted · skipped`; do not print memory contents or
|
|
296
|
+
receipt contents.
|
|
297
|
+
|
|
259
298
|
For the **`## Workflow`**, **`## Agent skills`**, and **`## Prod`** blocks, reconcile per section in **both** CLAUDE.md and AGENTS.md that exist:
|
|
260
299
|
|
|
261
300
|
- If **both** files exist → write/update the block in **both** (keep them coherent — Codex is a first-class surface).
|
package/README.md
CHANGED
|
@@ -332,6 +332,15 @@ still reference. Flags: `--force` (overwrite pre-existing files on `init`),
|
|
|
332
332
|
|
|
333
333
|
## Release notes
|
|
334
334
|
|
|
335
|
+
### 0.23.0
|
|
336
|
+
|
|
337
|
+
- added: `assets/memory-templates/meta_decision_layer_choice.md`
|
|
338
|
+
- added: `assets/memory-templates/meta_memory_lifecycle.md`
|
|
339
|
+
- added: `scripts/memory-lifecycle/setup.mjs`
|
|
340
|
+
- changed: `.agents/skills/setup-workflow/SKILL.md`
|
|
341
|
+
- changed: `.claude/skills/setup-workflow/SKILL.md`
|
|
342
|
+
- changed: `scripts/memory-lifecycle/index.mjs`
|
|
343
|
+
|
|
335
344
|
### 0.22.0
|
|
336
345
|
|
|
337
346
|
- added: `.agents/skills/setup-workflow/worktree-lifecycle.md`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"kitVersion": "0.
|
|
2
|
+
"kitVersion": "0.23.0",
|
|
3
3
|
"files": [
|
|
4
4
|
{
|
|
5
5
|
"path": ".agents/skills/ask-matt/SKILL.md",
|
|
@@ -573,7 +573,7 @@
|
|
|
573
573
|
"kind": "skill",
|
|
574
574
|
"ownerSkill": "setup-workflow",
|
|
575
575
|
"surface": "codex",
|
|
576
|
-
"sha256": "
|
|
576
|
+
"sha256": "247250aa38a81b542600db42cfe4d02eecc1236e8af47df1f4def627f4df0668",
|
|
577
577
|
"mode": 420,
|
|
578
578
|
"origin": "kit"
|
|
579
579
|
},
|
|
@@ -1642,7 +1642,7 @@
|
|
|
1642
1642
|
"kind": "skill",
|
|
1643
1643
|
"ownerSkill": "setup-workflow",
|
|
1644
1644
|
"surface": "claude",
|
|
1645
|
-
"sha256": "
|
|
1645
|
+
"sha256": "247250aa38a81b542600db42cfe4d02eecc1236e8af47df1f4def627f4df0668",
|
|
1646
1646
|
"mode": 420,
|
|
1647
1647
|
"origin": "kit"
|
|
1648
1648
|
},
|
|
@@ -1970,6 +1970,20 @@
|
|
|
1970
1970
|
"mode": 420,
|
|
1971
1971
|
"origin": "kit"
|
|
1972
1972
|
},
|
|
1973
|
+
{
|
|
1974
|
+
"path": "assets/memory-templates/meta_decision_layer_choice.md",
|
|
1975
|
+
"kind": "template",
|
|
1976
|
+
"sha256": "b22bd1d0e3daa31cbdbb9a3a81964d7a00d5275e69c92c9bd4ad3b4e40995b41",
|
|
1977
|
+
"mode": 420,
|
|
1978
|
+
"origin": "kit"
|
|
1979
|
+
},
|
|
1980
|
+
{
|
|
1981
|
+
"path": "assets/memory-templates/meta_memory_lifecycle.md",
|
|
1982
|
+
"kind": "template",
|
|
1983
|
+
"sha256": "215e865d4e803ce0b2cd43e88d76501a61269dfa90aae5e6a474941a0b72b0ca",
|
|
1984
|
+
"mode": 420,
|
|
1985
|
+
"origin": "kit"
|
|
1986
|
+
},
|
|
1973
1987
|
{
|
|
1974
1988
|
"path": "docs/agents/security-audit-runbook-template.md",
|
|
1975
1989
|
"kind": "template",
|
|
@@ -2099,7 +2113,14 @@
|
|
|
2099
2113
|
{
|
|
2100
2114
|
"path": "scripts/memory-lifecycle/index.mjs",
|
|
2101
2115
|
"kind": "script",
|
|
2102
|
-
"sha256": "
|
|
2116
|
+
"sha256": "871507e20133ccbb11f2a57f092bcb41aa1f6b7deaaa74df2418573316e6bd96",
|
|
2117
|
+
"mode": 420,
|
|
2118
|
+
"origin": "kit"
|
|
2119
|
+
},
|
|
2120
|
+
{
|
|
2121
|
+
"path": "scripts/memory-lifecycle/setup.mjs",
|
|
2122
|
+
"kind": "script",
|
|
2123
|
+
"sha256": "c2c8885b806a830239ae54314c9dd0400399140870b6e62dc1e8b043dffcb78f",
|
|
2103
2124
|
"mode": 420,
|
|
2104
2125
|
"origin": "kit"
|
|
2105
2126
|
},
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Durable Knowledge Placement
|
|
2
|
+
|
|
3
|
+
Use this consumer-owned policy to decide where a learning belongs. Edit the
|
|
4
|
+
categories and examples to match this repository's terminology.
|
|
5
|
+
|
|
6
|
+
## Placement layers
|
|
7
|
+
|
|
8
|
+
- Repository instructions: stable rules that should guide every relevant task.
|
|
9
|
+
- Workflow skill: repeatable procedure with a named entry point and verification.
|
|
10
|
+
- Domain documentation: product language, boundaries, and durable decisions.
|
|
11
|
+
- Local memory: contextual knowledge that helps future sessions but is not yet a
|
|
12
|
+
repository-wide rule.
|
|
13
|
+
|
|
14
|
+
## Decision check
|
|
15
|
+
|
|
16
|
+
Before retaining a learning, record:
|
|
17
|
+
|
|
18
|
+
1. who needs it;
|
|
19
|
+
2. when it should be loaded;
|
|
20
|
+
3. what evidence would make it stale;
|
|
21
|
+
4. which tracked layer is the narrowest durable owner.
|
|
22
|
+
|
|
23
|
+
Prefer a tracked repository layer when the knowledge changes how work should be
|
|
24
|
+
performed. Keep personal preferences and user-profile information outside
|
|
25
|
+
project-owned memories unless the user explicitly places them here.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Memory Lifecycle Policy
|
|
2
|
+
|
|
3
|
+
This file is consumer-owned after its first seed. Edit roots, retention classes,
|
|
4
|
+
and review cadence to match the repository. Kit updates must never overwrite it.
|
|
5
|
+
|
|
6
|
+
## Retention classes
|
|
7
|
+
|
|
8
|
+
- Active: still relevant to current work and safe to load.
|
|
9
|
+
- Archive candidate: useful history that should leave the active set.
|
|
10
|
+
- Protected: user-profile, preference, or other content that must not be pruned
|
|
11
|
+
by an automated repository workflow.
|
|
12
|
+
|
|
13
|
+
## Archive and restore
|
|
14
|
+
|
|
15
|
+
- Archive only inside the configured consumer-owned archive root.
|
|
16
|
+
- Preview every action before mutation.
|
|
17
|
+
- Restore only with an explicit restore grant.
|
|
18
|
+
- Preserve the archive and refuse destination collisions.
|
|
19
|
+
- Record path verdicts and hashes in a content-free, collision-safe receipt.
|
|
20
|
+
|
|
21
|
+
## Pruning
|
|
22
|
+
|
|
23
|
+
Pruning is never implied by setup, update, archive, or restore. It requires a
|
|
24
|
+
separate preview and explicit user approval. A failed or interrupted operation
|
|
25
|
+
must leave the last safe active and archived state recoverable.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikon85/agent-workflow-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Portable AI-agent workflow skills (plan → execute → land → learn) for Claude Code & Codex — grilling, TDD, diagnosis, two-axis code review, cross-model Codex review, design & domain-modeling, plus a skill router (ask-matt). npx init/update/diff/uninstall.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
".claude/",
|
|
22
22
|
"!.claude/logs/",
|
|
23
23
|
".agents/",
|
|
24
|
+
"assets/",
|
|
24
25
|
"scripts/",
|
|
25
26
|
"docs/",
|
|
26
27
|
"src/",
|
|
@@ -10,6 +10,8 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
10
10
|
import { dirname, isAbsolute, normalize, relative, resolve, sep } from 'node:path';
|
|
11
11
|
import { pathToFileURL } from 'node:url';
|
|
12
12
|
|
|
13
|
+
export { setupMemoryLifecycle } from './setup.mjs';
|
|
14
|
+
|
|
13
15
|
async function exists(path) {
|
|
14
16
|
try {
|
|
15
17
|
return await lstat(path);
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lstat,
|
|
3
|
+
mkdir,
|
|
4
|
+
readFile,
|
|
5
|
+
rename,
|
|
6
|
+
rm,
|
|
7
|
+
writeFile,
|
|
8
|
+
} from 'node:fs/promises';
|
|
9
|
+
import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from 'node:path';
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
12
|
+
|
|
13
|
+
const PROFILE_PATH = 'docs/agents/workflow-capabilities.json';
|
|
14
|
+
const TEMPLATE_NAMES = [
|
|
15
|
+
'meta_decision_layer_choice.md',
|
|
16
|
+
'meta_memory_lifecycle.md',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
function contained(root, path) {
|
|
20
|
+
if (isAbsolute(path)) return null;
|
|
21
|
+
const normalized = normalize(path);
|
|
22
|
+
if (normalized === '..' || normalized.startsWith(`..${sep}`)) return null;
|
|
23
|
+
const absolute = resolve(root, normalized);
|
|
24
|
+
return relative(resolve(root), absolute).split(sep)[0] === '..' ? null : absolute;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function lstatIfPresent(path) {
|
|
28
|
+
try {
|
|
29
|
+
return await lstat(path);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error.code === 'ENOENT') return null;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function hasSymlink(root, path) {
|
|
37
|
+
let current = resolve(root);
|
|
38
|
+
const segments = relative(current, path).split(sep).filter(Boolean);
|
|
39
|
+
for (const segment of segments) {
|
|
40
|
+
current = resolve(current, segment);
|
|
41
|
+
if ((await lstatIfPresent(current))?.isSymbolicLink()) return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function readJson(path) {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(await readFile(path, 'utf8'));
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error.code === 'ENOENT') return null;
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function writeJsonAtomic(path, value) {
|
|
56
|
+
await mkdir(dirname(path), { recursive: true });
|
|
57
|
+
const staged = `${path}.${randomUUID()}.tmp`;
|
|
58
|
+
try {
|
|
59
|
+
await writeFile(staged, `${JSON.stringify(value, null, 2)}\n`, { flag: 'wx' });
|
|
60
|
+
await rename(staged, path);
|
|
61
|
+
} finally {
|
|
62
|
+
await rm(staged, { force: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function defaultCapability() {
|
|
67
|
+
return {
|
|
68
|
+
enabled: true,
|
|
69
|
+
activeRoot: '.memory/active',
|
|
70
|
+
archiveRoot: '.memory/archive',
|
|
71
|
+
receiptRoot: '.memory/receipts',
|
|
72
|
+
approvals: { restore: false, prune: false },
|
|
73
|
+
memories: TEMPLATE_NAMES.map((path) => ({ path, enabled: true })),
|
|
74
|
+
templatesSeeded: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function setupMemoryLifecycle({
|
|
79
|
+
projectRoot = process.cwd(),
|
|
80
|
+
templateRoot = join(projectRoot, 'assets', 'memory-templates'),
|
|
81
|
+
decision,
|
|
82
|
+
} = {}) {
|
|
83
|
+
const profilePath = resolve(projectRoot, PROFILE_PATH);
|
|
84
|
+
if (await hasSymlink(projectRoot, profilePath)) {
|
|
85
|
+
throw new Error('memoryLifecycle profile path contains a symlink');
|
|
86
|
+
}
|
|
87
|
+
const profile = await readJson(profilePath);
|
|
88
|
+
const existing = profile?.memoryLifecycle;
|
|
89
|
+
|
|
90
|
+
if (decision !== 'enable') {
|
|
91
|
+
return {
|
|
92
|
+
state: existing?.enabled ? 'enabled' : 'disabled',
|
|
93
|
+
seeded: [],
|
|
94
|
+
adopted: [],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const capability = {
|
|
99
|
+
...defaultCapability(),
|
|
100
|
+
...existing,
|
|
101
|
+
enabled: true,
|
|
102
|
+
approvals: {
|
|
103
|
+
restore: false,
|
|
104
|
+
prune: false,
|
|
105
|
+
...existing?.approvals,
|
|
106
|
+
},
|
|
107
|
+
templatesSeeded: true,
|
|
108
|
+
};
|
|
109
|
+
const activeRoot = contained(projectRoot, capability.activeRoot);
|
|
110
|
+
if (!activeRoot) throw new Error('memoryLifecycle.activeRoot must stay inside the project');
|
|
111
|
+
if (await hasSymlink(projectRoot, activeRoot)) {
|
|
112
|
+
throw new Error('memoryLifecycle.activeRoot contains a symlink');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const shouldSeed = existing?.templatesSeeded !== true;
|
|
116
|
+
const sources = shouldSeed
|
|
117
|
+
? await Promise.all(TEMPLATE_NAMES.map(async (name) => ({
|
|
118
|
+
name,
|
|
119
|
+
content: await readFile(join(templateRoot, name)),
|
|
120
|
+
})))
|
|
121
|
+
: [];
|
|
122
|
+
const seeded = [];
|
|
123
|
+
const adopted = [];
|
|
124
|
+
const destinations = sources.map(({ name, ...source }) => ({
|
|
125
|
+
...source,
|
|
126
|
+
name,
|
|
127
|
+
destination: contained(activeRoot, name),
|
|
128
|
+
}));
|
|
129
|
+
for (const { destination } of destinations) {
|
|
130
|
+
if (await hasSymlink(activeRoot, destination)) {
|
|
131
|
+
throw new Error('memory policy destination contains a symlink');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const { content, destination } of destinations) {
|
|
135
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
136
|
+
try {
|
|
137
|
+
await writeFile(destination, content, { flag: 'wx' });
|
|
138
|
+
seeded.push(relative(projectRoot, destination));
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (error.code !== 'EEXIST') throw error;
|
|
141
|
+
adopted.push(relative(projectRoot, destination));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await writeJsonAtomic(profilePath, {
|
|
146
|
+
schemaVersion: 1,
|
|
147
|
+
...profile,
|
|
148
|
+
memoryLifecycle: capability,
|
|
149
|
+
});
|
|
150
|
+
return { state: 'enabled', seeded, adopted };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export const MEMORY_POLICY_TEMPLATES = Object.freeze([...TEMPLATE_NAMES]);
|
|
154
|
+
|
|
155
|
+
async function main(argv) {
|
|
156
|
+
const result = await setupMemoryLifecycle({
|
|
157
|
+
decision: argv.includes('--enable') ? 'enable' : undefined,
|
|
158
|
+
});
|
|
159
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
|
|
163
|
+
main(process.argv.slice(2)).catch((error) => {
|
|
164
|
+
process.stderr.write(`${error.message}\n`);
|
|
165
|
+
process.exitCode = 1;
|
|
166
|
+
});
|
|
167
|
+
}
|
package/src/lib/bundle.mjs
CHANGED
|
@@ -65,9 +65,11 @@ export const HELPER_FILES = [
|
|
|
65
65
|
{ path: 'scripts/census/delta.mjs', kind: 'script', mode: 0o644 },
|
|
66
66
|
{ path: 'scripts/census/state.mjs', kind: 'script', mode: 0o644 },
|
|
67
67
|
{ path: 'scripts/census/transaction.mjs', kind: 'script', mode: 0o644 },
|
|
68
|
-
// Consumer-owned memory planning and recovery.
|
|
69
|
-
// skill API and the no-write-by-default CLI.
|
|
68
|
+
// Consumer-owned memory planning, one-time policy seeding, and recovery.
|
|
70
69
|
{ path: 'scripts/memory-lifecycle/index.mjs', kind: 'script', mode: 0o644 },
|
|
70
|
+
{ path: 'scripts/memory-lifecycle/setup.mjs', kind: 'script', mode: 0o644 },
|
|
71
|
+
{ path: 'assets/memory-templates/meta_decision_layer_choice.md', kind: 'template', mode: 0o644 },
|
|
72
|
+
{ path: 'assets/memory-templates/meta_memory_lifecycle.md', kind: 'template', mode: 0o644 },
|
|
71
73
|
// Profile-driven Worktree Lifecycle foundation. The setup adapter imports
|
|
72
74
|
// core.py, while capabilities.json keeps the historical 8/8 denominator
|
|
73
75
|
// explicit until the remaining hook and cleanup adapters are activated.
|