opencode-extended-sidebar 0.2.90 → 0.2.91

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 (108) hide show
  1. package/.oesignore +17 -17
  2. package/CHANGELOG.md +96 -95
  3. package/LICENSE +21 -21
  4. package/README.md +150 -235
  5. package/oes.json +13 -11
  6. package/package.json +100 -100
  7. package/scripts/install-git-hooks.mjs +29 -29
  8. package/src/pware.oc.core/constants/index.ts +18 -18
  9. package/src/pware.oc.core/constants/pware.oc.core.constants.eventKind.ts +29 -29
  10. package/src/pware.oc.core/constants/pware.oc.core.constants.eventName.ts +15 -13
  11. package/src/pware.oc.core/constants/pware.oc.core.constants.eventType.ts +241 -241
  12. package/src/pware.oc.core/constants/pware.oc.core.constants.myWork.ts +55 -55
  13. package/src/pware.oc.core/constants/pware.oc.core.constants.partType.ts +65 -65
  14. package/src/pware.oc.core/constants/pware.oc.core.constants.phase.ts +58 -58
  15. package/src/pware.oc.core/constants/pware.oc.core.constants.pulse.ts +63 -63
  16. package/src/pware.oc.core/constants/pware.oc.core.constants.rowKind.ts +34 -34
  17. package/src/pware.oc.core/constants/pware.oc.core.constants.status.ts +74 -74
  18. package/src/pware.oc.core/constants/pware.oc.core.constants.toolName.ts +69 -69
  19. package/src/pware.oc.core/git/index.ts +7 -7
  20. package/src/pware.oc.core/git/pware.oc.core.git.ts +237 -237
  21. package/src/pware.oc.core/git/pware.oc.core.gitignore.ts +87 -87
  22. package/src/pware.oc.core/index.ts +19 -18
  23. package/src/pware.oc.core/pware.oc.core.bus.ts +42 -42
  24. package/src/pware.oc.core/pware.oc.core.cache.ts +48 -48
  25. package/src/pware.oc.core/pware.oc.core.clipboard.ts +97 -97
  26. package/src/pware.oc.core/pware.oc.core.debug.ts +280 -280
  27. package/src/pware.oc.core/pware.oc.core.events.ts +79 -79
  28. package/src/pware.oc.core/pware.oc.core.glyph.ts +135 -135
  29. package/src/pware.oc.core/pware.oc.core.layout.ts +234 -234
  30. package/src/pware.oc.core/pware.oc.core.oes.ts +99 -89
  31. package/src/pware.oc.core/pware.oc.core.paths.ts +240 -240
  32. package/src/pware.oc.core/pware.oc.core.preview.ts +74 -74
  33. package/src/pware.oc.core/pware.oc.core.pulse.ts +726 -726
  34. package/src/pware.oc.core/pware.oc.core.runtimeConfig.ts +41 -0
  35. package/src/pware.oc.core/pware.oc.core.sqlite.ts +164 -175
  36. package/src/pware.oc.core/pware.oc.core.sqliteGateway.ts +89 -0
  37. package/src/pware.oc.core/pware.oc.core.status.ts +214 -214
  38. package/src/pware.oc.core/pware.oc.core.timing.ts +63 -63
  39. package/src/pware.oc.core/pware.oc.core.width.ts +215 -215
  40. package/src/pware.oc.omo/constants/index.ts +15 -15
  41. package/src/pware.oc.omo/constants/pware.oc.omo.constants.backgroundTask.ts +18 -18
  42. package/src/pware.oc.omo/constants/pware.oc.omo.constants.boulderStatus.ts +49 -49
  43. package/src/pware.oc.omo/constants/pware.oc.omo.constants.docKind.ts +29 -29
  44. package/src/pware.oc.omo/constants/pware.oc.omo.constants.eventName.ts +11 -11
  45. package/src/pware.oc.omo/constants/pware.oc.omo.constants.planStatus.ts +60 -60
  46. package/src/pware.oc.omo/constants/pware.oc.omo.constants.reviewStatus.ts +49 -49
  47. package/src/pware.oc.omo/constants/pware.oc.omo.constants.startWork.ts +25 -25
  48. package/src/pware.oc.omo/constants/pware.oc.omo.constants.verdict.ts +38 -38
  49. package/src/pware.oc.omo/index.ts +7 -7
  50. package/src/pware.oc.omo/resolver/index.ts +19 -19
  51. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approval.ts +179 -179
  52. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approvalGroup.ts +116 -116
  53. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approvalState.ts +34 -34
  54. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.boulder.ts +503 -503
  55. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.config.ts +40 -40
  56. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.doc.ts +269 -269
  57. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.draftFile.ts +18 -18
  58. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.notepadsFile.ts +18 -18
  59. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.plan.ts +155 -155
  60. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.planFile.ts +363 -361
  61. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.proofFile.ts +18 -18
  62. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.rulesFile.ts +11 -11
  63. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.runContinuationFile.ts +14 -14
  64. package/src/pware.oc.opencode/constants/index.ts +10 -10
  65. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.eventName.ts +15 -15
  66. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.fileTouch.ts +18 -18
  67. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.questionKind.ts +45 -45
  68. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.sessionStatus.ts +58 -58
  69. package/src/pware.oc.opencode/index.ts +8 -8
  70. package/src/pware.oc.opencode/pware.oc.opencode.events.ts +182 -182
  71. package/src/pware.oc.opencode/pware.oc.opencode.files.ts +399 -399
  72. package/src/pware.oc.opencode/resolver/index.ts +223 -170
  73. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.file.ts +150 -162
  74. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.question.ts +149 -185
  75. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.session.ts +248 -211
  76. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.todo.ts +22 -26
  77. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.tool.ts +224 -236
  78. package/src/pware.oc.perf/index.ts +14 -14
  79. package/src/pware.oc.perf/pware.oc.perf.asciichart.d.ts +15 -15
  80. package/src/pware.oc.perf/pware.oc.perf.charts.ts +284 -284
  81. package/src/pware.oc.perf/pware.oc.perf.reader.ts +962 -927
  82. package/src/pware.oc.perf/pware.oc.perf.realtime.ts +88 -88
  83. package/src/pware.oc.perf/pware.oc.perf.realtimeBlock.ts +118 -118
  84. package/src/pware.oc.perf/pware.oc.perf.realtimeCpuRam.ts +79 -79
  85. package/src/pware.oc.perf/pware.oc.perf.realtimeSampler.ts +71 -71
  86. package/src/pware.oc.perf/pware.oc.perf.realtimeTimeline.ts +214 -214
  87. package/src/pware.oc.perf/pware.oc.perf.self.ts +179 -179
  88. package/src/pware.oc.perf/pware.oc.perf.view.tsx +463 -462
  89. package/src/pware.oc.runtime/index.ts +13 -13
  90. package/src/pware.oc.runtime/pware.oc.runtime.monitor.ts +142 -142
  91. package/src/pware.oc.runtime/pware.oc.runtime.mywork-enrich.ts +87 -79
  92. package/src/pware.oc.runtime/pware.oc.runtime.mywork.ts +282 -253
  93. package/src/pware.oc.runtime/pware.oc.runtime.omoRead.ts +37 -0
  94. package/src/pware.oc.runtime/pware.oc.runtime.questions.ts +83 -95
  95. package/src/pware.oc.runtime/pware.oc.runtime.snapshotClient.ts +130 -129
  96. package/src/pware.oc.runtime/pware.oc.runtime.source.ts +105 -105
  97. package/src/pware.oc.runtime/pware.oc.runtime.worker.ts +44 -43
  98. package/src/pware.oc.runtime/resolver/index.ts +268 -224
  99. package/src/pware.oc.runtime/resolver/pware.oc.runtime.resolver.delegate.ts +146 -146
  100. package/src/pware.oc.ui/index.ts +12 -12
  101. package/src/pware.oc.ui/pware.oc.ui.chrome.tsx +381 -339
  102. package/src/pware.oc.ui/pware.oc.ui.glyphs.tsx +144 -144
  103. package/src/pware.oc.ui/pware.oc.ui.host.tsx +111 -111
  104. package/src/pware.oc.ui/pware.oc.ui.live.tsx +82 -82
  105. package/src/pware.oc.ui/pware.oc.ui.menudialogs.tsx +843 -843
  106. package/src/pware.oc.ui/pware.oc.ui.sections.tsx +552 -526
  107. package/src/pware.oc.ui/pware.oc.ui.sidebar.tsx +1718 -1629
  108. package/src/pware.oc.ui.tsx +98 -98
@@ -1,179 +1,179 @@
1
- /**
2
- * pware.oc.core.omo.resolver.approval
3
- *
4
- * OMO plan approval queue — drafts/plans under `.omo/` (or legacy `.sisyphus/`)
5
- * whose `status` says they are waiting for the user's sign-off. File discovery
6
- * and stat are shared with the docs index: both this module and `doc.ts` read
7
- * one per-root omo scan cache, so `.omo/` is walked once per TTL no matter how
8
- * many consumers ask. Classification then reads each plan/draft file's
9
- * frontmatter; the result is memoized against the same scan record and is
10
- * recomputed only when that record turns over. A missing `.omo/` is an empty
11
- * list, not an error.
12
- */
13
- import fs from "node:fs"
14
- import path from "node:path"
15
- import { profile } from "../../pware.oc.core/pware.oc.core.debug.js"
16
- import { canonicalizePath } from "../../pware.oc.core/pware.oc.core.paths.js"
17
- import {
18
- MY_WORK_GROUP_DRAFTING,
19
- MY_WORK_GROUP_FINISHED,
20
- MY_WORK_GROUP_READY_REVIEW,
21
- MY_WORK_GROUP_READY_START,
22
- } from "../../pware.oc.core/constants/pware.oc.core.constants.myWork.js"
23
- import { resolveApprovalGroup } from "./pware.oc.omo.resolver.approvalGroup.js"
24
- import { planWorkStateByPlanName } from "./pware.oc.omo.resolver.boulder.js"
25
- import {
26
- approvalName,
27
- parsePlanPendingAction,
28
- parsePlanStatus,
29
- parseReviewBlock,
30
- type ApprovalItem,
31
- } from "./pware.oc.omo.resolver.plan.js"
32
- import { DOC_KIND_DRAFT, DOC_KIND_PLAN } from "../constants/pware.oc.omo.constants.docKind.js"
33
- import {
34
- omoKindRows,
35
- omoScanRecord,
36
- resetDocsCache,
37
- type OmoDocScan,
38
- } from "./pware.oc.omo.resolver.doc.js"
39
- import type { DocView } from "./pware.oc.omo.resolver.doc.js"
40
-
41
- const MAX_ITEMS = 40
42
-
43
- /** The "My work" approval buckets, keyed by group, in scan order. */
44
- export type ScanResult = {
45
- drafting: ApprovalItem[]
46
- readyReview: ApprovalItem[]
47
- readyStart: ApprovalItem[]
48
- finished: ApprovalItem[]
49
- /** Draft documents no action group covers — approved/done, unknown or no status. */
50
- draftDocs: ApprovalItem[]
51
- /** Plan documents no action group covers — unknown or no status. */
52
- plans: ApprovalItem[]
53
- }
54
-
55
- function emptyScan(): ScanResult {
56
- return {
57
- drafting: [],
58
- readyReview: [],
59
- readyStart: [],
60
- finished: [],
61
- draftDocs: [],
62
- plans: [],
63
- }
64
- }
65
-
66
- function sortApprovals(items: ApprovalItem[]): ApprovalItem[] {
67
- items.sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0) || a.name.localeCompare(b.name))
68
- return items.slice(0, MAX_ITEMS)
69
- }
70
-
71
- function isMarkdown(rel: string): boolean {
72
- return rel.toLowerCase().endsWith(".md")
73
- }
74
-
75
- /** Drafts/plans split into the four "My work" buckets by status + file type. */
76
- function classify(
77
- root: string,
78
- draftRows: readonly DocView[],
79
- planRows: readonly DocView[],
80
- ): ScanResult {
81
- const drafting: ApprovalItem[] = []
82
- const readyReview: ApprovalItem[] = []
83
- const readyStart: ApprovalItem[] = []
84
- const finished: ApprovalItem[] = []
85
- const draftDocs: ApprovalItem[] = []
86
- const plans: ApprovalItem[] = []
87
- const seen = new Set<string>()
88
- const workStates = planWorkStateByPlanName(root)
89
- const visit = (rows: readonly DocView[], isDraft: boolean) => {
90
- for (const row of rows) {
91
- const rel = row.rel
92
- if (!isMarkdown(rel) || seen.has(rel)) continue
93
- let text = ""
94
- try {
95
- text = fs.readFileSync(path.join(root, rel), "utf8")
96
- } catch {
97
- continue
98
- }
99
- const status = parsePlanStatus(text)
100
- const name = approvalName(rel)
101
- const workState = workStates.get(name) ?? "absent"
102
- // A plan with no parseable status still reconciles against boulder: one
103
- // whose boulder work completed lands in Finished (resolveApprovalGroup →
104
- // planWorkDone returns true for a completed work state regardless of
105
- // status). A no-status plan with no completed work falls through to the
106
- // Plans archive below; a no-status draft is a working document — Draft docs.
107
- const group = resolveApprovalGroup(status, isDraft, workState, false)
108
- const item: ApprovalItem = {
109
- rel,
110
- name,
111
- status,
112
- pendingAction: parsePlanPendingAction(text),
113
- updatedAt: row.updatedAt,
114
- review: parseReviewBlock(text),
115
- workState,
116
- }
117
- seen.add(rel)
118
- if (!group) {
119
- // A document no action group covers (superseded approved/done, unknown
120
- // or no status) is browsable, not a queue item: drafts → Draft docs,
121
- // plans → Plans.
122
- if (isDraft) draftDocs.push(item)
123
- else plans.push(item)
124
- continue
125
- }
126
- switch (group) {
127
- case MY_WORK_GROUP_DRAFTING:
128
- drafting.push(item)
129
- break
130
- case MY_WORK_GROUP_READY_REVIEW:
131
- readyReview.push(item)
132
- break
133
- case MY_WORK_GROUP_READY_START:
134
- readyStart.push(item)
135
- break
136
- case MY_WORK_GROUP_FINISHED:
137
- finished.push(item)
138
- break
139
- }
140
- }
141
- }
142
- visit(draftRows, true)
143
- visit(planRows, false)
144
- return {
145
- drafting: sortApprovals(drafting),
146
- readyReview: sortApprovals(readyReview),
147
- readyStart: sortApprovals(readyStart),
148
- finished: sortApprovals(finished),
149
- draftDocs: sortApprovals(draftDocs),
150
- plans: sortApprovals(plans),
151
- }
152
- }
153
-
154
- /** Approval buckets memoized against the shared per-root omo scan record. */
155
- const approvalMemo = new WeakMap<OmoDocScan, ScanResult>()
156
-
157
- /** Drop the shared omo scan cache — approvals and docs both re-read next call. */
158
- export function resetApprovalsCache(): void {
159
- resetDocsCache()
160
- }
161
-
162
- /** Drafts/plans split into the four "My work" buckets by status + file type. */
163
- export function listApprovals(projectRoot: string | null | undefined): ScanResult {
164
- if (!projectRoot) return emptyScan()
165
- const root = canonicalizePath(projectRoot)
166
- const scan = omoScanRecord(root)
167
- if (!scan) return emptyScan()
168
- const memoized = approvalMemo.get(scan)
169
- if (memoized) return memoized
170
- const result = profile("omo.approvals", () =>
171
- classify(
172
- root,
173
- omoKindRows(DOC_KIND_DRAFT, root),
174
- omoKindRows(DOC_KIND_PLAN, root),
175
- ),
176
- )
177
- approvalMemo.set(scan, result)
178
- return result
179
- }
1
+ /**
2
+ * pware.oc.core.omo.resolver.approval
3
+ *
4
+ * OMO plan approval queue — drafts/plans under `.omo/` (or legacy `.sisyphus/`)
5
+ * whose `status` says they are waiting for the user's sign-off. File discovery
6
+ * and stat are shared with the docs index: both this module and `doc.ts` read
7
+ * one per-root omo scan cache, so `.omo/` is walked once per TTL no matter how
8
+ * many consumers ask. Classification then reads each plan/draft file's
9
+ * frontmatter; the result is memoized against the same scan record and is
10
+ * recomputed only when that record turns over. A missing `.omo/` is an empty
11
+ * list, not an error.
12
+ */
13
+ import fs from "node:fs"
14
+ import path from "node:path"
15
+ import { profile } from "../../pware.oc.core/pware.oc.core.debug.js"
16
+ import { canonicalizePath } from "../../pware.oc.core/pware.oc.core.paths.js"
17
+ import {
18
+ MY_WORK_GROUP_DRAFTING,
19
+ MY_WORK_GROUP_FINISHED,
20
+ MY_WORK_GROUP_READY_REVIEW,
21
+ MY_WORK_GROUP_READY_START,
22
+ } from "../../pware.oc.core/constants/pware.oc.core.constants.myWork.js"
23
+ import { resolveApprovalGroup } from "./pware.oc.omo.resolver.approvalGroup.js"
24
+ import { planWorkStateByPlanName } from "./pware.oc.omo.resolver.boulder.js"
25
+ import {
26
+ approvalName,
27
+ parsePlanPendingAction,
28
+ parsePlanStatus,
29
+ parseReviewBlock,
30
+ type ApprovalItem,
31
+ } from "./pware.oc.omo.resolver.plan.js"
32
+ import { DOC_KIND_DRAFT, DOC_KIND_PLAN } from "../constants/pware.oc.omo.constants.docKind.js"
33
+ import {
34
+ omoKindRows,
35
+ omoScanRecord,
36
+ resetDocsCache,
37
+ type OmoDocScan,
38
+ } from "./pware.oc.omo.resolver.doc.js"
39
+ import type { DocView } from "./pware.oc.omo.resolver.doc.js"
40
+
41
+ const MAX_ITEMS = 40
42
+
43
+ /** The "My work" approval buckets, keyed by group, in scan order. */
44
+ export type ScanResult = {
45
+ drafting: ApprovalItem[]
46
+ readyReview: ApprovalItem[]
47
+ readyStart: ApprovalItem[]
48
+ finished: ApprovalItem[]
49
+ /** Draft documents no action group covers — approved/done, unknown or no status. */
50
+ draftDocs: ApprovalItem[]
51
+ /** Plan documents no action group covers — unknown or no status. */
52
+ plans: ApprovalItem[]
53
+ }
54
+
55
+ function emptyScan(): ScanResult {
56
+ return {
57
+ drafting: [],
58
+ readyReview: [],
59
+ readyStart: [],
60
+ finished: [],
61
+ draftDocs: [],
62
+ plans: [],
63
+ }
64
+ }
65
+
66
+ function sortApprovals(items: ApprovalItem[]): ApprovalItem[] {
67
+ items.sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0) || a.name.localeCompare(b.name))
68
+ return items.slice(0, MAX_ITEMS)
69
+ }
70
+
71
+ function isMarkdown(rel: string): boolean {
72
+ return rel.toLowerCase().endsWith(".md")
73
+ }
74
+
75
+ /** Drafts/plans split into the four "My work" buckets by status + file type. */
76
+ function classify(
77
+ root: string,
78
+ draftRows: readonly DocView[],
79
+ planRows: readonly DocView[],
80
+ ): ScanResult {
81
+ const drafting: ApprovalItem[] = []
82
+ const readyReview: ApprovalItem[] = []
83
+ const readyStart: ApprovalItem[] = []
84
+ const finished: ApprovalItem[] = []
85
+ const draftDocs: ApprovalItem[] = []
86
+ const plans: ApprovalItem[] = []
87
+ const seen = new Set<string>()
88
+ const workStates = planWorkStateByPlanName(root)
89
+ const visit = (rows: readonly DocView[], isDraft: boolean) => {
90
+ for (const row of rows) {
91
+ const rel = row.rel
92
+ if (!isMarkdown(rel) || seen.has(rel)) continue
93
+ let text = ""
94
+ try {
95
+ text = fs.readFileSync(path.join(root, rel), "utf8")
96
+ } catch {
97
+ continue
98
+ }
99
+ const status = parsePlanStatus(text)
100
+ const name = approvalName(rel)
101
+ const workState = workStates.get(name) ?? "absent"
102
+ // A plan with no parseable status still reconciles against boulder: one
103
+ // whose boulder work completed lands in Finished (resolveApprovalGroup →
104
+ // planWorkDone returns true for a completed work state regardless of
105
+ // status). A no-status plan with no completed work falls through to the
106
+ // Plans archive below; a no-status draft is a working document — Draft docs.
107
+ const group = resolveApprovalGroup(status, isDraft, workState, false)
108
+ const item: ApprovalItem = {
109
+ rel,
110
+ name,
111
+ status,
112
+ pendingAction: parsePlanPendingAction(text),
113
+ updatedAt: row.updatedAt,
114
+ review: parseReviewBlock(text),
115
+ workState,
116
+ }
117
+ seen.add(rel)
118
+ if (!group) {
119
+ // A document no action group covers (superseded approved/done, unknown
120
+ // or no status) is browsable, not a queue item: drafts → Draft docs,
121
+ // plans → Plans.
122
+ if (isDraft) draftDocs.push(item)
123
+ else plans.push(item)
124
+ continue
125
+ }
126
+ switch (group) {
127
+ case MY_WORK_GROUP_DRAFTING:
128
+ drafting.push(item)
129
+ break
130
+ case MY_WORK_GROUP_READY_REVIEW:
131
+ readyReview.push(item)
132
+ break
133
+ case MY_WORK_GROUP_READY_START:
134
+ readyStart.push(item)
135
+ break
136
+ case MY_WORK_GROUP_FINISHED:
137
+ finished.push(item)
138
+ break
139
+ }
140
+ }
141
+ }
142
+ visit(draftRows, true)
143
+ visit(planRows, false)
144
+ return {
145
+ drafting: sortApprovals(drafting),
146
+ readyReview: sortApprovals(readyReview),
147
+ readyStart: sortApprovals(readyStart),
148
+ finished: sortApprovals(finished),
149
+ draftDocs: sortApprovals(draftDocs),
150
+ plans: sortApprovals(plans),
151
+ }
152
+ }
153
+
154
+ /** Approval buckets memoized against the shared per-root omo scan record. */
155
+ const approvalMemo = new WeakMap<OmoDocScan, ScanResult>()
156
+
157
+ /** Drop the shared omo scan cache — approvals and docs both re-read next call. */
158
+ export function resetApprovalsCache(): void {
159
+ resetDocsCache()
160
+ }
161
+
162
+ /** Drafts/plans split into the four "My work" buckets by status + file type. */
163
+ export function listApprovals(projectRoot: string | null | undefined): ScanResult {
164
+ if (!projectRoot) return emptyScan()
165
+ const root = canonicalizePath(projectRoot)
166
+ const scan = omoScanRecord(root)
167
+ if (!scan) return emptyScan()
168
+ const memoized = approvalMemo.get(scan)
169
+ if (memoized) return memoized
170
+ const result = profile("omo.approvals", () =>
171
+ classify(
172
+ root,
173
+ omoKindRows(DOC_KIND_DRAFT, root),
174
+ omoKindRows(DOC_KIND_PLAN, root),
175
+ ),
176
+ )
177
+ approvalMemo.set(scan, result)
178
+ return result
179
+ }
@@ -1,116 +1,116 @@
1
- /**
2
- * pware.oc.omo.resolver.approvalGroup
3
- *
4
- * Which "My work" approval group a plan belongs to, from its OMO plan status
5
- * alone, plus whether a plan path is still a draft. Lives in omo (not core)
6
- * because it consumes the OMO plan-status constants; core may not import them.
7
- */
8
- import {
9
- MY_WORK_GROUP_DRAFTING,
10
- MY_WORK_GROUP_FINISHED,
11
- MY_WORK_GROUP_READY_REVIEW,
12
- MY_WORK_GROUP_READY_START,
13
- type ApprovalGroupKind,
14
- } from "../../pware.oc.core/constants/pware.oc.core.constants.myWork.js"
15
- import {
16
- PLAN_PENDING_STATUSES,
17
- PLAN_STATUS_APPROVED,
18
- PLAN_STATUS_DONE,
19
- PLAN_STATUS_DRAFTING,
20
- WORK_STATE_ABSENT,
21
- WORK_STATE_COMPLETED,
22
- type WorkState,
23
- } from "../../pware.oc.omo/constants/pware.oc.omo.constants.planStatus.js"
24
-
25
- /** The pending sign-off set widened so `.includes()` accepts any status string. */
26
- const PENDING_STATUSES: readonly string[] = PLAN_PENDING_STATUSES
27
-
28
- /**
29
- * Which approval group a plan belongs to, from its OMO status alone:
30
- * `drafting` while still a draft, `ready-to-review` for a pending status,
31
- * `ready-to-start` for an approved plan, `finished` for a done plan. Null when
32
- * the item is superseded — an approved or done draft, or an unknown status —
33
- * and must not be shown.
34
- */
35
- export function approvalGroup(
36
- status: string | null,
37
- isDraft: boolean,
38
- ): ApprovalGroupKind | null {
39
- const s = (status ?? "").toLowerCase()
40
- if (s === PLAN_STATUS_DRAFTING) return MY_WORK_GROUP_DRAFTING
41
- if (PENDING_STATUSES.includes(s)) return MY_WORK_GROUP_READY_REVIEW
42
- if (s === PLAN_STATUS_APPROVED) return isDraft ? null : MY_WORK_GROUP_READY_START
43
- if (s === PLAN_STATUS_DONE) return isDraft ? null : MY_WORK_GROUP_FINISHED
44
- return null
45
- }
46
-
47
- /** True when a plan path points at a draft still being written, not a final plan. */
48
- export function isDraftOf(rel: string): boolean {
49
- return rel.startsWith("drafts/") || rel.startsWith(".sisyphus/drafts/")
50
- }
51
-
52
- /**
53
- * True when we have trustworthy evidence the plan's work finished: a boulder
54
- * work completed (layer 1), or — with no boulder work for this plan — the
55
- * writer session's todos all completed (layer 2). Layer 2 only applies to an
56
- * `approved` plan; a pending/drafting plan was never cleared to start, so its
57
- * completed todos are the planner's, not the work's.
58
- */
59
- export function planWorkDone(
60
- status: string | null,
61
- workState: WorkState,
62
- todosDone: boolean,
63
- ): boolean {
64
- const s = (status ?? "").toLowerCase()
65
- if (workState === WORK_STATE_COMPLETED) return true
66
- if (workState === WORK_STATE_ABSENT && todosDone && s === PLAN_STATUS_APPROVED) return true
67
- return false
68
- }
69
-
70
- /**
71
- * The effective My-work group, reconciling the (untrusted) frontmatter status
72
- * against boulder + db evidence. Done work → finished regardless of the
73
- * frontmatter (a draft stays superseded); otherwise it falls back to the pure
74
- * `approvalGroup` mapping, so the plugin still works with no boulder and no db.
75
- */
76
- export function resolveApprovalGroup(
77
- status: string | null,
78
- isDraft: boolean,
79
- workState: WorkState,
80
- todosDone: boolean,
81
- ): ApprovalGroupKind | null {
82
- if (planWorkDone(status, workState, todosDone)) {
83
- return isDraft ? null : MY_WORK_GROUP_FINISHED
84
- }
85
- return approvalGroup(status, isDraft)
86
- }
87
-
88
- /** True when the group is the drafting bucket. */
89
- export function isDrafting(g: ApprovalGroupKind | null): boolean {
90
- return g === MY_WORK_GROUP_DRAFTING
91
- }
92
-
93
- /** True when the group is waiting for the user's sign-off. */
94
- export function isReadyToReview(g: ApprovalGroupKind | null): boolean {
95
- return g === MY_WORK_GROUP_READY_REVIEW
96
- }
97
-
98
- /** Alias for isReadyToReview — a plan awaiting approval. */
99
- export function isWaitingApproval(g: ApprovalGroupKind | null): boolean {
100
- return g === MY_WORK_GROUP_READY_REVIEW
101
- }
102
-
103
- /** Alias for isReadyToReview — a plan pending approval. */
104
- export function isPendingApproval(g: ApprovalGroupKind | null): boolean {
105
- return g === MY_WORK_GROUP_READY_REVIEW
106
- }
107
-
108
- /** True when the group is approved and ready to start. */
109
- export function isReadyToStart(g: ApprovalGroupKind | null): boolean {
110
- return g === MY_WORK_GROUP_READY_START
111
- }
112
-
113
- /** True when the group is finished. */
114
- export function isFinished(g: ApprovalGroupKind | null): boolean {
115
- return g === MY_WORK_GROUP_FINISHED
116
- }
1
+ /**
2
+ * pware.oc.omo.resolver.approvalGroup
3
+ *
4
+ * Which "My work" approval group a plan belongs to, from its OMO plan status
5
+ * alone, plus whether a plan path is still a draft. Lives in omo (not core)
6
+ * because it consumes the OMO plan-status constants; core may not import them.
7
+ */
8
+ import {
9
+ MY_WORK_GROUP_DRAFTING,
10
+ MY_WORK_GROUP_FINISHED,
11
+ MY_WORK_GROUP_READY_REVIEW,
12
+ MY_WORK_GROUP_READY_START,
13
+ type ApprovalGroupKind,
14
+ } from "../../pware.oc.core/constants/pware.oc.core.constants.myWork.js"
15
+ import {
16
+ PLAN_PENDING_STATUSES,
17
+ PLAN_STATUS_APPROVED,
18
+ PLAN_STATUS_DONE,
19
+ PLAN_STATUS_DRAFTING,
20
+ WORK_STATE_ABSENT,
21
+ WORK_STATE_COMPLETED,
22
+ type WorkState,
23
+ } from "../../pware.oc.omo/constants/pware.oc.omo.constants.planStatus.js"
24
+
25
+ /** The pending sign-off set widened so `.includes()` accepts any status string. */
26
+ const PENDING_STATUSES: readonly string[] = PLAN_PENDING_STATUSES
27
+
28
+ /**
29
+ * Which approval group a plan belongs to, from its OMO status alone:
30
+ * `drafting` while still a draft, `ready-to-review` for a pending status,
31
+ * `ready-to-start` for an approved plan, `finished` for a done plan. Null when
32
+ * the item is superseded — an approved or done draft, or an unknown status —
33
+ * and must not be shown.
34
+ */
35
+ export function approvalGroup(
36
+ status: string | null,
37
+ isDraft: boolean,
38
+ ): ApprovalGroupKind | null {
39
+ const s = (status ?? "").toLowerCase()
40
+ if (s === PLAN_STATUS_DRAFTING) return MY_WORK_GROUP_DRAFTING
41
+ if (PENDING_STATUSES.includes(s)) return MY_WORK_GROUP_READY_REVIEW
42
+ if (s === PLAN_STATUS_APPROVED) return isDraft ? null : MY_WORK_GROUP_READY_START
43
+ if (s === PLAN_STATUS_DONE) return isDraft ? null : MY_WORK_GROUP_FINISHED
44
+ return null
45
+ }
46
+
47
+ /** True when a plan path points at a draft still being written, not a final plan. */
48
+ export function isDraftOf(rel: string): boolean {
49
+ return rel.startsWith("drafts/") || rel.startsWith(".sisyphus/drafts/")
50
+ }
51
+
52
+ /**
53
+ * True when we have trustworthy evidence the plan's work finished: a boulder
54
+ * work completed (layer 1), or — with no boulder work for this plan — the
55
+ * writer session's todos all completed (layer 2). Layer 2 only applies to an
56
+ * `approved` plan; a pending/drafting plan was never cleared to start, so its
57
+ * completed todos are the planner's, not the work's.
58
+ */
59
+ export function planWorkDone(
60
+ status: string | null,
61
+ workState: WorkState,
62
+ todosDone: boolean,
63
+ ): boolean {
64
+ const s = (status ?? "").toLowerCase()
65
+ if (workState === WORK_STATE_COMPLETED) return true
66
+ if (workState === WORK_STATE_ABSENT && todosDone && s === PLAN_STATUS_APPROVED) return true
67
+ return false
68
+ }
69
+
70
+ /**
71
+ * The effective My-work group, reconciling the (untrusted) frontmatter status
72
+ * against boulder + db evidence. Done work → finished regardless of the
73
+ * frontmatter (a draft stays superseded); otherwise it falls back to the pure
74
+ * `approvalGroup` mapping, so the plugin still works with no boulder and no db.
75
+ */
76
+ export function resolveApprovalGroup(
77
+ status: string | null,
78
+ isDraft: boolean,
79
+ workState: WorkState,
80
+ todosDone: boolean,
81
+ ): ApprovalGroupKind | null {
82
+ if (planWorkDone(status, workState, todosDone)) {
83
+ return isDraft ? null : MY_WORK_GROUP_FINISHED
84
+ }
85
+ return approvalGroup(status, isDraft)
86
+ }
87
+
88
+ /** True when the group is the drafting bucket. */
89
+ export function isDrafting(g: ApprovalGroupKind | null): boolean {
90
+ return g === MY_WORK_GROUP_DRAFTING
91
+ }
92
+
93
+ /** True when the group is waiting for the user's sign-off. */
94
+ export function isReadyToReview(g: ApprovalGroupKind | null): boolean {
95
+ return g === MY_WORK_GROUP_READY_REVIEW
96
+ }
97
+
98
+ /** Alias for isReadyToReview — a plan awaiting approval. */
99
+ export function isWaitingApproval(g: ApprovalGroupKind | null): boolean {
100
+ return g === MY_WORK_GROUP_READY_REVIEW
101
+ }
102
+
103
+ /** Alias for isReadyToReview — a plan pending approval. */
104
+ export function isPendingApproval(g: ApprovalGroupKind | null): boolean {
105
+ return g === MY_WORK_GROUP_READY_REVIEW
106
+ }
107
+
108
+ /** True when the group is approved and ready to start. */
109
+ export function isReadyToStart(g: ApprovalGroupKind | null): boolean {
110
+ return g === MY_WORK_GROUP_READY_START
111
+ }
112
+
113
+ /** True when the group is finished. */
114
+ export function isFinished(g: ApprovalGroupKind | null): boolean {
115
+ return g === MY_WORK_GROUP_FINISHED
116
+ }
@@ -1,34 +1,34 @@
1
- /**
2
- * pware.oc.omo.resolver.approvalstate
3
- *
4
- * Reads the planner session's `.omo/run-continuation` background-task marker.
5
- * Lives in the omo layer — no sibling domain may read omo files. The runtime
6
- * layer's my-work enrich module composes this marker with the session activity
7
- * state.
8
- */
9
- import path from "node:path"
10
- import { firstOmoPath } from "./pware.oc.omo.resolver.boulder.js"
11
- import { readJson } from "../../pware.oc.core/pware.oc.core.paths.js"
12
-
13
- /** First existing `.omo`/`.sisyphus` run-continuation directory, or null. */
14
- export function firstRunContinuationDir(projectRoot: string): string | null {
15
- return firstOmoPath(projectRoot, "run-continuation")
16
- }
17
-
18
- /**
19
- * The `.omo/run-continuation` background-task state for a session, or null when
20
- * absent/unreadable.
21
- */
22
- export function readRunContinuationState(
23
- projectRoot: string | null | undefined,
24
- sessionId: string,
25
- ): string | null {
26
- if (!projectRoot) return null
27
- const dir = firstRunContinuationDir(projectRoot)
28
- if (!dir) return null
29
- const raw = readJson(path.join(dir, `${sessionId}.json`)) as {
30
- sources?: { "background-task"?: { state?: unknown } }
31
- } | null
32
- const state = raw?.sources?.["background-task"]?.state
33
- return typeof state === "string" ? state : null
34
- }
1
+ /**
2
+ * pware.oc.omo.resolver.approvalstate
3
+ *
4
+ * Reads the planner session's `.omo/run-continuation` background-task marker.
5
+ * Lives in the omo layer — no sibling domain may read omo files. The runtime
6
+ * layer's my-work enrich module composes this marker with the session activity
7
+ * state.
8
+ */
9
+ import path from "node:path"
10
+ import { firstOmoPath } from "./pware.oc.omo.resolver.boulder.js"
11
+ import { readJson } from "../../pware.oc.core/pware.oc.core.paths.js"
12
+
13
+ /** First existing `.omo`/`.sisyphus` run-continuation directory, or null. */
14
+ export function firstRunContinuationDir(projectRoot: string): string | null {
15
+ return firstOmoPath(projectRoot, "run-continuation")
16
+ }
17
+
18
+ /**
19
+ * The `.omo/run-continuation` background-task state for a session, or null when
20
+ * absent/unreadable.
21
+ */
22
+ export function readRunContinuationState(
23
+ projectRoot: string | null | undefined,
24
+ sessionId: string,
25
+ ): string | null {
26
+ if (!projectRoot) return null
27
+ const dir = firstRunContinuationDir(projectRoot)
28
+ if (!dir) return null
29
+ const raw = readJson(path.join(dir, `${sessionId}.json`)) as {
30
+ sources?: { "background-task"?: { state?: unknown } }
31
+ } | null
32
+ const state = raw?.sources?.["background-task"]?.state
33
+ return typeof state === "string" ? state : null
34
+ }