@litfamily/litopencode 1.0.32 → 1.0.33
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/CHANGELOG.md +14 -0
- package/README-Ko-KR.md +6 -6
- package/README.md +6 -6
- package/TRADEMARK.md +12 -0
- package/dist/activation-primary-prompts.js +5 -1
- package/dist/agents/defaults.js +1 -1
- package/dist/commands.js +10 -4
- package/dist/durable-plan.d.ts +5 -1
- package/dist/durable-plan.js +14 -2
- package/dist/hooks.js +3 -0
- package/dist/plan-scope-roots.d.ts +23 -0
- package/dist/plan-scope-roots.js +116 -0
- package/dist/restart-notice.d.ts +7 -0
- package/dist/restart-notice.js +40 -0
- package/dist/server.js +4 -0
- package/dist/session-liveness.d.ts +20 -0
- package/dist/session-liveness.js +99 -0
- package/dist/start-work-typed.js +12 -1
- package/dist/state.d.ts +1 -0
- package/dist/state.js +1 -0
- package/dist/tui/mission-band.d.ts +2 -0
- package/dist/tui/mission-band.js +2 -0
- package/dist/tui/mission-source.d.ts +3 -2
- package/dist/tui/mission-source.js +40 -7
- package/dist/tui/mission-threads.d.ts +10 -2
- package/dist/tui/mission-threads.js +15 -6
- package/dist/tui.js +28 -1
- package/dist/v2/events.js +3 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/reference-Ko-KR.md +20 -3
- package/docs/reference.md +22 -3
- package/package.json +1 -1
- package/skills/lit-adhd/SKILL.md +8 -7
- package/skills/lit-adhd/references/brief-format.md +5 -2
- package/skills/lit-adhd/references/card-examples.md +23 -2
- package/skills/lit-adhd/references/status-taxonomy.md +6 -1
- package/skills/lit-adhd/scripts/rewind.mjs +122 -24
- package/skills/lit-plan/SKILL.md +6 -0
- package/skills/managed-skill-manifest.json +4 -4
- package/tools/check-pack-payload.mjs +1 -0
- package/tools/version-manifests.json +2 -2
|
@@ -30,10 +30,12 @@ export declare function readNotifyOptions(options: unknown): NotifyOptions;
|
|
|
30
30
|
* dim recent names, and `+N` for the ones that do not fit. The label goes before any chip does.
|
|
31
31
|
*/
|
|
32
32
|
export declare function skillRow(chips: readonly SkillChip[], shimmer: ChipShimmer | undefined, palette: MissionPalette, width: number, rainbow?: Rainbow): Line;
|
|
33
|
+
/** `restartTo`: an installed LitOpenCode version newer than the code this OpenCode start loaded. */
|
|
33
34
|
export type CardFigures = {
|
|
34
35
|
readonly contextPercent: number | null;
|
|
35
36
|
readonly branch?: string;
|
|
36
37
|
readonly inLane: boolean;
|
|
38
|
+
readonly restartTo?: string;
|
|
37
39
|
};
|
|
38
40
|
export type CardInputs = {
|
|
39
41
|
readonly view: MissionView;
|
package/dist/tui/mission-band.js
CHANGED
|
@@ -153,6 +153,8 @@ function topLine(view, frame, palette, width, border, rest, mark) {
|
|
|
153
153
|
/** The figures in the bottom border, most important first; the last ones go first when room runs out. */
|
|
154
154
|
function figureParts(view, figures, palette) {
|
|
155
155
|
const parts = [];
|
|
156
|
+
if (figures.restartTo !== undefined)
|
|
157
|
+
parts.push({ text: `restart to ${truncateCells(figures.restartTo, 16)}`, fg: palette.warning });
|
|
156
158
|
if (figures.contextPercent !== null) {
|
|
157
159
|
const percent = Math.round(figures.contextPercent);
|
|
158
160
|
parts.push({ text: `ctx ${percent}%`, fg: percent >= contextWarnPercent ? palette.warning : palette.muted });
|
|
@@ -123,8 +123,9 @@ export declare function readCardInput(state: MissionStateSource, sessionID: stri
|
|
|
123
123
|
export declare const earlierWorkWindowMs: number;
|
|
124
124
|
/**
|
|
125
125
|
* The lanes beside this session's own mission: its workflow stack frames, its running `task` calls and
|
|
126
|
-
* the stacks of other sessions in the workspace that moved in the last fifteen minutes
|
|
127
|
-
*
|
|
126
|
+
* the stacks of other sessions in the workspace that moved in the last fifteen minutes, read with their
|
|
127
|
+
* liveness records. Another session's completed start-work run shows as done. Only counts that are real
|
|
128
|
+
* totals are carried; the input of a tool call is read for its description alone.
|
|
128
129
|
*/
|
|
129
130
|
export declare function readThreadSources(state: MissionStateSource, sessionID: string, root: string | undefined, now: number): ThreadSource[];
|
|
130
131
|
/**
|
|
@@ -8,6 +8,7 @@ import { isLaneResult, isReviewLane } from "./mission-looks.js";
|
|
|
8
8
|
import { readSkillUse, skillChips } from "./mission-skills.js";
|
|
9
9
|
import { isRealCount } from "./mission-threads.js";
|
|
10
10
|
import { readSiblingStacksSync, readStackSync } from "../workflow-stack.js";
|
|
11
|
+
import { readLivenessSync } from "../session-liveness.js";
|
|
11
12
|
const ledgerByteLimit = 1024 * 1024;
|
|
12
13
|
/** The same root the server plugin uses: the worktree unless it is the filesystem root, else the directory. */
|
|
13
14
|
export function missionProjectRoot(paths) {
|
|
@@ -383,28 +384,60 @@ function stackSources(stack) {
|
|
|
383
384
|
touchedAt: frame.at
|
|
384
385
|
}));
|
|
385
386
|
}
|
|
386
|
-
|
|
387
|
+
/** `<skill> · <herdr pane>` when the session runs in a herdr pane, else the last four characters of its id. */
|
|
388
|
+
function siblingName(skill, sessionID, liveness) {
|
|
389
|
+
return `${skill} · ${liveness?.herdrPane ?? sessionID.slice(-4)}`;
|
|
390
|
+
}
|
|
391
|
+
/** A sibling's own liveness record settles its status: ended reads done, idle reads idle (a held frame stays paused). */
|
|
392
|
+
function siblingSource(stack, liveness, finishedAt) {
|
|
387
393
|
const top = stack.frames.find((frame) => frame.status === "active") ?? stack.frames[stack.frames.length - 1];
|
|
394
|
+
const endedAt = liveness?.state === "ended" ? Date.parse(liveness.at) : finishedAt;
|
|
395
|
+
const status = endedAt !== undefined ? "done" : top.status !== "active" ? "paused" : liveness?.state === "idle" ? "idle" : "working";
|
|
388
396
|
return {
|
|
389
397
|
kind: "session",
|
|
390
|
-
name:
|
|
391
|
-
status
|
|
398
|
+
name: siblingName(top.skill, stack.sessionID, liveness),
|
|
399
|
+
status,
|
|
392
400
|
...countsOf(top.done, top.total),
|
|
393
401
|
...(top.phase === undefined ? {} : { phase: top.phase }),
|
|
394
|
-
touchedAt: stack.updatedAt
|
|
402
|
+
touchedAt: Math.max(stack.updatedAt, liveness === undefined ? 0 : Date.parse(liveness.at)),
|
|
403
|
+
...(endedAt === undefined ? {} : { doneAt: endedAt }),
|
|
404
|
+
...(liveness === undefined && finishedAt === undefined ? {} : { settled: true })
|
|
395
405
|
};
|
|
396
406
|
}
|
|
407
|
+
/** Another session's start-work run that completed, with when, read from the bounded work record. */
|
|
408
|
+
function finishedWork(root, sessionID, now) {
|
|
409
|
+
const file = path.join(litLoopDir(root), "work-schema-3.json");
|
|
410
|
+
const stat = lstatOrUndefined(file);
|
|
411
|
+
if (stat === undefined || !stat.isFile() || stat.size > ledgerByteLimit)
|
|
412
|
+
return undefined;
|
|
413
|
+
try {
|
|
414
|
+
const raw = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
415
|
+
if (!isRecord(raw) || raw.schemaVersion !== 3 || raw.status !== "completed" || typeof raw.sessionID !== "string" || raw.sessionID === sessionID)
|
|
416
|
+
return undefined;
|
|
417
|
+
const at = typeof raw.updatedAt === "string" ? Date.parse(raw.updatedAt) : Number.NaN;
|
|
418
|
+
return Number.isFinite(at) && at <= now && now - at <= siblingFreshMs ? { sessionID: raw.sessionID, at } : undefined;
|
|
419
|
+
}
|
|
420
|
+
catch {
|
|
421
|
+
return undefined;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
397
424
|
/**
|
|
398
425
|
* The lanes beside this session's own mission: its workflow stack frames, its running `task` calls and
|
|
399
|
-
* the stacks of other sessions in the workspace that moved in the last fifteen minutes
|
|
400
|
-
*
|
|
426
|
+
* the stacks of other sessions in the workspace that moved in the last fifteen minutes, read with their
|
|
427
|
+
* liveness records. Another session's completed start-work run shows as done. Only counts that are real
|
|
428
|
+
* totals are carried; the input of a tool call is read for its description alone.
|
|
401
429
|
*/
|
|
402
430
|
export function readThreadSources(state, sessionID, root, now) {
|
|
403
431
|
const tasks = taskSources(state, sessionID, now);
|
|
404
432
|
if (root === undefined)
|
|
405
433
|
return tasks.sources;
|
|
406
434
|
const siblings = readSiblingStacksSync(root, sessionID, { now, freshMs: siblingFreshMs, max: siblingMax }).filter((stack) => !tasks.children.has(stack.sessionID));
|
|
407
|
-
|
|
435
|
+
const finished = finishedWork(root, sessionID, now);
|
|
436
|
+
const others = siblings.map((stack) => siblingSource(stack, readLivenessSync(root, stack.sessionID), stack.sessionID === finished?.sessionID ? finished.at : undefined));
|
|
437
|
+
if (finished !== undefined && !siblings.some((stack) => stack.sessionID === finished.sessionID) && !tasks.children.has(finished.sessionID)) {
|
|
438
|
+
others.push({ kind: "session", name: siblingName("start-work", finished.sessionID, readLivenessSync(root, finished.sessionID)), status: "done", touchedAt: finished.at, doneAt: finished.at, settled: true });
|
|
439
|
+
}
|
|
440
|
+
return [...stackSources(readStackSync(root, sessionID)), ...tasks.sources, ...others];
|
|
408
441
|
}
|
|
409
442
|
/**
|
|
410
443
|
* Whether earlier work exists for the band's idle hint and the one suggestion: another session here
|
|
@@ -13,6 +13,10 @@ export type ThreadSource = {
|
|
|
13
13
|
readonly startedAt?: number;
|
|
14
14
|
/** When the lane last moved; an old one reads as idle. */
|
|
15
15
|
readonly touchedAt?: number;
|
|
16
|
+
/** When a done lane finished; it leaves the card a minute later. */
|
|
17
|
+
readonly doneAt?: number;
|
|
18
|
+
/** The status came from the session's liveness record, so the five-minute idle guess does not apply. */
|
|
19
|
+
readonly settled?: boolean;
|
|
16
20
|
};
|
|
17
21
|
export type ThreadRow = {
|
|
18
22
|
readonly key: string;
|
|
@@ -25,10 +29,14 @@ export type ThreadRow = {
|
|
|
25
29
|
export declare const threadRowCap = 4;
|
|
26
30
|
/** A lane untouched for this long is shown as idle rather than working. */
|
|
27
31
|
export declare const idleAfterMs: number;
|
|
32
|
+
/** A finished lane stays this long, so a glance still catches it, then leaves. */
|
|
33
|
+
export declare const doneLingerMs = 60000;
|
|
28
34
|
export declare function isRealCount(done: unknown, total: unknown): done is number;
|
|
29
35
|
/**
|
|
30
|
-
* The rows for the sources, or undefined when
|
|
31
|
-
*
|
|
36
|
+
* The rows for the sources, or undefined when only one lane of the session's own work exists, which the
|
|
37
|
+
* four-row card already shows; one other session is still a row. A source untouched for five minutes reads
|
|
38
|
+
* as idle unless a liveness record settled it, a done lane leaves a minute after it finished, and other
|
|
39
|
+
* sessions follow the session's own lanes, working first, then paused, finished and idle.
|
|
32
40
|
*/
|
|
33
41
|
export declare function threadsOf(sources: readonly ThreadSource[], now: number): ThreadRow[] | undefined;
|
|
34
42
|
/** How many card rows the threads take: the fork line, the shown lanes and the `+N more` line. */
|
|
@@ -9,6 +9,9 @@ import { cellWidth, lineWidth, truncateCells } from "./mission-text.js";
|
|
|
9
9
|
export const threadRowCap = 4;
|
|
10
10
|
/** A lane untouched for this long is shown as idle rather than working. */
|
|
11
11
|
export const idleAfterMs = 5 * 60_000;
|
|
12
|
+
/** A finished lane stays this long, so a glance still catches it, then leaves. */
|
|
13
|
+
export const doneLingerMs = 60_000;
|
|
14
|
+
const sessionRank = { working: 0, paused: 1, done: 2, failed: 2, idle: 3 };
|
|
12
15
|
const pulseFrames = ["▓▒░░░", "░▓▒░░", "░░▓▒░", "░░░▓▒", "░░▒▓░", "░▒▓░░"];
|
|
13
16
|
const steadyPulse = "░▒▓▒░";
|
|
14
17
|
const pulseMs = 250;
|
|
@@ -34,14 +37,20 @@ function factsFor(source, status, now) {
|
|
|
34
37
|
return parts.join(" · ");
|
|
35
38
|
}
|
|
36
39
|
/**
|
|
37
|
-
* The rows for the sources, or undefined when
|
|
38
|
-
*
|
|
40
|
+
* The rows for the sources, or undefined when only one lane of the session's own work exists, which the
|
|
41
|
+
* four-row card already shows; one other session is still a row. A source untouched for five minutes reads
|
|
42
|
+
* as idle unless a liveness record settled it, a done lane leaves a minute after it finished, and other
|
|
43
|
+
* sessions follow the session's own lanes, working first, then paused, finished and idle.
|
|
39
44
|
*/
|
|
40
45
|
export function threadsOf(sources, now) {
|
|
41
|
-
|
|
46
|
+
const live = sources.filter((source) => !(source.status === "done" && source.doneAt !== undefined && now - source.doneAt > doneLingerMs));
|
|
47
|
+
const statusOf = (source) => source.status === "working" && source.settled !== true && source.touchedAt !== undefined && now - source.touchedAt > idleAfterMs ? "idle" : source.status;
|
|
48
|
+
const own = live.filter((source) => source.kind !== "session");
|
|
49
|
+
const others = live.filter((source) => source.kind === "session").sort((left, right) => sessionRank[statusOf(left)] - sessionRank[statusOf(right)]);
|
|
50
|
+
if (others.length === 0 && own.length < 2)
|
|
42
51
|
return undefined;
|
|
43
|
-
return
|
|
44
|
-
const status = source
|
|
52
|
+
return [...own, ...others].map((source, index) => {
|
|
53
|
+
const status = statusOf(source);
|
|
45
54
|
return {
|
|
46
55
|
key: `${source.kind}:${index}:${source.name}`,
|
|
47
56
|
name: source.name,
|
|
@@ -110,7 +119,7 @@ export function threadLines(rows, palette, width, options) {
|
|
|
110
119
|
return [];
|
|
111
120
|
const shown = rows.slice(0, threadRowCap);
|
|
112
121
|
const more = rows.length - shown.length;
|
|
113
|
-
const fork = [{ text: "┬ ", fg: palette.borderSubtle }, { text: `${rows.length} lanes in parallel`, fg: palette.muted }];
|
|
122
|
+
const fork = [{ text: "┬ ", fg: palette.borderSubtle }, { text: `${rows.length} ${rows.length === 1 ? "lane" : "lanes"} in parallel`, fg: palette.muted }];
|
|
114
123
|
const lines = [fork];
|
|
115
124
|
shown.forEach((row, index) => lines.push(rowLine(row, index, index === shown.length - 1 && more === 0, palette, width, options)));
|
|
116
125
|
if (more > 0)
|
package/dist/tui.js
CHANGED
|
@@ -10,12 +10,15 @@ import { bandCard, readBandOptions, readNotifyOptions, statusCard } from "./tui/
|
|
|
10
10
|
import { activeSkillLook, turnGlow, waitingOnYou } from "./tui/mission-looks.js";
|
|
11
11
|
import { rainbowActive, rainbowAllowed, rainbowAt, rainbowShows, rainbowTickMs } from "./tui/mission-rainbow.js";
|
|
12
12
|
import { threadLineCount, threadsOf } from "./tui/mission-threads.js";
|
|
13
|
+
import { readPackageMetadata } from "./cli/json.js";
|
|
14
|
+
import { readInstalledVersions, restartVersion } from "./restart-notice.js";
|
|
13
15
|
export const litOpenCodeTuiPluginId = "litopencode";
|
|
14
16
|
const homeLineWidth = 69;
|
|
15
17
|
const refreshDelayMs = 80;
|
|
16
18
|
const ledgerPollMs = 2000;
|
|
17
19
|
const toastMs = 4000;
|
|
18
20
|
const liveTickMs = 1000;
|
|
21
|
+
const restartCheckMs = 10 * 60_000;
|
|
19
22
|
const trackedSessionLimit = 4;
|
|
20
23
|
const refreshEvents = [
|
|
21
24
|
"message.updated",
|
|
@@ -57,6 +60,21 @@ const tui = async (api, options) => {
|
|
|
57
60
|
const suggested = new Set();
|
|
58
61
|
const suggestedDays = new Map();
|
|
59
62
|
const colorAllowed = rainbowAllowed(motionEnabled, process.env.NO_COLOR);
|
|
63
|
+
// The version this start loaded; an install newer than it shows `restart to <v>` and one toast.
|
|
64
|
+
const loaded = await readPackageMetadata().catch(() => undefined);
|
|
65
|
+
const [restartTo, setRestartTo] = createSignal(undefined);
|
|
66
|
+
let restartTimer;
|
|
67
|
+
async function checkRestart() {
|
|
68
|
+
if (loaded === undefined)
|
|
69
|
+
return;
|
|
70
|
+
const target = restartVersion(loaded.version, await readInstalledVersions(loaded.packageRoot).catch(() => []));
|
|
71
|
+
if (target === undefined || target === restartTo())
|
|
72
|
+
return;
|
|
73
|
+
if (restartTo() === undefined) {
|
|
74
|
+
api.ui.toast({ variant: "info", title: "🔥 LIT", message: `LitOpenCode ${target} is installed. Restart OpenCode to load it.`, duration: toastMs });
|
|
75
|
+
}
|
|
76
|
+
setRestartTo(target);
|
|
77
|
+
}
|
|
60
78
|
const state = () => api.state;
|
|
61
79
|
const palette = () => paletteFromTheme(api.theme.current, api.theme.mode());
|
|
62
80
|
// OpenCode keeps the sidebar choice in its KV store under "sidebar" ("auto" or "hide"); a child
|
|
@@ -269,7 +287,11 @@ const tui = async (api, options) => {
|
|
|
269
287
|
for (const type of refreshEvents) {
|
|
270
288
|
api.event.on(type, scheduleRefresh);
|
|
271
289
|
}
|
|
290
|
+
void checkRestart();
|
|
291
|
+
restartTimer = setInterval(() => void checkRestart(), restartCheckMs);
|
|
272
292
|
api.lifecycle.onDispose(() => {
|
|
293
|
+
if (restartTimer !== undefined)
|
|
294
|
+
clearInterval(restartTimer);
|
|
273
295
|
if (frameTimer !== undefined)
|
|
274
296
|
clearInterval(frameTimer);
|
|
275
297
|
if (refreshTimer !== undefined)
|
|
@@ -401,7 +423,12 @@ const tui = async (api, options) => {
|
|
|
401
423
|
...(rainbowOn(snapshot, snapshot.now) ? { rainbow: rainbowAt(snapshot.now) } : {}),
|
|
402
424
|
...(snapshot.card.lanes !== undefined && activeSkillLook(snapshot.view, snapshot.card.chips, snapshot.card.busy) === "review" ? { lanes: snapshot.card.lanes } : {}),
|
|
403
425
|
...(shimmer === undefined ? {} : { shimmer }),
|
|
404
|
-
figures: {
|
|
426
|
+
figures: {
|
|
427
|
+
contextPercent: snapshot.card.contextPercent,
|
|
428
|
+
...(snapshot.card.branch === undefined ? {} : { branch: snapshot.card.branch }),
|
|
429
|
+
inLane: snapshot.inLane,
|
|
430
|
+
...(restartTo() === undefined ? {} : { restartTo: restartTo() })
|
|
431
|
+
},
|
|
405
432
|
...(last === undefined ? {} : { last })
|
|
406
433
|
}, colors, width);
|
|
407
434
|
const rows = lines.map(lineElement);
|
package/dist/v2/events.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createAutoHandoff } from "../auto-handoff-hooks.js";
|
|
2
2
|
import { LifecycleConflictError, LifecycleSafetyError, createBoundedAuthorityLifecycle, parseFencedProgress } from "../bounded-authority.js";
|
|
3
|
+
import { markLiveness } from "../session-liveness.js";
|
|
3
4
|
function isRecord(value) {
|
|
4
5
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
6
|
}
|
|
@@ -100,6 +101,7 @@ export function createV2Events(options) {
|
|
|
100
101
|
if (step.sessionID === sessionID)
|
|
101
102
|
steps.delete(messageID);
|
|
102
103
|
options.onSessionDeleted(sessionID);
|
|
104
|
+
await markLiveness(options.projectRoot, sessionID, "ended");
|
|
103
105
|
await toHandoff("session.deleted", { info: { id: sessionID } });
|
|
104
106
|
return;
|
|
105
107
|
case "session.step.started": {
|
|
@@ -138,6 +140,7 @@ export function createV2Events(options) {
|
|
|
138
140
|
await toHandoff("session.status", { sessionID, status: data.status });
|
|
139
141
|
return;
|
|
140
142
|
case "session.idle":
|
|
143
|
+
await markLiveness(options.projectRoot, sessionID, "idle");
|
|
141
144
|
await toHandoff("session.idle", { sessionID });
|
|
142
145
|
return;
|
|
143
146
|
case "session.compaction.ended":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.33"><title>release: 1.0.33</title><g shape-rendering="crispEdges"><rect width="49" height="20" fill="#080d14"/><rect x="49" width="97" height="20" fill="#ff6337"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="255" y="140" textLength="390" transform="scale(.1)">release</text><text x="965" y="140" textLength="870" transform="scale(.1)" fill="#080D14">1.0.33</text></g></svg>
|
package/docs/reference-Ko-KR.md
CHANGED
|
@@ -141,7 +141,7 @@ litopencode install
|
|
|
141
141
|
| `/litgoal` | 끝나는 지점을 정하고 지킴: 확인 가능한 기준이 붙은 목표 하나를 디스크에 남김. `lit-loop`와 `/start-work`가 그 목표를 향해 일함 |
|
|
142
142
|
| `/lit-brainstorm` | 열린 질문을 여러 선택지로 펼친 뒤 짧은 목록으로 좁히고, 고른 것을 `deep-interview`나 `lit-plan`에 넘김. 채팅에서는 `lit brainstorm`, `lit brainstorming`, `lit ideation`, `lit ideate`, `lit idea`, `lit ideas`. 직접 만들지는 않음 |
|
|
143
143
|
| `/lit-hijack` | 다른 사람이 공개한 작업의 기법 원리를 내 스킬이나 시스템에 옮김: 출처 기록, 라이선스 확인, 격차 분석, 원문 없는 명세, 분리된 구현, 동작 비교, 보고서. 각 단계의 완료는 동봉된 `hijack.mjs`가 판정함. 채팅에서는 `lit hijack`, `lit hijacking`, `lit 하이재킹`, `lit 하이잭` |
|
|
144
|
-
| `/lit-adhd`, `/lit-rewind` | 하던 일을 이어서 시작: 이전 세션의 상태, 실제 진행 또는 아는 사실, 로드맵, 추천 한 단계를 읽기 전용으로 보여 줌. 동봉된 `rewind.mjs`가 수집함. 채팅에서는 `lit adhd`, `lit rewind`, 이어서 `go`가 30분간 준비된 단계를 따라감. `lit approve`와 `lit deny`는 대기 중인 경계에 답하고, `lit deny`는 실행을 끝냄. |
|
|
144
|
+
| `/lit-adhd`, `/lit-rewind` | 하던 일을 이어서 시작: 세 줄(지금까지, 지금, 다음)로 시작해 이전 세션의 상태, 실제 진행 또는 아는 사실, 로드맵, 추천 한 단계를 읽기 전용으로 보여 줌. 끝난 계획과 완료된 start-work 실행은 끝난 일로 세고, liveness 기록으로 쉬는 세션을 가리며, 7일 넘은 계획은 빼고, 이 워크트리 `HANDOFF.md`의 `Next` 항목을 마지막 대안으로 씀. 동봉된 `rewind.mjs`가 수집함. 채팅에서는 `lit adhd`, `lit rewind`, 이어서 `go`가 30분간 준비된 단계를 따라감. `lit approve`와 `lit deny`는 대기 중인 경계에 답하고, `lit deny`는 실행을 끝냄. |
|
|
145
145
|
| `/litresearch` 또는 `/lit-research` | 순차 대체 경로를 포함한 근거 기반 연구 |
|
|
146
146
|
| `/lit-handoff` | 이어서 작업할 수 있는 핸드오프 작성 |
|
|
147
147
|
| `/lit-recap` | 로컬 ledger와 세션 맥락으로 짧은 리캡 작성 |
|
|
@@ -182,6 +182,15 @@ litopencode complete-goals
|
|
|
182
182
|
bounded-authority 경로입니다. `resume`은 신뢰된 사용자 경로와 work, session, revision,
|
|
183
183
|
grant가 모두 맞을 때만 허용됩니다. 복사하거나 인용한 텍스트는 명령으로 처리하지 않습니다.
|
|
184
184
|
|
|
185
|
+
`/start-work save-plan <JSON>`으로 승인된 계획을 저장하면, 저장 안내와 함께 한 단어 시작이 준비됩니다.
|
|
186
|
+
같은 세션에서 30분 안에 `go`를 입력하면 그 계획으로 타이핑 start-work 실행이 시작됩니다. 다른 세션의
|
|
187
|
+
`go`나 30분이 지난 `go`는 평범한 단어입니다. 체크리스트가 프로젝트 밖의 절대 경로를 가리키는 계획에는
|
|
188
|
+
`Scope roots: <폴더> (<동작>)` 줄이 있어야 합니다(동작은 `read`, `write`, `execute` 중에서). 이 줄로 덮이지
|
|
189
|
+
않은 바깥 폴더가 있으면 save-plan은 저장하지 않고 넣을 줄을 그대로 알려 줍니다. 파일 시스템 루트, 최상위
|
|
190
|
+
폴더, 홈 폴더 자체로만 덮을 수 있을 때는 더 좁은 기존 폴더를 적어 달라고 합니다. 코드 펜스 안의 경로와
|
|
191
|
+
인라인 코드로 인용한 명령은 세지 않습니다. 타이핑 start-work가 시작되면 올바른 `Scope roots:` 줄 하나하나가
|
|
192
|
+
실행의 권한이 되므로, 승인된 계획이 이미 적은 폴더 때문에 멈추지 않습니다. 이때 그 폴더는 있어야 합니다.
|
|
193
|
+
|
|
185
194
|
### UI 및 Visual QA 관리 헬퍼
|
|
186
195
|
|
|
187
196
|
`frontend-ui-ux`와 `visual-qa` 경로는 Node ESM 헬퍼와 제한된 읽기 전용
|
|
@@ -413,7 +422,12 @@ OpenCode 1.18은 `tui.json`이나 `tui.jsonc`의 `plugin` 배열에 적힌 TUI
|
|
|
413
422
|
상태 단어(`working`, `paused`, `done`, `failed`, `idle`), 그리고 실제 총량이 있을 때만 게이지
|
|
414
423
|
(`[▉▉░░░░░░] 3/10`)가 붙습니다. 총량을 모르면 아는 것(단계, 걸린 시간)을 글로 쓰고 일하는 중이면 작은
|
|
415
424
|
펄스를 보여 줄 뿐 물음표는 쓰지 않습니다. 작업이 살아 있는 동안 카드는 가장 높았던 높이를 유지하고,
|
|
416
|
-
모두 가라앉으면 네 줄로 돌아옵니다.
|
|
425
|
+
모두 가라앉으면 네 줄로 돌아옵니다. 다른 세션 줄은 이 세션의 작업 줄 뒤에 일하는 중, 멈춤, 끝남,
|
|
426
|
+
쉬는 중 순서로 놓이고, 다른 세션이 하나뿐이어도 줄이 생깁니다. 세션마다 훅이
|
|
427
|
+
`.litopencode/liveness/<session>.json`에 작은 기록을 남깁니다(도구 실행 뒤 `alive`, `session.idle`에서
|
|
428
|
+
`idle`, 세션 삭제 시 `ended`). 기록이 있으면 5분 추정 대신 그 기록으로 쉬는 중과 끝남을 정하고, herdr
|
|
429
|
+
pane에서 도는 세션은 `<skill> · <pane>`으로 부르며, 끝난 세션이나 다른 세션이 완료한 start-work 실행은
|
|
430
|
+
1분 동안 `done`으로 보였다가 사라집니다.
|
|
417
431
|
- `lit-adhd`(별칭 `lit-rewind`)가 도는 동안 테두리, LIT 글자, 게이지가 같은 밝기의 색상환을 따라 돕니다.
|
|
418
432
|
1초에 네 번 색이 조금씩 바뀌고 깜박이지 않습니다. `motion: false`와 `NO_COLOR`에서는 꺼집니다. 이전
|
|
419
433
|
작업이 있는 작업 공간의 쉬는 세션은 `lit adhd to pick up where you left off`를 보여 주고, 그곳에서 처음 연
|
|
@@ -433,7 +447,10 @@ OpenCode 1.18은 `tui.json`이나 `tui.jsonc`의 `plugin` 배열에 적힌 TUI
|
|
|
433
447
|
하위(subagent) 세션에서는 부모 세션의 카드를 `· in lane`과 함께 보여 주고, 홈 화면에는 띠가
|
|
434
448
|
없습니다. 폭이 좁으면 줄마다 덜 중요한 것부터 덜어 냅니다. 단계 줄은 지금 하는 일과 다음 할 일
|
|
435
449
|
글자, 막대 길이, 막대, 기준 개수를 차례로 빼고, 마지막에는 지금 단계만 남깁니다. 아래 테두리는 브랜치, 시간, context 사용량 순서로 뺍니다. 줄을
|
|
436
|
-
넘기지는 않습니다. 완료 순간도 여기서 함께 보입니다.
|
|
450
|
+
넘기지는 않습니다. 완료 순간도 여기서 함께 보입니다. 이번 OpenCode 시작 때 읽어 들인 코드보다 새
|
|
451
|
+
LitOpenCode가 설치되어 있으면(자동 업데이트 영수증이나 디스크의 패키지로 확인) 아래 테두리 맨 앞에
|
|
452
|
+
경고 색으로 `restart to <버전>`이 붙고, 폭이 좁아져도 가장 늦게 빠집니다. 같은 내용의 토스트도 한 번
|
|
453
|
+
뜹니다. 스스로 다시 시작하지는 않습니다.
|
|
437
454
|
- 홈 화면 입력창 아래, OpenCode 팁 다음 줄: `🔥 lit ready · last: <목표> ✓ n/m`. 프로젝트 ledger에
|
|
438
455
|
목표가 있을 때만 보입니다.
|
|
439
456
|
- 경고는 색만 바꾸지 않고 늘 `⚑`와 글자를 함께 붙입니다. 색이 없어도 똑같이 읽히게 하려는
|
package/docs/reference.md
CHANGED
|
@@ -169,7 +169,7 @@ for an approved plan; `/review-work` checks the `DoneClaim` through a five-lane
|
|
|
169
169
|
| `/litgoal` | Set and keep the finish line: one goal with checkable criteria on durable state. `lit-loop` and `/start-work` run toward it. |
|
|
170
170
|
| `/lit-brainstorm` | Open a question into options, narrow them to a short list, and hand the pick to `deep-interview` or `lit-plan`. Chat: `lit brainstorm`, `lit brainstorming`, `lit ideation`, `lit ideate`, `lit idea`, `lit ideas`. It never builds. |
|
|
171
171
|
| `/lit-hijack` | Port the mechanism in someone else's published work into your own skill or system: capture with provenance, licence gate, gap, source-free spec, separate build, parity proof and report. A bundled `hijack.mjs` decides when each phase is done. Chat: `lit hijack`, `lit hijacking`, `lit 하이재킹`, `lit 하이잭`. |
|
|
172
|
-
| `/lit-adhd`, `/lit-rewind` | Pick up where you left off: a read-only brief
|
|
172
|
+
| `/lit-adhd`, `/lit-rewind` | Pick up where you left off: a read-only brief that opens with three lines (done so far, doing now, next), then earlier sessions with status, real progress or known facts, a roadmap and one recommended step. Finished plans and completed start-work runs count as done, a liveness record marks idle sessions, plans older than seven days stay out, and this worktree's `HANDOFF.md` `Next` item is the fallback step. A bundled `rewind.mjs` collects it. Chat: `lit adhd`, `lit rewind`; then `go` follows the armed step for 30 minutes. `lit approve` and `lit deny` answer a pending boundary; `lit deny` ends the run. |
|
|
173
173
|
| `/litresearch` or `/lit-research` | Run evidence-backed research with a sequential fallback. |
|
|
174
174
|
| `/lit-handoff` | Create a resumable handoff; exact bare `handoff` also routes here. |
|
|
175
175
|
| `/lit-recap` | Read a concise recap from local ledger and session context. |
|
|
@@ -219,6 +219,16 @@ litopencode complete-goals
|
|
|
219
219
|
surface for approved execution. Resume requires the trusted user route and matching work,
|
|
220
220
|
session, revision, and grant; copied or quoted text is inert.
|
|
221
221
|
|
|
222
|
+
When `/start-work save-plan <JSON>` saves an approved plan, the saved-plan notice arms a one-word start:
|
|
223
|
+
typing `go` in that same session within 30 minutes starts the typed start-work run on that plan. A `go`
|
|
224
|
+
from another session, or later, is an ordinary word. A plan whose checklist names an absolute path
|
|
225
|
+
outside the project must carry a `Scope roots: <folder> (<actions>)` line (actions from `read`, `write`,
|
|
226
|
+
`execute`); save-plan refuses an uncovered outside folder and replies with the exact line to add, or
|
|
227
|
+
asks for a narrower existing folder when only the filesystem root, a top-level folder or the home
|
|
228
|
+
folder would cover it. Paths in code fences and commands quoted in an inline code span do not count.
|
|
229
|
+
When typed start-work begins, each valid `Scope roots:` line becomes a grant of the run, so it does
|
|
230
|
+
not pause for a folder the approved plan named; the folder must exist then.
|
|
231
|
+
|
|
222
232
|
Native goal verdict: the OpenCode host surface does not currently expose a native goal primitive;
|
|
223
233
|
LitOpenCode uses `.litopencode/litgoal` instead. Static skills are installed under
|
|
224
234
|
`skills/*/SKILL.md` and remain documentation unless a documented OpenCode route selects them.
|
|
@@ -535,7 +545,13 @@ What it draws:
|
|
|
535
545
|
`paused`, `done`, `failed`, `idle`) and a gauge only when the lane has a real total
|
|
536
546
|
(`[▉▉░░░░░░] 3/10`); otherwise it says what is known (the stage, how long it has run) and a
|
|
537
547
|
working lane shows a small pulse, never a question mark. The card keeps its tallest height while
|
|
538
|
-
lanes are live and drops back to four rows once everything has settled
|
|
548
|
+
lanes are live and drops back to four rows once everything has settled. Other sessions follow
|
|
549
|
+
this session's own lanes, working first, then paused, done and idle, and one other session is
|
|
550
|
+
already a row. Each session's hooks keep a small record in `.litopencode/liveness/<session>.json`
|
|
551
|
+
(`alive` after a tool, `idle` on `session.idle`, `ended` when the session is deleted); when a
|
|
552
|
+
record exists it decides idle and ended instead of the five-minute guess, a session running in
|
|
553
|
+
a herdr pane is named `<skill> · <pane>`, and an ended session or another session's completed
|
|
554
|
+
start-work run shows `done` for one minute and then leaves;
|
|
539
555
|
- while `lit-adhd` (alias `lit-rewind`) runs, the border, the LIT word and the gauges cycle through
|
|
540
556
|
the colour wheel at one fixed lightness, four small colour steps a second with no flashing. It
|
|
541
557
|
is off under `motion: false` and `NO_COLOR`. An idle session in a workspace with earlier work
|
|
@@ -557,7 +573,10 @@ What it draws:
|
|
|
557
573
|
A subagent session shows its parent's card with `· in lane`; the home screen has no band. When the
|
|
558
574
|
card is narrow each row drops its own low-priority parts: the track drops the live step and
|
|
559
575
|
next-task text, bar width, the bar, the criteria count and then every stage but the running one; the bottom border drops the branch,
|
|
560
|
-
then the time, then the context use. It never wraps.
|
|
576
|
+
then the time, then the context use. It never wraps. When an installed LitOpenCode is newer than the
|
|
577
|
+
code this OpenCode start loaded (the automatic update's receipt or the package on disk says so), the
|
|
578
|
+
bottom border starts with `restart to <version>` in the warning colour, the last figure to go, and one
|
|
579
|
+
toast says the same; nothing restarts on its own. The completion moment plays here too.
|
|
561
580
|
- A line under the home prompt, after OpenCode's tips: `🔥 lit ready · last: <goal> ✓ n/m`. It
|
|
562
581
|
appears only when the project ledger holds a goal.
|
|
563
582
|
- Warnings always carry `⚑` and words, not colour alone, so they read the same without colour.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@litfamily/litopencode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
4
4
|
"description": "Workflow plugin for OpenCode: add lit to a prompt and the work is planned, built, checked and written down so the next session can pick it up.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opencode",
|
package/skills/lit-adhd/SKILL.md
CHANGED
|
@@ -57,7 +57,7 @@ Use the OpenCode vocabulary for this contract: `chat.message`, `command.execute.
|
|
|
57
57
|
| `session_id` | The id of the session that typed the request. The route prompt states it; pass it as `--session`. Without it the brief still prints but no `go` step is armed. |
|
|
58
58
|
| `scope` | This worktree and the other worktrees of the same git repository. `--root <dir>` points elsewhere; `--all-dirs` is not used unless the user asks. |
|
|
59
59
|
| `store` | The OpenCode session database (`opencode.db`), opened read-only, else the older JSON session store, else nothing. A missing store is said in words. |
|
|
60
|
-
| `local_state` | `plans/*.md` and `.litopencode/plans/*.md` checklists, the active goal, the bounded start-work run, `.litopencode/workflow-stack/<session>.json`, `HANDOFF*.md` headings and `git log`. |
|
|
60
|
+
| `local_state` | `plans/*.md` and `.litopencode/plans/*.md` checklists, the active goal, the bounded start-work run, `.litopencode/workflow-stack/<session>.json`, `.litopencode/liveness/<session>.json`, `HANDOFF*.md` headings and the first item under their `Next` heading, and `git log`. These small records are read before the session store, so a large store cannot use up the read budget first. |
|
|
61
61
|
|
|
62
62
|
## #contract.mode_matrix
|
|
63
63
|
|
|
@@ -77,7 +77,7 @@ Use the OpenCode vocabulary for this contract: `chat.message`, `command.execute.
|
|
|
77
77
|
|
|
78
78
|
## #contract.outputs
|
|
79
79
|
|
|
80
|
-
- The brief, in Markdown: a headline, a card per live session grouped by worktree and branch, ended sessions as one table, the roadmap, one boxed recommended step, and `go`.
|
|
80
|
+
- The brief, in Markdown: a three-line opener (done so far, doing now, next), a headline, a card per live session grouped by worktree and branch, ended sessions as one table, the roadmap, one boxed recommended step, and `go`.
|
|
81
81
|
- At most one file written: `.litopencode/adhd/next-<session>.json`, only with `--write-next`, only for the asking session.
|
|
82
82
|
- `PASS` when the brief printed, `BLOCKED:` with the missing capability otherwise.
|
|
83
83
|
|
|
@@ -151,12 +151,13 @@ The installed copy of the script sits next to this file; use its path from the s
|
|
|
151
151
|
|
|
152
152
|
Shape (see `references/brief-format.md` for every rule and `references/card-examples.md` for worked cards):
|
|
153
153
|
|
|
154
|
+
- Three opening lines from records only. `Done so far`: this worktree's newest commits in the seven-day window (two at most), its completed start-work run and its plans with every row ticked (three items in all), else its met goal. `Doing now`: this session while it works, else the running start-work run and its plan, else the newest working session. `Next`: the recommended step, with `(type go)` when `go` runs it here.
|
|
154
155
|
- A headline: how many sessions, how many wait on the user, how many are active, and the one next step.
|
|
155
156
|
- Live sessions (working, waiting, blocked, paused) as full cards under a heading per worktree and branch: a coloured badge, the goal in bold, a real gauge or the known facts in words, what is done (or, before any edit, the tools it used most), what is next (or what it is doing now).
|
|
156
157
|
- Ended sessions folded into one table, one row each, at most eight: id, where, goal, how long ago, done.
|
|
157
|
-
- The roadmap: recent commits with their dates (`✓`), the step in hand (`▶`), the steps after it (`○`). Unfilled plan scaffolds and
|
|
158
|
-
- One boxed recommended step.
|
|
159
|
-
- The closing line: `Type go to do it.` when a step is armed here, otherwise where to act.
|
|
158
|
+
- The roadmap: recent commits with their dates (`✓`), the step in hand (`▶`), the steps after it (`○`). Unfilled plan scaffolds and any plan untouched for seven days, in this worktree or another, are left out. A plan with every row ticked is finished work: it counts in the opener, never in the roadmap.
|
|
159
|
+
- One boxed recommended step, in an untagged fence so the chat draws the box as plain text.
|
|
160
|
+
- The closing line: `Type go to do it.` when a step is armed here, otherwise where to act. When the read budget ran out before every plan was read, one more line says how many plans were not read.
|
|
160
161
|
|
|
161
162
|
### Progress is a bar or words, never filler
|
|
162
163
|
|
|
@@ -164,11 +165,11 @@ The collector draws `[▉▉▉░░░░░░░] 3/10` only when both numbe
|
|
|
164
165
|
|
|
165
166
|
### Status words
|
|
166
167
|
|
|
167
|
-
`working`, `waits-on-you`, `blocked`, `paused`, `done`, `idle`. `references/status-taxonomy.md` lists the record behind each and the precedence when two apply.
|
|
168
|
+
`working`, `waits-on-you`, `blocked`, `paused`, `done`, `idle`. A session that completed the start-work run, and has not moved since, reads `done`, and a done card names no next step. A session whose liveness record says idle or ended, at least as new as its last stored move, reads `idle` even inside the two-minute working window. The session asking for the brief is working. `references/status-taxonomy.md` lists the record behind each and the precedence when two apply.
|
|
168
169
|
|
|
169
170
|
### The recommended step
|
|
170
171
|
|
|
171
|
-
One step, chosen in this order: something waiting on the user, a blocked session, a paused discipline, another running session (with what it is doing now), the running start-work run, the single open plan, the newest unfinished session, an open plan in another worktree, the most recent session that stopped. The box always names a real step from the records; only an empty window asks what to start. If the step belongs to this session and is one of continue, keep working, or start the plan, the collector writes the next-step record and `go` follows it. If it belongs to another session or worktree, the box says where to act and `go` here only repeats that pointer; it never starts the step.
|
|
172
|
+
One step, chosen in this order: something waiting on the user, a blocked session, a paused discipline, another running session (with what it is doing now), the running start-work run, the single open plan, the first item under this worktree's `HANDOFF.md` `Next` heading (it never runs on `go`), the newest unfinished session, an open plan in another worktree, the most recent session that stopped. The box always names a real step from the records; only an empty window asks what to start. If the step belongs to this session and is one of continue, keep working, or start the plan, the collector writes the next-step record and `go` follows it. If it belongs to another session or worktree, the box says where to act and `go` here only repeats that pointer; it never starts the step.
|
|
172
173
|
|
|
173
174
|
## Following `go`
|
|
174
175
|
|
|
@@ -6,6 +6,7 @@ The collector's `--brief` output is the only format; paste it as printed. This f
|
|
|
6
6
|
|
|
7
7
|
The brief is Markdown, so OpenCode's chat draws it with the theme's colours.
|
|
8
8
|
|
|
9
|
+
0. The opener, three lines kept apart by a hard break and followed by a blank line: `**Done so far:**` this worktree's newest commits in the seven-day window (two at most), then `` `plans/<name>.md` (start-work complete) `` for a completed run and `` `plans/<name>.md` `<gauge>` `` for a plan with every row ticked, three items in all, else its met goal, else `nothing finished in this window`; `**Doing now:**` the asking session's goal while it works, else `start-work · <plan>` for a running run, else the newest working session's goal, else `nothing running`; `**Next:**` the recommended step, ending in ``(type `go`)`` when a step is armed here.
|
|
9
10
|
1. Headline: `## 🧭 <n> sessions · <k> waiting on you · <a> active · next: <short step>`, then one italic line naming the worktree family and how many worktrees had records (and a note when the store could not be read: missing database, old Node). Zero sessions print `No earlier sessions found here.` under the headings.
|
|
10
11
|
2. Live sessions (working, waits-on-you, blocked, paused) as full cards, grouped under one `### 🌿 \`branch\` · worktree` heading per worktree, `(this one)` on the worktree the command ran in. Each card is one quote, its lines kept apart by a hard break:
|
|
11
12
|
- a badge (🟢 ACTIVE, 🟠 WAITS ON YOU, 🔴 BLOCKED, ⏸️ PAUSED), the short id, how long ago it last moved, `this session` for the asking one, and the start-work boundary it waits on;
|
|
@@ -15,13 +16,15 @@ The brief is Markdown, so OpenCode's chat draws it with the theme's colours.
|
|
|
15
16
|
- `▶ Next:` the first open todo, else the open plan step, else the open goal criterion, else what a running session is doing now (`now: Run the gates`), else `nothing pending on record`.
|
|
16
17
|
3. Ended sessions (done, idle) under `### ⚪ Ended · <n>` as one table, newest first, at most eight rows and an italic count of the rest. Columns: id, where (cut to 20 cells), goal (cut to 44 cells), ago (the largest unit only: `5d`, `14h`, `20m`), done (`finished`, a file count, or `·`).
|
|
17
18
|
4. `### 🗺️ Roadmap`: per worktree with something to show, up to three recent commits with their month-day (`✓`), the plan step in hand (`▶ **now**`), up to two steps after it (`○ **later**`); another worktree's lines carry its name in inline code.
|
|
18
|
-
5. The box, `Recommended next step`, in a
|
|
19
|
+
5. The box, `Recommended next step`, in a code block with no language tag, so its frame keeps its columns and the chat draws it as plain text: the step wrapped at word breaks to at most three lines, then `type: go` when a step is armed.
|
|
19
20
|
6. The closing line: ``Type **`go`** to do it.`` when a step is armed; otherwise `Nothing runs on its own here: open that session, or say what to do.`
|
|
21
|
+
7. When the read budget ran out before every plan was read, an italic line: `<n> plans were not read (read budget used up).` Plans and the other small records are read before the session store, so this happens only with very large plan folders.
|
|
20
22
|
|
|
21
23
|
## Plans the roadmap leaves out
|
|
22
24
|
|
|
23
25
|
- An unfilled scaffold: a row still holding a `<placeholder>`, or every row the same.
|
|
24
|
-
-
|
|
26
|
+
- Any plan that has not changed in seven days, in this worktree or another.
|
|
27
|
+
- A plan with every row ticked: it is finished work and appears in the opener instead.
|
|
25
28
|
|
|
26
29
|
## Width and glyphs
|
|
27
30
|
|
|
@@ -4,6 +4,10 @@ A complete brief as the collector prints it, from a fixture store with invented
|
|
|
4
4
|
Markdown: the headings, bold status words, emoji badges, inline code and the table come out in the theme's colours.
|
|
5
5
|
|
|
6
6
|
````markdown
|
|
7
|
+
**Done so far:** feat(billing): add the ledger tables; `plans/ledger.md` (start-work complete)
|
|
8
|
+
**Doing now:** Port the exporter
|
|
9
|
+
**Next:** In "Migrate the billing tables", answer the open question.
|
|
10
|
+
|
|
7
11
|
## 🧭 4 sessions · 1 waiting on you · 1 active · next: In "Migrate the billing tables", answer the open question.
|
|
8
12
|
*this worktree family · 1 worktree with records*
|
|
9
13
|
|
|
@@ -35,7 +39,7 @@ Markdown: the headings, bold status words, emoji badges, inline code and the tab
|
|
|
35
39
|
- ○ **later** · 4. totals check
|
|
36
40
|
- ○ **later** · 5. cut-over
|
|
37
41
|
|
|
38
|
-
```
|
|
42
|
+
```
|
|
39
43
|
╭─ Recommended next step ──────────────────────────────────────────────╮
|
|
40
44
|
│ In "Migrate the billing tables", answer the open question. │
|
|
41
45
|
╰──────────────────────────────────────────────────────────────────────╯
|
|
@@ -46,6 +50,8 @@ Nothing runs on its own here: open that session, or say what to do.
|
|
|
46
50
|
|
|
47
51
|
What each part shows:
|
|
48
52
|
|
|
53
|
+
- The opener reads only records: the newest commit, the start-work run that completed its plan, this session's
|
|
54
|
+
goal while it works, and the same step the box recommends.
|
|
49
55
|
- The active card has a real total (the single open plan), so it has a bar. It has no edit yet, so `Done` names
|
|
50
56
|
the tools it used most, never a count of calls.
|
|
51
57
|
- The waiting card comes from a `question` tool call still open, and the box recommends answering it.
|
|
@@ -74,7 +80,22 @@ and says what it is doing now.
|
|
|
74
80
|
Nothing runs on its own here: open that session, or say what to do.
|
|
75
81
|
```
|
|
76
82
|
|
|
77
|
-
The box still names a real step from the records.
|
|
83
|
+
The box still names a real step from the records. When this worktree's `HANDOFF.md` has a `Next` heading, its
|
|
84
|
+
first item comes first (`From HANDOFF.md: Wire the exporter to the CLI`). Only an empty window says "say what to
|
|
85
|
+
start".
|
|
86
|
+
|
|
87
|
+
## A finished run and an idle session
|
|
88
|
+
|
|
89
|
+
```markdown
|
|
90
|
+
| id | where | goal | ago | done |
|
|
91
|
+
|---|---|---|---|---|
|
|
92
|
+
| `run0a1b2` | billing-api | Run the ledger plan | 10m | finished |
|
|
93
|
+
| `quiet9c8` | billing-api | Answer a question about the card | 1m | · |
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The session that completed the start-work run reads done and names no next step, even though its to-do list
|
|
97
|
+
still held an item. The second one moved a minute ago, but its liveness record says idle, so it is listed as
|
|
98
|
+
ended rather than drawn as an active card.
|
|
78
99
|
|
|
79
100
|
## `--ascii`
|
|
80
101
|
|
|
@@ -7,10 +7,15 @@ Every card carries one status word. The collector picks the first that applies,
|
|
|
7
7
|
| `waits-on-you` | `◆ WAITS ON YOU` | A `question` tool part still running or pending in the session, or the bounded run is `paused` with a pending boundary owned by the session. |
|
|
8
8
|
| `blocked` | `✕ BLOCKED` | The newest tool part ended in `error` and nothing has run for more than two minutes. |
|
|
9
9
|
| `paused` | `Ⅱ PAUSED` | The session's workflow stack holds a long discipline in the `paused` state. |
|
|
10
|
+
| `working` | `● WORKING` | The session is the one asking for the brief. |
|
|
11
|
+
| `done` | `✓ DONE` | The bounded start-work run is `completed`, owned by the session, and the session has not moved more than five seconds past the run's last update. |
|
|
12
|
+
| `idle` | `○ IDLE` | The session's `.litopencode/liveness` record says `idle` or `ended` and is at most five seconds older than the session's last stored move. |
|
|
10
13
|
| `working` | `● WORKING` | The session was updated within two minutes. |
|
|
11
14
|
| `done` | `✓ DONE` | A real count whose done equals its total. |
|
|
12
15
|
| `idle` | `○ IDLE` | None of the above. |
|
|
13
16
|
|
|
17
|
+
A `done` card never names a next step: what it left open is history. An `alive` liveness record changes nothing; the two-minute window still decides.
|
|
18
|
+
|
|
14
19
|
## Count sources, in order
|
|
15
20
|
|
|
16
21
|
1. The recorded stage count of a paused or active discipline in the stack (`lit-loop stage`).
|
|
@@ -26,4 +31,4 @@ Every card carries one status word. The collector picks the first that applies,
|
|
|
26
31
|
|
|
27
32
|
## Recommended-step precedence
|
|
28
33
|
|
|
29
|
-
Waiting, blocked, paused, another session still working, the running start-work run (this session only), the single open plan, the newest idle session with a known next step. The next-step record is written only for `continue`, `work` and `plan`, and only when the step belongs to the asking session.
|
|
34
|
+
Waiting, blocked, paused, another session still working, the running start-work run (this session only), the single open plan, this worktree's `HANDOFF.md` `Next` item, the newest idle session with a known next step. The next-step record is written only for `continue`, `work` and `plan`, and only when the step belongs to the asking session; a `HANDOFF.md` item writes no record at all.
|