ctxr-cli 0.16.0 → 0.18.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 (92) hide show
  1. package/README.md +4 -2
  2. package/dist/adapters/harness/claude-code.d.ts.map +1 -1
  3. package/dist/adapters/harness/claude-code.js +34 -37
  4. package/dist/adapters/harness/claude-code.js.map +1 -1
  5. package/dist/adapters/types.d.ts +14 -14
  6. package/dist/adapters/types.d.ts.map +1 -1
  7. package/dist/commands/adapters-generate.d.ts.map +1 -1
  8. package/dist/commands/adapters-generate.js +8 -10
  9. package/dist/commands/adapters-generate.js.map +1 -1
  10. package/dist/commands/init.js +1 -1
  11. package/dist/commands/init.js.map +1 -1
  12. package/dist/commands/publish-check.d.ts +7 -0
  13. package/dist/commands/publish-check.d.ts.map +1 -1
  14. package/dist/commands/publish-check.js +8 -3
  15. package/dist/commands/publish-check.js.map +1 -1
  16. package/dist/commands/publish-new.d.ts +8 -0
  17. package/dist/commands/publish-new.d.ts.map +1 -1
  18. package/dist/commands/publish-new.js +6 -3
  19. package/dist/commands/publish-new.js.map +1 -1
  20. package/dist/commands/serve.d.ts.map +1 -1
  21. package/dist/commands/serve.js +24 -2
  22. package/dist/commands/serve.js.map +1 -1
  23. package/dist/commands/session-start.d.ts +7 -1
  24. package/dist/commands/session-start.d.ts.map +1 -1
  25. package/dist/commands/session-start.js +25 -5
  26. package/dist/commands/session-start.js.map +1 -1
  27. package/dist/config/defaults.d.ts +5 -0
  28. package/dist/config/defaults.d.ts.map +1 -1
  29. package/dist/config/defaults.js +5 -0
  30. package/dist/config/defaults.js.map +1 -1
  31. package/dist/config/schema.d.ts +3 -0
  32. package/dist/config/schema.d.ts.map +1 -1
  33. package/dist/config/schema.js +50 -0
  34. package/dist/config/schema.js.map +1 -1
  35. package/dist/core/browse/nav.d.ts.map +1 -1
  36. package/dist/core/browse/nav.js +51 -5
  37. package/dist/core/browse/nav.js.map +1 -1
  38. package/dist/core/browse/page-url.d.ts +68 -0
  39. package/dist/core/browse/page-url.d.ts.map +1 -0
  40. package/dist/core/browse/page-url.js +101 -0
  41. package/dist/core/browse/page-url.js.map +1 -0
  42. package/dist/core/browse/routes.d.ts +25 -0
  43. package/dist/core/browse/routes.d.ts.map +1 -1
  44. package/dist/core/browse/routes.js +36 -1
  45. package/dist/core/browse/routes.js.map +1 -1
  46. package/dist/core/errors.d.ts +26 -0
  47. package/dist/core/errors.d.ts.map +1 -1
  48. package/dist/core/errors.js +49 -0
  49. package/dist/core/errors.js.map +1 -1
  50. package/dist/core/git/worktree.d.ts +10 -2
  51. package/dist/core/git/worktree.d.ts.map +1 -1
  52. package/dist/core/git/worktree.js +11 -2
  53. package/dist/core/git/worktree.js.map +1 -1
  54. package/dist/core/hooks.d.ts +9 -5
  55. package/dist/core/hooks.d.ts.map +1 -1
  56. package/dist/core/hooks.js +19 -9
  57. package/dist/core/hooks.js.map +1 -1
  58. package/dist/core/json-config-merge.d.ts +9 -1
  59. package/dist/core/json-config-merge.d.ts.map +1 -1
  60. package/dist/core/json-config-merge.js +37 -7
  61. package/dist/core/json-config-merge.js.map +1 -1
  62. package/dist/core/publish/filing.d.ts +5 -24
  63. package/dist/core/publish/filing.d.ts.map +1 -1
  64. package/dist/core/publish/filing.js +5 -36
  65. package/dist/core/publish/filing.js.map +1 -1
  66. package/dist/core/session.d.ts +61 -1
  67. package/dist/core/session.d.ts.map +1 -1
  68. package/dist/core/session.js +111 -2
  69. package/dist/core/session.js.map +1 -1
  70. package/dist/core/slug.d.ts +38 -0
  71. package/dist/core/slug.d.ts.map +1 -0
  72. package/dist/core/slug.js +50 -0
  73. package/dist/core/slug.js.map +1 -0
  74. package/dist/core/write-lifecycle/path-gate.d.ts +0 -28
  75. package/dist/core/write-lifecycle/path-gate.d.ts.map +1 -1
  76. package/dist/core/write-lifecycle/path-gate.js +0 -44
  77. package/dist/core/write-lifecycle/path-gate.js.map +1 -1
  78. package/dist/run.d.ts.map +1 -1
  79. package/dist/run.js +53 -16
  80. package/dist/run.js.map +1 -1
  81. package/dist/version.d.ts +1 -1
  82. package/dist/version.js +1 -1
  83. package/package.json +1 -1
  84. package/templates/conventions/baseline-conventions.md +1 -1
  85. package/templates/skills/ctxr-publish.md +12 -0
  86. package/templates/skills/ctxr-session-lifecycle.md +9 -0
  87. package/templates/skills/ctxr-submit.md +2 -1
  88. package/dist/commands/adapters-write-gate.d.ts +0 -20
  89. package/dist/commands/adapters-write-gate.d.ts.map +0 -1
  90. package/dist/commands/adapters-write-gate.js +0 -77
  91. package/dist/commands/adapters-write-gate.js.map +0 -1
  92. package/templates/hooks/claude-code-write-gate.sh +0 -43
@@ -1,3 +1,4 @@
1
+ import { slugifyPath, slugifySegment } from '../slug.js';
1
2
  /** What names the page's subject: the folder its notes live in, plus the note itself when a note names it. */
2
3
  export interface FilingSubject {
3
4
  /** Store-relative, `/`-separated, unslugified. Empty when the subject names the store root. */
@@ -23,31 +24,11 @@ export interface Filing {
23
24
  moves: FilingMove[];
24
25
  }
25
26
  /**
26
- * derive-the-page-filing-path design.md D6. Lowercase, then NFC — in that
27
- * order, so a decomposed filename and a composed one derive the same slug even
28
- * when lowercasing decomposes a character. Every run of characters that is not
29
- * a letter, digit, or combining mark becomes ONE separator, so no separate
30
- * collapse pass is needed; combining marks survive so a decomposing lowercase
31
- * cannot leave a stray separator behind.
32
- *
33
- * `&` is deliberately not expanded to `and`: that embeds English in a
34
- * derivation shipped to stores written in any language, and `&` is punctuation
35
- * like every other mark. There is deliberately no length cap either —
36
- * slugifying never lengthens its input, so a segment is already bounded by the
37
- * filesystem, and truncation is the one transform that can silently merge two
38
- * distinct subjects onto one path.
39
- *
40
- * Letters and digits of ANY script are kept (`\p{L}`, `\p{N}`). ASCII-folding
41
- * was rejected as a Latin-centric half-measure that slugifies a CJK or Cyrillic
42
- * store's whole taxonomy to empty strings.
43
- *
44
- * Idempotent, and that is load-bearing: `pagesNamingSubject` runs both sides of
45
- * every comparison through this function, which is what makes the scan
46
- * insensitive to filesystem normalization and to whatever case an author typed.
27
+ * Re-exported from `core/slug.ts`, which owns the one normalization rule; the
28
+ * filing module was where it was first written and is still where most callers
29
+ * expect to find it.
47
30
  */
48
- export declare function slugifySegment(raw: string): string;
49
- /** Slugifies a `/`-separated path a segment at a time, dropping any segment that slugifies to nothing (D6). */
50
- export declare function slugifyPath(relativePath: string): string;
31
+ export { slugifyPath, slugifySegment };
51
32
  /**
52
33
  * design.md D2: the group folder comes from the SELECTOR, never from where the
53
34
  * resolved notes live. The deepest common ancestor of a real store's resolved
@@ -1 +1 @@
1
- {"version":3,"file":"filing.d.ts","sourceRoot":"","sources":["../../../src/core/publish/filing.ts"],"names":[],"mappings":"AAOA,8GAA8G;AAC9G,MAAM,WAAW,aAAa;IAC5B,+FAA+F;IAC/F,SAAS,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,oHAAoH;IACpH,UAAU,EAAE,aAAa,GAAG,WAAW,CAAC;CACzC;AAED,MAAM,WAAW,MAAM;IACrB,kHAAkH;IAClH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,oGAAoG;IACpG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uHAAuH;IACvH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,6EAA6E;IAC7E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,+GAA+G;AAC/G,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMxD;AAsFD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClH"}
1
+ {"version":3,"file":"filing.d.ts","sourceRoot":"","sources":["../../../src/core/publish/filing.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEzD,8GAA8G;AAC9G,MAAM,WAAW,aAAa;IAC5B,+FAA+F;IAC/F,SAAS,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,oHAAoH;IACpH,UAAU,EAAE,aAAa,GAAG,WAAW,CAAC;CACzC;AAED,MAAM,WAAW,MAAM;IACrB,kHAAkH;IAClH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,oGAAoG;IACpG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uHAAuH;IACvH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,6EAA6E;IAC7E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;AAsFvC;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClH"}
@@ -4,44 +4,13 @@ import path from 'node:path';
4
4
  import { PUBLISH_INDEX_FILE } from '../browse/routes.js';
5
5
  import { extractLinkTargets } from '../graph/model.js';
6
6
  import { parseNoteText } from '../notes/parse.js';
7
+ import { slugifyPath, slugifySegment } from '../slug.js';
7
8
  /**
8
- * derive-the-page-filing-path design.md D6. Lowercase, then NFC — in that
9
- * order, so a decomposed filename and a composed one derive the same slug even
10
- * when lowercasing decomposes a character. Every run of characters that is not
11
- * a letter, digit, or combining mark becomes ONE separator, so no separate
12
- * collapse pass is needed; combining marks survive so a decomposing lowercase
13
- * cannot leave a stray separator behind.
14
- *
15
- * `&` is deliberately not expanded to `and`: that embeds English in a
16
- * derivation shipped to stores written in any language, and `&` is punctuation
17
- * like every other mark. There is deliberately no length cap either —
18
- * slugifying never lengthens its input, so a segment is already bounded by the
19
- * filesystem, and truncation is the one transform that can silently merge two
20
- * distinct subjects onto one path.
21
- *
22
- * Letters and digits of ANY script are kept (`\p{L}`, `\p{N}`). ASCII-folding
23
- * was rejected as a Latin-centric half-measure that slugifies a CJK or Cyrillic
24
- * store's whole taxonomy to empty strings.
25
- *
26
- * Idempotent, and that is load-bearing: `pagesNamingSubject` runs both sides of
27
- * every comparison through this function, which is what makes the scan
28
- * insensitive to filesystem normalization and to whatever case an author typed.
9
+ * Re-exported from `core/slug.ts`, which owns the one normalization rule; the
10
+ * filing module was where it was first written and is still where most callers
11
+ * expect to find it.
29
12
  */
30
- export function slugifySegment(raw) {
31
- return raw
32
- .toLowerCase()
33
- .normalize('NFC')
34
- .replace(/[^\p{L}\p{N}\p{M}]+/gu, '-')
35
- .replace(/^-+|-+$/g, '');
36
- }
37
- /** Slugifies a `/`-separated path a segment at a time, dropping any segment that slugifies to nothing (D6). */
38
- export function slugifyPath(relativePath) {
39
- return relativePath
40
- .split('/')
41
- .map(slugifySegment)
42
- .filter((segment) => segment.length > 0)
43
- .join('/');
44
- }
13
+ export { slugifyPath, slugifySegment };
45
14
  /** A published page is a directory holding an index page — the same definition the browsing surface uses. */
46
15
  async function pageDirectoriesIn(absoluteDirectory) {
47
16
  let entries;
@@ -1 +1 @@
1
- {"version":3,"file":"filing.js","sourceRoot":"","sources":["../../../src/core/publish/filing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filing.js","sourceRoot":"","sources":["../../../src/core/publish/filing.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,48 @@
1
1
  import type { StoreConfig } from '../config/schema.js';
2
+ /**
3
+ * A caller's session label, normalized to what may appear in a branch name and a
4
+ * directory name; empty when nothing survives, which the caller refuses rather
5
+ * than treating as "no label given" (D3).
6
+ *
7
+ * Truncation prefers the last `-` boundary at or before the cap, so a long label
8
+ * ends on a whole word instead of mid-word; a single over-long word has no
9
+ * boundary to find and is cut at the cap.
10
+ */
11
+ export declare function sessionLabelSlug(raw: string): string;
2
12
  /**
3
13
  * write-lifecycle spec: session branch names are prefixed (configurable —
4
14
  * default "session/") and unique. Sortable by creation time, since that's
5
15
  * useful for `session list`'s ordering without needing to consult git history.
16
+ *
17
+ * A caller's label takes the random suffix's place rather than being appended
18
+ * after it (name-the-session-at-start design.md D2) — the three random bytes
19
+ * only ever bought uniqueness within one second, which a label does at least as
20
+ * well, and a name carrying both a random token and a human one reads as
21
+ * neither. The stamp stays in FRONT of the label: `listSessionWorktreeDirs` and
22
+ * the browse navigation both order worktrees alphabetically, and a leading stamp
23
+ * is what keeps that order chronological.
24
+ *
25
+ * The label is expected pre-normalized by `sessionLabelSlug`, so that a caller
26
+ * refuses an unusable label before anything is created rather than here.
27
+ */
28
+ export declare function generateSessionBranchName(config: StoreConfig, now?: Date, labelSlug?: string): string;
29
+ /**
30
+ * The label a session worktree directory carries, or null when it carries none —
31
+ * recovered by matching the name `generateSessionBranchName` composes, with the
32
+ * stamp at its fixed width.
33
+ *
34
+ * Matched as a whole trailing field rather than by a suffix test, which would
35
+ * report a session labelled `ctx-a` as already holding the label `a`
36
+ * (name-the-session-at-start design.md D7). An unlabelled session's random suffix
37
+ * is six hex characters and is reported as no label.
6
38
  */
7
- export declare function generateSessionBranchName(config: StoreConfig, now?: Date): string;
39
+ export declare function sessionLabelFromDirName(config: StoreConfig, dirName: string): string | null;
40
+ /**
41
+ * The existing session worktree carrying `label`, or null. Reads the filesystem
42
+ * rather than asking git (D7), and finds a session whose branch was renamed by
43
+ * hand, because the directory keeps the name the label went into.
44
+ */
45
+ export declare function findSessionWorktreeByLabel(storeRoot: string, config: StoreConfig, label: string): Promise<string | null>;
8
46
  export declare function isSessionBranch(config: StoreConfig, branch: string): boolean;
9
47
  /**
10
48
  * write-lifecycle spec: a worktree is ALSO recognized as a session by where
@@ -26,4 +64,26 @@ export declare function worktreePathFor(store: {
26
64
  root: string;
27
65
  config: StoreConfig;
28
66
  }, branch: string): string;
67
+ /**
68
+ * The session worktrees present on disk, by directory name.
69
+ *
70
+ * preview-pages-before-they-land D1: discovery is a listing of the CONFIGURED
71
+ * worktrees path rather than `listWorktrees()`, which is better informed and
72
+ * would be the obvious choice anywhere else. The browsing surface rebuilds its
73
+ * route table on every request and caches nothing (local-browsing-surface D2),
74
+ * so asking git here would put a subprocess fork behind every page view, every
75
+ * stylesheet miss, every favicon probe — and caching the answer to avoid that
76
+ * would hide a session started after the server booted, which is the very
77
+ * discovery failure previewing exists to fix.
78
+ *
79
+ * Scanning the path is also the identity rule this module already committed
80
+ * to: `isSessionWorktreePath` above declares a session's durable identity to
81
+ * be its path shape, and `worktreePathFor` puts every session the CLI creates
82
+ * under that path. What it gives up is a worktree made by hand somewhere else,
83
+ * which the CLI never produces.
84
+ *
85
+ * A missing worktrees path yields no worktrees rather than throwing, matching
86
+ * how the published-page walk already treats a store with no publish directory.
87
+ */
88
+ export declare function listSessionWorktreeDirs(storeRoot: string, config: StoreConfig): Promise<string[]>;
29
89
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAQ7F;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAKxF;AAED,yFAAyF;AACzF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpG"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAgBvD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,GAAE,IAAiB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAQjH;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3F;AAMD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAKxF;AAED,yFAAyF;AACzF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpG;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAYvG"}
@@ -1,19 +1,92 @@
1
1
  import { randomBytes } from 'node:crypto';
2
+ import { readdir } from 'node:fs/promises';
2
3
  import path from 'node:path';
4
+ import { slugifySegment } from './slug.js';
5
+ /**
6
+ * The longest a normalized label may be. Not about git, which tolerates far
7
+ * longer refs: the label also becomes a worktree DIRECTORY name, which is a real
8
+ * path segment on every platform, and a preview heading someone has to read.
9
+ *
10
+ * `slugifySegment` deliberately has no cap of its own — truncation there could
11
+ * silently merge two distinct page subjects onto one path. Truncating here
12
+ * cannot do that silently, because two labels that truncate alike produce the
13
+ * same session name, and `session start` refuses a name that already exists
14
+ * (name-the-session-at-start design.md D4) rather than quietly reusing it.
15
+ */
16
+ const MAX_LABEL_LENGTH = 48;
17
+ /**
18
+ * A caller's session label, normalized to what may appear in a branch name and a
19
+ * directory name; empty when nothing survives, which the caller refuses rather
20
+ * than treating as "no label given" (D3).
21
+ *
22
+ * Truncation prefers the last `-` boundary at or before the cap, so a long label
23
+ * ends on a whole word instead of mid-word; a single over-long word has no
24
+ * boundary to find and is cut at the cap.
25
+ */
26
+ export function sessionLabelSlug(raw) {
27
+ const slug = slugifySegment(raw);
28
+ if (slug.length <= MAX_LABEL_LENGTH)
29
+ return slug;
30
+ const cut = slug.slice(0, MAX_LABEL_LENGTH);
31
+ const boundary = cut.lastIndexOf('-');
32
+ return (boundary > 0 ? cut.slice(0, boundary) : cut).replace(/-+$/, '');
33
+ }
3
34
  /**
4
35
  * write-lifecycle spec: session branch names are prefixed (configurable —
5
36
  * default "session/") and unique. Sortable by creation time, since that's
6
37
  * useful for `session list`'s ordering without needing to consult git history.
38
+ *
39
+ * A caller's label takes the random suffix's place rather than being appended
40
+ * after it (name-the-session-at-start design.md D2) — the three random bytes
41
+ * only ever bought uniqueness within one second, which a label does at least as
42
+ * well, and a name carrying both a random token and a human one reads as
43
+ * neither. The stamp stays in FRONT of the label: `listSessionWorktreeDirs` and
44
+ * the browse navigation both order worktrees alphabetically, and a leading stamp
45
+ * is what keeps that order chronological.
46
+ *
47
+ * The label is expected pre-normalized by `sessionLabelSlug`, so that a caller
48
+ * refuses an unusable label before anything is created rather than here.
7
49
  */
8
- export function generateSessionBranchName(config, now = new Date()) {
50
+ export function generateSessionBranchName(config, now = new Date(), labelSlug) {
9
51
  const stamp = now
10
52
  .toISOString()
11
53
  .replace(/[-:]/g, '')
12
54
  .replace(/\.\d+Z$/, '')
13
55
  .replace('T', '-');
14
- const suffix = randomBytes(3).toString('hex');
56
+ const suffix = labelSlug && labelSlug.length > 0 ? labelSlug : randomBytes(3).toString('hex');
15
57
  return `${config.session.branch_prefix}${stamp}-${suffix}`;
16
58
  }
59
+ /**
60
+ * The label a session worktree directory carries, or null when it carries none —
61
+ * recovered by matching the name `generateSessionBranchName` composes, with the
62
+ * stamp at its fixed width.
63
+ *
64
+ * Matched as a whole trailing field rather than by a suffix test, which would
65
+ * report a session labelled `ctx-a` as already holding the label `a`
66
+ * (name-the-session-at-start design.md D7). An unlabelled session's random suffix
67
+ * is six hex characters and is reported as no label.
68
+ */
69
+ export function sessionLabelFromDirName(config, dirName) {
70
+ const prefix = worktreeDirNameFor(config.session.branch_prefix);
71
+ const pattern = new RegExp(`^${escapeForRegExp(prefix)}\\d{8}-\\d{6}-(.+)$`);
72
+ const label = pattern.exec(dirName)?.[1];
73
+ if (label === undefined)
74
+ return null;
75
+ return /^[0-9a-f]{6}$/.test(label) ? null : label;
76
+ }
77
+ function escapeForRegExp(raw) {
78
+ return raw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
79
+ }
80
+ /**
81
+ * The existing session worktree carrying `label`, or null. Reads the filesystem
82
+ * rather than asking git (D7), and finds a session whose branch was renamed by
83
+ * hand, because the directory keeps the name the label went into.
84
+ */
85
+ export async function findSessionWorktreeByLabel(storeRoot, config, label) {
86
+ const dirs = await listSessionWorktreeDirs(storeRoot, config);
87
+ const match = dirs.find((dir) => sessionLabelFromDirName(config, dir) === label);
88
+ return match === undefined ? null : path.join(storeRoot, config.session.worktrees_path, match);
89
+ }
17
90
  export function isSessionBranch(config, branch) {
18
91
  return branch.startsWith(config.session.branch_prefix);
19
92
  }
@@ -43,4 +116,40 @@ export function worktreeDirNameFor(branch) {
43
116
  export function worktreePathFor(store, branch) {
44
117
  return path.join(store.root, store.config.session.worktrees_path, worktreeDirNameFor(branch));
45
118
  }
119
+ /**
120
+ * The session worktrees present on disk, by directory name.
121
+ *
122
+ * preview-pages-before-they-land D1: discovery is a listing of the CONFIGURED
123
+ * worktrees path rather than `listWorktrees()`, which is better informed and
124
+ * would be the obvious choice anywhere else. The browsing surface rebuilds its
125
+ * route table on every request and caches nothing (local-browsing-surface D2),
126
+ * so asking git here would put a subprocess fork behind every page view, every
127
+ * stylesheet miss, every favicon probe — and caching the answer to avoid that
128
+ * would hide a session started after the server booted, which is the very
129
+ * discovery failure previewing exists to fix.
130
+ *
131
+ * Scanning the path is also the identity rule this module already committed
132
+ * to: `isSessionWorktreePath` above declares a session's durable identity to
133
+ * be its path shape, and `worktreePathFor` puts every session the CLI creates
134
+ * under that path. What it gives up is a worktree made by hand somewhere else,
135
+ * which the CLI never produces.
136
+ *
137
+ * A missing worktrees path yields no worktrees rather than throwing, matching
138
+ * how the published-page walk already treats a store with no publish directory.
139
+ */
140
+ export async function listSessionWorktreeDirs(storeRoot, config) {
141
+ let entries;
142
+ try {
143
+ entries = await readdir(path.join(storeRoot, config.session.worktrees_path), { withFileTypes: true });
144
+ }
145
+ catch (err) {
146
+ if (err.code === 'ENOENT')
147
+ return [];
148
+ throw err;
149
+ }
150
+ return entries
151
+ .filter((entry) => entry.isDirectory())
152
+ .map((entry) => entry.name)
153
+ .sort();
154
+ }
46
155
  //# sourceMappingURL=session.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAmB,EAAE,GAAG,GAAS,IAAI,IAAI,EAAE;IACnF,MAAM,KAAK,GAAG,GAAG;SACd,WAAW,EAAE;SACb,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACrB,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,GAAG,KAAK,IAAI,MAAM,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAmB,EAAE,MAAc;IACjE,OAAO,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAmB,EAAE,YAAoB;IAC7E,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAClD,OAAO,KAAK,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAA4C,EAAE,MAAc;IAC1F,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;AAChG,CAAC"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Turning a caller-supplied name into a path segment, in one place: the publish
3
+ * path's page slugs and a session's label are the same question asked twice, and
4
+ * two normalizers would eventually disagree about a character neither author
5
+ * considered.
6
+ *
7
+ * Lives here rather than in `publish/filing.ts`, where it was first written,
8
+ * because `core/session.ts` needs it and `filing.ts` reaches `browse/routes.ts`,
9
+ * which reaches `session.ts` — importing it across that arc would close an import
10
+ * cycle for a four-line pure function.
11
+ */
12
+ /**
13
+ * derive-the-page-filing-path design.md D6. Lowercase, then NFC — in that
14
+ * order, so a decomposed filename and a composed one derive the same slug even
15
+ * when lowercasing decomposes a character. Every run of characters that is not
16
+ * a letter, digit, or combining mark becomes ONE separator, so no separate
17
+ * collapse pass is needed; combining marks survive so a decomposing lowercase
18
+ * cannot leave a stray separator behind.
19
+ *
20
+ * `&` is deliberately not expanded to `and`: that embeds English in a
21
+ * derivation shipped to stores written in any language, and `&` is punctuation
22
+ * like every other mark. There is deliberately no length cap either —
23
+ * slugifying never lengthens its input, so a segment is already bounded by the
24
+ * filesystem, and truncation is the one transform that can silently merge two
25
+ * distinct subjects onto one path.
26
+ *
27
+ * Letters and digits of ANY script are kept (`\p{L}`, `\p{N}`). ASCII-folding
28
+ * was rejected as a Latin-centric half-measure that slugifies a CJK or Cyrillic
29
+ * store's whole taxonomy to empty strings.
30
+ *
31
+ * Idempotent, and that is load-bearing: `pagesNamingSubject` runs both sides of
32
+ * every comparison through this function, which is what makes the scan
33
+ * insensitive to filesystem normalization and to whatever case an author typed.
34
+ */
35
+ export declare function slugifySegment(raw: string): string;
36
+ /** Slugifies a `/`-separated path a segment at a time, dropping any segment that slugifies to nothing (D6). */
37
+ export declare function slugifyPath(relativePath: string): string;
38
+ //# sourceMappingURL=slug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../src/core/slug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,+GAA+G;AAC/G,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMxD"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Turning a caller-supplied name into a path segment, in one place: the publish
3
+ * path's page slugs and a session's label are the same question asked twice, and
4
+ * two normalizers would eventually disagree about a character neither author
5
+ * considered.
6
+ *
7
+ * Lives here rather than in `publish/filing.ts`, where it was first written,
8
+ * because `core/session.ts` needs it and `filing.ts` reaches `browse/routes.ts`,
9
+ * which reaches `session.ts` — importing it across that arc would close an import
10
+ * cycle for a four-line pure function.
11
+ */
12
+ /**
13
+ * derive-the-page-filing-path design.md D6. Lowercase, then NFC — in that
14
+ * order, so a decomposed filename and a composed one derive the same slug even
15
+ * when lowercasing decomposes a character. Every run of characters that is not
16
+ * a letter, digit, or combining mark becomes ONE separator, so no separate
17
+ * collapse pass is needed; combining marks survive so a decomposing lowercase
18
+ * cannot leave a stray separator behind.
19
+ *
20
+ * `&` is deliberately not expanded to `and`: that embeds English in a
21
+ * derivation shipped to stores written in any language, and `&` is punctuation
22
+ * like every other mark. There is deliberately no length cap either —
23
+ * slugifying never lengthens its input, so a segment is already bounded by the
24
+ * filesystem, and truncation is the one transform that can silently merge two
25
+ * distinct subjects onto one path.
26
+ *
27
+ * Letters and digits of ANY script are kept (`\p{L}`, `\p{N}`). ASCII-folding
28
+ * was rejected as a Latin-centric half-measure that slugifies a CJK or Cyrillic
29
+ * store's whole taxonomy to empty strings.
30
+ *
31
+ * Idempotent, and that is load-bearing: `pagesNamingSubject` runs both sides of
32
+ * every comparison through this function, which is what makes the scan
33
+ * insensitive to filesystem normalization and to whatever case an author typed.
34
+ */
35
+ export function slugifySegment(raw) {
36
+ return raw
37
+ .toLowerCase()
38
+ .normalize('NFC')
39
+ .replace(/[^\p{L}\p{N}\p{M}]+/gu, '-')
40
+ .replace(/^-+|-+$/g, '');
41
+ }
42
+ /** Slugifies a `/`-separated path a segment at a time, dropping any segment that slugifies to nothing (D6). */
43
+ export function slugifyPath(relativePath) {
44
+ return relativePath
45
+ .split('/')
46
+ .map(slugifySegment)
47
+ .filter((segment) => segment.length > 0)
48
+ .join('/');
49
+ }
50
+ //# sourceMappingURL=slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/core/slug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,GAAG;SACP,WAAW,EAAE;SACb,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC;SACrC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,+GAA+G;AAC/G,MAAM,UAAU,WAAW,CAAC,YAAoB;IAC9C,OAAO,YAAY;SAChB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,cAAc,CAAC;SACnB,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;SACvC,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC"}
@@ -17,32 +17,4 @@ export interface PathGateResult {
17
17
  * a contexture-owned location passes.
18
18
  */
19
19
  export declare function sanctionedPath(config: StoreConfig, root: string, relativePath: string): Promise<PathGateResult>;
20
- export interface WriteScopeResult {
21
- inScope: boolean;
22
- reason?: string;
23
- }
24
- /**
25
- * The Claude Code write-gate hook's question: is `relativePath` safe for a
26
- * session opened at the store root to edit directly? In scope when it
27
- * resolves outside the store entirely (not this gate's concern — the
28
- * store's canonical checkout is what it protects) or inside the configured
29
- * session-worktree tree; out of scope, and denied, when it resolves inside
30
- * the store root's own content, including when a symlink disguises the
31
- * escape in either direction (reuses `resolveStorePath`'s escape check,
32
- * same as `sanctionedPath`, so the two can never disagree on what counts as
33
- * an escape).
34
- *
35
- * A `root` that is itself a linked worktree checkout is always in scope,
36
- * regardless of `relativePath`: `openStore` resolves the store root by
37
- * walking up from cwd for the nearest `contexture.yaml`, and every session
38
- * worktree carries its own copy of that file — so a session whose cwd is
39
- * already inside the worktree resolves the worktree itself as `root`, and
40
- * without this carve-out every edit in it would read as "in the store root,
41
- * outside the worktree" and be denied. The gate's actual job is protecting
42
- * the canonical checkout; a linked worktree IS the sanctioned workspace,
43
- * whichever directory a session happens to be driven from — this also
44
- * covers `session.workspaces_external: true` stores, whose worktrees an
45
- * external process may place outside `session.worktrees_path` entirely.
46
- */
47
- export declare function isWriteInScope(config: StoreConfig, root: string, relativePath: string): Promise<WriteScopeResult>;
48
20
  //# sourceMappingURL=path-gate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-gate.d.ts","sourceRoot":"","sources":["../../../src/core/write-lifecycle/path-gate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAI1D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsFD;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAsBrH;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqBvH"}
1
+ {"version":3,"file":"path-gate.d.ts","sourceRoot":"","sources":["../../../src/core/write-lifecycle/path-gate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAI1D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsFD;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAsBrH"}
@@ -107,48 +107,4 @@ export async function sanctionedPath(config, root, relativePath) {
107
107
  }
108
108
  return { ok: true };
109
109
  }
110
- /**
111
- * The Claude Code write-gate hook's question: is `relativePath` safe for a
112
- * session opened at the store root to edit directly? In scope when it
113
- * resolves outside the store entirely (not this gate's concern — the
114
- * store's canonical checkout is what it protects) or inside the configured
115
- * session-worktree tree; out of scope, and denied, when it resolves inside
116
- * the store root's own content, including when a symlink disguises the
117
- * escape in either direction (reuses `resolveStorePath`'s escape check,
118
- * same as `sanctionedPath`, so the two can never disagree on what counts as
119
- * an escape).
120
- *
121
- * A `root` that is itself a linked worktree checkout is always in scope,
122
- * regardless of `relativePath`: `openStore` resolves the store root by
123
- * walking up from cwd for the nearest `contexture.yaml`, and every session
124
- * worktree carries its own copy of that file — so a session whose cwd is
125
- * already inside the worktree resolves the worktree itself as `root`, and
126
- * without this carve-out every edit in it would read as "in the store root,
127
- * outside the worktree" and be denied. The gate's actual job is protecting
128
- * the canonical checkout; a linked worktree IS the sanctioned workspace,
129
- * whichever directory a session happens to be driven from — this also
130
- * covers `session.workspaces_external: true` stores, whose worktrees an
131
- * external process may place outside `session.worktrees_path` entirely.
132
- */
133
- export async function isWriteInScope(config, root, relativePath) {
134
- const resolution = await resolveStorePath(root, relativePath);
135
- if (resolution.kind === 'outside_store') {
136
- return { inScope: true };
137
- }
138
- if (resolution.kind === 'symlink_escape') {
139
- return { inScope: false, reason: 'escapes the store through a symbolic link' };
140
- }
141
- const worktreesPrefix = normalizePrefix(config.session.worktrees_path);
142
- const { rel } = resolution;
143
- if (rel === worktreesPrefix || rel.startsWith(`${worktreesPrefix}/`)) {
144
- return { inScope: true };
145
- }
146
- if (isLinkedWorktreeRoot(root)) {
147
- return { inScope: true };
148
- }
149
- return {
150
- inScope: false,
151
- reason: `is in the store root at "${rel}", outside the active session worktree ("${config.session.worktrees_path}")`,
152
- };
153
- }
154
110
  //# sourceMappingURL=path-gate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-gate.js","sourceRoot":"","sources":["../../../src/core/write-lifecycle/path-gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"path-gate.js","sourceRoot":"","sources":["../../../src/core/write-lifecycle/path-gate.ts"],"names":[],"mappings":"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"}
package/dist/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQhD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,YAAI,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAU,CAAC;AA+GpE,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAghBjF"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQhD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,YAAI,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAU,CAAC;AAuIpE,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+hBjF"}