@bevel-software/platform-shared 0.14.0 → 0.19.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.
Files changed (73) hide show
  1. package/dist/auth/types.d.ts +12 -0
  2. package/dist/auth/types.d.ts.map +1 -1
  3. package/dist/git/pr.types.d.ts +75 -11
  4. package/dist/git/pr.types.d.ts.map +1 -1
  5. package/dist/git/types.d.ts +75 -2
  6. package/dist/git/types.d.ts.map +1 -1
  7. package/dist/index.d.ts +6 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +6 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/workflow/events.d.ts +39 -4
  12. package/dist/workflow/events.d.ts.map +1 -1
  13. package/dist/workflow/events.js.map +1 -1
  14. package/dist/workflow/interface.d.ts +137 -5
  15. package/dist/workflow/interface.d.ts.map +1 -1
  16. package/dist/workflow/types.d.ts +93 -0
  17. package/dist/workflow/types.d.ts.map +1 -1
  18. package/dist/workspace/access-verbs.d.ts +83 -0
  19. package/dist/workspace/access-verbs.d.ts.map +1 -0
  20. package/dist/workspace/access-verbs.js +110 -0
  21. package/dist/workspace/access-verbs.js.map +1 -0
  22. package/dist/workspace/agent-preamble.d.ts +33 -0
  23. package/dist/workspace/agent-preamble.d.ts.map +1 -0
  24. package/dist/workspace/agent-preamble.js +45 -0
  25. package/dist/workspace/agent-preamble.js.map +1 -0
  26. package/dist/workspace/entry-exists.d.ts +27 -0
  27. package/dist/workspace/entry-exists.d.ts.map +1 -0
  28. package/dist/workspace/entry-exists.js +33 -0
  29. package/dist/workspace/entry-exists.js.map +1 -0
  30. package/dist/workspace/filename.d.ts +15 -0
  31. package/dist/workspace/filename.d.ts.map +1 -1
  32. package/dist/workspace/filename.js +37 -3
  33. package/dist/workspace/filename.js.map +1 -1
  34. package/dist/workspace/frontmatter-carriers.d.ts +44 -0
  35. package/dist/workspace/frontmatter-carriers.d.ts.map +1 -0
  36. package/dist/workspace/frontmatter-carriers.js +52 -0
  37. package/dist/workspace/frontmatter-carriers.js.map +1 -0
  38. package/dist/workspace/frontmatter.d.ts +23 -4
  39. package/dist/workspace/frontmatter.d.ts.map +1 -1
  40. package/dist/workspace/frontmatter.js +59 -9
  41. package/dist/workspace/frontmatter.js.map +1 -1
  42. package/dist/workspace/kb-layout.d.ts +365 -19
  43. package/dist/workspace/kb-layout.d.ts.map +1 -1
  44. package/dist/workspace/kb-layout.js +619 -20
  45. package/dist/workspace/kb-layout.js.map +1 -1
  46. package/dist/workspace/placeholder.d.ts +21 -0
  47. package/dist/workspace/placeholder.d.ts.map +1 -0
  48. package/dist/workspace/placeholder.js +28 -0
  49. package/dist/workspace/placeholder.js.map +1 -0
  50. package/dist/workspace/platform-files.d.ts +105 -0
  51. package/dist/workspace/platform-files.d.ts.map +1 -0
  52. package/dist/workspace/platform-files.js +147 -0
  53. package/dist/workspace/platform-files.js.map +1 -0
  54. package/dist/workspace/types.d.ts +8 -0
  55. package/dist/workspace/types.d.ts.map +1 -1
  56. package/package.json +1 -1
  57. package/src/auth/types.ts +12 -0
  58. package/src/git/pr.types.ts +77 -11
  59. package/src/git/types.ts +81 -3
  60. package/src/index.ts +6 -0
  61. package/src/workflow/events.ts +40 -3
  62. package/src/workflow/interface.ts +162 -6
  63. package/src/workflow/types.ts +70 -0
  64. package/src/workspace/access-verbs.ts +124 -0
  65. package/src/workspace/agent-preamble.ts +47 -0
  66. package/src/workspace/entry-exists.ts +36 -0
  67. package/src/workspace/filename.ts +38 -3
  68. package/src/workspace/frontmatter-carriers.ts +57 -0
  69. package/src/workspace/frontmatter.ts +57 -8
  70. package/src/workspace/kb-layout.ts +660 -24
  71. package/src/workspace/placeholder.ts +29 -0
  72. package/src/workspace/platform-files.ts +188 -0
  73. package/src/workspace/types.ts +8 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * THE sentence a rename, a move or a copy answers with when something is
3
+ * already at the destination.
4
+ *
5
+ * A rename is not a way to replace content: renaming a `.docx` onto an
6
+ * existing `.md` used to hand the markdown file the Word bytes and break the
7
+ * page. Every surface — the sidebar rename box, a drag onto a folder, the
8
+ * agent's `move_file` and `copy_file` — refuses with this one sentence, so a
9
+ * user who meets it in the sidebar and an agent that meets it in a tool
10
+ * result are told the same thing.
11
+ *
12
+ * Kept here, beside `filename.ts`, for the same reason that file is: the
13
+ * backend throws it and the frontend renders it, and neither should spell it
14
+ * its own way.
15
+ */
16
+ /** What is already sitting at the destination. */
17
+ export type ExistingEntryKind = 'file' | 'folder';
18
+ /**
19
+ * `A file named <name> already exists in <folder>.` — `name` and `folder` are
20
+ * read off `destinationPath`, which may be workspace-relative or
21
+ * repo-relative; only its last two segments are used, so the reader sees the
22
+ * name they typed and the folder they were aiming at rather than a full path.
23
+ * A destination directly at the top of the tree has no folder segment to
24
+ * name, and says `the top level` instead.
25
+ */
26
+ export declare function entryExistsMessage(kind: ExistingEntryKind, destinationPath: string): string;
27
+ //# sourceMappingURL=entry-exists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-exists.d.ts","sourceRoot":"","sources":["../../src/workspace/entry-exists.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,kDAAkD;AAClD,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAElD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAQ3F"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * THE sentence a rename, a move or a copy answers with when something is
3
+ * already at the destination.
4
+ *
5
+ * A rename is not a way to replace content: renaming a `.docx` onto an
6
+ * existing `.md` used to hand the markdown file the Word bytes and break the
7
+ * page. Every surface — the sidebar rename box, a drag onto a folder, the
8
+ * agent's `move_file` and `copy_file` — refuses with this one sentence, so a
9
+ * user who meets it in the sidebar and an agent that meets it in a tool
10
+ * result are told the same thing.
11
+ *
12
+ * Kept here, beside `filename.ts`, for the same reason that file is: the
13
+ * backend throws it and the frontend renders it, and neither should spell it
14
+ * its own way.
15
+ */
16
+ /**
17
+ * `A file named <name> already exists in <folder>.` — `name` and `folder` are
18
+ * read off `destinationPath`, which may be workspace-relative or
19
+ * repo-relative; only its last two segments are used, so the reader sees the
20
+ * name they typed and the folder they were aiming at rather than a full path.
21
+ * A destination directly at the top of the tree has no folder segment to
22
+ * name, and says `the top level` instead.
23
+ */
24
+ export function entryExistsMessage(kind, destinationPath) {
25
+ const segments = destinationPath
26
+ .replace(/\\/g, '/')
27
+ .split('/')
28
+ .filter((segment) => segment.length > 0 && segment !== '.');
29
+ const name = segments[segments.length - 1] ?? destinationPath;
30
+ const folder = segments.length > 1 ? segments[segments.length - 2] : 'the top level';
31
+ return `A ${kind} named ${name} already exists in ${folder}.`;
32
+ }
33
+ //# sourceMappingURL=entry-exists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-exists.js","sourceRoot":"","sources":["../../src/workspace/entry-exists.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAuB,EAAE,eAAuB;IACjF,MAAM,QAAQ,GAAG,eAAe;SAC7B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,KAAK,GAAG,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,eAAe,CAAC;IAC9D,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC;IACrF,OAAO,KAAK,IAAI,UAAU,IAAI,sBAAsB,MAAM,GAAG,CAAC;AAChE,CAAC"}
@@ -25,6 +25,21 @@ export declare function validateFilename(name: string): string | null;
25
25
  * `\` would round-trip differently on Windows vs the Linux container.
26
26
  */
27
27
  export declare function validateRelativePath(relativePath: string): string | null;
28
+ /**
29
+ * ONE identity per file, so everything that coordinates on a path agrees about
30
+ * what it is coordinating on: an in-process queue, a database lock row, and
31
+ * the bytes on disk. {@link validateRelativePath} accepts a leading `./` and
32
+ * repeated slashes as spellings of the same path, and two callers spelling one
33
+ * file differently would otherwise take two different locks and write over
34
+ * each other. `.` and `..` segments are refused outright by the validator, so
35
+ * there is nothing to resolve here beyond the separators.
36
+ *
37
+ * Case is deliberately left alone. The deployment target is Linux, where
38
+ * `Foo.md` and `foo.md` are two different files; folding case to suit a
39
+ * case-insensitive development machine would merge two real files in
40
+ * production, which is a worse failure than the race it would close.
41
+ */
42
+ export declare function canonicalRelativePath(relativePath: string): string;
28
43
  /**
29
44
  * Throwing wrapper for the backend service layer — keeps call sites a single
30
45
  * line and produces a clear `Error` the route handler can surface as a 400.
@@ -1 +1 @@
1
- {"version":3,"file":"filename.d.ts","sourceRoot":"","sources":["../../src/workspace/filename.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAsBH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2B5D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiBxE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAGlE"}
1
+ {"version":3,"file":"filename.d.ts","sourceRoot":"","sources":["../../src/workspace/filename.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA0BH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2B5D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiBxE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAelE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAGlE"}
@@ -21,9 +21,13 @@ const WINDOWS_RESERVED_NAMES = new Set([
21
21
  ]);
22
22
  /** Characters Windows forbids in any filename component. `/` is the path
23
23
  * separator on Unix, included for the same reason. `\` is also a path
24
- * separator on Windows. Control chars (0x00–0x1F) are rejected separately. */
24
+ * separator on Windows. Control characters are rejected with them: NUL and
25
+ * 0x01–0x1F because Windows refuses them, and DEL (0x7F) — which every
26
+ * filesystem would write — as a matter of hygiene: a name carrying a
27
+ * character nobody can see or type is not a name people can share, and the
28
+ * knowledge-base root names are validated by this same rule. */
25
29
  // eslint-disable-next-line no-control-regex
26
- const FORBIDDEN_CHARS = /[<>:"/\\|?*\x00-\x1F]/;
30
+ const FORBIDDEN_CHARS = /[<>:"/\\|?*\x00-\x1F\x7F]/;
27
31
  /** Per-component byte limit: NTFS = 255 UTF-16 units, ext4 = 255 bytes,
28
32
  * APFS = 255 UTF-8 bytes. Use UTF-8 bytes — the strictest of the three. */
29
33
  const MAX_NAME_BYTES = 255;
@@ -43,7 +47,7 @@ export function validateFilename(name) {
43
47
  if (name === '.' || name === '..')
44
48
  return 'Name cannot be "." or ".."';
45
49
  if (FORBIDDEN_CHARS.test(name)) {
46
- return 'Name cannot contain any of these characters: < > : " / \\ | ? *';
50
+ return 'Name cannot contain control characters or any of: < > : " / \\ | ? *';
47
51
  }
48
52
  // Windows trims trailing dots and spaces silently — a name ending in either
49
53
  // becomes a different filename on disk, breaking sync between OSes.
@@ -86,6 +90,36 @@ export function validateRelativePath(relativePath) {
86
90
  }
87
91
  return null;
88
92
  }
93
+ /**
94
+ * ONE identity per file, so everything that coordinates on a path agrees about
95
+ * what it is coordinating on: an in-process queue, a database lock row, and
96
+ * the bytes on disk. {@link validateRelativePath} accepts a leading `./` and
97
+ * repeated slashes as spellings of the same path, and two callers spelling one
98
+ * file differently would otherwise take two different locks and write over
99
+ * each other. `.` and `..` segments are refused outright by the validator, so
100
+ * there is nothing to resolve here beyond the separators.
101
+ *
102
+ * Case is deliberately left alone. The deployment target is Linux, where
103
+ * `Foo.md` and `foo.md` are two different files; folding case to suit a
104
+ * case-insensitive development machine would merge two real files in
105
+ * production, which is a worse failure than the race it would close.
106
+ */
107
+ export function canonicalRelativePath(relativePath) {
108
+ // Never LAUNDER a path. Dropping empty segments would turn the absolute
109
+ // `/etc/passwd` into the perfectly ordinary `etc/passwd`, and an absolute
110
+ // path is exactly what `path.resolve` lets win over the workspace directory
111
+ // — which is why the workspace-boundary check refuses it today. A path this
112
+ // cannot canonicalise is returned UNCHANGED, so every gate downstream sees
113
+ // what the caller actually sent and goes on refusing it.
114
+ if (relativePath.startsWith('/') || validateRelativePath(relativePath) !== null) {
115
+ return relativePath;
116
+ }
117
+ return relativePath
118
+ .replace(/^\.\//, '')
119
+ .split('/')
120
+ .filter((segment) => segment.length > 0)
121
+ .join('/');
122
+ }
89
123
  /**
90
124
  * Throwing wrapper for the backend service layer — keeps call sites a single
91
125
  * line and produces a clear `Error` the route handler can surface as a 400.
@@ -1 +1 @@
1
- {"version":3,"file":"filename.js","sourceRoot":"","sources":["../../src/workspace/filename.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filename.js","sourceRoot":"","sources":["../../src/workspace/filename.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Which files can carry their OWN frontmatter — and therefore their own
3
+ * per-file access rules.
4
+ *
5
+ * A file-level grant, revoke or restriction splices a `---` YAML block into
6
+ * the file itself. That is right for a Markdown note and destructive for
7
+ * anything else: spliced into a PDF, a presentation or an image it corrupts
8
+ * the bytes (the preview goes blank), and the grant never even resolves.
9
+ * Such a file takes its folder's rules instead.
10
+ *
11
+ * THE ONE predicate for that question: the access routes refuse a file-level
12
+ * mutation on a file it rejects, and the Manage access dialog shows the folder
13
+ * pointer for the same files.
14
+ *
15
+ * The carriers are exactly the files the access resolver reads its own
16
+ * frontmatter from — the backend's core access-frontmatter extension set:
17
+ * Markdown notes (`.md`) and `.tool` definitions (whole-document YAML whose
18
+ * access verbs sit beside the definition). Both are served by the file-reader
19
+ * registry's text-editable text reader. The registry test pins both facts, so
20
+ * this list cannot drift from the resolver or the registry silently. (Neither
21
+ * can live here: the registry's document readers carry backend-only extraction
22
+ * dependencies, and overlays register further extensions at boot — the backend
23
+ * passes its full registered set as `extensions`.)
24
+ *
25
+ * Matching is case-SENSITIVE, as the resolver's is: `Note.MD` carries no
26
+ * enforced rule, so a grant written there would never resolve. An extensionless
27
+ * file is NOT a carrier either: its content may be anything, and a path alone
28
+ * cannot tell a note from a binary.
29
+ */
30
+ export declare const FRONTMATTER_CARRIER_EXTENSIONS: readonly string[];
31
+ /**
32
+ * True when the file at `path` can carry its own frontmatter (and so its own
33
+ * access rules). `extensions` defaults to the core set; the backend passes the
34
+ * resolver's registered set so an overlay's kinds count too.
35
+ */
36
+ export declare function canCarryFrontmatter(path: string, extensions?: readonly string[]): boolean;
37
+ /** The `kind` a refused file-level access mutation answers with. */
38
+ export declare const FOLDER_GOVERNS_ACCESS_KIND = "folder-governs-access";
39
+ /**
40
+ * The one sentence both the 422 and the dialog say, naming the folder whose
41
+ * rules govern the file.
42
+ */
43
+ export declare function folderGovernsAccessMessage(folder: string): string;
44
+ //# sourceMappingURL=frontmatter-carriers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter-carriers.d.ts","sourceRoot":"","sources":["../../src/workspace/frontmatter-carriers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS,MAAM,EAAqB,CAAC;AAElF;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,SAAS,MAAM,EAAmC,GAC7D,OAAO,CAMT;AAED,oEAAoE;AACpE,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAElE;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjE"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Which files can carry their OWN frontmatter — and therefore their own
3
+ * per-file access rules.
4
+ *
5
+ * A file-level grant, revoke or restriction splices a `---` YAML block into
6
+ * the file itself. That is right for a Markdown note and destructive for
7
+ * anything else: spliced into a PDF, a presentation or an image it corrupts
8
+ * the bytes (the preview goes blank), and the grant never even resolves.
9
+ * Such a file takes its folder's rules instead.
10
+ *
11
+ * THE ONE predicate for that question: the access routes refuse a file-level
12
+ * mutation on a file it rejects, and the Manage access dialog shows the folder
13
+ * pointer for the same files.
14
+ *
15
+ * The carriers are exactly the files the access resolver reads its own
16
+ * frontmatter from — the backend's core access-frontmatter extension set:
17
+ * Markdown notes (`.md`) and `.tool` definitions (whole-document YAML whose
18
+ * access verbs sit beside the definition). Both are served by the file-reader
19
+ * registry's text-editable text reader. The registry test pins both facts, so
20
+ * this list cannot drift from the resolver or the registry silently. (Neither
21
+ * can live here: the registry's document readers carry backend-only extraction
22
+ * dependencies, and overlays register further extensions at boot — the backend
23
+ * passes its full registered set as `extensions`.)
24
+ *
25
+ * Matching is case-SENSITIVE, as the resolver's is: `Note.MD` carries no
26
+ * enforced rule, so a grant written there would never resolve. An extensionless
27
+ * file is NOT a carrier either: its content may be anything, and a path alone
28
+ * cannot tell a note from a binary.
29
+ */
30
+ export const FRONTMATTER_CARRIER_EXTENSIONS = ['.md', '.tool'];
31
+ /**
32
+ * True when the file at `path` can carry its own frontmatter (and so its own
33
+ * access rules). `extensions` defaults to the core set; the backend passes the
34
+ * resolver's registered set so an overlay's kinds count too.
35
+ */
36
+ export function canCarryFrontmatter(path, extensions = FRONTMATTER_CARRIER_EXTENSIONS) {
37
+ const name = path.slice(path.lastIndexOf('/') + 1);
38
+ // The resolver's own rule is a plain suffix match, so a file named exactly
39
+ // `.md` is read for its frontmatter there — and must be a carrier here too,
40
+ // or a rule the resolver honours could not be managed.
41
+ return extensions.some((ext) => name.endsWith(ext));
42
+ }
43
+ /** The `kind` a refused file-level access mutation answers with. */
44
+ export const FOLDER_GOVERNS_ACCESS_KIND = 'folder-governs-access';
45
+ /**
46
+ * The one sentence both the 422 and the dialog say, naming the folder whose
47
+ * rules govern the file.
48
+ */
49
+ export function folderGovernsAccessMessage(folder) {
50
+ return `This file's access comes from its folder. Manage access on ${folder} instead.`;
51
+ }
52
+ //# sourceMappingURL=frontmatter-carriers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter-carriers.js","sourceRoot":"","sources":["../../src/workspace/frontmatter-carriers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAElF;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,aAAgC,8BAA8B;IAE9D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACnD,2EAA2E;IAC3E,4EAA4E;IAC5E,uDAAuD;IACvD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAElE;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAAc;IACvD,OAAO,8DAA8D,MAAM,WAAW,CAAC;AACzF,CAAC"}
@@ -1,9 +1,28 @@
1
+ /**
2
+ * THE fence rule: a line is a frontmatter fence when, whitespace aside, it is
3
+ * exactly `---`. Forgiving on purpose — an opening fence with a trailing space
4
+ * or an indented fence is still a fence.
5
+ *
6
+ * Every reader in the platform asks this one function. The access model's
7
+ * line scan always judged fences this way while the splitter below demanded
8
+ * `---` at column 0, so a file written with a near-miss fence had access
9
+ * rules that applied while the catalog, the tool manuals and the frontmatter
10
+ * panel saw no frontmatter at all. One rule, asked everywhere, is what keeps
11
+ * a file from meaning two things.
12
+ */
13
+ export declare function isFrontmatterFence(line: string | undefined): boolean;
1
14
  /**
2
15
  * The ONE `---` frontmatter splitter, shared by backend and frontend so no file
3
- * type grows its own regex. Splits a leading `---`-fenced YAML block from the
4
- * body; null when the text doesn't open with a fence. Parsing the YAML inside is
5
- * the caller's concern (the access-control resolver deliberately keeps its own
6
- * hardened line-based reader — see `modules/access/access-splice.ts`).
16
+ * type grows its own reader. Splits a leading fenced YAML block from the body;
17
+ * null when the first line is not a fence or no later line closes it. Fences
18
+ * are judged by {@link isFrontmatterFence}. Parsing the YAML inside is the
19
+ * caller's concern (the access model keeps its own line scan, on the same
20
+ * fence rule, because a splice must put bytes back exactly as it found them).
21
+ *
22
+ * `frontmatter` is the raw text between the fence lines and `body` the raw
23
+ * text after the closing fence's line break, both byte for byte — line
24
+ * endings included — so a caller that rebuilds the file changes nothing it
25
+ * did not mean to.
7
26
  */
8
27
  export declare function extractFrontmatter(text: string): {
9
28
  frontmatter: string;
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/workspace/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAI7F;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAqBpF"}
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/workspace/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4B7F;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAwBpF"}
@@ -1,15 +1,62 @@
1
+ /**
2
+ * THE fence rule: a line is a frontmatter fence when, whitespace aside, it is
3
+ * exactly `---`. Forgiving on purpose — an opening fence with a trailing space
4
+ * or an indented fence is still a fence.
5
+ *
6
+ * Every reader in the platform asks this one function. The access model's
7
+ * line scan always judged fences this way while the splitter below demanded
8
+ * `---` at column 0, so a file written with a near-miss fence had access
9
+ * rules that applied while the catalog, the tool manuals and the frontmatter
10
+ * panel saw no frontmatter at all. One rule, asked everywhere, is what keeps
11
+ * a file from meaning two things.
12
+ */
13
+ export function isFrontmatterFence(line) {
14
+ return line?.trim() === '---';
15
+ }
1
16
  /**
2
17
  * The ONE `---` frontmatter splitter, shared by backend and frontend so no file
3
- * type grows its own regex. Splits a leading `---`-fenced YAML block from the
4
- * body; null when the text doesn't open with a fence. Parsing the YAML inside is
5
- * the caller's concern (the access-control resolver deliberately keeps its own
6
- * hardened line-based reader — see `modules/access/access-splice.ts`).
18
+ * type grows its own reader. Splits a leading fenced YAML block from the body;
19
+ * null when the first line is not a fence or no later line closes it. Fences
20
+ * are judged by {@link isFrontmatterFence}. Parsing the YAML inside is the
21
+ * caller's concern (the access model keeps its own line scan, on the same
22
+ * fence rule, because a splice must put bytes back exactly as it found them).
23
+ *
24
+ * `frontmatter` is the raw text between the fence lines and `body` the raw
25
+ * text after the closing fence's line break, both byte for byte — line
26
+ * endings included — so a caller that rebuilds the file changes nothing it
27
+ * did not mean to.
7
28
  */
8
29
  export function extractFrontmatter(text) {
9
- const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
10
- if (!m)
11
- return null;
12
- return { frontmatter: m[1], body: m[2] };
30
+ // Walk the lines by offset rather than splitting, so both halves can be
31
+ // sliced out of the original text with their own line endings intact.
32
+ let start = 0;
33
+ let lineIndex = 0;
34
+ let openEnd = -1; // offset just past the opening fence's line break
35
+ while (start <= text.length) {
36
+ const nl = text.indexOf('\n', start);
37
+ const end = nl === -1 ? text.length : nl;
38
+ const line = text.slice(start, end).replace(/\r$/, '');
39
+ const next = nl === -1 ? text.length + 1 : nl + 1;
40
+ if (lineIndex === 0) {
41
+ // A lone `---` with nothing after it opens nothing.
42
+ if (!isFrontmatterFence(line) || nl === -1)
43
+ return null;
44
+ openEnd = next;
45
+ }
46
+ else if (isFrontmatterFence(line)) {
47
+ // The frontmatter ends before the line break that precedes this fence.
48
+ const fmEnd = start - (start >= 2 && text[start - 2] === '\r' ? 2 : 1);
49
+ return {
50
+ frontmatter: fmEnd > openEnd ? text.slice(openEnd, fmEnd) : '',
51
+ body: next > text.length ? '' : text.slice(next),
52
+ };
53
+ }
54
+ if (nl === -1)
55
+ return null; // never closed
56
+ start = next;
57
+ lineIndex += 1;
58
+ }
59
+ return null;
13
60
  }
14
61
  /**
15
62
  * Set a top-level scalar key in a file's `---` frontmatter, LINE-based: replace an
@@ -37,7 +84,10 @@ export function setFrontmatterField(text, key, value) {
37
84
  // No frontmatter — prepend a fresh block, keeping the original body intact.
38
85
  return `---${eol}${line}${eol}---${eol}${text}`;
39
86
  }
40
- const fmLines = fm.frontmatter.split(/\r?\n/);
87
+ // An empty block has no lines, not one empty line: splitting '' would give
88
+ // [''], and the inserted key would be followed by a blank line before the
89
+ // closing fence.
90
+ const fmLines = fm.frontmatter === '' ? [] : fm.frontmatter.split(/\r?\n/);
41
91
  const idx = fmLines.findIndex((l) => keyRe.test(l));
42
92
  if (idx >= 0)
43
93
  fmLines[idx] = line;
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/workspace/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACpE,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,GAAW,EAAE,KAAa;IAC1E,MAAM,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,GAAG,GAAG,KAAK,KAAK,EAAE,CAAC;IAChC,8EAA8E;IAC9E,0EAA0E;IAC1E,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrF,8EAA8E;IAC9E,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,4EAA4E;QAC5E,OAAO,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,MAAM,GAAG,GAAG,IAAI,EAAE,CAAC;IAClD,CAAC;IACD,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;;QAC7B,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;AAClE,CAAC"}
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/workspace/frontmatter.ts"],"names":[],"mappings":"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"}