@ai-matrx/alchemy 0.8.60 → 0.10.1

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 (88) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +3 -0
  3. package/dist/actions.cjs +1 -1
  4. package/dist/actions.cjs.map +1 -1
  5. package/dist/actions.d.cts +465 -4
  6. package/dist/actions.d.ts +465 -4
  7. package/dist/actions.js +1 -1
  8. package/dist/actions.js.map +1 -1
  9. package/dist/checks.cjs +1 -1
  10. package/dist/checks.cjs.map +1 -1
  11. package/dist/checks.d.cts +22 -1
  12. package/dist/checks.d.ts +22 -1
  13. package/dist/checks.js +2 -2
  14. package/dist/checks.js.map +1 -1
  15. package/dist/core.cjs +1 -1
  16. package/dist/core.cjs.map +1 -1
  17. package/dist/core.d.cts +283 -39
  18. package/dist/core.d.ts +283 -39
  19. package/dist/core.js +2 -2
  20. package/dist/core.js.map +1 -1
  21. package/dist/declare.cjs +1 -1
  22. package/dist/declare.cjs.map +1 -1
  23. package/dist/declare.d.cts +12 -4
  24. package/dist/declare.d.ts +12 -4
  25. package/dist/declare.js +1 -1
  26. package/dist/declare.js.map +1 -1
  27. package/dist/index.cjs +1 -1
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +283 -39
  30. package/dist/index.d.ts +283 -39
  31. package/dist/index.js +2 -2
  32. package/dist/index.js.map +1 -1
  33. package/dist/menu.cjs +1 -1
  34. package/dist/menu.cjs.map +1 -1
  35. package/dist/menu.d.cts +262 -3
  36. package/dist/menu.d.ts +262 -3
  37. package/dist/menu.js +1 -1
  38. package/dist/menu.js.map +1 -1
  39. package/dist/operate-server.d.cts +11 -1
  40. package/dist/operate-server.d.ts +11 -1
  41. package/dist/operate.cjs +1 -1
  42. package/dist/operate.cjs.map +1 -1
  43. package/dist/operate.d.cts +283 -39
  44. package/dist/operate.d.ts +283 -39
  45. package/dist/operate.js +2 -2
  46. package/dist/operate.js.map +1 -1
  47. package/dist/ports.cjs.map +1 -1
  48. package/dist/ports.d.cts +269 -2
  49. package/dist/ports.d.ts +269 -2
  50. package/dist/react-bar.cjs +1 -1
  51. package/dist/react-bar.cjs.map +1 -1
  52. package/dist/react-bar.d.cts +4 -2
  53. package/dist/react-bar.d.ts +4 -2
  54. package/dist/react-bar.js +1 -1
  55. package/dist/react-bar.js.map +1 -1
  56. package/dist/react-host.d.cts +262 -3
  57. package/dist/react-host.d.ts +262 -3
  58. package/dist/react-menu.cjs +1 -1
  59. package/dist/react-menu.cjs.map +1 -1
  60. package/dist/react-menu.d.cts +4 -2
  61. package/dist/react-menu.d.ts +4 -2
  62. package/dist/react-menu.js +1 -1
  63. package/dist/react-menu.js.map +1 -1
  64. package/dist/react-overflow.cjs +1 -1
  65. package/dist/react-overflow.cjs.map +1 -1
  66. package/dist/react-overflow.d.cts +262 -3
  67. package/dist/react-overflow.d.ts +262 -3
  68. package/dist/react-overflow.js +1 -1
  69. package/dist/react-overflow.js.map +1 -1
  70. package/dist/react-palette.cjs +1 -1
  71. package/dist/react-palette.cjs.map +1 -1
  72. package/dist/react-palette.d.cts +4 -2
  73. package/dist/react-palette.d.ts +4 -2
  74. package/dist/react-palette.js +1 -1
  75. package/dist/react-palette.js.map +1 -1
  76. package/dist/react-selection.cjs +1 -1
  77. package/dist/react-selection.cjs.map +1 -1
  78. package/dist/react-selection.d.cts +4 -2
  79. package/dist/react-selection.d.ts +4 -2
  80. package/dist/react-selection.js +1 -1
  81. package/dist/react-selection.js.map +1 -1
  82. package/dist/react-sheet.cjs +1 -1
  83. package/dist/react-sheet.cjs.map +1 -1
  84. package/dist/react-sheet.d.cts +4 -2
  85. package/dist/react-sheet.d.ts +4 -2
  86. package/dist/react-sheet.js +1 -1
  87. package/dist/react-sheet.js.map +1 -1
  88. package/package.json +1 -1
package/dist/ports.d.ts CHANGED
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Matrx Alchemy — Declare types (CONTRACT §2.1).
3
+ *
4
+ * A declaration is plain JSON data (chair ruling N2): no functions, no classes,
5
+ * no React. Runtime behaviour lives in `MountedSurface` (`/declare/host`) and in
6
+ * handler registrations, never here. Zero React, zero `@ai-matrx/agents`.
7
+ */
8
+ type Json$1 = null | boolean | number | string | Json$1[] | {
9
+ [key: string]: Json$1;
10
+ };
1
11
  /** Unchanged from `ui_surface_value_type_chk`. */
2
12
  type ValueType = "string" | "number" | "boolean" | "object" | "array" | "document";
3
13
  type Classification = "ordinary" | "secret" | "credential";
@@ -204,6 +214,219 @@ interface ClickTarget {
204
214
  host?: unknown;
205
215
  }
206
216
 
217
+ /**
218
+ * Operate — the format and delivery contract (Matrx Alchemy CONTRACT §2.3, ALC-16).
219
+ *
220
+ * A format is an ADAPTER: `supports` is synchronous and loads nothing; `load` dynamically
221
+ * imports the engine the first time the format is chosen (print for rich-html/html/pdf/docx/
222
+ * epub, SheetJS for xlsx). Delivery accepts only a SEALED artifact, so the bytes previewed are
223
+ * the bytes copied, downloaded or sent.
224
+ */
225
+
226
+ /** A reference to a declared write target (resolved by the one write door, ALC-17). */
227
+ interface WriteTargetRef {
228
+ surfaceName?: string;
229
+ target: string;
230
+ item?: {
231
+ itemType: string;
232
+ identity: Record<string, string>;
233
+ };
234
+ }
235
+ /**
236
+ * Every write returns one (CONTRACT §2.3; the door is `createWriteDoor`, ALC-17). An applied
237
+ * receipt may carry a `warning` with its `fix` (rule 10: a person's kind mismatch warns, never refuses).
238
+ * A refusal's `reason` is a `WriteRefusalReason` (`./door`).
239
+ */
240
+ type Receipt = {
241
+ status: "applied";
242
+ to: WriteTargetRef;
243
+ sentence: string;
244
+ warning?: string;
245
+ fix?: string;
246
+ } | {
247
+ status: "queued";
248
+ to: WriteTargetRef;
249
+ sentence: string;
250
+ remedy: string;
251
+ } | {
252
+ status: "refused";
253
+ to: WriteTargetRef;
254
+ reason: string;
255
+ sentence: string;
256
+ remedy: string;
257
+ };
258
+
259
+ /**
260
+ * THE ONE WRITE DOOR (Matrx Alchemy ALC-17; Applets CONTRACTS §6 "receipts through the one write door").
261
+ *
262
+ * Every write — a person's edit, a menu row, a destination send, an agent, an applet, an automation,
263
+ * an Action projected from a write target — lands through `door.write`. The door:
264
+ *
265
+ * 1. resolves the DECLARED write target (the surface's own, then its ancestors'); an undeclared
266
+ * target is refused by name;
267
+ * 2. enforces the mode: `stream` takes ops from the target's `streamOps`; ops on any other target
268
+ * need `patchable` (+ `updatesValue`); a value on a `stream` target is refused;
269
+ * 3. checks the kind (rule 10): a person's mismatch WARNS (the receipt is still applied, with a
270
+ * `warning` and a `fix`); an agent's, applet's or automation's malformed write is REFUSED;
271
+ * 4. applies the policy: manual → a person only; ask → a person's own act is the approval, anyone
272
+ * else asks through `approvals`; queued → filed through `review`; auto → applies;
273
+ * 5. applies through the handler: the mounted page's LIVE handler wins over the HEADLESS one;
274
+ * neither → refused `unapplicable` ("open <surface> to apply it");
275
+ * 6. turns stale / missing record / broken protected span into "cannot apply" with a one-click
276
+ * remedy (rule 11).
277
+ *
278
+ * Every outcome is a `Receipt` carrying the system's own sentence. `write` never throws.
279
+ *
280
+ * Who counts as a person: `person`, `menu` and `destination` (a destination send is a person's own
281
+ * click on "Send to …"). `agent`, `applet` and `automation` are not.
282
+ *
283
+ * Open-risk ruling — stream ops into an entity target: an entity write is ONE atomic save. Ops reach
284
+ * an entity target only when it is declared `patchable` (the ops are handed to the handler in one
285
+ * call and commit as one save); a non-patchable entity target refuses ops with the remedy "stream
286
+ * into the editor, then save". Op-by-op persistence into a record does not exist.
287
+ */
288
+
289
+ /** Who is writing. `menu` and `destination` are a person's own act. */
290
+ type WriteCaller = "person" | "agent" | "applet" | "automation" | "destination" | "menu";
291
+ /** One text op for a `stream` (or `patchable`) target — the WidgetHandle op set. */
292
+ interface WriteOp {
293
+ op: StreamOp;
294
+ /** The text the op inserts or replaces with. */
295
+ text?: string;
296
+ /** What `replace` / `insert_before` / `insert_after` / `patch` anchor on. */
297
+ find?: string;
298
+ }
299
+ interface WriteRequest {
300
+ surfaceName: string;
301
+ /** A write target name; `"<itemType>.<name>"` names an item's target. */
302
+ target: string;
303
+ itemType?: string;
304
+ /** Which item, by its declared identity values. Required for an item target. */
305
+ itemIdentity?: Record<string, string>;
306
+ /** A whole value. Exactly one of `value` / `ops`. */
307
+ value?: unknown;
308
+ /** Text ops (stream / patchable targets). */
309
+ ops?: readonly WriteOp[];
310
+ by: WriteCaller;
311
+ runId?: string;
312
+ }
313
+ /** What a handler receives: the request plus the declared target it resolved to. */
314
+ interface WriteApplyRequest {
315
+ surfaceName: string;
316
+ /** The surface that declares the target (an ancestor when inherited). */
317
+ declaredOn: string;
318
+ target: WriteTarget;
319
+ item?: {
320
+ itemType: string;
321
+ identity: Record<string, string>;
322
+ };
323
+ value?: unknown;
324
+ ops?: readonly WriteOp[];
325
+ by: WriteCaller;
326
+ runId?: string;
327
+ }
328
+ /** Rule 11: the three "cannot apply" signals. */
329
+ type CannotApply = "stale" | "missing-record" | "broken-span";
330
+ /**
331
+ * A handler applies the write. Return nothing (or `{ status: "applied" }`) when it landed, or a
332
+ * `cannotApply` signal; THROWING an error whose `code` is a `CannotApply` signal means the same.
333
+ */
334
+ type WriteHandlerResult = void | {
335
+ status: "applied";
336
+ sentence?: string;
337
+ } | {
338
+ status: "cannot-apply";
339
+ cannotApply: CannotApply;
340
+ sentence?: string;
341
+ remedy?: string;
342
+ };
343
+ type WriteHandler = (request: WriteApplyRequest, signal: AbortSignal) => WriteHandlerResult | Promise<WriteHandlerResult>;
344
+ /** Files a `queued` write for an organization's review. */
345
+ interface WriteReviewPort {
346
+ file(request: WriteApplyRequest): Promise<{
347
+ sentence?: string;
348
+ remedy?: string;
349
+ } | void>;
350
+ }
351
+ interface WriteDoor {
352
+ write(request: WriteRequest, signal?: AbortSignal): Promise<Receipt>;
353
+ /** A feature's write handler that works with no page mounted. Refuses a second one for the same target. */
354
+ registerHeadless(surfaceName: string, targetName: string, handler: WriteHandler): () => void;
355
+ /** A mounted page's handler; wins over the headless one while registered. Returns unregister. */
356
+ registerLive(surfaceName: string, targetName: string, handler: WriteHandler): () => void;
357
+ }
358
+
359
+ /**
360
+ * Surface Actions — the shapes (Applets CONTRACTS §6, FROZEN; exported here as a superset).
361
+ *
362
+ * An Action is one thing a surface can have done to it, by a person, an agent,
363
+ * an applet or an automation: a write target, a client tool, a Kind Action or a
364
+ * row in `ui.ui_surface_action`. All of them project onto `ActionDeclaration`
365
+ * (`./declarations.ts`) and run through ONE runner (`./surface-run.ts`). There is
366
+ * never a second registry: `name` IS the alchemy action id, and `category`
367
+ * defaults to "applet" in alchemy's closed `ActionCategory` union.
368
+ *
369
+ * Types only — no runtime code, no React, no `@ai-matrx/agents`. `/ports`
370
+ * imports from here, so this file imports nothing but local types.
371
+ */
372
+
373
+ /** Who started a run. */
374
+ type ActionCaller = "person" | "agent" | "applet" | "automation";
375
+ /** Who may run it without a click: "manual" = only a person; "ask" = proposed first; "auto" = runs. */
376
+ type ActionPolicy = "ask" | "auto" | "manual";
377
+ interface ActionContext {
378
+ runId: string;
379
+ by: ActionCaller;
380
+ viewerId: string | null;
381
+ surfaceName?: string;
382
+ policy?: ActionPolicy;
383
+ }
384
+ /** The system's own sentence, never thrown into a UI. Superset of RecordsError (CONTRACTS §0 `AppletError`). */
385
+ interface ActionError {
386
+ code: string;
387
+ message: string;
388
+ retryable: boolean;
389
+ diagnostic?: string;
390
+ /** Superset: the one-click remedy a write door refusal names. */
391
+ remedy?: string;
392
+ }
393
+ /** CONTRACTS §0 `Result<T>`. */
394
+ type ActionResult<T = unknown> = {
395
+ ok: true;
396
+ data: T;
397
+ } | {
398
+ ok: false;
399
+ error: ActionError;
400
+ };
401
+ /** `POST /actions/run` (aidream) — the request. */
402
+ interface ServerActionRunRequest {
403
+ name: string;
404
+ input: Json$1;
405
+ by: ActionCaller;
406
+ surface_name?: string;
407
+ policy?: ActionPolicy;
408
+ }
409
+ /** `POST /actions/run` (aidream) — the response. */
410
+ interface ServerActionRunResponse {
411
+ status: "applied" | "proposed" | "refused";
412
+ message: string;
413
+ receipts: Json$1[];
414
+ proposal?: Json$1;
415
+ }
416
+ /** A mandate run request: by alias (an Action's `target`) or by key. */
417
+ type MandateRunRequest = ({
418
+ alias: string;
419
+ key?: never;
420
+ } | {
421
+ key: string;
422
+ alias?: never;
423
+ }) & {
424
+ variables: Record<string, Json$1>;
425
+ userInput?: string;
426
+ by: ActionCaller;
427
+ policy: ActionPolicy;
428
+ };
429
+
207
430
  /**
208
431
  * `@ai-matrx/alchemy/ports` — the host ports (Matrx Alchemy CONTRACT §2.2).
209
432
  *
@@ -222,7 +445,7 @@ interface ClickTarget {
222
445
  * PP-01a `window` (host-rendered windows for a live preparation session)
223
446
  * PP-13a `transferKnobs` (organization default recipes)
224
447
  *
225
- * ALC-17 adds approvals/bodies/receipts.
448
+ * ALC-17 `door` (the one write door), `review` (queued writes)
226
449
  *
227
450
  * ── Absent-port semantics ───────────────────────────────────────────────────
228
451
  *
@@ -252,6 +475,16 @@ interface ClickTarget {
252
475
  * to an overlay carrying the session as data)
253
476
  * transferKnobs absent → no organization default recipe; a person's own
254
477
  * default (persistence) or the package's Full applies
478
+ * serverActions absent → `runs: "server"` Actions refuse with "not available here"
479
+ * mandates absent → `runs: "mandate"` Actions refuse the same way
480
+ * pageActions absent → `runs: "page"` Actions refuse the same way
481
+ * approvals absent → a policy "ask" Action started by an agent, applet or automation is refused
482
+ * ("needs a person's approval"); a person's own click is the approval
483
+ * (`runs: "navigate"` goes through `overlay.navigate`; overlay absent → refused)
484
+ * door absent → write-target Actions dispatch to `pageActions` as before, and
485
+ * `Delivery.send` is refused with a remedy; bound → every such write goes
486
+ * through it and returns its receipt
487
+ * review absent → a write to a `queued` target is refused ("review isn't available here")
255
488
  *
256
489
  * Types only: this entry has no runtime code.
257
490
  */
@@ -397,6 +630,40 @@ interface AlchemyHostPorts {
397
630
  window?: WindowPort;
398
631
  /** Organization default recipes, resolved by the host's Feature Knob ladder (platform → organization). */
399
632
  transferKnobs?: TransferKnobsPort;
633
+ /** aidream `POST /actions/run`: a registered server action by name, as the caller, under the apply-policy cascade. */
634
+ serverActions?: ServerActionPort;
635
+ /** Runs a mandate by alias or key (the host binds `@ai-matrx/agents`; alchemy never imports it). */
636
+ mandates?: MandatePort;
637
+ /** The page's own handlers for `runs: "page"` Actions (in an applet frame: routed as `{ action, input, runId }`). */
638
+ pageActions?: PageActionPort;
639
+ /** Asks a person, in place, to approve an `ask` Action that an agent, applet or automation started. */
640
+ approvals?: ApprovalPort;
641
+ /** `createWriteDoor(...)`: every write to a declared target lands here and returns a receipt. */
642
+ door?: WriteDoor;
643
+ /** Files a write to a `queued` target for an organization's review. */
644
+ review?: WriteReviewPort;
645
+ }
646
+ interface ServerActionPort {
647
+ run(request: ServerActionRunRequest): Promise<ServerActionRunResponse>;
648
+ }
649
+ interface MandatePort {
650
+ /** Resolves with the run's result (a kind envelope or JSON); rejects with the system's sentence. */
651
+ run(request: MandateRunRequest): Promise<unknown>;
652
+ }
653
+ interface ApprovalRequest {
654
+ action: string;
655
+ label: string;
656
+ description: string;
657
+ input: Json;
658
+ by: "agent" | "applet" | "automation";
659
+ surfaceName: string;
660
+ }
661
+ interface ApprovalPort {
662
+ /** Resolves true when the person approves; false when they decline or dismiss. */
663
+ ask(request: ApprovalRequest): Promise<boolean>;
664
+ }
665
+ interface PageActionPort {
666
+ dispatch(name: string, input: unknown, context: ActionContext): Promise<ActionResult<unknown>>;
400
667
  }
401
668
  /**
402
669
  * Why a port and not `OverlayHostPort`: an overlay's `data` is `Json`, and a live preparation
@@ -515,4 +782,4 @@ interface ServerPort {
515
782
  call(operationId: string, input: Json, signal: AbortSignal): Promise<ServerResult>;
516
783
  }
517
784
 
518
- export type { AlchemyHostPorts, AssetResolverPort, AuthResumePort, ContextArrangementKnob, DensityKnob, DiagnosticsPort, HostDialogsPort, I18nPort, IconResolverPort, IdentityPort, Json, KindValidatorPort, MenuKnobsPort, NotifyPort, OverlayHostPort, PersistencePort, ServerPort, ServerResult, StorePort, TransferKnobsPort, TransportArtifact, TransportOutcome, TransportPort, WindowHandle, WindowOpenOptions, WindowPort, WindowSize };
785
+ export type { AlchemyHostPorts, ApprovalPort, ApprovalRequest, AssetResolverPort, AuthResumePort, ContextArrangementKnob, DensityKnob, DiagnosticsPort, HostDialogsPort, I18nPort, IconResolverPort, IdentityPort, Json, KindValidatorPort, MandatePort, MenuKnobsPort, NotifyPort, OverlayHostPort, PageActionPort, PersistencePort, ServerActionPort, ServerPort, ServerResult, StorePort, TransferKnobsPort, TransportArtifact, TransportOutcome, TransportPort, WindowHandle, WindowOpenOptions, WindowPort, WindowSize, WriteDoor, WriteReviewPort };
@@ -1,4 +1,4 @@
1
1
  "use client";
2
- "use strict";var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var react_bar_exports={};__export(react_bar_exports,{ActionBar:()=>ActionBar});module.exports=__toCommonJS(react_bar_exports);var React5=__toESM(require("react"),1),import_design_system2=require("@ai-matrx/design-system");function sectionLabel(section){return section.label??null}function fold(section){return{kind:"submenu",id:`${section.id}:fold`,label:section.label,...section.icon!==void 0?{icon:section.icon}:{},children:section.nodes}}function rowCount(nodes){return nodes.filter(n=>n.kind!=="separator"&&n.kind!=="label").length}function placementOf(node){return"placement"in node&&node.placement?node.placement:"overflow"}function foldNamed(sections){return sections.map(s=>s.label&&!s.primary&&rowCount(s.nodes)>3?{id:s.id,group:s.group,nodes:[fold({...s,label:s.label})]}:s)}function bar(model,_options={}){let primary=[],overflowSections=[];for(let s of model.sections){let rest=[];for(let n of s.nodes){if(n.kind==="separator"||n.kind==="label"){rest.push(n);continue}let p=placementOf(n);(p==="primary"||p==="both")&&primary.push(n),(p==="overflow"||p==="both")&&rest.push(n)}rowCount(rest)>0&&overflowSections.push({...s,nodes:rest})}return{primary,overflow:foldNamed(overflowSections)}}var React2=__toESM(require("react"),1);var DEFAULT_SENSITIVITY=Object.freeze({exportable:!0,classification:"ordinary",includedByDefault:!0});function resolveSensitivity(value){return{exportable:value.sensitivity?.exportable??DEFAULT_SENSITIVITY.exportable,classification:value.sensitivity?.classification??DEFAULT_SENSITIVITY.classification,includedByDefault:value.sensitivity?.includedByDefault??DEFAULT_SENSITIVITY.includedByDefault}}function toJson(value){if(!(value===void 0||typeof value=="function"||typeof value=="symbol")){if(value===null||typeof value=="string"||typeof value=="boolean")return value;if(typeof value=="number")return Number.isFinite(value)?value:null;if(typeof value=="bigint")return value.toString();if(value instanceof Date)return value.toISOString();if(Array.isArray(value))return value.map(v=>toJson(v)??null);if(typeof value=="object"){let out={};for(let[k,v]of Object.entries(value)){let j=toJson(v);j!==void 0&&(out[k]=j)}return out}}}function projectValues(raw,declared,pathPrefix=""){let byName=new Map(declared.map(d=>[d.name,d])),values={},omissions=[];for(let[name,value]of Object.entries(raw)){let path=pathPrefix?`${pathPrefix}.${name}`:name,decl=byName.get(name);if(!decl){omissions.push({path,reason:"filtered"});continue}let sensitivity=resolveSensitivity(decl);if(sensitivity.classification!=="ordinary"){omissions.push({path,reason:"excluded",classification:sensitivity.classification});continue}if(!sensitivity.exportable){omissions.push({path,reason:"excluded"});continue}let json=toJson(value);json!==void 0&&(values[name]=json)}return{values,omissions}}function createProjectedReads(source){return{async values(signal){if(!source.surface||!source.declaration)return{values:{},omissions:[]};let raw=await source.surface.readValues(signal),screenValues=source.declaration.values;return projectValues(raw,screenValues)},async item(signal){let item=source.item;if(!item||!source.declaration)return null;let type=source.declaration.itemTypes?.find(t=>t.name===item.itemType);if(!type)return{values:{},omissions:[{path:item.itemType,reason:"filtered"}]};let raw=await item.readValues(signal);return projectValues(raw,type.values,item.itemType)},async live(signal){return source.surface?.readLive?source.surface.readLive(signal):{}}}}async function runAction(action,target,options){let{ports}=options;if(action.requiresAuth&&!target.auth.authenticated)return ports.auth?(ports.auth.signInThenResume({actionId:action.id,contentFingerprint:options.contentFingerprint??action.id}),{status:"auth-pending"}):(ports.diagnostics.capture(new Error(`requiresAuth action "${action.id}" ran signed out with no auth port`),{area:"actions",detail:{actionId:action.id}}),{status:"failed",error:new Error("sign-in unavailable")});let reads=createProjectedReads(options.source??{surface:null,declaration:target.declaration,item:null}),signal=options.signal??new AbortController().signal;try{return{status:"ran",outcome:await action.run(target,{reads,ports,signal})}}catch(error){ports.diagnostics.capture(error,{area:"actions",detail:{actionId:action.id,stage:"run"}});let label=typeof action.label=="string"?action.label:action.id;return ports.notify?.error(`${label} did not finish.`,"Try again; if it keeps failing, report it from the feedback button."),{status:"failed",error}}}var APPROVED_HEADINGS=new Set(["Save","Copy as","Export","Edit","Creator tools","Admin","App","Compare","History"]),CONTAINER_WORD=/^(more|more…|more\.\.\.|other|others|misc|miscellaneous|additional|extra|extras|actions|options|advanced|stuff|everything else)$/i,TARGET_SHAPE=/^(Cell|Row|Column|Table|Range|Selection|Record) · .+$/;function isContainerWord(label){return CONTAINER_WORD.test(label.trim())}function isApprovedHeading(label,kind="group",approved=APPROVED_HEADINGS){let l=label.trim();return!l||isContainerWord(l)?!1:approved.has(l)?!0:kind==="target"||TARGET_SHAPE.test(l)}function defaultHeadingPolicy(){return globalThis.process?.env?.NODE_ENV==="production"?"inline":"throw"}var UnapprovedHeadingError=class extends Error{heading;constructor(heading,where){super(`Menu heading "${heading}" (${where}) is not an approved heading. Remedy: show these rows inline \u2014 declare no section (or kind "target" for the clicked thing's own label) \u2014 or ask Arman to add the name to APPROVED_HEADINGS in @ai-matrx/alchemy/menu. A generic container word ("More\u2026", "Other") is never approved.`),this.name="UnapprovedHeadingError",this.heading=heading}};var CATEGORY_GROUP={clipboard:"clipboard",copy:"transfer",export:"transfer",save:"document",share:"document",edit:"editable",history:"history",ai:"ai",ask:"ai",listen:"tools",study:"tools",app:"tools",feedback:"quick",creator:"admin",admin:"admin","surface-info":"surface-info"},GROUP_ORDER=["clipboard","editable","transfer","document","history","ai","tools","quick","surface","admin","surface-info"],CATEGORY_ORDER=["clipboard","edit","copy","export","save","share","history","ask","ai","listen","study","app","feedback","creator","admin","surface-info"];function translate(i18n,key,fallback){if(!i18n)return fallback;try{return i18n.t(key,fallback)}catch{return fallback}}function actionToNode(resolved,target,options={}){let{action,eligibility}=resolved,rawLabel=typeof action.label=="function"?action.label(target):action.label,label=translate(options.i18n,action.labelKey??action.id,rawLabel),base={id:action.id,actionId:action.id,...action.icon!==void 0?{icon:action.icon}:{},...action.placement!==void 0?{placement:action.placement}:{}};if(action.expand)return{...base,kind:"submenu",label,lazy:!0,loading:!1,...action.pending?.(target)?{pending:!0}:{},children:[],...action.emptyLabel!==void 0?{emptyLabel:action.emptyLabel}:{}};if(action.href!==void 0){let href=typeof action.href=="function"?action.href(target):action.href;return{...base,kind:"link",label,href}}if(action.toggle)return{...base,kind:"checkbox",label,checked:action.pressed?.(target)??!1,...action.description!==void 0?{description:action.description}:{}};let state=action.stateIcon?.(target)??null,pressed=action.pressed?.(target),hint=action.hint!==void 0?translate(options.i18n,action.hintKey??`${action.id}.hint`,action.hint):void 0;return{...base,kind:"item",label,...action.iconTone!==void 0?{iconTone:action.iconTone}:{},...state?{stateIcon:state}:{},...action.description!==void 0?{description:action.description}:{},...hint!==void 0?{hint}:{},...pressed!==void 0?{pressed}:{},...action.destructive?{destructive:!0}:{},...action.preserveSelection?{preserveSelection:!0}:{},...action.keepsMenuOpen?{keepsMenuOpen:!0}:{},...eligibility.status==="unavailable-verb"||eligibility.status==="unavailable"?{unavailable:{sentence:eligibility.sentence}}:{}}}function buildMenuModel(target,resolved,options={}){let policy=options.headingPolicy??defaultHeadingPolicy();resolved=resolved.map(r=>{let sec=r.action.section;if(r.action.expand&&isContainerWord(typeof r.action.label=="string"?r.action.label:"")&&policy==="throw")throw new UnapprovedHeadingError(r.action.label,`submenu of ${r.action.id}`);if(!sec)return r;let kind=sec.kind??(sec.primary?"target":"group");if(isApprovedHeading(sec.label,kind))return r;if(policy==="throw")throw new UnapprovedHeadingError(sec.label,`section of ${r.action.id}`);let{section:_dropped,...rest}=r.action;return{...r,action:rest}});let ordered=resolved.map((r,index)=>({r,index})).sort((a,b)=>{let ca=CATEGORY_ORDER.indexOf(a.r.action.category),cb=CATEGORY_ORDER.indexOf(b.r.action.category);if(ca!==cb)return ca-cb;let oa=a.r.action.order??0,ob=b.r.action.order??0;return oa!==ob?oa-ob:a.index-b.index}).map(x=>x.r),sections=new Map,roles={},explicit=new Map;resolved.forEach((r,index)=>{let sec=r.action.section;if(!sec)return;let entry=explicit.get(sec.id)??{group:CATEGORY_GROUP[r.action.category],rows:[]};entry.rows.push({r,index}),explicit.set(sec.id,entry)});let placed=new Set;for(let r of ordered){let sec=r.action.section;if(sec&&placed.has(sec.id))continue;let group=sec?explicit.get(sec.id)?.group??CATEGORY_GROUP[r.action.category]:CATEGORY_GROUP[r.action.category],sectionId=sec?`section:${sec.id}`:group,section=sections.get(sectionId);section||(section={id:sectionId,group,nodes:[],...sec?{label:translate(options.i18n,sec.labelKey??`section.${sec.id}`,sec.label)}:{},...sec?.icon!==void 0?{icon:sec.icon}:{},...sec?.primary?{primary:!0}:{},...sec&&(sec.kind??(sec.primary?"target":"group"))==="target"?{target:!0}:{}},sections.set(sectionId,section));let rows=sec?(explicit.get(sec.id)?.rows??[]).sort((x,y)=>(x.r.action.order??0)-(y.r.action.order??0)||x.index-y.index).map(x=>x.r):[r];sec&&placed.add(sec.id);for(let row of rows)row.action.startsGroup&&section.nodes.length>0&&section.nodes.push({kind:"separator",id:`${row.action.id}:group`}),section.nodes.push(actionToNode(row,target,options)),row.action.verb&&(roles[row.action.verb]=row.action.id)}let list=[...sections.values()].sort((a,b)=>!!a.primary!=!!b.primary?a.primary?-1:1:GROUP_ORDER.indexOf(a.group)-GROUP_ORDER.indexOf(b.group)),selected=target.selection?.text?.trim(),content=options.content?.trim(),fieldName=options.contentLabel?.trim();return{header:selected?{label:"Selected",text:target.selection?.text??""}:fieldName?{label:fieldName,text:options.content??""}:content?{label:"Content",text:options.content??""}:null,sections:list,roles}}function withGroupDividers(children,nodes){let out=[];return children.forEach((child,i)=>{let node=nodes[i];node&&(i>0&&(child.startsGroup||(children[i-1].section?.id??null)!==(child.section?.id??null))&&out.push({kind:"separator",id:`${child.id}:group`}),out.push(node))}),out}function withExpandedChildren(model,nodeId,children){let visit=nodes=>nodes.map(n=>n.kind!=="submenu"?n:n.id===nodeId?children==="loading"?{...n,loading:!0}:{...n,lazy:!1,loading:!1,pending:!1,children}:{...n,children:visit(n.children)});return{...model,sections:model.sections.map(s=>({...s,nodes:visit(s.nodes)}))}}function findNode(nodes,id){for(let n of nodes){if(n.id===id)return n;if(n.kind==="submenu"){let hit=findNode(n.children,id);if(hit)return hit}}return null}var React=__toESM(require("react"),1),KEY=Symbol.for("ai-matrx.alchemy.actions-context"),AlchemyActionsContext=globalThis[KEY]??=React.createContext(null);function useAlchemyActions(){let value=React.useContext(AlchemyActionsContext);if(!value)throw new Error("Alchemy actions: render inside <AlchemyActionsProvider> (@ai-matrx/alchemy/react/host).");return value}function isLatestExpansion(capturedTargetEpoch,currentTargetEpoch,capturedNodeSequence,currentNodeSequence){return capturedTargetEpoch===currentTargetEpoch&&capturedNodeSequence===currentNodeSequence}var import_jsx_runtime=require("react/jsx-runtime");function nodeInModel(model,id){for(let s of model.sections){let hit=findNode(s.nodes,id);if(hit)return hit}return null}function hasLoadedRows(model,id){let n=nodeInModel(model,id);return!!(n&&n.kind==="submenu"&&!n.lazy&&!n.loading)}function loadedChildren(model,id){let n=nodeInModel(model,id);return n&&n.kind==="submenu"&&!n.lazy?n.children:[]}function carryOpened(prev,next,opened){return next.map(n=>{if(n.kind!=="submenu")return n;let old=prev.find(o=>o.id===n.id);return!old||old.kind!=="submenu"||old.lazy?n:n.lazy?opened.has(n.id)?{...n,lazy:!1,loading:!1,pending:!1,children:old.children}:n:{...n,children:carryOpened(old.children,n.children,opened)}})}function carryOpenedModel(prev,next,opened){if(opened.size===0)return next;let prevNodes=prev.sections.flatMap(s=>s.nodes);return{...next,sections:next.sections.map(s=>({...s,nodes:carryOpened(prevNodes,s.nodes,opened)}))}}function useMenuEngine(target,options={}){let{registry,ports}=useAlchemyActions(),[resolved,setResolved]=React2.useState([]),[model,setModel]=React2.useState(null),[tick,setTick]=React2.useState(0),expanded=React2.useRef(new Map),opened=React2.useRef(new Set),expandSeq=React2.useRef(new Map),targetEpoch=React2.useRef(0),currentTarget=React2.useRef(target);currentTarget.current!==target&&(currentTarget.current=target,targetEpoch.current+=1);let active=options.active??!0,optionsRef=React2.useRef(options);optionsRef.current=options,React2.useEffect(()=>registry.subscribe(()=>setTick(t=>t+1)),[registry]);let expandAction=React2.useCallback(async(action,nodeId)=>{if(!target||!action.expand)return;let epoch=targetEpoch.current,seq=(expandSeq.current.get(nodeId)??0)+1;expandSeq.current.set(nodeId,seq);let latest=()=>isLatestExpansion(epoch,targetEpoch.current,seq,expandSeq.current.get(nodeId));setModel(m=>m&&!hasLoadedRows(m,nodeId)?withExpandedChildren(m,nodeId,"loading"):m);try{let children=await action.expand(target,new AbortController().signal);if(!latest())return;let nodes=withGroupDividers(children,children.map(child=>(expanded.current.set(child.id,child),actionToNode({action:child,eligibility:{status:"available"}},target,ports.i18n?{i18n:ports.i18n}:{}))));setModel(m=>m&&withExpandedChildren(m,nodeId,carryOpened(loadedChildren(m,nodeId),nodes,opened.current)));for(let child of children)child.expand&&opened.current.has(child.id)&&expandAction(child,child.id)}catch(error){if(!latest())return;ports.diagnostics.capture(error,{area:"menu",detail:{nodeId,stage:"expand"}}),setModel(m=>m&&withExpandedChildren(m,nodeId,[]))}},[target,ports]);React2.useEffect(()=>{expanded.current.clear(),opened.current.clear()},[target]),React2.useEffect(()=>{if(!target||!active)return;let live=!0;return registry.resolve(target,optionsRef.current.restrict).then(list=>{if(!live)return;setResolved(list);let built=buildMenuModel(target,list,{...ports.i18n?{i18n:ports.i18n}:{},content:optionsRef.current.content??null,contentLabel:optionsRef.current.contentLabel??null});setModel(prev=>prev?carryOpenedModel(prev,built,opened.current):built);for(let{action}of list)opened.current.has(action.id)&&action.expand&&expandAction(action,action.id)}),()=>{live=!1}},[registry,ports,target,active,tick,options.revision,expandAction]);let resolvedRef=React2.useRef(resolved);resolvedRef.current=resolved;let subscribedIds=resolved.map(r=>r.action.id).join(`
2
+ "use strict";var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var react_bar_exports={};__export(react_bar_exports,{ActionBar:()=>ActionBar});module.exports=__toCommonJS(react_bar_exports);var React5=__toESM(require("react"),1),import_design_system2=require("@ai-matrx/design-system");function sectionLabel(section){return section.label??null}function fold(section){return{kind:"submenu",id:`${section.id}:fold`,label:section.label,...section.icon!==void 0?{icon:section.icon}:{},children:section.nodes}}function rowCount(nodes){return nodes.filter(n=>n.kind!=="separator"&&n.kind!=="label").length}function placementOf(node){return"placement"in node&&node.placement?node.placement:"overflow"}function foldNamed(sections){return sections.map(s=>s.label&&!s.primary&&rowCount(s.nodes)>3?{id:s.id,group:s.group,nodes:[fold({...s,label:s.label})]}:s)}function bar(model,_options={}){let primary=[],overflowSections=[];for(let s of model.sections){let rest=[];for(let n of s.nodes){if(n.kind==="separator"||n.kind==="label"){rest.push(n);continue}let p=placementOf(n);(p==="primary"||p==="both")&&primary.push(n),(p==="overflow"||p==="both")&&rest.push(n)}rowCount(rest)>0&&overflowSections.push({...s,nodes:rest})}return{primary,overflow:foldNamed(overflowSections)}}var React2=__toESM(require("react"),1);var DEFAULT_SENSITIVITY=Object.freeze({exportable:!0,classification:"ordinary",includedByDefault:!0});function resolveSensitivity(value){return{exportable:value.sensitivity?.exportable??DEFAULT_SENSITIVITY.exportable,classification:value.sensitivity?.classification??DEFAULT_SENSITIVITY.classification,includedByDefault:value.sensitivity?.includedByDefault??DEFAULT_SENSITIVITY.includedByDefault}}function toJson(value){if(!(value===void 0||typeof value=="function"||typeof value=="symbol")){if(value===null||typeof value=="string"||typeof value=="boolean")return value;if(typeof value=="number")return Number.isFinite(value)?value:null;if(typeof value=="bigint")return value.toString();if(value instanceof Date)return value.toISOString();if(Array.isArray(value))return value.map(v=>toJson(v)??null);if(typeof value=="object"){let out={};for(let[k,v]of Object.entries(value)){let j=toJson(v);j!==void 0&&(out[k]=j)}return out}}}function projectValues(raw,declared,pathPrefix=""){let byName=new Map(declared.map(d=>[d.name,d])),values={},omissions=[];for(let[name,value]of Object.entries(raw)){let path=pathPrefix?`${pathPrefix}.${name}`:name,decl=byName.get(name);if(!decl){omissions.push({path,reason:"filtered"});continue}let sensitivity=resolveSensitivity(decl);if(sensitivity.classification!=="ordinary"){omissions.push({path,reason:"excluded",classification:sensitivity.classification});continue}if(!sensitivity.exportable){omissions.push({path,reason:"excluded"});continue}let json=toJson(value);json!==void 0&&(values[name]=json)}return{values,omissions}}function createProjectedReads(source){return{async values(signal){if(!source.surface||!source.declaration)return{values:{},omissions:[]};let raw=await source.surface.readValues(signal),screenValues=source.declaration.values;return projectValues(raw,screenValues)},async item(signal){let item=source.item;if(!item||!source.declaration)return null;let type=source.declaration.itemTypes?.find(t=>t.name===item.itemType);if(!type)return{values:{},omissions:[{path:item.itemType,reason:"filtered"}]};let raw=await item.readValues(signal);return projectValues(raw,type.values,item.itemType)},async live(signal){return source.surface?.readLive?source.surface.readLive(signal):{}}}}async function runAction(action,target,options){let{ports}=options;if(action.requiresAuth&&!target.auth.authenticated)return ports.auth?(ports.auth.signInThenResume({actionId:action.id,contentFingerprint:options.contentFingerprint??action.id}),{status:"auth-pending"}):(ports.diagnostics.capture(new Error(`requiresAuth action "${action.id}" ran signed out with no auth port`),{area:"actions",detail:{actionId:action.id}}),{status:"failed",error:new Error("sign-in unavailable")});let reads=createProjectedReads(options.source??{surface:null,declaration:target.declaration,item:null}),signal=options.signal??new AbortController().signal;try{return{status:"ran",outcome:await action.run(target,{reads,ports,signal})}}catch(error){ports.diagnostics.capture(error,{area:"actions",detail:{actionId:action.id,stage:"run"}});let label=typeof action.label=="string"?action.label:action.id;return ports.notify?.error(`${label} did not finish.`,"Try again; if it keeps failing, report it from the feedback button."),{status:"failed",error}}}var APPROVED_HEADINGS=new Set(["Save","Copy as","Export","Edit","Creator tools","Admin","App","Compare","History"]),CONTAINER_WORD=/^(more|more…|more\.\.\.|other|others|misc|miscellaneous|additional|extra|extras|actions|options|advanced|stuff|everything else)$/i,TARGET_SHAPE=/^(Cell|Row|Column|Table|Range|Selection|Record) · .+$/;function isContainerWord(label){return CONTAINER_WORD.test(label.trim())}function isApprovedHeading(label,kind="group",approved=APPROVED_HEADINGS){let l=label.trim();return!l||isContainerWord(l)?!1:approved.has(l)?!0:kind==="target"||TARGET_SHAPE.test(l)}function defaultHeadingPolicy(){return globalThis.process?.env?.NODE_ENV==="production"?"inline":"throw"}var UnapprovedHeadingError=class extends Error{heading;constructor(heading,where){super(`Menu heading "${heading}" (${where}) is not an approved heading. Remedy: show these rows inline \u2014 declare no section (or kind "target" for the clicked thing's own label) \u2014 or ask Arman to add the name to APPROVED_HEADINGS in @ai-matrx/alchemy/menu. A generic container word ("More\u2026", "Other") is never approved.`),this.name="UnapprovedHeadingError",this.heading=heading}};var CATEGORY_GROUP={clipboard:"clipboard",copy:"transfer",export:"transfer",save:"document",share:"document",edit:"editable",history:"history",ai:"ai",ask:"ai",listen:"tools",study:"tools",app:"tools",applet:"tools",feedback:"quick",creator:"admin",admin:"admin","surface-info":"surface-info"},GROUP_ORDER=["clipboard","editable","transfer","document","history","ai","tools","quick","surface","admin","surface-info"],CATEGORY_ORDER=["clipboard","edit","copy","export","save","share","history","ask","ai","listen","study","app","applet","feedback","creator","admin","surface-info"];function translate(i18n,key,fallback){if(!i18n)return fallback;try{return i18n.t(key,fallback)}catch{return fallback}}function actionToNode(resolved,target,options={}){let{action,eligibility}=resolved,rawLabel=typeof action.label=="function"?action.label(target):action.label,label=translate(options.i18n,action.labelKey??action.id,rawLabel),base={id:action.id,actionId:action.id,...action.icon!==void 0?{icon:action.icon}:{},...action.placement!==void 0?{placement:action.placement}:{}};if(action.expand)return{...base,kind:"submenu",label,lazy:!0,loading:!1,...action.pending?.(target)?{pending:!0}:{},children:[],...action.emptyLabel!==void 0?{emptyLabel:action.emptyLabel}:{}};if(action.href!==void 0){let href=typeof action.href=="function"?action.href(target):action.href;return{...base,kind:"link",label,href}}if(action.toggle)return{...base,kind:"checkbox",label,checked:action.pressed?.(target)??!1,...action.description!==void 0?{description:action.description}:{}};let state=action.stateIcon?.(target)??null,pressed=action.pressed?.(target),hint=action.hint!==void 0?translate(options.i18n,action.hintKey??`${action.id}.hint`,action.hint):void 0;return{...base,kind:"item",label,...action.iconTone!==void 0?{iconTone:action.iconTone}:{},...state?{stateIcon:state}:{},...action.description!==void 0?{description:action.description}:{},...hint!==void 0?{hint}:{},...pressed!==void 0?{pressed}:{},...action.destructive?{destructive:!0}:{},...action.preserveSelection?{preserveSelection:!0}:{},...action.keepsMenuOpen?{keepsMenuOpen:!0}:{},...eligibility.status==="unavailable-verb"||eligibility.status==="unavailable"?{unavailable:{sentence:eligibility.sentence}}:{}}}function buildMenuModel(target,resolved,options={}){let policy=options.headingPolicy??defaultHeadingPolicy();resolved=resolved.map(r=>{let sec=r.action.section;if(r.action.expand&&isContainerWord(typeof r.action.label=="string"?r.action.label:"")&&policy==="throw")throw new UnapprovedHeadingError(r.action.label,`submenu of ${r.action.id}`);if(!sec)return r;let kind=sec.kind??(sec.primary?"target":"group");if(isApprovedHeading(sec.label,kind))return r;if(policy==="throw")throw new UnapprovedHeadingError(sec.label,`section of ${r.action.id}`);let{section:_dropped,...rest}=r.action;return{...r,action:rest}});let ordered=resolved.map((r,index)=>({r,index})).sort((a,b)=>{let ca=CATEGORY_ORDER.indexOf(a.r.action.category),cb=CATEGORY_ORDER.indexOf(b.r.action.category);if(ca!==cb)return ca-cb;let oa=a.r.action.order??0,ob=b.r.action.order??0;return oa!==ob?oa-ob:a.index-b.index}).map(x=>x.r),sections=new Map,roles={},explicit=new Map;resolved.forEach((r,index)=>{let sec=r.action.section;if(!sec)return;let entry=explicit.get(sec.id)??{group:CATEGORY_GROUP[r.action.category],rows:[]};entry.rows.push({r,index}),explicit.set(sec.id,entry)});let placed=new Set;for(let r of ordered){let sec=r.action.section;if(sec&&placed.has(sec.id))continue;let group=sec?explicit.get(sec.id)?.group??CATEGORY_GROUP[r.action.category]:CATEGORY_GROUP[r.action.category],sectionId=sec?`section:${sec.id}`:group,section=sections.get(sectionId);section||(section={id:sectionId,group,nodes:[],...sec?{label:translate(options.i18n,sec.labelKey??`section.${sec.id}`,sec.label)}:{},...sec?.icon!==void 0?{icon:sec.icon}:{},...sec?.primary?{primary:!0}:{},...sec&&(sec.kind??(sec.primary?"target":"group"))==="target"?{target:!0}:{}},sections.set(sectionId,section));let rows=sec?(explicit.get(sec.id)?.rows??[]).sort((x,y)=>(x.r.action.order??0)-(y.r.action.order??0)||x.index-y.index).map(x=>x.r):[r];sec&&placed.add(sec.id);for(let row of rows)row.action.startsGroup&&section.nodes.length>0&&section.nodes.push({kind:"separator",id:`${row.action.id}:group`}),section.nodes.push(actionToNode(row,target,options)),row.action.verb&&(roles[row.action.verb]=row.action.id)}let list=[...sections.values()].sort((a,b)=>!!a.primary!=!!b.primary?a.primary?-1:1:GROUP_ORDER.indexOf(a.group)-GROUP_ORDER.indexOf(b.group)),selected=target.selection?.text?.trim(),content=options.content?.trim(),fieldName=options.contentLabel?.trim();return{header:selected?{label:"Selected",text:target.selection?.text??""}:fieldName?{label:fieldName,text:options.content??""}:content?{label:"Content",text:options.content??""}:null,sections:list,roles}}function withGroupDividers(children,nodes){let out=[];return children.forEach((child,i)=>{let node=nodes[i];node&&(i>0&&(child.startsGroup||(children[i-1].section?.id??null)!==(child.section?.id??null))&&out.push({kind:"separator",id:`${child.id}:group`}),out.push(node))}),out}function withExpandedChildren(model,nodeId,children){let visit=nodes=>nodes.map(n=>n.kind!=="submenu"?n:n.id===nodeId?children==="loading"?{...n,loading:!0}:{...n,lazy:!1,loading:!1,pending:!1,children}:{...n,children:visit(n.children)});return{...model,sections:model.sections.map(s=>({...s,nodes:visit(s.nodes)}))}}function findNode(nodes,id){for(let n of nodes){if(n.id===id)return n;if(n.kind==="submenu"){let hit=findNode(n.children,id);if(hit)return hit}}return null}var React=__toESM(require("react"),1),KEY=Symbol.for("ai-matrx.alchemy.actions-context"),AlchemyActionsContext=globalThis[KEY]??=React.createContext(null);function useAlchemyActions(){let value=React.useContext(AlchemyActionsContext);if(!value)throw new Error("Alchemy actions: render inside <AlchemyActionsProvider> (@ai-matrx/alchemy/react/host).");return value}function isLatestExpansion(capturedTargetEpoch,currentTargetEpoch,capturedNodeSequence,currentNodeSequence){return capturedTargetEpoch===currentTargetEpoch&&capturedNodeSequence===currentNodeSequence}var import_jsx_runtime=require("react/jsx-runtime");function nodeInModel(model,id){for(let s of model.sections){let hit=findNode(s.nodes,id);if(hit)return hit}return null}function hasLoadedRows(model,id){let n=nodeInModel(model,id);return!!(n&&n.kind==="submenu"&&!n.lazy&&!n.loading)}function loadedChildren(model,id){let n=nodeInModel(model,id);return n&&n.kind==="submenu"&&!n.lazy?n.children:[]}function carryOpened(prev,next,opened){return next.map(n=>{if(n.kind!=="submenu")return n;let old=prev.find(o=>o.id===n.id);return!old||old.kind!=="submenu"||old.lazy?n:n.lazy?opened.has(n.id)?{...n,lazy:!1,loading:!1,pending:!1,children:old.children}:n:{...n,children:carryOpened(old.children,n.children,opened)}})}function carryOpenedModel(prev,next,opened){if(opened.size===0)return next;let prevNodes=prev.sections.flatMap(s=>s.nodes);return{...next,sections:next.sections.map(s=>({...s,nodes:carryOpened(prevNodes,s.nodes,opened)}))}}function useMenuEngine(target,options={}){let{registry,ports}=useAlchemyActions(),[resolved,setResolved]=React2.useState([]),[model,setModel]=React2.useState(null),[tick,setTick]=React2.useState(0),expanded=React2.useRef(new Map),opened=React2.useRef(new Set),expandSeq=React2.useRef(new Map),targetEpoch=React2.useRef(0),currentTarget=React2.useRef(target);currentTarget.current!==target&&(currentTarget.current=target,targetEpoch.current+=1);let active=options.active??!0,optionsRef=React2.useRef(options);optionsRef.current=options,React2.useEffect(()=>registry.subscribe(()=>setTick(t=>t+1)),[registry]);let expandAction=React2.useCallback(async(action,nodeId)=>{if(!target||!action.expand)return;let epoch=targetEpoch.current,seq=(expandSeq.current.get(nodeId)??0)+1;expandSeq.current.set(nodeId,seq);let latest=()=>isLatestExpansion(epoch,targetEpoch.current,seq,expandSeq.current.get(nodeId));setModel(m=>m&&!hasLoadedRows(m,nodeId)?withExpandedChildren(m,nodeId,"loading"):m);try{let children=await action.expand(target,new AbortController().signal);if(!latest())return;let nodes=withGroupDividers(children,children.map(child=>(expanded.current.set(child.id,child),actionToNode({action:child,eligibility:{status:"available"}},target,ports.i18n?{i18n:ports.i18n}:{}))));setModel(m=>m&&withExpandedChildren(m,nodeId,carryOpened(loadedChildren(m,nodeId),nodes,opened.current)));for(let child of children)child.expand&&opened.current.has(child.id)&&expandAction(child,child.id)}catch(error){if(!latest())return;ports.diagnostics.capture(error,{area:"menu",detail:{nodeId,stage:"expand"}}),setModel(m=>m&&withExpandedChildren(m,nodeId,[]))}},[target,ports]);React2.useEffect(()=>{expanded.current.clear(),opened.current.clear()},[target]),React2.useEffect(()=>{if(!target||!active)return;let live=!0;return registry.resolve(target,optionsRef.current.restrict).then(list=>{if(!live)return;setResolved(list);let built=buildMenuModel(target,list,{...ports.i18n?{i18n:ports.i18n}:{},content:optionsRef.current.content??null,contentLabel:optionsRef.current.contentLabel??null});setModel(prev=>prev?carryOpenedModel(prev,built,opened.current):built);for(let{action}of list)opened.current.has(action.id)&&action.expand&&expandAction(action,action.id)}),()=>{live=!1}},[registry,ports,target,active,tick,options.revision,expandAction]);let resolvedRef=React2.useRef(resolved);resolvedRef.current=resolved;let subscribedIds=resolved.map(r=>r.action.id).join(`
3
3
  `);React2.useEffect(()=>{if(!target)return;let subscribing=!0,onChange=()=>{subscribing||setTick(t=>t+1)},offs=resolvedRef.current.map(r=>r.action.subscribe?.(onChange,target)).filter(off=>typeof off=="function");return subscribing=!1,()=>offs.forEach(off=>off())},[subscribedIds,target]);let findAction=React2.useCallback(id=>resolved.find(r=>r.action.id===id)?.action??expanded.current.get(id)??void 0,[resolved]),run=React2.useCallback(async nodeId=>{if(!target||!model)return null;let node=model.sections.map(s=>findNode(s.nodes,nodeId)).find(Boolean)??null,action=findAction(node&&"actionId"in node&&node.actionId?node.actionId:nodeId);if(!action)return null;let o=optionsRef.current,result=await runAction(action,target,{ports,...o.source?{source:o.source}:{},...o.contentFingerprint?{contentFingerprint:o.contentFingerprint}:{}});return o.onRan?.(nodeId,result,{keepOpen:!!action.keepsMenuOpen}),result},[target,model,findAction,ports]),expand=React2.useCallback(async nodeId=>{let action=findAction(nodeId);!target||!action?.expand||(opened.current.add(nodeId),await expandAction(action,nodeId))},[findAction,target,expandAction]),icon=React2.useCallback((key,tone)=>{if(!key||!ports.icons)return null;let Resolved=ports.icons.resolve(key);return Resolved?(0,import_jsx_runtime.jsx)(Resolved,{className:`h-4 w-4 shrink-0 ${tone??""}`,"aria-hidden":!0}):null},[ports.icons]),explain=React2.useCallback(sentence=>{ports.notify?ports.notify.info(sentence):ports.diagnostics.capture(new Error(`No notify port to explain: ${sentence}`),{area:"menu",detail:{sentence}})},[ports]);return{model,resolved,run,expand,icon,explain}}var React4=__toESM(require("react"),1),import_design_system=require("@ai-matrx/design-system");var React3=__toESM(require("react"),1),MenuSizeContext=React3.createContext("standard");function useMenuSize(){return React3.useContext(MenuSizeContext)}var MENU_SIZE_CLASSES={standard:{panel:"w-72",row:"gap-2",strip:"flex items-center gap-0.5 px-1 py-1",stripButton:"h-7 min-w-7 px-1.5",label:"text-xs",filter:"h-7 text-sm",hint:"text-xs"},large:{panel:"w-[22.5rem] [&_svg]:size-[18px]",row:"gap-3 min-h-9 px-3 text-[15px]",strip:"flex items-center justify-between gap-1 px-2 py-1.5",stripButton:"h-9 min-w-9 px-2",label:"text-[13px]",filter:"h-9 text-[15px]",hint:"text-[13px]"}};var import_jsx_runtime2=require("react/jsx-runtime");function NodeList({nodes,engine}){return(0,import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment,{children:nodes.map(node=>(0,import_jsx_runtime2.jsx)(MenuNodeView,{node,engine},node.id))})}function SectionList({sections,engine}){let size=MENU_SIZE_CLASSES[useMenuSize()];return(0,import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment,{children:sections.map((section,index)=>(0,import_jsx_runtime2.jsxs)(React4.Fragment,{children:[index>0?(0,import_jsx_runtime2.jsx)(import_design_system.DropdownMenuSeparator,{}):null,sectionLabel(section)?(0,import_jsx_runtime2.jsx)(import_design_system.DropdownMenuLabel,{className:`${size.label} font-medium text-muted-foreground`,children:sectionLabel(section)}):null,(0,import_jsx_runtime2.jsx)(NodeList,{nodes:section.nodes,engine})]},section.id))})}function iconOf(node,engine){if(node.kind!=="item")return"icon"in node?engine.icon(node.icon):null;if(node.stateIcon){let glyph=engine.icon(node.stateIcon.icon);return node.stateIcon.spin?(0,import_jsx_runtime2.jsx)("span",{className:"inline-flex animate-spin",children:glyph}):glyph}if(!("icon"in node))return null;let tone=node.pressed===!1?void 0:node.iconTone;return engine.icon(node.icon,tone)}function MenuNodeView({node,engine}){let size=MENU_SIZE_CLASSES[useMenuSize()];switch(node.kind){case"separator":return(0,import_jsx_runtime2.jsx)(import_design_system.DropdownMenuSeparator,{});case"label":return(0,import_jsx_runtime2.jsx)(import_design_system.DropdownMenuLabel,{className:`${size.label} font-medium text-muted-foreground`,children:node.label});case"submenu":return(0,import_jsx_runtime2.jsx)(SubmenuView,{node,engine});case"checkbox":return(0,import_jsx_runtime2.jsxs)(import_design_system.DropdownMenuCheckboxItem,{"data-alchemy-node":node.id,checked:node.checked,onSelect:()=>{engine.run(node.id)},className:size.row,children:[iconOf(node,engine),(0,import_jsx_runtime2.jsx)("span",{className:"truncate",children:node.label})]});case"link":return(0,import_jsx_runtime2.jsx)(import_design_system.DropdownMenuItem,{asChild:!0,"data-alchemy-node":node.id,children:(0,import_jsx_runtime2.jsxs)("a",{href:node.href,target:node.target,className:size.row,children:[iconOf(node,engine),(0,import_jsx_runtime2.jsx)("span",{className:"truncate",children:node.label})]})});case"item":return(0,import_jsx_runtime2.jsx)(LeafItem,{node,engine})}}function SubmenuView({node,engine}){let triggerRef=React4.useRef(null),size=MENU_SIZE_CLASSES[useMenuSize()];return(0,import_jsx_runtime2.jsxs)(import_design_system.DropdownMenuSub,{onOpenChange:open=>{open&&node.lazy&&!node.loading&&engine.expand(node.id)},children:[(0,import_jsx_runtime2.jsxs)(import_design_system.DropdownMenuSubTrigger,{ref:triggerRef,"data-alchemy-node":node.id,className:size.row,"aria-busy":node.pending?!0:void 0,children:[iconOf(node,engine),(0,import_jsx_runtime2.jsx)("span",{className:"truncate",children:node.label}),node.pending?(0,import_jsx_runtime2.jsx)("span",{className:"ml-auto text-xs text-muted-foreground",children:"Loading\u2026"}):null]}),(0,import_jsx_runtime2.jsx)(import_design_system.DropdownMenuSubContent,{"data-alchemy-submenu":node.id,onFocusOutside:event=>{let to=event.target,trigger=triggerRef.current;to instanceof Element&&trigger&&to.getAttribute("role")==="menu"&&to.contains(trigger)&&event.preventDefault()},className:`${size.panel} max-w-[calc(100vw-1rem)] max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto`,children:node.loading?(0,import_jsx_runtime2.jsx)(import_design_system.DropdownMenuLabel,{className:"text-xs text-muted-foreground",children:"Loading\u2026"}):node.children.length===0&&!node.lazy?(0,import_jsx_runtime2.jsx)(import_design_system.DropdownMenuLabel,{className:"text-xs text-muted-foreground",children:node.emptyLabel??"Nothing here yet"}):(0,import_jsx_runtime2.jsx)(NodeList,{nodes:node.children,engine})})]})}function LeafItem({node,engine}){let size=MENU_SIZE_CLASSES[useMenuSize()],row=(0,import_jsx_runtime2.jsxs)(import_design_system.DropdownMenuItem,{"data-alchemy-node":node.id,"aria-disabled":node.unavailable?!0:void 0,"aria-pressed":node.pressed,onSelect:event=>{if(node.unavailable){event.preventDefault();return}node.keepsMenuOpen&&event.preventDefault(),engine.run(node.id)},className:`${size.row} ${node.unavailable?"opacity-50":""} ${node.destructive?"text-destructive":""}`,children:[iconOf(node,engine),(0,import_jsx_runtime2.jsxs)("span",{className:"flex min-w-0 flex-1 flex-col",children:[(0,import_jsx_runtime2.jsx)("span",{className:"truncate",children:node.label}),node.description?(0,import_jsx_runtime2.jsx)("span",{className:"truncate text-xs text-muted-foreground",children:node.description}):null]}),node.hint?(0,import_jsx_runtime2.jsx)("span",{className:`ml-auto ${size.hint} text-muted-foreground`,children:node.hint}):null]});return node.unavailable?(0,import_jsx_runtime2.jsxs)(import_design_system.Tooltip,{children:[(0,import_jsx_runtime2.jsx)(import_design_system.TooltipTrigger,{asChild:!0,children:row}),(0,import_jsx_runtime2.jsx)(import_design_system.TooltipContent,{children:node.unavailable.sentence})]}):row}function LeafButton({node,engine,showLabel}){if(node.kind!=="item"&&node.kind!=="checkbox"&&node.kind!=="link")return null;let unavailable=node.kind==="item"?node.unavailable:void 0,pressed=node.kind==="item"?node.pressed:node.kind==="checkbox"?node.checked:void 0,glyph=iconOf(node,engine),size=MENU_SIZE_CLASSES[useMenuSize()],destructive=node.kind==="item"&&node.destructive,button=(0,import_jsx_runtime2.jsxs)("button",{type:"button","data-alchemy-node":node.id,"data-matrx-button":"","data-tap-floor":"","data-tap-floor-square":"","aria-label":node.label,"aria-disabled":unavailable?!0:void 0,"aria-pressed":pressed,onMouseDown:e=>{node.kind==="item"&&node.preserveSelection&&e.preventDefault()},onClick:()=>{if(unavailable){engine.explain(unavailable.sentence);return}if(node.kind==="link"){window.location.assign(node.href);return}engine.run(node.id)},className:`inline-flex ${size.stripButton} pointer-coarse:h-11 pointer-coarse:min-w-11 shrink-0 items-center justify-center gap-1.5 rounded-md text-sm ${destructive?"text-destructive hover:bg-destructive/10":"text-muted-foreground hover:bg-accent hover:text-foreground"} ${unavailable?"cursor-default opacity-50 hover:bg-transparent":""} ${pressed?"text-foreground":""}`,children:[glyph,showLabel||!glyph?(0,import_jsx_runtime2.jsx)("span",{className:"whitespace-nowrap",children:node.label}):null]});return(0,import_jsx_runtime2.jsxs)(import_design_system.Tooltip,{children:[(0,import_jsx_runtime2.jsx)(import_design_system.TooltipTrigger,{asChild:!0,children:button}),(0,import_jsx_runtime2.jsx)(import_design_system.TooltipContent,{children:unavailable?unavailable.sentence:node.label})]})}var import_jsx_runtime3=require("react/jsx-runtime");function isNarrow(width){return typeof window>"u"?!1:window.matchMedia?.(`(max-width: ${width-1}px)`).matches??!1}var TRIGGER_CLASS="inline-flex h-7 min-w-7 pointer-coarse:h-11 pointer-coarse:min-w-11 items-center justify-center gap-1 rounded-md px-1.5 text-muted-foreground hover:bg-accent hover:text-foreground";function PrimarySubmenu({node,engine}){return(0,import_jsx_runtime3.jsxs)(import_design_system2.DropdownMenu,{onOpenChange:open=>{open&&node.lazy&&!node.loading&&engine.expand(node.id)},children:[(0,import_jsx_runtime3.jsx)(import_design_system2.DropdownMenuTrigger,{asChild:!0,children:(0,import_jsx_runtime3.jsx)("button",{type:"button","aria-label":node.label,"data-alchemy-node":node.id,className:TRIGGER_CLASS,children:engine.icon(node.icon)??(0,import_jsx_runtime3.jsx)("span",{className:"text-sm",children:node.label})})}),(0,import_jsx_runtime3.jsx)(import_design_system2.DropdownMenuContent,{align:"start",className:"w-64 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto",children:node.loading?(0,import_jsx_runtime3.jsx)("div",{className:"px-2 py-1.5 text-xs text-muted-foreground",children:"Loading\u2026"}):(0,import_jsx_runtime3.jsx)(NodeList,{nodes:node.children,engine})})]})}function ActionBar({target,mini=!1,className,hideOverflow=!1,sheetBelow=768,loadSheet=()=>import("@ai-matrx/alchemy/react/sheet"),...options}){let engine=useMenuEngine(target,options),[sheetOpen,setSheetOpen]=React5.useState(!1),[Sheet,setSheet]=React5.useState(null);if(!engine.model)return null;let arranged=bar(engine.model,{mini});return arranged.primary.length===0&&arranged.overflow.length===0?null:(0,import_jsx_runtime3.jsx)(import_design_system2.TooltipProvider,{children:(0,import_jsx_runtime3.jsxs)("div",{role:"toolbar","aria-label":"Actions","data-alchemy-layout":"bar",className:`flex items-center ${mini?"gap-0":"gap-0.5"} ${className??""}`,children:[arranged.primary.map(node=>node.kind==="submenu"?(0,import_jsx_runtime3.jsx)(PrimarySubmenu,{node,engine},node.id):(0,import_jsx_runtime3.jsx)(LeafButton,{node,engine,showLabel:!1},node.id)),hideOverflow||arranged.overflow.length===0?null:isNarrow(sheetBelow)?(0,import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment,{children:[(0,import_jsx_runtime3.jsx)("button",{type:"button","aria-label":"More actions","data-alchemy-trigger":"overflow",className:TRIGGER_CLASS,onClick:()=>{setSheetOpen(!0),Sheet||loadSheet().then(m=>setSheet(()=>m.ActionSheet))},children:(0,import_jsx_runtime3.jsx)("span",{"aria-hidden":!0,className:"text-base leading-none",children:"\u22EF"})}),Sheet?(0,import_jsx_runtime3.jsx)(Sheet,{...options,target,open:sheetOpen,onOpenChange:setSheetOpen}):null]}):(0,import_jsx_runtime3.jsxs)(import_design_system2.DropdownMenu,{children:[(0,import_jsx_runtime3.jsx)(import_design_system2.DropdownMenuTrigger,{asChild:!0,children:(0,import_jsx_runtime3.jsx)("button",{type:"button","aria-label":"More actions","data-alchemy-trigger":"overflow",className:TRIGGER_CLASS,children:(0,import_jsx_runtime3.jsx)("span",{"aria-hidden":!0,className:"text-base leading-none",children:"\u22EF"})})}),(0,import_jsx_runtime3.jsx)(import_design_system2.DropdownMenuContent,{align:"end",className:"w-64 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto",children:(0,import_jsx_runtime3.jsx)(SectionList,{sections:arranged.overflow,engine})})]})]})})}
4
4
  //# sourceMappingURL=react-bar.cjs.map