@cad0p/pi-steering 0.1.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 (246) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +29 -0
  3. package/README.md +920 -0
  4. package/dist/__test-helpers__.d.ts +95 -0
  5. package/dist/__test-helpers__.d.ts.map +1 -0
  6. package/dist/__test-helpers__.js +174 -0
  7. package/dist/__test-helpers__.js.map +1 -0
  8. package/dist/bin/pi-steering.d.ts +9 -0
  9. package/dist/bin/pi-steering.d.ts.map +1 -0
  10. package/dist/bin/pi-steering.js +506 -0
  11. package/dist/bin/pi-steering.js.map +1 -0
  12. package/dist/compat.d.ts +50 -0
  13. package/dist/compat.d.ts.map +1 -0
  14. package/dist/compat.js +180 -0
  15. package/dist/compat.js.map +1 -0
  16. package/dist/defaults.d.ts +61 -0
  17. package/dist/defaults.d.ts.map +1 -0
  18. package/dist/defaults.js +106 -0
  19. package/dist/defaults.js.map +1 -0
  20. package/dist/define-config.d.ts +235 -0
  21. package/dist/define-config.d.ts.map +1 -0
  22. package/dist/define-config.js +118 -0
  23. package/dist/define-config.js.map +1 -0
  24. package/dist/define-predicate.d.ts +49 -0
  25. package/dist/define-predicate.d.ts.map +1 -0
  26. package/dist/define-predicate.js +35 -0
  27. package/dist/define-predicate.js.map +1 -0
  28. package/dist/evaluator-internals/context.d.ts +186 -0
  29. package/dist/evaluator-internals/context.d.ts.map +1 -0
  30. package/dist/evaluator-internals/context.js +219 -0
  31. package/dist/evaluator-internals/context.js.map +1 -0
  32. package/dist/evaluator-internals/override.d.ts +19 -0
  33. package/dist/evaluator-internals/override.d.ts.map +1 -0
  34. package/dist/evaluator-internals/override.js +79 -0
  35. package/dist/evaluator-internals/override.js.map +1 -0
  36. package/dist/evaluator-internals/predicates.d.ts +152 -0
  37. package/dist/evaluator-internals/predicates.d.ts.map +1 -0
  38. package/dist/evaluator-internals/predicates.js +849 -0
  39. package/dist/evaluator-internals/predicates.js.map +1 -0
  40. package/dist/evaluator-internals/speculative-synthesis.d.ts +102 -0
  41. package/dist/evaluator-internals/speculative-synthesis.d.ts.map +1 -0
  42. package/dist/evaluator-internals/speculative-synthesis.js +101 -0
  43. package/dist/evaluator-internals/speculative-synthesis.js.map +1 -0
  44. package/dist/evaluator.d.ts +101 -0
  45. package/dist/evaluator.d.ts.map +1 -0
  46. package/dist/evaluator.js +714 -0
  47. package/dist/evaluator.js.map +1 -0
  48. package/dist/helpers/walker-unknown-cwd-reason.d.ts +68 -0
  49. package/dist/helpers/walker-unknown-cwd-reason.d.ts.map +1 -0
  50. package/dist/helpers/walker-unknown-cwd-reason.js +73 -0
  51. package/dist/helpers/walker-unknown-cwd-reason.js.map +1 -0
  52. package/dist/index.d.ts +42 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +93 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/internal/drop-unused-observers.d.ts +43 -0
  57. package/dist/internal/drop-unused-observers.d.ts.map +1 -0
  58. package/dist/internal/drop-unused-observers.js +50 -0
  59. package/dist/internal/drop-unused-observers.js.map +1 -0
  60. package/dist/internal/finalize-plugin-state.d.ts +22 -0
  61. package/dist/internal/finalize-plugin-state.d.ts.map +1 -0
  62. package/dist/internal/finalize-plugin-state.js +14 -0
  63. package/dist/internal/finalize-plugin-state.js.map +1 -0
  64. package/dist/internal/merge-observers.d.ts +30 -0
  65. package/dist/internal/merge-observers.d.ts.map +1 -0
  66. package/dist/internal/merge-observers.js +27 -0
  67. package/dist/internal/merge-observers.js.map +1 -0
  68. package/dist/internal/pattern-utils.d.ts +33 -0
  69. package/dist/internal/pattern-utils.d.ts.map +1 -0
  70. package/dist/internal/pattern-utils.js +20 -0
  71. package/dist/internal/pattern-utils.js.map +1 -0
  72. package/dist/internal/ref-text.d.ts +11 -0
  73. package/dist/internal/ref-text.d.ts.map +1 -0
  74. package/dist/internal/ref-text.js +15 -0
  75. package/dist/internal/ref-text.js.map +1 -0
  76. package/dist/internal/session-runtime.d.ts +44 -0
  77. package/dist/internal/session-runtime.d.ts.map +1 -0
  78. package/dist/internal/session-runtime.js +143 -0
  79. package/dist/internal/session-runtime.js.map +1 -0
  80. package/dist/internal/watch-matcher.d.ts +56 -0
  81. package/dist/internal/watch-matcher.d.ts.map +1 -0
  82. package/dist/internal/watch-matcher.js +179 -0
  83. package/dist/internal/watch-matcher.js.map +1 -0
  84. package/dist/loader.d.ts +97 -0
  85. package/dist/loader.d.ts.map +1 -0
  86. package/dist/loader.js +527 -0
  87. package/dist/loader.js.map +1 -0
  88. package/dist/observer-dispatcher.d.ts +69 -0
  89. package/dist/observer-dispatcher.d.ts.map +1 -0
  90. package/dist/observer-dispatcher.js +184 -0
  91. package/dist/observer-dispatcher.js.map +1 -0
  92. package/dist/plugin-merger.d.ts +175 -0
  93. package/dist/plugin-merger.d.ts.map +1 -0
  94. package/dist/plugin-merger.js +450 -0
  95. package/dist/plugin-merger.js.map +1 -0
  96. package/dist/plugins/git/branch-tracker.d.ts +85 -0
  97. package/dist/plugins/git/branch-tracker.d.ts.map +1 -0
  98. package/dist/plugins/git/branch-tracker.js +181 -0
  99. package/dist/plugins/git/branch-tracker.js.map +1 -0
  100. package/dist/plugins/git/cwd-extensions.d.ts +10 -0
  101. package/dist/plugins/git/cwd-extensions.d.ts.map +1 -0
  102. package/dist/plugins/git/cwd-extensions.js +155 -0
  103. package/dist/plugins/git/cwd-extensions.js.map +1 -0
  104. package/dist/plugins/git/git-ops.d.ts +89 -0
  105. package/dist/plugins/git/git-ops.d.ts.map +1 -0
  106. package/dist/plugins/git/git-ops.js +107 -0
  107. package/dist/plugins/git/git-ops.js.map +1 -0
  108. package/dist/plugins/git/index.d.ts +225 -0
  109. package/dist/plugins/git/index.d.ts.map +1 -0
  110. package/dist/plugins/git/index.js +52 -0
  111. package/dist/plugins/git/index.js.map +1 -0
  112. package/dist/plugins/git/predicates.d.ts +312 -0
  113. package/dist/plugins/git/predicates.d.ts.map +1 -0
  114. package/dist/plugins/git/predicates.js +580 -0
  115. package/dist/plugins/git/predicates.js.map +1 -0
  116. package/dist/plugins/git/rules.d.ts +209 -0
  117. package/dist/plugins/git/rules.d.ts.map +1 -0
  118. package/dist/plugins/git/rules.js +267 -0
  119. package/dist/plugins/git/rules.js.map +1 -0
  120. package/dist/schema.d.ts +1799 -0
  121. package/dist/schema.d.ts.map +1 -0
  122. package/dist/schema.js +4 -0
  123. package/dist/schema.js.map +1 -0
  124. package/dist/testing/index.d.ts +621 -0
  125. package/dist/testing/index.d.ts.map +1 -0
  126. package/dist/testing/index.js +747 -0
  127. package/dist/testing/index.js.map +1 -0
  128. package/examples/README.md +83 -0
  129. package/examples/combined-git-discipline/README.md +52 -0
  130. package/examples/combined-git-discipline/node_modules/.bin/pi-steering +43 -0
  131. package/examples/combined-git-discipline/package.json +18 -0
  132. package/examples/combined-git-discipline/steering.json +27 -0
  133. package/examples/combined-git-discipline/steering.test.ts +42 -0
  134. package/examples/combined-git-discipline/steering.ts +64 -0
  135. package/examples/combined-git-discipline/tsconfig.json +7 -0
  136. package/examples/draft-prs-only/README.md +42 -0
  137. package/examples/draft-prs-only/node_modules/.bin/pi-steering +43 -0
  138. package/examples/draft-prs-only/package.json +18 -0
  139. package/examples/draft-prs-only/steering.json +12 -0
  140. package/examples/draft-prs-only/steering.test.ts +48 -0
  141. package/examples/draft-prs-only/steering.ts +36 -0
  142. package/examples/draft-prs-only/tsconfig.json +7 -0
  143. package/examples/dynamic-reason-runtime-cwd/README.md +148 -0
  144. package/examples/dynamic-reason-runtime-cwd/node_modules/.bin/pi-steering +43 -0
  145. package/examples/dynamic-reason-runtime-cwd/package.json +18 -0
  146. package/examples/dynamic-reason-runtime-cwd/steering.test.ts +130 -0
  147. package/examples/dynamic-reason-runtime-cwd/steering.ts +82 -0
  148. package/examples/dynamic-reason-runtime-cwd/tsconfig.json +7 -0
  149. package/examples/force-push-strict/README.md +75 -0
  150. package/examples/force-push-strict/node_modules/.bin/pi-steering +43 -0
  151. package/examples/force-push-strict/package.json +18 -0
  152. package/examples/force-push-strict/steering.json +12 -0
  153. package/examples/force-push-strict/steering.test.ts +51 -0
  154. package/examples/force-push-strict/steering.ts +54 -0
  155. package/examples/force-push-strict/tsconfig.json +7 -0
  156. package/examples/no-amend/README.md +52 -0
  157. package/examples/no-amend/node_modules/.bin/pi-steering +43 -0
  158. package/examples/no-amend/package.json +18 -0
  159. package/examples/no-amend/steering.cwd-scoped.json +12 -0
  160. package/examples/no-amend/steering.json +11 -0
  161. package/examples/no-amend/steering.test.ts +49 -0
  162. package/examples/no-amend/steering.ts +38 -0
  163. package/examples/no-amend/tsconfig.json +7 -0
  164. package/examples/work-item-plugin/README.md +103 -0
  165. package/examples/work-item-plugin/node_modules/.bin/pi-steering +43 -0
  166. package/examples/work-item-plugin/package.json +19 -0
  167. package/examples/work-item-plugin/src/index.test.ts +168 -0
  168. package/examples/work-item-plugin/src/index.ts +122 -0
  169. package/examples/work-item-plugin/src/observers/npm-test-tracker.test.ts +95 -0
  170. package/examples/work-item-plugin/src/observers/npm-test-tracker.ts +88 -0
  171. package/examples/work-item-plugin/src/observers/retest-required-tracker.test.ts +81 -0
  172. package/examples/work-item-plugin/src/observers/retest-required-tracker.ts +81 -0
  173. package/examples/work-item-plugin/src/predicates/work-item-format.test.ts +157 -0
  174. package/examples/work-item-plugin/src/predicates/work-item-format.ts +99 -0
  175. package/examples/work-item-plugin/src/rules/commit-description-check.test.ts +107 -0
  176. package/examples/work-item-plugin/src/rules/commit-description-check.ts +83 -0
  177. package/examples/work-item-plugin/src/rules/commit-requires-work-item.test.ts +79 -0
  178. package/examples/work-item-plugin/src/rules/commit-requires-work-item.ts +56 -0
  179. package/examples/work-item-plugin/src/rules/push-requires-tests.test.ts +245 -0
  180. package/examples/work-item-plugin/src/rules/push-requires-tests.ts +62 -0
  181. package/examples/work-item-plugin/tsconfig.json +8 -0
  182. package/package.json +88 -0
  183. package/skills/steering-authoring/SKILL.md +102 -0
  184. package/src/INVARIANTS.md +116 -0
  185. package/src/__test-helpers__.ts +243 -0
  186. package/src/bin/pi-steering.test.ts +920 -0
  187. package/src/bin/pi-steering.ts +584 -0
  188. package/src/compat.test.ts +431 -0
  189. package/src/compat.ts +282 -0
  190. package/src/defaults.test.ts +585 -0
  191. package/src/defaults.ts +148 -0
  192. package/src/define-config.test.ts +888 -0
  193. package/src/define-config.ts +375 -0
  194. package/src/define-predicate.test.ts +70 -0
  195. package/src/define-predicate.ts +57 -0
  196. package/src/evaluator-internals/context.ts +290 -0
  197. package/src/evaluator-internals/override.test.ts +99 -0
  198. package/src/evaluator-internals/override.ts +83 -0
  199. package/src/evaluator-internals/predicates.ts +1037 -0
  200. package/src/evaluator-internals/speculative-synthesis.test.ts +411 -0
  201. package/src/evaluator-internals/speculative-synthesis.ts +199 -0
  202. package/src/evaluator.test.ts +6296 -0
  203. package/src/evaluator.ts +1106 -0
  204. package/src/factory-time-load.test.ts +630 -0
  205. package/src/helpers/walker-unknown-cwd-reason.test.ts +73 -0
  206. package/src/helpers/walker-unknown-cwd-reason.ts +83 -0
  207. package/src/index.test.ts +836 -0
  208. package/src/index.ts +229 -0
  209. package/src/internal/drop-unused-observers.test.ts +141 -0
  210. package/src/internal/drop-unused-observers.ts +81 -0
  211. package/src/internal/finalize-plugin-state.ts +43 -0
  212. package/src/internal/merge-observers.ts +51 -0
  213. package/src/internal/pattern-utils.test.ts +52 -0
  214. package/src/internal/pattern-utils.ts +38 -0
  215. package/src/internal/ref-text.test.ts +54 -0
  216. package/src/internal/ref-text.ts +17 -0
  217. package/src/internal/session-runtime.test.ts +629 -0
  218. package/src/internal/session-runtime.ts +201 -0
  219. package/src/internal/watch-matcher.test.ts +326 -0
  220. package/src/internal/watch-matcher.ts +200 -0
  221. package/src/jsdoc-propagation.test.ts +277 -0
  222. package/src/loader.test.ts +1098 -0
  223. package/src/loader.ts +581 -0
  224. package/src/not-block-onunknown.test.ts +554 -0
  225. package/src/observer-dispatcher.test.ts +939 -0
  226. package/src/observer-dispatcher.ts +290 -0
  227. package/src/per-predicate-typing.test.ts +361 -0
  228. package/src/plugin-merger.test.ts +790 -0
  229. package/src/plugin-merger.ts +598 -0
  230. package/src/plugins/git/README.md +485 -0
  231. package/src/plugins/git/branch-tracker.test.ts +281 -0
  232. package/src/plugins/git/branch-tracker.ts +187 -0
  233. package/src/plugins/git/cwd-extensions.test.ts +230 -0
  234. package/src/plugins/git/cwd-extensions.ts +160 -0
  235. package/src/plugins/git/git-ops.test.ts +397 -0
  236. package/src/plugins/git/git-ops.ts +173 -0
  237. package/src/plugins/git/index.ts +253 -0
  238. package/src/plugins/git/integration.test.ts +705 -0
  239. package/src/plugins/git/predicates.test.ts +1401 -0
  240. package/src/plugins/git/predicates.ts +693 -0
  241. package/src/plugins/git/rules.test.ts +1001 -0
  242. package/src/plugins/git/rules.ts +307 -0
  243. package/src/schema.test.ts +259 -0
  244. package/src/schema.ts +1963 -0
  245. package/src/testing/index.test.ts +1696 -0
  246. package/src/testing/index.ts +1472 -0
@@ -0,0 +1,95 @@
1
+ import type { ExtensionContext, ExecResult as PiExecResult } from "@earendil-works/pi-coding-agent";
2
+ import type { EvaluatorHost } from "./evaluator-internals/context.ts";
3
+ /**
4
+ * Per-test scratch `$HOME` fixture. Registers `beforeEach` /
5
+ * `afterEach` that:
6
+ *
7
+ * - `mkdtempSync` a fresh temp dir using `prefix`,
8
+ * - save `process.env["HOME"]`, point it at the temp dir,
9
+ * - restore `process.env["HOME"]` and recursively remove the temp
10
+ * dir on teardown.
11
+ *
12
+ * Used by every test surface that exercises the loader walk-up
13
+ * (`index.test.ts`, `loader.test.ts`, `internal/session-runtime.test.ts`)
14
+ * so the per-file scratch-HOME boilerplate stays in one place.
15
+ *
16
+ * The temp dir path is exposed via the optional `onReady` callback,
17
+ * fired inside `beforeEach`; tests typically stash it in a
18
+ * describe-scoped `let` for terser reads.
19
+ */
20
+ export declare function useIsolatedHome(prefix: string, onReady?: (tmp: string) => void): void;
21
+ /**
22
+ * Like {@link useIsolatedHome} but also chdirs into the scratch dir, so factory-time tests find the per-test config via the loader walk-up. macOS tmpdir is a symlink; canonicalized via `realpathSync` so cwd-mismatch tests don't see false-divergence.
23
+ */
24
+ export declare function useScratchHome(prefix: string, onReady?: (tmp: string) => void): void;
25
+ /**
26
+ * Write a single-file steering config to `<dir>/.pi/steering.ts`.
27
+ * `body` is the full module source (must include `export default`).
28
+ * Used by suites whose fixtures embed regex literals or other
29
+ * non-JSON-friendly module shapes inline.
30
+ */
31
+ export declare function writeSteeringSingleFileConfig(dir: string, body: string): void;
32
+ /**
33
+ * Write a directory-form steering config to
34
+ * `<dir>/.pi/steering/index.ts`. `body` is the full module source
35
+ * (must include `export default`). Mirrors the layout the bin tests
36
+ * use for their isolated `@cad0p/pi-steering` invocations.
37
+ */
38
+ export declare function writeSteeringDirConfig(dir: string, body: string): void;
39
+ /**
40
+ * Exact shape pi's `sessionManager.getEntries()` returns for entries
41
+ * produced by `appendEntry`. The evaluator filters to `type: "custom"`,
42
+ * matches by `customType`, and reads `{ data, timestamp }` — other
43
+ * fields (`id`, `parentId`) exist on real entries so we mirror them
44
+ * here to avoid silent type drift.
45
+ */
46
+ export interface CustomEntry {
47
+ readonly type: "custom";
48
+ readonly customType: string;
49
+ readonly data: unknown;
50
+ readonly timestamp: string;
51
+ readonly id: string;
52
+ readonly parentId: string | null;
53
+ }
54
+ /**
55
+ * Minimal stub for pi's `ExtensionContext`. Only the fields the
56
+ * evaluator + observer-dispatcher read are populated; everything else
57
+ * throws if touched so accidental reliance on unsupported surface
58
+ * breaks loudly.
59
+ *
60
+ * The `entries` array mimics `sessionManager.getEntries()` output —
61
+ * tests that want cross-handler `findEntries` visibility pass
62
+ * `host.entries` (from {@link makeTrackedHost}) here so the host's
63
+ * `appendEntry` writes show up on subsequent reads.
64
+ */
65
+ export declare function makeCtx(cwd: string, entries?: ReadonlyArray<CustomEntry>): ExtensionContext;
66
+ /**
67
+ * Tracked {@link EvaluatorHost} recording every exec / appendEntry
68
+ * call so tests can assert memoization + audit logging.
69
+ *
70
+ * `entries` is the backing array `makeCtx` wraps when tests want the
71
+ * host's `appendEntry` writes visible to a later `findEntries` read.
72
+ * Timestamps are monotonically-incrementing second-level ISO strings
73
+ * so ordering asserts stay stable inside the same millisecond.
74
+ */
75
+ export interface TrackedHost extends EvaluatorHost {
76
+ readonly execCalls: Array<{
77
+ cmd: string;
78
+ args: string[];
79
+ cwd: string;
80
+ }>;
81
+ readonly appended: Array<{
82
+ type: string;
83
+ data: unknown;
84
+ }>;
85
+ readonly entries: CustomEntry[];
86
+ }
87
+ /**
88
+ * Build a {@link TrackedHost}. Optional `exec` override lets evaluator
89
+ * tests count real invocations against the cache (the default exec
90
+ * returns `{ stdout: "", stderr: "", code: 0, killed: false }`).
91
+ */
92
+ export declare function makeTrackedHost(options?: {
93
+ exec?: (cmd: string, args: string[], cwd: string) => Promise<PiExecResult>;
94
+ }): TrackedHost;
95
+ //# sourceMappingURL=__test-helpers__.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"__test-helpers__.d.ts","sourceRoot":"","sources":["../src/__test-helpers__.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,IAAI,YAAY,EAC3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAMtE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC9B,IAAI,CAcN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC9B,IAAI,CAkBN;AAMD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAG7E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAItE;AAMD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,aAAa,CAAC,WAAW,CAAM,GACvC,gBAAgB,CAUlB;AAMD;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAY,SAAQ,aAAa;IAChD,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC1D,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE;IACxC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CAC5E,GAAG,WAAW,CA+Bd"}
@@ -0,0 +1,174 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Part of pi-steering.
3
+ /**
4
+ * Shared test-double helpers.
5
+ *
6
+ * `evaluator.test.ts` and `observer-dispatcher.test.ts` both need:
7
+ *
8
+ * - a minimal {@link ExtensionContext} stub whose `sessionManager`
9
+ * only exposes `getEntries()` (everything else throws on access),
10
+ * - a "tracked host" {@link EvaluatorHost} that records every
11
+ * `exec` / `appendEntry` call plus pushes `appendEntry` payloads
12
+ * into an entries array shaped like the pi session JSONL, so the
13
+ * same array can back a `makeCtx` stub and let tests assert
14
+ * cross-handler `findEntries` visibility.
15
+ *
16
+ * The two former copies diverged only in whether `makeHost` accepted an
17
+ * `exec` override (evaluator tests need it to count child-process
18
+ * invocations for the memoization assertions; observer tests don't).
19
+ * That's now a single option on the unified helper.
20
+ *
21
+ * Kept OUT of the public surface: `__test-helpers__` is a leading-double-
22
+ * underscore convention indicating "test only"; nothing under `src/`
23
+ * imports it at runtime.
24
+ */
25
+ import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync, } from "node:fs";
26
+ import { tmpdir } from "node:os";
27
+ import { join } from "node:path";
28
+ import { afterEach, beforeEach } from "node:test";
29
+ // ---------------------------------------------------------------------------
30
+ // Isolated $HOME fixture
31
+ // ---------------------------------------------------------------------------
32
+ /**
33
+ * Per-test scratch `$HOME` fixture. Registers `beforeEach` /
34
+ * `afterEach` that:
35
+ *
36
+ * - `mkdtempSync` a fresh temp dir using `prefix`,
37
+ * - save `process.env["HOME"]`, point it at the temp dir,
38
+ * - restore `process.env["HOME"]` and recursively remove the temp
39
+ * dir on teardown.
40
+ *
41
+ * Used by every test surface that exercises the loader walk-up
42
+ * (`index.test.ts`, `loader.test.ts`, `internal/session-runtime.test.ts`)
43
+ * so the per-file scratch-HOME boilerplate stays in one place.
44
+ *
45
+ * The temp dir path is exposed via the optional `onReady` callback,
46
+ * fired inside `beforeEach`; tests typically stash it in a
47
+ * describe-scoped `let` for terser reads.
48
+ */
49
+ export function useIsolatedHome(prefix, onReady) {
50
+ let tmp;
51
+ let priorHome;
52
+ beforeEach(() => {
53
+ tmp = mkdtempSync(join(tmpdir(), prefix));
54
+ priorHome = process.env["HOME"];
55
+ process.env["HOME"] = tmp;
56
+ onReady?.(tmp);
57
+ });
58
+ afterEach(() => {
59
+ if (priorHome === undefined)
60
+ delete process.env["HOME"];
61
+ else
62
+ process.env["HOME"] = priorHome;
63
+ rmSync(tmp, { recursive: true, force: true });
64
+ });
65
+ }
66
+ /**
67
+ * Like {@link useIsolatedHome} but also chdirs into the scratch dir, so factory-time tests find the per-test config via the loader walk-up. macOS tmpdir is a symlink; canonicalized via `realpathSync` so cwd-mismatch tests don't see false-divergence.
68
+ */
69
+ export function useScratchHome(prefix, onReady) {
70
+ let tmp;
71
+ let priorHome;
72
+ let priorCwd;
73
+ beforeEach(() => {
74
+ priorCwd = process.cwd();
75
+ tmp = realpathSync(mkdtempSync(join(tmpdir(), prefix)));
76
+ priorHome = process.env["HOME"];
77
+ process.env["HOME"] = tmp;
78
+ process.chdir(tmp);
79
+ onReady?.(tmp);
80
+ });
81
+ afterEach(() => {
82
+ process.chdir(priorCwd);
83
+ if (priorHome === undefined)
84
+ delete process.env["HOME"];
85
+ else
86
+ process.env["HOME"] = priorHome;
87
+ rmSync(tmp, { recursive: true, force: true });
88
+ });
89
+ }
90
+ // ---------------------------------------------------------------------------
91
+ // Steering-config fixture writers
92
+ // ---------------------------------------------------------------------------
93
+ /**
94
+ * Write a single-file steering config to `<dir>/.pi/steering.ts`.
95
+ * `body` is the full module source (must include `export default`).
96
+ * Used by suites whose fixtures embed regex literals or other
97
+ * non-JSON-friendly module shapes inline.
98
+ */
99
+ export function writeSteeringSingleFileConfig(dir, body) {
100
+ mkdirSync(join(dir, ".pi"), { recursive: true });
101
+ writeFileSync(join(dir, ".pi", "steering.ts"), body, "utf8");
102
+ }
103
+ /**
104
+ * Write a directory-form steering config to
105
+ * `<dir>/.pi/steering/index.ts`. `body` is the full module source
106
+ * (must include `export default`). Mirrors the layout the bin tests
107
+ * use for their isolated `@cad0p/pi-steering` invocations.
108
+ */
109
+ export function writeSteeringDirConfig(dir, body) {
110
+ const pi = join(dir, ".pi", "steering");
111
+ mkdirSync(pi, { recursive: true });
112
+ writeFileSync(join(pi, "index.ts"), body, "utf8");
113
+ }
114
+ // ---------------------------------------------------------------------------
115
+ // ExtensionContext stub
116
+ // ---------------------------------------------------------------------------
117
+ /**
118
+ * Minimal stub for pi's `ExtensionContext`. Only the fields the
119
+ * evaluator + observer-dispatcher read are populated; everything else
120
+ * throws if touched so accidental reliance on unsupported surface
121
+ * breaks loudly.
122
+ *
123
+ * The `entries` array mimics `sessionManager.getEntries()` output —
124
+ * tests that want cross-handler `findEntries` visibility pass
125
+ * `host.entries` (from {@link makeTrackedHost}) here so the host's
126
+ * `appendEntry` writes show up on subsequent reads.
127
+ */
128
+ export function makeCtx(cwd, entries = []) {
129
+ return {
130
+ cwd,
131
+ sessionManager: {
132
+ getEntries: () => entries,
133
+ // Other SessionManager methods are stubbed to throw via the
134
+ // unknown-cast below; any accidental dependency surfaces as a
135
+ // clear TypeError rather than silently passing.
136
+ },
137
+ };
138
+ }
139
+ /**
140
+ * Build a {@link TrackedHost}. Optional `exec` override lets evaluator
141
+ * tests count real invocations against the cache (the default exec
142
+ * returns `{ stdout: "", stderr: "", code: 0, killed: false }`).
143
+ */
144
+ export function makeTrackedHost(options) {
145
+ const execCalls = [];
146
+ const appended = [];
147
+ const entries = [];
148
+ let idCounter = 0;
149
+ return {
150
+ execCalls,
151
+ appended,
152
+ entries,
153
+ exec: async (cmd, args, opts) => {
154
+ const cwd = opts?.cwd ?? "/";
155
+ execCalls.push({ cmd, args: [...args], cwd });
156
+ if (options?.exec) {
157
+ return options.exec(cmd, args, cwd);
158
+ }
159
+ return { stdout: "", stderr: "", code: 0, killed: false };
160
+ },
161
+ appendEntry: (type, data) => {
162
+ appended.push({ type, data });
163
+ entries.push({
164
+ type: "custom",
165
+ customType: type,
166
+ data,
167
+ timestamp: new Date(Date.UTC(2026, 0, 1, 0, 0, idCounter++)).toISOString(),
168
+ id: `entry-${idCounter}`,
169
+ parentId: null,
170
+ });
171
+ },
172
+ };
173
+ }
174
+ //# sourceMappingURL=__test-helpers__.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"__test-helpers__.js","sourceRoot":"","sources":["../src/__test-helpers__.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI entrypoint. Exported (not just `void main(...)` at module top)
4
+ * so the test suite can exercise the argument parser without spawning
5
+ * a subprocess. Real invocation goes through the bottom-of-file
6
+ * bootstrap when this module is run as `node pi-steering.js`.
7
+ */
8
+ export declare function main(argv: string[]): Promise<number>;
9
+ //# sourceMappingURL=pi-steering.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-steering.d.ts","sourceRoot":"","sources":["../../src/bin/pi-steering.ts"],"names":[],"mappings":";AAsCA;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAkB1D"}