@agimon-ai/doompi-minor-mode 0.0.1-alpha.100

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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/dist/apiContracts.cjs +17 -0
  4. package/dist/apiContracts.cjs.map +1 -0
  5. package/dist/apiContracts.d.mts +53 -0
  6. package/dist/apiContracts.d.mts.map +1 -0
  7. package/dist/apiContracts.mjs +13 -0
  8. package/dist/apiContracts.mjs.map +1 -0
  9. package/dist/catalog-8apySKXB.mjs +222 -0
  10. package/dist/catalog-8apySKXB.mjs.map +1 -0
  11. package/dist/catalog-jTd7UXiI.cjs +227 -0
  12. package/dist/catalog-jTd7UXiI.cjs.map +1 -0
  13. package/dist/catalog.cjs +3 -0
  14. package/dist/catalog.d.mts +14 -0
  15. package/dist/catalog.d.mts.map +1 -0
  16. package/dist/catalog.mjs +2 -0
  17. package/dist/command-B5HZmmyU.cjs +11 -0
  18. package/dist/command-B5HZmmyU.cjs.map +1 -0
  19. package/dist/command-BvYpwiin.mjs +6 -0
  20. package/dist/command-BvYpwiin.mjs.map +1 -0
  21. package/dist/command-C4u3oOPT.mjs +128 -0
  22. package/dist/command-C4u3oOPT.mjs.map +1 -0
  23. package/dist/command-D9hQfJb_.cjs +151 -0
  24. package/dist/command-D9hQfJb_.cjs.map +1 -0
  25. package/dist/command.cjs +8 -0
  26. package/dist/command.d.mts +6 -0
  27. package/dist/command.d.mts.map +1 -0
  28. package/dist/command.mjs +3 -0
  29. package/dist/extensions/pi.cjs +181 -0
  30. package/dist/extensions/pi.cjs.map +1 -0
  31. package/dist/extensions/pi.d.mts +5 -0
  32. package/dist/extensions/pi.d.mts.map +1 -0
  33. package/dist/extensions/pi.mjs +176 -0
  34. package/dist/extensions/pi.mjs.map +1 -0
  35. package/dist/extensions/server.cjs +134 -0
  36. package/dist/extensions/server.cjs.map +1 -0
  37. package/dist/extensions/server.d.mts +5 -0
  38. package/dist/extensions/server.d.mts.map +1 -0
  39. package/dist/extensions/server.mjs +129 -0
  40. package/dist/extensions/server.mjs.map +1 -0
  41. package/dist/headlessCommand-BJhocUje.mjs +53 -0
  42. package/dist/headlessCommand-BJhocUje.mjs.map +1 -0
  43. package/dist/headlessCommand-CaFFcvJA.cjs +58 -0
  44. package/dist/headlessCommand-CaFFcvJA.cjs.map +1 -0
  45. package/dist/index-COS4uLcb.d.mts +24 -0
  46. package/dist/index-COS4uLcb.d.mts.map +1 -0
  47. package/dist/index-DEjyk6tg.d.mts +8 -0
  48. package/dist/index-DEjyk6tg.d.mts.map +1 -0
  49. package/dist/index-DSKnT657.d.mts +31 -0
  50. package/dist/index-DSKnT657.d.mts.map +1 -0
  51. package/dist/index.cjs +180 -0
  52. package/dist/index.cjs.map +1 -0
  53. package/dist/index.d.mts +53 -0
  54. package/dist/index.d.mts.map +1 -0
  55. package/dist/index.mjs +136 -0
  56. package/dist/index.mjs.map +1 -0
  57. package/dist/minorModeCommand.cjs +5 -0
  58. package/dist/minorModeCommand.d.mts +2 -0
  59. package/dist/minorModeCommand.mjs +2 -0
  60. package/dist/mode-BwRkDqO4.mjs +241 -0
  61. package/dist/mode-BwRkDqO4.mjs.map +1 -0
  62. package/dist/mode-Dft08ke8.cjs +444 -0
  63. package/dist/mode-Dft08ke8.cjs.map +1 -0
  64. package/dist/mode-EZWqhrYy.d.mts +492 -0
  65. package/dist/mode-EZWqhrYy.d.mts.map +1 -0
  66. package/dist/mode.cjs +36 -0
  67. package/dist/mode.d.mts +2 -0
  68. package/dist/mode.mjs +2 -0
  69. package/dist/modeDefinition-BcqEwTzh.mjs +46 -0
  70. package/dist/modeDefinition-BcqEwTzh.mjs.map +1 -0
  71. package/dist/modeDefinition-BtgwqXMo.cjs +51 -0
  72. package/dist/modeDefinition-BtgwqXMo.cjs.map +1 -0
  73. package/dist/modeDefinition.cjs +3 -0
  74. package/dist/modeDefinition.d.mts +2 -0
  75. package/dist/modeDefinition.mjs +2 -0
  76. package/dist/owner-BbCQufLu.cjs +14 -0
  77. package/dist/owner-BbCQufLu.cjs.map +1 -0
  78. package/dist/owner-Bs55c_qE.mjs +9 -0
  79. package/dist/owner-Bs55c_qE.mjs.map +1 -0
  80. package/dist/owner.cjs +3 -0
  81. package/dist/owner.d.mts +2 -0
  82. package/dist/owner.mjs +2 -0
  83. package/dist/projection-Cy1LWVIe.mjs +47 -0
  84. package/dist/projection-Cy1LWVIe.mjs.map +1 -0
  85. package/dist/projection-DYOm9Kev.cjs +58 -0
  86. package/dist/projection-DYOm9Kev.cjs.map +1 -0
  87. package/dist/projection.cjs +4 -0
  88. package/dist/projection.d.mts +12 -0
  89. package/dist/projection.d.mts.map +1 -0
  90. package/dist/projection.mjs +2 -0
  91. package/dist/reloadHandoff-C-GaCf0F.cjs +71 -0
  92. package/dist/reloadHandoff-C-GaCf0F.cjs.map +1 -0
  93. package/dist/reloadHandoff-D1QsS9qd.mjs +54 -0
  94. package/dist/reloadHandoff-D1QsS9qd.mjs.map +1 -0
  95. package/dist/reloadHandoff.cjs +5 -0
  96. package/dist/reloadHandoff.d.mts +11 -0
  97. package/dist/reloadHandoff.d.mts.map +1 -0
  98. package/dist/reloadHandoff.mjs +2 -0
  99. package/dist/validation-BuQc8UrL.mjs +81 -0
  100. package/dist/validation-BuQc8UrL.mjs.map +1 -0
  101. package/dist/validation-DRV8Dtoc.cjs +104 -0
  102. package/dist/validation-DRV8Dtoc.cjs.map +1 -0
  103. package/package.json +157 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-jTd7UXiI.cjs","names":["DoomProtocolError","MINOR_MODE_ERROR_CODE","MINOR_MODE_CATALOG_SOURCE","minorModeKey","validateMinorModeDefinition"],"sources":["../src/services/catalog/index.ts"],"sourcesContent":["import type { DoomExtensionContext } from '@agimon-ai/doompi-core/config';\nimport { DoomProtocolError } from '@agimon-ai/doompi-core/protocol';\n\nimport {\n MINOR_MODE_ACTION_TIMEOUT_MS,\n MINOR_MODE_CATALOG_SOURCE,\n MINOR_MODE_ERROR_CODE,\n MINOR_MODE_MAX_RECORDS,\n type MinorModeActionRequest,\n type MinorModeActionResponse,\n type MinorModeCatalogService,\n type MinorModeCatalogSnapshot,\n type MinorModeOwnerDefinition,\n type MinorModeOwnerHandle,\n type MinorModeRecord,\n type MinorModeRegistrationRef,\n type MinorModeSessionKind,\n} from '../../schemas/mode';\nimport { minorModeKey, validateMinorModeActionArguments, validateMinorModeDefinition } from '../validation';\n\nexport interface MinorModeCatalogHostOptions<ExtensionContext extends DoomExtensionContext = DoomExtensionContext> {\n sessionKind: MinorModeSessionKind;\n context: ExtensionContext;\n actionTimeoutMs?: number;\n restoreSnapshot?: MinorModeCatalogSnapshot;\n onRestorationError?(error: unknown): void;\n routeInvocation?(\n request: MinorModeActionRequest,\n requesterSource: string,\n invoke: () => Promise<MinorModeActionResponse>,\n ): Promise<MinorModeActionResponse>;\n}\n\ninterface ActiveOwner {\n readonly token: symbol;\n readonly definition: MinorModeOwnerDefinition<DoomExtensionContext>;\n record: MinorModeRecord;\n readonly operations: Set<AbortController>;\n}\n\ninterface PendingOperation {\n readonly requesterSource: string;\n readonly request: MinorModeActionRequest;\n readonly promise: Promise<MinorModeActionResponse>;\n}\n\nfunction protocolError(code: string, message: string, retryable = false): DoomProtocolError {\n return new DoomProtocolError({ code, message, retryable });\n}\n\nfunction registrationRef(record: MinorModeRecord): MinorModeRegistrationRef {\n return {\n source: record.descriptor.source,\n id: record.descriptor.id,\n ownerGeneration: record.ownerGeneration,\n registrationId: record.registrationId,\n };\n}\n\nfunction sameRegistration(record: MinorModeRecord, ref: MinorModeRegistrationRef): boolean {\n return (\n record.descriptor.source === ref.source &&\n record.descriptor.id === ref.id &&\n record.ownerGeneration === ref.ownerGeneration &&\n record.registrationId === ref.registrationId\n );\n}\n\nfunction sameRequest(left: MinorModeActionRequest, right: MinorModeActionRequest): boolean {\n return JSON.stringify(left) === JSON.stringify(right);\n}\n\nfunction abortError(signal: AbortSignal): DoomProtocolError {\n const timeout = signal.reason === 'minor-mode-timeout';\n return protocolError(\n timeout ? MINOR_MODE_ERROR_CODE.actionTimeout : MINOR_MODE_ERROR_CODE.actionAborted,\n timeout ? 'Minor-mode action timed out.' : 'Minor-mode action was aborted.',\n timeout,\n );\n}\n\nasync function runAbortable<T>(operation: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) throw abortError(signal);\n return new Promise<T>((resolve, reject) => {\n const aborted = (): void => reject(abortError(signal));\n signal.addEventListener('abort', aborted, { once: true });\n operation.then(resolve, reject).finally(() => signal.removeEventListener('abort', aborted));\n });\n}\n\nexport function createMinorModeCatalogHost<ExtensionContext extends DoomExtensionContext>(\n options: MinorModeCatalogHostOptions<ExtensionContext>,\n): MinorModeCatalogService {\n const generation = `${MINOR_MODE_CATALOG_SOURCE}:${crypto.randomUUID()}`;\n const actionTimeoutMs = options.actionTimeoutMs ?? MINOR_MODE_ACTION_TIMEOUT_MS;\n const owners = new Map<string, ActiveOwner>();\n const activeByMode = new Map<string, string>();\n const pending = new Map<string, PendingOperation>();\n const listeners = new Set<() => void>();\n const restoreTimers = new Set<ReturnType<typeof setTimeout>>();\n const restoreRecords = new Map<string, MinorModeRecord>(\n (options.restoreSnapshot?.modes ?? [])\n .filter(({ state }) => state.activation === 'active' || state.activation === 'activating')\n .map((record) => [minorModeKey(record.descriptor), structuredClone(record)]),\n );\n let revision = 0;\n let disposed = false;\n\n const notify = (): void => {\n revision += 1;\n for (const listener of listeners) listener();\n };\n\n const snapshot = (): MinorModeCatalogSnapshot => ({\n hostGeneration: generation,\n revision,\n modes: [...owners.values()]\n .map(({ record }) => structuredClone(record))\n .toSorted(\n (left, right) =>\n left.descriptor.order - right.descriptor.order ||\n left.descriptor.source.localeCompare(right.descriptor.source) ||\n left.descriptor.id.localeCompare(right.descriptor.id),\n ),\n });\n\n const invokeOwner = async (\n owner: ActiveOwner,\n request: MinorModeActionRequest,\n signal: AbortSignal,\n ): Promise<MinorModeActionResponse> => {\n const action = owner.record.descriptor.actions.find(({ id }) => id === request.actionId);\n const availability = owner.record.state.actions.find(({ id }) => id === request.actionId);\n if (!action) {\n throw protocolError(\n MINOR_MODE_ERROR_CODE.actionNotFound,\n `Minor mode action '${request.actionId}' was not found.`,\n );\n }\n if (!availability?.enabled) {\n throw protocolError(\n MINOR_MODE_ERROR_CODE.actionDisabled,\n availability?.disabledReason ?? `Minor mode action '${request.actionId}' is disabled.`,\n );\n }\n if (!action.contexts.includes(options.sessionKind)) {\n throw protocolError(\n MINOR_MODE_ERROR_CODE.unsupportedContext,\n `Action '${action.id}' is unavailable in ${options.sessionKind} sessions.`,\n );\n }\n validateMinorModeActionArguments(action, request.arguments);\n try {\n const result = await runAbortable(\n Promise.resolve(\n owner.definition.handleAction(request.actionId, structuredClone(request.arguments), {\n context: options.context,\n operationId: request.operationId,\n sessionKind: options.sessionKind,\n signal,\n }),\n ),\n signal,\n );\n const current = owners.get(minorModeKey(owner.record.descriptor));\n if (disposed || current !== owner) {\n throw protocolError(MINOR_MODE_ERROR_CODE.staleRegistration, 'Minor-mode owner was replaced.');\n }\n return {\n operationId: request.operationId,\n catalogRevision: revision,\n mode: structuredClone(owner.record),\n ...(result?.message ? { message: result.message } : {}),\n };\n } catch (error) {\n if (signal.aborted) throw abortError(signal);\n if (error instanceof DoomProtocolError) throw error;\n owner.definition.onError?.(error);\n throw protocolError(MINOR_MODE_ERROR_CODE.ownerFailed, error instanceof Error ? error.message : String(error));\n }\n };\n\n const invoke = (\n request: MinorModeActionRequest,\n requesterSource: string,\n signal?: AbortSignal,\n ): Promise<MinorModeActionResponse> => {\n if (disposed) {\n return Promise.reject(protocolError(MINOR_MODE_ERROR_CODE.sessionReplaced, 'Minor-mode catalog is disposed.'));\n }\n const terminal = pending.get(request.operationId);\n if (terminal) {\n if (terminal.requesterSource !== requesterSource || !sameRequest(terminal.request, request)) {\n return Promise.reject(\n protocolError(MINOR_MODE_ERROR_CODE.registrationConflict, 'Minor-mode operation id was reused.'),\n );\n }\n return terminal.promise;\n }\n const key = minorModeKey(request.mode);\n const owner = owners.get(key);\n if (!owner || !sameRegistration(owner.record, request.mode)) {\n return Promise.reject(protocolError(MINOR_MODE_ERROR_CODE.modeNotFound, 'Minor mode is unavailable.'));\n }\n if (activeByMode.has(key)) {\n return Promise.reject(protocolError(MINOR_MODE_ERROR_CODE.modeBusy, 'Minor mode already has an active action.'));\n }\n\n const controller = new AbortController();\n const onAbort = (): void => controller.abort(signal?.reason);\n signal?.addEventListener('abort', onAbort, { once: true });\n const timer = setTimeout(() => controller.abort('minor-mode-timeout'), actionTimeoutMs);\n owner.operations.add(controller);\n activeByMode.set(key, request.operationId);\n const direct = () => invokeOwner(owner, request, controller.signal);\n const promise = Promise.resolve(\n options.routeInvocation ? options.routeInvocation(request, requesterSource, direct) : direct(),\n ).finally(() => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n owner.operations.delete(controller);\n if (activeByMode.get(key) === request.operationId) activeByMode.delete(key);\n pending.delete(request.operationId);\n });\n pending.set(request.operationId, { requesterSource, request: structuredClone(request), promise });\n return promise;\n };\n\n const scheduleRestoration = (owner: ActiveOwner): void => {\n const key = minorModeKey(owner.record.descriptor);\n const previous = restoreRecords.get(key);\n restoreRecords.delete(key);\n if (!previous) return;\n const timer = setTimeout(() => {\n restoreTimers.delete(timer);\n if (disposed || owners.get(key) !== owner || owner.record.state.activation === 'active') return;\n const action = owner.record.descriptor.actions.find(({ id }) => id === 'activate');\n const availability = owner.record.state.actions.find(({ id }) => id === 'activate');\n if (!action || action.parameters.some(({ required }) => required) || !availability?.enabled) return;\n void invoke(\n {\n operationId: `minor-mode-restore:${crypto.randomUUID()}`,\n mode: registrationRef(owner.record),\n actionId: 'activate',\n arguments: {},\n },\n MINOR_MODE_CATALOG_SOURCE,\n ).catch((error: unknown) => {\n if (options.onRestorationError) options.onRestorationError(error);\n else\n queueMicrotask(() => {\n throw error instanceof Error ? error : new Error(String(error));\n });\n });\n }, 0);\n restoreTimers.add(timer);\n };\n\n return {\n generation,\n getSnapshot: snapshot,\n list: () => snapshot().modes,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n registerOwner(definition) {\n if (disposed) throw protocolError(MINOR_MODE_ERROR_CODE.sessionReplaced, 'Minor-mode catalog is disposed.');\n if (owners.size >= MINOR_MODE_MAX_RECORDS) {\n throw protocolError(MINOR_MODE_ERROR_CODE.registrationConflict, 'Minor-mode catalog capacity reached.');\n }\n const initialState = structuredClone(definition.initialState);\n const invalid = validateMinorModeDefinition(definition.descriptor, initialState);\n if (invalid) throw protocolError(MINOR_MODE_ERROR_CODE.registrationConflict, invalid);\n const key = minorModeKey(definition.descriptor);\n if (owners.has(key)) {\n throw protocolError(\n MINOR_MODE_ERROR_CODE.registrationConflict,\n `Minor mode '${definition.descriptor.source}/${definition.descriptor.id}' already has a live owner.`,\n );\n }\n const owner: ActiveOwner = {\n token: Symbol(key),\n definition: definition as unknown as MinorModeOwnerDefinition<DoomExtensionContext>,\n operations: new Set(),\n record: {\n descriptor: structuredClone(definition.descriptor),\n state: initialState,\n ownerGeneration: `${key}:${crypto.randomUUID()}`,\n registrationId: `minor-mode-registration:${crypto.randomUUID()}`,\n stateRevision: 0,\n },\n };\n owners.set(key, owner);\n notify();\n scheduleRestoration(owner);\n let ownerDisposed = false;\n const handle: MinorModeOwnerHandle = {\n getState: () => structuredClone(owner.record.state),\n publish(state) {\n if (ownerDisposed || owners.get(key) !== owner) return;\n const validation = validateMinorModeDefinition(owner.record.descriptor, state);\n if (validation) throw new Error(validation);\n owner.record = {\n ...owner.record,\n state: structuredClone(state),\n stateRevision: owner.record.stateRevision + 1,\n };\n notify();\n },\n dispose() {\n if (ownerDisposed) return;\n ownerDisposed = true;\n if (owners.get(key) !== owner) return;\n for (const controller of owner.operations) controller.abort('minor-mode-owner-disposed');\n owner.operations.clear();\n owners.delete(key);\n notify();\n },\n };\n return handle;\n },\n invoke,\n dispose() {\n if (disposed) return;\n disposed = true;\n for (const timer of restoreTimers) clearTimeout(timer);\n restoreTimers.clear();\n for (const owner of owners.values()) {\n for (const controller of owner.operations) controller.abort('minor-mode-catalog-disposed');\n owner.operations.clear();\n }\n owners.clear();\n pending.clear();\n activeByMode.clear();\n restoreRecords.clear();\n notify();\n listeners.clear();\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_catalog = require("./catalog-jTd7UXiI.cjs");
3
+ exports.createMinorModeCatalogHost = require_catalog.createMinorModeCatalogHost;
@@ -0,0 +1,14 @@
1
+ import { D as MinorModeCatalogService, O as MinorModeCatalogSnapshot, Y as MinorModeSessionKind, x as MinorModeActionResponse, y as MinorModeActionRequest } from "./mode-EZWqhrYy.mjs";
2
+ import { DoomExtensionContext } from "@agimon-ai/doompi-core/config";
3
+ //#region src/services/catalog/index.d.ts
4
+ export interface MinorModeCatalogHostOptions<ExtensionContext extends DoomExtensionContext = DoomExtensionContext> {
5
+ sessionKind: MinorModeSessionKind;
6
+ context: ExtensionContext;
7
+ actionTimeoutMs?: number;
8
+ restoreSnapshot?: MinorModeCatalogSnapshot;
9
+ onRestorationError?(error: unknown): void;
10
+ routeInvocation?(request: MinorModeActionRequest, requesterSource: string, invoke: () => Promise<MinorModeActionResponse>): Promise<MinorModeActionResponse>;
11
+ }
12
+ export declare function createMinorModeCatalogHost<ExtensionContext extends DoomExtensionContext>(options: MinorModeCatalogHostOptions<ExtensionContext>): MinorModeCatalogService;
13
+ //#endregion
14
+ //# sourceMappingURL=catalog.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.mts","names":[],"sources":["../src/services/catalog/index.ts"],"mappings":";;;iBAoBiB,4BAA4B,yBAAyB,uBAAuB;EAC3F,aAAa;EACb,SAAS;EACT;EACA,kBAAkB;EAClB,oBAAoB;EACpB,iBACE,SAAS,wBACT,yBACA,cAAc,QAAQ,2BACrB,QAAQ;;wBA4DG,2BAA2B,yBAAyB,sBAClE,SAAS,4BAA4B,oBACpC"}
@@ -0,0 +1,2 @@
1
+ import { t as createMinorModeCatalogHost } from "./catalog-8apySKXB.mjs";
2
+ export { createMinorModeCatalogHost };
@@ -0,0 +1,11 @@
1
+ //#region src/constants/command.ts
2
+ const MINOR_MODE_COMMAND_DESCRIPTION = "Toggle or drive minor modes";
3
+ //#endregion
4
+ Object.defineProperty(exports, "MINOR_MODE_COMMAND_DESCRIPTION", {
5
+ enumerable: true,
6
+ get: function() {
7
+ return MINOR_MODE_COMMAND_DESCRIPTION;
8
+ }
9
+ });
10
+
11
+ //# sourceMappingURL=command-B5HZmmyU.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-B5HZmmyU.cjs","names":[],"sources":["../src/constants/command.ts"],"sourcesContent":["export const MINOR_MODE_COMMAND_DESCRIPTION = 'Toggle or drive minor modes';\n"],"mappings":";AAAA,MAAa,iCAAiC"}
@@ -0,0 +1,6 @@
1
+ //#region src/constants/command.ts
2
+ const MINOR_MODE_COMMAND_DESCRIPTION = "Toggle or drive minor modes";
3
+ //#endregion
4
+ export { MINOR_MODE_COMMAND_DESCRIPTION as t };
5
+
6
+ //# sourceMappingURL=command-BvYpwiin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-BvYpwiin.mjs","names":[],"sources":["../src/constants/command.ts"],"sourcesContent":["export const MINOR_MODE_COMMAND_DESCRIPTION = 'Toggle or drive minor modes';\n"],"mappings":";AAAA,MAAa,iCAAiC"}
@@ -0,0 +1,128 @@
1
+ //#region src/services/command/index.ts
2
+ const MINOR_MODE_COMMAND = "minor";
3
+ const REQUESTER_SOURCE = "@agimon-ai/doompi/mode-catalog/ui-command";
4
+ function isOn(record) {
5
+ return record.state.activation === "active" || record.state.activation === "deactivating";
6
+ }
7
+ /** A catalog mode addressed the way a person types it: id, label, or id stem. */
8
+ function matchMinorMode(records, query) {
9
+ const needle = query.toLowerCase();
10
+ return records.find((record) => record.descriptor.id.toLowerCase() === needle || record.descriptor.label.toLowerCase() === needle || record.descriptor.id.toLowerCase().split(".")[0] === needle);
11
+ }
12
+ /** The actions a session of this kind can currently take on a mode. */
13
+ function actionsFor(record, kind) {
14
+ return record.descriptor.actions.filter((action) => {
15
+ if (!action.contexts.includes(kind)) return false;
16
+ return record.state.actions.find((entry) => entry.id === action.id)?.enabled !== false;
17
+ });
18
+ }
19
+ async function promptArguments(ui, action) {
20
+ const collected = {};
21
+ for (const parameter of action.parameters) {
22
+ if (!parameter.required) continue;
23
+ const title = `${action.label}: ${parameter.label}`;
24
+ if (parameter.kind === "boolean") {
25
+ const value = await ui.confirm(title, parameter.description ?? "");
26
+ if (value === void 0) return void 0;
27
+ collected[parameter.name] = value;
28
+ continue;
29
+ }
30
+ if (parameter.kind === "enum") {
31
+ const options = parameter.choices.map((choice) => choice.label);
32
+ const picked = await ui.select(title, options);
33
+ const choice = picked === void 0 ? void 0 : parameter.choices[options.indexOf(picked)];
34
+ if (!choice) return void 0;
35
+ collected[parameter.name] = choice.value;
36
+ continue;
37
+ }
38
+ const raw = await ui.input(title, parameter.description ?? "");
39
+ if (raw === void 0 || raw === "") return void 0;
40
+ if (parameter.kind === "number") {
41
+ const value = Number(raw);
42
+ if (!Number.isFinite(value)) {
43
+ await ui.notify(`${parameter.label} must be a number.`, "warning");
44
+ return;
45
+ }
46
+ collected[parameter.name] = value;
47
+ } else collected[parameter.name] = raw;
48
+ }
49
+ return collected;
50
+ }
51
+ /** Runs the catalog command against an explicit interaction surface. */
52
+ async function executeMinorModeCommand(args, options) {
53
+ const { catalog, kind, ui } = options;
54
+ if (!catalog) {
55
+ await ui.notify("Minor modes are unavailable in this session.", "warning");
56
+ return;
57
+ }
58
+ const records = catalog.list();
59
+ const [modeQuery, actionQuery] = args.trim().split(/\s+/).filter(Boolean);
60
+ let record;
61
+ if (modeQuery) {
62
+ record = matchMinorMode(records, modeQuery);
63
+ if (!record) {
64
+ const known = records.map((entry) => entry.descriptor.label.toLowerCase()).join(", ") || "none";
65
+ await ui.notify(`No minor mode matches "${modeQuery}". Available: ${known}.`, "warning");
66
+ return;
67
+ }
68
+ } else {
69
+ const listed = records.filter((entry) => actionsFor(entry, kind).length > 0);
70
+ if (listed.length === 0) {
71
+ await ui.notify("No minor modes are available in this session.", "info");
72
+ return;
73
+ }
74
+ const labels = listed.map((entry) => `${isOn(entry) ? "[x]" : "[ ]"} ${entry.descriptor.label}: ${entry.descriptor.description}`);
75
+ const on = listed.filter(isOn).length;
76
+ const picked = await ui.select(`Minor modes (${String(on)} on)`, labels);
77
+ if (picked === void 0) return;
78
+ record = listed[labels.indexOf(picked)];
79
+ if (!record) return;
80
+ }
81
+ const actions = actionsFor(record, kind);
82
+ if (actions.length === 0) {
83
+ const reasons = [...new Set(record.state.actions.map((entry) => entry.disabledReason).filter((reason) => reason !== void 0 && reason.length > 0))];
84
+ const because = reasons.length > 0 ? ` ${reasons.join(" ")}` : "";
85
+ await ui.notify(`${record.descriptor.label} has no actions available in this session.${because}`, "warning");
86
+ return;
87
+ }
88
+ let action;
89
+ if (actionQuery) {
90
+ action = actions.find((entry) => entry.id.toLowerCase() === actionQuery.toLowerCase());
91
+ if (!action) {
92
+ const known = actions.map((entry) => entry.id).join(", ");
93
+ await ui.notify(`No "${actionQuery}" action on ${record.descriptor.label}. Available: ${known}.`, "warning");
94
+ return;
95
+ }
96
+ } else if (actions.length === 1) action = actions[0];
97
+ else {
98
+ const labels = actions.map((entry) => `${entry.label}: ${entry.description}`);
99
+ const picked = await ui.select(`${record.descriptor.label} (${record.state.activation})`, labels);
100
+ if (picked === void 0) return;
101
+ action = actions[labels.indexOf(picked)];
102
+ }
103
+ if (!action) return;
104
+ const argumentsValue = await promptArguments(ui, action);
105
+ if (argumentsValue === void 0) return;
106
+ try {
107
+ const response = await catalog.invoke({
108
+ operationId: globalThis.crypto.randomUUID(),
109
+ mode: {
110
+ source: record.descriptor.source,
111
+ id: record.descriptor.id,
112
+ ownerGeneration: record.ownerGeneration,
113
+ registrationId: record.registrationId
114
+ },
115
+ actionId: action.id,
116
+ arguments: argumentsValue
117
+ }, REQUESTER_SOURCE);
118
+ const state = response.mode.state;
119
+ const detail = state.detail ? `: ${state.detail}` : "";
120
+ await ui.notify(response.message ?? `${record.descriptor.label} is ${state.activation}${detail}.`, "info");
121
+ } catch (error) {
122
+ await ui.notify(`${record.descriptor.label} ${action.label} failed: ${error instanceof Error ? error.message : String(error)}`, "error");
123
+ }
124
+ }
125
+ //#endregion
126
+ export { matchMinorMode as i, actionsFor as n, executeMinorModeCommand as r, MINOR_MODE_COMMAND as t };
127
+
128
+ //# sourceMappingURL=command-C4u3oOPT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-C4u3oOPT.mjs","names":[],"sources":["../src/services/command/index.ts"],"sourcesContent":["import type {\n MinorModeActionDescriptor,\n MinorModeArguments,\n MinorModeCatalogService,\n MinorModeRecord,\n MinorModeSessionKind,\n} from '../../schemas/mode';\n\nexport const MINOR_MODE_COMMAND = 'minor';\nexport { MINOR_MODE_COMMAND_DESCRIPTION } from '../../constants/command';\nconst REQUESTER_SOURCE = '@agimon-ai/doompi/mode-catalog/ui-command';\n\ntype NotificationLevel = 'info' | 'warning' | 'error';\n\nexport interface MinorModeCommandPrompter {\n select(title: string, options: readonly string[]): Promise<string | undefined>;\n input(title: string, message: string): Promise<string | undefined>;\n confirm(title: string, message: string): Promise<boolean | undefined>;\n notify(message: string, level: NotificationLevel): void | Promise<void>;\n}\n\nfunction isOn(record: MinorModeRecord): boolean {\n return record.state.activation === 'active' || record.state.activation === 'deactivating';\n}\n\n/** A catalog mode addressed the way a person types it: id, label, or id stem. */\nexport function matchMinorMode(records: readonly MinorModeRecord[], query: string): MinorModeRecord | undefined {\n const needle = query.toLowerCase();\n return records.find(\n (record) =>\n record.descriptor.id.toLowerCase() === needle ||\n record.descriptor.label.toLowerCase() === needle ||\n record.descriptor.id.toLowerCase().split('.')[0] === needle,\n );\n}\n\n/** The actions a session of this kind can currently take on a mode. */\nexport function actionsFor(record: MinorModeRecord, kind: MinorModeSessionKind): MinorModeActionDescriptor[] {\n return record.descriptor.actions.filter((action) => {\n if (!action.contexts.includes(kind)) return false;\n const availability = record.state.actions.find((entry) => entry.id === action.id);\n return availability?.enabled !== false;\n });\n}\n\nasync function promptArguments(\n ui: MinorModeCommandPrompter,\n action: MinorModeActionDescriptor,\n): Promise<MinorModeArguments | undefined> {\n const collected: MinorModeArguments = {};\n for (const parameter of action.parameters) {\n if (!parameter.required) continue;\n const title = `${action.label}: ${parameter.label}`;\n if (parameter.kind === 'boolean') {\n const value = await ui.confirm(title, parameter.description ?? '');\n if (value === undefined) return undefined;\n collected[parameter.name] = value;\n continue;\n }\n if (parameter.kind === 'enum') {\n const options = parameter.choices.map((choice) => choice.label);\n const picked = await ui.select(title, options);\n const choice = picked === undefined ? undefined : parameter.choices[options.indexOf(picked)];\n if (!choice) return undefined;\n collected[parameter.name] = choice.value;\n continue;\n }\n const raw = await ui.input(title, parameter.description ?? '');\n if (raw === undefined || raw === '') return undefined;\n if (parameter.kind === 'number') {\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n await ui.notify(`${parameter.label} must be a number.`, 'warning');\n return undefined;\n }\n collected[parameter.name] = value;\n } else {\n collected[parameter.name] = raw;\n }\n }\n return collected;\n}\n\nexport interface ExecuteMinorModeCommandOptions {\n catalog: MinorModeCatalogService | undefined;\n kind: MinorModeSessionKind;\n ui: MinorModeCommandPrompter;\n}\n\n/** Runs the catalog command against an explicit interaction surface. */\nexport async function executeMinorModeCommand(args: string, options: ExecuteMinorModeCommandOptions): Promise<void> {\n const { catalog, kind, ui } = options;\n if (!catalog) {\n await ui.notify('Minor modes are unavailable in this session.', 'warning');\n return;\n }\n\n const records = catalog.list();\n const [modeQuery, actionQuery] = args.trim().split(/\\s+/).filter(Boolean);\n\n let record: MinorModeRecord | undefined;\n if (modeQuery) {\n record = matchMinorMode(records, modeQuery);\n if (!record) {\n const known = records.map((entry) => entry.descriptor.label.toLowerCase()).join(', ') || 'none';\n await ui.notify(`No minor mode matches \"${modeQuery}\". Available: ${known}.`, 'warning');\n return;\n }\n } else {\n const listed = records.filter((entry) => actionsFor(entry, kind).length > 0);\n if (listed.length === 0) {\n await ui.notify('No minor modes are available in this session.', 'info');\n return;\n }\n const labels = listed.map(\n (entry) => `${isOn(entry) ? '[x]' : '[ ]'} ${entry.descriptor.label}: ${entry.descriptor.description}`,\n );\n const on = listed.filter(isOn).length;\n const picked = await ui.select(`Minor modes (${String(on)} on)`, labels);\n if (picked === undefined) return;\n record = listed[labels.indexOf(picked)];\n if (!record) return;\n }\n\n const actions = actionsFor(record, kind);\n if (actions.length === 0) {\n // The mode already said why each action is unavailable. Repeating that\n // is the difference between a dead end and an explanation: \"requires\n // an interactive session\" tells a cockpit user to reach for the TUI,\n // where the bare sentence leaves them guessing.\n const reasons = [\n ...new Set(\n record.state.actions\n .map((entry) => entry.disabledReason)\n .filter((reason): reason is string => reason !== undefined && reason.length > 0),\n ),\n ];\n const because = reasons.length > 0 ? ` ${reasons.join(' ')}` : '';\n await ui.notify(`${record.descriptor.label} has no actions available in this session.${because}`, 'warning');\n return;\n }\n\n let action: MinorModeActionDescriptor | undefined;\n if (actionQuery) {\n action = actions.find((entry) => entry.id.toLowerCase() === actionQuery.toLowerCase());\n if (!action) {\n const known = actions.map((entry) => entry.id).join(', ');\n await ui.notify(`No \"${actionQuery}\" action on ${record.descriptor.label}. Available: ${known}.`, 'warning');\n return;\n }\n } else if (actions.length === 1) {\n action = actions[0];\n } else {\n const labels = actions.map((entry) => `${entry.label}: ${entry.description}`);\n const picked = await ui.select(`${record.descriptor.label} (${record.state.activation})`, labels);\n if (picked === undefined) return;\n action = actions[labels.indexOf(picked)];\n }\n if (!action) return;\n\n const argumentsValue = await promptArguments(ui, action);\n if (argumentsValue === undefined) return;\n\n try {\n const response = await catalog.invoke(\n {\n operationId: globalThis.crypto.randomUUID(),\n mode: {\n source: record.descriptor.source,\n id: record.descriptor.id,\n ownerGeneration: record.ownerGeneration,\n registrationId: record.registrationId,\n },\n actionId: action.id,\n arguments: argumentsValue,\n },\n REQUESTER_SOURCE,\n );\n const state = response.mode.state;\n const detail = state.detail ? `: ${state.detail}` : '';\n await ui.notify(response.message ?? `${record.descriptor.label} is ${state.activation}${detail}.`, 'info');\n } catch (error) {\n await ui.notify(\n `${record.descriptor.label} ${action.label} failed: ${error instanceof Error ? error.message : String(error)}`,\n 'error',\n );\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ //#region src/services/command/index.ts
2
+ const MINOR_MODE_COMMAND = "minor";
3
+ const REQUESTER_SOURCE = "@agimon-ai/doompi/mode-catalog/ui-command";
4
+ function isOn(record) {
5
+ return record.state.activation === "active" || record.state.activation === "deactivating";
6
+ }
7
+ /** A catalog mode addressed the way a person types it: id, label, or id stem. */
8
+ function matchMinorMode(records, query) {
9
+ const needle = query.toLowerCase();
10
+ return records.find((record) => record.descriptor.id.toLowerCase() === needle || record.descriptor.label.toLowerCase() === needle || record.descriptor.id.toLowerCase().split(".")[0] === needle);
11
+ }
12
+ /** The actions a session of this kind can currently take on a mode. */
13
+ function actionsFor(record, kind) {
14
+ return record.descriptor.actions.filter((action) => {
15
+ if (!action.contexts.includes(kind)) return false;
16
+ return record.state.actions.find((entry) => entry.id === action.id)?.enabled !== false;
17
+ });
18
+ }
19
+ async function promptArguments(ui, action) {
20
+ const collected = {};
21
+ for (const parameter of action.parameters) {
22
+ if (!parameter.required) continue;
23
+ const title = `${action.label}: ${parameter.label}`;
24
+ if (parameter.kind === "boolean") {
25
+ const value = await ui.confirm(title, parameter.description ?? "");
26
+ if (value === void 0) return void 0;
27
+ collected[parameter.name] = value;
28
+ continue;
29
+ }
30
+ if (parameter.kind === "enum") {
31
+ const options = parameter.choices.map((choice) => choice.label);
32
+ const picked = await ui.select(title, options);
33
+ const choice = picked === void 0 ? void 0 : parameter.choices[options.indexOf(picked)];
34
+ if (!choice) return void 0;
35
+ collected[parameter.name] = choice.value;
36
+ continue;
37
+ }
38
+ const raw = await ui.input(title, parameter.description ?? "");
39
+ if (raw === void 0 || raw === "") return void 0;
40
+ if (parameter.kind === "number") {
41
+ const value = Number(raw);
42
+ if (!Number.isFinite(value)) {
43
+ await ui.notify(`${parameter.label} must be a number.`, "warning");
44
+ return;
45
+ }
46
+ collected[parameter.name] = value;
47
+ } else collected[parameter.name] = raw;
48
+ }
49
+ return collected;
50
+ }
51
+ /** Runs the catalog command against an explicit interaction surface. */
52
+ async function executeMinorModeCommand(args, options) {
53
+ const { catalog, kind, ui } = options;
54
+ if (!catalog) {
55
+ await ui.notify("Minor modes are unavailable in this session.", "warning");
56
+ return;
57
+ }
58
+ const records = catalog.list();
59
+ const [modeQuery, actionQuery] = args.trim().split(/\s+/).filter(Boolean);
60
+ let record;
61
+ if (modeQuery) {
62
+ record = matchMinorMode(records, modeQuery);
63
+ if (!record) {
64
+ const known = records.map((entry) => entry.descriptor.label.toLowerCase()).join(", ") || "none";
65
+ await ui.notify(`No minor mode matches "${modeQuery}". Available: ${known}.`, "warning");
66
+ return;
67
+ }
68
+ } else {
69
+ const listed = records.filter((entry) => actionsFor(entry, kind).length > 0);
70
+ if (listed.length === 0) {
71
+ await ui.notify("No minor modes are available in this session.", "info");
72
+ return;
73
+ }
74
+ const labels = listed.map((entry) => `${isOn(entry) ? "[x]" : "[ ]"} ${entry.descriptor.label}: ${entry.descriptor.description}`);
75
+ const on = listed.filter(isOn).length;
76
+ const picked = await ui.select(`Minor modes (${String(on)} on)`, labels);
77
+ if (picked === void 0) return;
78
+ record = listed[labels.indexOf(picked)];
79
+ if (!record) return;
80
+ }
81
+ const actions = actionsFor(record, kind);
82
+ if (actions.length === 0) {
83
+ const reasons = [...new Set(record.state.actions.map((entry) => entry.disabledReason).filter((reason) => reason !== void 0 && reason.length > 0))];
84
+ const because = reasons.length > 0 ? ` ${reasons.join(" ")}` : "";
85
+ await ui.notify(`${record.descriptor.label} has no actions available in this session.${because}`, "warning");
86
+ return;
87
+ }
88
+ let action;
89
+ if (actionQuery) {
90
+ action = actions.find((entry) => entry.id.toLowerCase() === actionQuery.toLowerCase());
91
+ if (!action) {
92
+ const known = actions.map((entry) => entry.id).join(", ");
93
+ await ui.notify(`No "${actionQuery}" action on ${record.descriptor.label}. Available: ${known}.`, "warning");
94
+ return;
95
+ }
96
+ } else if (actions.length === 1) action = actions[0];
97
+ else {
98
+ const labels = actions.map((entry) => `${entry.label}: ${entry.description}`);
99
+ const picked = await ui.select(`${record.descriptor.label} (${record.state.activation})`, labels);
100
+ if (picked === void 0) return;
101
+ action = actions[labels.indexOf(picked)];
102
+ }
103
+ if (!action) return;
104
+ const argumentsValue = await promptArguments(ui, action);
105
+ if (argumentsValue === void 0) return;
106
+ try {
107
+ const response = await catalog.invoke({
108
+ operationId: globalThis.crypto.randomUUID(),
109
+ mode: {
110
+ source: record.descriptor.source,
111
+ id: record.descriptor.id,
112
+ ownerGeneration: record.ownerGeneration,
113
+ registrationId: record.registrationId
114
+ },
115
+ actionId: action.id,
116
+ arguments: argumentsValue
117
+ }, REQUESTER_SOURCE);
118
+ const state = response.mode.state;
119
+ const detail = state.detail ? `: ${state.detail}` : "";
120
+ await ui.notify(response.message ?? `${record.descriptor.label} is ${state.activation}${detail}.`, "info");
121
+ } catch (error) {
122
+ await ui.notify(`${record.descriptor.label} ${action.label} failed: ${error instanceof Error ? error.message : String(error)}`, "error");
123
+ }
124
+ }
125
+ //#endregion
126
+ Object.defineProperty(exports, "MINOR_MODE_COMMAND", {
127
+ enumerable: true,
128
+ get: function() {
129
+ return MINOR_MODE_COMMAND;
130
+ }
131
+ });
132
+ Object.defineProperty(exports, "actionsFor", {
133
+ enumerable: true,
134
+ get: function() {
135
+ return actionsFor;
136
+ }
137
+ });
138
+ Object.defineProperty(exports, "executeMinorModeCommand", {
139
+ enumerable: true,
140
+ get: function() {
141
+ return executeMinorModeCommand;
142
+ }
143
+ });
144
+ Object.defineProperty(exports, "matchMinorMode", {
145
+ enumerable: true,
146
+ get: function() {
147
+ return matchMinorMode;
148
+ }
149
+ });
150
+
151
+ //# sourceMappingURL=command-D9hQfJb_.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-D9hQfJb_.cjs","names":[],"sources":["../src/services/command/index.ts"],"sourcesContent":["import type {\n MinorModeActionDescriptor,\n MinorModeArguments,\n MinorModeCatalogService,\n MinorModeRecord,\n MinorModeSessionKind,\n} from '../../schemas/mode';\n\nexport const MINOR_MODE_COMMAND = 'minor';\nexport { MINOR_MODE_COMMAND_DESCRIPTION } from '../../constants/command';\nconst REQUESTER_SOURCE = '@agimon-ai/doompi/mode-catalog/ui-command';\n\ntype NotificationLevel = 'info' | 'warning' | 'error';\n\nexport interface MinorModeCommandPrompter {\n select(title: string, options: readonly string[]): Promise<string | undefined>;\n input(title: string, message: string): Promise<string | undefined>;\n confirm(title: string, message: string): Promise<boolean | undefined>;\n notify(message: string, level: NotificationLevel): void | Promise<void>;\n}\n\nfunction isOn(record: MinorModeRecord): boolean {\n return record.state.activation === 'active' || record.state.activation === 'deactivating';\n}\n\n/** A catalog mode addressed the way a person types it: id, label, or id stem. */\nexport function matchMinorMode(records: readonly MinorModeRecord[], query: string): MinorModeRecord | undefined {\n const needle = query.toLowerCase();\n return records.find(\n (record) =>\n record.descriptor.id.toLowerCase() === needle ||\n record.descriptor.label.toLowerCase() === needle ||\n record.descriptor.id.toLowerCase().split('.')[0] === needle,\n );\n}\n\n/** The actions a session of this kind can currently take on a mode. */\nexport function actionsFor(record: MinorModeRecord, kind: MinorModeSessionKind): MinorModeActionDescriptor[] {\n return record.descriptor.actions.filter((action) => {\n if (!action.contexts.includes(kind)) return false;\n const availability = record.state.actions.find((entry) => entry.id === action.id);\n return availability?.enabled !== false;\n });\n}\n\nasync function promptArguments(\n ui: MinorModeCommandPrompter,\n action: MinorModeActionDescriptor,\n): Promise<MinorModeArguments | undefined> {\n const collected: MinorModeArguments = {};\n for (const parameter of action.parameters) {\n if (!parameter.required) continue;\n const title = `${action.label}: ${parameter.label}`;\n if (parameter.kind === 'boolean') {\n const value = await ui.confirm(title, parameter.description ?? '');\n if (value === undefined) return undefined;\n collected[parameter.name] = value;\n continue;\n }\n if (parameter.kind === 'enum') {\n const options = parameter.choices.map((choice) => choice.label);\n const picked = await ui.select(title, options);\n const choice = picked === undefined ? undefined : parameter.choices[options.indexOf(picked)];\n if (!choice) return undefined;\n collected[parameter.name] = choice.value;\n continue;\n }\n const raw = await ui.input(title, parameter.description ?? '');\n if (raw === undefined || raw === '') return undefined;\n if (parameter.kind === 'number') {\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n await ui.notify(`${parameter.label} must be a number.`, 'warning');\n return undefined;\n }\n collected[parameter.name] = value;\n } else {\n collected[parameter.name] = raw;\n }\n }\n return collected;\n}\n\nexport interface ExecuteMinorModeCommandOptions {\n catalog: MinorModeCatalogService | undefined;\n kind: MinorModeSessionKind;\n ui: MinorModeCommandPrompter;\n}\n\n/** Runs the catalog command against an explicit interaction surface. */\nexport async function executeMinorModeCommand(args: string, options: ExecuteMinorModeCommandOptions): Promise<void> {\n const { catalog, kind, ui } = options;\n if (!catalog) {\n await ui.notify('Minor modes are unavailable in this session.', 'warning');\n return;\n }\n\n const records = catalog.list();\n const [modeQuery, actionQuery] = args.trim().split(/\\s+/).filter(Boolean);\n\n let record: MinorModeRecord | undefined;\n if (modeQuery) {\n record = matchMinorMode(records, modeQuery);\n if (!record) {\n const known = records.map((entry) => entry.descriptor.label.toLowerCase()).join(', ') || 'none';\n await ui.notify(`No minor mode matches \"${modeQuery}\". Available: ${known}.`, 'warning');\n return;\n }\n } else {\n const listed = records.filter((entry) => actionsFor(entry, kind).length > 0);\n if (listed.length === 0) {\n await ui.notify('No minor modes are available in this session.', 'info');\n return;\n }\n const labels = listed.map(\n (entry) => `${isOn(entry) ? '[x]' : '[ ]'} ${entry.descriptor.label}: ${entry.descriptor.description}`,\n );\n const on = listed.filter(isOn).length;\n const picked = await ui.select(`Minor modes (${String(on)} on)`, labels);\n if (picked === undefined) return;\n record = listed[labels.indexOf(picked)];\n if (!record) return;\n }\n\n const actions = actionsFor(record, kind);\n if (actions.length === 0) {\n // The mode already said why each action is unavailable. Repeating that\n // is the difference between a dead end and an explanation: \"requires\n // an interactive session\" tells a cockpit user to reach for the TUI,\n // where the bare sentence leaves them guessing.\n const reasons = [\n ...new Set(\n record.state.actions\n .map((entry) => entry.disabledReason)\n .filter((reason): reason is string => reason !== undefined && reason.length > 0),\n ),\n ];\n const because = reasons.length > 0 ? ` ${reasons.join(' ')}` : '';\n await ui.notify(`${record.descriptor.label} has no actions available in this session.${because}`, 'warning');\n return;\n }\n\n let action: MinorModeActionDescriptor | undefined;\n if (actionQuery) {\n action = actions.find((entry) => entry.id.toLowerCase() === actionQuery.toLowerCase());\n if (!action) {\n const known = actions.map((entry) => entry.id).join(', ');\n await ui.notify(`No \"${actionQuery}\" action on ${record.descriptor.label}. Available: ${known}.`, 'warning');\n return;\n }\n } else if (actions.length === 1) {\n action = actions[0];\n } else {\n const labels = actions.map((entry) => `${entry.label}: ${entry.description}`);\n const picked = await ui.select(`${record.descriptor.label} (${record.state.activation})`, labels);\n if (picked === undefined) return;\n action = actions[labels.indexOf(picked)];\n }\n if (!action) return;\n\n const argumentsValue = await promptArguments(ui, action);\n if (argumentsValue === undefined) return;\n\n try {\n const response = await catalog.invoke(\n {\n operationId: globalThis.crypto.randomUUID(),\n mode: {\n source: record.descriptor.source,\n id: record.descriptor.id,\n ownerGeneration: record.ownerGeneration,\n registrationId: record.registrationId,\n },\n actionId: action.id,\n arguments: argumentsValue,\n },\n REQUESTER_SOURCE,\n );\n const state = response.mode.state;\n const detail = state.detail ? `: ${state.detail}` : '';\n await ui.notify(response.message ?? `${record.descriptor.label} is ${state.activation}${detail}.`, 'info');\n } catch (error) {\n await ui.notify(\n `${record.descriptor.label} ${action.label} failed: ${error instanceof Error ? error.message : String(error)}`,\n 'error',\n );\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_command = require("./command-B5HZmmyU.cjs");
3
+ const require_command$1 = require("./command-D9hQfJb_.cjs");
4
+ exports.MINOR_MODE_COMMAND = require_command$1.MINOR_MODE_COMMAND;
5
+ exports.MINOR_MODE_COMMAND_DESCRIPTION = require_command.MINOR_MODE_COMMAND_DESCRIPTION;
6
+ exports.actionsFor = require_command$1.actionsFor;
7
+ exports.executeMinorModeCommand = require_command$1.executeMinorModeCommand;
8
+ exports.matchMinorMode = require_command$1.matchMinorMode;
@@ -0,0 +1,6 @@
1
+ import { a as executeMinorModeCommand, i as actionsFor, n as MINOR_MODE_COMMAND, o as matchMinorMode, r as MinorModeCommandPrompter, t as ExecuteMinorModeCommandOptions } from "./index-COS4uLcb.mjs";
2
+ //#region src/constants/command.d.ts
3
+ export declare const MINOR_MODE_COMMAND_DESCRIPTION = "Toggle or drive minor modes";
4
+ //#endregion
5
+ export { ExecuteMinorModeCommandOptions, MINOR_MODE_COMMAND, MinorModeCommandPrompter, actionsFor, executeMinorModeCommand, matchMinorMode };
6
+ //# sourceMappingURL=command.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.mts","names":[],"sources":["../src/constants/command.ts"],"mappings":";;qBAAa"}
@@ -0,0 +1,3 @@
1
+ import { t as MINOR_MODE_COMMAND_DESCRIPTION } from "./command-BvYpwiin.mjs";
2
+ import { i as matchMinorMode, n as actionsFor, r as executeMinorModeCommand, t as MINOR_MODE_COMMAND } from "./command-C4u3oOPT.mjs";
3
+ export { MINOR_MODE_COMMAND, MINOR_MODE_COMMAND_DESCRIPTION, actionsFor, executeMinorModeCommand, matchMinorMode };
@@ -0,0 +1,181 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ const require_mode = require("../mode-Dft08ke8.cjs");
6
+ const require_catalog = require("../catalog-jTd7UXiI.cjs");
7
+ const require_command = require("../command-B5HZmmyU.cjs");
8
+ const require_command$1 = require("../command-D9hQfJb_.cjs");
9
+ const require_projection = require("../projection-DYOm9Kev.cjs");
10
+ const require_reloadHandoff = require("../reloadHandoff-C-GaCf0F.cjs");
11
+ let _agimon_ai_doompi_core_piExtension = require("@agimon-ai/doompi-core/piExtension");
12
+ let _agimon_ai_doompi_core_extensionFile = require("@agimon-ai/doompi-core/extensionFile");
13
+ let _agimon_ai_doompi_core_cordisHost = require("@agimon-ai/doompi-core/cordisHost");
14
+ let _agimon_ai_doompi_core_notification = require("@agimon-ai/doompi-core/notification");
15
+ let _agimon_ai_doompi_core_transition = require("@agimon-ai/doompi-core/transition");
16
+ //#region src/extensions/workspaces/sessions/(backend)/_lib/minorModeCommand.ts
17
+ function sessionKindOf(ctx) {
18
+ return ctx.hasUI && ctx.mode === "tui" ? "tui" : "headless";
19
+ }
20
+ /** Register the Pi prompt adapter for the shared minor-mode command behavior. */
21
+ function registerMinorModeCommand(pi, currentCatalog) {
22
+ pi.registerCommand(require_command$1.MINOR_MODE_COMMAND, {
23
+ description: require_command.MINOR_MODE_COMMAND_DESCRIPTION,
24
+ getArgumentCompletions: (prefix) => {
25
+ const query = prefix.trim().toLowerCase();
26
+ return (currentCatalog()?.list() ?? []).map((record) => record.descriptor.label.toLowerCase()).filter((label) => label.startsWith(query)).map((label) => ({
27
+ value: label,
28
+ label
29
+ }));
30
+ },
31
+ handler: (args, ctx) => require_command$1.executeMinorModeCommand(args, {
32
+ catalog: currentCatalog(),
33
+ kind: sessionKindOf(ctx),
34
+ ui: {
35
+ select: (title, options) => ctx.ui.select(title, [...options]),
36
+ input: (title, message) => ctx.ui.input(title, message),
37
+ confirm: (title, message) => ctx.ui.confirm(title, message),
38
+ notify: (message, level) => ctx.ui.notify(message, level)
39
+ }
40
+ })
41
+ });
42
+ }
43
+ //#endregion
44
+ //#region src/extensions/workspaces/sessions/(backend)/_lib/catalogRuntime.ts
45
+ /** Registrations and state flips arrive in bursts; one entry covers a burst. */
46
+ const PROJECTION_SETTLE_MS = 50;
47
+ /**
48
+ * Pi's rpc mode subscribes to session events only after bindExtensions()
49
+ * returns, which is after session_start has run, so an entry journaled during
50
+ * startup never reaches a client. A publish deferred past that point does.
51
+ */
52
+ const BOOT_PUBLISH_DELAY_MS = 500;
53
+ function notify(cordis, context, body, level) {
54
+ const service = (0, _agimon_ai_doompi_core_notification.readDoomNotificationService)(cordis);
55
+ if (service) {
56
+ try {
57
+ Promise.resolve(service.request({
58
+ body,
59
+ level
60
+ })).catch(() => void 0);
61
+ } catch {}
62
+ return;
63
+ }
64
+ context.ui.notify(body, level);
65
+ }
66
+ function transitionSource(requesterSource) {
67
+ if (requesterSource.includes("voice")) return "voice";
68
+ if (requesterSource.includes("leader")) return "leader";
69
+ if (requesterSource.includes("ui")) return "ui";
70
+ return "system";
71
+ }
72
+ /**
73
+ * The minor modes that are actually on, for the composition panel.
74
+ *
75
+ * Read from the bound catalog at publish time rather than passed in, because a
76
+ * mode switching on is one of the reasons a publish happens at all, and a
77
+ * remembered list would describe the composition before the switch.
78
+ */
79
+ function createMinorModePiRuntime(pi) {
80
+ const activeCatalog = { current: void 0 };
81
+ registerMinorModeCommand(pi, () => activeCatalog.current);
82
+ pi.on("session_start", () => {
83
+ setTimeout(() => {
84
+ activeCatalog.republish?.();
85
+ }, BOOT_PUBLISH_DELAY_MS);
86
+ });
87
+ return { services: [(cordis) => modeCatalogPlugin(cordis, pi, activeCatalog)] };
88
+ }
89
+ function modeCatalogPlugin(cordis, pi, activeCatalog) {
90
+ cordis.inject([_agimon_ai_doompi_core_cordisHost.DOOM_CORDIS_SESSION_SERVICE, _agimon_ai_doompi_core_transition.DOOM_TRANSITION_SERVICE], (sessionContext) => {
91
+ const session = sessionContext.get(_agimon_ai_doompi_core_cordisHost.DOOM_CORDIS_SESSION_SERVICE);
92
+ const context = session.context;
93
+ const coordinator = (0, _agimon_ai_doompi_core_transition.requireDoomTransitionCoordinator)(sessionContext);
94
+ const reloadSession = session.reason === "reload";
95
+ const sessionId = session.sessionId;
96
+ const restoreSnapshot = reloadSession ? require_reloadHandoff.consumeMinorModeReloadHandoff(sessionId) : void 0;
97
+ if (!reloadSession) require_reloadHandoff.discardMinorModeReloadHandoff(sessionId);
98
+ const sessionKind = context.hasUI && context.mode === "tui" ? "tui" : "headless";
99
+ const catalog = require_catalog.createMinorModeCatalogHost({
100
+ sessionKind,
101
+ context,
102
+ restoreSnapshot,
103
+ onRestorationError(error) {
104
+ notify(sessionContext, context, `Could not restore a minor mode after reload: ${error instanceof Error ? error.message : String(error)}`, "warning");
105
+ },
106
+ async routeInvocation(request, requesterSource, invoke) {
107
+ let response;
108
+ const result = await coordinator.execute({
109
+ sessionId: context.sessionManager.getSessionId(),
110
+ hostGeneration: coordinator.hostGeneration,
111
+ operationId: request.operationId,
112
+ source: transitionSource(requesterSource),
113
+ target: {
114
+ axis: "live",
115
+ capability: "minor-mode"
116
+ }
117
+ }, async () => {
118
+ response = await invoke();
119
+ return "applied";
120
+ });
121
+ if (result.outcome !== "applied" || !response) throw new Error(`Minor-mode transition was ${result.outcome}: ${result.diagnostics.join(", ")}`);
122
+ return response;
123
+ }
124
+ });
125
+ sessionContext.plugin((providerContext) => {
126
+ providerContext.provide(require_mode.DOOM_MINOR_MODE_CATALOG_SERVICE, catalog);
127
+ });
128
+ activeCatalog.current = catalog;
129
+ activeCatalog.sessionId = sessionId;
130
+ let published;
131
+ let settle;
132
+ const publish = () => {
133
+ settle = void 0;
134
+ const projection = require_projection.projectMinorModes(catalog.getSnapshot(), sessionKind);
135
+ const serialized = JSON.stringify(projection);
136
+ if (serialized === published) return;
137
+ published = serialized;
138
+ pi.appendEntry(require_mode.DOOM_MINOR_MODE_ENTRY_TYPE, projection);
139
+ };
140
+ const unsubscribe = catalog.subscribe(() => {
141
+ settle ??= setTimeout(publish, PROJECTION_SETTLE_MS);
142
+ });
143
+ activeCatalog.republish = () => {
144
+ published = void 0;
145
+ publish();
146
+ };
147
+ return () => {
148
+ if (settle) clearTimeout(settle);
149
+ unsubscribe();
150
+ activeCatalog.republish = void 0;
151
+ activeCatalog.current = void 0;
152
+ activeCatalog.sessionId = void 0;
153
+ catalog.dispose();
154
+ };
155
+ });
156
+ }
157
+ //#endregion
158
+ //#region src/extensions/workspaces/sessions/(backend)/root.cli.ts
159
+ var root_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineRoot)(({ pi }) => {
160
+ const runtime = createMinorModePiRuntime(pi);
161
+ return {
162
+ value: runtime,
163
+ services: runtime.services,
164
+ onStop: runtime.onStop,
165
+ onDispose: runtime.onDispose
166
+ };
167
+ });
168
+ //#endregion
169
+ //#region generated/pi.ts
170
+ const extension = (0, _agimon_ai_doompi_core_piExtension.definePiExtension)("@agimon-ai/doompi-minor-mode", async (context) => {
171
+ const scopeSession = await root_cli_default(context);
172
+ return {
173
+ ...(0, _agimon_ai_doompi_core_extensionFile.composeRootHooks)(scopeSession),
174
+ services: [...scopeSession.services ?? []]
175
+ };
176
+ });
177
+ //#endregion
178
+ exports.default = extension;
179
+ exports.extension = extension;
180
+
181
+ //# sourceMappingURL=pi.cjs.map