@sabaiway/agent-workflow-memory 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/LICENSE +21 -0
- package/README.md +61 -0
- package/SKILL.md +201 -0
- package/bin/install.mjs +185 -0
- package/bin/install.test.mjs +76 -0
- package/capability.json +27 -0
- package/migrations/1.1.0-communication-language.md +51 -0
- package/migrations/1.2.0-agent-attribution.md +57 -0
- package/migrations/README.md +46 -0
- package/migrations/legacy-stamp-takeover.md +72 -0
- package/package.json +53 -0
- package/references/contracts.md +62 -0
- package/references/scripts/_expect-shim.mjs +41 -0
- package/references/scripts/archive-changelog.mjs +438 -0
- package/references/scripts/archive-changelog.test.mjs +212 -0
- package/references/scripts/archive-issues.mjs +179 -0
- package/references/scripts/archive-issues.test.mjs +95 -0
- package/references/scripts/check-docs-size.mjs +353 -0
- package/references/scripts/check-docs-size.test.mjs +180 -0
- package/references/scripts/install-git-hooks.mjs +83 -0
- package/references/templates/AGENTS.md +96 -0
- package/references/templates/active_plan.md +31 -0
- package/references/templates/agent_rules.md +85 -0
- package/references/templates/architecture.md +49 -0
- package/references/templates/changelog.md +24 -0
- package/references/templates/current_state.md +36 -0
- package/references/templates/decisions.md +44 -0
- package/references/templates/env_commands.md +41 -0
- package/references/templates/handover.md +37 -0
- package/references/templates/known_issues.md +33 -0
- package/references/templates/pages/PAGE_TEMPLATE.md +53 -0
- package/references/templates/pages/index.md +23 -0
- package/references/templates/pages/shared-patterns.md +30 -0
- package/references/templates/tech_reference.md +34 -0
- package/references/templates/technical_specification.md +37 -0
- package/scripts/package-content.test.mjs +78 -0
- package/scripts/stamp-takeover.mjs +181 -0
- package/scripts/stamp-takeover.test.mjs +166 -0
- package/scripts/standalone-bootstrap.test.mjs +111 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// End-to-end acceptance: a standalone substrate bootstrap into a fresh project.
|
|
2
|
+
//
|
|
3
|
+
// The unit suites cover each module in isolation (the stamp state machine, the atomic
|
|
4
|
+
// writer, the hook installer). This drives the documented bootstrap WRITE steps end to end
|
|
5
|
+
// over a real temp project + a real git checkout, then asserts the deployed artifact set:
|
|
6
|
+
// docs/ai + entry point exist, the pre-commit hook is installed, the deployment-lineage
|
|
7
|
+
// stamp is .memory-version (the lineage head) ONLY, and the methodology slot ships empty.
|
|
8
|
+
//
|
|
9
|
+
// Standalone here means substrate-only: nothing fills the slot, so it stays empty and no
|
|
10
|
+
// second (composition-root) stamp appears. The composition path is covered separately.
|
|
11
|
+
|
|
12
|
+
import { describe, it, afterEach } from 'node:test';
|
|
13
|
+
import assert from 'node:assert/strict';
|
|
14
|
+
import {
|
|
15
|
+
mkdtempSync,
|
|
16
|
+
mkdirSync,
|
|
17
|
+
rmSync,
|
|
18
|
+
cpSync,
|
|
19
|
+
readdirSync,
|
|
20
|
+
readFileSync,
|
|
21
|
+
existsSync,
|
|
22
|
+
symlinkSync,
|
|
23
|
+
} from 'node:fs';
|
|
24
|
+
import { tmpdir } from 'node:os';
|
|
25
|
+
import { join, resolve, dirname } from 'node:path';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
import { execFileSync } from 'node:child_process';
|
|
28
|
+
import { writeStampAtomic, LINEAGE_HEAD } from './stamp-takeover.mjs';
|
|
29
|
+
|
|
30
|
+
const SKILL_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
31
|
+
const TEMPLATES = join(SKILL_ROOT, 'references', 'templates');
|
|
32
|
+
const ENFORCEMENT = join(SKILL_ROOT, 'references', 'scripts');
|
|
33
|
+
|
|
34
|
+
// The empty delimited slot the substrate ships in its entry point. Hard-coded (not imported
|
|
35
|
+
// from the composition root) so this substrate test stays self-contained and dependency-free.
|
|
36
|
+
const SLOT_START = '<!-- workflow:methodology:start -->';
|
|
37
|
+
const SLOT_END = '<!-- workflow:methodology:end -->';
|
|
38
|
+
|
|
39
|
+
const tempDirs = [];
|
|
40
|
+
const makeProject = () => {
|
|
41
|
+
const dir = mkdtempSync(join(tmpdir(), 'substrate-bootstrap-'));
|
|
42
|
+
tempDirs.push(dir);
|
|
43
|
+
return dir;
|
|
44
|
+
};
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
while (tempDirs.length) rmSync(tempDirs.pop(), { recursive: true, force: true });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Mirrors the bootstrap WRITE steps: entry point at the root (+ tool alias symlink), every
|
|
50
|
+
// other template under docs/ai, enforcement scripts copied in, the hook installed against a
|
|
51
|
+
// real checkout, and the lineage head stamped atomically. Returns the docs/ai dir.
|
|
52
|
+
const bootstrap = (project) => {
|
|
53
|
+
cpSync(join(TEMPLATES, 'AGENTS.md'), join(project, 'AGENTS.md'));
|
|
54
|
+
symlinkSync('AGENTS.md', join(project, 'CLAUDE.md'));
|
|
55
|
+
|
|
56
|
+
const docsAi = join(project, 'docs', 'ai');
|
|
57
|
+
mkdirSync(docsAi, { recursive: true });
|
|
58
|
+
for (const entry of readdirSync(TEMPLATES)) {
|
|
59
|
+
if (entry === 'AGENTS.md') continue;
|
|
60
|
+
cpSync(join(TEMPLATES, entry), join(docsAi, entry), { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const projectScripts = join(project, 'scripts');
|
|
64
|
+
mkdirSync(projectScripts, { recursive: true });
|
|
65
|
+
cpSync(ENFORCEMENT, projectScripts, { recursive: true });
|
|
66
|
+
|
|
67
|
+
// The hook installer resolves its target from its OWN location, so run the copied-in copy
|
|
68
|
+
// (project/scripts/...) to install into project/.git/hooks — exactly as the procedure does.
|
|
69
|
+
execFileSync('git', ['init', '-q'], { cwd: project });
|
|
70
|
+
execFileSync(process.execPath, [join(projectScripts, 'install-git-hooks.mjs')], {
|
|
71
|
+
cwd: project,
|
|
72
|
+
stdio: 'pipe',
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return docsAi;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
describe('standalone substrate bootstrap (end-to-end, real temp project)', () => {
|
|
79
|
+
it('deploys docs/ai + entry point and installs the pre-commit hook', () => {
|
|
80
|
+
const project = makeProject();
|
|
81
|
+
const docsAi = bootstrap(project);
|
|
82
|
+
|
|
83
|
+
assert.ok(existsSync(join(project, 'AGENTS.md')), 'entry point exists');
|
|
84
|
+
assert.ok(existsSync(docsAi), 'docs/ai exists');
|
|
85
|
+
assert.ok(existsSync(join(docsAi, 'agent_rules.md')), 'a representative docs/ai file landed');
|
|
86
|
+
|
|
87
|
+
const hook = join(project, '.git', 'hooks', 'pre-commit');
|
|
88
|
+
assert.ok(existsSync(hook), 'pre-commit hook installed');
|
|
89
|
+
assert.match(readFileSync(hook, 'utf8'), /install-git-hooks\.mjs/, 'hook carries the installer marker');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('stamps .memory-version (lineage head) ONLY — no second stamp', async () => {
|
|
93
|
+
const project = makeProject();
|
|
94
|
+
const docsAi = bootstrap(project);
|
|
95
|
+
await writeStampAtomic(join(docsAi, '.memory-version'), LINEAGE_HEAD);
|
|
96
|
+
|
|
97
|
+
assert.equal(readFileSync(join(docsAi, '.memory-version'), 'utf8').trim(), LINEAGE_HEAD);
|
|
98
|
+
assert.ok(!existsSync(join(docsAi, '.workflow-version')), 'no composition-root stamp in a standalone bootstrap');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('ships the methodology slot present-but-empty', () => {
|
|
102
|
+
const project = makeProject();
|
|
103
|
+
bootstrap(project);
|
|
104
|
+
|
|
105
|
+
const entry = readFileSync(join(project, 'AGENTS.md'), 'utf8');
|
|
106
|
+
const start = entry.indexOf(SLOT_START);
|
|
107
|
+
const end = entry.indexOf(SLOT_END);
|
|
108
|
+
assert.ok(start !== -1 && end !== -1 && end > start, 'an ordered slot marker pair is present');
|
|
109
|
+
assert.equal(entry.slice(start + SLOT_START.length, end).trim(), '', 'the slot is empty as shipped');
|
|
110
|
+
});
|
|
111
|
+
});
|