projectkeeper 0.0.0-stage → 1.0.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 (276) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/LICENSE +21 -0
  3. package/README.md +283 -2
  4. package/README.zh-CN.md +285 -0
  5. package/THIRD_PARTY_NOTICES.md +53 -0
  6. package/bin/pk.mjs +6 -0
  7. package/bin/postinstall.mjs +5 -0
  8. package/bin/strip-types.mjs +28 -0
  9. package/package.json +68 -4
  10. package/patches/README.md +111 -0
  11. package/patches/pi-ai-0.85.0.ts +122 -0
  12. package/patches/pi-ai-0.87.1.ts +122 -0
  13. package/scripts/apply-pi-streaming-patch.ts +86 -0
  14. package/skills/clerk/coverage/SKILL.md +35 -0
  15. package/skills/clerk/cross-check/SKILL.md +118 -0
  16. package/skills/clerk/deepen-dispatch/SKILL.md +69 -0
  17. package/skills/clerk/lane-follow-up/SKILL.md +94 -0
  18. package/skills/clerk/lane-plan/SKILL.md +107 -0
  19. package/skills/clerk/lane-slot/SKILL.md +113 -0
  20. package/skills/clerk/lane-topic/SKILL.md +116 -0
  21. package/skills/clerk/orientation/SKILL.md +160 -0
  22. package/skills/clerk/reconcile/SKILL.md +77 -0
  23. package/skills/clerk/skeleton-dispatch/SKILL.md +43 -0
  24. package/skills/clerk/spot-check/SKILL.md +52 -0
  25. package/skills/clerk/synthesis/SKILL.md +65 -0
  26. package/skills/table-follow-up/SKILL.md +42 -0
  27. package/src/cli.ts +319 -0
  28. package/src/codemap/README.md +13 -0
  29. package/src/codemap/engines.ts +102 -0
  30. package/src/codemap/facts.ts +504 -0
  31. package/src/context/agent-entry.ts +232 -0
  32. package/src/context/ask.ts +97 -0
  33. package/src/context/assemble.ts +1058 -0
  34. package/src/context/code-source.ts +103 -0
  35. package/src/context/k-briefs.ts +114 -0
  36. package/src/context/lineage.ts +100 -0
  37. package/src/context/object-brief.ts +300 -0
  38. package/src/context/owner-words.ts +191 -0
  39. package/src/context/pack-fixture.ts +342 -0
  40. package/src/context/project-rules.ts +160 -0
  41. package/src/intake/intake.ts +392 -0
  42. package/src/intake/material-rules.ts +166 -0
  43. package/src/intake/removal.ts +316 -0
  44. package/src/intake/skipped.ts +72 -0
  45. package/src/keeper/adjustment.ts +565 -0
  46. package/src/keeper/bounds/boundary.ts +509 -0
  47. package/src/keeper/bounds/command.ts +1665 -0
  48. package/src/keeper/bounds/paths.ts +164 -0
  49. package/src/keeper/bounds/reads.ts +718 -0
  50. package/src/keeper/bounds/shell-write-guard.ts +521 -0
  51. package/src/keeper/capabilities.ts +136 -0
  52. package/src/keeper/clerk-steps.ts +151 -0
  53. package/src/keeper/clerk-tools.ts +1424 -0
  54. package/src/keeper/conversation.ts +253 -0
  55. package/src/keeper/evidence.ts +662 -0
  56. package/src/keeper/fake-provider.ts +132 -0
  57. package/src/keeper/held.ts +15 -0
  58. package/src/keeper/history-tools.ts +163 -0
  59. package/src/keeper/jobs/answering.ts +53 -0
  60. package/src/keeper/key-check.ts +105 -0
  61. package/src/keeper/ledger-tools.ts +295 -0
  62. package/src/keeper/link-check.ts +185 -0
  63. package/src/keeper/merge.ts +260 -0
  64. package/src/keeper/note-origin.ts +56 -0
  65. package/src/keeper/numbers-check.ts +102 -0
  66. package/src/keeper/open-in-pi.ts +57 -0
  67. package/src/keeper/organize/absence.ts +266 -0
  68. package/src/keeper/organize/carried-on.ts +214 -0
  69. package/src/keeper/organize/clerk-coverage.ts +293 -0
  70. package/src/keeper/organize/clerk-prompts.ts +132 -0
  71. package/src/keeper/organize/clerk.ts +1395 -0
  72. package/src/keeper/organize/coverage-gate.ts +19 -0
  73. package/src/keeper/organize/coverage-tools.ts +765 -0
  74. package/src/keeper/organize/entries.ts +153 -0
  75. package/src/keeper/organize/entry-gate.ts +289 -0
  76. package/src/keeper/organize/fill-tools.ts +718 -0
  77. package/src/keeper/organize/follow-up.ts +280 -0
  78. package/src/keeper/organize/generation-check.ts +504 -0
  79. package/src/keeper/organize/graph.ts +230 -0
  80. package/src/keeper/organize/lane-tools.ts +289 -0
  81. package/src/keeper/organize/looked-tools.ts +54 -0
  82. package/src/keeper/organize/materials.ts +243 -0
  83. package/src/keeper/organize/owner-lines.ts +493 -0
  84. package/src/keeper/organize/place-tools.ts +216 -0
  85. package/src/keeper/organize/placement-inference.ts +1045 -0
  86. package/src/keeper/organize/placement-time.ts +320 -0
  87. package/src/keeper/organize/placing.ts +821 -0
  88. package/src/keeper/organize/positioning.ts +33 -0
  89. package/src/keeper/organize/readiness.ts +47 -0
  90. package/src/keeper/organize/reading.ts +401 -0
  91. package/src/keeper/organize/round-blocks.ts +65 -0
  92. package/src/keeper/organize/round-news.ts +164 -0
  93. package/src/keeper/organize/round-open.ts +586 -0
  94. package/src/keeper/organize/schedule-state.ts +39 -0
  95. package/src/keeper/organize/schedule.ts +137 -0
  96. package/src/keeper/organize/service.ts +409 -0
  97. package/src/keeper/organize/skills.ts +116 -0
  98. package/src/keeper/organize/slots.ts +85 -0
  99. package/src/keeper/organize/stage-gate.ts +175 -0
  100. package/src/keeper/organize/stage-tools.ts +471 -0
  101. package/src/keeper/organize/standing-notes.ts +141 -0
  102. package/src/keeper/organize/table-follow-up.ts +330 -0
  103. package/src/keeper/organize/takeover-clerk.ts +832 -0
  104. package/src/keeper/organize/takeover-state.ts +103 -0
  105. package/src/keeper/organize/takeover.ts +216 -0
  106. package/src/keeper/organize/update-pending.ts +535 -0
  107. package/src/keeper/organize/workbench-placement.ts +92 -0
  108. package/src/keeper/own-keys.ts +114 -0
  109. package/src/keeper/owner-text.ts +165 -0
  110. package/src/keeper/project-folder.ts +334 -0
  111. package/src/keeper/prompts.ts +101 -0
  112. package/src/keeper/references.ts +177 -0
  113. package/src/keeper/relook/compose.ts +120 -0
  114. package/src/keeper/relook/prompts.ts +36 -0
  115. package/src/keeper/roles.ts +259 -0
  116. package/src/keeper/round-tools.ts +227 -0
  117. package/src/keeper/route.ts +148 -0
  118. package/src/keeper/rules.ts +97 -0
  119. package/src/keeper/runtime.ts +1858 -0
  120. package/src/keeper/scope-tools.ts +194 -0
  121. package/src/keeper/sendback-text.ts +83 -0
  122. package/src/keeper/step-timing.ts +207 -0
  123. package/src/keeper/testing/clerk-script.ts +212 -0
  124. package/src/keeper/testing/streaming-arguments.ts +57 -0
  125. package/src/keeper/tools.ts +2340 -0
  126. package/src/keeper/utterance-tools.ts +64 -0
  127. package/src/keeper/verbatim.ts +397 -0
  128. package/src/ledger/adapters.ts +186 -0
  129. package/src/ledger/arrangements.ts +257 -0
  130. package/src/ledger/blame.ts +58 -0
  131. package/src/ledger/code-engine-child.ts +69 -0
  132. package/src/ledger/code-engine.ts +548 -0
  133. package/src/ledger/code.ts +607 -0
  134. package/src/ledger/docs.ts +294 -0
  135. package/src/ledger/git-read.ts +321 -0
  136. package/src/ledger/index.ts +1850 -0
  137. package/src/ledger/item-range.ts +16 -0
  138. package/src/ledger/lines.ts +328 -0
  139. package/src/ledger/numbering.ts +269 -0
  140. package/src/ledger/ranges.ts +74 -0
  141. package/src/ledger/rebuild-worker.ts +15 -0
  142. package/src/ledger/rebuild.ts +387 -0
  143. package/src/ledger/repo-scan.ts +181 -0
  144. package/src/ledger/schema.ts +450 -0
  145. package/src/ledger/sessions.ts +134 -0
  146. package/src/ledger/text-scan.ts +466 -0
  147. package/src/ledger/time.ts +185 -0
  148. package/src/ledger/ts-symbols.ts +180 -0
  149. package/src/ledger/views.ts +377 -0
  150. package/src/mcp/server.ts +127 -0
  151. package/src/mcp/tools.ts +187 -0
  152. package/src/model/ids.ts +23 -0
  153. package/src/model/k-types.ts +912 -0
  154. package/src/model/time.ts +85 -0
  155. package/src/model/types.ts +1382 -0
  156. package/src/model/views-k.ts +707 -0
  157. package/src/model/vocab.ts +269 -0
  158. package/src/process/analysis.ts +79 -0
  159. package/src/process/breakpoint-candidates.ts +383 -0
  160. package/src/process/breakpoints.ts +746 -0
  161. package/src/process/claim-check.ts +295 -0
  162. package/src/process/delivery-links.ts +52 -0
  163. package/src/process/facts.ts +487 -0
  164. package/src/process/generations.ts +138 -0
  165. package/src/process/index.ts +243 -0
  166. package/src/process/integration.ts +128 -0
  167. package/src/process/placement.ts +107 -0
  168. package/src/process/plan.ts +276 -0
  169. package/src/process/sendbacks.ts +244 -0
  170. package/src/process/text.ts +185 -0
  171. package/src/process/units.ts +543 -0
  172. package/src/process/unnumbered.ts +431 -0
  173. package/src/process/work.ts +884 -0
  174. package/src/scope/candidates.ts +86 -0
  175. package/src/scope/decisions.ts +229 -0
  176. package/src/scope/discover.ts +741 -0
  177. package/src/scope/ignore.ts +126 -0
  178. package/src/scope/ignored-place.ts +93 -0
  179. package/src/scope/skip.ts +161 -0
  180. package/src/scope/toolchain.ts +180 -0
  181. package/src/scope/worktree.ts +187 -0
  182. package/src/server/api.ts +549 -0
  183. package/src/server/app.ts +595 -0
  184. package/src/server/drafts-api.ts +170 -0
  185. package/src/server/folders-api.ts +243 -0
  186. package/src/server/graph-view.ts +639 -0
  187. package/src/server/http.ts +224 -0
  188. package/src/server/k-agent-api.ts +56 -0
  189. package/src/server/k-rounds-d99.ts +91 -0
  190. package/src/server/k-views.ts +405 -0
  191. package/src/server/keeper-page.ts +446 -0
  192. package/src/server/keys-api.ts +239 -0
  193. package/src/server/project-folder-api.ts +104 -0
  194. package/src/server/vendor.ts +14 -0
  195. package/src/server/workbench-content.ts +561 -0
  196. package/src/sources/anchor.ts +129 -0
  197. package/src/sources/files.ts +267 -0
  198. package/src/sources/gitobs.ts +41 -0
  199. package/src/sources/history.ts +231 -0
  200. package/src/sources/scan-worker.ts +10 -0
  201. package/src/sources/sessions/locate.ts +292 -0
  202. package/src/sources/sessions/read.ts +346 -0
  203. package/src/sources/sessions/scope.ts +42 -0
  204. package/src/sources/sessions/utterances.ts +223 -0
  205. package/src/sources/watch.ts +215 -0
  206. package/src/store/json-file.ts +50 -0
  207. package/src/store/paths.ts +39 -0
  208. package/src/store/project-store.ts +295 -0
  209. package/src/store/versions.ts +172 -0
  210. package/src/store/workspace.ts +216 -0
  211. package/src/table/check.ts +333 -0
  212. package/src/table/follow-up-tools.ts +30 -0
  213. package/src/table/follow-up.ts +344 -0
  214. package/src/table/import.ts +610 -0
  215. package/src/table/project-home.ts +61 -0
  216. package/src/table/sessions.ts +168 -0
  217. package/src/table/takeover.ts +483 -0
  218. package/src/util/git-check.ts +29 -0
  219. package/src/util/git.ts +411 -0
  220. package/src/util/own-ts.ts +15 -0
  221. package/src/util/paths.ts +225 -0
  222. package/template/FILLING-IN.md +148 -0
  223. package/template/examples/papertrail.json +747 -0
  224. package/template/projectkeeper.schema.json +1001 -0
  225. package/ui/app.js +1135 -0
  226. package/ui/failures.js +82 -0
  227. package/ui/flyout.js +120 -0
  228. package/ui/folder-chooser.js +264 -0
  229. package/ui/glossary.js +156 -0
  230. package/ui/graph-fit.js +157 -0
  231. package/ui/graph-material.js +61 -0
  232. package/ui/graph-palette.js +109 -0
  233. package/ui/graph-tools.js +62 -0
  234. package/ui/graph.js +1712 -0
  235. package/ui/index.html +31 -0
  236. package/ui/k/code-view.js +230 -0
  237. package/ui/k/draft-view.js +93 -0
  238. package/ui/k/k-views.css +224 -0
  239. package/ui/k/round-tree.js +450 -0
  240. package/ui/k/scope-k.js +159 -0
  241. package/ui/k-data.js +118 -0
  242. package/ui/k-fold.js +106 -0
  243. package/ui/k-process.css +302 -0
  244. package/ui/k-process.js +934 -0
  245. package/ui/keeper-activity.js +175 -0
  246. package/ui/keeper-view.js +801 -0
  247. package/ui/keeper.css +101 -0
  248. package/ui/key-order.js +62 -0
  249. package/ui/list-fold.js +67 -0
  250. package/ui/markdown.d.ts +21 -0
  251. package/ui/markdown.js +472 -0
  252. package/ui/placement.d.ts +92 -0
  253. package/ui/placement.js +445 -0
  254. package/ui/popover-place.d.ts +16 -0
  255. package/ui/popover-place.js +89 -0
  256. package/ui/popover.js +198 -0
  257. package/ui/project-folder.js +37 -0
  258. package/ui/shell-state.js +40 -0
  259. package/ui/strip-rows.js +171 -0
  260. package/ui/styles.css +492 -0
  261. package/ui/theme-pick.js +36 -0
  262. package/ui/theme.js +74 -0
  263. package/ui/themes/LICENSE.md +13 -0
  264. package/ui/themes/README.md +44 -0
  265. package/ui/themes/TOKENS.md +291 -0
  266. package/ui/themes/a1/board.css +1557 -0
  267. package/ui/themes/a1/pk.css +392 -0
  268. package/ui/themes/b1/board.css +1163 -0
  269. package/ui/themes/b1/pk.css +218 -0
  270. package/ui/themes/d2/board.css +518 -0
  271. package/ui/themes/d2/pk.css +243 -0
  272. package/ui/themes/guard.css +73 -0
  273. package/ui/themes/i1/board.css +776 -0
  274. package/ui/themes/i1/pk.css +223 -0
  275. package/ui/themes/manifest.json +13 -0
  276. package/ui/views.js +2796 -0
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Fixed vocabularies from the Spec (product/SPEC.md §1–§2, §6.9, §7.7; v2.8 additions marked where they are).
3
+ *
4
+ * These strings are the interface's fixed parts: identical across projects, English, and
5
+ * used verbatim as labels. Keeper-written content never replaces them. Keep every list in
6
+ * sync with the Spec section named beside it; the Spec is the authority, not this file.
7
+ */
8
+
9
+ /**
10
+ * §1.2 `Used as`. `null` in the data means the interface shows `Not yet judged`.
11
+ * v2.8: `Reference only` — material the project says is for reference only, and the documents third-party material
12
+ * brings with it; it can be cited, never a requirement, boundary or plan (§1.1, §1.15). `History only` — what exists
13
+ * only in history: old versions and deleted files in version history, and the branches and directories the project
14
+ * keeps for recovery only; it forms no current node and enters no context (D61).
15
+ */
16
+ export const USED_AS = [
17
+ 'Purpose', 'Decision', 'Requirement', 'Design', 'Plan', 'Task', 'Status', 'Code', 'Test', 'QC',
18
+ 'Session', 'Run result', 'Reference only', 'History only', 'Other',
19
+ ] as const;
20
+ export type UsedAs = (typeof USED_AS)[number];
21
+ export const NOT_YET_JUDGED = 'Not yet judged';
22
+
23
+ /** §1.2 source availability. Availability and validity are different things. */
24
+ export const AVAILABILITY = ['Changed since read', 'Moved', 'No longer available'] as const;
25
+ export type Availability = (typeof AVAILABILITY)[number];
26
+
27
+ /**
28
+ * §1.5 generic node categories. A project without a category simply has no such nodes. v2.8 (D63): `Owner's words`,
29
+ * the top layer of the product reference — what the owner said or explicitly confirmed, each with the words and
30
+ * where they were said.
31
+ */
32
+ export const OWNER_WORDS = "Owner's words";
33
+ export const NODE_CATEGORY = [
34
+ "Owner's words", 'Product', 'Goal', 'Area', 'Requirement', 'Design', 'Decision', 'Plan', 'Work item', 'Session', 'Run',
35
+ 'Review', 'Test', 'Result', 'Change',
36
+ ] as const;
37
+ export type NodeCategory = (typeof NODE_CATEGORY)[number];
38
+
39
+ /** §1.6 relation types; meaning is the same in every project. v2.8: `carries out` — a piece of work carries out a
40
+ * decision that asks for something to be done (§2.2). */
41
+ export const RELATION_TYPE = [
42
+ 'serves', 'refines', 'implements', 'verifies', 'depends on', 'produced', 'replaces',
43
+ 'contradicts', 'affects', 'carries out',
44
+ ] as const;
45
+ export type RelationType = (typeof RELATION_TYPE)[number];
46
+
47
+ /** §2.3 basis. `Explicit` is not labelled by default; `Inferred` is shown. */
48
+ export const BASIS = ['Explicit', 'Inferred'] as const;
49
+ export type Basis = (typeof BASIS)[number];
50
+
51
+ /** §2.5 Keeper assessment of a relation. Only a re-look or an owner correction changes it. */
52
+ export const ASSESSMENT = ['Holds', 'Questioned', 'Not assessed'] as const;
53
+ export type Assessment = (typeof ASSESSMENT)[number];
54
+
55
+ /**
56
+ * §2.1 validity. `Unjudged` has no interface label: it is the state right after reading,
57
+ * before the Keeper judged the material; it stays out of the graph's default view.
58
+ * v2.8 (D61): `Removed` — an object built before its material was deleted from the project's current version. The
59
+ * deletion itself says "no longer needed"; it is not `Abandoned`, which carries a disposal.
60
+ */
61
+ export const VALIDITY = ['Current', 'Proposed', 'Unjudged', 'Deferred', 'Replaced', 'Abandoned', 'Removed'] as const;
62
+ export type Validity = (typeof VALIDITY)[number];
63
+
64
+ /** §2.2 progress. Code existing is not `Done`. */
65
+ export const PROGRESS = ['Planned', 'In progress', 'Done', 'On hold'] as const;
66
+ export type Progress = (typeof PROGRESS)[number];
67
+
68
+ /**
69
+ * §2.2 (v2.8) whether a decision that asks for something to be done was carried out. `Partly carried out` always says
70
+ * what is still left. The work that carries it out is linked by `carries out`; a decision carried out stays `Current`
71
+ * and is not read as a to-do.
72
+ */
73
+ export const CARRY_OUT = ['Carried out', 'Partly carried out', 'Not carried out yet'] as const;
74
+ export type CarryOut = (typeof CARRY_OUT)[number];
75
+
76
+ /**
77
+ * §2.2 acceptance (owner D41). Progress, acceptance and independent checking are three different facts. `Done` says
78
+ * the promised result exists and the material says so; whether the owner accepted it is this, and whether anyone
79
+ * checked it is the assessment on a `verifies` relation. Only the owner's own statement or an acceptance the project
80
+ * records can set `Accepted`. A project with no acceptance step leaves this empty and the workbench does not show it.
81
+ */
82
+ export const ACCEPTANCE = ['Accepted', 'Not yet accepted'] as const;
83
+ export type Acceptance = (typeof ACCEPTANCE)[number] | '';
84
+
85
+ /** §2.4 statement types inside a fact record. */
86
+ export const STATEMENT_TYPE = ['Observed', 'Claimed', 'Inferred', 'Open'] as const;
87
+ export type StatementType = (typeof STATEMENT_TYPE)[number];
88
+
89
+ /** §1.9 identity of a piece of material or Keeper output. */
90
+ export const IDENTITY = ['Decision', 'Artifact', 'Proposal', 'Report', 'Interpretation'] as const;
91
+ export type Identity = (typeof IDENTITY)[number];
92
+
93
+ /** §1.7 what the owner is asked to do about a note. */
94
+ export const NOTE_ASK = ['For your decision', 'Worth discussing', 'For information'] as const;
95
+ export type NoteAsk = (typeof NOTE_ASK)[number];
96
+
97
+ /** §2.7 note status and owner response, recorded separately. */
98
+ export const NOTE_STATUS = ['Current', 'Resolved', 'Withdrawn'] as const;
99
+ /**
100
+ * Spec §4.1 (D47 supplement; D56 item 5 added the last two): how a note came about. `Organizing` is a note written
101
+ * while a material was being organized, `Takeover` one written while taking the project over — two notes on the
102
+ * 4873 home had neither and were left blank.
103
+ */
104
+ export const NOTE_ORIGIN = ['Product re-look', 'Change follow-up', 'Investigation', 'Owner question', 'Organizing', 'Takeover'] as const;
105
+ export type NoteOrigin = (typeof NOTE_ORIGIN)[number];
106
+ export type NoteStatus = (typeof NOTE_STATUS)[number];
107
+ export const OWNER_RESPONSE = ['Discussed', 'Decided', 'Delegated', 'No action needed'] as const;
108
+ export type OwnerResponse = (typeof OWNER_RESPONSE)[number];
109
+
110
+ /**
111
+ * §1.8 how one piece of work was cut out of the stream (D56). A change record covers one piece of work: a session
112
+ * or an execution, together with the files it changed and the commits it made. Changes with no session are grouped
113
+ * by time.
114
+ */
115
+ export const WORK_SEGMENT_KIND = ['Session', 'Execution', 'Time range'] as const;
116
+ export type WorkSegmentKind = (typeof WORK_SEGMENT_KIND)[number];
117
+
118
+ /**
119
+ * §1.8 what is not a change. The same matter comes up again and again in ordinary work — it is designed once,
120
+ * executed once, asked about midway, checked, reviewed, looked up again by the next task, re-read after a
121
+ * compaction, recalled from memory — and none of those is a new change. What is recorded is the net change.
122
+ */
123
+ export const NOT_A_CHANGE = [
124
+ 'Restating', 'Re-reading', 'Checking a dependency', 'Re-reading after compaction', 'Recalling from memory',
125
+ 'Changed and changed back', 'Wording, formatting or version number only',
126
+ ] as const;
127
+ export type NotAChange = (typeof NOT_A_CHANGE)[number];
128
+
129
+ /** §1.8 change record material category and effect; one record's items each carry their own pair. */
130
+ export const CHANGE_MATERIAL = [
131
+ 'Decision', 'Owner statement', 'Product direction', 'Plan update', 'Status report',
132
+ 'Development note', 'Code change', 'Test result', 'Review', 'Iteration boundary', 'Other',
133
+ ] as const;
134
+ export type ChangeMaterial = (typeof CHANGE_MATERIAL)[number];
135
+ /** `Removed` (D61) is the item that records an object becoming `Removed` because its material was deleted (§2.1: each
136
+ * validity change is an item of a change record); §1.8's list has no word for it yet. */
137
+ export const CHANGE_EFFECT = [
138
+ 'Added', 'Approved', 'Replaced', 'Deferred', 'Abandoned', 'Completed', 'Corrected', 'Removed',
139
+ ] as const;
140
+ export type ChangeEffect = (typeof CHANGE_EFFECT)[number];
141
+
142
+ /** §2.10 propagation state. One object gets one of these per round, for every item that reached it (D56). */
143
+ export const PROPAGATION = ['Updated', 'Still on old understanding', 'Reusable as is', 'Not yet checked'] as const;
144
+ export type Propagation = (typeof PROPAGATION)[number];
145
+
146
+ /**
147
+ * §2.10 objects that are never judged, and why. A point-in-time record says how things stood then, so a later
148
+ * change cannot leave it behind; a decision is checked for what replaced it (§5.5) instead. Both are listed in the
149
+ * change's detail and neither counts towards what is pending.
150
+ */
151
+ export const NOT_JUDGED_REASON = ['Point-in-time record', 'Decision'] as const;
152
+ export type NotJudgedReason = (typeof NOT_JUDGED_REASON)[number];
153
+
154
+ /** §2.10 the three ways an item on an object ends; until one of them happens the item stays with the object. */
155
+ export const ITEM_CLOSE = ['Followed', 'Superseded by a later change', 'No action needed'] as const;
156
+ export type ItemClose = (typeof ITEM_CLOSE)[number];
157
+
158
+ /** §1.11 coverage label of an active scope. */
159
+ export const COVERAGE_LABEL = ['Up to date', 'Organizing', 'Changes pending', 'Organizing paused'] as const;
160
+ export type CoverageLabel = (typeof COVERAGE_LABEL)[number];
161
+
162
+ /**
163
+ * §1.11 entry marks and how they close. Marks are facts for judgement, not validities. v2.8 (D63): `Decided without
164
+ * owner` — a rule or decision a role set in the owner's place that is in force now (§1.9).
165
+ */
166
+ export const MARK_KIND = ['Suspected stale', 'Undocumented decision', 'Layer drift', 'Scope question', 'Disposal', 'Decided without owner'] as const;
167
+ export type MarkKind = (typeof MARK_KIND)[number];
168
+ export const MARK_CLOSE = ['Resolved', 'Fixed', 'Became a change', 'Dismissed', 'No longer relevant'] as const;
169
+ export type MarkClose = (typeof MARK_CLOSE)[number];
170
+
171
+ /** §1.12 work kind of a context package; §7.2 says unrecognised defaults to `Implement`. */
172
+ export const WORK_KIND = ['Implement', 'Review', 'Plan', 'Discuss product', 'Investigate'] as const;
173
+ export type WorkKind = (typeof WORK_KIND)[number];
174
+ export const CONTEXT_PURPOSE = ['Start', 'Work', 'Handover'] as const;
175
+ export type ContextPurpose = (typeof CONTEXT_PURPOSE)[number];
176
+ export const INCOMING_AGENT = 'Incoming agent';
177
+
178
+ /** §1.13 Keeper work kinds; §6.9 job status and overall Keeper status. */
179
+ export const JOB_KIND = ['Organizing', 'Product re-look', 'Investigation', 'Answering', 'Your request', 'Context'] as const;
180
+ export type JobKind = (typeof JOB_KIND)[number];
181
+ export const JOB_STATUS = ['Running', 'Queued', 'Paused', 'Stopped', 'Waiting for quota', 'Failed', 'Done'] as const;
182
+ export type JobStatus = (typeof JOB_STATUS)[number];
183
+ export const KEEPER_STATUS = [
184
+ 'Working', 'Working on your request', 'Idle', 'Organizing paused', 'Waiting for quota',
185
+ 'Unavailable', 'Not connected',
186
+ ] as const;
187
+ export type KeeperStatus = (typeof KEEPER_STATUS)[number];
188
+
189
+ /**
190
+ * §1.1 scope item category and relation. v2.8: `Third-party material` (SDKs, libraries and templates distributed with
191
+ * the project, with their own documents) and `Generated` (build output, caches, exports) are listed apart: what the
192
+ * project uses, not its own intent.
193
+ */
194
+ export const SCOPE_CATEGORY = ['Directory', 'Repository', 'Worktree', 'Session source'] as const;
195
+ export type ScopeCategory = (typeof SCOPE_CATEGORY)[number];
196
+ export const SCOPE_RELATION = [
197
+ 'Main project', 'Worktree of main repo', 'Copy of another project', 'Nested repository',
198
+ 'Experiment', 'Third-party material', 'Generated', 'Excluded', 'Session source',
199
+ ] as const;
200
+ export type ScopeRelation = (typeof SCOPE_RELATION)[number];
201
+
202
+ /** §3.7 understanding state shown in Project scope. */
203
+ export const UNDERSTANDING_STATE = ['Not organized yet', 'Initial model', 'Takeover complete'] as const;
204
+ export type UnderstandingState = (typeof UNDERSTANDING_STATE)[number];
205
+
206
+ /** §1.11 takeover depth (D36, D105), chosen on the `Takeover` page before `Start`. `null` in the data: the project has not been started. */
207
+ export const TAKEOVER_DEPTH = ['Full', 'Focused', 'First picture only'] as const;
208
+ export type TakeoverDepth = (typeof TAKEOVER_DEPTH)[number];
209
+ export const DEPTH_NOT_CHOSEN = 'Depth not chosen';
210
+
211
+ /**
212
+ * §1.11 organizing level of one material, counted by category in the coverage. `Settled by rule` (batch C2, pending the
213
+ * Product architect's word for it): material the project's own rules settle directly — the organizing plan names it, or
214
+ * a rule decided how its sources are used — so it is not read closely, not counted in the depth question's close reading
215
+ * (§3.7) and never listed as failed. `Skipped: too large` (D105): a file over the size intake reads of one file — its text
216
+ * is not read, so it has no sources; the ledger records it. Not pending and not a failure.
217
+ */
218
+ export const SKIPPED_TOO_LARGE = 'Skipped: too large';
219
+ export const ORGANIZING_LEVEL = ['Read in full', 'Conclusions only', 'Sampled', 'Settled by rule', 'Indexed', 'Not organized', SKIPPED_TOO_LARGE] as const;
220
+ export type OrganizingLevel = (typeof ORGANIZING_LEVEL)[number];
221
+
222
+ /** §7.7 delivery state of a mid-work update to an active session. */
223
+ export const DELIVERY = ['Delivered', 'Pending next read', 'Not supported by host'] as const;
224
+ export type Delivery = (typeof DELIVERY)[number];
225
+
226
+ /**
227
+ * §6.3 graph scales and fixed group names. The scales are `Overview`, `Work` and `Compare` (D45); the `Change` view went
228
+ * with D48: whether downstream followed a change is the Keeper's report in Follow up, not a scale.
229
+ */
230
+ export const GRAPH_SCALE = ['Overview', 'Work', 'Compare'] as const;
231
+ export type GraphScale = (typeof GRAPH_SCALE)[number];
232
+ export const GROUP_EXISTING_FOUNDATION = 'Existing foundation';
233
+ export const GROUP_UNPLACED = 'Unplaced';
234
+ export const NO_ESTABLISHED_LINK = 'No established link';
235
+ export const UPDATE_PENDING = 'Update pending';
236
+
237
+ /** §1.3 product-reference categories (Goal/Area/Requirement/Design/Decision plus the applicable boundary). `Plan` is
238
+ * written here too: §1.5 draws plans and milestones as their own node category, and plan documents are read by the
239
+ * same jobs that read the other intent material (2026-09-17: without it the Keeper filed plans as Design). */
240
+ export const REFERENCE_CATEGORY = ["Owner's words", 'Product', 'Goal', 'Area', 'Requirement', 'Design', 'Decision', 'Plan', 'Boundary'] as const;
241
+ export type ReferenceCategory = (typeof REFERENCE_CATEGORY)[number];
242
+
243
+ /**
244
+ * §1.15 (v2.8, D62, D64) the project's own rules, in the three groups Project scope and the start context show them
245
+ * in (§6.7, §7.3; CKC-21). The first two are how the project works; the third is what it says about its material.
246
+ */
247
+ export const RULE_GROUP = ['How work is organized', 'Working rules', 'Material rules'] as const;
248
+ export type RuleGroup = (typeof RULE_GROUP)[number];
249
+ /**
250
+ * §1.15 the kinds of material rule the Keeper looks for at least. `Other` keeps the list open: a project may write
251
+ * down a rule about its material that none of the six names.
252
+ */
253
+ export const MATERIAL_RULE = ['Obsolete', 'Reference only', 'Recovery only', 'Authoritative', 'Untrusted', 'Declared open', 'Other'] as const;
254
+ /**
255
+ * §2.12: which steps the project's own way of working expects of a piece of work, as a rule of `How work is organized`
256
+ * says. A breakpoint for a missing step is lit only where the project expects the step (a project without independent
257
+ * QC has no `Not checked`, D72): the program reads these, the rule's words stay the rule's.
258
+ */
259
+ export const PROCESS_EXPECTATION = ['Written plan', 'Written dispatch', 'Independent check', 'Re-check after fix', 'Owner acceptance'] as const;
260
+ export type ProcessExpectation = (typeof PROCESS_EXPECTATION)[number];
261
+ export type MaterialRule = (typeof MATERIAL_RULE)[number];
262
+
263
+ /** Session hosts read in P1 (PLAN PA-2), plus pi for the Keeper's own sessions. */
264
+ export const SESSION_HOST = ['claude', 'codex', 'pi'] as const;
265
+ export type SessionHost = (typeof SESSION_HOST)[number];
266
+
267
+ export function isOneOf<T extends readonly string[]>(list: T, value: unknown): value is T[number] {
268
+ return typeof value === 'string' && (list as readonly string[]).includes(value);
269
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * One computation of the process engine over a project (Spec v3.0 §2.12, §2.13 rows 1–5): the ledger's facts read once,
3
+ * the units of work, every work item's process, and which steps the project's own rules expect of which work (§1.15
4
+ * `expects`, D72: a breakpoint for a missing step is lit only where the project expects the step).
5
+ */
6
+ import type { Ledger } from '../ledger/index.ts';
7
+ import type { Project, ProjectRule, WorkThread } from '../model/types.ts';
8
+ import type { ProcessExpectation } from '../model/vocab.ts';
9
+ import type { ProjectStore } from '../store/project-store.ts';
10
+ import { Facts } from './facts.ts';
11
+ import { buildUnits, isArrangementPath, type Unit, type UnitIndex } from './units.ts';
12
+ import { processOf, type WorkContext, type WorkProcess } from './work.ts';
13
+
14
+ export interface Analysis {
15
+ readonly store: ProjectStore;
16
+ readonly project: Project;
17
+ readonly facts: Facts;
18
+ readonly index: UnitIndex;
19
+ readonly ctx: WorkContext;
20
+ /** A work item's process (computed on first use, then kept for this computation). */
21
+ process(threadId: string): WorkProcess | null;
22
+ /** The current rule of `How work is organized` that expects this step of this work, or null (§1.15, D72). */
23
+ expecting(thread: WorkThread, step: ProcessExpectation): ProjectRule | null;
24
+ }
25
+
26
+ export function analyze(store: ProjectStore, project: Project, ledger: Ledger): Analysis {
27
+ const facts = new Facts(ledger);
28
+ const index = buildUnits(store, facts);
29
+ const ctx: WorkContext = { store, project, facts, index };
30
+ const cache = new Map<string, WorkProcess>();
31
+ const rules = store.rules.filter((r) => r.validity === 'Current' && r.group === 'How work is organized' && (r.expects?.length ?? 0) > 0);
32
+ const process = (threadId: string): WorkProcess | null => {
33
+ if (cache.has(threadId)) return cache.get(threadId)!;
34
+ const t = store.threads.get(threadId);
35
+ if (!t) return null;
36
+ const p = processOf(ctx, t);
37
+ cache.set(threadId, p);
38
+ return p;
39
+ };
40
+ return {
41
+ store, project, facts, index, ctx, process,
42
+ expecting(thread: WorkThread, step: ProcessExpectation): ProjectRule | null {
43
+ return rules.find((r) => (r.expects ?? []).includes(step) && appliesTo(r, thread, process(thread.id), index, facts)) ?? null;
44
+ },
45
+ };
46
+ }
47
+
48
+ const norm = (s: string): string => s.toLowerCase().replace(/\s+/g, ' ').trim();
49
+ const singular = (s: string): string => (s.length > 3 ? s.replace(/(?<!s)s$/, '') : s);
50
+
51
+ /**
52
+ * Whether a rule applies to a piece of work (§1.15 "适用于什么"): a rule with no `appliesTo` applies to all work;
53
+ * otherwise an entry applies when it is the work's number or id, a path its commits touch (a directory or a file), a
54
+ * branch it lies on, or words of its title, or of its task's title, kind or milestone.
55
+ */
56
+ export function appliesTo(rule: ProjectRule, thread: WorkThread, p: WorkProcess | null, index: UnitIndex, facts: Facts): boolean {
57
+ if (rule.appliesTo.length === 0) return true;
58
+ const nums = thread.ids.map((x) => x.toLowerCase());
59
+ const units = (p?.own ?? []).map((n) => index.units.get(n)).filter((u): u is Unit => u !== undefined);
60
+ const text = norm([thread.title, ...units.map((u) => `${u.title ?? ''} ${u.fields.kind ?? ''} ${u.fields.milestone ?? ''} ${u.fields.type ?? ''}`)].join(' '));
61
+ for (const raw of rule.appliesTo) {
62
+ const e = raw.trim();
63
+ if (!e) continue;
64
+ const low = e.toLowerCase();
65
+ if (low === thread.id.toLowerCase() || nums.includes(low)) return true;
66
+ if (/[/\\]|\.\w{1,5}$/.test(e)) {
67
+ const prefix = e.replace(/\\/g, '/').replace(/^\.\//, '').replace(/\/+$/, '');
68
+ if (p?.delivery.commits.some((c) => facts.filesOf(c).some((f) => !isArrangementPath(f.path) && (f.path === prefix || f.path.startsWith(`${prefix}/`))))) return true;
69
+ if (p?.delivery.branches.some((b) => b === prefix || b.startsWith(prefix))) return true;
70
+ continue;
71
+ }
72
+ // An entry shaped like a number (`AP`, `CKC-24`) is a number, never a word; words match whole words.
73
+ if (/^(?:[A-Z]{1,6}(?:-[A-Z]?)?\d{1,4}|[A-Z]{2,6})$/.test(e)) continue;
74
+ const w = singular(norm(e));
75
+ const re = new RegExp(`(?<![a-z0-9])${w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?![a-z0-9])`);
76
+ if (/[\u3000-\u9fff]/.test(w) ? text.includes(w) : re.test(text)) return true;
77
+ }
78
+ return false;
79
+ }