@x-otto/hook-contracts 0.0.1-alpha.2 → 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @x-otto/hook-contracts
2
2
 
3
- > Engine↔hooks pure type contracts. Zero runtime `export type` only, compiled output is empty.
3
+ > Engine↔hooks type contracts. A type-contract package with 5 runtime exports: `PERMISSION_MODES`, `WATERFALL_TIMINGS`, `isWaterfallTiming`, `EVENT_DOMAIN`, `getEventDomain`.
4
4
 
5
- `@x-otto/hook-contracts` defines the type-level contract between the engine (`@x-otto/agent`) and the hook system (`@x-otto/hooks`). It provides 25 hook timings with typed input/output payloads, the unified `AgentMessage` type, permission config shapes, and re-exports session event types from `@x-otto/interchange`. Both sides `import type`, avoiding a circular runtime dependency.
5
+ `@x-otto/hook-contracts` defines the type-level contract between the engine (`@x-otto/agent`) and the hook system (`@x-otto/hooks`). It provides 25 hook timings with typed input/output payloads, the unified `AgentMessage` type, permission config shapes, and re-exports session event types from `@x-otto/interchange`. Both sides `import type` for the type surface; the 5 runtime exports are the only values shipped.
6
6
 
7
7
  ## Installation
8
8
 
@@ -41,6 +41,7 @@ type ToolBeforeOutput = HookPayloadMap['tool.execute.before']['output']
41
41
  - `ObserverTiming` — compile-time subset: timings where output is `void` (read-only observation)
42
42
  - `InterceptorTiming` — compile-time subset: timings where output can modify behavior
43
43
  - `HookHandle<T extends HookTiming>` — derives correct handler signature
44
+ - `WATERFALL_TIMINGS` / `isWaterfallTiming` — runtime allowlist for waterfall (transform-chain) timings
44
45
 
45
46
  ### Hook Payload Types
46
47
  - `ChatMessageInput` / `ChatMessageOutput` — message interception
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AgentSessionEvent, AgentSessionEventMap, AgentSessionEventType, AgentSessionSubscriber, AgentTool, AskUserQuestion, GrillAnswer, GrillOption, GrillQuestion, GrillRequest, Message, ToolCallContext, ToolCallEvent, ToolErrorKind, ToolResult } from "@x-otto/interchange";
1
+ import { AgentSessionEvent, AgentSessionEventMap, AgentSessionEventType, AgentSessionSubscriber, AgentTool, AgentToolDefinition, AskUserQuestion, EVENT_DOMAIN, EventDomain, GrillAnswer, GrillOption, GrillQuestion, GrillRequest, Message, ToolCallContext, ToolCallEvent, ToolErrorKind, ToolExecutionPolicy, ToolResult, getEventDomain } from "@x-otto/interchange";
2
2
 
3
3
  //#region src/messages.d.ts
4
4
  interface CustomAgentMessages {}
@@ -57,11 +57,34 @@ interface ToolExecuteBeforeInput {
57
57
  */
58
58
  readonly?: boolean;
59
59
  }
60
+ /**
61
+ * Hook 契约层的权限决策词表(handler 返回给引擎)。
62
+ *
63
+ * **三层同名不同构**(终局保留,非过渡):
64
+ * - **配置层** `RuleEffect`(`permission-config.ts`):config.json 写的效果值,消费方 = setting zod schema + PermissionRuleConfig。
65
+ * - **契约层** `PermissionDecision`(本类型):hook handler 返回给引擎的简化词表,消费方 = ToolExecuteBeforeOutput.decision。
66
+ * - **运行时层** guard 的 `PermissionDecision`(`guard/src/permission/types.ts`):更丰富的结构体(含 policyName/reason/timestamp/safety),消费方 = 引擎权限评估。
67
+ *
68
+ * 三层字面量恰好相同(都是 'allow'|'deny'|'ask')但分属不同抽象层,消费方不交叉——
69
+ * 合并会制造跨层耦合(config.json 解析器不需要 policyName/timestamp)。
70
+ * 故注释点明层次关系是终局方向,非待合并的过渡方案。
71
+ */
60
72
  type PermissionDecision = 'allow' | 'deny' | 'ask';
61
73
  /** 审批显示等级(仅驱动 UI 文案/排序,不参与 allow/deny/ask 裁决)。 */
62
74
  type ApprovalRisk = 'low' | 'medium' | 'high';
63
75
  interface ToolExecuteBeforeOutput {
64
- args: Record<string, unknown>;
76
+ /**
77
+ * 执行性参数(command/path 等不可变)——引擎消费此版本做执行/审计。
78
+ * TS readonly 约束编译期不可改(运行时不 freeze,因 waterfall 共享可变对象需后续 hook 改 displayArgs)。
79
+ * 对照 deepseek-harness tools/pre-execute 禁止参数改写的论证(audit/history/presentation 一致性)。
80
+ */
81
+ readonly args: Readonly<Record<string, unknown>>;
82
+ /**
83
+ * 展示性字段(label/description/title 等)——hook 可改写,引擎消费此版本做展示。
84
+ * waterfall 语义:后一个 hook 看到前一个 hook 的 displayArgs 改写(与 args 改写同构)。
85
+ * 消费方读 `output.displayArgs ?? output.args`(优先 displayArgs,回退原始 args)。
86
+ */
87
+ displayArgs?: Record<string, unknown>;
65
88
  cancelled: boolean;
66
89
  cancelReason?: string;
67
90
  decision?: PermissionDecision;
@@ -122,11 +145,20 @@ interface SystemPromptTransformInput {
122
145
  userText?: string;
123
146
  }
124
147
  interface SystemPromptTransformOutput {
125
- /** 会话内稳定的 system 前缀(进入 prompt cache)。稳定注入累加到这里。 */
148
+ /**
149
+ * 会话内稳定的 system 前缀(进入 prompt cache)。稳定注入累加到这里。
150
+ *
151
+ * RFC-327 修订 D1a(M1):stable 子字段——逐字节稳定,写入会永久污染后续所有轮次的
152
+ * prompt cache 前缀,成本与危害远大于 volatile。插件 waterfall **默认不开放本字段**
153
+ * (写入需独立更高档授权;第一版直接拒绝,见 `module-wiring.ts` stable 写入守卫)。
154
+ */
126
155
  systemPrompt: string;
127
156
  /**
128
157
  * 每轮可变(volatile)的 system 尾段:附在 stable 前缀的 cache 断点**之后**,
129
158
  * 不破坏 prompt cache。逐轮变化的注入(如 phase context)写这里而非 systemPrompt。
159
+ *
160
+ * RFC-327 修订 D1a(M1):`string[]` 数组形态(追加语义——审计与预算按数组元素计);
161
+ * 插件 waterfall 默认只开放本字段 + 预算闸(volatile 尾段 4KB 顶,见 `module-wiring.ts`)。
130
162
  */
131
163
  systemTail?: string[];
132
164
  }
@@ -331,10 +363,15 @@ interface TaskHookOutput {
331
363
  };
332
364
  durationMs?: number;
333
365
  }
366
+ /**
367
+ * Task 生命周期状态(hook 契约层判别联合)。
368
+ * emit 点已核实:orchestrator 侧只 emit 这 5 个值,无超集(grep packages/orchestrator/src 确认)。
369
+ */
370
+ type TaskHookStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
334
371
  interface TaskHookInfo {
335
372
  id: string;
336
373
  parentId?: string;
337
- status: string;
374
+ status: TaskHookStatus;
338
375
  sessionId?: string;
339
376
  attempts: number;
340
377
  maxAttempts: number;
@@ -344,23 +381,73 @@ interface TaskHookInfo {
344
381
  error?: TaskHookError;
345
382
  /**
346
383
  * Swarm 编排事件上下文(RFC-107 D1 / M-N6)。
347
- * 当 task 属于 swarm 编排时由 Swarm.emitEvent 经 hookRegistry 桥接注入;
348
- * 下游 hook 据此区分普通 task swarm 成员 turn,并消费路由/编组元数据。
384
+ *
385
+ * **死字段标注(RFC-398 M6)**:swarmEvent 桥接已被 RFC-398 M6 删除(全仓零消费方,
386
+ * 编排事件塞进 task.started 是语义错位)。本字段保留类型(契约层不删导出),但运行时
387
+ * 不再填充——orchestrator/swarm/swarm.ts:75 注释"删 swarmEvent 死桥接"。
388
+ * 下游 hook 不应依赖此字段有值。
349
389
  */
350
390
  swarmEvent?: SwarmEventPayload;
351
391
  }
352
392
  /**
353
393
  * Swarm 编排事件载荷(hook-contracts 拥有最小形状;实际数据由 orchestrator/swarm 填充)。
354
394
  * 不新建 swarm.* HookTiming 家族——经既有 task.*(如 task.started)携带。
395
+ *
396
+ * **RFC-415 D3**:从 `type: string` + `[key: string]: unknown` 收窄为判别联合——
397
+ * 每个 type 对应自己的附加载荷形状,消费方按 type narrow 取字段(不再 cast)。
398
+ *
399
+ * **死字段标注(RFC-398 M6)**:TaskHookInfo.swarmEvent 运行时不再填充
400
+ * (RFC-398 M6 删桥接),本类型保留为契约层导出供未来重新接线使用。
355
401
  */
356
- interface SwarmEventPayload {
357
- /** 事件类型:swarm.start | swarm.end | agent.start | agent.end | handoff |
358
- * routing.decision | parallel.fanOut | parallel.fanIn | pipeline.step |
359
- * hierarchy.delegate | error */
360
- type: string;
361
- /** 事件附加元数据(按 type 不同携带 agentId/durationMs/decision 等字段)。 */
362
- [key: string]: unknown;
363
- }
402
+ type SwarmEventPayload = {
403
+ type: 'swarm.start';
404
+ agentId?: string;
405
+ totalAgents?: number;
406
+ } | {
407
+ type: 'swarm.end';
408
+ agentId?: string;
409
+ durationMs?: number;
410
+ } | {
411
+ type: 'agent.start';
412
+ agentId: string;
413
+ } | {
414
+ type: 'agent.end';
415
+ agentId: string;
416
+ durationMs?: number;
417
+ } | {
418
+ type: 'handoff';
419
+ fromAgent: string;
420
+ toAgent: string;
421
+ reason?: string;
422
+ } | {
423
+ type: 'routing.decision';
424
+ decision: string;
425
+ agentId?: string;
426
+ } | {
427
+ type: 'parallel.fanOut';
428
+ parentAgent: string;
429
+ childAgents: string[];
430
+ } | {
431
+ type: 'parallel.fanIn';
432
+ parentAgent: string;
433
+ childAgents: string[];
434
+ results?: unknown[];
435
+ } | {
436
+ type: 'pipeline.step';
437
+ step: number;
438
+ totalSteps: number;
439
+ agentId?: string;
440
+ } | {
441
+ type: 'hierarchy.delegate';
442
+ parentId: string;
443
+ childId: string;
444
+ } | {
445
+ type: 'error';
446
+ error: string;
447
+ agentId?: string;
448
+ };
449
+ /** Swarm 事件类型字面量联合(从 SwarmEventPayload 派生,供消费方 narrow)。 */
450
+ type SwarmEventType = SwarmEventPayload['type'];
364
451
  /** 通知 hook 出站 payload(producer=HookChannel;consumer=.claude 桥/用户 hook)。 */
365
452
  interface NotificationHookInput {
366
453
  sessionId: string;
@@ -386,7 +473,35 @@ type HookEmitInput<T extends HookTiming> = T extends 'session.error' ? SessionEv
386
473
  type HookOutput<T extends HookTiming> = HookPayloadMap[T]['output'];
387
474
  type ObserverTiming = { [K in HookTiming]: HookPayloadMap[K]['output'] extends void ? K : never }[HookTiming];
388
475
  type InterceptorTiming = { [K in HookTiming]: HookPayloadMap[K]['output'] extends void ? never : K }[HookTiming];
389
- type HookHandle<T extends HookTiming> = T extends ObserverTiming ? (input: HookInput<T>) => void | Promise<void> : (input: HookInput<T>, output: HookOutput<T>) => void | Promise<void>;
476
+ /**
477
+ * RFC-327 修订 D1(M1):interceptor handle 的 waterfall 中止哨兵——**返回值形态**而非
478
+ * output 字段(output 是共享可变对象,放 output 会被后续 hook 覆盖,哨兵更安全)。
479
+ *
480
+ * 语义(serial-with-early-bail):任一 interceptor hook 返回 `{ abort: true }` →
481
+ * 终止当前 timing 的 hook 链,output 保留已累积值,后续 hook 不再执行。与 sticky-veto
482
+ * 的交互矩阵(RFC 定稿 §3 D1):abort 优先(终止链),abort **不清** sticky——
483
+ * abort 前已钉住的 cancelled/decision 值保留。空对象 `{}` / `{ abort: false }` 等价于
484
+ * void(不中断)。
485
+ */
486
+ interface HookAbortSignal {
487
+ abort?: boolean;
488
+ }
489
+ type HookHandle<T extends HookTiming> = T extends ObserverTiming ? (input: HookInput<T>) => void | Promise<void> : (input: HookInput<T>, output: HookOutput<T>) => void | HookAbortSignal | Promise<void | HookAbortSignal>;
490
+ /**
491
+ * RFC-327 修订 D1(M1):waterfall 白名单 timing——插件经受控贡献点改写主循环中间产物的
492
+ * 全部允许 timing。**编译期**从 `HookPayloadMap` 派生(Pick 白名单),新增 timing 必须
493
+ * 显式加入下方 `WATERFALL_TIMINGS` 数组(同字面量联合,二者漂移即编译错误);运行时校验
494
+ * (`isWaterfallTiming`)只作兜底——防 JS 插件/类型不安全条目在装载期注入白名单外 timing。
495
+ *
496
+ * 三个 timing 的 output 均无 `cancelled`/`decision` 字段(与 `STICKY_CANCELLED_TIMINGS`
497
+ * 现状一致)——waterfall 的 abort 走返回值哨兵(`HookAbortSignal`),**不**进入 sticky
498
+ * 白名单(不盲探测,见 `hook-registry.ts` STICKY 常量注释)。
499
+ */
500
+ type WaterfallTiming = Extract<keyof HookPayloadMap, 'system.prompt.transform' | 'chat.params' | 'messages.transform'>;
501
+ /** 运行时白名单(与 `WaterfallTiming` 同字面量,漂移即编译错误——`as const` 数组反哺联合)。 */
502
+ declare const WATERFALL_TIMINGS: readonly WaterfallTiming[];
503
+ /** 运行时校验兜底(装载期/测试用;类型安全代码经 `WaterfallTiming` 编译期已保证)。 */
504
+ declare function isWaterfallTiming(timing: string): timing is WaterfallTiming;
390
505
  //#endregion
391
506
  //#region src/permission-config.d.ts
392
507
  /**
@@ -407,7 +522,15 @@ type HookHandle<T extends HookTiming> = T extends ObserverTiming ? (input: HookI
407
522
  /** 权限模式词表(config.json `permission_mode` + 运行时模式)。 */
408
523
  declare const PERMISSION_MODES: readonly ["bypass", "auto", "confirm", "strict", "readonly"];
409
524
  type PermissionMode = (typeof PERMISSION_MODES)[number];
410
- /** 规则效果。 */
525
+ /**
526
+ * 规则效果(配置层词表)。
527
+ *
528
+ * 与 `timings.ts` 的 `PermissionDecision`(契约层)字面量相同但分属不同层——
529
+ * 本类型是 config.json 写的效果值(消费方 = setting zod + PermissionRuleConfig),
530
+ * `PermissionDecision` 是 hook handler 返回的词表(消费方 = ToolExecuteBeforeOutput.decision)。
531
+ * guard 运行时另有同名结构体 `PermissionDecision`(guard/src/permission/types.ts)。
532
+ * 三层同名不同构,不合并(→ timings.ts PermissionDecision 注释)。
533
+ */
411
534
  type RuleEffect = 'allow' | 'deny' | 'ask';
412
535
  /** 单条权限规则的**配置**形状(config.json)。运行时 `PermissionRule`(含编译后 RegExp)属引擎。 */
413
536
  interface PermissionRuleConfig {
@@ -415,6 +538,17 @@ interface PermissionRuleConfig {
415
538
  effect: RuleEffect;
416
539
  tools?: string[];
417
540
  paths?: string[];
541
+ /**
542
+ * shell 命令内容正则(对 bash 类工具的 `args.command` 与 MCP 工具的字符串参数生效)。
543
+ *
544
+ * 补齐配置化规则此前只能按 tools/paths 匹配的缺口——「禁止某个命令」是团队规约的常见
545
+ * 诉求(如本仓 AGENTS.md 的 `git stash` 红线),此前只能硬编码进 builtin 策略(把项目
546
+ * 规约塞进通用引擎,架构上错位)。有了本字段,项目规约走项目配置,引擎只提供机制。
547
+ *
548
+ * 匹配语义与 builtin 命令类策略一致:经 `extractShellCommands` 拆分复合命令(`&&`/`;`/
549
+ * 管道)后逐段匹配,任一段命中即触发——防 `foo && git stash` 这类绕过。
550
+ */
551
+ commands?: string[];
418
552
  deny_reason?: string;
419
553
  ask_prompt?: string;
420
554
  }
@@ -428,7 +562,25 @@ interface PermissionPolicySetting {
428
562
  sessions?: string[];
429
563
  };
430
564
  rules: PermissionRuleConfig[];
565
+ /**
566
+ * 配置依赖的 policy-schema 版本(2026-08-15 全 agent 锁死事故教训固化)。
567
+ *
568
+ * 背景:`commands` 维度引入后,旧 dist 的 compilePolicyFromSetting 不认识该字段会静默
569
+ * 丢弃,产出 {tools:∅, paths:∅, condition:∅} 的 deny 规则 → matchesRule 匹配一切 →
570
+ * 锁死全部工具(bash/read/write/grep 全瘫)。空匹配守卫(48a01a379)能把这类规则
571
+ * fail-closed 跳过,但**无版本戳时排障仍靠猜**——规则被跳过是"配置写错"还是"dist 太旧"
572
+ * 无法区分。
573
+ *
574
+ * 语义:声明本配置依赖的最低 schema 版本。compilePolicyFromSetting 读取
575
+ * POLICY_SCHEMA_VERSION 常量对比——配置声明的版本 > 编译方支持的版本时,显式报错
576
+ * (warn + 跳过整条策略),并把版本差异写进日志。用户/运维据此一眼判断"该升级 dist
577
+ * 了",而非对着静默跳过的规则排查。
578
+ *
579
+ * 向后兼容:缺省 = 0(不声明),编译方不校验——旧配置不受影响,漂移防护只对显式
580
+ * 声明版本的新配置生效。
581
+ */
582
+ schemaVersion?: number;
431
583
  }
432
584
  //#endregion
433
- export { type AgentMessage, type AgentSessionEvent, type AgentSessionEventMap, type AgentSessionEventType, type AgentSessionSubscriber, type AgentTool, type ApprovalRisk, type AskUserQuestion, type ChatMessageInput, type ChatMessageOutput, type ChatParamsInput, type ChatParamsOutput, type CustomAgentMessages, type GrillAnswer, type GrillOption, type GrillQuestion, type GrillRequest, type HookEmitInput, type HookHandle, type HookInput, type HookOutput, type HookPayloadMap, type HookTiming, type InterceptorTiming, type MessagesTransformInput, type MessagesTransformOutput, type NotificationHookInput, type ObserverTiming, PERMISSION_MODES, type PermissionDecision, type PermissionMode, type PermissionPolicySetting, type PermissionRuleConfig, type RuleEffect, type SessionEventInput, type SwarmEventPayload, type SystemAgentMessage, type SystemMessageLevel, type SystemPromptTransformInput, type SystemPromptTransformOutput, type TaskHookError, type TaskHookInfo, type TaskHookOutput, type ToolCallContext, type ToolCallEvent, type ToolErrorKind, type ToolExecuteAfterInput, type ToolExecuteAfterOutput, type ToolExecuteBeforeInput, type ToolExecuteBeforeOutput, type ToolResult };
585
+ export { type AgentMessage, type AgentSessionEvent, type AgentSessionEventMap, type AgentSessionEventType, type AgentSessionSubscriber, type AgentTool, type AgentToolDefinition, type ApprovalRisk, type AskUserQuestion, type ChatMessageInput, type ChatMessageOutput, type ChatParamsInput, type ChatParamsOutput, type CustomAgentMessages, EVENT_DOMAIN, type EventDomain, type GrillAnswer, type GrillOption, type GrillQuestion, type GrillRequest, type HookAbortSignal, type HookEmitInput, type HookHandle, type HookInput, type HookOutput, type HookPayloadMap, type HookTiming, type InterceptorTiming, type MessagesTransformInput, type MessagesTransformOutput, type NotificationHookInput, type ObserverTiming, PERMISSION_MODES, type PermissionDecision, type PermissionMode, type PermissionPolicySetting, type PermissionRuleConfig, type RuleEffect, type SessionEventInput, type SwarmEventPayload, type SwarmEventType, type SystemAgentMessage, type SystemMessageLevel, type SystemPromptTransformInput, type SystemPromptTransformOutput, type TaskHookError, type TaskHookInfo, type TaskHookOutput, type TaskHookStatus, type ToolCallContext, type ToolCallEvent, type ToolErrorKind, type ToolExecuteAfterInput, type ToolExecuteAfterOutput, type ToolExecuteBeforeInput, type ToolExecuteBeforeOutput, type ToolExecutionPolicy, type ToolResult, WATERFALL_TIMINGS, type WaterfallTiming, getEventDomain, isWaterfallTiming };
434
586
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/messages.ts","../src/timings.ts","../src/permission-config.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/messages.ts","../src/timings.ts","../src/permission-config.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- const e=[`bypass`,`auto`,`confirm`,`strict`,`readonly`];export{e as PERMISSION_MODES};
1
+ import{EVENT_DOMAIN as e,getEventDomain as t}from"@x-otto/interchange";const n=[`system.prompt.transform`,`chat.params`,`messages.transform`];function r(e){return n.includes(e)}const i=[`bypass`,`auto`,`confirm`,`strict`,`readonly`];export{e as EVENT_DOMAIN,i as PERMISSION_MODES,n as WATERFALL_TIMINGS,t as getEventDomain,r as isWaterfallTiming};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/permission-config.ts"],"sourcesContent":["/**\n * 权限**配置形状**单一真源(RFC-077 mirror-debt 收口,HK-1)。\n *\n * 背景:权限配置形状(mode 词表 + policy/rule 的 config 结构)历史上双份定义——\n * `@x-otto/setting` 的 zod schema(z.infer)与 `@x-otto/hooks` 引擎的手写 interface。二者层序不可互依\n * (hooks L2 < setting L3,hooks 不能上依赖 setting),故各写一套、无 drift guard。\n *\n * 收口:把配置形状沉到二者都能**下依赖**的零依赖叶 `@x-otto/hook-contracts`(L1):\n * - `@x-otto/hooks` 引擎 import 这些类型(删手写镜像)。\n * - `@x-otto/setting` 的 zod schema `satisfies z.ZodType<…>` 钉死到此(drift→编译报错),并 re-export。\n *\n * 这里只放**配置/wire 形状**(作者在 config.json 写的东西);运行时引擎类型\n * (PermissionPolicy/PermissionContext/PermissionDecision/PolicyScope 等,含 RegExp/函数/时间戳)\n * 仍属引擎、留 `@x-otto/hooks`。\n */\n\n/** 权限模式词表(config.json `permission_mode` + 运行时模式)。 */\nexport const PERMISSION_MODES = ['bypass', 'auto', 'confirm', 'strict', 'readonly'] as const\nexport type PermissionMode = (typeof PERMISSION_MODES)[number]\n\n/** 规则效果。 */\nexport type RuleEffect = 'allow' | 'deny' | 'ask'\n\n/** 单条权限规则的**配置**形状(config.json)。运行时 `PermissionRule`(含编译后 RegExp)属引擎。 */\nexport interface PermissionRuleConfig {\n name: string\n effect: RuleEffect\n tools?: string[]\n paths?: string[]\n deny_reason?: string\n ask_prompt?: string\n}\n\n/** 单个权限策略的**配置**形状(config.json)。运行时 `PermissionPolicy`(含 safety/priority 语义)属引擎。 */\nexport interface PermissionPolicySetting {\n name: string\n priority?: number\n enabled?: boolean\n scope?: {\n agents?: string[]\n sessions?: string[]\n }\n rules: PermissionRuleConfig[]\n}\n"],"mappings":"AAiBA,MAAa,EAAmB,CAAC,SAAU,OAAQ,UAAW,SAAU,WAAW"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/timings.ts","../src/permission-config.ts"],"sourcesContent":["import type { AgentMessage, AgentTool, ToolResult } from './messages'\n\nexport type HookTiming =\n | 'chat.message.before'\n | 'chat.message.after'\n | 'tool.execute.before'\n | 'tool.execute.after'\n | 'messages.transform'\n | 'chat.params'\n | 'session.created'\n | 'session.restored'\n | 'session.deleted'\n | 'session.idle'\n | 'session.error'\n | 'stream.start'\n | 'stream.end'\n | 'compaction.before'\n | 'compaction.after'\n | 'memory.prune.before'\n | 'process.spawned'\n | 'process.exited'\n | 'task.created'\n | 'task.started'\n | 'task.completed'\n | 'task.failed'\n | 'task.cancelled'\n | 'system.prompt.transform'\n | 'notification'\n\nexport interface ChatMessageInput {\n message: AgentMessage\n sessionId: string\n isFirstMessage: boolean\n metadata: Record<string, unknown>\n}\n\nexport interface ChatMessageOutput {\n message: AgentMessage\n cancelled: boolean\n metadata: Record<string, unknown>\n}\n\nexport interface ToolExecuteBeforeInput {\n toolName: string\n toolCallId: string\n args: Record<string, unknown>\n agentName: string\n sessionId: string\n /**\n * 执行器据工具声明的 AgentTool.pathParams 从 args 解析出的文件系统路径。\n * PEP(permission/file guard)只读此字段做路径规则匹配,不再从 args 硬编码猜参数名。\n */\n paths?: readonly string[]\n /**\n * 工具是否为只读(AgentTool.readonly)。sandbox-guard 据此跳过写评估——\n * read/grep/find/lsp 等只读工具的 paths 是读目标而非写目标,不应被当作越界写而误升 ask/deny。\n */\n readonly?: boolean\n}\n\n/**\n * Hook 契约层的权限决策词表(handler 返回给引擎)。\n *\n * **三层同名不同构**(终局保留,非过渡):\n * - **配置层** `RuleEffect`(`permission-config.ts`):config.json 写的效果值,消费方 = setting zod schema + PermissionRuleConfig。\n * - **契约层** `PermissionDecision`(本类型):hook handler 返回给引擎的简化词表,消费方 = ToolExecuteBeforeOutput.decision。\n * - **运行时层** guard 的 `PermissionDecision`(`guard/src/permission/types.ts`):更丰富的结构体(含 policyName/reason/timestamp/safety),消费方 = 引擎权限评估。\n *\n * 三层字面量恰好相同(都是 'allow'|'deny'|'ask')但分属不同抽象层,消费方不交叉——\n * 合并会制造跨层耦合(config.json 解析器不需要 policyName/timestamp)。\n * 故注释点明层次关系是终局方向,非待合并的过渡方案。\n */\nexport type PermissionDecision = 'allow' | 'deny' | 'ask'\n\n/** 审批显示等级(仅驱动 UI 文案/排序,不参与 allow/deny/ask 裁决)。 */\nexport type ApprovalRisk = 'low' | 'medium' | 'high'\n\nexport interface ToolExecuteBeforeOutput {\n /**\n * 执行性参数(command/path 等不可变)——引擎消费此版本做执行/审计。\n * TS readonly 约束编译期不可改(运行时不 freeze,因 waterfall 共享可变对象需后续 hook 改 displayArgs)。\n * 对照 deepseek-harness tools/pre-execute 禁止参数改写的论证(audit/history/presentation 一致性)。\n */\n readonly args: Readonly<Record<string, unknown>>\n /**\n * 展示性字段(label/description/title 等)——hook 可改写,引擎消费此版本做展示。\n * waterfall 语义:后一个 hook 看到前一个 hook 的 displayArgs 改写(与 args 改写同构)。\n * 消费方读 `output.displayArgs ?? output.args`(优先 displayArgs,回退原始 args)。\n */\n displayArgs?: Record<string, unknown>\n cancelled: boolean\n cancelReason?: string\n decision?: PermissionDecision\n decisionReason?: string\n /**\n * decision==='ask' 时由权限层从 rich PermissionDecision(safety+policyName)派生的风险等级,\n * 透传给 HITL UI 作显示提示。缺省时下游回退 'medium'。\n */\n risk?: ApprovalRisk\n}\n\nexport interface ToolExecuteAfterInput {\n toolName: string\n toolCallId: string\n args: Record<string, unknown>\n result: ToolResult\n agentName: string\n sessionId: string\n durationMs: number\n /**\n * 工具是否为只读(AgentTool.readonly),由执行器从工具声明派生。\n * after-hook(comment-checker / edit-files-panel)据此识别「会改文件的工具」,\n * 取代各自硬编码的 write/edit 工具名集合——工具身份单源自注册表声明。\n */\n readonly?: boolean\n}\n\nexport interface ToolExecuteAfterOutput {\n result: ToolResult\n metadata: Record<string, unknown>\n}\n\nexport interface MessagesTransformInput {\n messages: AgentMessage[]\n tools: AgentTool[]\n agentName: string\n sessionId: string\n}\n\nexport interface MessagesTransformOutput {\n messages: AgentMessage[]\n}\n\nexport interface ChatParamsInput {\n sessionId?: string\n model: string\n provider: string\n temperature?: number\n maxTokens?: number\n thinkingLevel?: string\n}\n\nexport interface ChatParamsOutput {\n temperature?: number\n maxTokens?: number\n thinkingLevel?: string\n metadata: Record<string, unknown>\n}\n\nexport interface SystemPromptTransformInput {\n systemPrompt: string\n sessionId: string\n tools: AgentTool[]\n /** RFC-284 T3a:当前 prompt 的显式 user query,用于 volatile Relevant Hints。 */\n userText?: string\n}\n\nexport interface SystemPromptTransformOutput {\n /**\n * 会话内稳定的 system 前缀(进入 prompt cache)。稳定注入累加到这里。\n *\n * RFC-327 修订 D1a(M1):stable 子字段——逐字节稳定,写入会永久污染后续所有轮次的\n * prompt cache 前缀,成本与危害远大于 volatile。插件 waterfall **默认不开放本字段**\n * (写入需独立更高档授权;第一版直接拒绝,见 `module-wiring.ts` stable 写入守卫)。\n */\n systemPrompt: string\n /**\n * 每轮可变(volatile)的 system 尾段:附在 stable 前缀的 cache 断点**之后**,\n * 不破坏 prompt cache。逐轮变化的注入(如 phase context)写这里而非 systemPrompt。\n *\n * RFC-327 修订 D1a(M1):`string[]` 数组形态(追加语义——审计与预算按数组元素计);\n * 插件 waterfall 默认只开放本字段 + 预算闸(volatile 尾段 4KB 顶,见 `module-wiring.ts`)。\n */\n systemTail?: string[]\n}\n\nexport interface SessionEventInput {\n sessionId: string\n metadata: Record<string, unknown>\n}\n\nexport interface MemoryPruneBeforeInput {\n sessionId: string\n /** 即将参与裁剪判定的上下文消息条数。 */\n messageCount: number\n}\n\nexport interface MemoryPruneBeforeOutput {\n /** true → 否决本轮裁剪(引擎据此对 process 传 skipPrune)。 */\n cancelled: boolean\n}\n\nexport interface HookPayloadMap {\n 'chat.message.before': { input: ChatMessageInput; output: ChatMessageOutput }\n 'chat.message.after': { input: ChatMessageInput; output: ChatMessageOutput }\n 'tool.execute.before': { input: ToolExecuteBeforeInput; output: ToolExecuteBeforeOutput }\n 'tool.execute.after': { input: ToolExecuteAfterInput; output: ToolExecuteAfterOutput }\n 'messages.transform': { input: MessagesTransformInput; output: MessagesTransformOutput }\n 'chat.params': { input: ChatParamsInput; output: ChatParamsOutput }\n 'session.created': { input: SessionEventInput; output: void }\n 'session.restored': { input: SessionEventInput; output: void }\n 'session.deleted': { input: SessionEventInput; output: void }\n 'session.idle': { input: SessionEventInput; output: void }\n /**\n * 会话错误(observer)。\n *\n * **`error` 是 `string` 而非 `Error`**(RFC-362 review 修正):`HookRegistry.emit()` 会对本\n * timing 做结构式 sanitize(`sanitizeEmitInput`,取 `error.message`),防止任何消费方读到\n * 含栈追踪/敏感路径的原始 Error 对象。**handler 侧实际收到的永远是字符串**。\n *\n * 此前本处声明为 `Error`,与运行时真实形状不符——消费方(如 `module-wiring.ts` 的 monitor\n * 投影)被迫写 `input.error as unknown as string` 双重断言绕过。类型说谎会让断言像\"必要的\n * 技巧\"而非\"契约错了\"的信号,故改为如实声明。\n *\n * 发射方(`pipeline.ts`)传入 `Error` 仍然成立——见 `HookEmitInput`:emit 的入参类型对本\n * timing 放宽为 `Error | string`,sanitize 后收敛为 `string` 交给 handler。\n */\n 'session.error': { input: SessionEventInput & { error: string }; output: void }\n 'stream.start': { input: { sessionId: string; model: string }; output: void }\n 'stream.end': {\n input: {\n sessionId: string\n model: string\n stopReason: string\n /**\n * RFC-129 D6:本次 done 事件的 token 用量(可选——向后兼容,既有消费方不读取新字段则\n * 行为不变)。来源 `event.message.usage`(即时数据),非会话级累积状态。\n */\n tokenUsage?: { input: number; output: number }\n }\n output: void\n }\n 'compaction.before': { input: { sessionId: string; messageCount: number }; output: void }\n 'compaction.after': { input: { sessionId: string; retainedCount: number }; output: void }\n 'memory.prune.before': { input: MemoryPruneBeforeInput; output: MemoryPruneBeforeOutput }\n 'process.spawned': {\n input: { sessionId: string; processId: string; pid: number; command: string; port?: number }\n output: void\n }\n 'process.exited': {\n input: {\n sessionId: string\n processId: string\n pid: number\n command: string\n status: string\n exitCode?: number\n }\n output: void\n }\n 'task.created': { input: { task: TaskHookInfo }; output: void }\n 'task.started': { input: { task: TaskHookInfo; agent: string }; output: void }\n 'task.completed': {\n input: {\n task: TaskHookInfo\n result: TaskHookOutput\n subagentResult?: TaskHookOutput\n }\n output: void\n }\n 'task.failed': {\n input: { task: TaskHookInfo; error: TaskHookError }\n output: void\n }\n 'task.cancelled': { input: { taskId: string }; output: void }\n 'system.prompt.transform': {\n input: SystemPromptTransformInput\n output: SystemPromptTransformOutput\n }\n notification: { input: NotificationHookInput; output: void }\n}\n\n/**\n * task.* hook 的 **hook-owned** payload 契约。\n *\n * Task/TaskResult/TaskError 定义在 orchestrator 领域包(依赖 hook-contracts),反向 import 成环;\n * 故 hook 层拥有自己暴露的 payload 形状(生产者 orchestrator 的 Task 是其结构超集,emit 时直接赋值,\n * spread 的额外字段经 TS 豁免)。取代原 `Record<string, unknown>` + orchestrator 侧 `as unknown as` 下降。\n */\nexport interface TaskHookError {\n code: string\n message: string\n retriable: boolean\n}\nexport interface TaskHookOutput {\n text: string\n summary?: string\n tokenUsage?: { input: number; output: number; cacheRead: number }\n durationMs?: number\n}\n/**\n * Task 生命周期状态(hook 契约层判别联合)。\n * emit 点已核实:orchestrator 侧只 emit 这 5 个值,无超集(grep packages/orchestrator/src 确认)。\n */\nexport type TaskHookStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'\n\nexport interface TaskHookInfo {\n id: string\n parentId?: string\n status: TaskHookStatus\n sessionId?: string\n attempts: number\n maxAttempts: number\n createdAt: number\n completedAt?: number\n output?: TaskHookOutput\n error?: TaskHookError\n /**\n * Swarm 编排事件上下文(RFC-107 D1 / M-N6)。\n *\n * **死字段标注(RFC-398 M6)**:swarmEvent 桥接已被 RFC-398 M6 删除(全仓零消费方,\n * 编排事件塞进 task.started 是语义错位)。本字段保留类型(契约层不删导出),但运行时\n * 不再填充——orchestrator/swarm/swarm.ts:75 注释\"删 swarmEvent 死桥接\"。\n * 下游 hook 不应依赖此字段有值。\n */\n swarmEvent?: SwarmEventPayload\n}\n\n/**\n * Swarm 编排事件载荷(hook-contracts 拥有最小形状;实际数据由 orchestrator/swarm 填充)。\n * 不新建 swarm.* HookTiming 家族——经既有 task.*(如 task.started)携带。\n *\n * **RFC-415 D3**:从 `type: string` + `[key: string]: unknown` 收窄为判别联合——\n * 每个 type 对应自己的附加载荷形状,消费方按 type narrow 取字段(不再 cast)。\n *\n * **死字段标注(RFC-398 M6)**:TaskHookInfo.swarmEvent 运行时不再填充\n * (RFC-398 M6 删桥接),本类型保留为契约层导出供未来重新接线使用。\n */\nexport type SwarmEventPayload =\n | { type: 'swarm.start'; agentId?: string; totalAgents?: number }\n | { type: 'swarm.end'; agentId?: string; durationMs?: number }\n | { type: 'agent.start'; agentId: string }\n | { type: 'agent.end'; agentId: string; durationMs?: number }\n | { type: 'handoff'; fromAgent: string; toAgent: string; reason?: string }\n | { type: 'routing.decision'; decision: string; agentId?: string }\n | { type: 'parallel.fanOut'; parentAgent: string; childAgents: string[] }\n | { type: 'parallel.fanIn'; parentAgent: string; childAgents: string[]; results?: unknown[] }\n | { type: 'pipeline.step'; step: number; totalSteps: number; agentId?: string }\n | { type: 'hierarchy.delegate'; parentId: string; childId: string }\n | { type: 'error'; error: string; agentId?: string }\n\n/** Swarm 事件类型字面量联合(从 SwarmEventPayload 派生,供消费方 narrow)。 */\nexport type SwarmEventType = SwarmEventPayload['type']\n\n/** 通知 hook 出站 payload(producer=HookChannel;consumer=.claude 桥/用户 hook)。 */\nexport interface NotificationHookInput {\n sessionId: string\n message: string\n title?: string\n /** 归一类别:turn_complete / error / approval_required / input_required(matcher 据此过滤)。 */\n notification_type: string\n}\n\nexport type HookInput<T extends HookTiming> = HookPayloadMap[T]['input']\n\n/**\n * emit 侧入参类型(RFC-362 review 修正)——与 `HookInput`(handler 侧收到的类型)的区别只在\n * `session.error`:发射方持有原始 `Error`,registry 在 `sanitizeEmitInput` 里取 `.message`\n * 收敛为 `string` 后才交给 handler。\n *\n * 为什么要分成两个类型而不是让两侧都用 `Error | string`:handler 侧若也是联合类型,每个消费方\n * 都得重新 narrow 一次(`typeof e === 'string' ? e : e.message`),而这个分支在运行时**永远\n * 走不到第二条**——那正是\"用 type guard 弥补类型设计不足\"。分开声明后,两侧各自拿到确定的类型,\n * sanitize 这个转换点在类型上也变得显式可见。\n */\nexport type HookEmitInput<T extends HookTiming> = T extends 'session.error'\n ? SessionEventInput & { error: Error | string }\n : HookPayloadMap[T]['input']\nexport type HookOutput<T extends HookTiming> = HookPayloadMap[T]['output']\n\nexport type ObserverTiming = {\n [K in HookTiming]: HookPayloadMap[K]['output'] extends void ? K : never\n}[HookTiming]\n\nexport type InterceptorTiming = {\n [K in HookTiming]: HookPayloadMap[K]['output'] extends void ? never : K\n}[HookTiming]\n\n/**\n * RFC-327 修订 D1(M1):interceptor handle 的 waterfall 中止哨兵——**返回值形态**而非\n * output 字段(output 是共享可变对象,放 output 会被后续 hook 覆盖,哨兵更安全)。\n *\n * 语义(serial-with-early-bail):任一 interceptor hook 返回 `{ abort: true }` →\n * 终止当前 timing 的 hook 链,output 保留已累积值,后续 hook 不再执行。与 sticky-veto\n * 的交互矩阵(RFC 定稿 §3 D1):abort 优先(终止链),abort **不清** sticky——\n * abort 前已钉住的 cancelled/decision 值保留。空对象 `{}` / `{ abort: false }` 等价于\n * void(不中断)。\n */\nexport interface HookAbortSignal {\n abort?: boolean\n}\n\nexport type HookHandle<T extends HookTiming> = T extends ObserverTiming\n ? (input: HookInput<T>) => void | Promise<void>\n : (\n input: HookInput<T>,\n output: HookOutput<T>,\n ) => void | HookAbortSignal | Promise<void | HookAbortSignal>\n\n/**\n * RFC-327 修订 D1(M1):waterfall 白名单 timing——插件经受控贡献点改写主循环中间产物的\n * 全部允许 timing。**编译期**从 `HookPayloadMap` 派生(Pick 白名单),新增 timing 必须\n * 显式加入下方 `WATERFALL_TIMINGS` 数组(同字面量联合,二者漂移即编译错误);运行时校验\n * (`isWaterfallTiming`)只作兜底——防 JS 插件/类型不安全条目在装载期注入白名单外 timing。\n *\n * 三个 timing 的 output 均无 `cancelled`/`decision` 字段(与 `STICKY_CANCELLED_TIMINGS`\n * 现状一致)——waterfall 的 abort 走返回值哨兵(`HookAbortSignal`),**不**进入 sticky\n * 白名单(不盲探测,见 `hook-registry.ts` STICKY 常量注释)。\n */\nexport type WaterfallTiming = Extract<\n keyof HookPayloadMap,\n 'system.prompt.transform' | 'chat.params' | 'messages.transform'\n>\n\n/** 运行时白名单(与 `WaterfallTiming` 同字面量,漂移即编译错误——`as const` 数组反哺联合)。 */\nexport const WATERFALL_TIMINGS: readonly WaterfallTiming[] = [\n 'system.prompt.transform',\n 'chat.params',\n 'messages.transform',\n]\n\n/** 运行时校验兜底(装载期/测试用;类型安全代码经 `WaterfallTiming` 编译期已保证)。 */\nexport function isWaterfallTiming(timing: string): timing is WaterfallTiming {\n return (WATERFALL_TIMINGS as readonly string[]).includes(timing)\n}\n","/**\n * 权限**配置形状**单一真源(RFC-077 mirror-debt 收口,HK-1)。\n *\n * 背景:权限配置形状(mode 词表 + policy/rule 的 config 结构)历史上双份定义——\n * `@x-otto/setting` 的 zod schema(z.infer)与 `@x-otto/hooks` 引擎的手写 interface。二者层序不可互依\n * (hooks L2 < setting L3,hooks 不能上依赖 setting),故各写一套、无 drift guard。\n *\n * 收口:把配置形状沉到二者都能**下依赖**的零依赖叶 `@x-otto/hook-contracts`(L1):\n * - `@x-otto/hooks` 引擎 import 这些类型(删手写镜像)。\n * - `@x-otto/setting` 的 zod schema `satisfies z.ZodType<…>` 钉死到此(drift→编译报错),并 re-export。\n *\n * 这里只放**配置/wire 形状**(作者在 config.json 写的东西);运行时引擎类型\n * (PermissionPolicy/PermissionContext/PermissionDecision/PolicyScope 等,含 RegExp/函数/时间戳)\n * 仍属引擎、留 `@x-otto/hooks`。\n */\n\n/** 权限模式词表(config.json `permission_mode` + 运行时模式)。 */\nexport const PERMISSION_MODES = ['bypass', 'auto', 'confirm', 'strict', 'readonly'] as const\nexport type PermissionMode = (typeof PERMISSION_MODES)[number]\n\n/**\n * 规则效果(配置层词表)。\n *\n * 与 `timings.ts` 的 `PermissionDecision`(契约层)字面量相同但分属不同层——\n * 本类型是 config.json 写的效果值(消费方 = setting zod + PermissionRuleConfig),\n * `PermissionDecision` 是 hook handler 返回的词表(消费方 = ToolExecuteBeforeOutput.decision)。\n * guard 运行时另有同名结构体 `PermissionDecision`(guard/src/permission/types.ts)。\n * 三层同名不同构,不合并(→ timings.ts PermissionDecision 注释)。\n */\nexport type RuleEffect = 'allow' | 'deny' | 'ask'\n\n/** 单条权限规则的**配置**形状(config.json)。运行时 `PermissionRule`(含编译后 RegExp)属引擎。 */\nexport interface PermissionRuleConfig {\n name: string\n effect: RuleEffect\n tools?: string[]\n paths?: string[]\n /**\n * shell 命令内容正则(对 bash 类工具的 `args.command` 与 MCP 工具的字符串参数生效)。\n *\n * 补齐配置化规则此前只能按 tools/paths 匹配的缺口——「禁止某个命令」是团队规约的常见\n * 诉求(如本仓 AGENTS.md 的 `git stash` 红线),此前只能硬编码进 builtin 策略(把项目\n * 规约塞进通用引擎,架构上错位)。有了本字段,项目规约走项目配置,引擎只提供机制。\n *\n * 匹配语义与 builtin 命令类策略一致:经 `extractShellCommands` 拆分复合命令(`&&`/`;`/\n * 管道)后逐段匹配,任一段命中即触发——防 `foo && git stash` 这类绕过。\n */\n commands?: string[]\n deny_reason?: string\n ask_prompt?: string\n}\n\n/** 单个权限策略的**配置**形状(config.json)。运行时 `PermissionPolicy`(含 safety/priority 语义)属引擎。 */\nexport interface PermissionPolicySetting {\n name: string\n priority?: number\n enabled?: boolean\n scope?: {\n agents?: string[]\n sessions?: string[]\n }\n rules: PermissionRuleConfig[]\n /**\n * 配置依赖的 policy-schema 版本(2026-08-15 全 agent 锁死事故教训固化)。\n *\n * 背景:`commands` 维度引入后,旧 dist 的 compilePolicyFromSetting 不认识该字段会静默\n * 丢弃,产出 {tools:∅, paths:∅, condition:∅} 的 deny 规则 → matchesRule 匹配一切 →\n * 锁死全部工具(bash/read/write/grep 全瘫)。空匹配守卫(48a01a379)能把这类规则\n * fail-closed 跳过,但**无版本戳时排障仍靠猜**——规则被跳过是\"配置写错\"还是\"dist 太旧\"\n * 无法区分。\n *\n * 语义:声明本配置依赖的最低 schema 版本。compilePolicyFromSetting 读取\n * POLICY_SCHEMA_VERSION 常量对比——配置声明的版本 > 编译方支持的版本时,显式报错\n * (warn + 跳过整条策略),并把版本差异写进日志。用户/运维据此一眼判断\"该升级 dist\n * 了\",而非对着静默跳过的规则排查。\n *\n * 向后兼容:缺省 = 0(不声明),编译方不校验——旧配置不受影响,漂移防护只对显式\n * 声明版本的新配置生效。\n */\n schemaVersion?: number\n}\n"],"mappings":"uEA+ZA,MAAa,EAAgD,CAC3D,0BACA,cACA,qBACD,CAGD,SAAgB,EAAkB,EAA2C,CAC3E,OAAQ,EAAwC,SAAS,EAAO,CCtZlE,MAAa,EAAmB,CAAC,SAAU,OAAQ,UAAW,SAAU,WAAW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-otto/hook-contracts",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.1.0-alpha.10",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -19,7 +19,7 @@
19
19
  "tag": "alpha"
20
20
  },
21
21
  "dependencies": {
22
- "@x-otto/interchange": "0.1.0-alpha.3"
22
+ "@x-otto/interchange": "0.1.0-alpha.10"
23
23
  },
24
24
  "private": false,
25
25
  "scripts": {