@undefineds.co/linx 0.3.20 → 0.3.23
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/dist/generated/version.js +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/auto-mode/pod-persistence.js +53 -3
- package/dist/lib/auto-mode/pod-persistence.js.map +1 -1
- package/dist/lib/auto-mode/secretary.js +2 -2
- package/dist/lib/auto-mode/secretary.js.map +1 -1
- package/dist/lib/chat-api.js +23 -61
- package/dist/lib/chat-api.js.map +1 -1
- package/dist/lib/codex-plugin/index.js +1 -0
- package/dist/lib/codex-plugin/index.js.map +1 -1
- package/dist/lib/codex-plugin/symphony-mcp.js +335 -0
- package/dist/lib/codex-plugin/symphony-mcp.js.map +1 -0
- package/dist/lib/linx-cloud-errors.js +0 -5
- package/dist/lib/linx-cloud-errors.js.map +1 -1
- package/dist/lib/linx-status-line.js +1 -8
- package/dist/lib/linx-status-line.js.map +1 -1
- package/dist/lib/linx-tui-contract.js +2 -1
- package/dist/lib/linx-tui-contract.js.map +1 -1
- package/dist/lib/models.js +3 -2
- package/dist/lib/models.js.map +1 -1
- package/dist/lib/pi-adapter/auth.js +68 -0
- package/dist/lib/pi-adapter/auth.js.map +1 -0
- package/dist/lib/pi-adapter/branding.js +67 -110
- package/dist/lib/pi-adapter/branding.js.map +1 -1
- package/dist/lib/pi-adapter/interactive.js +341 -101
- package/dist/lib/pi-adapter/interactive.js.map +1 -1
- package/dist/lib/pi-adapter/pod-mirror.js +38 -107
- package/dist/lib/pi-adapter/pod-mirror.js.map +1 -1
- package/dist/lib/pi-adapter/pod-native.js +2 -0
- package/dist/lib/pi-adapter/pod-native.js.map +1 -1
- package/dist/lib/pi-adapter/pod-tools.js +140 -0
- package/dist/lib/pi-adapter/pod-tools.js.map +1 -0
- package/dist/lib/pi-adapter/runtime.js +2 -12
- package/dist/lib/pi-adapter/runtime.js.map +1 -1
- package/dist/lib/pi-adapter/session.js +13 -17
- package/dist/lib/pi-adapter/session.js.map +1 -1
- package/dist/lib/pi-adapter/stream.js +2 -20
- package/dist/lib/pi-adapter/stream.js.map +1 -1
- package/dist/lib/pod-chat-store.js +53 -4
- package/dist/lib/pod-chat-store.js.map +1 -1
- package/dist/lib/resource-identity.js +2 -0
- package/dist/lib/resource-identity.js.map +1 -0
- package/dist/lib/status-line-command.js +2 -2
- package/dist/lib/status-line-command.js.map +1 -1
- package/dist/lib/symphony/archive.js +15 -37
- package/dist/lib/symphony/archive.js.map +1 -1
- package/dist/lib/symphony/pod-projection.js +189 -1346
- package/dist/lib/symphony/pod-projection.js.map +1 -1
- package/dist/lib/symphony-command.js +209 -109
- package/dist/lib/symphony-command.js.map +1 -1
- package/dist/plugins/linx-symphony-codex/.codex-plugin/plugin.json +38 -0
- package/dist/plugins/linx-symphony-codex/.mcp.json +10 -0
- package/dist/plugins/linx-symphony-codex/README.md +9 -0
- package/dist/plugins/linx-symphony-codex/hooks.json +60 -0
- package/dist/plugins/linx-symphony-codex/scripts/symphony-hook-events.mjs +119 -0
- package/dist/plugins/linx-symphony-codex/scripts/symphony-mcp.mjs +335 -0
- package/dist/plugins/linx-symphony-codex/skills/symphony/SKILL.md +791 -0
- package/dist/skills/symphony/SKILL.md +7 -0
- package/dist/skills/xpod-cli/SKILL.md +2 -13
- package/package.json +4 -4
- package/vendor/agent-runtime/dist/chat-reconciler.d.ts +33 -0
- package/vendor/agent-runtime/dist/chat-reconciler.js +108 -0
- package/vendor/agent-runtime/dist/index.d.ts +4 -1
- package/vendor/agent-runtime/dist/index.js +4 -1
- package/vendor/agent-runtime/dist/matrix-client.d.ts +149 -0
- package/vendor/agent-runtime/dist/matrix-client.js +220 -0
- package/vendor/agent-runtime/dist/pod-resource-identity.d.ts +17 -0
- package/vendor/agent-runtime/dist/pod-resource-identity.js +54 -0
- package/vendor/agent-runtime/dist/reconciler.d.ts +0 -11
- package/vendor/agent-runtime/dist/reconciler.js +5 -43
- package/vendor/agent-runtime/dist/symphony.d.ts +272 -27
- package/vendor/agent-runtime/dist/symphony.js +1268 -21
- package/vendor/agent-runtime/dist/workspace.d.ts +61 -0
- package/vendor/agent-runtime/dist/workspace.js +81 -0
- package/vendor/agent-runtime/package.json +5 -1
- package/vendor/stores/dist/current-pod-base.d.ts +2 -0
- package/vendor/stores/dist/current-pod-base.js +14 -0
- package/vendor/stores/dist/exact-records.d.ts +7 -0
- package/vendor/stores/dist/exact-records.js +87 -0
- package/vendor/stores/dist/index.d.ts +1 -0
- package/vendor/stores/dist/index.js +1 -0
- package/vendor/stores/dist/login.d.ts +51 -0
- package/vendor/stores/dist/login.js +195 -0
- package/vendor/stores/dist/pod-collection.d.ts +28 -0
- package/vendor/stores/dist/pod-collection.js +194 -0
- package/vendor/stores/dist/pod-write-guard.d.ts +5 -0
- package/vendor/stores/dist/pod-write-guard.js +133 -0
- package/vendor/stores/dist/symphony-control.d.ts +245 -0
- package/vendor/stores/dist/symphony-control.js +2175 -0
- package/vendor/stores/package.json +14 -0
- package/dist/lib/capture/persistence.js +0 -377
- package/dist/lib/capture/persistence.js.map +0 -1
- package/dist/lib/capture/tool.js +0 -242
- package/dist/lib/capture/tool.js.map +0 -1
- package/dist/skills/basic/SKILL.md +0 -46
- package/dist/skills/capture/SKILL.md +0 -165
- package/vendor/agent-runtime/dist/coordination.d.ts +0 -93
- package/vendor/agent-runtime/dist/coordination.js +0 -145
|
@@ -8,7 +8,7 @@ import { listArchivedAutoModeSessions, runAutoMode } from '../auto-mode/runner.j
|
|
|
8
8
|
import { resolveAutoModeCommandRoute, } from '../../../vendor/agent-runtime/dist/auto-mode.js';
|
|
9
9
|
import { getAIConfigProviderCatalog, getAIConfigProviderMetadata } from '../models.js';
|
|
10
10
|
import { runSymphony } from '../symphony-command.js';
|
|
11
|
-
import { applyLinxInteractiveBranding, requestLinxCloudLogin } from './branding.js';
|
|
11
|
+
import { applyLinxInteractiveBranding, checkAndShowLinxUpdate, requestLinxCloudLogin } from './branding.js';
|
|
12
12
|
import { installPodStatusOutputFilter } from './pod-status-output.js';
|
|
13
13
|
import { createPodBackedExtensionUiContext } from './pod-approval.js';
|
|
14
14
|
import { DEFAULT_SECRETARY_CHAT_ID, secretaryChatUri, secretaryThreadUri } from './pod-mirror-mapping.js';
|
|
@@ -16,8 +16,8 @@ import { getSecretaryAutoInputController } from './auto-input-controller.js';
|
|
|
16
16
|
import { createSymphonyIdeaRecord, listSymphonyIssues, listSymphonySessions, } from '../symphony/archive.js';
|
|
17
17
|
import { listOpenSymphonyIssuesFromPod, listRecentSymphonyReportsFromPod, listRunningSymphonyWorkersFromPod, mirrorSymphonyProjectionJsonLdFromPod, persistSymphonyIdeaToPod, persistSymphonyControlStateToPod, } from '../symphony/pod-projection.js';
|
|
18
18
|
import { getSessionControlManager, installSessionControlRuntimeEventBridge, } from './session-control.js';
|
|
19
|
-
import {
|
|
20
|
-
let
|
|
19
|
+
import { buildLinxFooterStatusLine, calculateSessionUsage, DEFAULT_STATUS_LINE_TOKENS, formatTokenCount, LINX_STATUS_LINE_TOKEN_NAMES, parseLinxStatusLineColorArg, parseLinxStatusLineTokenArgs, readLinxStatusLineConfig, resetLinxStatusLineConfig, writeLinxStatusLineConfigPatch, } from '../linx-status-line.js';
|
|
20
|
+
let footerPatched = false;
|
|
21
21
|
let assistantMessagePatched = false;
|
|
22
22
|
let linxResumeOutputStyleRestore = null;
|
|
23
23
|
const BACKEND_OWNED_SLASH_COMMANDS = new Set([
|
|
@@ -29,7 +29,6 @@ const BACKEND_OWNED_SLASH_COMMANDS = new Set([
|
|
|
29
29
|
const SYMPHONY_STATUS_POD_TIMEOUT_MS = 1_200;
|
|
30
30
|
const DEFAULT_SYMPHONY_WORKER_SUPERVISOR_INTERVAL_MS = 10 * 60 * 1000;
|
|
31
31
|
const CODEX_STYLE_STATUS_LINE_TOKENS = [
|
|
32
|
-
'mode',
|
|
33
32
|
'model-with-reasoning',
|
|
34
33
|
'git-branch',
|
|
35
34
|
'context-remaining',
|
|
@@ -38,16 +37,20 @@ const CODEX_STYLE_STATUS_LINE_TOKENS = [
|
|
|
38
37
|
'current-dir',
|
|
39
38
|
];
|
|
40
39
|
const COMPACT_STATUS_LINE_TOKENS = [
|
|
41
|
-
'mode',
|
|
42
40
|
'model-with-reasoning',
|
|
43
41
|
'context-remaining',
|
|
44
42
|
'current-dir',
|
|
45
43
|
];
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
const STATUS_LINE_CODEX_PRESET_OPTION = 'Preset: Codex-style';
|
|
45
|
+
const STATUS_LINE_COMPACT_PRESET_OPTION = 'Preset: Compact';
|
|
46
|
+
const STATUS_LINE_TOGGLE_COLORS_OPTION = 'Toggle colors';
|
|
47
|
+
const STATUS_LINE_RESET_OPTION = 'Reset to default';
|
|
48
|
+
const STATUS_LINE_DONE_OPTION = 'Done';
|
|
49
|
+
/** Module-level reference to interactive for footer mode state (set during bootstrap). */
|
|
50
|
+
let _linxFooterInteractive = null;
|
|
48
51
|
export function bootstrapLinxInteractiveMode(runtime, options = {}) {
|
|
49
52
|
installLinxResumeOutputStyle();
|
|
50
|
-
|
|
53
|
+
patchPiFooter();
|
|
51
54
|
patchPiAssistantMessageRendering();
|
|
52
55
|
const sessionCwd = runtime?.cwd || process.cwd();
|
|
53
56
|
ensureInteractiveRuntimeHost(runtime);
|
|
@@ -55,7 +58,7 @@ export function bootstrapLinxInteractiveMode(runtime, options = {}) {
|
|
|
55
58
|
interactive.runtime = runtime;
|
|
56
59
|
interactive.__autoEnabled = runtime?.autoEnabled === true;
|
|
57
60
|
interactive.__linxSymphonyModeEnabled = runtime?.symphonyEnabled === true;
|
|
58
|
-
|
|
61
|
+
_linxFooterInteractive = interactive;
|
|
59
62
|
if (options.onSymphonyControlChange) {
|
|
60
63
|
;
|
|
61
64
|
interactive.__linxOnSymphonyControlChange = options.onSymphonyControlChange;
|
|
@@ -556,6 +559,9 @@ function parseLinxGlobalCommand(input) {
|
|
|
556
559
|
: input.slice('/status-line'.length).trim();
|
|
557
560
|
return { action: 'statusline', args: splitInteractiveCommandArgs(body) };
|
|
558
561
|
}
|
|
562
|
+
if (input === '/update' || input === '/upgrade') {
|
|
563
|
+
return { action: 'update' };
|
|
564
|
+
}
|
|
559
565
|
if (input === '/rewind') {
|
|
560
566
|
return { action: 'rewind-select' };
|
|
561
567
|
}
|
|
@@ -681,6 +687,10 @@ async function handleLinxGlobalCommand(interactive, runtime, command) {
|
|
|
681
687
|
await handleInteractiveStatusLineCommand(interactive, command.args);
|
|
682
688
|
return;
|
|
683
689
|
}
|
|
690
|
+
if (command.action === 'update') {
|
|
691
|
+
await checkAndShowLinxUpdate(interactive, { manual: true });
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
684
694
|
if (command.action === 'rewind-select') {
|
|
685
695
|
await handleInteractiveRewindSelector(interactive, runtime);
|
|
686
696
|
return;
|
|
@@ -697,53 +707,133 @@ async function handleInteractiveStatusLineCommand(interactive, args) {
|
|
|
697
707
|
return;
|
|
698
708
|
}
|
|
699
709
|
const summary = formatInteractiveStatusLineSummary();
|
|
700
|
-
if (typeof interactive.
|
|
701
|
-
interactive
|
|
702
|
-
interactive.ui?.requestRender?.();
|
|
710
|
+
if (typeof interactive.showSelector === 'function') {
|
|
711
|
+
await showInteractiveStatusLineMultiSelect(interactive);
|
|
703
712
|
return;
|
|
704
713
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
'Use compact preset',
|
|
708
|
-
'Configure tokens manually',
|
|
709
|
-
'Toggle colors',
|
|
710
|
-
'Show available tokens',
|
|
711
|
-
'Reset to default',
|
|
712
|
-
]);
|
|
713
|
-
if (choice === 'Use Codex-style preset') {
|
|
714
|
-
writeInteractiveStatusLineConfig(interactive, {
|
|
715
|
-
statusLine: CODEX_STYLE_STATUS_LINE_TOKENS,
|
|
716
|
-
message: 'Status line set to Codex-style preset.',
|
|
717
|
-
});
|
|
714
|
+
if (typeof interactive.showExtensionSelector === 'function') {
|
|
715
|
+
await showInteractiveStatusLineFallbackSelector(interactive);
|
|
718
716
|
return;
|
|
719
717
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
message: 'Status line set to compact preset.',
|
|
724
|
-
});
|
|
718
|
+
{
|
|
719
|
+
interactive.showStatus?.(`${summary} · Use /statusline set <tokens...>, /statusline tokens, /statusline colors <on|off>, or /statusline reset.`);
|
|
720
|
+
interactive.ui?.requestRender?.();
|
|
725
721
|
return;
|
|
726
722
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
723
|
+
}
|
|
724
|
+
async function showInteractiveStatusLineFallbackSelector(interactive) {
|
|
725
|
+
while (true) {
|
|
726
|
+
const currentSummary = formatInteractiveStatusLineSummary();
|
|
727
|
+
const config = readLinxStatusLineConfig();
|
|
728
|
+
const options = buildInteractiveStatusLineOptions(config);
|
|
729
|
+
const choice = await interactive.showExtensionSelector(`Status line\n${currentSummary}`, options);
|
|
730
|
+
if (!choice || choice === STATUS_LINE_DONE_OPTION) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const token = parseInteractiveStatusLineTokenChoice(choice);
|
|
734
|
+
if (token) {
|
|
735
|
+
toggleInteractiveStatusLineToken(interactive, token);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (choice === STATUS_LINE_CODEX_PRESET_OPTION) {
|
|
739
|
+
writeInteractiveStatusLineConfig(interactive, {
|
|
740
|
+
statusLine: CODEX_STYLE_STATUS_LINE_TOKENS,
|
|
741
|
+
message: 'Status line set to Codex-style preset.',
|
|
742
|
+
});
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
if (choice === STATUS_LINE_COMPACT_PRESET_OPTION) {
|
|
746
|
+
writeInteractiveStatusLineConfig(interactive, {
|
|
747
|
+
statusLine: COMPACT_STATUS_LINE_TOKENS,
|
|
748
|
+
message: 'Status line set to compact preset.',
|
|
749
|
+
});
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
if (choice === STATUS_LINE_TOGGLE_COLORS_OPTION) {
|
|
753
|
+
const current = readLinxStatusLineConfig();
|
|
754
|
+
writeInteractiveStatusLineConfig(interactive, {
|
|
755
|
+
statusLineUseColors: !current.useColors,
|
|
756
|
+
message: `Status line colors ${current.useColors ? 'disabled' : 'enabled'}.`,
|
|
757
|
+
});
|
|
758
|
+
continue;
|
|
759
|
+
}
|
|
760
|
+
if (choice === STATUS_LINE_RESET_OPTION) {
|
|
761
|
+
resetLinxStatusLineConfig();
|
|
762
|
+
finishInteractiveStatusLineUpdate(interactive, `Status line reset to default: ${DEFAULT_STATUS_LINE_TOKENS.join(', ')}`);
|
|
763
|
+
}
|
|
734
764
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
765
|
+
}
|
|
766
|
+
async function showInteractiveStatusLineMultiSelect(interactive) {
|
|
767
|
+
await new Promise((resolvePromise, rejectPromise) => {
|
|
768
|
+
let resolved = false;
|
|
769
|
+
const resolveOnce = () => {
|
|
770
|
+
if (!resolved) {
|
|
771
|
+
resolved = true;
|
|
772
|
+
resolvePromise();
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
try {
|
|
776
|
+
interactive.showSelector((done) => {
|
|
777
|
+
const close = () => {
|
|
778
|
+
done();
|
|
779
|
+
resolveOnce();
|
|
780
|
+
};
|
|
781
|
+
const selector = new LinxStatusLineSelectorComponent(readLinxStatusLineConfig(), ({ tokens, useColors }) => {
|
|
782
|
+
writeInteractiveStatusLineConfig(interactive, {
|
|
783
|
+
statusLine: tokens,
|
|
784
|
+
statusLineUseColors: useColors,
|
|
785
|
+
message: `Status line updated: ${tokens.join(', ')}`,
|
|
786
|
+
});
|
|
787
|
+
close();
|
|
788
|
+
}, () => {
|
|
789
|
+
close();
|
|
790
|
+
interactive.ui?.requestRender?.();
|
|
791
|
+
});
|
|
792
|
+
return { component: selector, focus: selector.getList() };
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
catch (error) {
|
|
796
|
+
rejectPromise(error);
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
function buildInteractiveStatusLineOptions(config = readLinxStatusLineConfig()) {
|
|
801
|
+
const enabled = new Set(config.tokens);
|
|
802
|
+
return [
|
|
803
|
+
...LINX_STATUS_LINE_TOKEN_NAMES.map((token) => `${enabled.has(token) ? '✓' : '○'} ${token}`),
|
|
804
|
+
STATUS_LINE_CODEX_PRESET_OPTION,
|
|
805
|
+
STATUS_LINE_COMPACT_PRESET_OPTION,
|
|
806
|
+
STATUS_LINE_TOGGLE_COLORS_OPTION,
|
|
807
|
+
STATUS_LINE_RESET_OPTION,
|
|
808
|
+
STATUS_LINE_DONE_OPTION,
|
|
809
|
+
];
|
|
810
|
+
}
|
|
811
|
+
function parseInteractiveStatusLineTokenChoice(choice) {
|
|
812
|
+
if (typeof choice !== 'string') {
|
|
813
|
+
return null;
|
|
738
814
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
return;
|
|
815
|
+
const token = choice.replace(/^[✓○]\s*/u, '').trim();
|
|
816
|
+
if (!token) {
|
|
817
|
+
return null;
|
|
743
818
|
}
|
|
744
|
-
|
|
745
|
-
|
|
819
|
+
return LINX_STATUS_LINE_TOKEN_NAMES.includes(token)
|
|
820
|
+
? token
|
|
821
|
+
: null;
|
|
822
|
+
}
|
|
823
|
+
function toggleInteractiveStatusLineToken(interactive, token) {
|
|
824
|
+
const current = readLinxStatusLineConfig().tokens;
|
|
825
|
+
const exists = current.includes(token);
|
|
826
|
+
if (exists && current.length <= 1) {
|
|
827
|
+
interactive.showError?.('Status line needs at least one item.');
|
|
828
|
+
return;
|
|
746
829
|
}
|
|
830
|
+
const next = exists
|
|
831
|
+
? current.filter((item) => item !== token)
|
|
832
|
+
: [...current, token];
|
|
833
|
+
writeInteractiveStatusLineConfig(interactive, {
|
|
834
|
+
statusLine: next,
|
|
835
|
+
message: `Status line ${exists ? 'removed' : 'added'}: ${token}`,
|
|
836
|
+
});
|
|
747
837
|
}
|
|
748
838
|
function handleInteractiveStatusLineArgs(interactive, args) {
|
|
749
839
|
const action = args[0]?.toLowerCase();
|
|
@@ -781,20 +871,6 @@ function handleInteractiveStatusLineArgs(interactive, args) {
|
|
|
781
871
|
interactive.showError?.(`${message}. Use /statusline tokens to list valid tokens.`);
|
|
782
872
|
}
|
|
783
873
|
}
|
|
784
|
-
async function promptInteractiveStatusLineTokens(interactive) {
|
|
785
|
-
if (typeof interactive.showExtensionInput !== 'function') {
|
|
786
|
-
interactive.showStatus?.(`Use /statusline set ${CODEX_STYLE_STATUS_LINE_TOKENS.join(' ')}`);
|
|
787
|
-
interactive.ui?.requestRender?.();
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
const value = await interactive.showExtensionInput('Status line tokens', CODEX_STYLE_STATUS_LINE_TOKENS.join(' '));
|
|
791
|
-
if (typeof value !== 'string' || !value.trim()) {
|
|
792
|
-
interactive.showStatus?.('Status line unchanged.');
|
|
793
|
-
interactive.ui?.requestRender?.();
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
handleInteractiveStatusLineArgs(interactive, ['set', ...splitInteractiveCommandArgs(value)]);
|
|
797
|
-
}
|
|
798
874
|
function writeInteractiveStatusLineConfig(interactive, patch) {
|
|
799
875
|
writeLinxStatusLineConfigPatch({
|
|
800
876
|
...(patch.statusLine ? { statusLine: patch.statusLine } : {}),
|
|
@@ -891,15 +967,14 @@ async function handleInteractiveRewindTurnsCommand(interactive, runtime, turns)
|
|
|
891
967
|
interactive.ui?.requestRender?.();
|
|
892
968
|
}
|
|
893
969
|
async function rewindSessionManagerBeforeUserEntry(interactive, runtime, session, sessionManager, entryId) {
|
|
894
|
-
const
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
if (entry.type !== 'message' || entry.message?.role !== 'user') {
|
|
900
|
-
throw new Error('Cannot rewind: selected message is not a user turn.');
|
|
970
|
+
const entry = typeof sessionManager?.getEntry === 'function'
|
|
971
|
+
? sessionManager.getEntry(entryId)
|
|
972
|
+
: getActiveSessionBranch(sessionManager).find((candidate) => candidate?.id === entryId);
|
|
973
|
+
if (!entry || entry.type !== 'message' || entry.message?.role !== 'user') {
|
|
974
|
+
throw new Error('Cannot rewind: selected message is not a user turn in the active branch.');
|
|
901
975
|
}
|
|
902
976
|
const previousState = captureRewindSessionState(sessionManager);
|
|
977
|
+
const previousBranch = getActiveSessionBranch(sessionManager);
|
|
903
978
|
await stopActiveSessionWorkForRewind(session);
|
|
904
979
|
resetPendingAutoInputForRewind(interactive, runtime);
|
|
905
980
|
const targetLeafId = typeof entry.parentId === 'string' && entry.parentId ? entry.parentId : null;
|
|
@@ -1162,6 +1237,178 @@ function refreshInteractiveTranscriptFromSessionManager(interactive) {
|
|
|
1162
1237
|
interactive?.showWarning?.(`Rewind transcript refresh failed: ${message}`);
|
|
1163
1238
|
}
|
|
1164
1239
|
}
|
|
1240
|
+
class LinxMultiSelectList {
|
|
1241
|
+
getRows;
|
|
1242
|
+
onToggle;
|
|
1243
|
+
onAction;
|
|
1244
|
+
onCancel;
|
|
1245
|
+
selectedIndex = 0;
|
|
1246
|
+
constructor(getRows, onToggle, onAction, onCancel) {
|
|
1247
|
+
this.getRows = getRows;
|
|
1248
|
+
this.onToggle = onToggle;
|
|
1249
|
+
this.onAction = onAction;
|
|
1250
|
+
this.onCancel = onCancel;
|
|
1251
|
+
}
|
|
1252
|
+
invalidate() {
|
|
1253
|
+
// No cached render state.
|
|
1254
|
+
}
|
|
1255
|
+
render(width) {
|
|
1256
|
+
const rows = this.normalizedRows();
|
|
1257
|
+
if (rows.length === 0) {
|
|
1258
|
+
return [' No options'];
|
|
1259
|
+
}
|
|
1260
|
+
const lines = [];
|
|
1261
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
1262
|
+
const row = rows[index];
|
|
1263
|
+
const cursor = index === this.selectedIndex ? '> ' : ' ';
|
|
1264
|
+
const label = row.kind === 'item'
|
|
1265
|
+
? `${row.selected ? '✓' : '○'} ${row.label}`
|
|
1266
|
+
: row.label;
|
|
1267
|
+
lines.push(`${cursor}${truncateToWidth(label, Math.max(1, width - 2))}`);
|
|
1268
|
+
if (row.description) {
|
|
1269
|
+
lines.push(` ${truncateToWidth(row.description, Math.max(1, width - 2))}`);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
lines.push('');
|
|
1273
|
+
lines.push('↑↓ navigate Enter toggles items/actions Escape/Ctrl+C cancel');
|
|
1274
|
+
return lines;
|
|
1275
|
+
}
|
|
1276
|
+
handleInput(keyData) {
|
|
1277
|
+
const rows = this.normalizedRows();
|
|
1278
|
+
if (rows.length === 0) {
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
const keybindings = getKeybindings();
|
|
1282
|
+
if (keybindings.matches(keyData, 'tui.select.up')) {
|
|
1283
|
+
this.selectedIndex = this.selectedIndex === 0 ? rows.length - 1 : this.selectedIndex - 1;
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
if (keybindings.matches(keyData, 'tui.select.down')) {
|
|
1287
|
+
this.selectedIndex = this.selectedIndex === rows.length - 1 ? 0 : this.selectedIndex + 1;
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
if (keybindings.matches(keyData, 'tui.select.confirm')) {
|
|
1291
|
+
const selected = rows[this.selectedIndex];
|
|
1292
|
+
if (selected?.kind === 'item') {
|
|
1293
|
+
this.onToggle(selected.id);
|
|
1294
|
+
}
|
|
1295
|
+
else if (selected?.kind === 'action') {
|
|
1296
|
+
this.onAction(selected.id);
|
|
1297
|
+
}
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
if (keybindings.matches(keyData, 'tui.select.cancel')) {
|
|
1301
|
+
this.onCancel();
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
normalizedRows() {
|
|
1305
|
+
const rows = this.getRows();
|
|
1306
|
+
if (this.selectedIndex >= rows.length) {
|
|
1307
|
+
this.selectedIndex = Math.max(0, rows.length - 1);
|
|
1308
|
+
}
|
|
1309
|
+
return rows;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
class LinxStatusLineSelectorComponent extends Container {
|
|
1313
|
+
list;
|
|
1314
|
+
draftTokens;
|
|
1315
|
+
draftUseColors;
|
|
1316
|
+
notice = null;
|
|
1317
|
+
constructor(config, onCommit, onCancel) {
|
|
1318
|
+
super();
|
|
1319
|
+
this.draftTokens = [...config.tokens];
|
|
1320
|
+
this.draftUseColors = config.useColors;
|
|
1321
|
+
this.addChild(new Spacer(1));
|
|
1322
|
+
this.addChild(new Text('Status line', 1, 0));
|
|
1323
|
+
this.addChild(new Text('Select the items that appear in the bottom TUI status line.', 1, 0));
|
|
1324
|
+
this.addChild(new Text(`Current source: tokens ${config.tokenSource}, colors ${config.colorSource}.`, 1, 0));
|
|
1325
|
+
this.addChild(new Spacer(1));
|
|
1326
|
+
this.list = new LinxMultiSelectList(() => this.rows(), (id) => this.toggleToken(id), (id) => this.handleAction(id, onCommit), onCancel);
|
|
1327
|
+
this.addChild(this.list);
|
|
1328
|
+
}
|
|
1329
|
+
getList() {
|
|
1330
|
+
return this.list;
|
|
1331
|
+
}
|
|
1332
|
+
rows() {
|
|
1333
|
+
const enabled = new Set(this.draftTokens);
|
|
1334
|
+
const rows = LINX_STATUS_LINE_TOKEN_NAMES.map((token) => ({
|
|
1335
|
+
kind: 'item',
|
|
1336
|
+
id: token,
|
|
1337
|
+
label: token,
|
|
1338
|
+
selected: enabled.has(token),
|
|
1339
|
+
}));
|
|
1340
|
+
rows.push({
|
|
1341
|
+
kind: 'action',
|
|
1342
|
+
id: 'preset-codex',
|
|
1343
|
+
label: STATUS_LINE_CODEX_PRESET_OPTION,
|
|
1344
|
+
description: CODEX_STYLE_STATUS_LINE_TOKENS.join(', '),
|
|
1345
|
+
}, {
|
|
1346
|
+
kind: 'action',
|
|
1347
|
+
id: 'preset-compact',
|
|
1348
|
+
label: STATUS_LINE_COMPACT_PRESET_OPTION,
|
|
1349
|
+
description: COMPACT_STATUS_LINE_TOKENS.join(', '),
|
|
1350
|
+
}, {
|
|
1351
|
+
kind: 'action',
|
|
1352
|
+
id: 'toggle-colors',
|
|
1353
|
+
label: `${STATUS_LINE_TOGGLE_COLORS_OPTION}: ${this.draftUseColors ? 'on' : 'off'}`,
|
|
1354
|
+
}, {
|
|
1355
|
+
kind: 'action',
|
|
1356
|
+
id: 'reset',
|
|
1357
|
+
label: STATUS_LINE_RESET_OPTION,
|
|
1358
|
+
description: DEFAULT_STATUS_LINE_TOKENS.join(', '),
|
|
1359
|
+
}, {
|
|
1360
|
+
kind: 'action',
|
|
1361
|
+
id: 'done',
|
|
1362
|
+
label: STATUS_LINE_DONE_OPTION,
|
|
1363
|
+
description: this.notice ?? 'Save changes and close.',
|
|
1364
|
+
});
|
|
1365
|
+
return rows;
|
|
1366
|
+
}
|
|
1367
|
+
toggleToken(id) {
|
|
1368
|
+
const token = id;
|
|
1369
|
+
if (!LINX_STATUS_LINE_TOKEN_NAMES.includes(token)) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
const exists = this.draftTokens.includes(token);
|
|
1373
|
+
if (exists && this.draftTokens.length <= 1) {
|
|
1374
|
+
this.notice = 'Status line needs at least one item.';
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
this.draftTokens = exists
|
|
1378
|
+
? this.draftTokens.filter((item) => item !== token)
|
|
1379
|
+
: [...this.draftTokens, token];
|
|
1380
|
+
this.notice = null;
|
|
1381
|
+
}
|
|
1382
|
+
handleAction(id, onCommit) {
|
|
1383
|
+
if (id === 'preset-codex') {
|
|
1384
|
+
this.draftTokens = [...CODEX_STYLE_STATUS_LINE_TOKENS];
|
|
1385
|
+
this.notice = 'Draft changed to Codex-style preset.';
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
if (id === 'preset-compact') {
|
|
1389
|
+
this.draftTokens = [...COMPACT_STATUS_LINE_TOKENS];
|
|
1390
|
+
this.notice = 'Draft changed to compact preset.';
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
if (id === 'toggle-colors') {
|
|
1394
|
+
this.draftUseColors = !this.draftUseColors;
|
|
1395
|
+
this.notice = `Draft colors ${this.draftUseColors ? 'enabled' : 'disabled'}.`;
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (id === 'reset') {
|
|
1399
|
+
this.draftTokens = [...DEFAULT_STATUS_LINE_TOKENS];
|
|
1400
|
+
this.draftUseColors = true;
|
|
1401
|
+
this.notice = 'Draft reset to default.';
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
if (id === 'done') {
|
|
1405
|
+
onCommit({
|
|
1406
|
+
tokens: this.draftTokens,
|
|
1407
|
+
useColors: this.draftUseColors,
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1165
1412
|
function collectRewindUserMessages(_session, sessionManager) {
|
|
1166
1413
|
return getActiveSessionBranch(sessionManager)
|
|
1167
1414
|
.filter((entry) => entry?.type === 'message' && entry.message?.role === 'user')
|
|
@@ -1523,6 +1770,10 @@ const LINX_INTERACTIVE_SLASH_COMMANDS = [
|
|
|
1523
1770
|
{ value: 'reset', description: 'Restore default status line tokens' },
|
|
1524
1771
|
]),
|
|
1525
1772
|
},
|
|
1773
|
+
{
|
|
1774
|
+
name: 'update',
|
|
1775
|
+
description: 'check for a LinX CLI update and install from the TUI',
|
|
1776
|
+
},
|
|
1526
1777
|
{
|
|
1527
1778
|
name: 'ai',
|
|
1528
1779
|
argumentHint: 'connect <provider>',
|
|
@@ -1673,12 +1924,7 @@ function renderSymphonySecretaryProjection(input) {
|
|
|
1673
1924
|
'Default response style: reply like normal chat.',
|
|
1674
1925
|
'Do not print internal Symphony binding, Issue/Task routing, worker selection, or report-style sections unless a visible state change or blocker must be surfaced.',
|
|
1675
1926
|
'If the message is ordinary chat or early exploration, answer directly and do not explain that it was not delegated.',
|
|
1676
|
-
'If real delegation is needed,
|
|
1677
|
-
'When you need to inspect or mutate Symphony Pod resources from the AI side, use the xpod CLI as the direct Pod tool surface.',
|
|
1678
|
-
'Prefer model-backed xpod obj commands for Idea, Issue, Task, Delivery, Run, RunStep, Report, Evidence, ApprovalRequest, InputRequest, and InboxNotification resources.',
|
|
1679
|
-
'xpod uses the same Solid authority as LinX inside the Agent Runtime; do not ask the model to handle tokens or client secrets.',
|
|
1680
|
-
'Before mutating Pod resources from tools, verify xpod auth status/whoami reports the same acting WebID/Pod root as the LinX session; stop on mismatch.',
|
|
1681
|
-
'Do not hand-patch TTL or guess Pod paths for modeled product resources; use xpod/model descriptors or inspect existing links first.',
|
|
1927
|
+
'If real delegation is needed, summarize the visible handoff result briefly after updating control state.',
|
|
1682
1928
|
'',
|
|
1683
1929
|
'User message:',
|
|
1684
1930
|
input,
|
|
@@ -1727,9 +1973,8 @@ async function dispatchSymphonyWorkerFromInteractive(interactive, objective, sou
|
|
|
1727
1973
|
target: {
|
|
1728
1974
|
source: 'active-session',
|
|
1729
1975
|
backend,
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
label: backend,
|
|
1976
|
+
agent: `${backend}-worker`,
|
|
1977
|
+
label: `${backend} worker`,
|
|
1733
1978
|
...(source?.chat ? { chat: source.chat } : {}),
|
|
1734
1979
|
...(source?.thread ? { thread: source.thread } : {}),
|
|
1735
1980
|
},
|
|
@@ -2078,8 +2323,8 @@ async function formatSymphonyStatus(interactive) {
|
|
|
2078
2323
|
? 'Pod control state: active.'
|
|
2079
2324
|
: 'Pod control state: portable local archive mode.',
|
|
2080
2325
|
'Skills: issue triage, existing issue lookup, create/update/ask decision, task split, worker dispatch, status/report tracking.',
|
|
2081
|
-
'Delegation target: AI Secretary
|
|
2082
|
-
'Allowed targets: personal AI contact chat or group chat
|
|
2326
|
+
'Delegation target: AI Secretary must choose a Chat resource before dispatch.',
|
|
2327
|
+
'Allowed targets: personal AI contact chat or group chat.',
|
|
2083
2328
|
'Thread role: concrete work timeline under the selected Chat.',
|
|
2084
2329
|
'Session role: backend runtime lifecycle only.',
|
|
2085
2330
|
];
|
|
@@ -2247,7 +2492,6 @@ async function listRecentSymphonyReports(interactive) {
|
|
|
2247
2492
|
}
|
|
2248
2493
|
function formatSymphonyWorkerStatus(session) {
|
|
2249
2494
|
const target = session.target?.label
|
|
2250
|
-
?? session.target?.contact
|
|
2251
2495
|
?? session.target?.agent
|
|
2252
2496
|
?? session.target?.chat
|
|
2253
2497
|
?? session.backend;
|
|
@@ -2261,10 +2505,8 @@ function formatSymphonyWorkerStatus(session) {
|
|
|
2261
2505
|
function formatSymphonyReportStatus(report) {
|
|
2262
2506
|
const status = report.status;
|
|
2263
2507
|
const reportRecord = report;
|
|
2264
|
-
const target = reportRecord.
|
|
2265
|
-
?? reportRecord.
|
|
2266
|
-
?? reportRecord.target?.contact
|
|
2267
|
-
?? reportRecord.agent
|
|
2508
|
+
const target = reportRecord.agent
|
|
2509
|
+
?? reportRecord.target?.label
|
|
2268
2510
|
?? reportRecord.target?.agent
|
|
2269
2511
|
?? report.backend;
|
|
2270
2512
|
const title = 'summary' in report && report.summary
|
|
@@ -2869,42 +3111,40 @@ function isPotentialPiResumeOutput(text) {
|
|
|
2869
3111
|
function stripAnsi(text) {
|
|
2870
3112
|
return text.replace(/\x1b\[[0-9;]*m/gu, '');
|
|
2871
3113
|
}
|
|
2872
|
-
function
|
|
2873
|
-
if (
|
|
3114
|
+
function patchPiFooter() {
|
|
3115
|
+
if (footerPatched) {
|
|
2874
3116
|
return;
|
|
2875
3117
|
}
|
|
2876
3118
|
const originalRender = FooterComponent.prototype.render;
|
|
2877
3119
|
FooterComponent.prototype.render = function patchedRender(width) {
|
|
2878
3120
|
const lines = originalRender.call(this, width);
|
|
2879
|
-
if (Array.isArray(lines)) {
|
|
3121
|
+
if (Array.isArray(lines) && lines.length > 1 && typeof lines[1] === 'string') {
|
|
2880
3122
|
const session = this.session;
|
|
2881
3123
|
const autoCompactEnabled = this.autoCompactEnabled !== false;
|
|
2882
3124
|
const footerData = this.footerData;
|
|
2883
|
-
const
|
|
3125
|
+
const modePrefix = buildLinxFooterModePrefix();
|
|
3126
|
+
const modeLen = visibleWidth(modePrefix);
|
|
3127
|
+
const bulletLen = modeLen > 0 ? 3 : 0;
|
|
3128
|
+
const statusWidth = Math.max(0, width - modeLen - bulletLen);
|
|
3129
|
+
lines[1] = buildLinxFooterStatusLine({
|
|
2884
3130
|
session,
|
|
2885
|
-
width,
|
|
3131
|
+
width: statusWidth,
|
|
2886
3132
|
autoCompactEnabled,
|
|
2887
3133
|
footerData: footerData,
|
|
2888
|
-
modeLabel: buildLinxStatusLineModeLabel(),
|
|
2889
3134
|
});
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
// append the configurable status line after notices to keep it the
|
|
2893
|
-
// bottom-most line.
|
|
2894
|
-
if (lines.length > 1 && typeof lines[1] === 'string') {
|
|
2895
|
-
lines.splice(1, 1);
|
|
3135
|
+
if (modePrefix) {
|
|
3136
|
+
lines[1] = modePrefix + ' • ' + lines[1];
|
|
2896
3137
|
}
|
|
2897
|
-
lines.push(statusLine);
|
|
2898
3138
|
}
|
|
2899
3139
|
return lines;
|
|
2900
3140
|
};
|
|
2901
|
-
|
|
3141
|
+
footerPatched = true;
|
|
2902
3142
|
}
|
|
2903
|
-
function
|
|
2904
|
-
if (!
|
|
3143
|
+
function buildLinxFooterModePrefix() {
|
|
3144
|
+
if (!_linxFooterInteractive)
|
|
2905
3145
|
return '';
|
|
2906
|
-
const autoOn =
|
|
2907
|
-
const symphonyOn =
|
|
3146
|
+
const autoOn = _linxFooterInteractive.__autoEnabled === true;
|
|
3147
|
+
const symphonyOn = _linxFooterInteractive.__linxSymphonyModeEnabled === true;
|
|
2908
3148
|
if (!autoOn && !symphonyOn)
|
|
2909
3149
|
return '';
|
|
2910
3150
|
if (autoOn && symphonyOn)
|