@sabaiway/agent-workflow-kit 1.9.0 → 1.10.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.
@@ -0,0 +1,271 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFileSync } from 'node:fs';
4
+ import { fileURLToPath } from 'node:url';
5
+ import {
6
+ KIT_OWN_PATHS,
7
+ KNOWN_FOOTPRINT,
8
+ FOOTPRINT_STOP,
9
+ normalizeSlashes,
10
+ isDirPattern,
11
+ isGlobPattern,
12
+ patternToProbe,
13
+ expandGlob,
14
+ matchesKnownGlob,
15
+ } from './known-footprint.mjs';
16
+
17
+ // An ENOENT-typed error, matching the shape Node's fs throws.
18
+ const enoent = () => Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
19
+ const eacces = () => Object.assign(new Error('EACCES'), { code: 'EACCES' });
20
+ const fileStat = { isFile: () => true };
21
+ const dirStat = { isFile: () => false };
22
+
23
+ // The probe form of an anchored pattern, for subsumption/coverage reasoning (strip leading "/").
24
+ const probeOf = (pattern) => normalizeSlashes(pattern).replace(/^\//, '');
25
+ // A pattern's "scope" — the path-prefix it ignores. A glob's scope is its parent directory.
26
+ const scopeOf = (pattern) => {
27
+ const probe = probeOf(pattern);
28
+ if (isGlobPattern(pattern)) return `${probe.slice(0, probe.lastIndexOf('/') + 1)}`; // e.g. ".github/"
29
+ return probe;
30
+ };
31
+ // Does `pattern` (as a gitignore rule) cover the concrete repo-relative `path`?
32
+ const covers = (pattern, path) => {
33
+ const scope = scopeOf(pattern);
34
+ return scope.endsWith('/') ? path === scope.slice(0, -1) || path.startsWith(scope) : path === scope;
35
+ };
36
+
37
+ // ── (a) shape + type enum ───────────────────────────────────────────────────────
38
+
39
+ describe('KNOWN_FOOTPRINT shape', () => {
40
+ it('every entry is well-shaped with type ∈ {dir,file}', () => {
41
+ for (const e of KNOWN_FOOTPRINT) {
42
+ assert.equal(typeof e.pattern, 'string', `pattern is a string`);
43
+ assert.equal(typeof e.owner, 'string', `${e.pattern}: owner is a string`);
44
+ assert.ok(e.type === 'dir' || e.type === 'file', `${e.pattern}: type is dir|file`);
45
+ assert.equal(typeof e.falsePositiveRisk, 'boolean', `${e.pattern}: falsePositiveRisk is boolean`);
46
+ assert.equal(typeof e.note, 'string', `${e.pattern}: note is a string`);
47
+ if ('glob' in e) assert.equal(e.glob, true, `${e.pattern}: glob, when present, is true`);
48
+ }
49
+ });
50
+
51
+ it('a dir entry ends with "/", a file entry does not (glob excepted)', () => {
52
+ for (const e of KNOWN_FOOTPRINT) {
53
+ if (isGlobPattern(e.pattern)) continue;
54
+ assert.equal(isDirPattern(e.pattern), e.type === 'dir', `${e.pattern}: trailing slash matches type`);
55
+ }
56
+ });
57
+ });
58
+
59
+ // ── (b) uniqueness ────────────────────────────────────────────────────────────────
60
+
61
+ describe('uniqueness', () => {
62
+ it('KIT_OWN_PATHS has no duplicate patterns', () => {
63
+ assert.equal(new Set(KIT_OWN_PATHS).size, KIT_OWN_PATHS.length);
64
+ });
65
+ it('KNOWN_FOOTPRINT has no duplicate patterns', () => {
66
+ const pats = KNOWN_FOOTPRINT.map((e) => e.pattern);
67
+ assert.equal(new Set(pats).size, pats.length);
68
+ });
69
+ });
70
+
71
+ // ── (c) anchoring ─────────────────────────────────────────────────────────────────
72
+
73
+ describe('anchoring', () => {
74
+ const allPatterns = [...KIT_OWN_PATHS, ...KNOWN_FOOTPRINT.map((e) => e.pattern)];
75
+ it('every pattern is anchored (starts with "/") and has no traversal', () => {
76
+ for (const p of allPatterns) {
77
+ assert.ok(p.startsWith('/'), `${p}: anchored`);
78
+ assert.ok(!normalizeSlashes(p).split('/').includes('..'), `${p}: no ".."`);
79
+ }
80
+ });
81
+ it('a bare trailing "*" appears ONLY on a glob:true entry', () => {
82
+ for (const p of KIT_OWN_PATHS) assert.ok(!p.includes('*'), `KIT_OWN ${p}: no wildcard`);
83
+ for (const e of KNOWN_FOOTPRINT) {
84
+ if (e.pattern.includes('*')) assert.equal(e.glob, true, `${e.pattern}: wildcard ⇒ glob:true`);
85
+ }
86
+ const globs = KNOWN_FOOTPRINT.filter((e) => e.glob);
87
+ assert.deepEqual(globs.map((e) => e.pattern), ['/.github/copilot-*'], 'exactly one reviewed glob');
88
+ });
89
+ });
90
+
91
+ // ── (d) disjoint registries ───────────────────────────────────────────────────────
92
+
93
+ describe('disjointness', () => {
94
+ it('KIT_OWN_PATHS ∩ KNOWN_FOOTPRINT == ∅', () => {
95
+ const own = new Set(KIT_OWN_PATHS);
96
+ for (const e of KNOWN_FOOTPRINT) assert.ok(!own.has(e.pattern), `${e.pattern}: not in both`);
97
+ });
98
+ });
99
+
100
+ // ── (e) no prefix/subsumption between non-glob patterns (glob exempt) ──────────────
101
+
102
+ describe('no subsumption', () => {
103
+ it('no non-glob pattern is an ancestor of another across both arrays', () => {
104
+ const all = [...KIT_OWN_PATHS, ...KNOWN_FOOTPRINT.map((e) => e.pattern)].filter((p) => !isGlobPattern(p));
105
+ for (const a of all) {
106
+ for (const b of all) {
107
+ if (a === b) continue;
108
+ // a subsumes b iff a is a directory pattern and b sits under it.
109
+ if (isDirPattern(a)) {
110
+ assert.ok(!probeOf(b).startsWith(probeOf(a)), `${a} subsumes ${b} — remove the redundant child`);
111
+ }
112
+ }
113
+ }
114
+ });
115
+ });
116
+
117
+ // ── (f) external set must NOT reach the kit's own .claude/settings.json ────────────
118
+
119
+ describe('external set excludes .claude/settings.json', () => {
120
+ it('no KNOWN_FOOTPRINT pattern covers .claude/settings.json (KIT_OWN carries it, hidden-only)', () => {
121
+ for (const e of KNOWN_FOOTPRINT) {
122
+ assert.ok(!covers(e.pattern, '.claude/settings.json'), `${e.pattern}: must not cover .claude/settings.json`);
123
+ }
124
+ // sanity: KIT_OWN intentionally DOES carry it.
125
+ assert.ok(KIT_OWN_PATHS.includes('/.claude/settings.json'));
126
+ });
127
+ });
128
+
129
+ // ── (g) frozen snapshot + count sentinel ──────────────────────────────────────────
130
+
131
+ describe('frozen snapshot', () => {
132
+ it('KIT_OWN_PATHS matches the frozen expected set + count', () => {
133
+ const expected = [
134
+ '/AGENTS.md',
135
+ '/CLAUDE.md',
136
+ '/docs/ai/',
137
+ '/scripts/_expect-shim.mjs',
138
+ '/scripts/archive-changelog.mjs',
139
+ '/scripts/archive-changelog.test.mjs',
140
+ '/scripts/archive-issues.mjs',
141
+ '/scripts/archive-issues.test.mjs',
142
+ '/scripts/check-docs-size.mjs',
143
+ '/scripts/check-docs-size.test.mjs',
144
+ '/scripts/install-git-hooks.mjs',
145
+ '/docs/plans/',
146
+ '/.claude/settings.local.json',
147
+ '/.claude/settings.json',
148
+ ];
149
+ assert.equal(KIT_OWN_PATHS.length, 14, 'KIT_OWN_PATHS count sentinel — edit deliberately');
150
+ assert.deepEqual(KIT_OWN_PATHS, expected);
151
+ });
152
+
153
+ it('KNOWN_FOOTPRINT matches the frozen expected pattern set + count', () => {
154
+ const expected = [
155
+ '/.claude/skills/',
156
+ '/.cursor/rules/',
157
+ '/.cursorrules',
158
+ '/.codeium/',
159
+ '/.windsurf/',
160
+ '/.windsurfrules',
161
+ '/GEMINI.md',
162
+ '/.antigravity.md',
163
+ '/.github/copilot-*',
164
+ '/.aider.conf.yml',
165
+ '/.aider.chat.history.md',
166
+ '/.aider.input.history',
167
+ '/.continue/',
168
+ ];
169
+ assert.equal(KNOWN_FOOTPRINT.length, 13, 'KNOWN_FOOTPRINT count sentinel — edit deliberately');
170
+ assert.deepEqual(KNOWN_FOOTPRINT.map((e) => e.pattern), expected);
171
+ });
172
+ });
173
+
174
+ // ── (h) patternToProbe + expandGlob ───────────────────────────────────────────────
175
+
176
+ describe('patternToProbe', () => {
177
+ it('strips the leading "/" and round-trips a file', () => {
178
+ assert.equal(patternToProbe('/AGENTS.md'), 'AGENTS.md');
179
+ assert.equal(patternToProbe('/.cursorrules'), '.cursorrules');
180
+ });
181
+ it('preserves a trailing "/" for a dir', () => {
182
+ assert.equal(patternToProbe('/docs/ai/'), 'docs/ai/');
183
+ assert.equal(patternToProbe('/.claude/skills/'), '.claude/skills/');
184
+ });
185
+ it('normalizes Windows back-slashes', () => {
186
+ assert.equal(patternToProbe('\\docs\\ai\\'), 'docs/ai/');
187
+ });
188
+ it('STOPs on a glob pattern (must expandGlob first)', () => {
189
+ assert.throws(() => patternToProbe('/.github/copilot-*'), (e) => e.code === FOOTPRINT_STOP);
190
+ });
191
+ it('STOPs on traversal', () => {
192
+ assert.throws(() => patternToProbe('/x/../y'), (e) => e.code === FOOTPRINT_STOP);
193
+ });
194
+ it('STOPs on an unanchored pattern', () => {
195
+ assert.throws(() => patternToProbe('AGENTS.md'), (e) => e.code === FOOTPRINT_STOP);
196
+ });
197
+ });
198
+
199
+ describe('expandGlob', () => {
200
+ const dir = '/repo';
201
+ const entries = {
202
+ '/repo/.github': ['copilot-instructions.md', 'copilot-setup-steps.yml', 'copilot-agents', 'workflows', 'README.md'],
203
+ };
204
+ const kinds = {
205
+ '/repo/.github/copilot-instructions.md': fileStat,
206
+ '/repo/.github/copilot-setup-steps.yml': fileStat,
207
+ '/repo/.github/copilot-agents': dirStat, // matches the glob but is a directory → excluded
208
+ '/repo/.github/workflows': dirStat,
209
+ '/repo/.github/README.md': fileStat,
210
+ };
211
+ const readdir = (p) => {
212
+ if (p in entries) return entries[p];
213
+ throw enoent();
214
+ };
215
+ const stat = (p) => {
216
+ if (p in kinds) return kinds[p];
217
+ throw enoent();
218
+ };
219
+
220
+ it('matches only the concrete present FILES under the parent (dirs + non-matches excluded)', () => {
221
+ assert.deepEqual(expandGlob('/.github/copilot-*', { dir, readdir, stat }), [
222
+ '/.github/copilot-instructions.md',
223
+ '/.github/copilot-setup-steps.yml',
224
+ ]);
225
+ });
226
+ it('an absent parent dir → no candidates', () => {
227
+ assert.deepEqual(expandGlob('/.github/copilot-*', { dir: '/empty', readdir, stat }), []);
228
+ });
229
+ it('a non-ENOENT readdir error → STOP (never a silent drop)', () => {
230
+ const boom = () => { throw eacces(); };
231
+ assert.throws(() => expandGlob('/.github/copilot-*', { dir, readdir: boom, stat }), (e) => e.code === FOOTPRINT_STOP);
232
+ });
233
+ it('STOPs when called on a non-glob pattern', () => {
234
+ assert.throws(() => expandGlob('/AGENTS.md', { dir, readdir, stat }), (e) => e.code === FOOTPRINT_STOP);
235
+ });
236
+ });
237
+
238
+ // ── small pure helpers ────────────────────────────────────────────────────────────
239
+
240
+ describe('source hygiene', () => {
241
+ it('the shipped hidden-mode tools contain no NUL bytes (text-safe; never classified binary)', () => {
242
+ for (const f of ['known-footprint.mjs', 'hide-footprint.mjs']) {
243
+ const src = readFileSync(fileURLToPath(new URL(`./${f}`, import.meta.url)), 'utf8');
244
+ assert.ok(!src.includes('\u0000'), `${f} must not contain a NUL byte`);
245
+ }
246
+ });
247
+ });
248
+
249
+ describe('matchesKnownGlob', () => {
250
+ it('recognizes a concrete child of a glob:true entry', () => {
251
+ assert.equal(matchesKnownGlob('/.github/copilot-instructions.md'), true);
252
+ assert.equal(matchesKnownGlob('/.github/copilot-setup-steps.yml'), true);
253
+ });
254
+ it('rejects a non-matching sibling, a nested path, and a non-glob registry pattern', () => {
255
+ assert.equal(matchesKnownGlob('/.github/dependabot.yml'), false, 'sibling not matching the glob');
256
+ assert.equal(matchesKnownGlob('/.github/copilot/extra.md'), false, 'one directory level only');
257
+ assert.equal(matchesKnownGlob('/AGENTS.md'), false, 'a registry pattern is not a glob child');
258
+ });
259
+ });
260
+
261
+ describe('pure helpers', () => {
262
+ it('normalizeSlashes converts back-slashes', () => assert.equal(normalizeSlashes('a\\b\\c'), 'a/b/c'));
263
+ it('isDirPattern keys on a trailing slash', () => {
264
+ assert.equal(isDirPattern('/docs/ai/'), true);
265
+ assert.equal(isDirPattern('/AGENTS.md'), false);
266
+ });
267
+ it('isGlobPattern detects a wildcard', () => {
268
+ assert.equal(isGlobPattern('/.github/copilot-*'), true);
269
+ assert.equal(isGlobPattern('/AGENTS.md'), false);
270
+ });
271
+ });