patchwork-os 0.2.0-beta.1 → 0.2.0-beta.10.canary.95

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 (652) hide show
  1. package/README.bridge.md +14 -14
  2. package/README.md +201 -34
  3. package/deploy/README.md +1 -1
  4. package/deploy/bootstrap-vps.sh +14 -9
  5. package/deploy/deploy-dashboard.sh +25 -1
  6. package/deploy/macos/README.md +153 -0
  7. package/deploy/macos/com.patchwork.bridge.plist.template +54 -0
  8. package/deploy/macos/com.patchwork.tunnel.plist.template +76 -0
  9. package/deploy/macos/install-mac-bridge.sh +244 -0
  10. package/deploy/macos/uninstall-mac-bridge.sh +22 -0
  11. package/dist/activityLog.d.ts +6 -0
  12. package/dist/activityLog.js +63 -26
  13. package/dist/activityLog.js.map +1 -1
  14. package/dist/adapters/claude.js +22 -16
  15. package/dist/adapters/claude.js.map +1 -1
  16. package/dist/adapters/gemini.js +15 -11
  17. package/dist/adapters/gemini.js.map +1 -1
  18. package/dist/adapters/openai.js +9 -9
  19. package/dist/adapters/openai.js.map +1 -1
  20. package/dist/ajv2020.d.ts +25 -0
  21. package/dist/ajv2020.js +33 -0
  22. package/dist/ajv2020.js.map +1 -0
  23. package/dist/analyticsAggregator.js +1 -1
  24. package/dist/analyticsAggregator.js.map +1 -1
  25. package/dist/analyticsConfig.d.ts +29 -0
  26. package/dist/analyticsConfig.js +102 -0
  27. package/dist/analyticsConfig.js.map +1 -0
  28. package/dist/analyticsPrefs.d.ts +38 -2
  29. package/dist/analyticsPrefs.js +148 -23
  30. package/dist/analyticsPrefs.js.map +1 -1
  31. package/dist/analyticsSend.d.ts +17 -1
  32. package/dist/analyticsSend.js +67 -5
  33. package/dist/analyticsSend.js.map +1 -1
  34. package/dist/approvalHttp.d.ts +14 -0
  35. package/dist/approvalHttp.js +212 -9
  36. package/dist/approvalHttp.js.map +1 -1
  37. package/dist/approvalInsights.js +13 -5
  38. package/dist/approvalInsights.js.map +1 -1
  39. package/dist/approvalQueue.d.ts +97 -3
  40. package/dist/approvalQueue.js +193 -19
  41. package/dist/approvalQueue.js.map +1 -1
  42. package/dist/approvalSignals.js +19 -11
  43. package/dist/approvalSignals.js.map +1 -1
  44. package/dist/automation.d.ts +35 -10
  45. package/dist/automation.js +133 -37
  46. package/dist/automation.js.map +1 -1
  47. package/dist/automationSuggestions.js +10 -8
  48. package/dist/automationSuggestions.js.map +1 -1
  49. package/dist/bridge.d.ts +2 -0
  50. package/dist/bridge.js +202 -25
  51. package/dist/bridge.js.map +1 -1
  52. package/dist/bridgeLockDiscovery.d.ts +27 -1
  53. package/dist/bridgeLockDiscovery.js +38 -11
  54. package/dist/bridgeLockDiscovery.js.map +1 -1
  55. package/dist/bridgeToken.js +3 -2
  56. package/dist/bridgeToken.js.map +1 -1
  57. package/dist/claudeDriver.js +23 -8
  58. package/dist/claudeDriver.js.map +1 -1
  59. package/dist/claudeOrchestrator.d.ts +1 -1
  60. package/dist/claudeOrchestrator.js +87 -44
  61. package/dist/claudeOrchestrator.js.map +1 -1
  62. package/dist/commands/analytics.d.ts +8 -0
  63. package/dist/commands/analytics.js +134 -0
  64. package/dist/commands/analytics.js.map +1 -0
  65. package/dist/commands/auditEnv.d.ts +36 -0
  66. package/dist/commands/auditEnv.js +202 -0
  67. package/dist/commands/auditEnv.js.map +1 -0
  68. package/dist/commands/dashboard.js +8 -1
  69. package/dist/commands/dashboard.js.map +1 -1
  70. package/dist/commands/doctor.d.ts +35 -0
  71. package/dist/commands/doctor.js +51 -0
  72. package/dist/commands/doctor.js.map +1 -0
  73. package/dist/commands/install.js +3 -0
  74. package/dist/commands/install.js.map +1 -1
  75. package/dist/commands/launchd.js +15 -16
  76. package/dist/commands/launchd.js.map +1 -1
  77. package/dist/commands/patchworkInit.d.ts +5 -0
  78. package/dist/commands/patchworkInit.js +89 -7
  79. package/dist/commands/patchworkInit.js.map +1 -1
  80. package/dist/commands/recipe.d.ts +110 -0
  81. package/dist/commands/recipe.js +512 -9
  82. package/dist/commands/recipe.js.map +1 -1
  83. package/dist/commands/recipeInstall.js +11 -4
  84. package/dist/commands/recipeInstall.js.map +1 -1
  85. package/dist/commands/shadowScan.d.ts +34 -0
  86. package/dist/commands/shadowScan.js +142 -0
  87. package/dist/commands/shadowScan.js.map +1 -0
  88. package/dist/commands/task.js +2 -2
  89. package/dist/commands/task.js.map +1 -1
  90. package/dist/commands/tools.d.ts +20 -1
  91. package/dist/commands/tools.js +112 -3
  92. package/dist/commands/tools.js.map +1 -1
  93. package/dist/commands/tracesImport.js +21 -4
  94. package/dist/commands/tracesImport.js.map +1 -1
  95. package/dist/commitIssueLinkLog.d.ts +16 -0
  96. package/dist/commitIssueLinkLog.js +110 -24
  97. package/dist/commitIssueLinkLog.js.map +1 -1
  98. package/dist/companions/registry.js +15 -7
  99. package/dist/companions/registry.js.map +1 -1
  100. package/dist/config.d.ts +47 -3
  101. package/dist/config.js +111 -21
  102. package/dist/config.js.map +1 -1
  103. package/dist/connectorRoutes.js +866 -57
  104. package/dist/connectorRoutes.js.map +1 -1
  105. package/dist/connectors/airtable.d.ts +230 -0
  106. package/dist/connectors/airtable.js +700 -0
  107. package/dist/connectors/airtable.js.map +1 -0
  108. package/dist/connectors/asana.js +13 -9
  109. package/dist/connectors/asana.js.map +1 -1
  110. package/dist/connectors/baseConnector.js +25 -3
  111. package/dist/connectors/baseConnector.js.map +1 -1
  112. package/dist/connectors/caldiy.d.ts +137 -0
  113. package/dist/connectors/caldiy.js +424 -0
  114. package/dist/connectors/caldiy.js.map +1 -0
  115. package/dist/connectors/circleci.d.ts +162 -0
  116. package/dist/connectors/circleci.js +576 -0
  117. package/dist/connectors/circleci.js.map +1 -0
  118. package/dist/connectors/cloudflare.d.ts +132 -0
  119. package/dist/connectors/cloudflare.js +622 -0
  120. package/dist/connectors/cloudflare.js.map +1 -0
  121. package/dist/connectors/confluence.js +35 -0
  122. package/dist/connectors/confluence.js.map +1 -1
  123. package/dist/connectors/connectorRedirectUri.d.ts +30 -0
  124. package/dist/connectors/connectorRedirectUri.js +38 -0
  125. package/dist/connectors/connectorRedirectUri.js.map +1 -0
  126. package/dist/connectors/connectorRegistry.d.ts +63 -0
  127. package/dist/connectors/connectorRegistry.js +354 -0
  128. package/dist/connectors/connectorRegistry.js.map +1 -0
  129. package/dist/connectors/datadog.js +33 -4
  130. package/dist/connectors/datadog.js.map +1 -1
  131. package/dist/connectors/discord.js +14 -10
  132. package/dist/connectors/discord.js.map +1 -1
  133. package/dist/connectors/elasticsearch.d.ts +141 -0
  134. package/dist/connectors/elasticsearch.js +601 -0
  135. package/dist/connectors/elasticsearch.js.map +1 -0
  136. package/dist/connectors/figma.d.ts +130 -0
  137. package/dist/connectors/figma.js +387 -0
  138. package/dist/connectors/figma.js.map +1 -0
  139. package/dist/connectors/github.d.ts +17 -0
  140. package/dist/connectors/github.js +53 -2
  141. package/dist/connectors/github.js.map +1 -1
  142. package/dist/connectors/gitlab.js +12 -6
  143. package/dist/connectors/gitlab.js.map +1 -1
  144. package/dist/connectors/gmail.js +72 -21
  145. package/dist/connectors/gmail.js.map +1 -1
  146. package/dist/connectors/googleCalendar.js +8 -8
  147. package/dist/connectors/googleCalendar.js.map +1 -1
  148. package/dist/connectors/googleDocs.d.ts +103 -0
  149. package/dist/connectors/googleDocs.js +409 -0
  150. package/dist/connectors/googleDocs.js.map +1 -0
  151. package/dist/connectors/googleDrive.d.ts +12 -0
  152. package/dist/connectors/googleDrive.js +35 -8
  153. package/dist/connectors/googleDrive.js.map +1 -1
  154. package/dist/connectors/grafana.d.ts +133 -0
  155. package/dist/connectors/grafana.js +478 -0
  156. package/dist/connectors/grafana.js.map +1 -0
  157. package/dist/connectors/jira.d.ts +25 -0
  158. package/dist/connectors/jira.js +227 -1
  159. package/dist/connectors/jira.js.map +1 -1
  160. package/dist/connectors/linear.js +1 -1
  161. package/dist/connectors/linear.js.map +1 -1
  162. package/dist/connectors/mcpOAuth.js +78 -16
  163. package/dist/connectors/mcpOAuth.js.map +1 -1
  164. package/dist/connectors/monday.d.ts +217 -0
  165. package/dist/connectors/monday.js +655 -0
  166. package/dist/connectors/monday.js.map +1 -0
  167. package/dist/connectors/mongodb.d.ts +139 -0
  168. package/dist/connectors/mongodb.js +455 -0
  169. package/dist/connectors/mongodb.js.map +1 -0
  170. package/dist/connectors/oauthStateStore.d.ts +20 -0
  171. package/dist/connectors/oauthStateStore.js +94 -4
  172. package/dist/connectors/oauthStateStore.js.map +1 -1
  173. package/dist/connectors/obsidian.d.ts +83 -0
  174. package/dist/connectors/obsidian.js +441 -0
  175. package/dist/connectors/obsidian.js.map +1 -0
  176. package/dist/connectors/paystack.d.ts +159 -0
  177. package/dist/connectors/paystack.js +607 -0
  178. package/dist/connectors/paystack.js.map +1 -0
  179. package/dist/connectors/pipedrive.d.ts +189 -0
  180. package/dist/connectors/pipedrive.js +559 -0
  181. package/dist/connectors/pipedrive.js.map +1 -0
  182. package/dist/connectors/postgres.d.ts +127 -0
  183. package/dist/connectors/postgres.js +512 -0
  184. package/dist/connectors/postgres.js.map +1 -0
  185. package/dist/connectors/posthog.d.ts +119 -0
  186. package/dist/connectors/posthog.js +479 -0
  187. package/dist/connectors/posthog.js.map +1 -0
  188. package/dist/connectors/redis.d.ts +140 -0
  189. package/dist/connectors/redis.js +571 -0
  190. package/dist/connectors/redis.js.map +1 -0
  191. package/dist/connectors/resend.d.ts +131 -0
  192. package/dist/connectors/resend.js +529 -0
  193. package/dist/connectors/resend.js.map +1 -0
  194. package/dist/connectors/salesforce.d.ts +136 -0
  195. package/dist/connectors/salesforce.js +603 -0
  196. package/dist/connectors/salesforce.js.map +1 -0
  197. package/dist/connectors/secrets.d.ts +51 -0
  198. package/dist/connectors/secrets.js +102 -0
  199. package/dist/connectors/secrets.js.map +1 -0
  200. package/dist/connectors/sendgrid.d.ts +102 -0
  201. package/dist/connectors/sendgrid.js +423 -0
  202. package/dist/connectors/sendgrid.js.map +1 -0
  203. package/dist/connectors/shopify.d.ts +145 -0
  204. package/dist/connectors/shopify.js +502 -0
  205. package/dist/connectors/shopify.js.map +1 -0
  206. package/dist/connectors/slack.d.ts +1 -1
  207. package/dist/connectors/slack.js +61 -9
  208. package/dist/connectors/slack.js.map +1 -1
  209. package/dist/connectors/snowflake.d.ts +119 -0
  210. package/dist/connectors/snowflake.js +615 -0
  211. package/dist/connectors/snowflake.js.map +1 -0
  212. package/dist/connectors/supabase.d.ts +92 -0
  213. package/dist/connectors/supabase.js +630 -0
  214. package/dist/connectors/supabase.js.map +1 -0
  215. package/dist/connectors/todoist.d.ts +117 -0
  216. package/dist/connectors/todoist.js +485 -0
  217. package/dist/connectors/todoist.js.map +1 -0
  218. package/dist/connectors/tokenStorage.js +56 -14
  219. package/dist/connectors/tokenStorage.js.map +1 -1
  220. package/dist/connectors/twilio.d.ts +118 -0
  221. package/dist/connectors/twilio.js +475 -0
  222. package/dist/connectors/twilio.js.map +1 -0
  223. package/dist/connectors/vercel.d.ts +110 -0
  224. package/dist/connectors/vercel.js +479 -0
  225. package/dist/connectors/vercel.js.map +1 -0
  226. package/dist/connectors/webflow.d.ts +118 -0
  227. package/dist/connectors/webflow.js +393 -0
  228. package/dist/connectors/webflow.js.map +1 -0
  229. package/dist/connectors/woocommerce.d.ts +220 -0
  230. package/dist/connectors/woocommerce.js +464 -0
  231. package/dist/connectors/woocommerce.js.map +1 -0
  232. package/dist/crypto.js +7 -2
  233. package/dist/crypto.js.map +1 -1
  234. package/dist/decisionReplay.js +15 -6
  235. package/dist/decisionReplay.js.map +1 -1
  236. package/dist/decisionTraceLog.d.ts +28 -0
  237. package/dist/decisionTraceLog.js +156 -29
  238. package/dist/decisionTraceLog.js.map +1 -1
  239. package/dist/drivers/claude/api.js +5 -4
  240. package/dist/drivers/claude/api.js.map +1 -1
  241. package/dist/drivers/claude/envSanitizer.d.ts +0 -6
  242. package/dist/drivers/claude/envSanitizer.js +17 -2
  243. package/dist/drivers/claude/envSanitizer.js.map +1 -1
  244. package/dist/drivers/claude/streamParser.js +5 -4
  245. package/dist/drivers/claude/streamParser.js.map +1 -1
  246. package/dist/drivers/claude/subprocess.js +22 -3
  247. package/dist/drivers/claude/subprocess.js.map +1 -1
  248. package/dist/drivers/gemini/index.d.ts +22 -0
  249. package/dist/drivers/gemini/index.js +256 -129
  250. package/dist/drivers/gemini/index.js.map +1 -1
  251. package/dist/drivers/local/index.d.ts +17 -0
  252. package/dist/drivers/local/index.js +99 -0
  253. package/dist/drivers/local/index.js.map +1 -1
  254. package/dist/drivers/openai/index.js +30 -2
  255. package/dist/drivers/openai/index.js.map +1 -1
  256. package/dist/extensionClient.d.ts +37 -4
  257. package/dist/extensionClient.js +58 -16
  258. package/dist/extensionClient.js.map +1 -1
  259. package/dist/featureFlags.d.ts +91 -0
  260. package/dist/featureFlags.js +174 -3
  261. package/dist/featureFlags.js.map +1 -1
  262. package/dist/fileLock.js +21 -12
  263. package/dist/fileLock.js.map +1 -1
  264. package/dist/fileLockSync.d.ts +67 -0
  265. package/dist/fileLockSync.js +126 -0
  266. package/dist/fileLockSync.js.map +1 -0
  267. package/dist/fp/activityAnalytics.js +26 -12
  268. package/dist/fp/activityAnalytics.js.map +1 -1
  269. package/dist/fp/automationInterpreter.d.ts +15 -1
  270. package/dist/fp/automationInterpreter.js +217 -82
  271. package/dist/fp/automationInterpreter.js.map +1 -1
  272. package/dist/fp/automationProgram.d.ts +30 -0
  273. package/dist/fp/automationProgram.js.map +1 -1
  274. package/dist/fp/automationState.d.ts +24 -5
  275. package/dist/fp/automationState.js +56 -9
  276. package/dist/fp/automationState.js.map +1 -1
  277. package/dist/fp/automationUtils.js +1 -1
  278. package/dist/fp/automationUtils.js.map +1 -1
  279. package/dist/fp/commandDescription.js +7 -1
  280. package/dist/fp/commandDescription.js.map +1 -1
  281. package/dist/fp/extensionSnapshot.js +8 -2
  282. package/dist/fp/extensionSnapshot.js.map +1 -1
  283. package/dist/fp/interpreterContext.d.ts +66 -1
  284. package/dist/fp/interpreterContext.js +91 -1
  285. package/dist/fp/interpreterContext.js.map +1 -1
  286. package/dist/fp/policyParser.js +29 -1
  287. package/dist/fp/policyParser.js.map +1 -1
  288. package/dist/fsWatchWithFallback.d.ts +36 -0
  289. package/dist/fsWatchWithFallback.js +128 -0
  290. package/dist/fsWatchWithFallback.js.map +1 -0
  291. package/dist/haltPushDispatch.d.ts +33 -0
  292. package/dist/haltPushDispatch.js +103 -0
  293. package/dist/haltPushDispatch.js.map +1 -0
  294. package/dist/httpBodyValidation.d.ts +41 -0
  295. package/dist/httpBodyValidation.js +45 -0
  296. package/dist/httpBodyValidation.js.map +1 -0
  297. package/dist/inboxRoutes.d.ts +22 -0
  298. package/dist/inboxRoutes.js +61 -1
  299. package/dist/inboxRoutes.js.map +1 -1
  300. package/dist/index.js +1053 -76
  301. package/dist/index.js.map +1 -1
  302. package/dist/installGuard.js +6 -2
  303. package/dist/installGuard.js.map +1 -1
  304. package/dist/lockfile.js +31 -4
  305. package/dist/lockfile.js.map +1 -1
  306. package/dist/oauth.d.ts +9 -0
  307. package/dist/oauth.js +33 -0
  308. package/dist/oauth.js.map +1 -1
  309. package/dist/oauthRoutes.d.ts +1 -1
  310. package/dist/oauthRoutes.js +5 -3
  311. package/dist/oauthRoutes.js.map +1 -1
  312. package/dist/orchestrator/childBridgeRegistry.js +29 -11
  313. package/dist/orchestrator/childBridgeRegistry.js.map +1 -1
  314. package/dist/patchworkConfig.d.ts +44 -1
  315. package/dist/patchworkConfig.js +28 -3
  316. package/dist/patchworkConfig.js.map +1 -1
  317. package/dist/pluginLoader.js +10 -1
  318. package/dist/pluginLoader.js.map +1 -1
  319. package/dist/pluginWatcher.js +12 -14
  320. package/dist/pluginWatcher.js.map +1 -1
  321. package/dist/preToolUseHook.js +3 -2
  322. package/dist/preToolUseHook.js.map +1 -1
  323. package/dist/processTree.d.ts +34 -0
  324. package/dist/processTree.js +105 -0
  325. package/dist/processTree.js.map +1 -0
  326. package/dist/prompts.js +3 -3
  327. package/dist/prompts.js.map +1 -1
  328. package/dist/recipeOrchestration.d.ts +9 -0
  329. package/dist/recipeOrchestration.js +341 -24
  330. package/dist/recipeOrchestration.js.map +1 -1
  331. package/dist/recipeRoutes.d.ts +58 -2
  332. package/dist/recipeRoutes.js +744 -115
  333. package/dist/recipeRoutes.js.map +1 -1
  334. package/dist/recipes/RecipeOrchestrator.d.ts +2 -0
  335. package/dist/recipes/RecipeOrchestrator.js +6 -1
  336. package/dist/recipes/RecipeOrchestrator.js.map +1 -1
  337. package/dist/recipes/agentExecutor.d.ts +25 -5
  338. package/dist/recipes/agentExecutor.js.map +1 -1
  339. package/dist/recipes/chainedRunner.d.ts +2 -0
  340. package/dist/recipes/chainedRunner.js +142 -5
  341. package/dist/recipes/chainedRunner.js.map +1 -1
  342. package/dist/recipes/connectorPreflight.d.ts +66 -0
  343. package/dist/recipes/connectorPreflight.js +169 -0
  344. package/dist/recipes/connectorPreflight.js.map +1 -0
  345. package/dist/recipes/dependencyGraph.js +13 -5
  346. package/dist/recipes/dependencyGraph.js.map +1 -1
  347. package/dist/recipes/githubInstallSource.d.ts +128 -0
  348. package/dist/recipes/githubInstallSource.js +206 -0
  349. package/dist/recipes/githubInstallSource.js.map +1 -0
  350. package/dist/recipes/haltCategory.d.ts +119 -0
  351. package/dist/recipes/haltCategory.js +188 -0
  352. package/dist/recipes/haltCategory.js.map +1 -0
  353. package/dist/recipes/idempotencyKey.d.ts +134 -0
  354. package/dist/recipes/idempotencyKey.js +322 -0
  355. package/dist/recipes/idempotencyKey.js.map +1 -0
  356. package/dist/recipes/installer.js +48 -2
  357. package/dist/recipes/installer.js.map +1 -1
  358. package/dist/recipes/judgeSummary.d.ts +50 -0
  359. package/dist/recipes/judgeSummary.js +47 -0
  360. package/dist/recipes/judgeSummary.js.map +1 -0
  361. package/dist/recipes/judgeVerdict.d.ts +48 -0
  362. package/dist/recipes/judgeVerdict.js +174 -0
  363. package/dist/recipes/judgeVerdict.js.map +1 -0
  364. package/dist/recipes/migrations/index.d.ts +9 -0
  365. package/dist/recipes/migrations/index.js +133 -0
  366. package/dist/recipes/migrations/index.js.map +1 -1
  367. package/dist/recipes/names.d.ts +20 -0
  368. package/dist/recipes/names.js +25 -0
  369. package/dist/recipes/names.js.map +1 -1
  370. package/dist/recipes/parser.js +88 -5
  371. package/dist/recipes/parser.js.map +1 -1
  372. package/dist/recipes/replayRun.js +1 -1
  373. package/dist/recipes/replayRun.js.map +1 -1
  374. package/dist/recipes/runBudget.d.ts +70 -0
  375. package/dist/recipes/runBudget.js +109 -0
  376. package/dist/recipes/runBudget.js.map +1 -0
  377. package/dist/recipes/scheduler.d.ts +30 -0
  378. package/dist/recipes/scheduler.js +69 -19
  379. package/dist/recipes/scheduler.js.map +1 -1
  380. package/dist/recipes/schema.d.ts +36 -0
  381. package/dist/recipes/schemaGenerator.js +103 -5
  382. package/dist/recipes/schemaGenerator.js.map +1 -1
  383. package/dist/recipes/stepObservation.js +9 -0
  384. package/dist/recipes/stepObservation.js.map +1 -1
  385. package/dist/recipes/toolRegistry.js +20 -3
  386. package/dist/recipes/toolRegistry.js.map +1 -1
  387. package/dist/recipes/tools/fanOut.d.ts +20 -0
  388. package/dist/recipes/tools/fanOut.js +199 -0
  389. package/dist/recipes/tools/fanOut.js.map +1 -0
  390. package/dist/recipes/tools/file.js +5 -2
  391. package/dist/recipes/tools/file.js.map +1 -1
  392. package/dist/recipes/tools/github.d.ts +1 -1
  393. package/dist/recipes/tools/github.js +75 -1
  394. package/dist/recipes/tools/github.js.map +1 -1
  395. package/dist/recipes/tools/gmail.js +27 -5
  396. package/dist/recipes/tools/gmail.js.map +1 -1
  397. package/dist/recipes/tools/googleDrive.js +64 -0
  398. package/dist/recipes/tools/googleDrive.js.map +1 -1
  399. package/dist/recipes/tools/http.d.ts +10 -0
  400. package/dist/recipes/tools/http.js +176 -0
  401. package/dist/recipes/tools/http.js.map +1 -0
  402. package/dist/recipes/tools/index.d.ts +2 -0
  403. package/dist/recipes/tools/index.js +2 -0
  404. package/dist/recipes/tools/index.js.map +1 -1
  405. package/dist/recipes/tools/slack.js +1 -1
  406. package/dist/recipes/validation.d.ts +17 -0
  407. package/dist/recipes/validation.js +29 -11
  408. package/dist/recipes/validation.js.map +1 -1
  409. package/dist/recipes/workspaceRoot.d.ts +37 -0
  410. package/dist/recipes/workspaceRoot.js +73 -0
  411. package/dist/recipes/workspaceRoot.js.map +1 -0
  412. package/dist/recipes/yamlPositions.d.ts +56 -0
  413. package/dist/recipes/yamlPositions.js +183 -0
  414. package/dist/recipes/yamlPositions.js.map +1 -0
  415. package/dist/recipes/yamlRunner.d.ts +182 -8
  416. package/dist/recipes/yamlRunner.js +877 -217
  417. package/dist/recipes/yamlRunner.js.map +1 -1
  418. package/dist/recipesHttp.d.ts +19 -3
  419. package/dist/recipesHttp.js +67 -11
  420. package/dist/recipesHttp.js.map +1 -1
  421. package/dist/resources.js +21 -13
  422. package/dist/resources.js.map +1 -1
  423. package/dist/runLog.d.ts +58 -5
  424. package/dist/runLog.js +98 -21
  425. package/dist/runLog.js.map +1 -1
  426. package/dist/sanitizeParsedJson.d.ts +39 -0
  427. package/dist/sanitizeParsedJson.js +55 -0
  428. package/dist/sanitizeParsedJson.js.map +1 -0
  429. package/dist/schemas/recipe.v1.json +885 -196
  430. package/dist/server.d.ts +160 -3
  431. package/dist/server.js +1099 -122
  432. package/dist/server.js.map +1 -1
  433. package/dist/sessionCheckpoint.d.ts +8 -0
  434. package/dist/sessionCheckpoint.js +33 -3
  435. package/dist/sessionCheckpoint.js.map +1 -1
  436. package/dist/ssrfGuard.d.ts +16 -0
  437. package/dist/ssrfGuard.js +87 -4
  438. package/dist/ssrfGuard.js.map +1 -1
  439. package/dist/streamableHttp.d.ts +9 -4
  440. package/dist/streamableHttp.js +76 -20
  441. package/dist/streamableHttp.js.map +1 -1
  442. package/dist/telemetry.js +19 -12
  443. package/dist/telemetry.js.map +1 -1
  444. package/dist/testing/shadowRun.d.ts +52 -0
  445. package/dist/testing/shadowRun.js +71 -0
  446. package/dist/testing/shadowRun.js.map +1 -0
  447. package/dist/tools/batchLsp.d.ts +3 -0
  448. package/dist/tools/bridgeDoctor.d.ts +11 -0
  449. package/dist/tools/bridgeDoctor.js +48 -2
  450. package/dist/tools/bridgeDoctor.js.map +1 -1
  451. package/dist/tools/bridgeStatus.d.ts +0 -12
  452. package/dist/tools/bridgeStatus.js +2 -28
  453. package/dist/tools/bridgeStatus.js.map +1 -1
  454. package/dist/tools/cancelClaudeTask.d.ts +1 -0
  455. package/dist/tools/clipboard.d.ts +2 -0
  456. package/dist/tools/closeTabs.d.ts +1 -0
  457. package/dist/tools/codeLens.d.ts +1 -0
  458. package/dist/tools/createIssueFromAIComment.d.ts +1 -0
  459. package/dist/tools/ctxGetTaskContext.d.ts +9 -0
  460. package/dist/tools/ctxGetTaskContext.js +50 -2
  461. package/dist/tools/ctxGetTaskContext.js.map +1 -1
  462. package/dist/tools/ctxQueryTraces.js +32 -24
  463. package/dist/tools/ctxQueryTraces.js.map +1 -1
  464. package/dist/tools/ctxSaveTrace.d.ts +1 -0
  465. package/dist/tools/debug.d.ts +4 -0
  466. package/dist/tools/decorations.d.ts +2 -0
  467. package/dist/tools/detectUnusedCode.js +9 -7
  468. package/dist/tools/detectUnusedCode.js.map +1 -1
  469. package/dist/tools/documentLinks.d.ts +1 -0
  470. package/dist/tools/editText.d.ts +1 -0
  471. package/dist/tools/editText.js +2 -1
  472. package/dist/tools/editText.js.map +1 -1
  473. package/dist/tools/enrichCommit.d.ts +1 -0
  474. package/dist/tools/enrichStackTrace.js +11 -5
  475. package/dist/tools/enrichStackTrace.js.map +1 -1
  476. package/dist/tools/explainDiagnostic.d.ts +1 -0
  477. package/dist/tools/explainSymbol.d.ts +1 -0
  478. package/dist/tools/fileOperations.d.ts +3 -0
  479. package/dist/tools/fileOperations.js +2 -1
  480. package/dist/tools/fileOperations.js.map +1 -1
  481. package/dist/tools/fileWatcher.d.ts +2 -0
  482. package/dist/tools/fileWatcher.js +8 -2
  483. package/dist/tools/fileWatcher.js.map +1 -1
  484. package/dist/tools/findFiles.d.ts +1 -0
  485. package/dist/tools/fixAllLintErrors.d.ts +1 -0
  486. package/dist/tools/fixAllLintErrors.js +10 -5
  487. package/dist/tools/fixAllLintErrors.js.map +1 -1
  488. package/dist/tools/foldingRanges.d.ts +1 -0
  489. package/dist/tools/formatDocument.d.ts +1 -0
  490. package/dist/tools/formatDocument.js +10 -5
  491. package/dist/tools/formatDocument.js.map +1 -1
  492. package/dist/tools/generateTests.d.ts +1 -0
  493. package/dist/tools/getAIComments.d.ts +1 -0
  494. package/dist/tools/getAnalyticsReport.js +5 -1
  495. package/dist/tools/getAnalyticsReport.js.map +1 -1
  496. package/dist/tools/getBufferContent.d.ts +1 -0
  497. package/dist/tools/getChangeImpact.d.ts +1 -0
  498. package/dist/tools/getChangeImpact.js +23 -14
  499. package/dist/tools/getChangeImpact.js.map +1 -1
  500. package/dist/tools/getClaudeTaskStatus.d.ts +1 -0
  501. package/dist/tools/getCodeCoverage.d.ts +1 -0
  502. package/dist/tools/getCodeCoverage.js +32 -14
  503. package/dist/tools/getCodeCoverage.js.map +1 -1
  504. package/dist/tools/getCommitsForIssue.d.ts +1 -0
  505. package/dist/tools/getDebugState.d.ts +1 -0
  506. package/dist/tools/getDiagnostics.js +32 -29
  507. package/dist/tools/getDiagnostics.js.map +1 -1
  508. package/dist/tools/getDiffFromHandoff.js +8 -2
  509. package/dist/tools/getDiffFromHandoff.js.map +1 -1
  510. package/dist/tools/getDocumentSymbols.d.ts +1 -0
  511. package/dist/tools/getGitHotspots.d.ts +1 -0
  512. package/dist/tools/getImportedSignatures.d.ts +1 -0
  513. package/dist/tools/getImportedSignatures.js +18 -14
  514. package/dist/tools/getImportedSignatures.js.map +1 -1
  515. package/dist/tools/getPRTemplate.d.ts +1 -0
  516. package/dist/tools/getProjectContext.js +23 -10
  517. package/dist/tools/getProjectContext.js.map +1 -1
  518. package/dist/tools/getSymbolHistory.d.ts +1 -0
  519. package/dist/tools/getToolCapabilities.d.ts +10 -5
  520. package/dist/tools/getToolCapabilities.js +79 -202
  521. package/dist/tools/getToolCapabilities.js.map +1 -1
  522. package/dist/tools/getTypeSignature.d.ts +1 -0
  523. package/dist/tools/getWorkspaceSettings.d.ts +1 -0
  524. package/dist/tools/gitWrite.d.ts +11 -0
  525. package/dist/tools/github/actions.d.ts +2 -0
  526. package/dist/tools/github/composite.d.ts +3 -0
  527. package/dist/tools/github/issues.d.ts +4 -0
  528. package/dist/tools/github/pr.d.ts +7 -0
  529. package/dist/tools/handoffNote.d.ts +1 -0
  530. package/dist/tools/handoffNote.js +2 -1
  531. package/dist/tools/handoffNote.js.map +1 -1
  532. package/dist/tools/headless/lspClient.js +3 -0
  533. package/dist/tools/headless/lspClient.js.map +1 -1
  534. package/dist/tools/hoverAtCursor.d.ts +1 -0
  535. package/dist/tools/httpClient.d.ts +2 -0
  536. package/dist/tools/httpClient.js +38 -71
  537. package/dist/tools/httpClient.js.map +1 -1
  538. package/dist/tools/inlayHints.d.ts +1 -0
  539. package/dist/tools/launchQuickTask.d.ts +1 -0
  540. package/dist/tools/listClaudeTasks.d.ts +1 -0
  541. package/dist/tools/listClaudeTasks.js +10 -8
  542. package/dist/tools/listClaudeTasks.js.map +1 -1
  543. package/dist/tools/listTerminals.d.ts +1 -0
  544. package/dist/tools/lsp.d.ts +15 -0
  545. package/dist/tools/lsp.js +17 -0
  546. package/dist/tools/lsp.js.map +1 -1
  547. package/dist/tools/navigateToSymbolByName.d.ts +1 -0
  548. package/dist/tools/openDiff.d.ts +1 -0
  549. package/dist/tools/openDiff.js +4 -1
  550. package/dist/tools/openDiff.js.map +1 -1
  551. package/dist/tools/openFile.d.ts +1 -0
  552. package/dist/tools/openFile.js +4 -1
  553. package/dist/tools/openFile.js.map +1 -1
  554. package/dist/tools/openInBrowser.js +6 -1
  555. package/dist/tools/openInBrowser.js.map +1 -1
  556. package/dist/tools/organizeImports.d.ts +1 -0
  557. package/dist/tools/organizeImports.js +5 -3
  558. package/dist/tools/organizeImports.js.map +1 -1
  559. package/dist/tools/performanceReport.js +5 -3
  560. package/dist/tools/performanceReport.js.map +1 -1
  561. package/dist/tools/planPersistence.d.ts +3 -0
  562. package/dist/tools/planPersistence.js +4 -1
  563. package/dist/tools/planPersistence.js.map +1 -1
  564. package/dist/tools/previewEdit.d.ts +1 -0
  565. package/dist/tools/previewEdit.js +15 -4
  566. package/dist/tools/previewEdit.js.map +1 -1
  567. package/dist/tools/recentTracesDigest.js +54 -11
  568. package/dist/tools/recentTracesDigest.js.map +1 -1
  569. package/dist/tools/refactorAnalyze.d.ts +1 -0
  570. package/dist/tools/refactorExtractFunction.js +4 -1
  571. package/dist/tools/refactorExtractFunction.js.map +1 -1
  572. package/dist/tools/refactorPreview.d.ts +1 -0
  573. package/dist/tools/refactorPreview.js +10 -2
  574. package/dist/tools/refactorPreview.js.map +1 -1
  575. package/dist/tools/replaceBlock.d.ts +1 -0
  576. package/dist/tools/replaceBlock.js +2 -1
  577. package/dist/tools/replaceBlock.js.map +1 -1
  578. package/dist/tools/resumeClaudeTask.d.ts +1 -0
  579. package/dist/tools/runClaudeTask.d.ts +1 -0
  580. package/dist/tools/runTests.js +15 -4
  581. package/dist/tools/runTests.js.map +1 -1
  582. package/dist/tools/screenshot.d.ts +1 -0
  583. package/dist/tools/screenshotAndAnnotate.js +6 -2
  584. package/dist/tools/screenshotAndAnnotate.js.map +1 -1
  585. package/dist/tools/searchAndReplace.d.ts +1 -0
  586. package/dist/tools/searchAndReplace.js +17 -7
  587. package/dist/tools/searchAndReplace.js.map +1 -1
  588. package/dist/tools/searchTools.js +20 -19
  589. package/dist/tools/searchTools.js.map +1 -1
  590. package/dist/tools/searchWorkspace.d.ts +1 -0
  591. package/dist/tools/selectionRanges.d.ts +1 -0
  592. package/dist/tools/semanticTokens.d.ts +1 -0
  593. package/dist/tools/signatureHelp.d.ts +1 -0
  594. package/dist/tools/spawnWorkspace.js +15 -7
  595. package/dist/tools/spawnWorkspace.js.map +1 -1
  596. package/dist/tools/terminal.d.ts +6 -0
  597. package/dist/tools/testRunners/pytest.js +6 -2
  598. package/dist/tools/testRunners/pytest.js.map +1 -1
  599. package/dist/tools/testRunners/vitestJest.js +3 -1
  600. package/dist/tools/testRunners/vitestJest.js.map +1 -1
  601. package/dist/tools/testTraceToSource.d.ts +1 -0
  602. package/dist/tools/transaction.d.ts +4 -0
  603. package/dist/tools/transaction.js +4 -1
  604. package/dist/tools/transaction.js.map +1 -1
  605. package/dist/tools/typeHierarchy.d.ts +1 -0
  606. package/dist/tools/utils.d.ts +18 -0
  607. package/dist/tools/utils.js +103 -18
  608. package/dist/tools/utils.js.map +1 -1
  609. package/dist/tools/vscodeCommands.d.ts +2 -0
  610. package/dist/tools/vscodeTasks.d.ts +2 -0
  611. package/dist/tools/workspaceSettings.d.ts +1 -0
  612. package/dist/transport.d.ts +3 -1
  613. package/dist/transport.js +103 -52
  614. package/dist/transport.js.map +1 -1
  615. package/dist/winShim.d.ts +34 -0
  616. package/dist/winShim.js +94 -0
  617. package/dist/winShim.js.map +1 -0
  618. package/dist/wireHaltPushDispatch.d.ts +38 -0
  619. package/dist/wireHaltPushDispatch.js +71 -0
  620. package/dist/wireHaltPushDispatch.js.map +1 -0
  621. package/dist/writeFileAtomic.d.ts +23 -0
  622. package/dist/writeFileAtomic.js +121 -0
  623. package/dist/writeFileAtomic.js.map +1 -0
  624. package/package.json +23 -7
  625. package/scripts/postinstall.mjs +42 -2
  626. package/scripts/smoke/run-all.mjs +213 -0
  627. package/scripts/start-all.mjs +572 -0
  628. package/scripts/start-all.ps1 +209 -0
  629. package/scripts/start-all.sh +73 -17
  630. package/scripts/start-orchestrator.ps1 +158 -0
  631. package/scripts/start-remote.mjs +122 -0
  632. package/templates/automation-policies/recipe-authoring.json +1 -1
  633. package/templates/automation-policies/security-first.json +1 -1
  634. package/templates/automation-policies/strict-lint.json +1 -1
  635. package/templates/automation-policies/test-driven.json +1 -1
  636. package/templates/automation-policy.example.json +1 -1
  637. package/templates/co.patchwork-os.bridge.plist +2 -2
  638. package/templates/recipes/approval-queue-ui-test.yaml +1 -1
  639. package/templates/recipes/ctx-loop-test.yaml +1 -1
  640. package/templates/recipes/fix-errors-on-save.yaml +71 -0
  641. package/templates/recipes/morning-brief.yaml +5 -2
  642. package/templates/recipes/project-health-check.yaml +4 -1
  643. package/templates/recipes/sentry-to-linear.yaml +72 -38
  644. package/templates/recipes/webhook/apple-watch-health-log.yaml +145 -0
  645. package/templates/recipes/webhook/customer-escalation.yaml +8 -9
  646. package/templates/recipes/webhook/meeting-prep.yaml +11 -5
  647. package/dist/commands/marketplace.d.ts +0 -16
  648. package/dist/commands/marketplace.js +0 -32
  649. package/dist/commands/marketplace.js.map +0 -1
  650. package/dist/recipes/legacyRecipeCompat.d.ts +0 -10
  651. package/dist/recipes/legacyRecipeCompat.js +0 -131
  652. package/dist/recipes/legacyRecipeCompat.js.map +0 -1
@@ -14,26 +14,115 @@
14
14
  * - TTL eviction at access time (consume() or add()) — no per-state timer,
15
15
  * so 10k states cost 10k Map slots + 10k longs, nothing more.
16
16
  * - `consume()` is single-use; second call with the same state returns false.
17
+ *
18
+ * Persistence (opt-in via `namespace`):
19
+ * - When `namespace` is set, the state map is mirrored to disk at
20
+ * `${PATCHWORK_HOME}/tokens/oauth-state.<namespace>.json` (mode 0600).
21
+ * - The in-memory Map remains the read path; disk is the source of truth
22
+ * so a bridge restart between /authorize and /callback survives.
23
+ * - Each mutation triggers an atomic re-serialise of the namespace's map
24
+ * via `writeFileAtomicSync` (sibling tmp + rename). State payloads are
25
+ * short-lived (≤10 min) and bounded (≤1000 entries × ~80 bytes each),
26
+ * so a full-rewrite-on-mutation is the simplest correct shape.
27
+ * - State values are CSRF nonces, NOT secrets — they're single-use and
28
+ * useless after consume(). Plain JSON storage at 0600 is sufficient;
29
+ * no need to encrypt under the master key like tokenStorage.ts does.
17
30
  */
31
+ import { existsSync, mkdirSync, readFileSync } from "node:fs";
32
+ import os from "node:os";
33
+ import { join } from "node:path";
34
+ import { writeFileAtomicSync } from "../writeFileAtomic.js";
18
35
  const DEFAULT_TTL_MS = 10 * 60_000;
19
36
  const DEFAULT_MAX_ENTRIES = 1000;
37
+ function getStorageDir() {
38
+ const base = process.env.PATCHWORK_HOME ?? join(os.homedir(), ".patchwork");
39
+ return join(base, "tokens");
40
+ }
41
+ function stateFilePath(namespace) {
42
+ return join(getStorageDir(), `oauth-state.${namespace}.json`);
43
+ }
44
+ function loadFromDisk(namespace) {
45
+ const m = new Map();
46
+ const file = stateFilePath(namespace);
47
+ if (!existsSync(file))
48
+ return m;
49
+ try {
50
+ const raw = readFileSync(file, "utf-8");
51
+ const parsed = JSON.parse(raw);
52
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
53
+ const now = Date.now();
54
+ // Use Object.hasOwn to avoid walking the prototype chain — same
55
+ // pattern as the rest of the codebase (see Record<string,T>
56
+ // prototype-walk feedback).
57
+ for (const key of Object.keys(parsed)) {
58
+ if (!Object.hasOwn(parsed, key))
59
+ continue;
60
+ const expiry = parsed[key];
61
+ if (typeof expiry === "number" && expiry >= now) {
62
+ m.set(key, expiry);
63
+ }
64
+ }
65
+ }
66
+ }
67
+ catch {
68
+ // Corrupt file → start empty. Next mutation rewrites it.
69
+ }
70
+ return m;
71
+ }
72
+ function persistToDisk(namespace, states) {
73
+ const dir = getStorageDir();
74
+ if (!existsSync(dir)) {
75
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
76
+ }
77
+ const obj = {};
78
+ for (const [k, v] of states)
79
+ obj[k] = v;
80
+ writeFileAtomicSync(stateFilePath(namespace), JSON.stringify(obj), {
81
+ mode: 0o600,
82
+ });
83
+ }
20
84
  export function createOAuthStateStore(opts = {}) {
21
85
  const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
22
86
  const maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
23
- const states = new Map(); // state → expiresAt ms
87
+ const namespace = opts.namespace;
88
+ const persist = typeof namespace === "string" && namespace.length > 0;
89
+ // Read-through cache. Seeded from disk on construction so a bridge
90
+ // restart preserves in-flight OAuth states.
91
+ const states = persist
92
+ ? loadFromDisk(namespace)
93
+ : new Map();
24
94
  function pruneExpired(now) {
95
+ let changed = false;
25
96
  for (const [s, expiry] of states) {
26
- if (expiry < now)
97
+ if (expiry < now) {
27
98
  states.delete(s);
99
+ changed = true;
100
+ }
101
+ }
102
+ return changed;
103
+ }
104
+ function flush() {
105
+ if (!persist)
106
+ return;
107
+ try {
108
+ persistToDisk(namespace, states);
109
+ }
110
+ catch {
111
+ // Disk failure is non-fatal — the in-memory store still works for
112
+ // the lifetime of this process. A restart loses the unflushed state.
28
113
  }
29
114
  }
30
115
  return {
31
116
  add(state) {
32
117
  const now = Date.now();
33
- pruneExpired(now);
34
- if (states.size >= maxEntries)
118
+ const prunedSomething = pruneExpired(now);
119
+ if (states.size >= maxEntries) {
120
+ if (prunedSomething)
121
+ flush();
35
122
  return false;
123
+ }
36
124
  states.set(state, now + ttlMs);
125
+ flush();
37
126
  return true;
38
127
  },
39
128
  consume(state) {
@@ -42,6 +131,7 @@ export function createOAuthStateStore(opts = {}) {
42
131
  if (expiry === undefined)
43
132
  return false;
44
133
  states.delete(state);
134
+ flush();
45
135
  return expiry >= now;
46
136
  },
47
137
  size() {
@@ -1 +1 @@
1
- {"version":3,"file":"oauthStateStore.js","sourceRoot":"","sources":["../../src/connectors/oauthStateStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAgBH,MAAM,cAAc,GAAG,EAAE,GAAG,MAAM,CAAC;AACnC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC,MAAM,UAAU,qBAAqB,CAAC,OAAgB,EAAE;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,cAAc,CAAC;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,mBAAmB,CAAC;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC,CAAC,uBAAuB;IAEjE,SAAS,YAAY,CAAC,GAAW;QAC/B,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACjC,IAAI,MAAM,GAAG,GAAG;gBAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG,CAAC,KAAa;YACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,YAAY,CAAC,GAAG,CAAC,CAAC;YAClB,IAAI,MAAM,CAAC,IAAI,IAAI,UAAU;gBAAE,OAAO,KAAK,CAAC;YAC5C,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,CAAC,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,KAAa;YACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACrB,OAAO,MAAM,IAAI,GAAG,CAAC;QACvB,CAAC;QACD,IAAI;YACF,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"oauthStateStore.js","sourceRoot":"","sources":["../../src/connectors/oauthStateStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Obsidian connector — read/write notes via the Obsidian Local REST API plugin.
3
+ *
4
+ * Auth: API key (Bearer token) from plugin settings.
5
+ * - Env var: OBSIDIAN_API_KEY overrides stored key for CI/headless use.
6
+ * - Stored: getSecretJsonSync("obsidian") → ObsidianTokens
7
+ *
8
+ * Tools: listVault, readNote, writeNote, deleteNote, searchVault, appendToNote,
9
+ * getActiveNote, openNote, executeCommand, listCommands
10
+ *
11
+ * The plugin runs at https://127.0.0.1:27124 with a self-signed certificate.
12
+ * All fetch calls use an undici Agent with rejectUnauthorized: false.
13
+ *
14
+ * Extends BaseConnector for unified auth, retry, rate-limit, error handling.
15
+ */
16
+ import { type AuthContext, BaseConnector, type ConnectorError, type ConnectorStatus } from "./baseConnector.js";
17
+ export interface ObsidianTokens {
18
+ apiKey: string;
19
+ baseUrl: string;
20
+ connected_at: string;
21
+ }
22
+ export interface ObsidianVaultEntry {
23
+ path: string;
24
+ type: "file" | "directory";
25
+ }
26
+ export interface ObsidianSearchMatch {
27
+ filename: string;
28
+ score: number;
29
+ matches: string[];
30
+ }
31
+ export interface ObsidianCommand {
32
+ id: string;
33
+ name: string;
34
+ }
35
+ export declare function loadTokens(): ObsidianTokens | null;
36
+ export declare function saveTokens(tokens: ObsidianTokens): void;
37
+ export declare function clearTokens(): void;
38
+ export declare class ObsidianConnector extends BaseConnector {
39
+ readonly providerName = "obsidian";
40
+ protected cachedTokens: ObsidianTokens | null;
41
+ protected getOAuthConfig(): null;
42
+ authenticate(): Promise<AuthContext>;
43
+ healthCheck(): Promise<{
44
+ ok: boolean;
45
+ error?: ConnectorError;
46
+ }>;
47
+ normalizeError(error: unknown): ConnectorError;
48
+ getStatus(): ConnectorStatus;
49
+ private baseUrl;
50
+ listVault(vaultPath?: string): Promise<ObsidianVaultEntry[]>;
51
+ readNote(notePath: string): Promise<string>;
52
+ writeNote(notePath: string, content: string, append?: boolean): Promise<void>;
53
+ appendToNote(notePath: string, content: string): Promise<void>;
54
+ deleteNote(notePath: string): Promise<void>;
55
+ searchVault(query: string): Promise<ObsidianSearchMatch[]>;
56
+ getActiveNote(): Promise<string>;
57
+ openNote(notePath: string): Promise<void>;
58
+ listCommands(): Promise<ObsidianCommand[]>;
59
+ executeCommand(commandId: string): Promise<void>;
60
+ }
61
+ export declare function getObsidianConnector(): ObsidianConnector;
62
+ export declare function resetObsidianConnector(): void;
63
+ export { loadTokens as isConnected };
64
+ export interface ConnectorHandlerResult {
65
+ status: number;
66
+ body: string;
67
+ contentType?: string;
68
+ }
69
+ /**
70
+ * POST /connections/obsidian/connect { apiKey: "...", baseUrl?: "https://..." }
71
+ * Stores the API key and verifies it by calling GET /vault/.
72
+ */
73
+ export declare function handleObsidianConnect(body: string): Promise<ConnectorHandlerResult>;
74
+ /**
75
+ * POST /connections/obsidian/test
76
+ * Verifies stored API key is still valid.
77
+ */
78
+ export declare function handleObsidianTest(): Promise<ConnectorHandlerResult>;
79
+ /**
80
+ * DELETE /connections/obsidian
81
+ * Removes stored API key.
82
+ */
83
+ export declare function handleObsidianDisconnect(): ConnectorHandlerResult;
@@ -0,0 +1,441 @@
1
+ /**
2
+ * Obsidian connector — read/write notes via the Obsidian Local REST API plugin.
3
+ *
4
+ * Auth: API key (Bearer token) from plugin settings.
5
+ * - Env var: OBSIDIAN_API_KEY overrides stored key for CI/headless use.
6
+ * - Stored: getSecretJsonSync("obsidian") → ObsidianTokens
7
+ *
8
+ * Tools: listVault, readNote, writeNote, deleteNote, searchVault, appendToNote,
9
+ * getActiveNote, openNote, executeCommand, listCommands
10
+ *
11
+ * The plugin runs at https://127.0.0.1:27124 with a self-signed certificate.
12
+ * All fetch calls use an undici Agent with rejectUnauthorized: false.
13
+ *
14
+ * Extends BaseConnector for unified auth, retry, rate-limit, error handling.
15
+ */
16
+ import { unlinkSync } from "node:fs";
17
+ import { homedir } from "node:os";
18
+ import path from "node:path";
19
+ import { Agent, fetch as undiciFetch } from "undici";
20
+ import { BaseConnector, } from "./baseConnector.js";
21
+ import { getSecretJsonSync, storeSecretJsonSync } from "./tokenStorage.js";
22
+ const DEFAULT_BASE_URL = "https://127.0.0.1:27124";
23
+ // Reusable TLS agent that accepts the plugin's self-signed certificate.
24
+ const tlsAgent = new Agent({ connect: { rejectUnauthorized: false } });
25
+ // ------------------------------------------------------------------ token helpers
26
+ export function loadTokens() {
27
+ const envKey = process.env.OBSIDIAN_API_KEY;
28
+ if (envKey) {
29
+ return {
30
+ apiKey: envKey,
31
+ baseUrl: DEFAULT_BASE_URL,
32
+ connected_at: new Date().toISOString(),
33
+ };
34
+ }
35
+ return getSecretJsonSync("obsidian");
36
+ }
37
+ export function saveTokens(tokens) {
38
+ storeSecretJsonSync("obsidian", tokens);
39
+ }
40
+ export function clearTokens() {
41
+ try {
42
+ const p = path.join(homedir(), ".patchwork", "tokens", "obsidian.json");
43
+ unlinkSync(p);
44
+ }
45
+ catch {
46
+ /* already gone */
47
+ }
48
+ }
49
+ // ------------------------------------------------------------------ connector
50
+ export class ObsidianConnector extends BaseConnector {
51
+ providerName = "obsidian";
52
+ cachedTokens = null;
53
+ getOAuthConfig() {
54
+ return null;
55
+ }
56
+ async authenticate() {
57
+ const tokens = loadTokens();
58
+ if (!tokens) {
59
+ throw new Error("Obsidian not connected. Run: patchwork connect obsidian or set OBSIDIAN_API_KEY");
60
+ }
61
+ this.cachedTokens = tokens;
62
+ return { token: tokens.apiKey };
63
+ }
64
+ async healthCheck() {
65
+ try {
66
+ const result = await this.apiCall(async (token) => {
67
+ const tokens = this.cachedTokens ?? loadTokens();
68
+ const baseUrl = tokens?.baseUrl ?? DEFAULT_BASE_URL;
69
+ const res = await undiciFetch(`${baseUrl}/vault/`, {
70
+ dispatcher: tlsAgent,
71
+ headers: buildHeaders(token),
72
+ });
73
+ if (!res.ok)
74
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
75
+ status: res.status,
76
+ });
77
+ return res.json();
78
+ });
79
+ if ("error" in result)
80
+ return { ok: false, error: result.error };
81
+ return { ok: true };
82
+ }
83
+ catch (err) {
84
+ return { ok: false, error: this.normalizeError(err) };
85
+ }
86
+ }
87
+ normalizeError(error) {
88
+ if (error && typeof error === "object" && "status" in error) {
89
+ const status = error.status;
90
+ if (status === 401 || status === 403)
91
+ return {
92
+ code: "auth_expired",
93
+ message: "Obsidian API key rejected — check plugin settings",
94
+ retryable: false,
95
+ suggestedAction: "Reconnect: patchwork connect obsidian",
96
+ };
97
+ if (status === 404)
98
+ return {
99
+ code: "not_found",
100
+ message: "Obsidian note or path not found",
101
+ retryable: false,
102
+ };
103
+ return {
104
+ code: "provider_error",
105
+ message: `Obsidian API error: HTTP ${status}`,
106
+ retryable: status >= 500,
107
+ };
108
+ }
109
+ if (error instanceof Error) {
110
+ if (error.message.includes("ECONNREFUSED") ||
111
+ error.message.includes("ENOTFOUND")) {
112
+ return {
113
+ code: "network_error",
114
+ message: `Cannot reach Obsidian Local REST API: ${error.message}. Is the plugin running?`,
115
+ retryable: true,
116
+ suggestedAction: "Start Obsidian and enable the Local REST API plugin",
117
+ };
118
+ }
119
+ }
120
+ return {
121
+ code: "provider_error",
122
+ message: error instanceof Error ? error.message : String(error),
123
+ retryable: false,
124
+ };
125
+ }
126
+ getStatus() {
127
+ const tokens = loadTokens();
128
+ return {
129
+ id: "obsidian",
130
+ status: tokens ? "connected" : "disconnected",
131
+ lastSync: tokens?.connected_at,
132
+ workspace: tokens?.baseUrl,
133
+ };
134
+ }
135
+ baseUrl() {
136
+ return (this.cachedTokens ?? loadTokens())?.baseUrl ?? DEFAULT_BASE_URL;
137
+ }
138
+ // ---------------------------------------------------------------- vault ops
139
+ async listVault(vaultPath) {
140
+ const result = await this.apiCall(async (token) => {
141
+ const encoded = vaultPath ? encodeURIComponent(vaultPath) : "";
142
+ const url = `${this.baseUrl()}/vault/${encoded ? `${encoded}/` : ""}`;
143
+ const res = await undiciFetch(url, {
144
+ dispatcher: tlsAgent,
145
+ headers: buildHeaders(token),
146
+ });
147
+ if (!res.ok)
148
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
149
+ status: res.status,
150
+ });
151
+ return res.json();
152
+ });
153
+ if ("error" in result)
154
+ throw new Error(result.error.message);
155
+ const raw = result.data;
156
+ return (raw.files ?? []).map((f) => ({
157
+ path: f,
158
+ type: f.endsWith("/") ? "directory" : "file",
159
+ }));
160
+ }
161
+ async readNote(notePath) {
162
+ const result = await this.apiCall(async (token) => {
163
+ const res = await undiciFetch(`${this.baseUrl()}/vault/${encodeURIComponent(notePath)}`, {
164
+ dispatcher: tlsAgent,
165
+ headers: buildHeaders(token),
166
+ });
167
+ if (!res.ok)
168
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
169
+ status: res.status,
170
+ });
171
+ return res.text();
172
+ });
173
+ if ("error" in result)
174
+ throw new Error(result.error.message);
175
+ return result.data;
176
+ }
177
+ async writeNote(notePath, content, append = false) {
178
+ const result = await this.apiCall(async (token) => {
179
+ const method = append ? "POST" : "PUT";
180
+ const res = await undiciFetch(`${this.baseUrl()}/vault/${encodeURIComponent(notePath)}`, {
181
+ method,
182
+ dispatcher: tlsAgent,
183
+ headers: {
184
+ ...buildHeaders(token),
185
+ "Content-Type": "text/markdown",
186
+ },
187
+ body: content,
188
+ });
189
+ if (!res.ok)
190
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
191
+ status: res.status,
192
+ });
193
+ return null;
194
+ });
195
+ if ("error" in result)
196
+ throw new Error(result.error.message);
197
+ }
198
+ async appendToNote(notePath, content) {
199
+ return this.writeNote(notePath, content, true);
200
+ }
201
+ async deleteNote(notePath) {
202
+ const result = await this.apiCall(async (token) => {
203
+ const res = await undiciFetch(`${this.baseUrl()}/vault/${encodeURIComponent(notePath)}`, {
204
+ method: "DELETE",
205
+ dispatcher: tlsAgent,
206
+ headers: buildHeaders(token),
207
+ });
208
+ if (!res.ok)
209
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
210
+ status: res.status,
211
+ });
212
+ return null;
213
+ });
214
+ if ("error" in result)
215
+ throw new Error(result.error.message);
216
+ }
217
+ async searchVault(query) {
218
+ const result = await this.apiCall(async (token) => {
219
+ const res = await undiciFetch(`${this.baseUrl()}/search/simple/?query=${encodeURIComponent(query)}`, {
220
+ method: "POST",
221
+ dispatcher: tlsAgent,
222
+ headers: buildHeaders(token),
223
+ });
224
+ if (!res.ok)
225
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
226
+ status: res.status,
227
+ });
228
+ return res.json();
229
+ });
230
+ if ("error" in result)
231
+ throw new Error(result.error.message);
232
+ return result.data;
233
+ }
234
+ async getActiveNote() {
235
+ const result = await this.apiCall(async (token) => {
236
+ const res = await undiciFetch(`${this.baseUrl()}/active/`, {
237
+ dispatcher: tlsAgent,
238
+ headers: buildHeaders(token),
239
+ });
240
+ if (!res.ok)
241
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
242
+ status: res.status,
243
+ });
244
+ return res.text();
245
+ });
246
+ if ("error" in result)
247
+ throw new Error(result.error.message);
248
+ return result.data;
249
+ }
250
+ async openNote(notePath) {
251
+ const result = await this.apiCall(async (token) => {
252
+ const res = await undiciFetch(`${this.baseUrl()}/open/${encodeURIComponent(notePath)}`, {
253
+ method: "POST",
254
+ dispatcher: tlsAgent,
255
+ headers: buildHeaders(token),
256
+ });
257
+ if (!res.ok)
258
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
259
+ status: res.status,
260
+ });
261
+ return null;
262
+ });
263
+ if ("error" in result)
264
+ throw new Error(result.error.message);
265
+ }
266
+ async listCommands() {
267
+ const result = await this.apiCall(async (token) => {
268
+ const res = await undiciFetch(`${this.baseUrl()}/commands/`, {
269
+ dispatcher: tlsAgent,
270
+ headers: buildHeaders(token),
271
+ });
272
+ if (!res.ok)
273
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
274
+ status: res.status,
275
+ });
276
+ return res.json();
277
+ });
278
+ if ("error" in result)
279
+ throw new Error(result.error.message);
280
+ return result.data.commands ?? [];
281
+ }
282
+ async executeCommand(commandId) {
283
+ const result = await this.apiCall(async (token) => {
284
+ const res = await undiciFetch(`${this.baseUrl()}/commands/${encodeURIComponent(commandId)}/execute`, {
285
+ method: "POST",
286
+ dispatcher: tlsAgent,
287
+ headers: buildHeaders(token),
288
+ });
289
+ if (!res.ok)
290
+ throw Object.assign(new Error(`HTTP ${res.status}`), {
291
+ status: res.status,
292
+ });
293
+ return null;
294
+ });
295
+ if ("error" in result)
296
+ throw new Error(result.error.message);
297
+ }
298
+ }
299
+ // ------------------------------------------------------------------ helpers
300
+ function buildHeaders(token) {
301
+ return {
302
+ Authorization: `Bearer ${token}`,
303
+ Accept: "application/json",
304
+ };
305
+ }
306
+ // ------------------------------------------------------------------ singleton
307
+ let _instance = null;
308
+ export function getObsidianConnector() {
309
+ if (!_instance)
310
+ _instance = new ObsidianConnector();
311
+ return _instance;
312
+ }
313
+ export function resetObsidianConnector() {
314
+ _instance = null;
315
+ }
316
+ // ------------------------------------------------------------------ convenience re-exports
317
+ export { loadTokens as isConnected };
318
+ /**
319
+ * POST /connections/obsidian/connect { apiKey: "...", baseUrl?: "https://..." }
320
+ * Stores the API key and verifies it by calling GET /vault/.
321
+ */
322
+ export async function handleObsidianConnect(body) {
323
+ let apiKey;
324
+ let baseUrl = DEFAULT_BASE_URL;
325
+ try {
326
+ const parsed = JSON.parse(body);
327
+ if (typeof parsed.apiKey !== "string" || parsed.apiKey.trim() === "") {
328
+ return {
329
+ status: 400,
330
+ contentType: "application/json",
331
+ body: JSON.stringify({
332
+ ok: false,
333
+ error: "apiKey is required. Find it in Obsidian → Local REST API plugin settings.",
334
+ }),
335
+ };
336
+ }
337
+ apiKey = parsed.apiKey.trim();
338
+ if (typeof parsed.baseUrl === "string" && parsed.baseUrl.trim() !== "") {
339
+ baseUrl = parsed.baseUrl.trim();
340
+ }
341
+ }
342
+ catch {
343
+ return {
344
+ status: 400,
345
+ contentType: "application/json",
346
+ body: JSON.stringify({ ok: false, error: "Invalid JSON body" }),
347
+ };
348
+ }
349
+ try {
350
+ const res = await undiciFetch(`${baseUrl}/vault/`, {
351
+ dispatcher: tlsAgent,
352
+ headers: {
353
+ Authorization: `Bearer ${apiKey}`,
354
+ Accept: "application/json",
355
+ },
356
+ });
357
+ if (!res.ok) {
358
+ return {
359
+ status: 401,
360
+ contentType: "application/json",
361
+ body: JSON.stringify({
362
+ ok: false,
363
+ error: "API key rejected by Obsidian plugin — check the key in plugin settings",
364
+ }),
365
+ };
366
+ }
367
+ const tokens = {
368
+ apiKey,
369
+ baseUrl,
370
+ connected_at: new Date().toISOString(),
371
+ };
372
+ saveTokens(tokens);
373
+ resetObsidianConnector();
374
+ return {
375
+ status: 200,
376
+ contentType: "application/json",
377
+ body: JSON.stringify({
378
+ ok: true,
379
+ baseUrl,
380
+ connectedAt: tokens.connected_at,
381
+ }),
382
+ };
383
+ }
384
+ catch (err) {
385
+ return {
386
+ status: 500,
387
+ contentType: "application/json",
388
+ body: JSON.stringify({
389
+ ok: false,
390
+ error: err instanceof Error ? err.message : String(err),
391
+ }),
392
+ };
393
+ }
394
+ }
395
+ /**
396
+ * POST /connections/obsidian/test
397
+ * Verifies stored API key is still valid.
398
+ */
399
+ export async function handleObsidianTest() {
400
+ const tokens = loadTokens();
401
+ if (!tokens) {
402
+ return {
403
+ status: 400,
404
+ contentType: "application/json",
405
+ body: JSON.stringify({ ok: false, error: "Obsidian not connected" }),
406
+ };
407
+ }
408
+ try {
409
+ const connector = getObsidianConnector();
410
+ const check = await connector.healthCheck();
411
+ return {
412
+ status: check.ok ? 200 : 401,
413
+ contentType: "application/json",
414
+ body: JSON.stringify(check.ok ? { ok: true } : { ok: false, error: check.error?.message }),
415
+ };
416
+ }
417
+ catch (err) {
418
+ return {
419
+ status: 500,
420
+ contentType: "application/json",
421
+ body: JSON.stringify({
422
+ ok: false,
423
+ error: err instanceof Error ? err.message : String(err),
424
+ }),
425
+ };
426
+ }
427
+ }
428
+ /**
429
+ * DELETE /connections/obsidian
430
+ * Removes stored API key.
431
+ */
432
+ export function handleObsidianDisconnect() {
433
+ clearTokens();
434
+ resetObsidianConnector();
435
+ return {
436
+ status: 200,
437
+ contentType: "application/json",
438
+ body: JSON.stringify({ ok: true }),
439
+ };
440
+ }
441
+ //# sourceMappingURL=obsidian.js.map