@volter-ai-dev/supercode-ui 0.1.28 → 0.1.30

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/composer.mjs CHANGED
@@ -40,6 +40,7 @@ var EMPTY_UI_STATE = Object.freeze({
40
40
  canReduce: false,
41
41
  canInterrupt: false,
42
42
  canRespond: false,
43
+ canConfigureSettings: false,
43
44
  messaging: null,
44
45
  workspace: "",
45
46
  taskPlan: Object.freeze({ source: "none", items: Object.freeze([]), residueCount: 0, observedAt: null }),
@@ -48,6 +49,8 @@ var EMPTY_UI_STATE = Object.freeze({
48
49
  exportBackTarget: null,
49
50
  exportReceipt: null,
50
51
  reductionReceipt: null,
52
+ interopSettings: null,
53
+ interopSettingsError: null,
51
54
  error: null,
52
55
  recoverable: false,
53
56
  harnesses: Object.freeze([]),
@@ -65,7 +68,7 @@ function harnessDisplayName(id) {
65
68
  function canContinueHere(state) {
66
69
  if (state.mode !== "mirror" || state.canSend) return false;
67
70
  const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
68
- return state.canResume && row?.runtimeStatus !== "busy" && row?.runtimeStatus !== "idle";
71
+ return state.canResume && row?.runtimeStatus !== "running" && row?.runtimeStatus !== "busy" && row?.runtimeStatus !== "idle";
69
72
  }
70
73
  function isSendKey(event) {
71
74
  return event.key === "Enter" && !event.shiftKey && !event.isComposing;
@@ -252,7 +255,7 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
252
255
  if (state.mode !== "mirror" || state.canSend) return null;
253
256
  const attached = state.attached;
254
257
  const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
255
- const activeElsewhere = row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
258
+ const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
256
259
  const resume = canContinueHere(state);
257
260
  const join = state.canAttach;
258
261
  const branch = state.canBranch;
package/controller.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { createToolPresentation, normalizeUiState } from './core.mjs';
1
+ import { createToolPresentation, normalizeUiState, relativeAge } from './core.mjs';
2
2
 
3
3
  const HARNESS_LABELS = {
4
4
  'claude-code': 'Claude Code',
@@ -28,16 +28,6 @@ function workspaceName(cwd) {
28
28
  return cwd.replaceAll('\\', '/').split('/').filter(Boolean).at(-1) ?? cwd;
29
29
  }
30
30
 
31
- function relativeAge(updatedAt, now) {
32
- if (typeof updatedAt !== 'number' || !Number.isFinite(updatedAt) || updatedAt <= 0) return '';
33
- const delta = Math.max(0, now - updatedAt);
34
- if (delta < 60_000) return 'now';
35
- if (delta < 3_600_000) return `${Math.floor(delta / 60_000)}m ago`;
36
- if (delta < 86_400_000) return `${Math.floor(delta / 3_600_000)}h ago`;
37
- if (delta < 604_800_000) return `${Math.floor(delta / 86_400_000)}d ago`;
38
- return `${Math.floor(delta / 604_800_000)}w ago`;
39
- }
40
-
41
31
  function payloadText(payload) {
42
32
  if (typeof payload === 'string') return payload;
43
33
  try {
@@ -384,6 +374,7 @@ function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
384
374
  canReduce: actions.reduce === true,
385
375
  canInterrupt: actions.interrupt === true,
386
376
  canRespond: actions.respond === true,
377
+ canConfigureSettings: actions.configureHarness === true,
387
378
  messaging: snapshot.connection?.messaging ?? null,
388
379
  workspace: snapshot.workspace ?? '',
389
380
  taskPlan: {
@@ -401,6 +392,8 @@ function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
401
392
  exportBackTarget: options.exportBackTarget ?? null,
402
393
  exportReceipt: options.exportReceipt ?? null,
403
394
  reductionReceipt: options.reductionReceipt ?? snapshot.reductionReceipt ?? null,
395
+ interopSettings: snapshot.interopSettings ?? null,
396
+ interopSettingsError: snapshot.interopSettingsError ?? null,
404
397
  error: snapshot.error?.message ?? null,
405
398
  recoverable: snapshot.error?.recoverable === true,
406
399
  harnesses: (snapshot.harnesses ?? []).map((harness) => ({
@@ -464,6 +457,12 @@ async function dispatchStandard(controller, intent, options) {
464
457
  if (intent.action === 'terminal') return controller.dispatch({ type: 'openTerminal' });
465
458
  if (intent.action === 'interrupt') return controller.dispatch({ type: 'interrupt' });
466
459
  if (intent.action === 'respond') return controller.dispatch({ type: 'respond', requestId: intent.requestId, optionId: intent.optionId });
460
+ if (intent.action === 'configureHarness') return controller.dispatch({
461
+ type: 'configureHarness',
462
+ harness: intent.harness,
463
+ changes: intent.changes,
464
+ expectedRevision: intent.expectedRevision,
465
+ });
467
466
  if (intent.action === 'refresh') return controller.dispatch({ type: 'refresh', autoObserve: true });
468
467
  if (intent.action === 'export' && active) {
469
468
  const artifact = await controller.exportSession(active, intent.targetHarness);
package/conversation.mjs CHANGED
@@ -41,6 +41,7 @@ var EMPTY_UI_STATE = Object.freeze({
41
41
  canReduce: false,
42
42
  canInterrupt: false,
43
43
  canRespond: false,
44
+ canConfigureSettings: false,
44
45
  messaging: null,
45
46
  workspace: "",
46
47
  taskPlan: Object.freeze({ source: "none", items: Object.freeze([]), residueCount: 0, observedAt: null }),
@@ -49,6 +50,8 @@ var EMPTY_UI_STATE = Object.freeze({
49
50
  exportBackTarget: null,
50
51
  exportReceipt: null,
51
52
  reductionReceipt: null,
53
+ interopSettings: null,
54
+ interopSettingsError: null,
52
55
  error: null,
53
56
  recoverable: false,
54
57
  harnesses: Object.freeze([]),
@@ -67,7 +70,7 @@ var MAX_TOOL_PREVIEW_CHARS = 4e3;
67
70
  function record(value) {
68
71
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
69
72
  }
70
- function boundedString(value, max) {
73
+ function boundedString(value, max = 2e3) {
71
74
  if (typeof value !== "string") return "";
72
75
  return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
73
76
  }
package/core.d.ts CHANGED
@@ -36,6 +36,7 @@ export {
36
36
  isSendKey,
37
37
  normalizeUiState,
38
38
  operationLabel,
39
+ relativeAge,
39
40
  sessionActivity,
40
41
  sessionDisplayName,
41
42
  terminalCommand,
package/core.mjs CHANGED
@@ -38,6 +38,7 @@ export const EMPTY_UI_STATE = Object.freeze({
38
38
  canReduce: false,
39
39
  canInterrupt: false,
40
40
  canRespond: false,
41
+ canConfigureSettings: false,
41
42
  messaging: null,
42
43
  workspace: '',
43
44
  taskPlan: Object.freeze({ source: 'none', items: Object.freeze([]), residueCount: 0, observedAt: null }),
@@ -46,6 +47,8 @@ export const EMPTY_UI_STATE = Object.freeze({
46
47
  exportBackTarget: null,
47
48
  exportReceipt: null,
48
49
  reductionReceipt: null,
50
+ interopSettings: null,
51
+ interopSettingsError: null,
49
52
  error: null,
50
53
  recoverable: false,
51
54
  harnesses: Object.freeze([]),
@@ -85,7 +88,17 @@ function nullableNumber(value) {
85
88
  return typeof value === 'number' && Number.isFinite(value) ? value : null;
86
89
  }
87
90
 
88
- function boundedString(value, max) {
91
+ export function relativeAge(updatedAt, now = Date.now()) {
92
+ if (typeof updatedAt !== 'number' || !Number.isFinite(updatedAt) || updatedAt <= 0) return '';
93
+ const delta = Math.max(0, now - updatedAt);
94
+ if (delta < 60_000) return 'now';
95
+ if (delta < 3_600_000) return `${Math.floor(delta / 60_000)}m ago`;
96
+ if (delta < 86_400_000) return `${Math.floor(delta / 3_600_000)}h ago`;
97
+ if (delta < 604_800_000) return `${Math.floor(delta / 86_400_000)}d ago`;
98
+ return `${Math.floor(delta / 604_800_000)}w ago`;
99
+ }
100
+
101
+ function boundedString(value, max = 2_000) {
89
102
  if (typeof value !== 'string') return '';
90
103
  return value.length <= max ? value : `${value.slice(0, max)}…`;
91
104
  }
@@ -541,11 +554,12 @@ function readSessions(value) {
541
554
  title: string(row.title),
542
555
  preview: string(row.preview),
543
556
  age: string(row.age),
557
+ previewUpdatedAt: nullableNumber(row.previewUpdatedAt),
544
558
  updatedAt: nullableNumber(row.updatedAt),
545
559
  messages: nullableNumber(row.messages),
546
560
  active: row.active === true,
547
561
  live: row.live === true,
548
- runtimeStatus: row.runtimeStatus === 'busy' || row.runtimeStatus === 'idle' ? row.runtimeStatus : null,
562
+ runtimeStatus: row.runtimeStatus === 'running' || row.runtimeStatus === 'busy' || row.runtimeStatus === 'idle' ? row.runtimeStatus : null,
549
563
  }];
550
564
  });
551
565
  }
@@ -660,6 +674,81 @@ function readReductionReceipt(value) {
660
674
  };
661
675
  }
662
676
 
677
+ function readInteropSettings(value) {
678
+ const report = record(value);
679
+ if (
680
+ report?.schema !== 'supercode.harness-interop-settings.v1' ||
681
+ typeof report.harness !== 'string' ||
682
+ typeof report.revision !== 'string' ||
683
+ !Array.isArray(report.controls) ||
684
+ !Array.isArray(report.advisories)
685
+ ) return null;
686
+ const controls = report.controls.slice(0, 20).flatMap((raw) => {
687
+ const control = record(raw);
688
+ if (!control || typeof control.key !== 'string' || typeof control.label !== 'string') return [];
689
+ return [{
690
+ key: boundedString(control.key, 200),
691
+ nativeKey: boundedString(control.native_key ?? control.nativeKey, 200),
692
+ label: boundedString(control.label, 300),
693
+ description: boundedString(control.description),
694
+ scope: ['user', 'project', 'managed', 'command_line'].includes(control.scope) ? control.scope : 'user',
695
+ sourcePath: boundedString(control.source_path ?? control.sourcePath, 4_000),
696
+ configuredValue: typeof (control.configured_value ?? control.configuredValue) === 'string' ? boundedString(control.configured_value ?? control.configuredValue, 500) : null,
697
+ effectiveValue: typeof (control.effective_value ?? control.effectiveValue) === 'string' ? boundedString(control.effective_value ?? control.effectiveValue, 500) : null,
698
+ effectiveKnown: (control.effective_known ?? control.effectiveKnown) === true,
699
+ effectiveNote: boundedString(control.effective_note ?? control.effectiveNote),
700
+ choices: Array.isArray(control.choices) ? control.choices.slice(0, 20).flatMap((candidate) => {
701
+ const choice = record(candidate);
702
+ return choice && typeof choice.value === 'string' && typeof choice.label === 'string'
703
+ ? [{
704
+ value: boundedString(choice.value, 500),
705
+ label: boundedString(choice.label, 300),
706
+ description: boundedString(choice.description),
707
+ ...(typeof choice.risk === 'string' ? { risk: boundedString(choice.risk) } : {}),
708
+ }]
709
+ : [];
710
+ }) : [],
711
+ writable: control.writable === true,
712
+ resettable: control.resettable === true,
713
+ requiresRestart: (control.requires_restart ?? control.requiresRestart) === true,
714
+ }];
715
+ });
716
+ const advisories = report.advisories.slice(0, 20).flatMap((raw) => {
717
+ const advisory = record(raw);
718
+ const recommendation = record(advisory?.recommendation);
719
+ const change = record(recommendation?.change);
720
+ if (
721
+ !advisory || !recommendation || !change ||
722
+ typeof advisory.code !== 'string' || typeof advisory.title !== 'string' ||
723
+ typeof advisory.setting !== 'string' || typeof change.key !== 'string'
724
+ ) return [];
725
+ return [{
726
+ code: boundedString(advisory.code, 200),
727
+ severity: ['info', 'warning', 'error'].includes(advisory.severity) ? advisory.severity : 'warning',
728
+ title: boundedString(advisory.title, 500),
729
+ message: boundedString(advisory.message),
730
+ setting: boundedString(advisory.setting, 200),
731
+ recommendation: {
732
+ label: boundedString(recommendation.label, 500),
733
+ description: boundedString(recommendation.description),
734
+ consequence: boundedString(recommendation.consequence),
735
+ change: {
736
+ key: boundedString(change.key, 200),
737
+ value: typeof change.value === 'string' ? boundedString(change.value, 500) : null,
738
+ },
739
+ command: boundedString(recommendation.command, 4_000),
740
+ },
741
+ }];
742
+ });
743
+ return {
744
+ schema: 'supercode.harness-interop-settings.v1',
745
+ harness: report.harness,
746
+ revision: boundedString(report.revision, 500),
747
+ controls,
748
+ advisories,
749
+ };
750
+ }
751
+
663
752
  export function normalizeUiState(value) {
664
753
  const raw = record(value) ?? {};
665
754
  const pill = record(raw.pill);
@@ -685,6 +774,7 @@ export function normalizeUiState(value) {
685
774
  canReduce: raw.canReduce === true,
686
775
  canInterrupt: raw.canInterrupt === true,
687
776
  canRespond: raw.canRespond === true,
777
+ canConfigureSettings: raw.canConfigureSettings === true,
688
778
  messaging: raw.messaging === 'live_peer' ? 'live_peer' : null,
689
779
  workspace: string(raw.workspace),
690
780
  taskPlan: readTaskPlan(raw.taskPlan),
@@ -693,6 +783,8 @@ export function normalizeUiState(value) {
693
783
  exportBackTarget: typeof raw.exportBackTarget === 'string' ? raw.exportBackTarget : null,
694
784
  exportReceipt: readExportReceipt(raw.exportReceipt),
695
785
  reductionReceipt: readReductionReceipt(raw.reductionReceipt),
786
+ interopSettings: readInteropSettings(raw.interopSettings),
787
+ interopSettingsError: typeof raw.interopSettingsError === 'string' ? boundedString(raw.interopSettingsError) : null,
696
788
  error: typeof raw.error === 'string' ? raw.error : null,
697
789
  recoverable: raw.recoverable === true,
698
790
  harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
@@ -729,6 +821,7 @@ export function sessionActivity(state, row) {
729
821
  const attention = state.attention.find((item) => item.key === row.key)?.kind;
730
822
  if (attention) return attention;
731
823
  if (row.runtimeStatus === 'busy') return 'working';
824
+ if (row.runtimeStatus === 'running') return 'running';
732
825
  if (row.live || row.runtimeStatus === 'idle') return 'recent';
733
826
  return 'idle';
734
827
  }
@@ -793,12 +886,12 @@ export function activitySummary(entries) {
793
886
  export function canContinueHere(state) {
794
887
  if (state.mode !== 'mirror' || state.canSend) return false;
795
888
  const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
796
- return state.canResume && row?.runtimeStatus !== 'busy' && row?.runtimeStatus !== 'idle';
889
+ return state.canResume && row?.runtimeStatus !== 'running' && row?.runtimeStatus !== 'busy' && row?.runtimeStatus !== 'idle';
797
890
  }
798
891
 
799
892
  export function operationLabel(operation) {
800
893
  if (!operation) return '';
801
- const labels = { discover: 'Refreshing chats…', observe: 'Loading recent messages…', attach: 'Opening chat…', start: 'Starting new chat…', resume: 'Continuing here…', join: 'Joining live session…', detach: 'Detaching to read-only…', branch: 'Starting continuation…', reduce: 'Reducing context and verifying reversibility…', terminal: 'Preparing terminal handoff…', export: 'Exporting losslessly…', interrupt: 'Stopping agent…', respond: 'Sending response…', loadEarlier: 'Loading earlier messages…', loadSessions: 'Loading more chats…', refresh: 'Retrying…' };
894
+ const labels = { discover: 'Refreshing chats…', observe: 'Loading recent messages…', attach: 'Opening chat…', start: 'Starting new chat…', resume: 'Continuing here…', join: 'Joining live session…', detach: 'Detaching to read-only…', branch: 'Starting continuation…', reduce: 'Reducing context and verifying reversibility…', terminal: 'Preparing terminal handoff…', export: 'Exporting losslessly…', interrupt: 'Stopping agent…', respond: 'Sending response…', configureHarness: 'Updating harness settings…', loadEarlier: 'Loading earlier messages…', loadSessions: 'Loading more chats…', refresh: 'Retrying…' };
802
895
  return labels[operation] ?? `${operation.replaceAll('_', ' ')}…`;
803
896
  }
804
897