@mossbear/projections 0.1.0-alpha.65 → 0.1.0-alpha.66

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,32 @@
1
+ /**
2
+ * Where a document's declared path lands in a repo that is **not** its home:
3
+ * mirrored under the bundle's own folder, `<bundleDir>/<declared path>`.
4
+ *
5
+ * A declared path is placement — where the document sits in its home repo's
6
+ * layout. Honoured literally everywhere, a bundle carrying `README.md` drops that
7
+ * README at the root of every subscribed repo lacking one, with nothing saying
8
+ * the file is foreign. Mirroring keeps the layout and moves the whole delivery
9
+ * inside a directory Mossbear owns outright, which is also what makes a
10
+ * recursive orphan sweep there sound.
11
+ *
12
+ * The same shape as `evalShadowPath` — a prefix plus the scope-relative path —
13
+ * because it is the same idea: a shadow tree that mirrors a path without landing
14
+ * on it. It has no inverse yet because nothing reads a mirrored path back into a
15
+ * declared one; add it beside its first caller.
16
+ */
17
+ /**
18
+ * True when a declared path is already inside `.mossbear/` — Mossbear's own
19
+ * tree, which a document may land in literally anywhere, and which
20
+ * `bundleMirrorPath` therefore refuses to mirror. Exported so the caller choosing
21
+ * between the two asks the same question this module does.
22
+ */
23
+ export declare function isMossbearTreePath(path: string): boolean;
24
+ /**
25
+ * The mirrored path for a document declaring `declaredPath`, relative to the
26
+ * same root `bundleDir` is (the repo). `null` when the declared path could not
27
+ * have been declared in the first place (absolute, escaping, control
28
+ * characters, over-long, or already inside `.mossbear/`), when `bundleDir` is
29
+ * not a safe relative path, or when the two together pass the 512-char bound.
30
+ */
31
+ export declare function bundleMirrorPath(bundleDir: string, declaredPath: string): string | null;
32
+ //# sourceMappingURL=bundle-mirror-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-mirror-path.d.ts","sourceRoot":"","sources":["../src/bundle-mirror-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYvF"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Where a document's declared path lands in a repo that is **not** its home:
3
+ * mirrored under the bundle's own folder, `<bundleDir>/<declared path>`.
4
+ *
5
+ * A declared path is placement — where the document sits in its home repo's
6
+ * layout. Honoured literally everywhere, a bundle carrying `README.md` drops that
7
+ * README at the root of every subscribed repo lacking one, with nothing saying
8
+ * the file is foreign. Mirroring keeps the layout and moves the whole delivery
9
+ * inside a directory Mossbear owns outright, which is also what makes a
10
+ * recursive orphan sweep there sound.
11
+ *
12
+ * The same shape as `evalShadowPath` — a prefix plus the scope-relative path —
13
+ * because it is the same idea: a shadow tree that mirrors a path without landing
14
+ * on it. It has no inverse yet because nothing reads a mirrored path back into a
15
+ * declared one; add it beside its first caller.
16
+ */
17
+ import { isSafeRelativePath, isUnderMossbearDir, toPosix } from './path-rules.js';
18
+ /**
19
+ * True when a declared path is already inside `.mossbear/` — Mossbear's own
20
+ * tree, which a document may land in literally anywhere, and which
21
+ * `bundleMirrorPath` therefore refuses to mirror. Exported so the caller choosing
22
+ * between the two asks the same question this module does.
23
+ */
24
+ export function isMossbearTreePath(path) {
25
+ return isUnderMossbearDir(toPosix(path));
26
+ }
27
+ /**
28
+ * The mirrored path for a document declaring `declaredPath`, relative to the
29
+ * same root `bundleDir` is (the repo). `null` when the declared path could not
30
+ * have been declared in the first place (absolute, escaping, control
31
+ * characters, over-long, or already inside `.mossbear/`), when `bundleDir` is
32
+ * not a safe relative path, or when the two together pass the 512-char bound.
33
+ */
34
+ export function bundleMirrorPath(bundleDir, declaredPath) {
35
+ const dir = trimTrailingSlashes(toPosix(bundleDir));
36
+ const normalized = toPosix(declaredPath);
37
+ if (!isSafeRelativePath(dir))
38
+ return null;
39
+ if (!isSafeRelativePath(normalized))
40
+ return null;
41
+ // A document declaring a place inside Mossbear's own state has no layout of
42
+ // its own to mirror, and mirroring it would nest one bundle's folder inside
43
+ // another's.
44
+ if (isUnderMossbearDir(normalized))
45
+ return null;
46
+ const mirrored = `${dir}/${normalized}`;
47
+ return isSafeRelativePath(mirrored) ? mirrored : null;
48
+ }
49
+ function trimTrailingSlashes(path) {
50
+ return path.replace(/\/+$/, '');
51
+ }
52
+ //# sourceMappingURL=bundle-mirror-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-mirror-path.js","sourceRoot":"","sources":["../src/bundle-mirror-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,YAAoB;IACtE,MAAM,GAAG,GAAG,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAA;IACnD,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACxC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACzC,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAA;IAChD,4EAA4E;IAC5E,4EAA4E;IAC5E,aAAa;IACb,IAAI,kBAAkB,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAA;IAE/C,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,UAAU,EAAE,CAAA;IACvC,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAA;AACvD,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AACjC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bundle-mirror-path.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-mirror-path.test.d.ts","sourceRoot":"","sources":["../src/bundle-mirror-path.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,46 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { bundleMirrorPath, isMossbearTreePath } from './bundle-mirror-path.js';
3
+ const DIR = '.mossbear/context/team-docs';
4
+ describe('bundleMirrorPath', () => {
5
+ it('keeps a foreign document inside the bundle folder, layout intact', () => {
6
+ expect(bundleMirrorPath(DIR, 'README.md')).toBe(`${DIR}/README.md`);
7
+ expect(bundleMirrorPath(DIR, 'docs/architecture.md')).toBe(`${DIR}/docs/architecture.md`);
8
+ expect(bundleMirrorPath(`${DIR}/`, 'docs/a.md')).toBe(`${DIR}/docs/a.md`);
9
+ expect(bundleMirrorPath('.mossbear\\context\\team-docs', 'docs\\a.md')).toBe(`${DIR}/docs/a.md`);
10
+ });
11
+ it('refuses a declared path no repo could hold', () => {
12
+ for (const bad of [
13
+ '',
14
+ '/etc/passwd',
15
+ 'C:/x.md',
16
+ '../escape.md',
17
+ 'a/../b.md',
18
+ 'a//b.md',
19
+ 'a\u0000.md',
20
+ ]) {
21
+ expect(bundleMirrorPath(DIR, bad)).toBeNull();
22
+ }
23
+ });
24
+ it('refuses a declared path inside Mossbear state rather than nesting a bundle in a bundle', () => {
25
+ expect(bundleMirrorPath(DIR, '.mossbear/context/other/a.md')).toBeNull();
26
+ expect(bundleMirrorPath(DIR, '.Mossbear/config.json')).toBeNull();
27
+ });
28
+ it('refuses when the mirror would pass the 512-char bound the declared path alone fits', () => {
29
+ const declared = `${'d/'.repeat(252)}x.md`;
30
+ expect(declared.length).toBeLessThanOrEqual(512);
31
+ expect(bundleMirrorPath(DIR, declared)).toBeNull();
32
+ });
33
+ it('refuses an unsafe bundle folder', () => {
34
+ expect(bundleMirrorPath('../elsewhere', 'a.md')).toBeNull();
35
+ expect(bundleMirrorPath('/abs', 'a.md')).toBeNull();
36
+ });
37
+ });
38
+ describe('isMossbearTreePath', () => {
39
+ it('recognises Mossbear’s own tree whatever the case or separator', () => {
40
+ expect(isMossbearTreePath('.mossbear/context/a.md')).toBe(true);
41
+ expect(isMossbearTreePath('.Mossbear\\evals\\AGENTS.md')).toBe(true);
42
+ expect(isMossbearTreePath('docs/.mossbear/a.md')).toBe(false);
43
+ expect(isMossbearTreePath('README.md')).toBe(false);
44
+ });
45
+ });
46
+ //# sourceMappingURL=bundle-mirror-path.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-mirror-path.test.js","sourceRoot":"","sources":["../src/bundle-mirror-path.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE9E,MAAM,GAAG,GAAG,6BAA6B,CAAA;AAEzC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,CAAA;QACnE,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC,CAAC,IAAI,CACxD,GAAG,GAAG,uBAAuB,CAC9B,CAAA;QACD,MAAM,CAAC,gBAAgB,CAAC,GAAG,GAAG,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,CAAA;QACzE,MAAM,CAAC,gBAAgB,CAAC,+BAA+B,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAC1E,GAAG,GAAG,YAAY,CACnB,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,KAAK,MAAM,GAAG,IAAI;YAChB,EAAE;YACF,aAAa;YACb,SAAS;YACT,cAAc;YACd,WAAW;YACX,SAAS;YACT,YAAY;SACb,EAAE,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC/C,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wFAAwF,EAAE,GAAG,EAAE;QAChG,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,8BAA8B,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QACxE,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oFAAoF,EAAE,GAAG,EAAE;QAC5F,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAA;QAC1C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAA;QAChD,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACpD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC3D,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACrD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,kBAAkB,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/D,MAAM,CAAC,kBAAkB,CAAC,6BAA6B,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACpE,MAAM,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC7D,MAAM,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@
12
12
  * second writer until it stopped scaffolding a starter template; the docs
13
13
  * phase is the only one now.)
14
14
  */
15
+ export * from './bundle-mirror-path.js';
15
16
  export * from './eval-path.js';
16
17
  export * from './agents-dir.js';
17
18
  export * from './claude-md.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,yBAAyB,CAAA;AACvC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA"}
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@
12
12
  * second writer until it stopped scaffolding a starter template; the docs
13
13
  * phase is the only one now.)
14
14
  */
15
+ export * from './bundle-mirror-path.js';
15
16
  export * from './eval-path.js';
16
17
  export * from './agents-dir.js';
17
18
  export * from './claude-md.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,yBAAyB,CAAA;AACvC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mossbear/projections",
3
- "version": "0.1.0-alpha.65",
3
+ "version": "0.1.0-alpha.66",
4
4
  "private": false,
5
5
  "description": "Guide file format detection and compatibility renderers for Mossbear — AGENTS.md, .agents/, CLAUDE.md, .claude/rules/, .cursorrules.",
6
6
  "license": "MIT",
@@ -38,7 +38,7 @@
38
38
  "test": "vitest run"
39
39
  },
40
40
  "dependencies": {
41
- "@mossbear/protocol": "0.1.0-alpha.65",
41
+ "@mossbear/protocol": "0.1.0-alpha.66",
42
42
  "valibot": "^1.4.2"
43
43
  },
44
44
  "devDependencies": {