@aemonge-dev/pi-stardeck 0.9.0 → 0.9.2

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.
@@ -31,18 +31,6 @@ import {
31
31
  } from './src/active-work.ts';
32
32
  import { collectDiagnostics } from './src/diagnostics.ts';
33
33
  import { loadConfig } from './src/config.ts';
34
- import {
35
- type GoalHeaderState,
36
- isGoalOwnedPrompt,
37
- loadGoalAutomaticTurnLimit,
38
- restoreGoalHeaderState,
39
- sameGoalHeaderState,
40
- } from './src/goal.ts';
41
- import {
42
- countOpenGoals,
43
- installGoalBlockTakeover,
44
- readGoalHeadline,
45
- } from './src/goal-block.ts';
46
34
  import { collectOpenSpec, collectOpenSpecOverview } from './src/openspec.ts';
47
35
  import { collectOrchestration } from './src/orchestration.ts';
48
36
  import {
@@ -56,7 +44,6 @@ import {
56
44
  formatOpenSpecOverview,
57
45
  formatOrchestration,
58
46
  GALACTICA_HEADER_CHANNEL,
59
- goalHeaderLifecycle,
60
47
  type HeaderActivity,
61
48
  type HeaderLifecycle,
62
49
  directToolCompletionHeaderActivity,
@@ -202,10 +189,6 @@ class GalacticaStatusRuntime {
202
189
  private focus: OpenSpecFocus;
203
190
  private workFocus: SessionWorkFocus;
204
191
  private subject: SessionSubject;
205
- private goal: GoalHeaderState | null;
206
- private goalProjectionSuppressed = false;
207
- private goalAutomaticTurnLimit: number | undefined;
208
- private goalPollCleanup: (() => void) | undefined;
209
192
  private sessionName: string | undefined;
210
193
  private lastTitle: string | undefined;
211
194
  private diagnosticsPath: string | undefined;
@@ -237,7 +220,6 @@ class GalacticaStatusRuntime {
237
220
  focus: OpenSpecFocus,
238
221
  workFocus: SessionWorkFocus,
239
222
  subject: SessionSubject,
240
- goal: GoalHeaderState | null,
241
223
  sessionName: string | undefined,
242
224
  ) {
243
225
  this.pi = pi;
@@ -246,17 +228,10 @@ class GalacticaStatusRuntime {
246
228
  this.focus = focus;
247
229
  this.workFocus = workFocus;
248
230
  this.subject = subject;
249
- this.goal = goal;
250
231
  this.sessionName = sessionName;
251
- this.liveLifecycle = goal
252
- ? goalHeaderLifecycle(goal)
253
- : workFocus.state === 'validation'
254
- ? 'waiting'
255
- : 'listening';
232
+ this.liveLifecycle = workFocus.state === 'validation' ? 'waiting' : 'listening';
256
233
  this.liveActivity =
257
- !goal && workFocus.state === 'validation'
258
- ? { kind: 'awaiting-validation' }
259
- : undefined;
234
+ workFocus.state === 'validation' ? { kind: 'awaiting-validation' } : undefined;
260
235
  this.store = new AtomicStatusStore({
261
236
  cwd: ctx.cwd,
262
237
  projectRoot: ctx.cwd,
@@ -266,7 +241,6 @@ class GalacticaStatusRuntime {
266
241
  this.recordEvent({ type: 'focus/openspec', at: seededAt, focus });
267
242
  this.recordEvent({ type: 'focus/work', at: seededAt, work: workFocus });
268
243
  this.recordEvent({ type: 'focus/subject', at: seededAt, subject });
269
- if (goal) this.recordEvent({ type: 'focus/goal', at: seededAt, goal });
270
244
  }
271
245
 
272
246
  private runner: CommandRunner = async (command, args, options) => {
@@ -292,15 +266,6 @@ class GalacticaStatusRuntime {
292
266
  if ((snap.spans?.length ?? 0) > 0 || idle > 0) this.publish();
293
267
  }, 1_000);
294
268
  this.publish();
295
- this.ensureGoalPolling();
296
- this.launch(
297
- loadGoalAutomaticTurnLimit().then((limit) => {
298
- if (this.stopped || this.goalAutomaticTurnLimit === limit) return;
299
- this.goalAutomaticTurnLimit = limit;
300
- this.publish();
301
- }),
302
- 'config',
303
- );
304
269
  this.launch(
305
270
  (async () => {
306
271
  this.loadedConfig = await loadConfig();
@@ -632,14 +597,9 @@ class GalacticaStatusRuntime {
632
597
  this.watchSignature = '';
633
598
  }
634
599
 
635
- private projectedGoal(): GoalHeaderState | null {
636
- return this.goalProjectionSuppressed ? null : this.goal;
637
- }
638
-
639
600
  private publish(): void {
640
601
  if (this.stopped) return;
641
602
  const snapshot = this.store.get();
642
- const goal = this.projectedGoal();
643
603
  // Builders read focus facts through the snapshot layer (recordEvent stores
644
604
  // the same object references), so output stays byte-identical while the
645
605
  // ledger becomes the feeding seam.
@@ -652,7 +612,7 @@ class GalacticaStatusRuntime {
652
612
  ? snapshot.openspec
653
613
  : null;
654
614
  const visibleWorkFocus =
655
- focus.mode === 'task' || goal || (work.state === 'clear' && this.openSpecFeedback)
615
+ focus.mode === 'task' || (work.state === 'clear' && this.openSpecFeedback)
656
616
  ? undefined
657
617
  : work;
658
618
  const widgets = buildWidgetSnapshots(
@@ -666,7 +626,6 @@ class GalacticaStatusRuntime {
666
626
  openSpecOverview: this.openSpecOverview,
667
627
  openSpecProjectDetected: this.openSpecProjectDetected,
668
628
  workFocus: visibleWorkFocus,
669
- goal,
670
629
  },
671
630
  );
672
631
  this.publisher.sync(widgets);
@@ -681,9 +640,6 @@ class GalacticaStatusRuntime {
681
640
  lifecycle: this.liveLifecycle,
682
641
  activity: this.liveActivity,
683
642
  taskflowPhase: this.liveTaskflowPhase,
684
- goal,
685
- openGoals: goal ? 0 : countOpenGoals(this.ctx),
686
- goalAutomaticTurnLimit: this.goalAutomaticTurnLimit,
687
643
  activeRuns: (() => {
688
644
  const runs = this.runtimeSpans.snapshot();
689
645
  return { children: runs.children, subagents: runs.subagents };
@@ -724,7 +680,6 @@ class GalacticaStatusRuntime {
724
680
  focus: facts.openSpec,
725
681
  workFocus: facts.work,
726
682
  subject: facts.subject,
727
- goal: this.projectedGoal(),
728
683
  ...(taskTitle ? { taskTitle } : {}),
729
684
  ...(this.sessionName ? { sessionName: this.sessionName } : {}),
730
685
  projectRoot: snapshot.projectRoot,
@@ -757,56 +712,7 @@ class GalacticaStatusRuntime {
757
712
  return this.subject;
758
713
  }
759
714
 
760
- currentGoal(): GoalHeaderState | null {
761
- return this.goal;
762
- }
763
-
764
- syncGoalFromSession(): void {
765
- this.setGoal(
766
- readGoalHeadline(this.ctx) ??
767
- restoreGoalHeaderState(this.ctx.sessionManager.getBranch()),
768
- );
769
- }
770
-
771
- private ensureGoalPolling(): void {
772
- if (!this.goal || this.goalPollCleanup || this.stopped) return;
773
- const timer = setInterval(() => this.syncGoalFromSession(), 500);
774
- timer.unref?.();
775
- const cleanup = this.resources.add(() => clearInterval(timer));
776
- this.goalPollCleanup = () => {
777
- cleanup();
778
- this.goalPollCleanup = undefined;
779
- };
780
- }
781
-
782
- private stopGoalPolling(): void {
783
- this.goalPollCleanup?.();
784
- }
785
-
786
- setGoal(goal: GoalHeaderState | null): void {
787
- if (sameGoalHeaderState(this.goal, goal)) return;
788
- this.goal = goal;
789
- this.recordEvent({ type: 'focus/goal', at: Date.now(), goal });
790
- this.goalProjectionSuppressed = false;
791
- if (goal) {
792
- this.ensureGoalPolling();
793
- if (goal.status !== 'active' || goal.waiting) {
794
- this.liveLifecycle = goalHeaderLifecycle(goal);
795
- this.liveActivity = undefined;
796
- } else if (['listening', 'waiting', 'blocked'].includes(this.liveLifecycle)) {
797
- this.liveLifecycle = 'working';
798
- this.liveActivity = undefined;
799
- }
800
- this.publish();
801
- this.updateTitle();
802
- return;
803
- }
804
- this.stopGoalPolling();
805
- this.settle();
806
- this.updateTitle();
807
- }
808
-
809
- beginTurn(prompt: unknown): void {
715
+ beginTurn(): void {
810
716
  this.directToolActivities.clear();
811
717
  this.directToolFailed = false;
812
718
  this.titleActivity.reset();
@@ -815,18 +721,6 @@ class GalacticaStatusRuntime {
815
721
  this.currentTurnId = `turn-${this.turnCounter}`;
816
722
  this.runtimeSpans.beginRoot(this.currentTurnId, 'understanding');
817
723
  this.syncSpanEvents();
818
- this.syncGoalFromSession();
819
- const suppressStoppedGoal = Boolean(
820
- this.goal && this.goal.status !== 'active' && !isGoalOwnedPrompt(prompt),
821
- );
822
- const projectionChanged = this.goalProjectionSuppressed !== suppressStoppedGoal;
823
- this.goalProjectionSuppressed = suppressStoppedGoal;
824
- if (projectionChanged) {
825
- this.liveLifecycle = 'understanding';
826
- this.liveActivity = { kind: 'understanding' };
827
- this.publish();
828
- return;
829
- }
830
724
  this.setLiveProjection('understanding', { kind: 'understanding' });
831
725
  }
832
726
 
@@ -936,6 +830,13 @@ class GalacticaStatusRuntime {
936
830
  this.publish();
937
831
  }
938
832
 
833
+ /** Clear the title-state activity when its authoring call ends — a
834
+ * finished tool never lingers as the live label (quiet-activity-row). */
835
+ finishTitleActivity(toolCallId: string): void {
836
+ if (!this.titleActivity.finish(toolCallId)) return;
837
+ this.publish();
838
+ }
839
+
939
840
  /** Accumulate one provider response's usage into the per-turn cost meter. */
940
841
  recordTurnUsage(message: unknown): void {
941
842
  if (!message || typeof message !== 'object' || Array.isArray(message)) return;
@@ -1024,7 +925,7 @@ class GalacticaStatusRuntime {
1024
925
 
1025
926
  markAnswering(): void {
1026
927
  if (this.liveLifecycle !== 'aborted') {
1027
- this.setLiveProjection('answering');
928
+ this.setLiveProjection('answering', { kind: 'answering' });
1028
929
  }
1029
930
  }
1030
931
 
@@ -1042,15 +943,6 @@ class GalacticaStatusRuntime {
1042
943
  this.publish();
1043
944
  return;
1044
945
  }
1045
- const goal = this.projectedGoal();
1046
- if (goal) {
1047
- if (goal.status === 'active' && !goal.waiting) {
1048
- this.setLiveProjection('working');
1049
- } else {
1050
- this.setLiveProjection(goalHeaderLifecycle(goal));
1051
- }
1052
- return;
1053
- }
1054
946
  if (this.focus.mode === 'task' || this.workFocus.state === 'validation') {
1055
947
  this.setLiveProjection('waiting', { kind: 'awaiting-validation' });
1056
948
  return;
@@ -1096,11 +988,6 @@ class GalacticaStatusRuntime {
1096
988
  ? 'Work: clear'
1097
989
  : `Work: ${this.workFocus.state} · ${this.workFocus.intent}`,
1098
990
  );
1099
- lines.push(
1100
- this.goal
1101
- ? `Goal: ${this.goal.status} · automatic ${this.goal.automaticModelTurns}/${this.goalAutomaticTurnLimit ?? '?'}`
1102
- : 'Goal: none',
1103
- );
1104
991
  lines.push(
1105
992
  snapshot.diagnostics
1106
993
  ? `Diagnostics: ${formatDiagnostics(snapshot.diagnostics)}`
@@ -1123,9 +1010,6 @@ class GalacticaStatusRuntime {
1123
1010
  configWarnings: snapshot.configWarnings,
1124
1011
  focus: this.focus,
1125
1012
  workFocus: this.workFocus,
1126
- goal: this.goal,
1127
- goalProjected: this.projectedGoal(),
1128
- goalAutomaticTurnLimit: this.goalAutomaticTurnLimit ?? null,
1129
1013
  openSpecFeedback: this.openSpecFeedback ?? null,
1130
1014
  openSpecOverview: this.openSpecOverview ?? null,
1131
1015
  detected: {
@@ -1349,7 +1233,6 @@ export default function galacticaStatus(pi: ExtensionAPI): void {
1349
1233
  const focus = restoreOpenSpecFocus(branch);
1350
1234
  const workFocus = restoreSessionWorkFocus(branch);
1351
1235
  const subject = restoreSessionSubject(branch);
1352
- const goal = readGoalHeadline(ctx) ?? restoreGoalHeaderState(branch);
1353
1236
  const sessionName = pi.getSessionName() ?? ctx.sessionManager.getSessionName();
1354
1237
  runtime = new GalacticaStatusRuntime(
1355
1238
  pi,
@@ -1358,7 +1241,6 @@ export default function galacticaStatus(pi: ExtensionAPI): void {
1358
1241
  focus,
1359
1242
  workFocus,
1360
1243
  subject,
1361
- goal,
1362
1244
  sessionName,
1363
1245
  );
1364
1246
  runtime.start();
@@ -1373,12 +1255,11 @@ export default function galacticaStatus(pi: ExtensionAPI): void {
1373
1255
  runtime?.setFocus(restoreOpenSpecFocus(branch));
1374
1256
  runtime?.setWorkFocus(restoreSessionWorkFocus(branch));
1375
1257
  runtime?.setSubject(restoreSessionSubject(branch));
1376
- runtime?.setGoal(readGoalHeadline(ctx) ?? restoreGoalHeaderState(branch));
1377
1258
  runtime?.settle();
1378
1259
  });
1379
1260
 
1380
- pi.on('before_agent_start', (event) => {
1381
- runtime?.beginTurn(event.prompt);
1261
+ pi.on('before_agent_start', () => {
1262
+ runtime?.beginTurn();
1382
1263
  });
1383
1264
 
1384
1265
  pi.on('tool_execution_start', (event) => {
@@ -1439,8 +1320,8 @@ export default function galacticaStatus(pi: ExtensionAPI): void {
1439
1320
  });
1440
1321
 
1441
1322
  pi.on('tool_execution_end', (event) => {
1323
+ runtime?.finishTitleActivity(event.toolCallId);
1442
1324
  runtime?.finishRuntimeRun(event.toolCallId);
1443
- queueMicrotask(() => runtime?.syncGoalFromSession());
1444
1325
  if (event.toolName !== 'taskflow') {
1445
1326
  runtime?.finishDirectTool(event.toolCallId, event.isError);
1446
1327
  return;
@@ -1459,7 +1340,6 @@ export default function galacticaStatus(pi: ExtensionAPI): void {
1459
1340
 
1460
1341
  pi.on('turn_end', (event) => {
1461
1342
  if (assistantStopReason(event.message) === 'aborted') runtime?.markAborted();
1462
- queueMicrotask(() => runtime?.syncGoalFromSession());
1463
1343
  });
1464
1344
 
1465
1345
  pi.on('agent_end', (event) => {
@@ -1469,10 +1349,7 @@ export default function galacticaStatus(pi: ExtensionAPI): void {
1469
1349
  });
1470
1350
 
1471
1351
  pi.on('agent_settled', () => {
1472
- queueMicrotask(() => {
1473
- runtime?.syncGoalFromSession();
1474
- runtime?.settle();
1475
- });
1352
+ queueMicrotask(() => runtime?.settle());
1476
1353
  });
1477
1354
 
1478
1355
  pi.on('session_shutdown', () => {
@@ -1552,7 +1429,7 @@ export default function galacticaStatus(pi: ExtensionAPI): void {
1552
1429
  name: 'subject',
1553
1430
  label: 'Session Subject',
1554
1431
  description:
1555
- 'Show or set the sanitized session subject that keeps the focus row populated beneath OpenSpec, Goal, and Session Work',
1432
+ 'Show or set the sanitized session subject that keeps the focus row populated beneath OpenSpec and Session Work',
1556
1433
  promptSnippet: 'Manage the automatic session subject title',
1557
1434
  promptGuidelines: [
1558
1435
  'Author a short sanitized subject (at most 120 characters, never raw prompt text) at the first conversational turn; revise it only when the topic clearly shifts. Never require Human action for it.',
@@ -1710,8 +1587,4 @@ export default function galacticaStatus(pi: ExtensionAPI): void {
1710
1587
  ctx.ui.notify(runtime?.debug() ?? 'galactica-status is not active', 'info');
1711
1588
  },
1712
1589
  });
1713
-
1714
- // Registered last: the goal widget takeover must never precede the
1715
- // status publisher's synchronous session-start publication order.
1716
- void installGoalBlockTakeover(pi);
1717
1590
  }
@@ -1,5 +1,4 @@
1
1
  import { basename } from 'node:path';
2
- import type { GoalHeaderState } from './goal.ts';
3
2
 
4
3
  export const OPEN_SPEC_FOCUS_ENTRY_TYPE = 'galactica-status.openspec-focus.v1';
5
4
  export const SESSION_WORK_FOCUS_ENTRY_TYPE = 'galactica-status.session-work.v1';
@@ -196,7 +195,6 @@ export function sameSessionSubject(
196
195
  export function formatActiveWorkTitle(options: {
197
196
  focus: OpenSpecFocus;
198
197
  workFocus?: SessionWorkFocus;
199
- goal?: GoalHeaderState | null;
200
198
  subject?: SessionSubject;
201
199
  taskTitle?: string;
202
200
  sessionName?: string;
@@ -209,13 +207,6 @@ export function formatActiveWorkTitle(options: {
209
207
  ? shorten(normalizeTitlePart(options.taskTitle), MAX_TASK_TITLE_POINTS)
210
208
  : '';
211
209
  detail = `${options.focus.change} › ${options.focus.taskId}${taskTitle ? ` ${taskTitle}` : ''}`;
212
- } else if (options.goal) {
213
- detail =
214
- options.goal.status === 'complete'
215
- ? 'Validate › Goal'
216
- : options.goal.status === 'active' && !options.goal.waiting
217
- ? 'Goal'
218
- : `Goal › ${options.goal.waiting ? 'waiting' : options.goal.status.replace('_', ' ')}`;
219
210
  } else if (options.workFocus && options.workFocus.state !== 'clear') {
220
211
  detail =
221
212
  options.workFocus.state === 'validation'
@@ -5,7 +5,6 @@ import type {
5
5
  RunSpan,
6
6
  StageValue,
7
7
  } from './types.ts';
8
- import type { GoalHeaderState } from './goal.ts';
9
8
  import type { OpenSpecFocus, SessionSubject, SessionWorkFocus } from './active-work.ts';
10
9
 
11
10
  /**
@@ -19,7 +18,6 @@ import type { OpenSpecFocus, SessionSubject, SessionWorkFocus } from './active-w
19
18
 
20
19
  export const LEDGER_EVENT_TYPES = [
21
20
  'focus/openspec',
22
- 'focus/goal',
23
21
  'focus/work',
24
22
  'focus/subject',
25
23
  'run/start',
@@ -39,7 +37,6 @@ export type LedgerEvent =
39
37
  at: number;
40
38
  focus: OpenSpecFocus;
41
39
  }
42
- | { type: 'focus/goal'; at: number; goal: GoalHeaderState | null }
43
40
  | { type: 'focus/work'; at: number; work: SessionWorkFocus }
44
41
  | { type: 'focus/subject'; at: number; subject: SessionSubject }
45
42
  | { type: 'run/start'; at: number; span: RunSpan }