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.
- package/.oesignore +17 -17
- package/CHANGELOG.md +96 -95
- package/LICENSE +21 -21
- package/README.md +150 -235
- package/oes.json +13 -11
- package/package.json +100 -100
- package/scripts/install-git-hooks.mjs +29 -29
- package/src/pware.oc.core/constants/index.ts +18 -18
- package/src/pware.oc.core/constants/pware.oc.core.constants.eventKind.ts +29 -29
- package/src/pware.oc.core/constants/pware.oc.core.constants.eventName.ts +15 -13
- package/src/pware.oc.core/constants/pware.oc.core.constants.eventType.ts +241 -241
- package/src/pware.oc.core/constants/pware.oc.core.constants.myWork.ts +55 -55
- package/src/pware.oc.core/constants/pware.oc.core.constants.partType.ts +65 -65
- package/src/pware.oc.core/constants/pware.oc.core.constants.phase.ts +58 -58
- package/src/pware.oc.core/constants/pware.oc.core.constants.pulse.ts +63 -63
- package/src/pware.oc.core/constants/pware.oc.core.constants.rowKind.ts +34 -34
- package/src/pware.oc.core/constants/pware.oc.core.constants.status.ts +74 -74
- package/src/pware.oc.core/constants/pware.oc.core.constants.toolName.ts +69 -69
- package/src/pware.oc.core/git/index.ts +7 -7
- package/src/pware.oc.core/git/pware.oc.core.git.ts +237 -237
- package/src/pware.oc.core/git/pware.oc.core.gitignore.ts +87 -87
- package/src/pware.oc.core/index.ts +19 -18
- package/src/pware.oc.core/pware.oc.core.bus.ts +42 -42
- package/src/pware.oc.core/pware.oc.core.cache.ts +48 -48
- package/src/pware.oc.core/pware.oc.core.clipboard.ts +97 -97
- package/src/pware.oc.core/pware.oc.core.debug.ts +280 -280
- package/src/pware.oc.core/pware.oc.core.events.ts +79 -79
- package/src/pware.oc.core/pware.oc.core.glyph.ts +135 -135
- package/src/pware.oc.core/pware.oc.core.layout.ts +234 -234
- package/src/pware.oc.core/pware.oc.core.oes.ts +99 -89
- package/src/pware.oc.core/pware.oc.core.paths.ts +240 -240
- package/src/pware.oc.core/pware.oc.core.preview.ts +74 -74
- package/src/pware.oc.core/pware.oc.core.pulse.ts +726 -726
- package/src/pware.oc.core/pware.oc.core.runtimeConfig.ts +41 -0
- package/src/pware.oc.core/pware.oc.core.sqlite.ts +164 -175
- package/src/pware.oc.core/pware.oc.core.sqliteGateway.ts +89 -0
- package/src/pware.oc.core/pware.oc.core.status.ts +214 -214
- package/src/pware.oc.core/pware.oc.core.timing.ts +63 -63
- package/src/pware.oc.core/pware.oc.core.width.ts +215 -215
- package/src/pware.oc.omo/constants/index.ts +15 -15
- package/src/pware.oc.omo/constants/pware.oc.omo.constants.backgroundTask.ts +18 -18
- package/src/pware.oc.omo/constants/pware.oc.omo.constants.boulderStatus.ts +49 -49
- package/src/pware.oc.omo/constants/pware.oc.omo.constants.docKind.ts +29 -29
- package/src/pware.oc.omo/constants/pware.oc.omo.constants.eventName.ts +11 -11
- package/src/pware.oc.omo/constants/pware.oc.omo.constants.planStatus.ts +60 -60
- package/src/pware.oc.omo/constants/pware.oc.omo.constants.reviewStatus.ts +49 -49
- package/src/pware.oc.omo/constants/pware.oc.omo.constants.startWork.ts +25 -25
- package/src/pware.oc.omo/constants/pware.oc.omo.constants.verdict.ts +38 -38
- package/src/pware.oc.omo/index.ts +7 -7
- package/src/pware.oc.omo/resolver/index.ts +19 -19
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approval.ts +179 -179
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approvalGroup.ts +116 -116
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approvalState.ts +34 -34
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.boulder.ts +503 -503
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.config.ts +40 -40
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.doc.ts +269 -269
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.draftFile.ts +18 -18
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.notepadsFile.ts +18 -18
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.plan.ts +155 -155
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.planFile.ts +363 -361
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.proofFile.ts +18 -18
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.rulesFile.ts +11 -11
- package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.runContinuationFile.ts +14 -14
- package/src/pware.oc.opencode/constants/index.ts +10 -10
- package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.eventName.ts +15 -15
- package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.fileTouch.ts +18 -18
- package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.questionKind.ts +45 -45
- package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.sessionStatus.ts +58 -58
- package/src/pware.oc.opencode/index.ts +8 -8
- package/src/pware.oc.opencode/pware.oc.opencode.events.ts +182 -182
- package/src/pware.oc.opencode/pware.oc.opencode.files.ts +399 -399
- package/src/pware.oc.opencode/resolver/index.ts +223 -170
- package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.file.ts +150 -162
- package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.question.ts +149 -185
- package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.session.ts +248 -211
- package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.todo.ts +22 -26
- package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.tool.ts +224 -236
- package/src/pware.oc.perf/index.ts +14 -14
- package/src/pware.oc.perf/pware.oc.perf.asciichart.d.ts +15 -15
- package/src/pware.oc.perf/pware.oc.perf.charts.ts +284 -284
- package/src/pware.oc.perf/pware.oc.perf.reader.ts +962 -927
- package/src/pware.oc.perf/pware.oc.perf.realtime.ts +88 -88
- package/src/pware.oc.perf/pware.oc.perf.realtimeBlock.ts +118 -118
- package/src/pware.oc.perf/pware.oc.perf.realtimeCpuRam.ts +79 -79
- package/src/pware.oc.perf/pware.oc.perf.realtimeSampler.ts +71 -71
- package/src/pware.oc.perf/pware.oc.perf.realtimeTimeline.ts +214 -214
- package/src/pware.oc.perf/pware.oc.perf.self.ts +179 -179
- package/src/pware.oc.perf/pware.oc.perf.view.tsx +463 -462
- package/src/pware.oc.runtime/index.ts +13 -13
- package/src/pware.oc.runtime/pware.oc.runtime.monitor.ts +142 -142
- package/src/pware.oc.runtime/pware.oc.runtime.mywork-enrich.ts +87 -79
- package/src/pware.oc.runtime/pware.oc.runtime.mywork.ts +282 -253
- package/src/pware.oc.runtime/pware.oc.runtime.omoRead.ts +37 -0
- package/src/pware.oc.runtime/pware.oc.runtime.questions.ts +83 -95
- package/src/pware.oc.runtime/pware.oc.runtime.snapshotClient.ts +130 -129
- package/src/pware.oc.runtime/pware.oc.runtime.source.ts +105 -105
- package/src/pware.oc.runtime/pware.oc.runtime.worker.ts +44 -43
- package/src/pware.oc.runtime/resolver/index.ts +268 -224
- package/src/pware.oc.runtime/resolver/pware.oc.runtime.resolver.delegate.ts +146 -146
- package/src/pware.oc.ui/index.ts +12 -12
- package/src/pware.oc.ui/pware.oc.ui.chrome.tsx +381 -339
- package/src/pware.oc.ui/pware.oc.ui.glyphs.tsx +144 -144
- package/src/pware.oc.ui/pware.oc.ui.host.tsx +111 -111
- package/src/pware.oc.ui/pware.oc.ui.live.tsx +82 -82
- package/src/pware.oc.ui/pware.oc.ui.menudialogs.tsx +843 -843
- package/src/pware.oc.ui/pware.oc.ui.sections.tsx +552 -526
- package/src/pware.oc.ui/pware.oc.ui.sidebar.tsx +1718 -1629
- package/src/pware.oc.ui.tsx +98 -98
|
@@ -1,144 +1,144 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pware.oc.ui.glyphs
|
|
3
|
-
*
|
|
4
|
-
* Domain glyph definitions (My work kinds, git letters, review lanes) that
|
|
5
|
-
* depend on opencode / omo / runtime types, so they cannot live in core. Each
|
|
6
|
-
* returns a complete `GlyphSpec` (char + tone). The pure mark/flow glyphs live
|
|
7
|
-
* in core (`pware.oc.core/pware.oc.core.glyph.ts`) and are re-exported here so
|
|
8
|
-
* every glyph resolves through this one module.
|
|
9
|
-
*/
|
|
10
|
-
import type { FileLetter } from "../pware.oc.opencode/pware.oc.opencode.files.js"
|
|
11
|
-
import type { MyWorkKind } from "../pware.oc.runtime/pware.oc.runtime.mywork.js"
|
|
12
|
-
import type { ReviewLane, ReviewState } from "../pware.oc.omo/resolver/pware.oc.omo.resolver.plan.js"
|
|
13
|
-
import {
|
|
14
|
-
REVIEW_STATUS_APPROVED,
|
|
15
|
-
REVIEW_STATUS_CHANGES_REQUESTED,
|
|
16
|
-
REVIEW_STATUS_INCONCLUSIVE,
|
|
17
|
-
REVIEW_STATUS_PENDING,
|
|
18
|
-
ROUND_STATUS_ACTIVE,
|
|
19
|
-
} from "../pware.oc.omo/constants/pware.oc.omo.constants.reviewStatus.js"
|
|
20
|
-
import {
|
|
21
|
-
MY_WORK_GROUP_DISMISSED,
|
|
22
|
-
MY_WORK_GROUP_DRAFT_DOCS,
|
|
23
|
-
MY_WORK_GROUP_DRAFTING,
|
|
24
|
-
MY_WORK_GROUP_FINISHED,
|
|
25
|
-
MY_WORK_GROUP_PINNED,
|
|
26
|
-
MY_WORK_GROUP_PLANS,
|
|
27
|
-
MY_WORK_GROUP_READY_REVIEW,
|
|
28
|
-
MY_WORK_GROUP_READY_START,
|
|
29
|
-
MY_WORK_GROUP_SESSIONS,
|
|
30
|
-
} from "../pware.oc.core/constants/pware.oc.core.constants.myWork.js"
|
|
31
|
-
import {
|
|
32
|
-
QUESTION_KIND_ERROR,
|
|
33
|
-
QUESTION_KIND_INTERRUPTED,
|
|
34
|
-
QUESTION_KIND_QUESTION,
|
|
35
|
-
} from "../pware.oc.opencode/constants/pware.oc.opencode.constants.questionKind.js"
|
|
36
|
-
import type { GlyphSpec } from "../pware.oc.core/pware.oc.core.glyph.js"
|
|
37
|
-
|
|
38
|
-
export { workStatusGlyph } from "../pware.oc.core/pware.oc.core.status.js"
|
|
39
|
-
export {
|
|
40
|
-
SPINNER_FRAMES,
|
|
41
|
-
QUEUED_GLYPH,
|
|
42
|
-
ENGAGE_MIN_FRAMES,
|
|
43
|
-
ENGAGE_MAX_FRAMES,
|
|
44
|
-
spinnerFrame,
|
|
45
|
-
engageFill,
|
|
46
|
-
engageDone,
|
|
47
|
-
flowBlinkOn,
|
|
48
|
-
sinPulseAlpha,
|
|
49
|
-
type SinPulseAlphaOpts,
|
|
50
|
-
markTone,
|
|
51
|
-
stateGlyph,
|
|
52
|
-
directionGlyph,
|
|
53
|
-
defaultBodyTone,
|
|
54
|
-
type GlyphSpec,
|
|
55
|
-
type ToneKey,
|
|
56
|
-
} from "../pware.oc.core/pware.oc.core.glyph.js"
|
|
57
|
-
|
|
58
|
-
/** Group header before a clustered row list. */
|
|
59
|
-
export const GROUP_GLYPH = "▾"
|
|
60
|
-
/** Perf: a phase of the wall clock spent thinking. */
|
|
61
|
-
export const THINK_GLYPH = "∴"
|
|
62
|
-
|
|
63
|
-
/** The glyph for a My work kind — a complete spec; the tone says how urgent it is. */
|
|
64
|
-
export function myWorkGlyph(kind: MyWorkKind): GlyphSpec {
|
|
65
|
-
if (kind === QUESTION_KIND_QUESTION) return { char: "?", tone: "warning" }
|
|
66
|
-
if (kind === QUESTION_KIND_INTERRUPTED) return { char: "⊘", tone: "textMuted" }
|
|
67
|
-
if (kind === QUESTION_KIND_ERROR) return { char: "×", tone: "error" }
|
|
68
|
-
if (kind === MY_WORK_GROUP_SESSIONS) return { char: "◔", tone: "primary" }
|
|
69
|
-
if (kind === MY_WORK_GROUP_PINNED) return { char: "P", tone: "primary" }
|
|
70
|
-
if (kind === MY_WORK_GROUP_READY_REVIEW) return { char: "!", tone: "warning" }
|
|
71
|
-
if (kind === MY_WORK_GROUP_DRAFTING) return { char: "…", tone: "textMuted" }
|
|
72
|
-
if (kind === MY_WORK_GROUP_DRAFT_DOCS) return { char: "•", tone: "textMuted" }
|
|
73
|
-
if (kind === MY_WORK_GROUP_PLANS) return { char: "▸", tone: "textMuted" }
|
|
74
|
-
if (kind === MY_WORK_GROUP_READY_START) return { char: "▶", tone: "primary" }
|
|
75
|
-
if (kind === MY_WORK_GROUP_FINISHED) return { char: "✓", tone: "success" }
|
|
76
|
-
if (kind === MY_WORK_GROUP_DISMISSED) return { char: "⊘", tone: "textMuted" }
|
|
77
|
-
return { char: "!", tone: "warning" }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Neutral tab-header light: a small muted bullet, shown when nothing is
|
|
82
|
-
* waiting on the user (and for every non-My-work tab).
|
|
83
|
-
*/
|
|
84
|
-
export const TAB_NEUTRAL_GLYPH: GlyphSpec = { char: "•", tone: "textMuted" }
|
|
85
|
-
|
|
86
|
-
/** One item the My-work tab light reasons about. `ended` marks a terminated part. */
|
|
87
|
-
export type TabAttentionItem = {
|
|
88
|
-
kind: MyWorkKind
|
|
89
|
-
/** True when the part already has a terminal end time — history, not live. */
|
|
90
|
-
ended?: boolean
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* The tab light's winner list, most urgent first. A live open question beats
|
|
95
|
-
* everything; an *ended* error is history (the panel still lists it in Errors)
|
|
96
|
-
* and never lights the tab; running/drafting/finished are not waiting on you.
|
|
97
|
-
*/
|
|
98
|
-
const TAB_ATTENTION_PRIORITY: readonly ((i: TabAttentionItem) => boolean)[] = [
|
|
99
|
-
(i) => i.kind === QUESTION_KIND_QUESTION,
|
|
100
|
-
(i) => i.kind === QUESTION_KIND_ERROR && !i.ended,
|
|
101
|
-
(i) => i.kind === MY_WORK_GROUP_READY_REVIEW,
|
|
102
|
-
(i) => i.kind === MY_WORK_GROUP_READY_START,
|
|
103
|
-
(i) => i.kind === QUESTION_KIND_INTERRUPTED && !i.ended,
|
|
104
|
-
]
|
|
105
|
-
|
|
106
|
-
/** The My-work tab light: the most urgent live waiting item, or a neutral bullet. */
|
|
107
|
-
export function tabAttentionGlyph(items: readonly TabAttentionItem[]): GlyphSpec {
|
|
108
|
-
for (const match of TAB_ATTENTION_PRIORITY) {
|
|
109
|
-
for (const item of items) {
|
|
110
|
-
if (match(item)) return myWorkGlyph(item.kind)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return TAB_NEUTRAL_GLYPH
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** A git-status letter as a glyph: added green, deleted red, modified yellow, rest muted. */
|
|
117
|
-
export function fileLetterGlyph(letter: FileLetter | null): GlyphSpec {
|
|
118
|
-
const char = letter ?? "•"
|
|
119
|
-
const tone =
|
|
120
|
-
letter === "A" ? "success" : letter === "D" ? "error" : letter === "M" ? "warning" : "textMuted"
|
|
121
|
-
return { char, tone }
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** One ulw-plan review lane: ✓ approved, ! changes, ? inconclusive, … live, · pending. */
|
|
125
|
-
export function reviewLaneGlyph(lane: ReviewLane | null | undefined): GlyphSpec {
|
|
126
|
-
const s = lane?.status
|
|
127
|
-
if (s === REVIEW_STATUS_APPROVED) return { char: "✓", tone: "success" }
|
|
128
|
-
if (s === REVIEW_STATUS_CHANGES_REQUESTED) return { char: "!", tone: "warning" }
|
|
129
|
-
if (s === REVIEW_STATUS_INCONCLUSIVE) return { char: "?", tone: "warning" }
|
|
130
|
-
if (s === REVIEW_STATUS_PENDING || !s) return { char: "·", tone: "textMuted" }
|
|
131
|
-
return { char: "…", tone: "textMuted" }
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Compact review state for a plan row: `R<round> <momus><independent>` while a
|
|
136
|
-
* round is recorded, otherwise just the two lanes. Null when no review exists.
|
|
137
|
-
*/
|
|
138
|
-
export function reviewStateSuffix(review: ReviewState | null | undefined): string | null {
|
|
139
|
-
if (!review || (!review.required && !review.roundId && !review.roundStatus)) return null
|
|
140
|
-
const lanes = `${reviewLaneGlyph(review.lanes.momus).char}${reviewLaneGlyph(review.lanes.independent).char}`
|
|
141
|
-
if (review.roundId) return `R${review.roundId} ${lanes}`
|
|
142
|
-
if (review.roundStatus === ROUND_STATUS_ACTIVE) return `R… ${lanes}`
|
|
143
|
-
return lanes
|
|
144
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* pware.oc.ui.glyphs
|
|
3
|
+
*
|
|
4
|
+
* Domain glyph definitions (My work kinds, git letters, review lanes) that
|
|
5
|
+
* depend on opencode / omo / runtime types, so they cannot live in core. Each
|
|
6
|
+
* returns a complete `GlyphSpec` (char + tone). The pure mark/flow glyphs live
|
|
7
|
+
* in core (`pware.oc.core/pware.oc.core.glyph.ts`) and are re-exported here so
|
|
8
|
+
* every glyph resolves through this one module.
|
|
9
|
+
*/
|
|
10
|
+
import type { FileLetter } from "../pware.oc.opencode/pware.oc.opencode.files.js"
|
|
11
|
+
import type { MyWorkKind } from "../pware.oc.runtime/pware.oc.runtime.mywork.js"
|
|
12
|
+
import type { ReviewLane, ReviewState } from "../pware.oc.omo/resolver/pware.oc.omo.resolver.plan.js"
|
|
13
|
+
import {
|
|
14
|
+
REVIEW_STATUS_APPROVED,
|
|
15
|
+
REVIEW_STATUS_CHANGES_REQUESTED,
|
|
16
|
+
REVIEW_STATUS_INCONCLUSIVE,
|
|
17
|
+
REVIEW_STATUS_PENDING,
|
|
18
|
+
ROUND_STATUS_ACTIVE,
|
|
19
|
+
} from "../pware.oc.omo/constants/pware.oc.omo.constants.reviewStatus.js"
|
|
20
|
+
import {
|
|
21
|
+
MY_WORK_GROUP_DISMISSED,
|
|
22
|
+
MY_WORK_GROUP_DRAFT_DOCS,
|
|
23
|
+
MY_WORK_GROUP_DRAFTING,
|
|
24
|
+
MY_WORK_GROUP_FINISHED,
|
|
25
|
+
MY_WORK_GROUP_PINNED,
|
|
26
|
+
MY_WORK_GROUP_PLANS,
|
|
27
|
+
MY_WORK_GROUP_READY_REVIEW,
|
|
28
|
+
MY_WORK_GROUP_READY_START,
|
|
29
|
+
MY_WORK_GROUP_SESSIONS,
|
|
30
|
+
} from "../pware.oc.core/constants/pware.oc.core.constants.myWork.js"
|
|
31
|
+
import {
|
|
32
|
+
QUESTION_KIND_ERROR,
|
|
33
|
+
QUESTION_KIND_INTERRUPTED,
|
|
34
|
+
QUESTION_KIND_QUESTION,
|
|
35
|
+
} from "../pware.oc.opencode/constants/pware.oc.opencode.constants.questionKind.js"
|
|
36
|
+
import type { GlyphSpec } from "../pware.oc.core/pware.oc.core.glyph.js"
|
|
37
|
+
|
|
38
|
+
export { workStatusGlyph } from "../pware.oc.core/pware.oc.core.status.js"
|
|
39
|
+
export {
|
|
40
|
+
SPINNER_FRAMES,
|
|
41
|
+
QUEUED_GLYPH,
|
|
42
|
+
ENGAGE_MIN_FRAMES,
|
|
43
|
+
ENGAGE_MAX_FRAMES,
|
|
44
|
+
spinnerFrame,
|
|
45
|
+
engageFill,
|
|
46
|
+
engageDone,
|
|
47
|
+
flowBlinkOn,
|
|
48
|
+
sinPulseAlpha,
|
|
49
|
+
type SinPulseAlphaOpts,
|
|
50
|
+
markTone,
|
|
51
|
+
stateGlyph,
|
|
52
|
+
directionGlyph,
|
|
53
|
+
defaultBodyTone,
|
|
54
|
+
type GlyphSpec,
|
|
55
|
+
type ToneKey,
|
|
56
|
+
} from "../pware.oc.core/pware.oc.core.glyph.js"
|
|
57
|
+
|
|
58
|
+
/** Group header before a clustered row list. */
|
|
59
|
+
export const GROUP_GLYPH = "▾"
|
|
60
|
+
/** Perf: a phase of the wall clock spent thinking. */
|
|
61
|
+
export const THINK_GLYPH = "∴"
|
|
62
|
+
|
|
63
|
+
/** The glyph for a My work kind — a complete spec; the tone says how urgent it is. */
|
|
64
|
+
export function myWorkGlyph(kind: MyWorkKind): GlyphSpec {
|
|
65
|
+
if (kind === QUESTION_KIND_QUESTION) return { char: "?", tone: "warning" }
|
|
66
|
+
if (kind === QUESTION_KIND_INTERRUPTED) return { char: "⊘", tone: "textMuted" }
|
|
67
|
+
if (kind === QUESTION_KIND_ERROR) return { char: "×", tone: "error" }
|
|
68
|
+
if (kind === MY_WORK_GROUP_SESSIONS) return { char: "◔", tone: "primary" }
|
|
69
|
+
if (kind === MY_WORK_GROUP_PINNED) return { char: "P", tone: "primary" }
|
|
70
|
+
if (kind === MY_WORK_GROUP_READY_REVIEW) return { char: "!", tone: "warning" }
|
|
71
|
+
if (kind === MY_WORK_GROUP_DRAFTING) return { char: "…", tone: "textMuted" }
|
|
72
|
+
if (kind === MY_WORK_GROUP_DRAFT_DOCS) return { char: "•", tone: "textMuted" }
|
|
73
|
+
if (kind === MY_WORK_GROUP_PLANS) return { char: "▸", tone: "textMuted" }
|
|
74
|
+
if (kind === MY_WORK_GROUP_READY_START) return { char: "▶", tone: "primary" }
|
|
75
|
+
if (kind === MY_WORK_GROUP_FINISHED) return { char: "✓", tone: "success" }
|
|
76
|
+
if (kind === MY_WORK_GROUP_DISMISSED) return { char: "⊘", tone: "textMuted" }
|
|
77
|
+
return { char: "!", tone: "warning" }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Neutral tab-header light: a small muted bullet, shown when nothing is
|
|
82
|
+
* waiting on the user (and for every non-My-work tab).
|
|
83
|
+
*/
|
|
84
|
+
export const TAB_NEUTRAL_GLYPH: GlyphSpec = { char: "•", tone: "textMuted" }
|
|
85
|
+
|
|
86
|
+
/** One item the My-work tab light reasons about. `ended` marks a terminated part. */
|
|
87
|
+
export type TabAttentionItem = {
|
|
88
|
+
kind: MyWorkKind
|
|
89
|
+
/** True when the part already has a terminal end time — history, not live. */
|
|
90
|
+
ended?: boolean
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The tab light's winner list, most urgent first. A live open question beats
|
|
95
|
+
* everything; an *ended* error is history (the panel still lists it in Errors)
|
|
96
|
+
* and never lights the tab; running/drafting/finished are not waiting on you.
|
|
97
|
+
*/
|
|
98
|
+
const TAB_ATTENTION_PRIORITY: readonly ((i: TabAttentionItem) => boolean)[] = [
|
|
99
|
+
(i) => i.kind === QUESTION_KIND_QUESTION,
|
|
100
|
+
(i) => i.kind === QUESTION_KIND_ERROR && !i.ended,
|
|
101
|
+
(i) => i.kind === MY_WORK_GROUP_READY_REVIEW,
|
|
102
|
+
(i) => i.kind === MY_WORK_GROUP_READY_START,
|
|
103
|
+
(i) => i.kind === QUESTION_KIND_INTERRUPTED && !i.ended,
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
/** The My-work tab light: the most urgent live waiting item, or a neutral bullet. */
|
|
107
|
+
export function tabAttentionGlyph(items: readonly TabAttentionItem[]): GlyphSpec {
|
|
108
|
+
for (const match of TAB_ATTENTION_PRIORITY) {
|
|
109
|
+
for (const item of items) {
|
|
110
|
+
if (match(item)) return myWorkGlyph(item.kind)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return TAB_NEUTRAL_GLYPH
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** A git-status letter as a glyph: added green, deleted red, modified yellow, rest muted. */
|
|
117
|
+
export function fileLetterGlyph(letter: FileLetter | null): GlyphSpec {
|
|
118
|
+
const char = letter ?? "•"
|
|
119
|
+
const tone =
|
|
120
|
+
letter === "A" ? "success" : letter === "D" ? "error" : letter === "M" ? "warning" : "textMuted"
|
|
121
|
+
return { char, tone }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** One ulw-plan review lane: ✓ approved, ! changes, ? inconclusive, … live, · pending. */
|
|
125
|
+
export function reviewLaneGlyph(lane: ReviewLane | null | undefined): GlyphSpec {
|
|
126
|
+
const s = lane?.status
|
|
127
|
+
if (s === REVIEW_STATUS_APPROVED) return { char: "✓", tone: "success" }
|
|
128
|
+
if (s === REVIEW_STATUS_CHANGES_REQUESTED) return { char: "!", tone: "warning" }
|
|
129
|
+
if (s === REVIEW_STATUS_INCONCLUSIVE) return { char: "?", tone: "warning" }
|
|
130
|
+
if (s === REVIEW_STATUS_PENDING || !s) return { char: "·", tone: "textMuted" }
|
|
131
|
+
return { char: "…", tone: "textMuted" }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Compact review state for a plan row: `R<round> <momus><independent>` while a
|
|
136
|
+
* round is recorded, otherwise just the two lanes. Null when no review exists.
|
|
137
|
+
*/
|
|
138
|
+
export function reviewStateSuffix(review: ReviewState | null | undefined): string | null {
|
|
139
|
+
if (!review || (!review.required && !review.roundId && !review.roundStatus)) return null
|
|
140
|
+
const lanes = `${reviewLaneGlyph(review.lanes.momus).char}${reviewLaneGlyph(review.lanes.independent).char}`
|
|
141
|
+
if (review.roundId) return `R${review.roundId} ${lanes}`
|
|
142
|
+
if (review.roundStatus === ROUND_STATUS_ACTIVE) return `R… ${lanes}`
|
|
143
|
+
return lanes
|
|
144
|
+
}
|
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
import type { TuiKeymap, TuiPluginApi } from "@opencode-ai/plugin/tui"
|
|
2
|
-
import { profileAsync } from "../pware.oc.core/pware.oc.core.debug.js"
|
|
3
|
-
import { PART_TYPE_TEXT } from "../pware.oc.core/constants/pware.oc.core.constants.partType.js"
|
|
4
|
-
import {
|
|
5
|
-
START_WORK_MAKE_PR,
|
|
6
|
-
START_WORK_SHIP,
|
|
7
|
-
} from "../pware.oc.omo/constants/pware.oc.omo.constants.startWork.js"
|
|
8
|
-
import { startWorkCommand, type StartWorkMode } from "../pware.oc.runtime/pware.oc.runtime.mywork.js"
|
|
9
|
-
|
|
10
|
-
export function selectSession(api: TuiPluginApi, sessionId: string | null | undefined): void {
|
|
11
|
-
if (!sessionId) return
|
|
12
|
-
const tui = (api as TuiPluginApi & {
|
|
13
|
-
client?: {
|
|
14
|
-
tui?: {
|
|
15
|
-
selectSession?: (arg: unknown) => Promise<unknown> | unknown
|
|
16
|
-
publish?: (arg: unknown) => Promise<unknown> | unknown
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}).client?.tui
|
|
20
|
-
if (!tui) return
|
|
21
|
-
const go = async () => {
|
|
22
|
-
try {
|
|
23
|
-
if (typeof tui.selectSession === "function") {
|
|
24
|
-
await tui.selectSession({ sessionID: sessionId })
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
} catch {
|
|
28
|
-
try {
|
|
29
|
-
await tui.selectSession?.(sessionId)
|
|
30
|
-
return
|
|
31
|
-
} catch {
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
await tui.publish?.({
|
|
36
|
-
type: "tui.session.select",
|
|
37
|
-
properties: { sessionID: sessionId },
|
|
38
|
-
})
|
|
39
|
-
} catch {
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
void profileAsync("rpc.selectSession", go)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function openSessionSwitcher(api: TuiPluginApi): void {
|
|
46
|
-
try {
|
|
47
|
-
const dispatch = (api.keymap as TuiKeymap & { dispatchCommand?: (name: string) => void })
|
|
48
|
-
.dispatchCommand
|
|
49
|
-
if (typeof dispatch === "function") {
|
|
50
|
-
dispatch("session.list")
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
} catch {
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
api.command?.show()
|
|
57
|
-
} catch {
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function openNewSessionPrompt(api: TuiPluginApi): void {
|
|
62
|
-
try {
|
|
63
|
-
api.route.navigate("home")
|
|
64
|
-
} catch {
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function runStartWork(
|
|
69
|
-
api: TuiPluginApi,
|
|
70
|
-
sessionId: string,
|
|
71
|
-
mode: StartWorkMode,
|
|
72
|
-
planName: string,
|
|
73
|
-
): void {
|
|
74
|
-
const client = api.client
|
|
75
|
-
const text = startWorkCommand(mode, planName)
|
|
76
|
-
const flag = mode === START_WORK_MAKE_PR ? "--make-pr" : mode === START_WORK_SHIP ? "--ship" : ""
|
|
77
|
-
const args = [planName, flag].map((s) => s.trim()).filter(Boolean).join(" ") || ""
|
|
78
|
-
const go = async () => {
|
|
79
|
-
try {
|
|
80
|
-
const res = await client.session.command({
|
|
81
|
-
sessionID: sessionId,
|
|
82
|
-
command: "start-work",
|
|
83
|
-
arguments: args,
|
|
84
|
-
})
|
|
85
|
-
if (res && !res.error) return
|
|
86
|
-
} catch {
|
|
87
|
-
}
|
|
88
|
-
try {
|
|
89
|
-
await client.session.promptAsync({
|
|
90
|
-
sessionID: sessionId,
|
|
91
|
-
parts: [{ type: PART_TYPE_TEXT, text }],
|
|
92
|
-
})
|
|
93
|
-
} catch {
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
void profileAsync("rpc.startWork", go)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function approvePlan(api: TuiPluginApi, sessionId: string): void {
|
|
100
|
-
const client = api.client
|
|
101
|
-
const go = async () => {
|
|
102
|
-
try {
|
|
103
|
-
await client.session.promptAsync({
|
|
104
|
-
sessionID: sessionId,
|
|
105
|
-
parts: [{ type: PART_TYPE_TEXT, text: "ok" }],
|
|
106
|
-
})
|
|
107
|
-
} catch {
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
void profileAsync("rpc.approve", go)
|
|
111
|
-
}
|
|
1
|
+
import type { TuiKeymap, TuiPluginApi } from "@opencode-ai/plugin/tui"
|
|
2
|
+
import { profileAsync } from "../pware.oc.core/pware.oc.core.debug.js"
|
|
3
|
+
import { PART_TYPE_TEXT } from "../pware.oc.core/constants/pware.oc.core.constants.partType.js"
|
|
4
|
+
import {
|
|
5
|
+
START_WORK_MAKE_PR,
|
|
6
|
+
START_WORK_SHIP,
|
|
7
|
+
} from "../pware.oc.omo/constants/pware.oc.omo.constants.startWork.js"
|
|
8
|
+
import { startWorkCommand, type StartWorkMode } from "../pware.oc.runtime/pware.oc.runtime.mywork.js"
|
|
9
|
+
|
|
10
|
+
export function selectSession(api: TuiPluginApi, sessionId: string | null | undefined): void {
|
|
11
|
+
if (!sessionId) return
|
|
12
|
+
const tui = (api as TuiPluginApi & {
|
|
13
|
+
client?: {
|
|
14
|
+
tui?: {
|
|
15
|
+
selectSession?: (arg: unknown) => Promise<unknown> | unknown
|
|
16
|
+
publish?: (arg: unknown) => Promise<unknown> | unknown
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}).client?.tui
|
|
20
|
+
if (!tui) return
|
|
21
|
+
const go = async () => {
|
|
22
|
+
try {
|
|
23
|
+
if (typeof tui.selectSession === "function") {
|
|
24
|
+
await tui.selectSession({ sessionID: sessionId })
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
} catch {
|
|
28
|
+
try {
|
|
29
|
+
await tui.selectSession?.(sessionId)
|
|
30
|
+
return
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
await tui.publish?.({
|
|
36
|
+
type: "tui.session.select",
|
|
37
|
+
properties: { sessionID: sessionId },
|
|
38
|
+
})
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
void profileAsync("rpc.selectSession", go)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function openSessionSwitcher(api: TuiPluginApi): void {
|
|
46
|
+
try {
|
|
47
|
+
const dispatch = (api.keymap as TuiKeymap & { dispatchCommand?: (name: string) => void })
|
|
48
|
+
.dispatchCommand
|
|
49
|
+
if (typeof dispatch === "function") {
|
|
50
|
+
dispatch("session.list")
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
api.command?.show()
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function openNewSessionPrompt(api: TuiPluginApi): void {
|
|
62
|
+
try {
|
|
63
|
+
api.route.navigate("home")
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function runStartWork(
|
|
69
|
+
api: TuiPluginApi,
|
|
70
|
+
sessionId: string,
|
|
71
|
+
mode: StartWorkMode,
|
|
72
|
+
planName: string,
|
|
73
|
+
): void {
|
|
74
|
+
const client = api.client
|
|
75
|
+
const text = startWorkCommand(mode, planName)
|
|
76
|
+
const flag = mode === START_WORK_MAKE_PR ? "--make-pr" : mode === START_WORK_SHIP ? "--ship" : ""
|
|
77
|
+
const args = [planName, flag].map((s) => s.trim()).filter(Boolean).join(" ") || ""
|
|
78
|
+
const go = async () => {
|
|
79
|
+
try {
|
|
80
|
+
const res = await client.session.command({
|
|
81
|
+
sessionID: sessionId,
|
|
82
|
+
command: "start-work",
|
|
83
|
+
arguments: args,
|
|
84
|
+
})
|
|
85
|
+
if (res && !res.error) return
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await client.session.promptAsync({
|
|
90
|
+
sessionID: sessionId,
|
|
91
|
+
parts: [{ type: PART_TYPE_TEXT, text }],
|
|
92
|
+
})
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
void profileAsync("rpc.startWork", go)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function approvePlan(api: TuiPluginApi, sessionId: string): void {
|
|
100
|
+
const client = api.client
|
|
101
|
+
const go = async () => {
|
|
102
|
+
try {
|
|
103
|
+
await client.session.promptAsync({
|
|
104
|
+
sessionID: sessionId,
|
|
105
|
+
parts: [{ type: PART_TYPE_TEXT, text: "ok" }],
|
|
106
|
+
})
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
void profileAsync("rpc.approve", go)
|
|
111
|
+
}
|