@agimon-ai/po-web-dashboard 0.0.0-alpha.65 → 0.0.0-alpha.67
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/web/features/remote/RemoteAccessPairing.cjs +6 -5
- package/dist/web/features/remote/RemoteAccessPairing.cjs.map +1 -1
- package/dist/web/features/remote/RemoteAccessPairing.mjs +6 -5
- package/dist/web/features/remote/RemoteAccessPairing.mjs.map +1 -1
- package/dist/web/features/selection/SelectionBar.cjs +1 -1
- package/dist/web/features/selection/SelectionBar.cjs.map +1 -1
- package/dist/web/features/selection/SelectionBar.mjs +1 -1
- package/dist/web/features/selection/SelectionBar.mjs.map +1 -1
- package/dist/web/lib/composition.cjs +1 -1
- package/dist/web/lib/composition.cjs.map +1 -1
- package/dist/web/lib/composition.mjs +1 -1
- package/dist/web/lib/composition.mjs.map +1 -1
- package/dist/web/lib/sessionModel.cjs +4 -0
- package/dist/web/lib/sessionModel.cjs.map +1 -1
- package/dist/web/lib/sessionModel.d.mts.map +1 -1
- package/dist/web/lib/sessionModel.mjs +4 -0
- package/dist/web/lib/sessionModel.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -33,7 +33,7 @@ function RemoteAccessPairing() {
|
|
|
33
33
|
}),
|
|
34
34
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
35
35
|
className: "text-center text-sm text-po-dim",
|
|
36
|
-
children: target === "native" ? "Scan with the phone camera to open the Po app
|
|
36
|
+
children: target === "native" ? "Scan with the phone camera to open the Po app. Scanning from inside Po? Use the Browser code, or paste the address below." : "Scan with the phone camera to open Po in the phone browser."
|
|
37
37
|
}),
|
|
38
38
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
39
39
|
className: "rounded-lg bg-po-hi p-3 text-po-deep",
|
|
@@ -43,14 +43,14 @@ function RemoteAccessPairing() {
|
|
|
43
43
|
label: "Scan to pair this device"
|
|
44
44
|
})
|
|
45
45
|
}),
|
|
46
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
46
|
+
target === "web" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
47
47
|
className: "flex w-full flex-col gap-1",
|
|
48
48
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_agimon_ai_po_web_components.SectionLabel, { children: "or enter this pairing code" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
49
49
|
"data-testid": "remote-pair-code",
|
|
50
50
|
className: "rounded bg-po-deep p-2 text-center font-mono text-lg tracking-widest text-po-text",
|
|
51
51
|
children: state.pairCode
|
|
52
52
|
})]
|
|
53
|
-
}),
|
|
53
|
+
}) : null,
|
|
54
54
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55
55
|
className: "flex w-full flex-col gap-1",
|
|
56
56
|
children: [
|
|
@@ -63,7 +63,8 @@ function RemoteAccessPairing() {
|
|
|
63
63
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
64
64
|
className: "text-sm text-po-dim",
|
|
65
65
|
children: [
|
|
66
|
-
"Compare this on the phone when entering the manual code.
|
|
66
|
+
target === "web" ? "Compare this on the phone when entering the manual code. " : "",
|
|
67
|
+
"Bundle revision ",
|
|
67
68
|
String(state.pairRevision),
|
|
68
69
|
"."
|
|
69
70
|
]
|
|
@@ -72,7 +73,7 @@ function RemoteAccessPairing() {
|
|
|
72
73
|
}),
|
|
73
74
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
74
75
|
className: "flex w-full flex-col gap-1",
|
|
75
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_agimon_ai_po_web_components.SectionLabel, { children: "or open this address" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
76
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_agimon_ai_po_web_components.SectionLabel, { children: target === "native" ? "or paste this address in the app" : "or open this address" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
76
77
|
"data-testid": "remote-pair-url",
|
|
77
78
|
className: "break-all rounded bg-po-deep p-2 text-sm text-po-dim",
|
|
78
79
|
children: state.pairUrl
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteAccessPairing.cjs","names":["useStore","remoteAccessStore","Spinner","NATIVE_PAIRING_LINK_PREFIX","Tabs","choosePairTarget","TabsList","TabsTrigger","QrCode","SectionLabel","Button","newPairingCode","addPasskey","PairedDeviceList"],"sources":["../../../../src/web/features/remote/RemoteAccessPairing.tsx"],"sourcesContent":["import { Button, SectionLabel, Spinner, Tabs, TabsList, TabsTrigger } from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\n\nimport { NATIVE_PAIRING_LINK_PREFIX } from '../../../types/remoteAccess';\nimport { QrCode } from '../../components/QrCode';\nimport {\n addPasskey,\n choosePairTarget,\n newPairingCode,\n type PairTarget,\n remoteAccessStore,\n} from '../../stores/remoteAccessStore';\nimport { PairedDeviceList } from './PairedDeviceList';\n\n/** The QR credential, a short manual code, and the direct address. */\nexport function RemoteAccessPairing() {\n const state = useStore(remoteAccessStore);\n if (state.pairUrl === undefined || state.pairCode === undefined || state.pairFingerprint === undefined)\n return <Spinner />;\n const target = state.pairTarget ?? 'web';\n // The app link wraps the same credential, so one code serves either; only its opener differs.\n const qrValue =\n target === 'native' ? `${NATIVE_PAIRING_LINK_PREFIX}${encodeURIComponent(state.pairUrl)}` : state.pairUrl;\n\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <Tabs value={target} onValueChange={(value) => choosePairTarget(value as PairTarget)}>\n <TabsList aria-label=\"Pair with\">\n <TabsTrigger value=\"web\" data-testid=\"remote-pair-target-web\">\n Browser\n </TabsTrigger>\n <TabsTrigger value=\"native\" data-testid=\"remote-pair-target-native\">\n Po app\n </TabsTrigger>\n </TabsList>\n </Tabs>\n <p className=\"text-center text-sm text-po-dim\">\n {target === 'native'\n ? 'Scan with the phone camera to open the Po app
|
|
1
|
+
{"version":3,"file":"RemoteAccessPairing.cjs","names":["useStore","remoteAccessStore","Spinner","NATIVE_PAIRING_LINK_PREFIX","Tabs","choosePairTarget","TabsList","TabsTrigger","QrCode","SectionLabel","Button","newPairingCode","addPasskey","PairedDeviceList"],"sources":["../../../../src/web/features/remote/RemoteAccessPairing.tsx"],"sourcesContent":["import { Button, SectionLabel, Spinner, Tabs, TabsList, TabsTrigger } from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\n\nimport { NATIVE_PAIRING_LINK_PREFIX } from '../../../types/remoteAccess';\nimport { QrCode } from '../../components/QrCode';\nimport {\n addPasskey,\n choosePairTarget,\n newPairingCode,\n type PairTarget,\n remoteAccessStore,\n} from '../../stores/remoteAccessStore';\nimport { PairedDeviceList } from './PairedDeviceList';\n\n/** The QR credential, a short manual code, and the direct address. */\nexport function RemoteAccessPairing() {\n const state = useStore(remoteAccessStore);\n if (state.pairUrl === undefined || state.pairCode === undefined || state.pairFingerprint === undefined)\n return <Spinner />;\n const target = state.pairTarget ?? 'web';\n // The app link wraps the same credential, so one code serves either; only its opener differs.\n const qrValue =\n target === 'native' ? `${NATIVE_PAIRING_LINK_PREFIX}${encodeURIComponent(state.pairUrl)}` : state.pairUrl;\n\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <Tabs value={target} onValueChange={(value) => choosePairTarget(value as PairTarget)}>\n <TabsList aria-label=\"Pair with\">\n <TabsTrigger value=\"web\" data-testid=\"remote-pair-target-web\">\n Browser\n </TabsTrigger>\n <TabsTrigger value=\"native\" data-testid=\"remote-pair-target-native\">\n Po app\n </TabsTrigger>\n </TabsList>\n </Tabs>\n <p className=\"text-center text-sm text-po-dim\">\n {target === 'native'\n ? 'Scan with the phone camera to open the Po app. Scanning from inside Po? Use the Browser code, or paste the address below.'\n : 'Scan with the phone camera to open Po in the phone browser.'}\n </p>\n {/* A light plate under the code: scanners want dark modules on a bright\n field, which is the one thing a dark theme cannot supply. */}\n <div className=\"rounded-lg bg-po-hi p-3 text-po-deep\">\n <QrCode value={qrValue} size={288} label=\"Scan to pair this device\" />\n </div>\n {target === 'web' ? (\n <div className=\"flex w-full flex-col gap-1\">\n <SectionLabel>or enter this pairing code</SectionLabel>\n <code\n data-testid=\"remote-pair-code\"\n className=\"rounded bg-po-deep p-2 text-center font-mono text-lg tracking-widest text-po-text\"\n >\n {state.pairCode}\n </code>\n </div>\n ) : null}\n <div className=\"flex w-full flex-col gap-1\">\n <SectionLabel>signing-key fingerprint</SectionLabel>\n <code\n data-testid=\"remote-signing-fingerprint\"\n className=\"break-all rounded bg-po-deep p-2 text-center font-mono text-sm text-po-text\"\n >\n {state.pairFingerprint.match(/.{1,8}/gu)?.join(' ') ?? state.pairFingerprint}\n </code>\n <p className=\"text-sm text-po-dim\">\n {target === 'web' ? 'Compare this on the phone when entering the manual code. ' : ''}\n Bundle revision {String(state.pairRevision)}.\n </p>\n </div>\n <div className=\"flex w-full flex-col gap-1\">\n <SectionLabel>{target === 'native' ? 'or paste this address in the app' : 'or open this address'}</SectionLabel>\n <code data-testid=\"remote-pair-url\" className=\"break-all rounded bg-po-deep p-2 text-sm text-po-dim\">\n {state.pairUrl}\n </code>\n </div>\n <Button variant=\"ghost\" size=\"sm\" data-testid=\"remote-new-code\" onClick={() => void newPairingCode()}>\n Show a new code\n </Button>\n\n {/* Enrolling a passkey turns every later visit into one Face ID instead\n of another scan, and it is what puts a second factor in front of the\n two actions that escalate past driving the agent. */}\n {state.passkeys?.supported === true ? (\n <div className=\"flex w-full flex-col gap-1.5 border-t border-po-border pt-3\">\n <SectionLabel>passkeys</SectionLabel>\n <p className=\"text-sm text-po-dim\">\n {state.passkeys.count === 0\n ? 'Add one on the device you just paired and it will not need the code again.'\n : `${String(state.passkeys.count)} registered. A paired device signs in with a gesture instead of a code.`}\n </p>\n <Button variant=\"outline\" size=\"sm\" data-testid=\"remote-add-passkey\" onClick={() => void addPasskey()}>\n Add a passkey for this device\n </Button>\n </div>\n ) : state.passkeys?.reason === undefined ? null : (\n <p data-testid=\"remote-passkey-unavailable\" className=\"w-full text-sm text-po-dim\">\n {state.passkeys.reason}\n </p>\n )}\n\n <PairedDeviceList />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -33,7 +33,7 @@ function RemoteAccessPairing() {
|
|
|
33
33
|
}),
|
|
34
34
|
/* @__PURE__ */ jsx("p", {
|
|
35
35
|
className: "text-center text-sm text-po-dim",
|
|
36
|
-
children: target === "native" ? "Scan with the phone camera to open the Po app
|
|
36
|
+
children: target === "native" ? "Scan with the phone camera to open the Po app. Scanning from inside Po? Use the Browser code, or paste the address below." : "Scan with the phone camera to open Po in the phone browser."
|
|
37
37
|
}),
|
|
38
38
|
/* @__PURE__ */ jsx("div", {
|
|
39
39
|
className: "rounded-lg bg-po-hi p-3 text-po-deep",
|
|
@@ -43,14 +43,14 @@ function RemoteAccessPairing() {
|
|
|
43
43
|
label: "Scan to pair this device"
|
|
44
44
|
})
|
|
45
45
|
}),
|
|
46
|
-
/* @__PURE__ */ jsxs("div", {
|
|
46
|
+
target === "web" ? /* @__PURE__ */ jsxs("div", {
|
|
47
47
|
className: "flex w-full flex-col gap-1",
|
|
48
48
|
children: [/* @__PURE__ */ jsx(SectionLabel, { children: "or enter this pairing code" }), /* @__PURE__ */ jsx("code", {
|
|
49
49
|
"data-testid": "remote-pair-code",
|
|
50
50
|
className: "rounded bg-po-deep p-2 text-center font-mono text-lg tracking-widest text-po-text",
|
|
51
51
|
children: state.pairCode
|
|
52
52
|
})]
|
|
53
|
-
}),
|
|
53
|
+
}) : null,
|
|
54
54
|
/* @__PURE__ */ jsxs("div", {
|
|
55
55
|
className: "flex w-full flex-col gap-1",
|
|
56
56
|
children: [
|
|
@@ -63,7 +63,8 @@ function RemoteAccessPairing() {
|
|
|
63
63
|
/* @__PURE__ */ jsxs("p", {
|
|
64
64
|
className: "text-sm text-po-dim",
|
|
65
65
|
children: [
|
|
66
|
-
"Compare this on the phone when entering the manual code.
|
|
66
|
+
target === "web" ? "Compare this on the phone when entering the manual code. " : "",
|
|
67
|
+
"Bundle revision ",
|
|
67
68
|
String(state.pairRevision),
|
|
68
69
|
"."
|
|
69
70
|
]
|
|
@@ -72,7 +73,7 @@ function RemoteAccessPairing() {
|
|
|
72
73
|
}),
|
|
73
74
|
/* @__PURE__ */ jsxs("div", {
|
|
74
75
|
className: "flex w-full flex-col gap-1",
|
|
75
|
-
children: [/* @__PURE__ */ jsx(SectionLabel, { children: "or open this address" }), /* @__PURE__ */ jsx("code", {
|
|
76
|
+
children: [/* @__PURE__ */ jsx(SectionLabel, { children: target === "native" ? "or paste this address in the app" : "or open this address" }), /* @__PURE__ */ jsx("code", {
|
|
76
77
|
"data-testid": "remote-pair-url",
|
|
77
78
|
className: "break-all rounded bg-po-deep p-2 text-sm text-po-dim",
|
|
78
79
|
children: state.pairUrl
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteAccessPairing.mjs","names":[],"sources":["../../../../src/web/features/remote/RemoteAccessPairing.tsx"],"sourcesContent":["import { Button, SectionLabel, Spinner, Tabs, TabsList, TabsTrigger } from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\n\nimport { NATIVE_PAIRING_LINK_PREFIX } from '../../../types/remoteAccess';\nimport { QrCode } from '../../components/QrCode';\nimport {\n addPasskey,\n choosePairTarget,\n newPairingCode,\n type PairTarget,\n remoteAccessStore,\n} from '../../stores/remoteAccessStore';\nimport { PairedDeviceList } from './PairedDeviceList';\n\n/** The QR credential, a short manual code, and the direct address. */\nexport function RemoteAccessPairing() {\n const state = useStore(remoteAccessStore);\n if (state.pairUrl === undefined || state.pairCode === undefined || state.pairFingerprint === undefined)\n return <Spinner />;\n const target = state.pairTarget ?? 'web';\n // The app link wraps the same credential, so one code serves either; only its opener differs.\n const qrValue =\n target === 'native' ? `${NATIVE_PAIRING_LINK_PREFIX}${encodeURIComponent(state.pairUrl)}` : state.pairUrl;\n\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <Tabs value={target} onValueChange={(value) => choosePairTarget(value as PairTarget)}>\n <TabsList aria-label=\"Pair with\">\n <TabsTrigger value=\"web\" data-testid=\"remote-pair-target-web\">\n Browser\n </TabsTrigger>\n <TabsTrigger value=\"native\" data-testid=\"remote-pair-target-native\">\n Po app\n </TabsTrigger>\n </TabsList>\n </Tabs>\n <p className=\"text-center text-sm text-po-dim\">\n {target === 'native'\n ? 'Scan with the phone camera to open the Po app
|
|
1
|
+
{"version":3,"file":"RemoteAccessPairing.mjs","names":[],"sources":["../../../../src/web/features/remote/RemoteAccessPairing.tsx"],"sourcesContent":["import { Button, SectionLabel, Spinner, Tabs, TabsList, TabsTrigger } from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\n\nimport { NATIVE_PAIRING_LINK_PREFIX } from '../../../types/remoteAccess';\nimport { QrCode } from '../../components/QrCode';\nimport {\n addPasskey,\n choosePairTarget,\n newPairingCode,\n type PairTarget,\n remoteAccessStore,\n} from '../../stores/remoteAccessStore';\nimport { PairedDeviceList } from './PairedDeviceList';\n\n/** The QR credential, a short manual code, and the direct address. */\nexport function RemoteAccessPairing() {\n const state = useStore(remoteAccessStore);\n if (state.pairUrl === undefined || state.pairCode === undefined || state.pairFingerprint === undefined)\n return <Spinner />;\n const target = state.pairTarget ?? 'web';\n // The app link wraps the same credential, so one code serves either; only its opener differs.\n const qrValue =\n target === 'native' ? `${NATIVE_PAIRING_LINK_PREFIX}${encodeURIComponent(state.pairUrl)}` : state.pairUrl;\n\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <Tabs value={target} onValueChange={(value) => choosePairTarget(value as PairTarget)}>\n <TabsList aria-label=\"Pair with\">\n <TabsTrigger value=\"web\" data-testid=\"remote-pair-target-web\">\n Browser\n </TabsTrigger>\n <TabsTrigger value=\"native\" data-testid=\"remote-pair-target-native\">\n Po app\n </TabsTrigger>\n </TabsList>\n </Tabs>\n <p className=\"text-center text-sm text-po-dim\">\n {target === 'native'\n ? 'Scan with the phone camera to open the Po app. Scanning from inside Po? Use the Browser code, or paste the address below.'\n : 'Scan with the phone camera to open Po in the phone browser.'}\n </p>\n {/* A light plate under the code: scanners want dark modules on a bright\n field, which is the one thing a dark theme cannot supply. */}\n <div className=\"rounded-lg bg-po-hi p-3 text-po-deep\">\n <QrCode value={qrValue} size={288} label=\"Scan to pair this device\" />\n </div>\n {target === 'web' ? (\n <div className=\"flex w-full flex-col gap-1\">\n <SectionLabel>or enter this pairing code</SectionLabel>\n <code\n data-testid=\"remote-pair-code\"\n className=\"rounded bg-po-deep p-2 text-center font-mono text-lg tracking-widest text-po-text\"\n >\n {state.pairCode}\n </code>\n </div>\n ) : null}\n <div className=\"flex w-full flex-col gap-1\">\n <SectionLabel>signing-key fingerprint</SectionLabel>\n <code\n data-testid=\"remote-signing-fingerprint\"\n className=\"break-all rounded bg-po-deep p-2 text-center font-mono text-sm text-po-text\"\n >\n {state.pairFingerprint.match(/.{1,8}/gu)?.join(' ') ?? state.pairFingerprint}\n </code>\n <p className=\"text-sm text-po-dim\">\n {target === 'web' ? 'Compare this on the phone when entering the manual code. ' : ''}\n Bundle revision {String(state.pairRevision)}.\n </p>\n </div>\n <div className=\"flex w-full flex-col gap-1\">\n <SectionLabel>{target === 'native' ? 'or paste this address in the app' : 'or open this address'}</SectionLabel>\n <code data-testid=\"remote-pair-url\" className=\"break-all rounded bg-po-deep p-2 text-sm text-po-dim\">\n {state.pairUrl}\n </code>\n </div>\n <Button variant=\"ghost\" size=\"sm\" data-testid=\"remote-new-code\" onClick={() => void newPairingCode()}>\n Show a new code\n </Button>\n\n {/* Enrolling a passkey turns every later visit into one Face ID instead\n of another scan, and it is what puts a second factor in front of the\n two actions that escalate past driving the agent. */}\n {state.passkeys?.supported === true ? (\n <div className=\"flex w-full flex-col gap-1.5 border-t border-po-border pt-3\">\n <SectionLabel>passkeys</SectionLabel>\n <p className=\"text-sm text-po-dim\">\n {state.passkeys.count === 0\n ? 'Add one on the device you just paired and it will not need the code again.'\n : `${String(state.passkeys.count)} registered. A paired device signs in with a gesture instead of a code.`}\n </p>\n <Button variant=\"outline\" size=\"sm\" data-testid=\"remote-add-passkey\" onClick={() => void addPasskey()}>\n Add a passkey for this device\n </Button>\n </div>\n ) : state.passkeys?.reason === undefined ? null : (\n <p data-testid=\"remote-passkey-unavailable\" className=\"w-full text-sm text-po-dim\">\n {state.passkeys.reason}\n </p>\n )}\n\n <PairedDeviceList />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,sBAAsB;CACpC,MAAM,QAAQ,SAAS,iBAAiB;CACxC,IAAI,MAAM,YAAY,KAAA,KAAa,MAAM,aAAa,KAAA,KAAa,MAAM,oBAAoB,KAAA,GAC3F,OAAO,oBAAC,SAAD,CAAU,CAAA;CACnB,MAAM,SAAS,MAAM,cAAc;CAEnC,MAAM,UACJ,WAAW,WAAW,GAAG,6BAA6B,mBAAmB,MAAM,OAAO,MAAM,MAAM;CAEpG,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,MAAD;IAAM,OAAO;IAAQ,gBAAgB,UAAU,iBAAiB,KAAmB;IACjF,UAAA,qBAAC,UAAD;KAAU,cAAW;KAArB,UAAA,CACE,oBAAC,aAAD;MAAa,OAAM;MAAM,eAAY;MAAyB,UAAA;KAEjD,CAAA,GACb,oBAAC,aAAD;MAAa,OAAM;MAAS,eAAY;MAA4B,UAAA;KAEvD,CAAA,CACL;;GACN,CAAA;GACN,oBAAC,KAAD;IAAG,WAAU;IACV,UAAA,WAAW,WACR,8HACA;GACH,CAAA;GAGH,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,oBAAC,QAAD;KAAQ,OAAO;KAAS,MAAM;KAAK,OAAM;IAA4B,CAAA;GAClE,CAAA;GACJ,WAAW,QACV,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,cAAD,EAAA,UAAc,6BAAwC,CAAA,GACtD,oBAAC,QAAD;KACE,eAAY;KACZ,WAAU;KAET,UAAA,MAAM;IACH,CAAA,CACH;GACH,CAAA,IAAA;GACJ,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,oBAAC,cAAD,EAAA,UAAc,0BAAqC,CAAA;KACnD,oBAAC,QAAD;MACE,eAAY;MACZ,WAAU;MAET,UAAA,MAAM,gBAAgB,MAAM,UAAU,CAAC,EAAE,KAAK,GAAG,KAAK,MAAM;KACzD,CAAA;KACN,qBAAC,KAAD;MAAG,WAAU;MAAb,UAAA;OACG,WAAW,QAAQ,8DAA8D;OAAG;OACpE,OAAO,MAAM,YAAY;OAAE;MAC3C;;IACA;;GACL,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,cAAD,EAAA,UAAe,WAAW,WAAW,qCAAqC,uBAAqC,CAAA,GAC/G,oBAAC,QAAD;KAAM,eAAY;KAAkB,WAAU;KAC3C,UAAA,MAAM;IACH,CAAA,CACH;;GACL,oBAAC,QAAD;IAAQ,SAAQ;IAAQ,MAAK;IAAK,eAAY;IAAkB,eAAe,KAAK,eAAe;IAAG,UAAA;GAE9F,CAAA;GAKP,MAAM,UAAU,cAAc,OAC7B,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,oBAAC,cAAD,EAAA,UAAc,WAAsB,CAAA;KACpC,oBAAC,KAAD;MAAG,WAAU;MACV,UAAA,MAAM,SAAS,UAAU,IACtB,+EACA,GAAG,OAAO,MAAM,SAAS,KAAK,EAAE;KACnC,CAAA;KACH,oBAAC,QAAD;MAAQ,SAAQ;MAAU,MAAK;MAAK,eAAY;MAAqB,eAAe,KAAK,WAAW;MAAG,UAAA;KAE/F,CAAA;IACL;GACH,CAAA,IAAA,MAAM,UAAU,WAAW,KAAA,IAAY,OACzC,oBAAC,KAAD;IAAG,eAAY;IAA6B,WAAU;IACnD,UAAA,MAAM,SAAS;GACf,CAAA;GAGL,oBAAC,kBAAD,CAAmB,CAAA;EAChB;;AAET"}
|
|
@@ -293,7 +293,7 @@ function SelectionBar() {
|
|
|
293
293
|
axes.map((axis) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(AxisButton, {
|
|
294
294
|
name: axis.name,
|
|
295
295
|
command: axis.command,
|
|
296
|
-
values: axis.values,
|
|
296
|
+
values: axis.values.length === 0 && !axis.multi ? [axis.emptyLabel] : axis.values,
|
|
297
297
|
multi: axis.multi,
|
|
298
298
|
sessionId: activeId,
|
|
299
299
|
pending: pendingMenu === axis.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectionBar.cjs","names":["PickerContent","answerDialogValue","cancelDialog","Popover","PopoverAnchor","Button","Spinner","ChevronDownIcon","Kbd","sessionsStore","cn","selectFastMode","useStore","useActiveSession","menuStore","useState","parseSelection","selectionAxes","minorModes","buttonVariants","PopoverTrigger","PluginSurface","HOST_SLOTS"],"sources":["../../../../src/web/features/selection/SelectionBar.tsx"],"sourcesContent":["import {\n Button,\n buttonVariants,\n ChevronDownIcon,\n cn,\n Kbd,\n PickerContent,\n type PickerItem,\n Popover,\n PopoverAnchor,\n PopoverTrigger,\n Spinner,\n} from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useState } from 'react';\n\nimport { PluginSurface } from '../../components/PluginSurface';\nimport { minorModes, type MinorMode, selectionAxes } from '../../lib/composition';\nimport { HOST_SLOTS } from '../../lib/pluginRegistry';\nimport { focusPrompt } from '../../lib/promptFocus';\nimport type { AgentInfo, DialogRequest, ModelChoice } from '../../lib/sessionModel';\nimport { parseSelection } from '../../lib/statusLine';\nimport { menuStore, setPendingMenu } from '../../stores/menuStore';\nimport { sessionsStore } from '../../stores/sessionsStore';\nimport {\n answerDialogValue,\n cancelDialog,\n loadModelChoices,\n runCommand,\n selectModel,\n selectThinkingLevel,\n selectFastMode,\n useActiveSession,\n} from '../../stores/sessionStore';\nimport { setDockOpen, setDockTab } from '../../stores/uiStore';\n\n// Category marks carry colour as a label underline; button geometry stays the same.\nconst AXIS_MARK = 'underline decoration-2 underline-offset-4';\nconst AXIS_TONE: Readonly<Record<string, string>> = {\n mode: 'decoration-po-blue',\n profile: 'decoration-po-magenta',\n domains: 'decoration-po-violet',\n minor: 'decoration-po-teal',\n model: 'decoration-po-cyan',\n};\n\nconst MENU_TITLE: Readonly<Record<string, string>> = {\n mode: 'Major mode',\n profile: 'Profile',\n domains: 'Domains',\n minor: 'Minor modes',\n};\n\nconst DOMAIN_SELECTION_KIND = 'po-domains-selection';\nconst DOMAIN_SELECTION_VERSION = 1;\n\n/** Team runs bill to their own sessions, so their spend arrives as a named status. */\nconst AGENT_COST_STATUS_KEY = 'po-team-cost';\n\n/** Adapt the agent's string-valued dialog without changing its single-choice replies. */\nfunction AxisMenu({\n menu,\n dialog,\n values = [],\n multiple = false,\n}: {\n menu: string;\n dialog: DialogRequest;\n values?: readonly string[];\n multiple?: boolean;\n}) {\n const title = MENU_TITLE[menu] ?? menu;\n const items: PickerItem[] = dialog.options.map((option, index) => {\n const clean = menu === 'mode' || multiple ? option.replace(/^\\[[ x]\\]\\s*/, '') : option;\n const separator = menu === 'mode' ? clean.indexOf(':') : -1;\n return {\n value: multiple ? clean : option,\n title: separator < 0 ? clean : clean.slice(0, separator),\n subtitle: separator < 0 ? undefined : clean.slice(separator + 1).trim(),\n props: { 'data-testid': `dialog-option-${index}` },\n };\n });\n const marked = items.filter((_, index) => dialog.options[index].startsWith('[x]')).map((item) => item.value);\n const selected = dialog.options.some((option) => /^\\[[ x]\\]/.test(option))\n ? marked\n : items.filter((item) => values.includes(item.title)).map((item) => item.value);\n return (\n <PickerContent\n align=\"start\"\n data-testid=\"dialog\"\n data-dialog-method={dialog.method}\n data-dialog-menu={menu}\n title={<span data-testid=\"dialog-title\">{title}</span>}\n meta={multiple ? `${selected.length} active` : values.join(', ') || dialog.title}\n items={items}\n value={selected}\n multiple={multiple}\n filterable\n filterPlaceholder={`Filter ${menu === 'mode' ? 'major modes' : title.toLowerCase()}`}\n onSelect={(option) => answerDialogValue(dialog.id, option)}\n onApply={(domains) =>\n answerDialogValue(\n dialog.id,\n JSON.stringify({ kind: DOMAIN_SELECTION_KIND, version: DOMAIN_SELECTION_VERSION, domains }),\n )\n }\n onCancel={() => cancelDialog(dialog.id)}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n focusPrompt();\n }}\n />\n );\n}\n\n/** Asking an axis still goes through its slash command and claimed dialog. */\nfunction AxisButton({\n name,\n command,\n values,\n multi = false,\n sessionId,\n pending,\n claimedDialog,\n children,\n className,\n}: {\n name: string;\n command: string;\n values: readonly string[];\n multi?: boolean;\n sessionId: string | null;\n pending: boolean;\n claimedDialog: DialogRequest | null;\n children: React.ReactNode;\n className: string;\n}) {\n const open = claimedDialog !== null;\n // Other plugin axes keep their existing reply contract, even when set-valued.\n const domains = name === 'domains' && command.replace(/^\\//, '') === 'domains' && multi;\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n if (!next && claimedDialog) cancelDialog(claimedDialog.id);\n }}\n >\n <PopoverAnchor asChild>\n <Button\n data-testid={`axis-${name}`}\n data-pending={pending}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n title={\n pending\n ? `Asking the session for ${name}…`\n : `Change ${name}${values.length ? `: ${values.join(', ')}` : ''}`\n }\n onClick={() => {\n setPendingMenu(name);\n runCommand(command);\n }}\n className={className}\n >\n {children}\n {pending ? (\n <Spinner className=\"size-3 shrink-0\" />\n ) : (\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n )}\n </Button>\n </PopoverAnchor>\n {claimedDialog ? (\n <AxisMenu\n key={`${sessionId}:${claimedDialog.id}`}\n menu={name}\n dialog={claimedDialog}\n values={values}\n multiple={domains}\n />\n ) : null}\n </Popover>\n );\n}\n\n/** Minor modes are commands and workspace navigation, not drafted selections. */\nfunction MinorModesPopup({ modes, onClose }: { modes: MinorMode[]; onClose: () => void }) {\n const items: PickerItem[] = modes.map((mode) => ({\n value: mode.id,\n title: mode.name,\n disabledReason:\n mode.availability === 'unavailable' ? mode.unavailableReason || 'Unavailable in this session' : undefined,\n lead: <Kbd className=\"w-8 justify-center\">{mode.keys}</Kbd>,\n trail:\n mode.availability === 'unavailable' ? (\n <span data-testid={`minor-reason-${mode.name}`} className=\"sr-only\">\n {mode.unavailableReason}\n </span>\n ) : mode.detail ? (\n <span data-testid={`minor-detail-${mode.name}`} className=\"truncate\">\n {mode.detail}\n </span>\n ) : undefined,\n props: { 'data-testid': `minor-${mode.name}`, 'data-availability': mode.availability },\n }));\n const active = modes.filter((mode) => mode.availability === 'on').map((mode) => mode.id);\n return (\n <PickerContent\n align=\"start\"\n data-testid=\"minor-popup\"\n title=\"Minor modes\"\n meta={`${active.length} on`}\n items={items}\n value={active}\n actions\n filterable\n filterPlaceholder=\"Filter minor modes\"\n onSelect={(id) => {\n const mode = modes.find((item) => item.id === id);\n if (mode === undefined) return;\n if (mode.activityGroup !== undefined) {\n setDockOpen(true);\n setDockTab(sessionsStore.state.activeId, 'activity');\n } else {\n setPendingMenu('minor');\n runCommand(`/minor ${mode.id}${mode.toggle === undefined ? '' : ` ${mode.toggle}`}`);\n }\n onClose();\n }}\n />\n );\n}\n\n/** Model choices and their extra controls retain the existing RPC actions. */\nexport function ModelPopup({\n agent,\n models,\n levels,\n fastMode = false,\n onClose,\n}: {\n agent: AgentInfo | null;\n models: ModelChoice[];\n levels: string[];\n fastMode?: boolean;\n onClose: () => void;\n}) {\n useEffect(() => {\n loadModelChoices();\n }, []);\n const items: PickerItem[] = models.map((model) => ({\n value: `${model.provider}/${model.id}`,\n title: model.id,\n subtitle: model.name !== model.id ? model.name : undefined,\n lead: <span className=\"w-24 truncate text-sm text-po-dim\">{model.provider}</span>,\n trail: model.reasoning ? 'thinks' : undefined,\n props: {\n 'data-testid': `model-${model.provider}-${model.id}`,\n 'data-current': agent?.model === model.id && agent.provider === model.provider,\n },\n }));\n return (\n <PickerContent\n align=\"end\"\n data-testid=\"model-popup\"\n title=\"Model\"\n meta={agent ? `${agent.provider}/${agent.model}` : ''}\n items={items}\n value={agent ? [`${agent.provider}/${agent.model}`] : []}\n filterable\n filterPlaceholder=\"Filter models\"\n filterProps={{ 'data-testid': 'model-filter' }}\n loading={\n <>\n <Spinner label=\"asking the session for its models\" />\n asking the session for its models…\n </>\n }\n onSelect={(value) => {\n const model = models.find((item) => `${item.provider}/${item.id}` === value);\n if (model === undefined) return;\n selectModel(model.provider, model.id);\n onClose();\n }}\n footer={\n <>\n <div className=\"flex flex-wrap items-center gap-1 px-3 py-2\">\n <span className=\"mr-1 text-sm font-semibold text-po-dim\">Thinking</span>\n {levels.length === 0 ? <span className=\"text-sm text-po-dim\">…</span> : null}\n {levels.map((level) => {\n const current = agent?.thinkingLevel === level;\n return (\n <Button\n key={level}\n variant=\"ghost\"\n size=\"xs\"\n data-testid={`thinking-${level}`}\n data-current={current}\n onClick={() => {\n selectThinkingLevel(level);\n onClose();\n }}\n className={cn(current && 'bg-po-tint-green font-semibold text-po-green')}\n >\n {level}\n </Button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 border-t border-po-border-soft px-3 py-2\">\n <Button\n variant=\"ghost\"\n size=\"xs\"\n role=\"switch\"\n aria-label=\"Codex Fast\"\n aria-checked={agent?.provider === 'openai-codex' && fastMode}\n aria-describedby=\"codex-fast-description\"\n data-testid=\"fast-toggle\"\n disabled={agent?.provider !== 'openai-codex'}\n onClick={() => selectFastMode(!fastMode)}\n className={cn(agent?.provider === 'openai-codex' && fastMode && 'bg-po-tint-green text-po-green')}\n >\n Fast {agent?.provider === 'openai-codex' && fastMode ? 'on' : 'off'}\n </Button>\n <span id=\"codex-fast-description\" className=\"text-sm text-po-dim\">\n {agent?.provider === 'openai-codex'\n ? 'Priority processing may cost more.'\n : 'Fast is available only for Codex.'}\n </span>\n </div>\n </>\n }\n />\n );\n}\n\n/** Session selection axes use the same popup presentation and trigger geometry. */\nexport function SelectionBar() {\n const activeId = useStore(sessionsStore, (state) => state.activeId);\n const raw = useActiveSession((state) => state.statuses['po-major-mode'] ?? '');\n const statuses = useActiveSession((state) => state.statuses);\n const widgets = useActiveSession((state) => state.widgets);\n const catalog = useActiveSession((state) => state.minorModes);\n const agent = useActiveSession((state) => state.agent);\n const stats = useActiveSession((state) => state.stats);\n const liveCost = useActiveSession((state) => state.liveCost);\n const models = useActiveSession((state) => state.models);\n const fastMode = useActiveSession((state) => state.fastMode);\n const thinkingLevels = useActiveSession((state) => state.thinkingLevels);\n const dialog = useActiveSession((state) => state.dialog);\n const pendingMenu = useStore(menuStore, (state) => state.pending);\n const claimed = useStore(menuStore, (state) => state.claimed);\n const [minorOpen, setMinorOpen] = useState(false);\n const [modelOpen, setModelOpen] = useState(false);\n\n const selection = parseSelection(raw);\n const axes = selectionAxes(statuses);\n const modes = minorModes(statuses, widgets, catalog);\n const activeMinors = modes.filter((mode) => mode.availability === 'on');\n\n const reportedAgentCost = Number(statuses[AGENT_COST_STATUS_KEY] ?? '');\n const agentCost = Number.isFinite(reportedAgentCost) ? reportedAgentCost : 0;\n const sessionCost = stats === null ? null : stats.cost + liveCost;\n /** The dialog this axis asked for, when the claim named it and it is still open. */\n const dialogFor = (name: string): DialogRequest | null =>\n dialog !== null && claimed !== null && claimed.dialogId === dialog.id && claimed.menu === name ? dialog : null;\n const minorDialog = dialogFor('minor');\n\n const axisClass = cn(\n buttonVariants({ variant: 'outline', size: 'lg' }),\n 'min-w-0 max-w-48 gap-1.5 px-3 font-sans font-medium text-po-text max-sm:min-w-24 max-sm:max-w-28 max-sm:flex-1 max-sm:basis-0 max-sm:shrink',\n );\n\n return (\n <footer\n data-testid=\"selection-bar\"\n data-pending={selection.pending}\n className=\"relative flex shrink-0 items-center gap-1.5 overflow-x-auto px-3 pb-3 [scrollbar-width:none] sm:gap-2 sm:px-5 [&::-webkit-scrollbar]:hidden\"\n >\n <AxisButton\n name=\"mode\"\n command=\"mode\"\n values={selection.majorMode ? [selection.majorMode] : []}\n sessionId={activeId}\n pending={pendingMenu === 'mode'}\n claimedDialog={dialogFor('mode')}\n className={cn(axisClass, 'max-sm:max-w-24')}\n >\n <span\n data-testid=\"selection-mode\"\n className={cn('min-w-0 truncate', AXIS_MARK, selection.pending ? 'decoration-po-yellow' : AXIS_TONE.mode)}\n >\n {selection.majorMode || 'Major mode'}\n </span>\n </AxisButton>\n\n {axes.map((axis) => (\n <AxisButton\n key={axis.name}\n name={axis.name}\n command={axis.command}\n values={axis.values}\n multi={axis.multi}\n sessionId={activeId}\n pending={pendingMenu === axis.name}\n claimedDialog={dialogFor(axis.name)}\n className={axisClass}\n >\n <span\n data-testid={`selection-${axis.name}`}\n className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE[axis.name] ?? 'decoration-po-faint')}\n >\n {axis.values[0] ?? axis.emptyLabel}\n </span>\n {axis.values.length > 1 ? (\n <span data-testid={`selection-${axis.name}-more`} className=\"shrink-0 text-xs\">\n +{axis.values.length - 1}\n </span>\n ) : null}\n </AxisButton>\n ))}\n\n <Popover\n open={minorOpen || minorDialog !== null}\n onOpenChange={(next) => {\n if (next) {\n setMinorOpen(true);\n return;\n }\n if (minorDialog) cancelDialog(minorDialog.id);\n setMinorOpen(false);\n }}\n >\n <PopoverTrigger asChild>\n <Button\n data-testid=\"axis-minor\"\n title={`Minor modes${activeMinors.length ? `: ${activeMinors.map((mode) => mode.name).join(', ')}` : ''}`}\n className={cn(axisClass, 'max-sm:max-w-24')}\n >\n <span data-testid=\"minor-summary\" className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE.minor)}>\n {activeMinors[0]?.name ?? 'Minor modes'}\n </span>\n {activeMinors.length > 1 ? <span className=\"shrink-0 text-xs\">+{activeMinors.length - 1}</span> : null}\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n </Button>\n </PopoverTrigger>\n {minorDialog ? (\n <AxisMenu key={`${activeId}:${minorDialog.id}`} menu=\"minor\" dialog={minorDialog} />\n ) : minorOpen ? (\n <MinorModesPopup key={activeId} modes={modes} onClose={() => setMinorOpen(false)} />\n ) : null}\n </Popover>\n\n <PluginSurface slot={HOST_SLOTS.selectionBar} sessionId={activeId} />\n <div className=\"min-w-0 flex-1 max-sm:hidden\" />\n\n <Popover open={modelOpen} onOpenChange={setModelOpen}>\n <PopoverTrigger asChild>\n <Button\n data-testid=\"axis-model\"\n title={\n agent\n ? `${agent.provider}/${agent.model}${agent.thinkingLevel ? ` · ${agent.thinkingLevel}` : ''}`\n : 'Model and thinking level'\n }\n className={axisClass}\n >\n <span data-testid=\"agent-model\" className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE.model)}>\n {agent?.model ?? 'Model'}\n </span>\n <span data-testid=\"agent-thinking\" className=\"shrink-0 text-sm text-po-dim max-sm:hidden\">\n {agent?.thinkingLevel ?? ''}\n </span>\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n </Button>\n </PopoverTrigger>\n {modelOpen ? (\n <ModelPopup\n key={activeId}\n agent={agent}\n models={models}\n levels={thinkingLevels}\n fastMode={fastMode}\n onClose={() => setModelOpen(false)}\n />\n ) : null}\n </Popover>\n\n <span\n data-testid=\"top-context\"\n title={\n stats?.contextTokens != null && stats.contextWindow != null\n ? `${stats.contextTokens.toLocaleString()} of ${stats.contextWindow.toLocaleString()} tokens`\n : 'Context usage, once the session reports it'\n }\n className=\"shrink-0 text-sm text-po-dim max-sm:hidden\"\n >\n {stats?.contextPercent == null ? '' : `ctx ${Math.round(stats.contextPercent)}%`}\n </span>\n <span\n data-testid=\"top-cost\"\n title={\n stats === null || sessionCost === null\n ? ''\n : agentCost > 0\n ? `$${sessionCost.toFixed(2)} session + $${agentCost.toFixed(2)} agents, ${stats.totalTokens.toLocaleString()} tokens this session`\n : `${stats.totalTokens.toLocaleString()} tokens this session`\n }\n className=\"shrink-0 text-sm text-po-dim max-sm:hidden\"\n >\n {sessionCost === null ? '' : `$${(sessionCost + agentCost).toFixed(2)}`}\n </span>\n </footer>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SelectionBar.cjs","names":["PickerContent","answerDialogValue","cancelDialog","Popover","PopoverAnchor","Button","Spinner","ChevronDownIcon","Kbd","sessionsStore","cn","selectFastMode","useStore","useActiveSession","menuStore","useState","parseSelection","selectionAxes","minorModes","buttonVariants","PopoverTrigger","PluginSurface","HOST_SLOTS"],"sources":["../../../../src/web/features/selection/SelectionBar.tsx"],"sourcesContent":["import {\n Button,\n buttonVariants,\n ChevronDownIcon,\n cn,\n Kbd,\n PickerContent,\n type PickerItem,\n Popover,\n PopoverAnchor,\n PopoverTrigger,\n Spinner,\n} from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useState } from 'react';\n\nimport { PluginSurface } from '../../components/PluginSurface';\nimport { minorModes, type MinorMode, selectionAxes } from '../../lib/composition';\nimport { HOST_SLOTS } from '../../lib/pluginRegistry';\nimport { focusPrompt } from '../../lib/promptFocus';\nimport type { AgentInfo, DialogRequest, ModelChoice } from '../../lib/sessionModel';\nimport { parseSelection } from '../../lib/statusLine';\nimport { menuStore, setPendingMenu } from '../../stores/menuStore';\nimport { sessionsStore } from '../../stores/sessionsStore';\nimport {\n answerDialogValue,\n cancelDialog,\n loadModelChoices,\n runCommand,\n selectModel,\n selectThinkingLevel,\n selectFastMode,\n useActiveSession,\n} from '../../stores/sessionStore';\nimport { setDockOpen, setDockTab } from '../../stores/uiStore';\n\n// Category marks carry colour as a label underline; button geometry stays the same.\nconst AXIS_MARK = 'underline decoration-2 underline-offset-4';\nconst AXIS_TONE: Readonly<Record<string, string>> = {\n mode: 'decoration-po-blue',\n profile: 'decoration-po-magenta',\n domains: 'decoration-po-violet',\n minor: 'decoration-po-teal',\n model: 'decoration-po-cyan',\n};\n\nconst MENU_TITLE: Readonly<Record<string, string>> = {\n mode: 'Major mode',\n profile: 'Profile',\n domains: 'Domains',\n minor: 'Minor modes',\n};\n\nconst DOMAIN_SELECTION_KIND = 'po-domains-selection';\nconst DOMAIN_SELECTION_VERSION = 1;\n\n/** Team runs bill to their own sessions, so their spend arrives as a named status. */\nconst AGENT_COST_STATUS_KEY = 'po-team-cost';\n\n/** Adapt the agent's string-valued dialog without changing its single-choice replies. */\nfunction AxisMenu({\n menu,\n dialog,\n values = [],\n multiple = false,\n}: {\n menu: string;\n dialog: DialogRequest;\n values?: readonly string[];\n multiple?: boolean;\n}) {\n const title = MENU_TITLE[menu] ?? menu;\n const items: PickerItem[] = dialog.options.map((option, index) => {\n const clean = menu === 'mode' || multiple ? option.replace(/^\\[[ x]\\]\\s*/, '') : option;\n const separator = menu === 'mode' ? clean.indexOf(':') : -1;\n return {\n value: multiple ? clean : option,\n title: separator < 0 ? clean : clean.slice(0, separator),\n subtitle: separator < 0 ? undefined : clean.slice(separator + 1).trim(),\n props: { 'data-testid': `dialog-option-${index}` },\n };\n });\n const marked = items.filter((_, index) => dialog.options[index].startsWith('[x]')).map((item) => item.value);\n const selected = dialog.options.some((option) => /^\\[[ x]\\]/.test(option))\n ? marked\n : items.filter((item) => values.includes(item.title)).map((item) => item.value);\n return (\n <PickerContent\n align=\"start\"\n data-testid=\"dialog\"\n data-dialog-method={dialog.method}\n data-dialog-menu={menu}\n title={<span data-testid=\"dialog-title\">{title}</span>}\n meta={multiple ? `${selected.length} active` : values.join(', ') || dialog.title}\n items={items}\n value={selected}\n multiple={multiple}\n filterable\n filterPlaceholder={`Filter ${menu === 'mode' ? 'major modes' : title.toLowerCase()}`}\n onSelect={(option) => answerDialogValue(dialog.id, option)}\n onApply={(domains) =>\n answerDialogValue(\n dialog.id,\n JSON.stringify({ kind: DOMAIN_SELECTION_KIND, version: DOMAIN_SELECTION_VERSION, domains }),\n )\n }\n onCancel={() => cancelDialog(dialog.id)}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n focusPrompt();\n }}\n />\n );\n}\n\n/** Asking an axis still goes through its slash command and claimed dialog. */\nfunction AxisButton({\n name,\n command,\n values,\n multi = false,\n sessionId,\n pending,\n claimedDialog,\n children,\n className,\n}: {\n name: string;\n command: string;\n values: readonly string[];\n multi?: boolean;\n sessionId: string | null;\n pending: boolean;\n claimedDialog: DialogRequest | null;\n children: React.ReactNode;\n className: string;\n}) {\n const open = claimedDialog !== null;\n // Other plugin axes keep their existing reply contract, even when set-valued.\n const domains = name === 'domains' && command.replace(/^\\//, '') === 'domains' && multi;\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n if (!next && claimedDialog) cancelDialog(claimedDialog.id);\n }}\n >\n <PopoverAnchor asChild>\n <Button\n data-testid={`axis-${name}`}\n data-pending={pending}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n title={\n pending\n ? `Asking the session for ${name}…`\n : `Change ${name}${values.length ? `: ${values.join(', ')}` : ''}`\n }\n onClick={() => {\n setPendingMenu(name);\n runCommand(command);\n }}\n className={className}\n >\n {children}\n {pending ? (\n <Spinner className=\"size-3 shrink-0\" />\n ) : (\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n )}\n </Button>\n </PopoverAnchor>\n {claimedDialog ? (\n <AxisMenu\n key={`${sessionId}:${claimedDialog.id}`}\n menu={name}\n dialog={claimedDialog}\n values={values}\n multiple={domains}\n />\n ) : null}\n </Popover>\n );\n}\n\n/** Minor modes are commands and workspace navigation, not drafted selections. */\nfunction MinorModesPopup({ modes, onClose }: { modes: MinorMode[]; onClose: () => void }) {\n const items: PickerItem[] = modes.map((mode) => ({\n value: mode.id,\n title: mode.name,\n disabledReason:\n mode.availability === 'unavailable' ? mode.unavailableReason || 'Unavailable in this session' : undefined,\n lead: <Kbd className=\"w-8 justify-center\">{mode.keys}</Kbd>,\n trail:\n mode.availability === 'unavailable' ? (\n <span data-testid={`minor-reason-${mode.name}`} className=\"sr-only\">\n {mode.unavailableReason}\n </span>\n ) : mode.detail ? (\n <span data-testid={`minor-detail-${mode.name}`} className=\"truncate\">\n {mode.detail}\n </span>\n ) : undefined,\n props: { 'data-testid': `minor-${mode.name}`, 'data-availability': mode.availability },\n }));\n const active = modes.filter((mode) => mode.availability === 'on').map((mode) => mode.id);\n return (\n <PickerContent\n align=\"start\"\n data-testid=\"minor-popup\"\n title=\"Minor modes\"\n meta={`${active.length} on`}\n items={items}\n value={active}\n actions\n filterable\n filterPlaceholder=\"Filter minor modes\"\n onSelect={(id) => {\n const mode = modes.find((item) => item.id === id);\n if (mode === undefined) return;\n if (mode.activityGroup !== undefined) {\n setDockOpen(true);\n setDockTab(sessionsStore.state.activeId, 'activity');\n } else {\n setPendingMenu('minor');\n runCommand(`/minor ${mode.id}${mode.toggle === undefined ? '' : ` ${mode.toggle}`}`);\n }\n onClose();\n }}\n />\n );\n}\n\n/** Model choices and their extra controls retain the existing RPC actions. */\nexport function ModelPopup({\n agent,\n models,\n levels,\n fastMode = false,\n onClose,\n}: {\n agent: AgentInfo | null;\n models: ModelChoice[];\n levels: string[];\n fastMode?: boolean;\n onClose: () => void;\n}) {\n useEffect(() => {\n loadModelChoices();\n }, []);\n const items: PickerItem[] = models.map((model) => ({\n value: `${model.provider}/${model.id}`,\n title: model.id,\n subtitle: model.name !== model.id ? model.name : undefined,\n lead: <span className=\"w-24 truncate text-sm text-po-dim\">{model.provider}</span>,\n trail: model.reasoning ? 'thinks' : undefined,\n props: {\n 'data-testid': `model-${model.provider}-${model.id}`,\n 'data-current': agent?.model === model.id && agent.provider === model.provider,\n },\n }));\n return (\n <PickerContent\n align=\"end\"\n data-testid=\"model-popup\"\n title=\"Model\"\n meta={agent ? `${agent.provider}/${agent.model}` : ''}\n items={items}\n value={agent ? [`${agent.provider}/${agent.model}`] : []}\n filterable\n filterPlaceholder=\"Filter models\"\n filterProps={{ 'data-testid': 'model-filter' }}\n loading={\n <>\n <Spinner label=\"asking the session for its models\" />\n asking the session for its models…\n </>\n }\n onSelect={(value) => {\n const model = models.find((item) => `${item.provider}/${item.id}` === value);\n if (model === undefined) return;\n selectModel(model.provider, model.id);\n onClose();\n }}\n footer={\n <>\n <div className=\"flex flex-wrap items-center gap-1 px-3 py-2\">\n <span className=\"mr-1 text-sm font-semibold text-po-dim\">Thinking</span>\n {levels.length === 0 ? <span className=\"text-sm text-po-dim\">…</span> : null}\n {levels.map((level) => {\n const current = agent?.thinkingLevel === level;\n return (\n <Button\n key={level}\n variant=\"ghost\"\n size=\"xs\"\n data-testid={`thinking-${level}`}\n data-current={current}\n onClick={() => {\n selectThinkingLevel(level);\n onClose();\n }}\n className={cn(current && 'bg-po-tint-green font-semibold text-po-green')}\n >\n {level}\n </Button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 border-t border-po-border-soft px-3 py-2\">\n <Button\n variant=\"ghost\"\n size=\"xs\"\n role=\"switch\"\n aria-label=\"Codex Fast\"\n aria-checked={agent?.provider === 'openai-codex' && fastMode}\n aria-describedby=\"codex-fast-description\"\n data-testid=\"fast-toggle\"\n disabled={agent?.provider !== 'openai-codex'}\n onClick={() => selectFastMode(!fastMode)}\n className={cn(agent?.provider === 'openai-codex' && fastMode && 'bg-po-tint-green text-po-green')}\n >\n Fast {agent?.provider === 'openai-codex' && fastMode ? 'on' : 'off'}\n </Button>\n <span id=\"codex-fast-description\" className=\"text-sm text-po-dim\">\n {agent?.provider === 'openai-codex'\n ? 'Priority processing may cost more.'\n : 'Fast is available only for Codex.'}\n </span>\n </div>\n </>\n }\n />\n );\n}\n\n/** Session selection axes use the same popup presentation and trigger geometry. */\nexport function SelectionBar() {\n const activeId = useStore(sessionsStore, (state) => state.activeId);\n const raw = useActiveSession((state) => state.statuses['po-major-mode'] ?? '');\n const statuses = useActiveSession((state) => state.statuses);\n const widgets = useActiveSession((state) => state.widgets);\n const catalog = useActiveSession((state) => state.minorModes);\n const agent = useActiveSession((state) => state.agent);\n const stats = useActiveSession((state) => state.stats);\n const liveCost = useActiveSession((state) => state.liveCost);\n const models = useActiveSession((state) => state.models);\n const fastMode = useActiveSession((state) => state.fastMode);\n const thinkingLevels = useActiveSession((state) => state.thinkingLevels);\n const dialog = useActiveSession((state) => state.dialog);\n const pendingMenu = useStore(menuStore, (state) => state.pending);\n const claimed = useStore(menuStore, (state) => state.claimed);\n const [minorOpen, setMinorOpen] = useState(false);\n const [modelOpen, setModelOpen] = useState(false);\n\n const selection = parseSelection(raw);\n const axes = selectionAxes(statuses);\n const modes = minorModes(statuses, widgets, catalog);\n const activeMinors = modes.filter((mode) => mode.availability === 'on');\n\n const reportedAgentCost = Number(statuses[AGENT_COST_STATUS_KEY] ?? '');\n const agentCost = Number.isFinite(reportedAgentCost) ? reportedAgentCost : 0;\n const sessionCost = stats === null ? null : stats.cost + liveCost;\n /** The dialog this axis asked for, when the claim named it and it is still open. */\n const dialogFor = (name: string): DialogRequest | null =>\n dialog !== null && claimed !== null && claimed.dialogId === dialog.id && claimed.menu === name ? dialog : null;\n const minorDialog = dialogFor('minor');\n\n const axisClass = cn(\n buttonVariants({ variant: 'outline', size: 'lg' }),\n 'min-w-0 max-w-48 gap-1.5 px-3 font-sans font-medium text-po-text max-sm:min-w-24 max-sm:max-w-28 max-sm:flex-1 max-sm:basis-0 max-sm:shrink',\n );\n\n return (\n <footer\n data-testid=\"selection-bar\"\n data-pending={selection.pending}\n className=\"relative flex shrink-0 items-center gap-1.5 overflow-x-auto px-3 pb-3 [scrollbar-width:none] sm:gap-2 sm:px-5 [&::-webkit-scrollbar]:hidden\"\n >\n <AxisButton\n name=\"mode\"\n command=\"mode\"\n values={selection.majorMode ? [selection.majorMode] : []}\n sessionId={activeId}\n pending={pendingMenu === 'mode'}\n claimedDialog={dialogFor('mode')}\n className={cn(axisClass, 'max-sm:max-w-24')}\n >\n <span\n data-testid=\"selection-mode\"\n className={cn('min-w-0 truncate', AXIS_MARK, selection.pending ? 'decoration-po-yellow' : AXIS_TONE.mode)}\n >\n {selection.majorMode || 'Major mode'}\n </span>\n </AxisButton>\n\n {axes.map((axis) => (\n <AxisButton\n key={axis.name}\n name={axis.name}\n command={axis.command}\n values={axis.values.length === 0 && !axis.multi ? [axis.emptyLabel] : axis.values}\n multi={axis.multi}\n sessionId={activeId}\n pending={pendingMenu === axis.name}\n claimedDialog={dialogFor(axis.name)}\n className={axisClass}\n >\n <span\n data-testid={`selection-${axis.name}`}\n className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE[axis.name] ?? 'decoration-po-faint')}\n >\n {axis.values[0] ?? axis.emptyLabel}\n </span>\n {axis.values.length > 1 ? (\n <span data-testid={`selection-${axis.name}-more`} className=\"shrink-0 text-xs\">\n +{axis.values.length - 1}\n </span>\n ) : null}\n </AxisButton>\n ))}\n\n <Popover\n open={minorOpen || minorDialog !== null}\n onOpenChange={(next) => {\n if (next) {\n setMinorOpen(true);\n return;\n }\n if (minorDialog) cancelDialog(minorDialog.id);\n setMinorOpen(false);\n }}\n >\n <PopoverTrigger asChild>\n <Button\n data-testid=\"axis-minor\"\n title={`Minor modes${activeMinors.length ? `: ${activeMinors.map((mode) => mode.name).join(', ')}` : ''}`}\n className={cn(axisClass, 'max-sm:max-w-24')}\n >\n <span data-testid=\"minor-summary\" className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE.minor)}>\n {activeMinors[0]?.name ?? 'Minor modes'}\n </span>\n {activeMinors.length > 1 ? <span className=\"shrink-0 text-xs\">+{activeMinors.length - 1}</span> : null}\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n </Button>\n </PopoverTrigger>\n {minorDialog ? (\n <AxisMenu key={`${activeId}:${minorDialog.id}`} menu=\"minor\" dialog={minorDialog} />\n ) : minorOpen ? (\n <MinorModesPopup key={activeId} modes={modes} onClose={() => setMinorOpen(false)} />\n ) : null}\n </Popover>\n\n <PluginSurface slot={HOST_SLOTS.selectionBar} sessionId={activeId} />\n <div className=\"min-w-0 flex-1 max-sm:hidden\" />\n\n <Popover open={modelOpen} onOpenChange={setModelOpen}>\n <PopoverTrigger asChild>\n <Button\n data-testid=\"axis-model\"\n title={\n agent\n ? `${agent.provider}/${agent.model}${agent.thinkingLevel ? ` · ${agent.thinkingLevel}` : ''}`\n : 'Model and thinking level'\n }\n className={axisClass}\n >\n <span data-testid=\"agent-model\" className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE.model)}>\n {agent?.model ?? 'Model'}\n </span>\n <span data-testid=\"agent-thinking\" className=\"shrink-0 text-sm text-po-dim max-sm:hidden\">\n {agent?.thinkingLevel ?? ''}\n </span>\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n </Button>\n </PopoverTrigger>\n {modelOpen ? (\n <ModelPopup\n key={activeId}\n agent={agent}\n models={models}\n levels={thinkingLevels}\n fastMode={fastMode}\n onClose={() => setModelOpen(false)}\n />\n ) : null}\n </Popover>\n\n <span\n data-testid=\"top-context\"\n title={\n stats?.contextTokens != null && stats.contextWindow != null\n ? `${stats.contextTokens.toLocaleString()} of ${stats.contextWindow.toLocaleString()} tokens`\n : 'Context usage, once the session reports it'\n }\n className=\"shrink-0 text-sm text-po-dim max-sm:hidden\"\n >\n {stats?.contextPercent == null ? '' : `ctx ${Math.round(stats.contextPercent)}%`}\n </span>\n <span\n data-testid=\"top-cost\"\n title={\n stats === null || sessionCost === null\n ? ''\n : agentCost > 0\n ? `$${sessionCost.toFixed(2)} session + $${agentCost.toFixed(2)} agents, ${stats.totalTokens.toLocaleString()} tokens this session`\n : `${stats.totalTokens.toLocaleString()} tokens this session`\n }\n className=\"shrink-0 text-sm text-po-dim max-sm:hidden\"\n >\n {sessionCost === null ? '' : `$${(sessionCost + agentCost).toFixed(2)}`}\n </span>\n </footer>\n );\n}\n"],"mappings":"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"}
|
|
@@ -293,7 +293,7 @@ function SelectionBar() {
|
|
|
293
293
|
axes.map((axis) => /* @__PURE__ */ jsxs(AxisButton, {
|
|
294
294
|
name: axis.name,
|
|
295
295
|
command: axis.command,
|
|
296
|
-
values: axis.values,
|
|
296
|
+
values: axis.values.length === 0 && !axis.multi ? [axis.emptyLabel] : axis.values,
|
|
297
297
|
multi: axis.multi,
|
|
298
298
|
sessionId: activeId,
|
|
299
299
|
pending: pendingMenu === axis.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectionBar.mjs","names":[],"sources":["../../../../src/web/features/selection/SelectionBar.tsx"],"sourcesContent":["import {\n Button,\n buttonVariants,\n ChevronDownIcon,\n cn,\n Kbd,\n PickerContent,\n type PickerItem,\n Popover,\n PopoverAnchor,\n PopoverTrigger,\n Spinner,\n} from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useState } from 'react';\n\nimport { PluginSurface } from '../../components/PluginSurface';\nimport { minorModes, type MinorMode, selectionAxes } from '../../lib/composition';\nimport { HOST_SLOTS } from '../../lib/pluginRegistry';\nimport { focusPrompt } from '../../lib/promptFocus';\nimport type { AgentInfo, DialogRequest, ModelChoice } from '../../lib/sessionModel';\nimport { parseSelection } from '../../lib/statusLine';\nimport { menuStore, setPendingMenu } from '../../stores/menuStore';\nimport { sessionsStore } from '../../stores/sessionsStore';\nimport {\n answerDialogValue,\n cancelDialog,\n loadModelChoices,\n runCommand,\n selectModel,\n selectThinkingLevel,\n selectFastMode,\n useActiveSession,\n} from '../../stores/sessionStore';\nimport { setDockOpen, setDockTab } from '../../stores/uiStore';\n\n// Category marks carry colour as a label underline; button geometry stays the same.\nconst AXIS_MARK = 'underline decoration-2 underline-offset-4';\nconst AXIS_TONE: Readonly<Record<string, string>> = {\n mode: 'decoration-po-blue',\n profile: 'decoration-po-magenta',\n domains: 'decoration-po-violet',\n minor: 'decoration-po-teal',\n model: 'decoration-po-cyan',\n};\n\nconst MENU_TITLE: Readonly<Record<string, string>> = {\n mode: 'Major mode',\n profile: 'Profile',\n domains: 'Domains',\n minor: 'Minor modes',\n};\n\nconst DOMAIN_SELECTION_KIND = 'po-domains-selection';\nconst DOMAIN_SELECTION_VERSION = 1;\n\n/** Team runs bill to their own sessions, so their spend arrives as a named status. */\nconst AGENT_COST_STATUS_KEY = 'po-team-cost';\n\n/** Adapt the agent's string-valued dialog without changing its single-choice replies. */\nfunction AxisMenu({\n menu,\n dialog,\n values = [],\n multiple = false,\n}: {\n menu: string;\n dialog: DialogRequest;\n values?: readonly string[];\n multiple?: boolean;\n}) {\n const title = MENU_TITLE[menu] ?? menu;\n const items: PickerItem[] = dialog.options.map((option, index) => {\n const clean = menu === 'mode' || multiple ? option.replace(/^\\[[ x]\\]\\s*/, '') : option;\n const separator = menu === 'mode' ? clean.indexOf(':') : -1;\n return {\n value: multiple ? clean : option,\n title: separator < 0 ? clean : clean.slice(0, separator),\n subtitle: separator < 0 ? undefined : clean.slice(separator + 1).trim(),\n props: { 'data-testid': `dialog-option-${index}` },\n };\n });\n const marked = items.filter((_, index) => dialog.options[index].startsWith('[x]')).map((item) => item.value);\n const selected = dialog.options.some((option) => /^\\[[ x]\\]/.test(option))\n ? marked\n : items.filter((item) => values.includes(item.title)).map((item) => item.value);\n return (\n <PickerContent\n align=\"start\"\n data-testid=\"dialog\"\n data-dialog-method={dialog.method}\n data-dialog-menu={menu}\n title={<span data-testid=\"dialog-title\">{title}</span>}\n meta={multiple ? `${selected.length} active` : values.join(', ') || dialog.title}\n items={items}\n value={selected}\n multiple={multiple}\n filterable\n filterPlaceholder={`Filter ${menu === 'mode' ? 'major modes' : title.toLowerCase()}`}\n onSelect={(option) => answerDialogValue(dialog.id, option)}\n onApply={(domains) =>\n answerDialogValue(\n dialog.id,\n JSON.stringify({ kind: DOMAIN_SELECTION_KIND, version: DOMAIN_SELECTION_VERSION, domains }),\n )\n }\n onCancel={() => cancelDialog(dialog.id)}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n focusPrompt();\n }}\n />\n );\n}\n\n/** Asking an axis still goes through its slash command and claimed dialog. */\nfunction AxisButton({\n name,\n command,\n values,\n multi = false,\n sessionId,\n pending,\n claimedDialog,\n children,\n className,\n}: {\n name: string;\n command: string;\n values: readonly string[];\n multi?: boolean;\n sessionId: string | null;\n pending: boolean;\n claimedDialog: DialogRequest | null;\n children: React.ReactNode;\n className: string;\n}) {\n const open = claimedDialog !== null;\n // Other plugin axes keep their existing reply contract, even when set-valued.\n const domains = name === 'domains' && command.replace(/^\\//, '') === 'domains' && multi;\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n if (!next && claimedDialog) cancelDialog(claimedDialog.id);\n }}\n >\n <PopoverAnchor asChild>\n <Button\n data-testid={`axis-${name}`}\n data-pending={pending}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n title={\n pending\n ? `Asking the session for ${name}…`\n : `Change ${name}${values.length ? `: ${values.join(', ')}` : ''}`\n }\n onClick={() => {\n setPendingMenu(name);\n runCommand(command);\n }}\n className={className}\n >\n {children}\n {pending ? (\n <Spinner className=\"size-3 shrink-0\" />\n ) : (\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n )}\n </Button>\n </PopoverAnchor>\n {claimedDialog ? (\n <AxisMenu\n key={`${sessionId}:${claimedDialog.id}`}\n menu={name}\n dialog={claimedDialog}\n values={values}\n multiple={domains}\n />\n ) : null}\n </Popover>\n );\n}\n\n/** Minor modes are commands and workspace navigation, not drafted selections. */\nfunction MinorModesPopup({ modes, onClose }: { modes: MinorMode[]; onClose: () => void }) {\n const items: PickerItem[] = modes.map((mode) => ({\n value: mode.id,\n title: mode.name,\n disabledReason:\n mode.availability === 'unavailable' ? mode.unavailableReason || 'Unavailable in this session' : undefined,\n lead: <Kbd className=\"w-8 justify-center\">{mode.keys}</Kbd>,\n trail:\n mode.availability === 'unavailable' ? (\n <span data-testid={`minor-reason-${mode.name}`} className=\"sr-only\">\n {mode.unavailableReason}\n </span>\n ) : mode.detail ? (\n <span data-testid={`minor-detail-${mode.name}`} className=\"truncate\">\n {mode.detail}\n </span>\n ) : undefined,\n props: { 'data-testid': `minor-${mode.name}`, 'data-availability': mode.availability },\n }));\n const active = modes.filter((mode) => mode.availability === 'on').map((mode) => mode.id);\n return (\n <PickerContent\n align=\"start\"\n data-testid=\"minor-popup\"\n title=\"Minor modes\"\n meta={`${active.length} on`}\n items={items}\n value={active}\n actions\n filterable\n filterPlaceholder=\"Filter minor modes\"\n onSelect={(id) => {\n const mode = modes.find((item) => item.id === id);\n if (mode === undefined) return;\n if (mode.activityGroup !== undefined) {\n setDockOpen(true);\n setDockTab(sessionsStore.state.activeId, 'activity');\n } else {\n setPendingMenu('minor');\n runCommand(`/minor ${mode.id}${mode.toggle === undefined ? '' : ` ${mode.toggle}`}`);\n }\n onClose();\n }}\n />\n );\n}\n\n/** Model choices and their extra controls retain the existing RPC actions. */\nexport function ModelPopup({\n agent,\n models,\n levels,\n fastMode = false,\n onClose,\n}: {\n agent: AgentInfo | null;\n models: ModelChoice[];\n levels: string[];\n fastMode?: boolean;\n onClose: () => void;\n}) {\n useEffect(() => {\n loadModelChoices();\n }, []);\n const items: PickerItem[] = models.map((model) => ({\n value: `${model.provider}/${model.id}`,\n title: model.id,\n subtitle: model.name !== model.id ? model.name : undefined,\n lead: <span className=\"w-24 truncate text-sm text-po-dim\">{model.provider}</span>,\n trail: model.reasoning ? 'thinks' : undefined,\n props: {\n 'data-testid': `model-${model.provider}-${model.id}`,\n 'data-current': agent?.model === model.id && agent.provider === model.provider,\n },\n }));\n return (\n <PickerContent\n align=\"end\"\n data-testid=\"model-popup\"\n title=\"Model\"\n meta={agent ? `${agent.provider}/${agent.model}` : ''}\n items={items}\n value={agent ? [`${agent.provider}/${agent.model}`] : []}\n filterable\n filterPlaceholder=\"Filter models\"\n filterProps={{ 'data-testid': 'model-filter' }}\n loading={\n <>\n <Spinner label=\"asking the session for its models\" />\n asking the session for its models…\n </>\n }\n onSelect={(value) => {\n const model = models.find((item) => `${item.provider}/${item.id}` === value);\n if (model === undefined) return;\n selectModel(model.provider, model.id);\n onClose();\n }}\n footer={\n <>\n <div className=\"flex flex-wrap items-center gap-1 px-3 py-2\">\n <span className=\"mr-1 text-sm font-semibold text-po-dim\">Thinking</span>\n {levels.length === 0 ? <span className=\"text-sm text-po-dim\">…</span> : null}\n {levels.map((level) => {\n const current = agent?.thinkingLevel === level;\n return (\n <Button\n key={level}\n variant=\"ghost\"\n size=\"xs\"\n data-testid={`thinking-${level}`}\n data-current={current}\n onClick={() => {\n selectThinkingLevel(level);\n onClose();\n }}\n className={cn(current && 'bg-po-tint-green font-semibold text-po-green')}\n >\n {level}\n </Button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 border-t border-po-border-soft px-3 py-2\">\n <Button\n variant=\"ghost\"\n size=\"xs\"\n role=\"switch\"\n aria-label=\"Codex Fast\"\n aria-checked={agent?.provider === 'openai-codex' && fastMode}\n aria-describedby=\"codex-fast-description\"\n data-testid=\"fast-toggle\"\n disabled={agent?.provider !== 'openai-codex'}\n onClick={() => selectFastMode(!fastMode)}\n className={cn(agent?.provider === 'openai-codex' && fastMode && 'bg-po-tint-green text-po-green')}\n >\n Fast {agent?.provider === 'openai-codex' && fastMode ? 'on' : 'off'}\n </Button>\n <span id=\"codex-fast-description\" className=\"text-sm text-po-dim\">\n {agent?.provider === 'openai-codex'\n ? 'Priority processing may cost more.'\n : 'Fast is available only for Codex.'}\n </span>\n </div>\n </>\n }\n />\n );\n}\n\n/** Session selection axes use the same popup presentation and trigger geometry. */\nexport function SelectionBar() {\n const activeId = useStore(sessionsStore, (state) => state.activeId);\n const raw = useActiveSession((state) => state.statuses['po-major-mode'] ?? '');\n const statuses = useActiveSession((state) => state.statuses);\n const widgets = useActiveSession((state) => state.widgets);\n const catalog = useActiveSession((state) => state.minorModes);\n const agent = useActiveSession((state) => state.agent);\n const stats = useActiveSession((state) => state.stats);\n const liveCost = useActiveSession((state) => state.liveCost);\n const models = useActiveSession((state) => state.models);\n const fastMode = useActiveSession((state) => state.fastMode);\n const thinkingLevels = useActiveSession((state) => state.thinkingLevels);\n const dialog = useActiveSession((state) => state.dialog);\n const pendingMenu = useStore(menuStore, (state) => state.pending);\n const claimed = useStore(menuStore, (state) => state.claimed);\n const [minorOpen, setMinorOpen] = useState(false);\n const [modelOpen, setModelOpen] = useState(false);\n\n const selection = parseSelection(raw);\n const axes = selectionAxes(statuses);\n const modes = minorModes(statuses, widgets, catalog);\n const activeMinors = modes.filter((mode) => mode.availability === 'on');\n\n const reportedAgentCost = Number(statuses[AGENT_COST_STATUS_KEY] ?? '');\n const agentCost = Number.isFinite(reportedAgentCost) ? reportedAgentCost : 0;\n const sessionCost = stats === null ? null : stats.cost + liveCost;\n /** The dialog this axis asked for, when the claim named it and it is still open. */\n const dialogFor = (name: string): DialogRequest | null =>\n dialog !== null && claimed !== null && claimed.dialogId === dialog.id && claimed.menu === name ? dialog : null;\n const minorDialog = dialogFor('minor');\n\n const axisClass = cn(\n buttonVariants({ variant: 'outline', size: 'lg' }),\n 'min-w-0 max-w-48 gap-1.5 px-3 font-sans font-medium text-po-text max-sm:min-w-24 max-sm:max-w-28 max-sm:flex-1 max-sm:basis-0 max-sm:shrink',\n );\n\n return (\n <footer\n data-testid=\"selection-bar\"\n data-pending={selection.pending}\n className=\"relative flex shrink-0 items-center gap-1.5 overflow-x-auto px-3 pb-3 [scrollbar-width:none] sm:gap-2 sm:px-5 [&::-webkit-scrollbar]:hidden\"\n >\n <AxisButton\n name=\"mode\"\n command=\"mode\"\n values={selection.majorMode ? [selection.majorMode] : []}\n sessionId={activeId}\n pending={pendingMenu === 'mode'}\n claimedDialog={dialogFor('mode')}\n className={cn(axisClass, 'max-sm:max-w-24')}\n >\n <span\n data-testid=\"selection-mode\"\n className={cn('min-w-0 truncate', AXIS_MARK, selection.pending ? 'decoration-po-yellow' : AXIS_TONE.mode)}\n >\n {selection.majorMode || 'Major mode'}\n </span>\n </AxisButton>\n\n {axes.map((axis) => (\n <AxisButton\n key={axis.name}\n name={axis.name}\n command={axis.command}\n values={axis.values}\n multi={axis.multi}\n sessionId={activeId}\n pending={pendingMenu === axis.name}\n claimedDialog={dialogFor(axis.name)}\n className={axisClass}\n >\n <span\n data-testid={`selection-${axis.name}`}\n className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE[axis.name] ?? 'decoration-po-faint')}\n >\n {axis.values[0] ?? axis.emptyLabel}\n </span>\n {axis.values.length > 1 ? (\n <span data-testid={`selection-${axis.name}-more`} className=\"shrink-0 text-xs\">\n +{axis.values.length - 1}\n </span>\n ) : null}\n </AxisButton>\n ))}\n\n <Popover\n open={minorOpen || minorDialog !== null}\n onOpenChange={(next) => {\n if (next) {\n setMinorOpen(true);\n return;\n }\n if (minorDialog) cancelDialog(minorDialog.id);\n setMinorOpen(false);\n }}\n >\n <PopoverTrigger asChild>\n <Button\n data-testid=\"axis-minor\"\n title={`Minor modes${activeMinors.length ? `: ${activeMinors.map((mode) => mode.name).join(', ')}` : ''}`}\n className={cn(axisClass, 'max-sm:max-w-24')}\n >\n <span data-testid=\"minor-summary\" className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE.minor)}>\n {activeMinors[0]?.name ?? 'Minor modes'}\n </span>\n {activeMinors.length > 1 ? <span className=\"shrink-0 text-xs\">+{activeMinors.length - 1}</span> : null}\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n </Button>\n </PopoverTrigger>\n {minorDialog ? (\n <AxisMenu key={`${activeId}:${minorDialog.id}`} menu=\"minor\" dialog={minorDialog} />\n ) : minorOpen ? (\n <MinorModesPopup key={activeId} modes={modes} onClose={() => setMinorOpen(false)} />\n ) : null}\n </Popover>\n\n <PluginSurface slot={HOST_SLOTS.selectionBar} sessionId={activeId} />\n <div className=\"min-w-0 flex-1 max-sm:hidden\" />\n\n <Popover open={modelOpen} onOpenChange={setModelOpen}>\n <PopoverTrigger asChild>\n <Button\n data-testid=\"axis-model\"\n title={\n agent\n ? `${agent.provider}/${agent.model}${agent.thinkingLevel ? ` · ${agent.thinkingLevel}` : ''}`\n : 'Model and thinking level'\n }\n className={axisClass}\n >\n <span data-testid=\"agent-model\" className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE.model)}>\n {agent?.model ?? 'Model'}\n </span>\n <span data-testid=\"agent-thinking\" className=\"shrink-0 text-sm text-po-dim max-sm:hidden\">\n {agent?.thinkingLevel ?? ''}\n </span>\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n </Button>\n </PopoverTrigger>\n {modelOpen ? (\n <ModelPopup\n key={activeId}\n agent={agent}\n models={models}\n levels={thinkingLevels}\n fastMode={fastMode}\n onClose={() => setModelOpen(false)}\n />\n ) : null}\n </Popover>\n\n <span\n data-testid=\"top-context\"\n title={\n stats?.contextTokens != null && stats.contextWindow != null\n ? `${stats.contextTokens.toLocaleString()} of ${stats.contextWindow.toLocaleString()} tokens`\n : 'Context usage, once the session reports it'\n }\n className=\"shrink-0 text-sm text-po-dim max-sm:hidden\"\n >\n {stats?.contextPercent == null ? '' : `ctx ${Math.round(stats.contextPercent)}%`}\n </span>\n <span\n data-testid=\"top-cost\"\n title={\n stats === null || sessionCost === null\n ? ''\n : agentCost > 0\n ? `$${sessionCost.toFixed(2)} session + $${agentCost.toFixed(2)} agents, ${stats.totalTokens.toLocaleString()} tokens this session`\n : `${stats.totalTokens.toLocaleString()} tokens this session`\n }\n className=\"shrink-0 text-sm text-po-dim max-sm:hidden\"\n >\n {sessionCost === null ? '' : `$${(sessionCost + agentCost).toFixed(2)}`}\n </span>\n </footer>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SelectionBar.mjs","names":[],"sources":["../../../../src/web/features/selection/SelectionBar.tsx"],"sourcesContent":["import {\n Button,\n buttonVariants,\n ChevronDownIcon,\n cn,\n Kbd,\n PickerContent,\n type PickerItem,\n Popover,\n PopoverAnchor,\n PopoverTrigger,\n Spinner,\n} from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useState } from 'react';\n\nimport { PluginSurface } from '../../components/PluginSurface';\nimport { minorModes, type MinorMode, selectionAxes } from '../../lib/composition';\nimport { HOST_SLOTS } from '../../lib/pluginRegistry';\nimport { focusPrompt } from '../../lib/promptFocus';\nimport type { AgentInfo, DialogRequest, ModelChoice } from '../../lib/sessionModel';\nimport { parseSelection } from '../../lib/statusLine';\nimport { menuStore, setPendingMenu } from '../../stores/menuStore';\nimport { sessionsStore } from '../../stores/sessionsStore';\nimport {\n answerDialogValue,\n cancelDialog,\n loadModelChoices,\n runCommand,\n selectModel,\n selectThinkingLevel,\n selectFastMode,\n useActiveSession,\n} from '../../stores/sessionStore';\nimport { setDockOpen, setDockTab } from '../../stores/uiStore';\n\n// Category marks carry colour as a label underline; button geometry stays the same.\nconst AXIS_MARK = 'underline decoration-2 underline-offset-4';\nconst AXIS_TONE: Readonly<Record<string, string>> = {\n mode: 'decoration-po-blue',\n profile: 'decoration-po-magenta',\n domains: 'decoration-po-violet',\n minor: 'decoration-po-teal',\n model: 'decoration-po-cyan',\n};\n\nconst MENU_TITLE: Readonly<Record<string, string>> = {\n mode: 'Major mode',\n profile: 'Profile',\n domains: 'Domains',\n minor: 'Minor modes',\n};\n\nconst DOMAIN_SELECTION_KIND = 'po-domains-selection';\nconst DOMAIN_SELECTION_VERSION = 1;\n\n/** Team runs bill to their own sessions, so their spend arrives as a named status. */\nconst AGENT_COST_STATUS_KEY = 'po-team-cost';\n\n/** Adapt the agent's string-valued dialog without changing its single-choice replies. */\nfunction AxisMenu({\n menu,\n dialog,\n values = [],\n multiple = false,\n}: {\n menu: string;\n dialog: DialogRequest;\n values?: readonly string[];\n multiple?: boolean;\n}) {\n const title = MENU_TITLE[menu] ?? menu;\n const items: PickerItem[] = dialog.options.map((option, index) => {\n const clean = menu === 'mode' || multiple ? option.replace(/^\\[[ x]\\]\\s*/, '') : option;\n const separator = menu === 'mode' ? clean.indexOf(':') : -1;\n return {\n value: multiple ? clean : option,\n title: separator < 0 ? clean : clean.slice(0, separator),\n subtitle: separator < 0 ? undefined : clean.slice(separator + 1).trim(),\n props: { 'data-testid': `dialog-option-${index}` },\n };\n });\n const marked = items.filter((_, index) => dialog.options[index].startsWith('[x]')).map((item) => item.value);\n const selected = dialog.options.some((option) => /^\\[[ x]\\]/.test(option))\n ? marked\n : items.filter((item) => values.includes(item.title)).map((item) => item.value);\n return (\n <PickerContent\n align=\"start\"\n data-testid=\"dialog\"\n data-dialog-method={dialog.method}\n data-dialog-menu={menu}\n title={<span data-testid=\"dialog-title\">{title}</span>}\n meta={multiple ? `${selected.length} active` : values.join(', ') || dialog.title}\n items={items}\n value={selected}\n multiple={multiple}\n filterable\n filterPlaceholder={`Filter ${menu === 'mode' ? 'major modes' : title.toLowerCase()}`}\n onSelect={(option) => answerDialogValue(dialog.id, option)}\n onApply={(domains) =>\n answerDialogValue(\n dialog.id,\n JSON.stringify({ kind: DOMAIN_SELECTION_KIND, version: DOMAIN_SELECTION_VERSION, domains }),\n )\n }\n onCancel={() => cancelDialog(dialog.id)}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n focusPrompt();\n }}\n />\n );\n}\n\n/** Asking an axis still goes through its slash command and claimed dialog. */\nfunction AxisButton({\n name,\n command,\n values,\n multi = false,\n sessionId,\n pending,\n claimedDialog,\n children,\n className,\n}: {\n name: string;\n command: string;\n values: readonly string[];\n multi?: boolean;\n sessionId: string | null;\n pending: boolean;\n claimedDialog: DialogRequest | null;\n children: React.ReactNode;\n className: string;\n}) {\n const open = claimedDialog !== null;\n // Other plugin axes keep their existing reply contract, even when set-valued.\n const domains = name === 'domains' && command.replace(/^\\//, '') === 'domains' && multi;\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n if (!next && claimedDialog) cancelDialog(claimedDialog.id);\n }}\n >\n <PopoverAnchor asChild>\n <Button\n data-testid={`axis-${name}`}\n data-pending={pending}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n title={\n pending\n ? `Asking the session for ${name}…`\n : `Change ${name}${values.length ? `: ${values.join(', ')}` : ''}`\n }\n onClick={() => {\n setPendingMenu(name);\n runCommand(command);\n }}\n className={className}\n >\n {children}\n {pending ? (\n <Spinner className=\"size-3 shrink-0\" />\n ) : (\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n )}\n </Button>\n </PopoverAnchor>\n {claimedDialog ? (\n <AxisMenu\n key={`${sessionId}:${claimedDialog.id}`}\n menu={name}\n dialog={claimedDialog}\n values={values}\n multiple={domains}\n />\n ) : null}\n </Popover>\n );\n}\n\n/** Minor modes are commands and workspace navigation, not drafted selections. */\nfunction MinorModesPopup({ modes, onClose }: { modes: MinorMode[]; onClose: () => void }) {\n const items: PickerItem[] = modes.map((mode) => ({\n value: mode.id,\n title: mode.name,\n disabledReason:\n mode.availability === 'unavailable' ? mode.unavailableReason || 'Unavailable in this session' : undefined,\n lead: <Kbd className=\"w-8 justify-center\">{mode.keys}</Kbd>,\n trail:\n mode.availability === 'unavailable' ? (\n <span data-testid={`minor-reason-${mode.name}`} className=\"sr-only\">\n {mode.unavailableReason}\n </span>\n ) : mode.detail ? (\n <span data-testid={`minor-detail-${mode.name}`} className=\"truncate\">\n {mode.detail}\n </span>\n ) : undefined,\n props: { 'data-testid': `minor-${mode.name}`, 'data-availability': mode.availability },\n }));\n const active = modes.filter((mode) => mode.availability === 'on').map((mode) => mode.id);\n return (\n <PickerContent\n align=\"start\"\n data-testid=\"minor-popup\"\n title=\"Minor modes\"\n meta={`${active.length} on`}\n items={items}\n value={active}\n actions\n filterable\n filterPlaceholder=\"Filter minor modes\"\n onSelect={(id) => {\n const mode = modes.find((item) => item.id === id);\n if (mode === undefined) return;\n if (mode.activityGroup !== undefined) {\n setDockOpen(true);\n setDockTab(sessionsStore.state.activeId, 'activity');\n } else {\n setPendingMenu('minor');\n runCommand(`/minor ${mode.id}${mode.toggle === undefined ? '' : ` ${mode.toggle}`}`);\n }\n onClose();\n }}\n />\n );\n}\n\n/** Model choices and their extra controls retain the existing RPC actions. */\nexport function ModelPopup({\n agent,\n models,\n levels,\n fastMode = false,\n onClose,\n}: {\n agent: AgentInfo | null;\n models: ModelChoice[];\n levels: string[];\n fastMode?: boolean;\n onClose: () => void;\n}) {\n useEffect(() => {\n loadModelChoices();\n }, []);\n const items: PickerItem[] = models.map((model) => ({\n value: `${model.provider}/${model.id}`,\n title: model.id,\n subtitle: model.name !== model.id ? model.name : undefined,\n lead: <span className=\"w-24 truncate text-sm text-po-dim\">{model.provider}</span>,\n trail: model.reasoning ? 'thinks' : undefined,\n props: {\n 'data-testid': `model-${model.provider}-${model.id}`,\n 'data-current': agent?.model === model.id && agent.provider === model.provider,\n },\n }));\n return (\n <PickerContent\n align=\"end\"\n data-testid=\"model-popup\"\n title=\"Model\"\n meta={agent ? `${agent.provider}/${agent.model}` : ''}\n items={items}\n value={agent ? [`${agent.provider}/${agent.model}`] : []}\n filterable\n filterPlaceholder=\"Filter models\"\n filterProps={{ 'data-testid': 'model-filter' }}\n loading={\n <>\n <Spinner label=\"asking the session for its models\" />\n asking the session for its models…\n </>\n }\n onSelect={(value) => {\n const model = models.find((item) => `${item.provider}/${item.id}` === value);\n if (model === undefined) return;\n selectModel(model.provider, model.id);\n onClose();\n }}\n footer={\n <>\n <div className=\"flex flex-wrap items-center gap-1 px-3 py-2\">\n <span className=\"mr-1 text-sm font-semibold text-po-dim\">Thinking</span>\n {levels.length === 0 ? <span className=\"text-sm text-po-dim\">…</span> : null}\n {levels.map((level) => {\n const current = agent?.thinkingLevel === level;\n return (\n <Button\n key={level}\n variant=\"ghost\"\n size=\"xs\"\n data-testid={`thinking-${level}`}\n data-current={current}\n onClick={() => {\n selectThinkingLevel(level);\n onClose();\n }}\n className={cn(current && 'bg-po-tint-green font-semibold text-po-green')}\n >\n {level}\n </Button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 border-t border-po-border-soft px-3 py-2\">\n <Button\n variant=\"ghost\"\n size=\"xs\"\n role=\"switch\"\n aria-label=\"Codex Fast\"\n aria-checked={agent?.provider === 'openai-codex' && fastMode}\n aria-describedby=\"codex-fast-description\"\n data-testid=\"fast-toggle\"\n disabled={agent?.provider !== 'openai-codex'}\n onClick={() => selectFastMode(!fastMode)}\n className={cn(agent?.provider === 'openai-codex' && fastMode && 'bg-po-tint-green text-po-green')}\n >\n Fast {agent?.provider === 'openai-codex' && fastMode ? 'on' : 'off'}\n </Button>\n <span id=\"codex-fast-description\" className=\"text-sm text-po-dim\">\n {agent?.provider === 'openai-codex'\n ? 'Priority processing may cost more.'\n : 'Fast is available only for Codex.'}\n </span>\n </div>\n </>\n }\n />\n );\n}\n\n/** Session selection axes use the same popup presentation and trigger geometry. */\nexport function SelectionBar() {\n const activeId = useStore(sessionsStore, (state) => state.activeId);\n const raw = useActiveSession((state) => state.statuses['po-major-mode'] ?? '');\n const statuses = useActiveSession((state) => state.statuses);\n const widgets = useActiveSession((state) => state.widgets);\n const catalog = useActiveSession((state) => state.minorModes);\n const agent = useActiveSession((state) => state.agent);\n const stats = useActiveSession((state) => state.stats);\n const liveCost = useActiveSession((state) => state.liveCost);\n const models = useActiveSession((state) => state.models);\n const fastMode = useActiveSession((state) => state.fastMode);\n const thinkingLevels = useActiveSession((state) => state.thinkingLevels);\n const dialog = useActiveSession((state) => state.dialog);\n const pendingMenu = useStore(menuStore, (state) => state.pending);\n const claimed = useStore(menuStore, (state) => state.claimed);\n const [minorOpen, setMinorOpen] = useState(false);\n const [modelOpen, setModelOpen] = useState(false);\n\n const selection = parseSelection(raw);\n const axes = selectionAxes(statuses);\n const modes = minorModes(statuses, widgets, catalog);\n const activeMinors = modes.filter((mode) => mode.availability === 'on');\n\n const reportedAgentCost = Number(statuses[AGENT_COST_STATUS_KEY] ?? '');\n const agentCost = Number.isFinite(reportedAgentCost) ? reportedAgentCost : 0;\n const sessionCost = stats === null ? null : stats.cost + liveCost;\n /** The dialog this axis asked for, when the claim named it and it is still open. */\n const dialogFor = (name: string): DialogRequest | null =>\n dialog !== null && claimed !== null && claimed.dialogId === dialog.id && claimed.menu === name ? dialog : null;\n const minorDialog = dialogFor('minor');\n\n const axisClass = cn(\n buttonVariants({ variant: 'outline', size: 'lg' }),\n 'min-w-0 max-w-48 gap-1.5 px-3 font-sans font-medium text-po-text max-sm:min-w-24 max-sm:max-w-28 max-sm:flex-1 max-sm:basis-0 max-sm:shrink',\n );\n\n return (\n <footer\n data-testid=\"selection-bar\"\n data-pending={selection.pending}\n className=\"relative flex shrink-0 items-center gap-1.5 overflow-x-auto px-3 pb-3 [scrollbar-width:none] sm:gap-2 sm:px-5 [&::-webkit-scrollbar]:hidden\"\n >\n <AxisButton\n name=\"mode\"\n command=\"mode\"\n values={selection.majorMode ? [selection.majorMode] : []}\n sessionId={activeId}\n pending={pendingMenu === 'mode'}\n claimedDialog={dialogFor('mode')}\n className={cn(axisClass, 'max-sm:max-w-24')}\n >\n <span\n data-testid=\"selection-mode\"\n className={cn('min-w-0 truncate', AXIS_MARK, selection.pending ? 'decoration-po-yellow' : AXIS_TONE.mode)}\n >\n {selection.majorMode || 'Major mode'}\n </span>\n </AxisButton>\n\n {axes.map((axis) => (\n <AxisButton\n key={axis.name}\n name={axis.name}\n command={axis.command}\n values={axis.values.length === 0 && !axis.multi ? [axis.emptyLabel] : axis.values}\n multi={axis.multi}\n sessionId={activeId}\n pending={pendingMenu === axis.name}\n claimedDialog={dialogFor(axis.name)}\n className={axisClass}\n >\n <span\n data-testid={`selection-${axis.name}`}\n className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE[axis.name] ?? 'decoration-po-faint')}\n >\n {axis.values[0] ?? axis.emptyLabel}\n </span>\n {axis.values.length > 1 ? (\n <span data-testid={`selection-${axis.name}-more`} className=\"shrink-0 text-xs\">\n +{axis.values.length - 1}\n </span>\n ) : null}\n </AxisButton>\n ))}\n\n <Popover\n open={minorOpen || minorDialog !== null}\n onOpenChange={(next) => {\n if (next) {\n setMinorOpen(true);\n return;\n }\n if (minorDialog) cancelDialog(minorDialog.id);\n setMinorOpen(false);\n }}\n >\n <PopoverTrigger asChild>\n <Button\n data-testid=\"axis-minor\"\n title={`Minor modes${activeMinors.length ? `: ${activeMinors.map((mode) => mode.name).join(', ')}` : ''}`}\n className={cn(axisClass, 'max-sm:max-w-24')}\n >\n <span data-testid=\"minor-summary\" className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE.minor)}>\n {activeMinors[0]?.name ?? 'Minor modes'}\n </span>\n {activeMinors.length > 1 ? <span className=\"shrink-0 text-xs\">+{activeMinors.length - 1}</span> : null}\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n </Button>\n </PopoverTrigger>\n {minorDialog ? (\n <AxisMenu key={`${activeId}:${minorDialog.id}`} menu=\"minor\" dialog={minorDialog} />\n ) : minorOpen ? (\n <MinorModesPopup key={activeId} modes={modes} onClose={() => setMinorOpen(false)} />\n ) : null}\n </Popover>\n\n <PluginSurface slot={HOST_SLOTS.selectionBar} sessionId={activeId} />\n <div className=\"min-w-0 flex-1 max-sm:hidden\" />\n\n <Popover open={modelOpen} onOpenChange={setModelOpen}>\n <PopoverTrigger asChild>\n <Button\n data-testid=\"axis-model\"\n title={\n agent\n ? `${agent.provider}/${agent.model}${agent.thinkingLevel ? ` · ${agent.thinkingLevel}` : ''}`\n : 'Model and thinking level'\n }\n className={axisClass}\n >\n <span data-testid=\"agent-model\" className={cn('min-w-0 truncate', AXIS_MARK, AXIS_TONE.model)}>\n {agent?.model ?? 'Model'}\n </span>\n <span data-testid=\"agent-thinking\" className=\"shrink-0 text-sm text-po-dim max-sm:hidden\">\n {agent?.thinkingLevel ?? ''}\n </span>\n <ChevronDownIcon className=\"size-3.5 shrink-0 opacity-60\" />\n </Button>\n </PopoverTrigger>\n {modelOpen ? (\n <ModelPopup\n key={activeId}\n agent={agent}\n models={models}\n levels={thinkingLevels}\n fastMode={fastMode}\n onClose={() => setModelOpen(false)}\n />\n ) : null}\n </Popover>\n\n <span\n data-testid=\"top-context\"\n title={\n stats?.contextTokens != null && stats.contextWindow != null\n ? `${stats.contextTokens.toLocaleString()} of ${stats.contextWindow.toLocaleString()} tokens`\n : 'Context usage, once the session reports it'\n }\n className=\"shrink-0 text-sm text-po-dim max-sm:hidden\"\n >\n {stats?.contextPercent == null ? '' : `ctx ${Math.round(stats.contextPercent)}%`}\n </span>\n <span\n data-testid=\"top-cost\"\n title={\n stats === null || sessionCost === null\n ? ''\n : agentCost > 0\n ? `$${sessionCost.toFixed(2)} session + $${agentCost.toFixed(2)} agents, ${stats.totalTokens.toLocaleString()} tokens this session`\n : `${stats.totalTokens.toLocaleString()} tokens this session`\n }\n className=\"shrink-0 text-sm text-po-dim max-sm:hidden\"\n >\n {sessionCost === null ? '' : `$${(sessionCost + agentCost).toFixed(2)}`}\n </span>\n </footer>\n );\n}\n"],"mappings":"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"}
|