zora-agent 0.10.0 → 0.10.2

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 (166) hide show
  1. package/README.md +171 -65
  2. package/dist/cli/daemon.js +1 -0
  3. package/dist/cli/daemon.js.map +1 -1
  4. package/dist/cli/index.js +27 -0
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/secret-commands.d.ts +16 -0
  7. package/dist/cli/secret-commands.d.ts.map +1 -0
  8. package/dist/cli/secret-commands.js +87 -0
  9. package/dist/cli/secret-commands.js.map +1 -0
  10. package/dist/cli/skill-commands.d.ts.map +1 -1
  11. package/dist/cli/skill-commands.js +75 -0
  12. package/dist/cli/skill-commands.js.map +1 -1
  13. package/dist/cli/subagent-commands.d.ts +13 -0
  14. package/dist/cli/subagent-commands.d.ts.map +1 -0
  15. package/dist/cli/subagent-commands.js +80 -0
  16. package/dist/cli/subagent-commands.js.map +1 -0
  17. package/dist/config/defaults.d.ts +6 -0
  18. package/dist/config/defaults.d.ts.map +1 -1
  19. package/dist/config/defaults.js +6 -0
  20. package/dist/config/defaults.js.map +1 -1
  21. package/dist/dashboard/cost-tracker.d.ts +40 -0
  22. package/dist/dashboard/cost-tracker.d.ts.map +1 -0
  23. package/dist/dashboard/cost-tracker.js +63 -0
  24. package/dist/dashboard/cost-tracker.js.map +1 -0
  25. package/dist/dashboard/frontend/dist/assets/{index-DSXaCp9r.js → index-Bi0V-1ti.js} +83 -83
  26. package/dist/dashboard/frontend/dist/assets/index-SQqtXVeO.css +1 -0
  27. package/dist/dashboard/frontend/dist/index.html +2 -2
  28. package/dist/dashboard/server.d.ts +5 -0
  29. package/dist/dashboard/server.d.ts.map +1 -1
  30. package/dist/dashboard/server.js +17 -0
  31. package/dist/dashboard/server.js.map +1 -1
  32. package/dist/hooks/built-in/audit-log.d.ts +13 -0
  33. package/dist/hooks/built-in/audit-log.d.ts.map +1 -0
  34. package/dist/hooks/built-in/audit-log.js +48 -0
  35. package/dist/hooks/built-in/audit-log.js.map +1 -0
  36. package/dist/hooks/built-in/rate-limit.d.ts +18 -0
  37. package/dist/hooks/built-in/rate-limit.d.ts.map +1 -0
  38. package/dist/hooks/built-in/rate-limit.js +30 -0
  39. package/dist/hooks/built-in/rate-limit.js.map +1 -0
  40. package/dist/hooks/built-in/secret-redact.d.ts +7 -0
  41. package/dist/hooks/built-in/secret-redact.d.ts.map +1 -0
  42. package/dist/hooks/built-in/secret-redact.js +33 -0
  43. package/dist/hooks/built-in/secret-redact.js.map +1 -0
  44. package/dist/hooks/built-in/shell-safety.d.ts +7 -0
  45. package/dist/hooks/built-in/shell-safety.d.ts.map +1 -0
  46. package/dist/hooks/built-in/shell-safety.js +34 -0
  47. package/dist/hooks/built-in/shell-safety.js.map +1 -0
  48. package/dist/hooks/index.d.ts +5 -0
  49. package/dist/hooks/index.d.ts.map +1 -1
  50. package/dist/hooks/index.js +5 -0
  51. package/dist/hooks/index.js.map +1 -1
  52. package/dist/hooks/tool-hook-runner.d.ts +36 -0
  53. package/dist/hooks/tool-hook-runner.d.ts.map +1 -0
  54. package/dist/hooks/tool-hook-runner.js +49 -0
  55. package/dist/hooks/tool-hook-runner.js.map +1 -0
  56. package/dist/lib/error-normalizer.d.ts +53 -0
  57. package/dist/lib/error-normalizer.d.ts.map +1 -0
  58. package/dist/lib/error-normalizer.js +128 -0
  59. package/dist/lib/error-normalizer.js.map +1 -0
  60. package/dist/memory/context-compressor.d.ts +3 -1
  61. package/dist/memory/context-compressor.d.ts.map +1 -1
  62. package/dist/memory/context-compressor.js +18 -3
  63. package/dist/memory/context-compressor.js.map +1 -1
  64. package/dist/memory/plan-cache.d.ts +27 -0
  65. package/dist/memory/plan-cache.d.ts.map +1 -0
  66. package/dist/memory/plan-cache.js +91 -0
  67. package/dist/memory/plan-cache.js.map +1 -0
  68. package/dist/orchestrator/code-tool-runner.d.ts +41 -0
  69. package/dist/orchestrator/code-tool-runner.d.ts.map +1 -0
  70. package/dist/orchestrator/code-tool-runner.js +375 -0
  71. package/dist/orchestrator/code-tool-runner.js.map +1 -0
  72. package/dist/orchestrator/error-pattern-detector.d.ts +54 -0
  73. package/dist/orchestrator/error-pattern-detector.d.ts.map +1 -0
  74. package/dist/orchestrator/error-pattern-detector.js +87 -0
  75. package/dist/orchestrator/error-pattern-detector.js.map +1 -0
  76. package/dist/orchestrator/execution-planner.d.ts +33 -0
  77. package/dist/orchestrator/execution-planner.d.ts.map +1 -0
  78. package/dist/orchestrator/execution-planner.js +67 -0
  79. package/dist/orchestrator/execution-planner.js.map +1 -0
  80. package/dist/orchestrator/orchestrator.d.ts +77 -0
  81. package/dist/orchestrator/orchestrator.d.ts.map +1 -1
  82. package/dist/orchestrator/orchestrator.js +595 -29
  83. package/dist/orchestrator/orchestrator.js.map +1 -1
  84. package/dist/orchestrator/retry-queue.d.ts +7 -1
  85. package/dist/orchestrator/retry-queue.d.ts.map +1 -1
  86. package/dist/orchestrator/retry-queue.js +10 -4
  87. package/dist/orchestrator/retry-queue.js.map +1 -1
  88. package/dist/orchestrator/step-classifier.d.ts +26 -0
  89. package/dist/orchestrator/step-classifier.d.ts.map +1 -0
  90. package/dist/orchestrator/step-classifier.js +77 -0
  91. package/dist/orchestrator/step-classifier.js.map +1 -0
  92. package/dist/orchestrator/tlci-dispatcher.d.ts +47 -0
  93. package/dist/orchestrator/tlci-dispatcher.d.ts.map +1 -0
  94. package/dist/orchestrator/tlci-dispatcher.js +116 -0
  95. package/dist/orchestrator/tlci-dispatcher.js.map +1 -0
  96. package/dist/routines/heartbeat.d.ts.map +1 -1
  97. package/dist/routines/heartbeat.js +3 -1
  98. package/dist/routines/heartbeat.js.map +1 -1
  99. package/dist/routines/routine-manager.d.ts.map +1 -1
  100. package/dist/routines/routine-manager.js +3 -1
  101. package/dist/routines/routine-manager.js.map +1 -1
  102. package/dist/security/intent-capsule.d.ts +19 -0
  103. package/dist/security/intent-capsule.d.ts.map +1 -1
  104. package/dist/security/intent-capsule.js +84 -1
  105. package/dist/security/intent-capsule.js.map +1 -1
  106. package/dist/security/policy-engine.d.ts +1 -0
  107. package/dist/security/policy-engine.d.ts.map +1 -1
  108. package/dist/security/policy-engine.js +22 -1
  109. package/dist/security/policy-engine.js.map +1 -1
  110. package/dist/services/negative-cache.d.ts +67 -0
  111. package/dist/services/negative-cache.d.ts.map +1 -0
  112. package/dist/services/negative-cache.js +164 -0
  113. package/dist/services/negative-cache.js.map +1 -0
  114. package/dist/skills/skill-auditor.d.ts +36 -0
  115. package/dist/skills/skill-auditor.d.ts.map +1 -0
  116. package/dist/skills/skill-auditor.js +89 -0
  117. package/dist/skills/skill-auditor.js.map +1 -0
  118. package/dist/skills/skill-installer.d.ts +41 -0
  119. package/dist/skills/skill-installer.d.ts.map +1 -0
  120. package/dist/skills/skill-installer.js +141 -0
  121. package/dist/skills/skill-installer.js.map +1 -0
  122. package/dist/skills/skill-scanner.d.ts +30 -0
  123. package/dist/skills/skill-scanner.d.ts.map +1 -0
  124. package/dist/skills/skill-scanner.js +249 -0
  125. package/dist/skills/skill-scanner.js.map +1 -0
  126. package/dist/tools/index.d.ts +2 -0
  127. package/dist/tools/index.d.ts.map +1 -1
  128. package/dist/tools/index.js +2 -0
  129. package/dist/tools/index.js.map +1 -1
  130. package/dist/tools/planning-tool.d.ts +95 -0
  131. package/dist/tools/planning-tool.d.ts.map +1 -0
  132. package/dist/tools/planning-tool.js +117 -0
  133. package/dist/tools/planning-tool.js.map +1 -0
  134. package/dist/tools/skill-tool.d.ts +94 -0
  135. package/dist/tools/skill-tool.d.ts.map +1 -0
  136. package/dist/tools/skill-tool.js +202 -0
  137. package/dist/tools/skill-tool.js.map +1 -0
  138. package/dist/tools/subagent-tool.d.ts +11 -0
  139. package/dist/tools/subagent-tool.d.ts.map +1 -0
  140. package/dist/tools/subagent-tool.js +87 -0
  141. package/dist/tools/subagent-tool.js.map +1 -0
  142. package/dist/types.d.ts +22 -0
  143. package/dist/types.d.ts.map +1 -1
  144. package/dist/utils/args.d.ts +5 -0
  145. package/dist/utils/args.d.ts.map +1 -0
  146. package/dist/utils/args.js +20 -0
  147. package/dist/utils/args.js.map +1 -0
  148. package/package.json +4 -1
  149. package/dist/dashboard/frontend/dist/assets/index-2FaDr6iS.js +0 -277
  150. package/dist/dashboard/frontend/dist/assets/index-B9-KXW14.css +0 -1
  151. package/dist/dashboard/frontend/dist/assets/index-BMxbyTer.css +0 -1
  152. package/dist/dashboard/frontend/dist/assets/index-BXUfB9iR.js +0 -253
  153. package/dist/dashboard/frontend/dist/assets/index-BcOGj1EF.css +0 -1
  154. package/dist/dashboard/frontend/dist/assets/index-BtiFO9YN.js +0 -261
  155. package/dist/dashboard/frontend/dist/assets/index-CQmpMTLW.js +0 -253
  156. package/dist/dashboard/frontend/dist/assets/index-Cfjy5acU.css +0 -1
  157. package/dist/dashboard/frontend/dist/assets/index-D41hcjgc.js +0 -253
  158. package/dist/dashboard/frontend/dist/assets/index-D83BawFd.css +0 -1
  159. package/dist/dashboard/frontend/dist/assets/index-DAODjoxu.css +0 -1
  160. package/dist/dashboard/frontend/dist/assets/index-DB-Eu5oV.js +0 -253
  161. package/dist/dashboard/frontend/dist/assets/index-W0VVEDu6.js +0 -253
  162. package/dist/dashboard/frontend/dist/assets/index-aK9PWl6w.js +0 -253
  163. package/dist/dashboard/frontend/vite.config.d.ts +0 -3
  164. package/dist/dashboard/frontend/vite.config.d.ts.map +0 -1
  165. package/dist/dashboard/frontend/vite.config.js +0 -11
  166. package/dist/dashboard/frontend/vite.config.js.map +0 -1
@@ -0,0 +1,95 @@
1
+ /**
2
+ * PlanningTool — Exposes TLCI's buildExecutionPlan as a callable LLM tool.
3
+ *
4
+ * The LLM can call plan_workflow to decompose a multi-step task into TLCI tiers,
5
+ * see the cost estimate, and optionally execute it. Makes TLCI self-driving.
6
+ *
7
+ * Usage by the LLM:
8
+ * plan_workflow({ steps: [{id:"1", description:"fetch user data from API"},...] })
9
+ * → returns plan summary + estimated cost
10
+ * plan_workflow({ steps: [...], execute: true })
11
+ * → returns plan + executes it via submitWorkflow
12
+ */
13
+ import type { DispatchResult } from '../orchestrator/tlci-dispatcher.js';
14
+ import type { WorkflowStep } from '../orchestrator/step-classifier.js';
15
+ import type { CustomToolDefinition } from '../orchestrator/execution-loop.js';
16
+ export declare const PLAN_WORKFLOW_TOOL_NAME = "plan_workflow";
17
+ export declare const PLAN_WORKFLOW_TOOL_DEFINITION: {
18
+ name: string;
19
+ description: string;
20
+ input_schema: {
21
+ type: "object";
22
+ properties: {
23
+ steps: {
24
+ type: string;
25
+ description: string;
26
+ items: {
27
+ type: string;
28
+ properties: {
29
+ id: {
30
+ type: string;
31
+ description: string;
32
+ };
33
+ description: {
34
+ type: string;
35
+ description: string;
36
+ };
37
+ inputType: {
38
+ type: string;
39
+ description: string;
40
+ };
41
+ outputType: {
42
+ type: string;
43
+ description: string;
44
+ };
45
+ };
46
+ required: string[];
47
+ };
48
+ minItems: number;
49
+ };
50
+ execute: {
51
+ type: string;
52
+ description: string;
53
+ default: boolean;
54
+ };
55
+ budgetLimitUSD: {
56
+ type: string;
57
+ description: string;
58
+ };
59
+ };
60
+ required: string[];
61
+ };
62
+ };
63
+ export interface PlanWorkflowArgs {
64
+ steps: WorkflowStep[];
65
+ execute?: boolean;
66
+ budgetLimitUSD?: number;
67
+ }
68
+ export interface PlanWorkflowResult {
69
+ planId: string;
70
+ planHash: string;
71
+ summary: string;
72
+ approvalView: string;
73
+ tierBreakdown: {
74
+ code: number;
75
+ slm: number;
76
+ frontier: number;
77
+ };
78
+ estimatedCostUSD: number;
79
+ savingsPct: number;
80
+ executed: boolean;
81
+ dispatchResult?: unknown;
82
+ }
83
+ export type SubmitWorkflowFn = (steps: WorkflowStep[], opts?: {
84
+ budgetLimitUSD?: number;
85
+ }) => Promise<DispatchResult>;
86
+ export declare function handlePlanWorkflow(args: PlanWorkflowArgs, submitWorkflow: SubmitWorkflowFn): Promise<PlanWorkflowResult>;
87
+ /**
88
+ * Create a plan_workflow CustomToolDefinition bound to the given submitWorkflow function.
89
+ * Pass this into ExecutionLoop's customTools array (via _createCustomTools).
90
+ *
91
+ * If submitWorkflow is not provided (plan-only mode), execution requests will
92
+ * throw a clear error instead of silently failing.
93
+ */
94
+ export declare function createPlanWorkflowTool(submitWorkflow?: SubmitWorkflowFn): CustomToolDefinition;
95
+ //# sourceMappingURL=planning-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planning-tool.d.ts","sourceRoot":"","sources":["../../src/tools/planning-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAO9E,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAIvD,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCzC,CAAC;AAIF,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAID,MAAM,MAAM,gBAAgB,GAAG,CAC7B,KAAK,EAAE,YAAY,EAAE,EACrB,IAAI,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,KAC/B,OAAO,CAAC,cAAc,CAAC,CAAC;AAI7B,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,gBAAgB,EACtB,cAAc,EAAE,gBAAgB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAwC7B;AAID;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,CAAC,EAAE,gBAAgB,GAChC,oBAAoB,CAgBtB"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * PlanningTool — Exposes TLCI's buildExecutionPlan as a callable LLM tool.
3
+ *
4
+ * The LLM can call plan_workflow to decompose a multi-step task into TLCI tiers,
5
+ * see the cost estimate, and optionally execute it. Makes TLCI self-driving.
6
+ *
7
+ * Usage by the LLM:
8
+ * plan_workflow({ steps: [{id:"1", description:"fetch user data from API"},...] })
9
+ * → returns plan summary + estimated cost
10
+ * plan_workflow({ steps: [...], execute: true })
11
+ * → returns plan + executes it via submitWorkflow
12
+ */
13
+ import { buildExecutionPlan, formatPlanSummary, formatPlanForApproval } from '../orchestrator/execution-planner.js';
14
+ import { createLogger } from '../utils/logger.js';
15
+ const log = createLogger('planning-tool');
16
+ // ─── Tool Name ────────────────────────────────────────────────────────────────
17
+ export const PLAN_WORKFLOW_TOOL_NAME = 'plan_workflow';
18
+ // ─── Tool Definition (JSON Schema for the LLM) ────────────────────────────────
19
+ export const PLAN_WORKFLOW_TOOL_DEFINITION = {
20
+ name: PLAN_WORKFLOW_TOOL_NAME,
21
+ description: [
22
+ 'Decompose the current task into discrete workflow steps for cost-efficient execution.',
23
+ 'Use when the task involves multiple operations (fetch → transform → classify → summarize → send).',
24
+ 'Returns an execution plan showing which steps run as code tools (free), local SLM ($0.0001/step),',
25
+ 'or frontier LLM ($0.003/step), with total estimated cost vs running everything through a frontier LLM.',
26
+ ].join(' '),
27
+ input_schema: {
28
+ type: 'object',
29
+ properties: {
30
+ steps: {
31
+ type: 'array',
32
+ description: 'Ordered workflow steps. Earlier steps may feed context to later ones.',
33
+ items: {
34
+ type: 'object',
35
+ properties: {
36
+ id: { type: 'string', description: 'Unique step identifier (e.g. "1", "fetch")' },
37
+ description: { type: 'string', description: 'Natural language description of this step' },
38
+ inputType: { type: 'string', description: 'Optional: url | json | text | fileList' },
39
+ outputType: { type: 'string', description: 'Optional: json | text | boolean | void' },
40
+ },
41
+ required: ['id', 'description'],
42
+ },
43
+ minItems: 1,
44
+ },
45
+ execute: {
46
+ type: 'boolean',
47
+ description: 'If true, execute the plan immediately. If false (default), return plan for review.',
48
+ default: false,
49
+ },
50
+ budgetLimitUSD: {
51
+ type: 'number',
52
+ description: 'Optional: abort if estimated cost exceeds this amount.',
53
+ },
54
+ },
55
+ required: ['steps'],
56
+ },
57
+ };
58
+ // ─── Handler ──────────────────────────────────────────────────────────────────
59
+ export async function handlePlanWorkflow(args, submitWorkflow) {
60
+ const { steps, execute = false, budgetLimitUSD } = args;
61
+ log.info({ steps: steps.length, execute, budgetLimitUSD }, 'plan_workflow called');
62
+ // Always build plan first to show cost/tier breakdown
63
+ const plan = buildExecutionPlan(steps);
64
+ const summary = formatPlanSummary(plan);
65
+ const approvalView = formatPlanForApproval(plan);
66
+ if (!execute) {
67
+ return {
68
+ planId: plan.planId,
69
+ planHash: plan.planHash,
70
+ summary,
71
+ approvalView,
72
+ tierBreakdown: plan.tierBreakdown,
73
+ estimatedCostUSD: plan.costComparison.tlciEstimate,
74
+ savingsPct: plan.costComparison.savingsPct,
75
+ executed: false,
76
+ };
77
+ }
78
+ // Execute via orchestrator's submitWorkflow.
79
+ // The dispatcher uses the plan cache, so the same steps will reuse the preview plan's
80
+ // hash. Use the DispatchResult's planId/planHash as the authoritative IDs to avoid
81
+ // exposing a preview planId that differs from the executed plan's ID.
82
+ const dispatchResult = await submitWorkflow(steps, { budgetLimitUSD });
83
+ return {
84
+ planId: dispatchResult.planId,
85
+ planHash: dispatchResult.planHash,
86
+ summary,
87
+ approvalView,
88
+ tierBreakdown: dispatchResult.tierBreakdown,
89
+ estimatedCostUSD: plan.costComparison.tlciEstimate,
90
+ savingsPct: plan.costComparison.savingsPct,
91
+ executed: true,
92
+ dispatchResult,
93
+ };
94
+ }
95
+ // ─── Factory: build a CustomToolDefinition wired to a submitWorkflow callback ─
96
+ /**
97
+ * Create a plan_workflow CustomToolDefinition bound to the given submitWorkflow function.
98
+ * Pass this into ExecutionLoop's customTools array (via _createCustomTools).
99
+ *
100
+ * If submitWorkflow is not provided (plan-only mode), execution requests will
101
+ * throw a clear error instead of silently failing.
102
+ */
103
+ export function createPlanWorkflowTool(submitWorkflow) {
104
+ const noopOrReal = submitWorkflow ?? (async (_steps, _opts) => {
105
+ throw new Error('plan_workflow: submitWorkflow not available — boot the orchestrator first or set execute:false');
106
+ });
107
+ return {
108
+ name: PLAN_WORKFLOW_TOOL_DEFINITION.name,
109
+ description: PLAN_WORKFLOW_TOOL_DEFINITION.description,
110
+ input_schema: PLAN_WORKFLOW_TOOL_DEFINITION.input_schema,
111
+ handler: async (input) => {
112
+ const args = input;
113
+ return handlePlanWorkflow(args, noopOrReal);
114
+ },
115
+ };
116
+ }
117
+ //# sourceMappingURL=planning-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planning-tool.js","sourceRoot":"","sources":["../../src/tools/planning-tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * SkillTool — Exposes the Claude Code skill library to running Zora agents.
3
+ *
4
+ * list_skills: discover available skills in ~/.claude/skills/
5
+ * invoke_skill: load and return a skill's content for injection into context
6
+ *
7
+ * Security: invoke_skill checks PolicyEngine.validatePath before loading any
8
+ * skill content. Skills must exist on disk — no remote loading.
9
+ *
10
+ * Usage: call createSkillTools(policyEngine) and spread the result into
11
+ * _createCustomTools() in the Orchestrator.
12
+ */
13
+ import type { CustomToolDefinition } from '../orchestrator/execution-loop.js';
14
+ import type { PolicyEngine } from '../security/policy-engine.js';
15
+ export declare const LIST_SKILLS_TOOL_NAME = "list_skills";
16
+ export declare const INVOKE_SKILL_TOOL_NAME = "invoke_skill";
17
+ export declare const LIST_SKILLS_TOOL_DEFINITION: {
18
+ name: string;
19
+ description: string;
20
+ input_schema: {
21
+ type: "object";
22
+ properties: {
23
+ filter: {
24
+ type: string;
25
+ description: string;
26
+ };
27
+ };
28
+ required: string[];
29
+ };
30
+ };
31
+ export declare const INVOKE_SKILL_TOOL_DEFINITION: {
32
+ name: string;
33
+ description: string;
34
+ input_schema: {
35
+ type: "object";
36
+ properties: {
37
+ name: {
38
+ type: string;
39
+ description: string;
40
+ };
41
+ context: {
42
+ type: string;
43
+ description: string;
44
+ additionalProperties: {
45
+ type: string;
46
+ };
47
+ };
48
+ };
49
+ required: string[];
50
+ };
51
+ };
52
+ export interface ListSkillsArgs {
53
+ filter?: string;
54
+ }
55
+ export interface ListSkillsResult {
56
+ skills: Array<{
57
+ name: string;
58
+ description: string;
59
+ }>;
60
+ count: number;
61
+ skillsDir: string;
62
+ denied?: boolean;
63
+ }
64
+ export interface InvokeSkillArgs {
65
+ name: string;
66
+ context?: Record<string, string>;
67
+ }
68
+ export interface InvokeSkillResult {
69
+ skillName: string;
70
+ content: string;
71
+ path: string;
72
+ }
73
+ /**
74
+ * Lists available skills, optionally filtered by name substring.
75
+ * If checkPolicy is provided and denies access to the skills directory,
76
+ * returns an empty list with denied: true rather than throwing.
77
+ */
78
+ export declare function handleListSkills(args: ListSkillsArgs, skillsDir?: string, checkPolicy?: (path: string) => Promise<boolean>): Promise<ListSkillsResult>;
79
+ /**
80
+ * Loads a skill by name and returns its content.
81
+ * The checkPolicy callback is called before loading — throw or return false to deny.
82
+ * It is called twice: once for the tool gate, and again for the resolved skill path.
83
+ */
84
+ export declare function handleInvokeSkill(args: InvokeSkillArgs, checkPolicy: (pathOrTool: string, args?: Record<string, unknown>) => Promise<boolean>, skillsDir?: string): Promise<InvokeSkillResult>;
85
+ /**
86
+ * Creates list_skills and invoke_skill tool definitions wired to a PolicyEngine.
87
+ *
88
+ * The policyEngine is used to validate the skill path before loading content.
89
+ * If policyEngine is null (e.g. in tests), all invocations are allowed.
90
+ *
91
+ * @returns Two CustomToolDefinition entries for the Orchestrator's _createCustomTools()
92
+ */
93
+ export declare function createSkillTools(policyEngine: PolicyEngine | null): CustomToolDefinition[];
94
+ //# sourceMappingURL=skill-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-tool.d.ts","sourceRoot":"","sources":["../../src/tools/skill-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAG9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAMjE,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,sBAAsB,iBAAiB,CAAC;AAIrD,eAAO,MAAM,2BAA2B;;;;;;;;;;;kBAapB,MAAM,EAAE;;CAE3B,CAAC;AAEF,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;kBAsBf,MAAM,EAAE;;CAEjC,CAAC;AAIF,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAMD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,cAAc,EACpB,SAAS,SAAa,EACtB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAC/C,OAAO,CAAC,gBAAgB,CAAC,CAmC3B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,eAAe,EACrB,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,EACrF,SAAS,SAAa,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAuD5B;AAID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,YAAY,GAAG,IAAI,GAChC,oBAAoB,EAAE,CAoDxB"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * SkillTool — Exposes the Claude Code skill library to running Zora agents.
3
+ *
4
+ * list_skills: discover available skills in ~/.claude/skills/
5
+ * invoke_skill: load and return a skill's content for injection into context
6
+ *
7
+ * Security: invoke_skill checks PolicyEngine.validatePath before loading any
8
+ * skill content. Skills must exist on disk — no remote loading.
9
+ *
10
+ * Usage: call createSkillTools(policyEngine) and spread the result into
11
+ * _createCustomTools() in the Orchestrator.
12
+ */
13
+ import os from 'node:os';
14
+ import path from 'node:path';
15
+ import fs from 'node:fs/promises';
16
+ import { loadSkills } from '../skills/skill-loader.js';
17
+ import { createLogger } from '../utils/logger.js';
18
+ const log = createLogger('skill-tool');
19
+ // ─── Tool Names ────────────────────────────────────────────────────────────────
20
+ export const LIST_SKILLS_TOOL_NAME = 'list_skills';
21
+ export const INVOKE_SKILL_TOOL_NAME = 'invoke_skill';
22
+ // ─── Tool Definitions (for documentation/testing) ─────────────────────────────
23
+ export const LIST_SKILLS_TOOL_DEFINITION = {
24
+ name: LIST_SKILLS_TOOL_NAME,
25
+ description: 'List all available Claude Code skills from ~/.claude/skills/. ' +
26
+ 'Call this before invoke_skill to confirm the skill exists.',
27
+ input_schema: {
28
+ type: 'object',
29
+ properties: {
30
+ filter: {
31
+ type: 'string',
32
+ description: 'Optional: filter skills by name substring',
33
+ },
34
+ },
35
+ required: [],
36
+ },
37
+ };
38
+ export const INVOKE_SKILL_TOOL_DEFINITION = {
39
+ name: INVOKE_SKILL_TOOL_NAME,
40
+ description: [
41
+ 'Load and return a Claude Code skill by name.',
42
+ 'Skills are reusable prompt templates in ~/.claude/skills/<name>/SKILL.md.',
43
+ 'The skill content is returned as text for injection into your context.',
44
+ 'Call list_skills first to see available skills.',
45
+ ].join(' '),
46
+ input_schema: {
47
+ type: 'object',
48
+ properties: {
49
+ name: {
50
+ type: 'string',
51
+ description: 'Exact skill name (directory name in ~/.claude/skills/)',
52
+ },
53
+ context: {
54
+ type: 'object',
55
+ description: 'Optional: key-value pairs for template variable substitution in the skill',
56
+ additionalProperties: { type: 'string' },
57
+ },
58
+ },
59
+ required: ['name'],
60
+ },
61
+ };
62
+ // ─── Pure Handlers (testable without PolicyEngine) ────────────────────────────
63
+ const SKILLS_DIR = path.join(os.homedir(), '.claude', 'skills');
64
+ /**
65
+ * Lists available skills, optionally filtered by name substring.
66
+ * If checkPolicy is provided and denies access to the skills directory,
67
+ * returns an empty list with denied: true rather than throwing.
68
+ */
69
+ export async function handleListSkills(args, skillsDir = SKILLS_DIR, checkPolicy) {
70
+ if (checkPolicy) {
71
+ const allowed = await checkPolicy(skillsDir);
72
+ if (!allowed) {
73
+ return { skills: [], count: 0, skillsDir, denied: true };
74
+ }
75
+ }
76
+ const all = await loadSkills(skillsDir);
77
+ // Validate each skill's real path stays within skillsDir (catches symlinks in the dir)
78
+ const resolvedSkillsDir = await fs.realpath(skillsDir).catch(() => path.resolve(skillsDir));
79
+ const safe = await Promise.all(all.map(async (s) => {
80
+ try {
81
+ const real = await fs.realpath(s.path).catch(() => path.resolve(s.path));
82
+ return real.startsWith(resolvedSkillsDir + path.sep) ? s : null;
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }));
88
+ const valid = safe.filter((s) => s !== null);
89
+ const skills = args.filter
90
+ ? valid.filter(s => s.name.toLowerCase().includes(args.filter.toLowerCase()))
91
+ : valid;
92
+ log.debug({ total: all.length, safe: valid.length, filtered: skills.length }, 'list_skills called');
93
+ return {
94
+ skills: skills.map(s => ({ name: s.name, description: s.description })),
95
+ count: skills.length,
96
+ skillsDir,
97
+ };
98
+ }
99
+ /**
100
+ * Loads a skill by name and returns its content.
101
+ * The checkPolicy callback is called before loading — throw or return false to deny.
102
+ * It is called twice: once for the tool gate, and again for the resolved skill path.
103
+ */
104
+ export async function handleInvokeSkill(args, checkPolicy, skillsDir = SKILLS_DIR) {
105
+ const { name, context = {} } = args;
106
+ // Policy check before loading any skill content
107
+ if (!(await checkPolicy(INVOKE_SKILL_TOOL_NAME, { name }))) {
108
+ throw new Error(`Policy denied: invoke_skill("${name}")`);
109
+ }
110
+ const all = await loadSkills(skillsDir);
111
+ const skill = all.find(s => s.name === name);
112
+ if (!skill) {
113
+ const names = all.map(s => s.name).join(', ');
114
+ throw new Error(`Skill "${name}" not found. Available: ${names || 'none'}`);
115
+ }
116
+ // Use fs.realpath() (not path.resolve) to follow symlinks before checking boundaries.
117
+ // path.resolve() only normalizes segments; a SKILL.md that is a symlink to /etc/passwd
118
+ // would pass a path.resolve() check but fail here.
119
+ // Falls back to path.resolve() when the path doesn't yet exist (e.g. tests with mocks)
120
+ // — symlinks to non-existent targets can't be exploited since readFile will also fail.
121
+ let resolvedSkillPath;
122
+ try {
123
+ resolvedSkillPath = await fs.realpath(skill.path);
124
+ }
125
+ catch {
126
+ resolvedSkillPath = path.resolve(skill.path);
127
+ }
128
+ const resolvedSkillsDir = await fs.realpath(skillsDir).catch(() => path.resolve(skillsDir));
129
+ if (!resolvedSkillPath.startsWith(resolvedSkillsDir + path.sep) &&
130
+ resolvedSkillPath !== resolvedSkillsDir) {
131
+ throw new Error(`Skill path "${resolvedSkillPath}" is outside the skills directory (symlink traversal blocked)`);
132
+ }
133
+ // Per-skill policy check on the resolved path
134
+ const pathAllowed = await checkPolicy(resolvedSkillPath);
135
+ if (!pathAllowed) {
136
+ throw new Error(`Access to skill at "${resolvedSkillPath}" denied by policy`);
137
+ }
138
+ let content = await fs.readFile(resolvedSkillPath, 'utf-8');
139
+ // Simple template substitution: {{key}} → value
140
+ for (const [key, value] of Object.entries(context)) {
141
+ content = content.replaceAll(`{{${key}}}`, value);
142
+ }
143
+ log.info({ skillName: name, contentLength: content.length }, 'skill invoked by agent');
144
+ return { skillName: name, content, path: skill.path };
145
+ }
146
+ // ─── Factory ───────────────────────────────────────────────────────────────────
147
+ /**
148
+ * Creates list_skills and invoke_skill tool definitions wired to a PolicyEngine.
149
+ *
150
+ * The policyEngine is used to validate the skill path before loading content.
151
+ * If policyEngine is null (e.g. in tests), all invocations are allowed.
152
+ *
153
+ * @returns Two CustomToolDefinition entries for the Orchestrator's _createCustomTools()
154
+ */
155
+ export function createSkillTools(policyEngine) {
156
+ // Build a policy check function from the engine.
157
+ // invoke_skill loads a file from disk — use validatePath to ensure the
158
+ // skill path is within the policy's allowed filesystem boundaries.
159
+ // The function accepts either a tool name (with optional args) or a resolved
160
+ // filesystem path, and returns a Promise<boolean> in both cases.
161
+ const checkPolicy = async (pathOrTool, _args) => {
162
+ if (!policyEngine)
163
+ return true; // no engine → allow (safe default for tests)
164
+ // For any call, validate the path or skills directory via validatePath.
165
+ // When called with a tool name, we validate the skills directory root.
166
+ // When called with a resolved skill path, we validate that specific path.
167
+ const pathToCheck = pathOrTool === INVOKE_SKILL_TOOL_NAME ? SKILLS_DIR : pathOrTool;
168
+ const result = policyEngine.validatePath(pathToCheck);
169
+ if (!result.allowed) {
170
+ log.warn({ path: pathToCheck, reason: result.reason }, 'skill access blocked by policy');
171
+ return false;
172
+ }
173
+ return true;
174
+ };
175
+ const listSkillsTool = {
176
+ name: LIST_SKILLS_TOOL_NAME,
177
+ description: LIST_SKILLS_TOOL_DEFINITION.description,
178
+ input_schema: LIST_SKILLS_TOOL_DEFINITION.input_schema,
179
+ handler: async (input) => {
180
+ const args = {
181
+ filter: input['filter'],
182
+ };
183
+ return handleListSkills(args, SKILLS_DIR, checkPolicy);
184
+ },
185
+ };
186
+ const invokeSkillTool = {
187
+ name: INVOKE_SKILL_TOOL_NAME,
188
+ description: INVOKE_SKILL_TOOL_DEFINITION.description,
189
+ input_schema: INVOKE_SKILL_TOOL_DEFINITION.input_schema,
190
+ handler: async (input) => {
191
+ const args = {
192
+ name: input['name'],
193
+ context: input['context'],
194
+ };
195
+ const result = await handleInvokeSkill(args, checkPolicy);
196
+ // Return a structured object with skillName, content, and path fields
197
+ return { skillName: result.skillName, content: result.content, path: result.path };
198
+ },
199
+ };
200
+ return [listSkillsTool, invokeSkillTool];
201
+ }
202
+ //# sourceMappingURL=skill-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-tool.js","sourceRoot":"","sources":["../../src/tools/skill-tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SubagentTool — delegate_to_subagent custom tool.
3
+ *
4
+ * Loads subagent definitions from .zora/subagents/<name>/SUBAGENT.md
5
+ * and exposes a delegate_to_subagent tool for the LLM to use.
6
+ */
7
+ import type { CustomToolDefinition } from '../orchestrator/execution-loop.js';
8
+ export declare function createSubagentTools(submitTask: (opts: {
9
+ prompt: string;
10
+ }) => Promise<string>): CustomToolDefinition[];
11
+ //# sourceMappingURL=subagent-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-tool.d.ts","sourceRoot":"","sources":["../../src/tools/subagent-tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAK9E,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,MAAM,CAAC,GACxD,oBAAoB,EAAE,CAmFxB"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * SubagentTool — delegate_to_subagent custom tool.
3
+ *
4
+ * Loads subagent definitions from .zora/subagents/<name>/SUBAGENT.md
5
+ * and exposes a delegate_to_subagent tool for the LLM to use.
6
+ */
7
+ import { loadSubagents } from '../skills/subagent-loader.js';
8
+ import { createLogger } from '../utils/logger.js';
9
+ const log = createLogger('subagent-tool');
10
+ export function createSubagentTools(submitTask) {
11
+ const listSubagentsTool = {
12
+ name: 'list_subagents',
13
+ description: 'List available subagents that can be delegated tasks. Each subagent has a specific role and restricted tool access.',
14
+ input_schema: {
15
+ type: 'object',
16
+ properties: {},
17
+ },
18
+ handler: async () => {
19
+ const subagents = await loadSubagents();
20
+ if (subagents.length === 0) {
21
+ return { subagents: [], message: 'No subagents defined. Create .zora/subagents/<name>/SUBAGENT.md to define one.' };
22
+ }
23
+ return {
24
+ subagents: subagents.map(s => ({
25
+ name: s.name,
26
+ description: s.description,
27
+ layer: s.layer,
28
+ allowedTools: s.allowedTools,
29
+ })),
30
+ count: subagents.length,
31
+ };
32
+ },
33
+ };
34
+ const delegateToSubagentTool = {
35
+ name: 'delegate_to_subagent',
36
+ description: 'Delegate a self-contained task to a named subagent. The subagent runs with its declared system prompt and restricted tool subset. Cannot spawn further subagents. Use list_subagents to see available subagents.',
37
+ input_schema: {
38
+ type: 'object',
39
+ properties: {
40
+ subagent_name: {
41
+ type: 'string',
42
+ description: 'Name of the subagent (matches the directory name in .zora/subagents/<name>/)',
43
+ },
44
+ task: {
45
+ type: 'string',
46
+ description: 'The specific task to delegate. Be precise — the subagent has no conversation history.',
47
+ },
48
+ },
49
+ required: ['subagent_name', 'task'],
50
+ },
51
+ handler: async (input) => {
52
+ const name = input['subagent_name'];
53
+ const task = input['task'];
54
+ if (!name || !task) {
55
+ return { error: 'subagent_name and task are required' };
56
+ }
57
+ const subagents = await loadSubagents();
58
+ const subagent = subagents.find(s => s.name === name);
59
+ if (!subagent) {
60
+ const available = subagents.map(s => s.name);
61
+ return {
62
+ error: `Subagent '${name}' not found.`,
63
+ available: available.length > 0 ? available : 'none defined',
64
+ };
65
+ }
66
+ log.info({ subagent: name, taskLength: task.length }, 'Delegating to subagent');
67
+ try {
68
+ // NOTE: SubmitTaskOptions does not yet support systemPrompt override.
69
+ // As a workaround, we prepend the subagent's system prompt as context
70
+ // in the task prompt. Full systemPrompt threading is tracked as a
71
+ // follow-up (requires SubmitTaskOptions.systemPrompt field).
72
+ const augmentedPrompt = subagent.systemPrompt
73
+ ? `[Subagent context — follow these instructions throughout this task]\n${subagent.systemPrompt}\n\n[Task]\n${task}`
74
+ : task;
75
+ const result = await submitTask({ prompt: augmentedPrompt });
76
+ return { result, subagent: name };
77
+ }
78
+ catch (err) {
79
+ const msg = err instanceof Error ? err.message : String(err);
80
+ log.error({ subagent: name, err: msg }, 'Subagent delegation failed');
81
+ return { error: `Subagent '${name}' failed: ${msg}` };
82
+ }
83
+ },
84
+ };
85
+ return [listSubagentsTool, delegateToSubagentTool];
86
+ }
87
+ //# sourceMappingURL=subagent-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-tool.js","sourceRoot":"","sources":["../../src/tools/subagent-tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAE1C,MAAM,UAAU,mBAAmB,CACjC,UAAyD;IAEzD,MAAM,iBAAiB,GAAyB;QAC9C,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,qHAAqH;QAClI,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE;SACf;QACD,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,SAAS,GAAG,MAAM,aAAa,EAAE,CAAC;YACxC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3B,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,gFAAgF,EAAE,CAAC;YACtH,CAAC;YACD,OAAO;gBACL,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC7B,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,WAAW,EAAE,CAAC,CAAC,WAAW;oBAC1B,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,YAAY,EAAE,CAAC,CAAC,YAAY;iBAC7B,CAAC,CAAC;gBACH,KAAK,EAAE,SAAS,CAAC,MAAM;aACxB,CAAC;QACJ,CAAC;KACF,CAAC;IAEF,MAAM,sBAAsB,GAAyB;QACnD,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,kNAAkN;QAC/N,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,aAAa,EAAE;oBACb,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,8EAA8E;iBAC5F;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,uFAAuF;iBACrG;aACF;YACD,QAAQ,EAAE,CAAC,eAAe,EAAE,MAAM,CAAC;SACpC;QACD,OAAO,EAAE,KAAK,EAAE,KAA8B,EAAE,EAAE;YAChD,MAAM,IAAI,GAAG,KAAK,CAAC,eAAe,CAAW,CAAC;YAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAW,CAAC;YAErC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACnB,OAAO,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC;YAC1D,CAAC;YAED,MAAM,SAAS,GAAG,MAAM,aAAa,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAEtD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC7C,OAAO;oBACL,KAAK,EAAE,aAAa,IAAI,cAAc;oBACtC,SAAS,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc;iBAC7D,CAAC;YACJ,CAAC;YAED,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC;YAEhF,IAAI,CAAC;gBACH,sEAAsE;gBACtE,sEAAsE;gBACtE,kEAAkE;gBAClE,6DAA6D;gBAC7D,MAAM,eAAe,GAAG,QAAQ,CAAC,YAAY;oBAC3C,CAAC,CAAC,wEAAwE,QAAQ,CAAC,YAAY,eAAe,IAAI,EAAE;oBACpH,CAAC,CAAC,IAAI,CAAC;gBAET,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;gBAC7D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACpC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7D,GAAG,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,4BAA4B,CAAC,CAAC;gBACtE,OAAO,EAAE,KAAK,EAAE,aAAa,IAAI,aAAa,GAAG,EAAE,EAAE,CAAC;YACxD,CAAC;QACH,CAAC;KACF,CAAC;IAEF,OAAO,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,CAAC;AACrD,CAAC"}