@treenity/core 3.0.0 → 3.0.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 (322) hide show
  1. package/README.md +78 -0
  2. package/dist/chain.d.ts +3 -4
  3. package/dist/chain.d.ts.map +1 -1
  4. package/dist/chain.js.map +1 -1
  5. package/dist/client/trpc.d.ts.map +1 -1
  6. package/dist/client/trpc.js +1 -0
  7. package/dist/client/trpc.js.map +1 -1
  8. package/dist/comp/index.d.ts +3 -4
  9. package/dist/comp/index.d.ts.map +1 -1
  10. package/dist/comp/index.js +5 -4
  11. package/dist/comp/index.js.map +1 -1
  12. package/dist/comp/needs.d.ts.map +1 -1
  13. package/dist/comp/needs.js +3 -3
  14. package/dist/comp/needs.js.map +1 -1
  15. package/dist/core/component.d.ts +10 -8
  16. package/dist/core/component.d.ts.map +1 -1
  17. package/dist/core/component.js +4 -8
  18. package/dist/core/component.js.map +1 -1
  19. package/dist/core/context.d.ts +2 -2
  20. package/dist/core/context.d.ts.map +1 -1
  21. package/dist/core/path.d.ts.map +1 -1
  22. package/dist/core/path.js +7 -3
  23. package/dist/core/path.js.map +1 -1
  24. package/dist/core/registry.d.ts +2 -1
  25. package/dist/core/registry.d.ts.map +1 -1
  26. package/dist/core/registry.js.map +1 -1
  27. package/dist/core.d.ts +1 -1
  28. package/dist/core.d.ts.map +1 -1
  29. package/dist/core.js +1 -1
  30. package/dist/core.js.map +1 -1
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +2 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/log.d.ts +30 -0
  36. package/dist/log.d.ts.map +1 -1
  37. package/dist/log.js +119 -0
  38. package/dist/log.js.map +1 -1
  39. package/dist/mod/examples/ticker/service.js +2 -3
  40. package/dist/mod/examples/ticker/service.js.map +1 -1
  41. package/dist/mod/index.d.ts +1 -1
  42. package/dist/mod/index.d.ts.map +1 -1
  43. package/dist/mod/index.js +1 -1
  44. package/dist/mod/index.js.map +1 -1
  45. package/dist/mod/loader.d.ts +1 -0
  46. package/dist/mod/loader.d.ts.map +1 -1
  47. package/dist/mod/loader.js +27 -1
  48. package/dist/mod/loader.js.map +1 -1
  49. package/dist/mods/clients.d.ts +2 -0
  50. package/dist/mods/clients.d.ts.map +1 -0
  51. package/dist/mods/clients.js +3 -0
  52. package/dist/mods/clients.js.map +1 -0
  53. package/dist/mods/llm/index.js +1 -1
  54. package/dist/mods/llm/index.js.map +1 -1
  55. package/dist/mods/mcp/server.d.ts +0 -1
  56. package/dist/mods/mcp/server.js +0 -1
  57. package/dist/mods/mcp/service.d.ts +0 -1
  58. package/dist/mods/mcp/service.js +0 -1
  59. package/dist/mods/mcp/types.d.ts +0 -1
  60. package/dist/mods/mcp/types.js +0 -1
  61. package/dist/mods/servers.d.ts +4 -0
  62. package/dist/mods/servers.d.ts.map +1 -0
  63. package/dist/mods/servers.js +5 -0
  64. package/dist/mods/servers.js.map +1 -0
  65. package/dist/mods/treenity/builtins.d.ts +2 -0
  66. package/dist/mods/treenity/builtins.d.ts.map +1 -0
  67. package/dist/mods/treenity/builtins.js +18 -0
  68. package/dist/mods/treenity/builtins.js.map +1 -0
  69. package/dist/mods/treenity/logs.d.ts +18 -0
  70. package/dist/mods/treenity/logs.d.ts.map +1 -0
  71. package/dist/mods/treenity/logs.js +17 -0
  72. package/dist/mods/treenity/logs.js.map +1 -0
  73. package/dist/mods/treenity/seed.js +29 -27
  74. package/dist/mods/treenity/seed.js.map +1 -1
  75. package/dist/mods/treenity/server.d.ts +2 -0
  76. package/dist/mods/treenity/server.d.ts.map +1 -1
  77. package/dist/mods/treenity/server.js +2 -0
  78. package/dist/mods/treenity/server.js.map +1 -1
  79. package/dist/mods/uix/client.js +4 -4
  80. package/dist/mods/uix/client.js.map +1 -1
  81. package/dist/mods/uix/compile.d.ts.map +1 -1
  82. package/dist/mods/uix/compile.js +4 -2
  83. package/dist/mods/uix/compile.js.map +1 -1
  84. package/dist/schema/_test-fixture.d.ts +11 -0
  85. package/dist/schema/_test-fixture.d.ts.map +1 -0
  86. package/dist/schema/_test-fixture.js +8 -0
  87. package/dist/schema/_test-fixture.js.map +1 -0
  88. package/dist/schema/types.d.ts +1 -0
  89. package/dist/schema/types.d.ts.map +1 -1
  90. package/dist/server/actions.js +1 -1
  91. package/dist/server/auth.d.ts.map +1 -1
  92. package/dist/server/auth.js +4 -3
  93. package/dist/server/auth.js.map +1 -1
  94. package/dist/server/client.d.ts +10 -3
  95. package/dist/server/client.d.ts.map +1 -1
  96. package/dist/server/client.js +1 -1
  97. package/dist/server/client.js.map +1 -1
  98. package/dist/server/doc-index.d.ts.map +1 -1
  99. package/dist/server/doc-index.js +13 -12
  100. package/dist/server/doc-index.js.map +1 -1
  101. package/dist/server/factory.d.ts +6 -0
  102. package/dist/server/factory.d.ts.map +1 -1
  103. package/dist/server/factory.js +44 -25
  104. package/dist/server/factory.js.map +1 -1
  105. package/dist/server/main.d.ts +0 -4
  106. package/dist/server/main.d.ts.map +1 -1
  107. package/dist/server/main.js +4 -30
  108. package/dist/server/main.js.map +1 -1
  109. package/dist/server/mcp.d.ts +0 -1
  110. package/dist/server/mcp.js +0 -1
  111. package/dist/server/migrate.js +3 -3
  112. package/dist/server/migrate.js.map +1 -1
  113. package/dist/server/mods-mount.d.ts +0 -1
  114. package/dist/server/mods-mount.d.ts.map +1 -1
  115. package/dist/server/mods-mount.js +0 -1
  116. package/dist/server/mods-mount.js.map +1 -1
  117. package/dist/server/mount-adapters.js +9 -4
  118. package/dist/server/mount-adapters.js.map +1 -1
  119. package/dist/server/prefab.d.ts +2 -2
  120. package/dist/server/prefab.d.ts.map +1 -1
  121. package/dist/server/prefab.js +4 -2
  122. package/dist/server/prefab.js.map +1 -1
  123. package/dist/server/refs.d.ts +3 -0
  124. package/dist/server/refs.d.ts.map +1 -0
  125. package/dist/server/refs.js +59 -0
  126. package/dist/server/refs.js.map +1 -0
  127. package/dist/server/server.d.ts.map +1 -1
  128. package/dist/server/server.js +13 -3
  129. package/dist/server/server.js.map +1 -1
  130. package/dist/server/sub.js.map +1 -1
  131. package/dist/server/trpc.d.ts +7 -0
  132. package/dist/server/trpc.d.ts.map +1 -1
  133. package/dist/server/trpc.js +6 -2
  134. package/dist/server/trpc.js.map +1 -1
  135. package/dist/tree/fs.d.ts.map +1 -1
  136. package/dist/tree/fs.js +20 -18
  137. package/dist/tree/fs.js.map +1 -1
  138. package/dist/tree/index.d.ts.map +1 -1
  139. package/dist/tree/index.js +2 -1
  140. package/dist/tree/index.js.map +1 -1
  141. package/dist/tree-chain.d.ts +2 -1
  142. package/dist/tree-chain.d.ts.map +1 -1
  143. package/dist/tree-chain.js +5 -3
  144. package/dist/tree-chain.js.map +1 -1
  145. package/dist/uri.d.ts.map +1 -1
  146. package/dist/uri.js +8 -3
  147. package/dist/uri.js.map +1 -1
  148. package/package.json +48 -6
  149. package/src/chain.ts +7 -5
  150. package/src/client/trpc.ts +1 -0
  151. package/src/comp/index.test.ts +45 -9
  152. package/src/comp/index.ts +19 -8
  153. package/src/comp/needs.ts +3 -3
  154. package/src/core/component.ts +16 -14
  155. package/src/core/context.ts +4 -4
  156. package/src/core/index.test.ts +22 -1
  157. package/src/core/path.ts +6 -3
  158. package/src/core/registry.ts +4 -7
  159. package/src/core.ts +1 -1
  160. package/src/index.ts +1 -0
  161. package/src/log.ts +172 -1
  162. package/src/mod/docs/07-realtime.md +19 -11
  163. package/src/mod/docs/08-services.md +10 -8
  164. package/src/mod/docs/10-acl.md +1 -1
  165. package/src/mod/docs/12-conventions.md +43 -0
  166. package/src/mod/docs/13-example.md +36 -26
  167. package/src/mod/docs/14-mod-format.md +81 -8
  168. package/src/mod/examples/ticker/service.ts +2 -3
  169. package/src/mod/index.ts +1 -1
  170. package/src/mod/loader.test.ts +53 -1
  171. package/src/mod/loader.ts +34 -1
  172. package/src/mods/clients.ts +2 -0
  173. package/src/mods/llm/index.ts +1 -1
  174. package/src/mods/servers.ts +4 -0
  175. package/src/mods/treenity/builtins.ts +21 -0
  176. package/src/mods/treenity/logs.ts +26 -0
  177. package/src/mods/treenity/seed.ts +30 -28
  178. package/src/mods/treenity/server.ts +2 -0
  179. package/src/mods/uix/client.ts +4 -4
  180. package/src/mods/uix/compile.ts +4 -2
  181. package/src/schema/_test-fixture.ts +12 -0
  182. package/src/schema/generated/ai.agent.json +133 -0
  183. package/src/schema/generated/ai.approval.json +105 -0
  184. package/src/schema/generated/ai.approvals.json +24 -0
  185. package/src/schema/generated/ai.assignment.json +28 -0
  186. package/src/schema/generated/ai.plan.json +84 -0
  187. package/src/schema/generated/ai.policy.json +105 -0
  188. package/src/schema/generated/ai.pool.json +37 -0
  189. package/src/schema/generated/ai.thread.json +64 -0
  190. package/src/schema/generated/board.kanban.json +7 -0
  191. package/src/schema/generated/canary.item.json +40 -0
  192. package/src/schema/generated/claude-search.json +20 -0
  193. package/src/schema/generated/craft.product.json +47 -0
  194. package/src/schema/generated/craft.shop.json +94 -0
  195. package/src/schema/generated/craft.subscription.json +27 -0
  196. package/src/schema/generated/examples.demo.sensor.reading.json +25 -0
  197. package/src/schema/generated/flow.node.action.json +61 -0
  198. package/src/schema/generated/flow.node.code.json +43 -0
  199. package/src/schema/generated/flow.node.condition.json +37 -0
  200. package/src/schema/generated/flow.node.end.json +35 -0
  201. package/src/schema/generated/flow.node.http.json +65 -0
  202. package/src/schema/generated/flow.node.llm.json +67 -0
  203. package/src/schema/generated/flow.node.loop.json +49 -0
  204. package/src/schema/generated/flow.node.start.json +39 -0
  205. package/src/schema/generated/flow.scenario.json +118 -0
  206. package/src/schema/generated/grove.attempt.json +199 -0
  207. package/src/schema/generated/grove.path.json +93 -0
  208. package/src/schema/generated/grove.review.json +27 -0
  209. package/src/schema/generated/grove.task.json +164 -0
  210. package/src/schema/generated/intel.scenario.json +58 -0
  211. package/src/schema/generated/intel.signal.json +113 -0
  212. package/src/schema/generated/intel.world.json +15 -0
  213. package/src/schema/generated/landing.block.json +201 -0
  214. package/src/schema/generated/landing.page.json +84 -0
  215. package/src/schema/generated/metatron.config.json +119 -0
  216. package/src/schema/generated/metatron.permission.json +36 -0
  217. package/src/schema/generated/metatron.skill.json +36 -0
  218. package/src/schema/generated/metatron.task.json +114 -0
  219. package/src/schema/generated/metatron.template.json +26 -0
  220. package/src/schema/generated/metatron.workspace.json +60 -0
  221. package/src/schema/generated/order.status.json +21 -0
  222. package/src/schema/generated/polyhope.backtest.json +161 -0
  223. package/src/schema/generated/polyhope.feed.json +33 -0
  224. package/src/schema/generated/polyhope.run.json +94 -0
  225. package/src/schema/generated/polyhope.strategy.json +152 -0
  226. package/src/schema/generated/polymax.activity.json +65 -0
  227. package/src/schema/generated/polymax.aggr-feed.json +28 -0
  228. package/src/schema/generated/polymax.aggr.json +20 -0
  229. package/src/schema/generated/polymax.alert.json +56 -0
  230. package/src/schema/generated/polymax.bot-config.json +14 -0
  231. package/src/schema/generated/polymax.bot-status.json +35 -0
  232. package/src/schema/generated/polymax.classification.json +55 -0
  233. package/src/schema/generated/polymax.deposits.json +45 -0
  234. package/src/schema/generated/polymax.holding.json +55 -0
  235. package/src/schema/generated/polymax.identity.json +71 -0
  236. package/src/schema/generated/polymax.lb-entry.json +75 -0
  237. package/src/schema/generated/polymax.leaderboard.json +37 -0
  238. package/src/schema/generated/polymax.market-ref.json +25 -0
  239. package/src/schema/generated/polymax.performance.json +65 -0
  240. package/src/schema/generated/polymax.profile.json +16 -0
  241. package/src/schema/generated/polymax.scan-result.json +50 -0
  242. package/src/schema/generated/polymax.status.json +40 -0
  243. package/src/schema/generated/polymax.tags.json +53 -0
  244. package/src/schema/generated/polymax.trader.json +16 -0
  245. package/src/schema/generated/polymax.wallet-market.json +50 -0
  246. package/src/schema/generated/polymax.wallet-pnl.json +35 -0
  247. package/src/schema/generated/pult.concept.json +53 -0
  248. package/src/schema/generated/pult.config.json +227 -0
  249. package/src/schema/generated/pult.connector.json +72 -0
  250. package/src/schema/generated/pult.market.json +113 -0
  251. package/src/schema/generated/pult.order.json +113 -0
  252. package/src/schema/generated/pult.rete.json +68 -0
  253. package/src/schema/generated/pult.sensor.json +74 -0
  254. package/src/schema/generated/pult.signal.json +54 -0
  255. package/src/schema/generated/pult.synapse.json +93 -0
  256. package/src/schema/generated/pult.trade.json +93 -0
  257. package/src/schema/generated/resim.config.json +34 -0
  258. package/src/schema/generated/resim.function.json +62 -0
  259. package/src/schema/generated/resim.goal.json +22 -0
  260. package/src/schema/generated/resim.resource.json +40 -0
  261. package/src/schema/generated/resim.state.json +48 -0
  262. package/src/schema/generated/resim.world.json +40 -0
  263. package/src/schema/generated/saveme.action.save.json +29 -0
  264. package/src/schema/generated/saveme.message.json +36 -0
  265. package/src/schema/generated/saveme.router.json +31 -0
  266. package/src/schema/generated/t.coolify.json +50 -0
  267. package/src/schema/generated/t.event.json +46 -0
  268. package/src/schema/generated/t.logs.json +155 -0
  269. package/src/schema/generated/t.note.json +31 -0
  270. package/src/schema/generated/t.person.json +36 -0
  271. package/src/schema/generated/t.tenant.json +57 -0
  272. package/src/schema/generated/t.tenant.status.json +42 -0
  273. package/src/schema/generated/tagger.config.json +115 -0
  274. package/src/schema/generated/tagger.result.json +57 -0
  275. package/src/schema/generated/tagger.tree.json +36 -0
  276. package/src/schema/generated/ui.table.json +46 -0
  277. package/src/schema/types.ts +1 -0
  278. package/src/server/actions.test.ts +1 -1
  279. package/src/server/actions.ts +1 -1
  280. package/src/server/api.test.ts +9 -0
  281. package/src/server/auth.ts +4 -3
  282. package/src/server/client.ts +1 -1
  283. package/src/server/coverage.test.ts +1 -1
  284. package/src/server/doc-index.ts +13 -12
  285. package/src/server/e2e.test.ts +4 -3
  286. package/src/server/factory.ts +46 -24
  287. package/src/server/main.ts +4 -36
  288. package/src/server/migrate.ts +4 -4
  289. package/src/server/mods-mount.ts +0 -2
  290. package/src/server/mount-adapters.ts +9 -4
  291. package/src/server/mount.test.ts +73 -5
  292. package/src/server/prefab.ts +3 -2
  293. package/src/server/refs.test.ts +82 -0
  294. package/src/server/refs.ts +64 -0
  295. package/src/server/server.ts +14 -3
  296. package/src/server/sub.ts +2 -2
  297. package/src/server/trpc.ts +9 -3
  298. package/src/tree/fs.ts +21 -15
  299. package/src/tree/index.test.ts +26 -0
  300. package/src/tree/index.ts +2 -1
  301. package/src/tree-chain.test.ts +37 -44
  302. package/src/tree-chain.ts +11 -5
  303. package/src/uri.test.ts +32 -5
  304. package/src/uri.ts +4 -2
  305. package/dist/mods/mcp/server.d.ts.map +0 -1
  306. package/dist/mods/mcp/server.js.map +0 -1
  307. package/dist/mods/mcp/service.d.ts.map +0 -1
  308. package/dist/mods/mcp/service.js.map +0 -1
  309. package/dist/mods/mcp/types.d.ts.map +0 -1
  310. package/dist/mods/mcp/types.js.map +0 -1
  311. package/dist/schema/test-opaque.d.ts +0 -3
  312. package/dist/schema/test-opaque.d.ts.map +0 -1
  313. package/dist/schema/test-opaque.js +0 -43
  314. package/dist/schema/test-opaque.js.map +0 -1
  315. package/dist/server/mcp.d.ts.map +0 -1
  316. package/dist/server/mcp.js.map +0 -1
  317. package/src/mods/mcp/CLAUDE.md +0 -6
  318. package/src/mods/mcp/server.ts +0 -2
  319. package/src/mods/mcp/service.ts +0 -19
  320. package/src/mods/mcp/types.ts +0 -7
  321. package/src/schema/test-opaque.ts +0 -42
  322. package/src/server/mcp.ts +0 -326
@@ -14,9 +14,13 @@ import { withMounts } from './mount';
14
14
  import type { ReactiveTree } from './sub';
15
15
  import { unwatchAllQueries, withSubscriptions } from './sub';
16
16
  import { createTreeRouter, type TreeRouter, type TrpcContext } from './trpc';
17
+ import { withRefIndex } from './refs';
17
18
  import { withValidation } from './validate';
18
19
  import { withVolatile } from './volatile';
19
20
  import { createWatchManager, type WatchManager } from './watch';
21
+ import { createLogger } from '#log';
22
+
23
+ const log = createLogger('http');
20
24
 
21
25
  export type RouteHandler = (req: import('node:http').IncomingMessage, res: import('node:http').ServerResponse, store: Tree) => Promise<void>;
22
26
 
@@ -36,7 +40,8 @@ export function createPipeline(bootstrap: Tree): Pipeline {
36
40
  const mountable = withMounts(bootstrap);
37
41
  const volatile = withVolatile(mountable);
38
42
  const validated = withValidation(volatile);
39
- const cached = withCache(validated);
43
+ const refsIndexed = withRefIndex(validated);
44
+ const cached = withCache(refsIndexed);
40
45
  const watcher = createWatchManager({
41
46
  onUserRemoved: (userId) => unwatchAllQueries(userId),
42
47
  });
@@ -130,7 +135,10 @@ export function createHttpServer(pipeline: Pipeline, opts?: HttpServerOpts): Ser
130
135
  // tRPC routes
131
136
  if (pathname.startsWith('/trpc')) {
132
137
  const path = pathname.replace(/^\/trpc/, '').replace(/^\//, '');
133
- await nodeHTTPRequestHandler({ req, res, router, path, createContext });
138
+ await nodeHTTPRequestHandler({
139
+ req, res, router, path, createContext,
140
+ onError: ({ error, path: p }) => log.error(`trpc ${p}: ${error.message}`),
141
+ });
134
142
  return;
135
143
  }
136
144
 
@@ -139,7 +147,10 @@ export function createHttpServer(pipeline: Pipeline, opts?: HttpServerOpts): Ser
139
147
 
140
148
  // Fallback: try tRPC for legacy non-prefixed calls
141
149
  const path = pathname.replace(/^\//, '');
142
- await nodeHTTPRequestHandler({ req, res, router, path, createContext });
150
+ await nodeHTTPRequestHandler({
151
+ req, res, router, path, createContext,
152
+ onError: ({ error, path: p }) => log.error(`trpc ${p}: ${error.message}`),
153
+ });
143
154
  });
144
155
  }
145
156
 
package/src/server/sub.ts CHANGED
@@ -26,7 +26,7 @@ export type NodeEvent =
26
26
  | { type: 'reconnect'; preserved: boolean };
27
27
 
28
28
  // Strip empty arrays and $path from node to keep wire format clean
29
- function cleanEvent(event: NodeEvent): NodeEvent {
29
+ function cleanEvent<T extends NodeEvent>(event: T): T {
30
30
  const e = { ...event };
31
31
  if ('addVps' in e && e.addVps && e.addVps.length === 0) delete e.addVps;
32
32
  if ('rmVps' in e && e.rmVps && e.rmVps.length === 0) delete e.rmVps;
@@ -90,7 +90,7 @@ export function withSubscriptions(
90
90
  type DataEvent = Exclude<NodeEvent, { type: 'reconnect' }>;
91
91
 
92
92
  function emit(raw: DataEvent) {
93
- const event = cleanEvent(raw) as DataEvent;
93
+ const event = cleanEvent(raw);
94
94
 
95
95
  const exact = exactListeners.get(event.path);
96
96
  if (exact) for (const fn of exact) fn(event);
@@ -66,6 +66,7 @@ export function createTreeRouter(baseStore: ReactiveTree, watcher: WatchManager)
66
66
  // Session-level claims (agents) override dynamic buildClaims (users)
67
67
  const claims = ctx.session?.claims ?? (userId ? await buildClaims(baseStore, userId) : ['public']);
68
68
  const store = withAcl(baseStore, userId, claims);
69
+
69
70
  const result = await next({ ctx: { ...ctx, store } });
70
71
 
71
72
  if (!result.ok) {
@@ -214,10 +215,11 @@ export function createTreeRouter(baseStore: ReactiveTree, watcher: WatchManager)
214
215
  const userPath = `/auth/users/${input.userId}`;
215
216
  const user = await baseStore.get(userPath);
216
217
  const cv = user ? user['credentials'] : undefined;
217
- const creds = isComponent(cv) ? cv as { $type: string; hash?: string } : undefined;
218
+ const creds = isComponent(cv) ? cv : undefined;
218
219
  // Always run scrypt to prevent timing-based user enumeration
219
- const ok = await verifyPassword(input.password, creds?.hash ?? DUMMY_HASH);
220
- if (!user || !creds?.hash || !ok) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Invalid credentials' });
220
+ const hash = typeof creds?.['hash'] === 'string' ? creds['hash'] : undefined;
221
+ const ok = await verifyPassword(input.password, hash ?? DUMMY_HASH);
222
+ if (!user || !hash || !ok) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Invalid credentials' });
221
223
  const token = await createSession(baseStore, input.userId);
222
224
  return { token, userId: input.userId };
223
225
  }),
@@ -227,6 +229,10 @@ export function createTreeRouter(baseStore: ReactiveTree, watcher: WatchManager)
227
229
  return { userId: ctx.session.userId };
228
230
  }),
229
231
 
232
+ getPerm: authed
233
+ .input(z.object({ path: z.string() }))
234
+ .query(async ({ input, ctx }) => ctx.store.getPerm(input.path)),
235
+
230
236
  logout: authed.mutation(async ({ ctx }) => {
231
237
  if (!ctx.session || !ctx.token) return { ok: false };
232
238
  await revokeSession(baseStore, ctx.token);
package/src/tree/fs.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  // Auto-promotes leaf→dir when children appear, demotes dir→leaf when last child removed.
5
5
 
6
6
  import type { NodeData } from '#core';
7
- import { dirname as treeDirname, isChildPath } from '#core/path';
7
+ import { dirname as treeDirname } from '#core/path';
8
8
  import { mkdir, readdir, readFile, rmdir, unlink, writeFile } from 'node:fs/promises';
9
9
  import { dirname, join, resolve } from 'node:path';
10
10
  import sift from 'sift';
@@ -128,10 +128,12 @@ export async function createFsTree(rootDir: string): Promise<Tree> {
128
128
  }
129
129
  }
130
130
 
131
- // Walk all nodes in both forms
132
- async function allNodes(): Promise<NodeData[]> {
131
+ // Collect children of a tree path up to given depth by walking only the relevant FS subtree
132
+ async function collectChildren(parent: string, depth: number): Promise<NodeData[]> {
133
133
  const results: NodeData[] = [];
134
- async function walk(dir: string) {
134
+ const fsDir = resolve(join(rootDir, parent));
135
+
136
+ async function walk(dir: string, currentDepth: number) {
135
137
  let entries;
136
138
  try { entries = await readdir(dir, { withFileTypes: true }); } catch (e: any) {
137
139
  if (e.code === 'ENOENT') return;
@@ -139,14 +141,24 @@ export async function createFsTree(rootDir: string): Promise<Tree> {
139
141
  }
140
142
 
141
143
  for (const e of entries) {
144
+ if (e.name === '$.json') continue; // parent's own data, not a child
142
145
  const full = join(dir, e.name);
143
- if (e.isDirectory()) { await walk(full); continue; }
144
- if (e.name.endsWith('.json')) {
145
- results.push(JSON.parse(await readFile(full, 'utf-8')));
146
+
147
+ if (e.isDirectory()) {
148
+ // Directory child — read its $.json if exists
149
+ const childPath = full.slice(rootDir.length) || '/';
150
+ const node = await readNode(childPath);
151
+ if (node) results.push(node);
152
+ if (currentDepth < depth) await walk(full, currentDepth + 1);
153
+ } else if (e.name.endsWith('.json')) {
154
+ // Leaf child — name.json
155
+ const node: NodeData = JSON.parse(await readFile(full, 'utf-8'));
156
+ results.push(node);
146
157
  }
147
158
  }
148
159
  }
149
- await walk(rootDir);
160
+
161
+ await walk(fsDir, 1);
150
162
  return results;
151
163
  }
152
164
 
@@ -157,13 +169,7 @@ export async function createFsTree(rootDir: string): Promise<Tree> {
157
169
 
158
170
  async getChildren(parent, opts) {
159
171
  const depth = opts?.depth ?? 1;
160
- const all = await allNodes();
161
- let filtered = all.filter((n) => {
162
- if (!isChildPath(parent, n.$path, false)) return false;
163
- if (depth === Infinity) return true;
164
- const rest = parent === '/' ? n.$path.slice(1) : n.$path.slice(parent.length + 1);
165
- return rest.split('/').length <= depth;
166
- });
172
+ let filtered = await collectChildren(parent, depth);
167
173
  if (opts?.query) {
168
174
  const test = sift(opts.query);
169
175
  filtered = filtered.filter(n => test(mapNodeForSift(n)));
@@ -106,6 +106,32 @@ describe('MemoryStore', () => {
106
106
  assert.deepEqual(result.items, all.items.slice(1, 3));
107
107
  });
108
108
 
109
+ it('get returns isolated copy — mutating result does not affect stored node', async () => {
110
+ const store = createMemoryTree();
111
+ await store.set(createNode('/x', 'item', { tags: ['a', 'b'] }));
112
+
113
+ const copy = await store.get('/x') as any;
114
+ copy.tags.push('mutated');
115
+ copy.extra = 'injected';
116
+
117
+ const stored = await store.get('/x') as any;
118
+ assert.deepEqual(stored.tags, ['a', 'b']);
119
+ assert.equal(stored.extra, undefined);
120
+ });
121
+
122
+ it('set stores isolated copy — mutating original after set does not affect stored node', async () => {
123
+ const store = createMemoryTree();
124
+ const node = createNode('/y', 'item', { value: 1 }) as any;
125
+ await store.set(node);
126
+
127
+ node.value = 999;
128
+ node.injected = true;
129
+
130
+ const stored = await store.get('/y') as any;
131
+ assert.equal(stored.value, 1);
132
+ assert.equal(stored.injected, undefined);
133
+ });
134
+
109
135
  });
110
136
 
111
137
  describe('OverlayStore', () => {
package/src/tree/index.ts CHANGED
@@ -165,7 +165,8 @@ export function createMemoryTree(): Tree {
165
165
  return {
166
166
  async get(path, _ctx) {
167
167
  if (typeof path !== 'string') throw new Error(`store.get: path must be string, got ${typeof path}`);
168
- return navigate(path)?.data;
168
+ const data = navigate(path)?.data;
169
+ return data ? structuredClone(data) : data;
169
170
  },
170
171
 
171
172
  async getChildren(parent, opts, _ctx) {
@@ -1,11 +1,11 @@
1
- import assert from 'node:assert/strict'
2
- import { describe, test } from 'node:test'
3
- import { createMemoryTree } from '#tree'
4
- import { register } from '#core'
5
- import { registerType } from '#comp'
6
- import { type TypedRef, refVal } from '#chain'
7
- import { isRef } from '#core'
8
- import type { Tree } from '#tree'
1
+ import { refVal, type TypedRef } from '#chain';
2
+ import { registerType } from '#comp';
3
+ import { isRef } from '#core';
4
+ import type { Tree } from '#tree';
5
+ import { createMemoryTree } from '#tree';
6
+ import assert from 'node:assert/strict';
7
+ import { describe, test } from 'node:test';
8
+ import { treeChain } from './tree-chain';
9
9
 
10
10
  // ── Test types ──
11
11
 
@@ -14,12 +14,17 @@ class Scanner {
14
14
  intervalMs = 900_000
15
15
  maxRetries = 3
16
16
  livePrices: TypedRef<LivePrices> = refVal(LivePrices)
17
+ scan() { return { started: true } }
18
+ configure(data: { interval: number }) { return data }
17
19
  }
18
20
  registerType('tch.scanner', Scanner)
19
21
 
20
22
  class LivePrices {
21
23
  static $type = 'tch.live-prices'
22
24
  feederUrl = 'ws://localhost:8090'
25
+ subscribe(data: { slugs: string[] }) {
26
+ return data.slugs.map((s: string) => ({ slug: s, bid: 0.6 }))
27
+ }
23
28
  }
24
29
  registerType('tch.live-prices', LivePrices)
25
30
 
@@ -37,14 +42,6 @@ class Wallet {
37
42
  }
38
43
  registerType('tch.wallet', Wallet)
39
44
 
40
- // ── Register actions ──
41
-
42
- register('tch.scanner', 'action:scan', () => ({ started: true }))
43
- register('tch.scanner', 'action:configure', (_ctx: any, data: any) => data)
44
- register('tch.live-prices', 'action:subscribe', (_ctx: any, data: any) =>
45
- data.slugs.map((s: string) => ({ slug: s, bid: 0.6 })),
46
- )
47
-
48
45
  // ── Seed ──
49
46
 
50
47
  async function seed(): Promise<Tree> {
@@ -80,8 +77,6 @@ async function seed(): Promise<Tree> {
80
77
  return tree
81
78
  }
82
79
 
83
- import { treeChain } from './tree-chain'
84
-
85
80
  describe('treeChain — path building', () => {
86
81
  test('$path from dot navigation', () => {
87
82
  const c = treeChain(null as any)
@@ -133,9 +128,9 @@ describe('treeChain — $get (typed component)', () => {
133
128
  assert.equal(scanner.maxRetries, 3)
134
129
  })
135
130
 
136
- test('$get with named component', async () => {
131
+ test('$field with named component', async () => {
137
132
  const tree = await seed()
138
- const wallet = await treeChain(tree).users.alice.$get(null, 'wallet')
133
+ const wallet = await treeChain(tree).users.alice.$field('wallet')
139
134
  assert.equal(wallet.address, '0xabc')
140
135
  })
141
136
 
@@ -290,6 +285,8 @@ class BoardTask {
290
285
  title = ''
291
286
  status = 'backlog'
292
287
  priority = 'normal'
288
+ move(data: { status: string }) { return { moved: data.status } }
289
+ assign(data: { to: string }) { return { assigned: data.to } }
293
290
  }
294
291
  registerType('tch.board.task', BoardTask)
295
292
 
@@ -316,13 +313,10 @@ class BrahmanBot {
316
313
  static $type = 'tch.brahman.bot'
317
314
  alias = ''
318
315
  running = false
316
+ restart() { return { restarted: true } }
319
317
  }
320
318
  registerType('tch.brahman.bot', BrahmanBot)
321
319
 
322
- register('tch.board.task', 'action:move', (_ctx: any, data: any) => ({ moved: data.status }))
323
- register('tch.board.task', 'action:assign', (_ctx: any, data: any) => ({ assigned: data.to }))
324
- register('tch.brahman.bot', 'action:restart', () => ({ restarted: true }))
325
-
326
320
  async function seedRealWorld(): Promise<Tree> {
327
321
  const tree = createMemoryTree()
328
322
 
@@ -557,22 +551,17 @@ describe('treeChain — $set', () => {
557
551
  })
558
552
 
559
553
  describe('treeChain — Symbol traps', () => {
560
- test('Symbol.toPrimitive returns TreeChain(path)', () => {
561
- const c = treeChain(null as any)
562
- assert.equal(c.services.scanner[Symbol.toPrimitive], 'TreeChain(/services/scanner)')
563
- })
564
-
565
554
  test('Symbol.toPrimitive on root', () => {
566
- assert.equal(treeChain(null as any)[Symbol.toPrimitive], 'TreeChain(/)')
555
+ assert.equal((treeChain(null as any) as any)[Symbol.toPrimitive], 'TreeChain(/)')
567
556
  })
568
557
 
569
558
  test('Symbol.toStringTag', () => {
570
- const c = treeChain(null as any).foo
571
- assert.equal(c[Symbol.toStringTag], 'TreeChain(/foo)')
559
+ const c = treeChain(null as any) as any
560
+ assert.equal(c.foo[Symbol.toStringTag], 'TreeChain(/foo)')
572
561
  })
573
562
 
574
563
  test('other symbols return undefined', () => {
575
- const c = treeChain(null as any)
564
+ const c = treeChain(null as any) as any
576
565
  assert.equal(c[Symbol.iterator], undefined)
577
566
  assert.equal(c[Symbol.asyncIterator], undefined)
578
567
  })
@@ -601,32 +590,35 @@ describe('treeChain — basePath edge cases', () => {
601
590
  describe('treeChain — error paths', () => {
602
591
  test('action without (Class) throws', async () => {
603
592
  const tree = await seed()
593
+ const t = treeChain(tree) as any
604
594
  await assert.rejects(
605
- async () => { await treeChain(tree).services.scanner.scan() },
595
+ async () => { await t.services.scanner.scan() },
606
596
  (e: Error) => e.message.includes('Class'),
607
597
  )
608
598
  })
609
599
 
610
600
  test('unregistered action throws', async () => {
611
601
  const tree = await seed()
602
+ const t = treeChain(tree) as any
612
603
  await assert.rejects(
613
- async () => { await treeChain(tree).services.scanner(Scanner).nonexistent() },
604
+ async () => { await t.services.scanner(Scanner).nonexistent() },
614
605
  (e: Error) => e.message.includes('action'),
615
606
  )
616
607
  })
617
608
 
618
609
  test('null field in ops throws', async () => {
619
610
  const tree = await seed()
611
+ const t = treeChain(tree) as any
620
612
  await assert.rejects(
621
- async () => { await treeChain(tree).services.scanner.$get(Scanner).noSuchField },
613
+ async () => { await t.services.scanner.$get(Scanner).noSuchField },
622
614
  (e: Error) => e.message.includes('null'),
623
615
  )
624
616
  })
625
617
 
626
- test('$get with missing named component throws', async () => {
618
+ test('$field with missing named component throws', async () => {
627
619
  const tree = await seed()
628
620
  await assert.rejects(
629
- async () => { await treeChain(tree).services.scanner.$get(null, 'ghost') },
621
+ async () => { await treeChain(tree).services.scanner.$field('ghost') },
630
622
  (e: Error) => e.message.includes('ghost'),
631
623
  )
632
624
  })
@@ -638,14 +630,15 @@ describe('treeChain — error paths', () => {
638
630
  })
639
631
 
640
632
  describe('treeChain — (Class) where node.$type matches', () => {
641
- test('getComp returns node itself when $type matches', async () => {
633
+ test('getComponent returns node itself when $type matches', async () => {
642
634
  const tree = await seed()
643
635
  // scanner.$type === 'tch.scanner', Scanner.$type === 'tch.scanner'
644
- // getComp returns node itself — all fields at node level
636
+ // getComponent returns node itself — all fields at node level
637
+ const node = await treeChain(tree).services.scanner
638
+ assert.equal(node.$type, 'tch.scanner')
639
+ assert.equal(node.$path, '/services/scanner')
645
640
  const scanner = await treeChain(tree).services.scanner(Scanner)
646
- assert.equal(scanner.$type, 'tch.scanner')
647
641
  assert.equal(scanner.intervalMs, 900_000)
648
- assert.equal(scanner.$path, '/services/scanner')
649
642
  })
650
643
  })
651
644
 
@@ -690,7 +683,7 @@ describe('treeChain — multiple ops chain', () => {
690
683
  await tree.set({ $path: '/lp', $type: 'tch.live-prices', feederUrl: 'ws://chain' })
691
684
 
692
685
  // $get → field (nested component, not a ref) → field
693
- const chain = await treeChain(tree).config.$get(null, 'nested').chain
686
+ const chain = await treeChain(tree).config.$field('nested').chain
694
687
  assert.equal(chain, 'polygon')
695
688
  })
696
689
  })
@@ -700,7 +693,7 @@ describe('treeChain — chain isolation', () => {
700
693
  const tree = await seed()
701
694
  const t = treeChain(tree)
702
695
 
703
- const chain1 = t.services.scanner.$get(Scanner)
696
+ const chain1 = t.services.scanner
704
697
  const chain2 = t.services['live-prices']
705
698
 
706
699
  const s = await chain1
package/src/tree-chain.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  // Navigate tree via dots, auto-follow refs, execute actions, typed components.
3
3
  // Layer L2: uses Tree (L1) + comp (L2). No server dependency.
4
4
 
5
- import { isComponent, isRef, normalizeType, resolve, type NodeData } from '#core'
6
- import { getComp, type Class, type TypeClass, type Raw } from '#comp'
7
- import type { Tree } from '#tree'
8
- import type { Chain } from './chain'
5
+ import { type Class, type Raw, type TypeClass } from '#comp';
6
+ import { getComponent, isComponent, isRef, type NodeData, normalizeType, resolve } from '#core';
7
+ import type { Tree } from '#tree';
8
+ import type { Chain } from './chain';
9
9
 
10
10
  type Spec = { cls: Class | null; key?: string }
11
11
  type Op = string | [string, unknown[]]
@@ -19,6 +19,7 @@ type TreeChainAPI = {
19
19
  <T>(cls: TypeClass<T>): Chain<T>
20
20
  readonly $path: string
21
21
  $get<T>(cls: Class<T>, key?: string): Chain<T>
22
+ $field(key: string): Chain<any>
22
23
  $children(query?: Record<string, unknown>): Promise<NodeData[]>
23
24
  $set<T>(cls: Class<T>, data?: Partial<Raw<T>>): Promise<void>
24
25
  then<R1 = NodeData, R2 = never>(
@@ -47,7 +48,7 @@ async function exec(tree: Tree, path: string, spec: Spec | null, ops: Op[]): Pro
47
48
  cur = ck
48
49
  curType = cur.$type
49
50
  } else if (spec.cls) {
50
- const comp = getComp(node, spec.cls)
51
+ const comp = getComponent(node, spec.cls)
51
52
  if (!comp) throw new Error(`Type "${normalizeType(spec.cls)}" not found on ${path}`)
52
53
  cur = comp
53
54
  curType = comp.$type ?? curType
@@ -97,6 +98,11 @@ function make(tree: Tree, path: string, spec: Spec | null, ops: Op[]): any {
97
98
  make(tree, path, { cls, key }, NO_OPS)
98
99
  }
99
100
 
101
+ if (p === '$field') {
102
+ return (key: string) =>
103
+ make(tree, path, { cls: null, key }, NO_OPS)
104
+ }
105
+
100
106
  if (p === '$children') {
101
107
  return (query?: Record<string, unknown>) =>
102
108
  tree.getChildren(path, query ? { query } : undefined).then(r => r.items)
package/src/uri.test.ts CHANGED
@@ -3,22 +3,22 @@ import { describe, it } from 'node:test';
3
3
  import { parseURI } from './uri';
4
4
 
5
5
  describe('parseURI', () => {
6
- it('read field on $type', () => {
6
+ it('#name = key (component/field access)', () => {
7
7
  const r = parseURI('/sys/types/cafe/contact#schema')
8
- assert.deepEqual(r, { path: '/sys/types/cafe/contact', field: 'schema' })
8
+ assert.deepEqual(r, { path: '/sys/types/cafe/contact', key: 'schema' })
9
9
  })
10
10
 
11
- it('read field on named component', () => {
11
+ it('#key.field = sub-field within component', () => {
12
12
  const r = parseURI('/users/me#profile.email')
13
13
  assert.deepEqual(r, { path: '/users/me', key: 'profile', field: 'email' })
14
14
  })
15
15
 
16
- it('action without key', () => {
16
+ it('#action() = node-level action (no key)', () => {
17
17
  const r = parseURI('/cafe/contact#submit()')
18
18
  assert.deepEqual(r, { path: '/cafe/contact', action: 'submit' })
19
19
  })
20
20
 
21
- it('action on named component', () => {
21
+ it('#key.action() = action on named component', () => {
22
22
  const r = parseURI('/cafe/contact#contact.submit()')
23
23
  assert.deepEqual(r, { path: '/cafe/contact', key: 'contact', action: 'submit' })
24
24
  })
@@ -83,4 +83,31 @@ describe('parseURI', () => {
83
83
  const r = parseURI('/x#submit()')
84
84
  assert.equal(r.data, undefined)
85
85
  })
86
+
87
+ it('#key does not set field or action', () => {
88
+ const r = parseURI('/x#view')
89
+ assert.equal(r.key, 'view')
90
+ assert.equal(r.field, undefined)
91
+ assert.equal(r.action, undefined)
92
+ })
93
+
94
+ it('#key.field does not set action', () => {
95
+ const r = parseURI('/x#profile.name')
96
+ assert.equal(r.key, 'profile')
97
+ assert.equal(r.field, 'name')
98
+ assert.equal(r.action, undefined)
99
+ })
100
+
101
+ it('#action() does not set key', () => {
102
+ const r = parseURI('/x#run()')
103
+ assert.equal(r.action, 'run')
104
+ assert.equal(r.key, undefined)
105
+ })
106
+
107
+ it('#key.action() sets both key and action', () => {
108
+ const r = parseURI('/x#comp.run()')
109
+ assert.equal(r.key, 'comp')
110
+ assert.equal(r.action, 'run')
111
+ assert.equal(r.field, undefined)
112
+ })
86
113
  })
package/src/uri.ts CHANGED
@@ -29,10 +29,12 @@ export function parseURI(uri: string): TreenityURI {
29
29
  const dot = clean.indexOf('.')
30
30
  const key = dot > -1 ? clean.slice(0, dot) : undefined
31
31
  const name = dot > -1 ? clean.slice(dot + 1) : clean
32
- if (!name) throw new Error('Empty name in URI fragment')
32
+ if (dot > -1 && !name) throw new Error('Empty name in URI fragment')
33
33
 
34
34
  if (key) result.key = key
35
- if (isCall) result.action = name; else result.field = name
35
+ if (isCall) { result.action = name }
36
+ else if (key) { result.field = name }
37
+ else { result.key = name }
36
38
  }
37
39
 
38
40
  const data = url.search ? expandDots(url.searchParams) : undefined
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mods/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,CAAC;AACjB,OAAO,WAAW,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mods/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,CAAC;AACjB,OAAO,WAAW,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/mods/mcp/service.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/mods/mcp/service.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAE9E,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,QAAQ,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IACpD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAEpD,OAAO;QACL,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC;KACF,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/mods/mcp/types.ts"],"names":[],"mappings":"AAEA,sEAAsE;AACtE,qBAAa,SAAS;IACpB,IAAI,SAAQ;CACb"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/mods/mcp/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAErC,sEAAsE;AACtE,MAAM,OAAO,SAAS;IACpB,IAAI,GAAG,IAAI,CAAC;CACb;AACD,YAAY,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC"}
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env tsx
2
- export {};
3
- //# sourceMappingURL=test-opaque.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-opaque.d.ts","sourceRoot":"","sources":["../../src/schema/test-opaque.ts"],"names":[],"mappings":""}
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env tsx
2
- // Quick test: does getAliasedSymbol resolve import to original @opaque decl?
3
- import * as ts from 'typescript';
4
- import * as path from 'node:path';
5
- const tsconfigPath = path.resolve(import.meta.dirname, '../../../tsconfig.json');
6
- const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
7
- const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(tsconfigPath));
8
- const program = ts.createProgram(parsed.fileNames, parsed.options);
9
- const checker = program.getTypeChecker();
10
- for (const sf of program.getSourceFiles()) {
11
- if (!sf.fileName.includes('brahman/types'))
12
- continue;
13
- ts.forEachChild(sf, (node) => {
14
- if (!ts.isClassDeclaration(node) || !node.name)
15
- return;
16
- if (node.name.text !== 'MessageAction')
17
- return;
18
- for (const member of node.members) {
19
- if (!ts.isMethodDeclaration(member) || !member.name || !ts.isIdentifier(member.name))
20
- continue;
21
- if (member.name.text !== 'run')
22
- continue;
23
- const param = member.parameters[0];
24
- if (!param?.type || !ts.isTypeReferenceNode(param.type)) {
25
- console.log('no type ref');
26
- return;
27
- }
28
- let sym = checker.getSymbolAtLocation(param.type.typeName);
29
- console.log('sym:', sym?.name, 'flags:', sym?.flags, 'isAlias:', !!(sym?.flags & ts.SymbolFlags.Alias));
30
- if (sym?.flags & ts.SymbolFlags.Alias) {
31
- sym = checker.getAliasedSymbol(sym);
32
- console.log('aliased to:', sym?.name, 'decls:', sym?.declarations?.length);
33
- const decl = sym?.declarations?.[0];
34
- if (decl) {
35
- console.log('decl kind:', ts.SyntaxKind[decl.kind], 'at', path.basename(decl.getSourceFile().fileName));
36
- console.log('JSDoc tags:', ts.getJSDocTags(decl).map(t => t.tagName.text));
37
- }
38
- }
39
- }
40
- });
41
- break;
42
- }
43
- //# sourceMappingURL=test-opaque.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-opaque.js","sourceRoot":"","sources":["../../src/schema/test-opaque.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/server/mcp.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAGlC,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AA+QtD,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CA4CrE"}