@asterxsk/kiln 0.3.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -155
- package/agent/AGENTS.md +67 -67
- package/agent/README.md +5 -5
- package/agent/extensions/ask-user/index.ts +418 -418
- package/agent/extensions/ask-user/install.ps1 +27 -27
- package/agent/extensions/ask-user/install.sh +24 -24
- package/agent/extensions/ask-user/package-lock.json +769 -769
- package/agent/extensions/ask-user/package.json +19 -19
- package/agent/extensions/ask-user/prompt.ts +45 -45
- package/agent/extensions/ask-user/tsconfig.json +7 -7
- package/agent/extensions/background-terminals/docs/implementation-guide.md +942 -942
- package/agent/extensions/background-terminals/index.ts +627 -627
- package/agent/extensions/background-terminals/install.ps1 +27 -27
- package/agent/extensions/background-terminals/install.sh +24 -24
- package/agent/extensions/background-terminals/manager.test.ts +735 -735
- package/agent/extensions/background-terminals/output.test.ts +109 -109
- package/agent/extensions/background-terminals/package-lock.json +769 -769
- package/agent/extensions/background-terminals/package.json +17 -17
- package/agent/extensions/background-terminals/prompt.test.ts +125 -125
- package/agent/extensions/background-terminals/ps.test.ts +82 -82
- package/agent/extensions/background-terminals/result-delivery.test.ts +44 -44
- package/agent/extensions/background-terminals/src/domain.ts +87 -87
- package/agent/extensions/background-terminals/src/manager.ts +907 -907
- package/agent/extensions/background-terminals/src/output.ts +84 -84
- package/agent/extensions/background-terminals/src/prompt.ts +142 -142
- package/agent/extensions/background-terminals/src/result-delivery.ts +27 -27
- package/agent/extensions/background-terminals/src/runtime.ts +36 -36
- package/agent/extensions/background-terminals/src/ui/output-view.ts +79 -79
- package/agent/extensions/background-terminals/src/ui/ps.ts +621 -621
- package/agent/extensions/background-terminals/tsconfig.json +7 -7
- package/agent/extensions/destructive/README.md +31 -31
- package/agent/extensions/destructive/index.ts +88 -88
- package/agent/extensions/destructive/install.ps1 +27 -27
- package/agent/extensions/destructive/install.sh +24 -24
- package/agent/extensions/file-search/index.spec.ts +443 -443
- package/agent/extensions/file-search/index.ts +459 -459
- package/agent/extensions/file-search/install.ps1 +27 -27
- package/agent/extensions/file-search/install.sh +24 -24
- package/agent/extensions/file-search/package-lock.json +2253 -2253
- package/agent/extensions/file-search/package.json +23 -23
- package/agent/extensions/file-search/src/args.ts +122 -122
- package/agent/extensions/file-search/src/binaries.ts +422 -422
- package/agent/extensions/file-search/src/output.ts +126 -126
- package/agent/extensions/file-search/src/process.ts +146 -146
- package/agent/extensions/file-search/src/prompt.ts +52 -52
- package/agent/extensions/file-search/tsconfig.json +7 -7
- package/agent/extensions/goal/README.md +50 -50
- package/agent/extensions/goal/index.ts +155 -155
- package/agent/extensions/goal/install.ps1 +27 -27
- package/agent/extensions/goal/install.sh +24 -24
- package/agent/extensions/kiln-update/README.md +38 -25
- package/agent/extensions/kiln-update/index.ts +177 -99
- package/agent/extensions/modelconf/PLAN.md +915 -915
- package/agent/extensions/modelconf/README.md +66 -66
- package/agent/extensions/modelconf/index.ts +296 -296
- package/agent/extensions/modelconf/install.ps1 +27 -27
- package/agent/extensions/modelconf/install.sh +24 -24
- package/agent/extensions/modelconf/package-lock.json +1809 -1809
- package/agent/extensions/modelconf/package.json +13 -13
- package/agent/extensions/modelconf/src/fuzzy.ts +26 -26
- package/agent/extensions/modelconf/src/glob.ts +13 -13
- package/agent/extensions/modelconf/src/persistence.test.ts +46 -46
- package/agent/extensions/modelconf/src/persistence.ts +164 -164
- package/agent/extensions/modelconf/src/ui/ModelConfView.test.ts +75 -75
- package/agent/extensions/modelconf/src/ui/ModelConfView.ts +1101 -1101
- package/agent/extensions/modelconf/tsconfig.json +15 -15
- package/agent/extensions/pi-web-access/CHANGELOG.md +690 -690
- package/agent/extensions/pi-web-access/LICENSE +21 -21
- package/agent/extensions/pi-web-access/README.md +470 -470
- package/agent/extensions/pi-web-access/SECURITY.md +5 -5
- package/agent/extensions/pi-web-access/activity.ts +101 -101
- package/agent/extensions/pi-web-access/auth-fetch.ts +148 -148
- package/agent/extensions/pi-web-access/brightdata-unlocker.ts +272 -272
- package/agent/extensions/pi-web-access/chrome-cookies.ts +669 -669
- package/agent/extensions/pi-web-access/content-find.ts +139 -139
- package/agent/extensions/pi-web-access/credential-source.ts +191 -191
- package/agent/extensions/pi-web-access/data-uri-sanitize.ts +406 -406
- package/agent/extensions/pi-web-access/datalab-pdf-extract.ts +568 -568
- package/agent/extensions/pi-web-access/declared-web-links.ts +173 -173
- package/agent/extensions/pi-web-access/evidence/CONTRACT-EVIDENCE.md +496 -496
- package/agent/extensions/pi-web-access/evidence/contract-probe.mjs +140 -140
- package/agent/extensions/pi-web-access/exa.ts +526 -526
- package/agent/extensions/pi-web-access/extract.ts +1196 -1196
- package/agent/extensions/pi-web-access/feature-config.ts +29 -29
- package/agent/extensions/pi-web-access/fetch-params.ts +111 -111
- package/agent/extensions/pi-web-access/gemini-adc.ts +298 -298
- package/agent/extensions/pi-web-access/gemini-api.ts +353 -353
- package/agent/extensions/pi-web-access/gemini-pdf-extract.ts +108 -108
- package/agent/extensions/pi-web-access/gemini-search.ts +21 -21
- package/agent/extensions/pi-web-access/gemini-url-context.ts +128 -128
- package/agent/extensions/pi-web-access/gemini-web-config.ts +101 -101
- package/agent/extensions/pi-web-access/gemini-web.ts +487 -487
- package/agent/extensions/pi-web-access/github-api.ts +197 -197
- package/agent/extensions/pi-web-access/github-extract.ts +746 -746
- package/agent/extensions/pi-web-access/github-issue-pr.ts +700 -700
- package/agent/extensions/pi-web-access/index.ts +1737 -1737
- package/agent/extensions/pi-web-access/package-lock.json +5808 -5808
- package/agent/extensions/pi-web-access/package.json +64 -64
- package/agent/extensions/pi-web-access/page-query.ts +96 -96
- package/agent/extensions/pi-web-access/pdf-extract.ts +409 -409
- package/agent/extensions/pi-web-access/promise-try.d.ts +7 -7
- package/agent/extensions/pi-web-access/query-rewrite.ts +51 -51
- package/agent/extensions/pi-web-access/render-search-error.ts +170 -170
- package/agent/extensions/pi-web-access/rsc-extract.ts +338 -338
- package/agent/extensions/pi-web-access/search-types.ts +20 -20
- package/agent/extensions/pi-web-access/source-check.ts +282 -282
- package/agent/extensions/pi-web-access/ssrf-protection.ts +526 -526
- package/agent/extensions/pi-web-access/storage.ts +521 -521
- package/agent/extensions/pi-web-access/summary-model-scope.ts +125 -125
- package/agent/extensions/pi-web-access/test/auth-fetch.test.mjs +208 -208
- package/agent/extensions/pi-web-access/test/brightdata-unlocker.test.mjs +840 -840
- package/agent/extensions/pi-web-access/test/chrome-cookie-extraction.test.mjs +441 -441
- package/agent/extensions/pi-web-access/test/config-path.test.mjs +283 -283
- package/agent/extensions/pi-web-access/test/content-find.test.mjs +25 -25
- package/agent/extensions/pi-web-access/test/credential-source.test.mjs +118 -118
- package/agent/extensions/pi-web-access/test/data-uri-sanitize.test.mjs +210 -210
- package/agent/extensions/pi-web-access/test/datalab-pdf-extract.test.mjs +552 -552
- package/agent/extensions/pi-web-access/test/declared-web-links.test.mjs +212 -212
- package/agent/extensions/pi-web-access/test/fetch-answer-storage.test.mjs +40 -40
- package/agent/extensions/pi-web-access/test/fetch-cache-storage.test.mjs +334 -334
- package/agent/extensions/pi-web-access/test/fetch-content-domain-policy.test.mjs +95 -95
- package/agent/extensions/pi-web-access/test/fetch-modes.test.mjs +53 -53
- package/agent/extensions/pi-web-access/test/fetch-not-found-guidance.test.mjs +92 -92
- package/agent/extensions/pi-web-access/test/fetch-params.test.mjs +86 -86
- package/agent/extensions/pi-web-access/test/fetch-render-call.test.mjs +34 -34
- package/agent/extensions/pi-web-access/test/fetch-routing.test.mjs +173 -173
- package/agent/extensions/pi-web-access/test/gemini-adc-auth.test.mjs +257 -257
- package/agent/extensions/pi-web-access/test/gemini-api-transport.test.mjs +170 -170
- package/agent/extensions/pi-web-access/test/gemini-pdf-extract.test.mjs +133 -133
- package/agent/extensions/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +178 -178
- package/agent/extensions/pi-web-access/test/gemini-web-header-overflow.test.mjs +148 -148
- package/agent/extensions/pi-web-access/test/get-search-content.test.mjs +223 -223
- package/agent/extensions/pi-web-access/test/github-extract.test.mjs +378 -378
- package/agent/extensions/pi-web-access/test/github-issue-pr.test.mjs +565 -565
- package/agent/extensions/pi-web-access/test/inline-content-config.test.mjs +99 -99
- package/agent/extensions/pi-web-access/test/lazy-extract-load.test.mjs +118 -118
- package/agent/extensions/pi-web-access/test/local-video-oversize.test.mjs +52 -52
- package/agent/extensions/pi-web-access/test/package-typebox-dependency.test.mjs +50 -50
- package/agent/extensions/pi-web-access/test/page-query.test.mjs +51 -51
- package/agent/extensions/pi-web-access/test/pdf-config.test.mjs +140 -140
- package/agent/extensions/pi-web-access/test/pdf-extract.test.mjs +500 -500
- package/agent/extensions/pi-web-access/test/proxy-transport.test.mjs +286 -286
- package/agent/extensions/pi-web-access/test/query-rewrite.test.mjs +52 -52
- package/agent/extensions/pi-web-access/test/rsc-fallback.test.mjs +102 -102
- package/agent/extensions/pi-web-access/test/search-error-render.test.mjs +152 -152
- package/agent/extensions/pi-web-access/test/search-providers.test.mjs +274 -274
- package/agent/extensions/pi-web-access/test/source-check.test.mjs +179 -179
- package/agent/extensions/pi-web-access/test/ssrf-allow-ranges-config.test.mjs +205 -205
- package/agent/extensions/pi-web-access/test/ssrf-protection.test.mjs +456 -456
- package/agent/extensions/pi-web-access/test/summary-model-scope.test.mjs +106 -106
- package/agent/extensions/pi-web-access/test/tool-registration-config.test.mjs +182 -182
- package/agent/extensions/pi-web-access/test/web-search-answer-render.test.mjs +66 -66
- package/agent/extensions/pi-web-access/test/youtube-extract-errors.test.mjs +64 -64
- package/agent/extensions/pi-web-access/tsconfig.json +11 -11
- package/agent/extensions/pi-web-access/utils.ts +451 -451
- package/agent/extensions/pi-web-access/video-extract.ts +392 -392
- package/agent/extensions/pi-web-access/youtube-extract.ts +328 -328
- package/agent/extensions/shared/activity-status.ts +31 -31
- package/agent/extensions/shared/child-session.test.ts +270 -270
- package/agent/extensions/shared/child-session.ts +148 -148
- package/agent/extensions/shared/context-utilization.test.ts +48 -48
- package/agent/extensions/shared/context-utilization.ts +47 -47
- package/agent/extensions/shared/dashboard-state.ts +99 -99
- package/agent/extensions/shared/install.ps1 +27 -27
- package/agent/extensions/shared/install.sh +24 -24
- package/agent/extensions/shared/tool-call-timeout.test.ts +117 -117
- package/agent/extensions/shared/tool-call-timeout.ts +104 -104
- package/agent/extensions/skillsconf/README.md +74 -74
- package/agent/extensions/skillsconf/index.ts +92 -92
- package/agent/extensions/skillsconf/install.ps1 +27 -27
- package/agent/extensions/skillsconf/install.sh +24 -24
- package/agent/extensions/skillsconf/package-lock.json +1809 -1809
- package/agent/extensions/skillsconf/package.json +18 -18
- package/agent/extensions/skillsconf/src/delete-skill.test.ts +64 -64
- package/agent/extensions/skillsconf/src/delete-skill.ts +45 -45
- package/agent/extensions/skillsconf/src/filter.test.ts +80 -80
- package/agent/extensions/skillsconf/src/filter.ts +74 -74
- package/agent/extensions/skillsconf/src/fuzzy.ts +26 -26
- package/agent/extensions/skillsconf/src/persistence.test.ts +72 -72
- package/agent/extensions/skillsconf/src/persistence.ts +169 -169
- package/agent/extensions/skillsconf/src/ui/SkillConfView.test.ts +337 -337
- package/agent/extensions/skillsconf/src/ui/SkillConfView.ts +758 -758
- package/agent/extensions/skillsconf/src/ui/text-input.ts +91 -91
- package/agent/extensions/skillsconf/src/ui/tui-helpers.ts +144 -144
- package/agent/extensions/skillsconf/tsconfig.json +15 -15
- package/agent/extensions/statusline/index.ts +273 -282
- package/agent/extensions/statusline/install.ps1 +27 -27
- package/agent/extensions/statusline/install.sh +24 -24
- package/agent/extensions/subagents/by-the-way.test.ts +29 -29
- package/agent/extensions/subagents/claude.test.ts +119 -119
- package/agent/extensions/subagents/codex.test.ts +102 -102
- package/agent/extensions/subagents/context-usage.test.ts +107 -107
- package/agent/extensions/subagents/docs/design-plan.md +568 -568
- package/agent/extensions/subagents/docs/effect-v4-extension-guide.md +354 -354
- package/agent/extensions/subagents/docs/effect-v4-notes.md +571 -571
- package/agent/extensions/subagents/index.ts +779 -779
- package/agent/extensions/subagents/install.ps1 +27 -27
- package/agent/extensions/subagents/install.sh +24 -24
- package/agent/extensions/subagents/manager.test.ts +276 -276
- package/agent/extensions/subagents/package-lock.json +2244 -2244
- package/agent/extensions/subagents/package.json +19 -19
- package/agent/extensions/subagents/result-delivery.test.ts +27 -27
- package/agent/extensions/subagents/src/backend.ts +73 -73
- package/agent/extensions/subagents/src/backends/claude.ts +701 -701
- package/agent/extensions/subagents/src/backends/codex.ts +1060 -1060
- package/agent/extensions/subagents/src/backends/pi.ts +575 -575
- package/agent/extensions/subagents/src/backends/stub.ts +300 -300
- package/agent/extensions/subagents/src/by-the-way.ts +21 -21
- package/agent/extensions/subagents/src/domain.ts +253 -253
- package/agent/extensions/subagents/src/format.ts +74 -74
- package/agent/extensions/subagents/src/manager.ts +736 -736
- package/agent/extensions/subagents/src/prompt.ts +92 -92
- package/agent/extensions/subagents/src/result-delivery.ts +20 -20
- package/agent/extensions/subagents/src/runtime.ts +53 -53
- package/agent/extensions/subagents/src/ui/takeover.ts +583 -583
- package/agent/extensions/subagents/src/ui/transcript.ts +201 -201
- package/agent/extensions/subagents/takeover.test.ts +29 -29
- package/agent/extensions/subagents/tsconfig.json +7 -7
- package/agent/extensions/todo/AGENTS.md +38 -38
- package/agent/extensions/todo/LICENSE +21 -21
- package/agent/extensions/todo/config.ts +55 -55
- package/agent/extensions/todo/index.ts +151 -151
- package/agent/extensions/todo/install.ps1 +27 -27
- package/agent/extensions/todo/install.sh +24 -24
- package/agent/extensions/todo/locales/de.json +17 -17
- package/agent/extensions/todo/locales/en.json +15 -15
- package/agent/extensions/todo/locales/es.json +17 -17
- package/agent/extensions/todo/locales/fr.json +17 -17
- package/agent/extensions/todo/locales/pt-BR.json +17 -17
- package/agent/extensions/todo/locales/pt.json +17 -17
- package/agent/extensions/todo/locales/ru.json +17 -17
- package/agent/extensions/todo/locales/uk.json +17 -17
- package/agent/extensions/todo/locales/zh.json +17 -17
- package/agent/extensions/todo/package-lock.json +3358 -3358
- package/agent/extensions/todo/package.json +67 -67
- package/agent/extensions/todo/state/i18n-bridge.ts +64 -64
- package/agent/extensions/todo/state/invariants.ts +20 -20
- package/agent/extensions/todo/state/replay.ts +38 -38
- package/agent/extensions/todo/state/selectors.ts +107 -107
- package/agent/extensions/todo/state/state-reducer.ts +326 -326
- package/agent/extensions/todo/state/state.ts +18 -18
- package/agent/extensions/todo/state/store.ts +82 -82
- package/agent/extensions/todo/state/task-graph.ts +57 -57
- package/agent/extensions/todo/todo-overlay.ts +200 -200
- package/agent/extensions/todo/todo.ts +155 -155
- package/agent/extensions/todo/tool/response-envelope.ts +109 -109
- package/agent/extensions/todo/tool/types.ts +206 -206
- package/agent/extensions/todo/view/format.ts +177 -177
- package/agent/extensions/trim-context/README.md +54 -54
- package/agent/extensions/trim-context/index.ts +487 -487
- package/agent/extensions/trim-context/install.ps1 +27 -27
- package/agent/extensions/trim-context/install.sh +24 -24
- package/agent/keybindings.json +7 -7
- package/agent/version.txt +1 -1
- package/bin/kiln.js +30 -21
- package/package.json +1 -1
- package/agent/extensions/taste/index.ts +0 -443
- package/agent/extensions/taste/install.ps1 +0 -27
- package/agent/extensions/taste/install.sh +0 -24
- package/agent.bak.20260905-190020/AGENTS.md +0 -67
- package/agent.bak.20260905-190020/README.md +0 -5
- package/agent.bak.20260905-190020/extensions/ask-user/index.ts +0 -418
- package/agent.bak.20260905-190020/extensions/ask-user/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/ask-user/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/ask-user/package-lock.json +0 -769
- package/agent.bak.20260905-190020/extensions/ask-user/package.json +0 -19
- package/agent.bak.20260905-190020/extensions/ask-user/prompt.ts +0 -45
- package/agent.bak.20260905-190020/extensions/ask-user/tsconfig.json +0 -7
- package/agent.bak.20260905-190020/extensions/background-terminals/docs/implementation-guide.md +0 -942
- package/agent.bak.20260905-190020/extensions/background-terminals/index.ts +0 -629
- package/agent.bak.20260905-190020/extensions/background-terminals/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/background-terminals/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/background-terminals/package-lock.json +0 -769
- package/agent.bak.20260905-190020/extensions/background-terminals/package.json +0 -17
- package/agent.bak.20260905-190020/extensions/background-terminals/src/domain.ts +0 -87
- package/agent.bak.20260905-190020/extensions/background-terminals/src/manager.ts +0 -907
- package/agent.bak.20260905-190020/extensions/background-terminals/src/output.ts +0 -84
- package/agent.bak.20260905-190020/extensions/background-terminals/src/prompt.ts +0 -142
- package/agent.bak.20260905-190020/extensions/background-terminals/src/result-delivery.ts +0 -27
- package/agent.bak.20260905-190020/extensions/background-terminals/src/runtime.ts +0 -36
- package/agent.bak.20260905-190020/extensions/background-terminals/src/ui/output-view.ts +0 -79
- package/agent.bak.20260905-190020/extensions/background-terminals/src/ui/ps.ts +0 -621
- package/agent.bak.20260905-190020/extensions/background-terminals/src/widget-order.ts +0 -121
- package/agent.bak.20260905-190020/extensions/background-terminals/test/manager.test.ts +0 -735
- package/agent.bak.20260905-190020/extensions/background-terminals/test/output.test.ts +0 -109
- package/agent.bak.20260905-190020/extensions/background-terminals/test/prompt.test.ts +0 -125
- package/agent.bak.20260905-190020/extensions/background-terminals/test/ps.test.ts +0 -82
- package/agent.bak.20260905-190020/extensions/background-terminals/test/result-delivery.test.ts +0 -44
- package/agent.bak.20260905-190020/extensions/background-terminals/tsconfig.json +0 -7
- package/agent.bak.20260905-190020/extensions/destructive/README.md +0 -34
- package/agent.bak.20260905-190020/extensions/destructive/index.ts +0 -124
- package/agent.bak.20260905-190020/extensions/destructive/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/destructive/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/file-search/index.ts +0 -459
- package/agent.bak.20260905-190020/extensions/file-search/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/file-search/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/file-search/package-lock.json +0 -2253
- package/agent.bak.20260905-190020/extensions/file-search/package.json +0 -23
- package/agent.bak.20260905-190020/extensions/file-search/src/args.ts +0 -122
- package/agent.bak.20260905-190020/extensions/file-search/src/binaries.ts +0 -422
- package/agent.bak.20260905-190020/extensions/file-search/src/output.ts +0 -126
- package/agent.bak.20260905-190020/extensions/file-search/src/process.ts +0 -146
- package/agent.bak.20260905-190020/extensions/file-search/src/prompt.ts +0 -52
- package/agent.bak.20260905-190020/extensions/file-search/test/index.spec.ts +0 -443
- package/agent.bak.20260905-190020/extensions/file-search/tsconfig.json +0 -7
- package/agent.bak.20260905-190020/extensions/goal/README.md +0 -50
- package/agent.bak.20260905-190020/extensions/goal/index.ts +0 -155
- package/agent.bak.20260905-190020/extensions/goal/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/goal/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/kiln-update/README.md +0 -25
- package/agent.bak.20260905-190020/extensions/kiln-update/index.ts +0 -99
- package/agent.bak.20260905-190020/extensions/kiln-update/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/kiln-update/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/modelconf/PLAN.md +0 -915
- package/agent.bak.20260905-190020/extensions/modelconf/README.md +0 -66
- package/agent.bak.20260905-190020/extensions/modelconf/index.ts +0 -296
- package/agent.bak.20260905-190020/extensions/modelconf/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/modelconf/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/modelconf/package-lock.json +0 -1809
- package/agent.bak.20260905-190020/extensions/modelconf/package.json +0 -13
- package/agent.bak.20260905-190020/extensions/modelconf/src/fuzzy.ts +0 -26
- package/agent.bak.20260905-190020/extensions/modelconf/src/glob.ts +0 -13
- package/agent.bak.20260905-190020/extensions/modelconf/src/persistence.test.ts +0 -46
- package/agent.bak.20260905-190020/extensions/modelconf/src/persistence.ts +0 -164
- package/agent.bak.20260905-190020/extensions/modelconf/src/ui/ModelConfView.test.ts +0 -75
- package/agent.bak.20260905-190020/extensions/modelconf/src/ui/ModelConfView.ts +0 -1101
- package/agent.bak.20260905-190020/extensions/modelconf/tsconfig.json +0 -15
- package/agent.bak.20260905-190020/extensions/pi-web-access/CHANGELOG.md +0 -690
- package/agent.bak.20260905-190020/extensions/pi-web-access/LICENSE +0 -21
- package/agent.bak.20260905-190020/extensions/pi-web-access/README.md +0 -470
- package/agent.bak.20260905-190020/extensions/pi-web-access/SECURITY.md +0 -5
- package/agent.bak.20260905-190020/extensions/pi-web-access/activity.ts +0 -101
- package/agent.bak.20260905-190020/extensions/pi-web-access/auth-fetch.ts +0 -148
- package/agent.bak.20260905-190020/extensions/pi-web-access/banner.png +0 -0
- package/agent.bak.20260905-190020/extensions/pi-web-access/brightdata-unlocker.ts +0 -272
- package/agent.bak.20260905-190020/extensions/pi-web-access/chrome-cookies.ts +0 -669
- package/agent.bak.20260905-190020/extensions/pi-web-access/content-find.ts +0 -139
- package/agent.bak.20260905-190020/extensions/pi-web-access/credential-source.ts +0 -191
- package/agent.bak.20260905-190020/extensions/pi-web-access/data-uri-sanitize.ts +0 -406
- package/agent.bak.20260905-190020/extensions/pi-web-access/datalab-pdf-extract.ts +0 -568
- package/agent.bak.20260905-190020/extensions/pi-web-access/declared-web-links.ts +0 -173
- package/agent.bak.20260905-190020/extensions/pi-web-access/evidence/CONTRACT-EVIDENCE.md +0 -496
- package/agent.bak.20260905-190020/extensions/pi-web-access/evidence/contract-probe.mjs +0 -140
- package/agent.bak.20260905-190020/extensions/pi-web-access/exa.ts +0 -526
- package/agent.bak.20260905-190020/extensions/pi-web-access/extract.ts +0 -1196
- package/agent.bak.20260905-190020/extensions/pi-web-access/feature-config.ts +0 -29
- package/agent.bak.20260905-190020/extensions/pi-web-access/fetch-params.ts +0 -111
- package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-adc.ts +0 -298
- package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-api.ts +0 -353
- package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-pdf-extract.ts +0 -108
- package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-search.ts +0 -21
- package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-url-context.ts +0 -128
- package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-web-config.ts +0 -101
- package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-web.ts +0 -487
- package/agent.bak.20260905-190020/extensions/pi-web-access/github-api.ts +0 -197
- package/agent.bak.20260905-190020/extensions/pi-web-access/github-extract.ts +0 -746
- package/agent.bak.20260905-190020/extensions/pi-web-access/github-issue-pr.ts +0 -700
- package/agent.bak.20260905-190020/extensions/pi-web-access/index.ts +0 -1737
- package/agent.bak.20260905-190020/extensions/pi-web-access/package-lock.json +0 -5808
- package/agent.bak.20260905-190020/extensions/pi-web-access/package.json +0 -64
- package/agent.bak.20260905-190020/extensions/pi-web-access/page-query.ts +0 -96
- package/agent.bak.20260905-190020/extensions/pi-web-access/pdf-extract.ts +0 -409
- package/agent.bak.20260905-190020/extensions/pi-web-access/pi-web-fetch-demo.mp4 +0 -0
- package/agent.bak.20260905-190020/extensions/pi-web-access/promise-try.d.ts +0 -7
- package/agent.bak.20260905-190020/extensions/pi-web-access/query-rewrite.ts +0 -51
- package/agent.bak.20260905-190020/extensions/pi-web-access/render-search-error.ts +0 -170
- package/agent.bak.20260905-190020/extensions/pi-web-access/rsc-extract.ts +0 -338
- package/agent.bak.20260905-190020/extensions/pi-web-access/search-types.ts +0 -20
- package/agent.bak.20260905-190020/extensions/pi-web-access/source-check.ts +0 -282
- package/agent.bak.20260905-190020/extensions/pi-web-access/ssrf-protection.ts +0 -526
- package/agent.bak.20260905-190020/extensions/pi-web-access/storage.ts +0 -521
- package/agent.bak.20260905-190020/extensions/pi-web-access/summary-model-scope.ts +0 -125
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/auth-fetch.test.mjs +0 -208
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/brightdata-unlocker.test.mjs +0 -840
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/chrome-cookie-extraction.test.mjs +0 -441
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/config-path.test.mjs +0 -283
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/content-find.test.mjs +0 -25
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/credential-source.test.mjs +0 -118
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/data-uri-sanitize.test.mjs +0 -210
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/datalab-pdf-extract.test.mjs +0 -552
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/declared-web-links.test.mjs +0 -212
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-answer-storage.test.mjs +0 -40
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-cache-storage.test.mjs +0 -334
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-content-domain-policy.test.mjs +0 -95
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-modes.test.mjs +0 -53
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-not-found-guidance.test.mjs +0 -92
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-params.test.mjs +0 -86
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-render-call.test.mjs +0 -34
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-routing.test.mjs +0 -173
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-adc-auth.test.mjs +0 -257
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-api-transport.test.mjs +0 -170
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-pdf-extract.test.mjs +0 -133
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +0 -178
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-web-header-overflow.test.mjs +0 -148
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/get-search-content.test.mjs +0 -223
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/github-extract.test.mjs +0 -378
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/github-issue-pr.test.mjs +0 -565
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/inline-content-config.test.mjs +0 -99
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/lazy-extract-load.test.mjs +0 -118
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/local-video-oversize.test.mjs +0 -52
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/package-typebox-dependency.test.mjs +0 -50
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/page-query.test.mjs +0 -51
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/pdf-config.test.mjs +0 -140
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/pdf-extract.test.mjs +0 -500
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/proxy-transport.test.mjs +0 -286
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/query-rewrite.test.mjs +0 -52
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/rsc-fallback.test.mjs +0 -102
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/search-error-render.test.mjs +0 -152
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/search-providers.test.mjs +0 -274
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/source-check.test.mjs +0 -179
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/ssrf-allow-ranges-config.test.mjs +0 -205
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/ssrf-protection.test.mjs +0 -456
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/summary-model-scope.test.mjs +0 -106
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/tool-registration-config.test.mjs +0 -182
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/web-search-answer-render.test.mjs +0 -66
- package/agent.bak.20260905-190020/extensions/pi-web-access/test/youtube-extract-errors.test.mjs +0 -64
- package/agent.bak.20260905-190020/extensions/pi-web-access/tsconfig.json +0 -11
- package/agent.bak.20260905-190020/extensions/pi-web-access/utils.ts +0 -451
- package/agent.bak.20260905-190020/extensions/pi-web-access/video-extract.ts +0 -392
- package/agent.bak.20260905-190020/extensions/pi-web-access/youtube-extract.ts +0 -328
- package/agent.bak.20260905-190020/extensions/shared/activity-status.ts +0 -31
- package/agent.bak.20260905-190020/extensions/shared/child-session.ts +0 -148
- package/agent.bak.20260905-190020/extensions/shared/context-utilization.ts +0 -47
- package/agent.bak.20260905-190020/extensions/shared/dashboard-state.ts +0 -99
- package/agent.bak.20260905-190020/extensions/shared/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/shared/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/shared/test/child-session.test.ts +0 -270
- package/agent.bak.20260905-190020/extensions/shared/test/context-utilization.test.ts +0 -48
- package/agent.bak.20260905-190020/extensions/shared/test/tool-call-timeout.test.ts +0 -117
- package/agent.bak.20260905-190020/extensions/shared/test/widget-order.test.ts +0 -167
- package/agent.bak.20260905-190020/extensions/shared/tool-call-timeout.ts +0 -104
- package/agent.bak.20260905-190020/extensions/skillsconf/README.md +0 -74
- package/agent.bak.20260905-190020/extensions/skillsconf/index.ts +0 -92
- package/agent.bak.20260905-190020/extensions/skillsconf/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/skillsconf/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/skillsconf/package-lock.json +0 -1809
- package/agent.bak.20260905-190020/extensions/skillsconf/package.json +0 -18
- package/agent.bak.20260905-190020/extensions/skillsconf/src/delete-skill.test.ts +0 -64
- package/agent.bak.20260905-190020/extensions/skillsconf/src/delete-skill.ts +0 -45
- package/agent.bak.20260905-190020/extensions/skillsconf/src/filter.test.ts +0 -80
- package/agent.bak.20260905-190020/extensions/skillsconf/src/filter.ts +0 -74
- package/agent.bak.20260905-190020/extensions/skillsconf/src/fuzzy.ts +0 -26
- package/agent.bak.20260905-190020/extensions/skillsconf/src/persistence.test.ts +0 -72
- package/agent.bak.20260905-190020/extensions/skillsconf/src/persistence.ts +0 -169
- package/agent.bak.20260905-190020/extensions/skillsconf/src/ui/SkillConfView.test.ts +0 -337
- package/agent.bak.20260905-190020/extensions/skillsconf/src/ui/SkillConfView.ts +0 -758
- package/agent.bak.20260905-190020/extensions/skillsconf/src/ui/text-input.ts +0 -91
- package/agent.bak.20260905-190020/extensions/skillsconf/src/ui/tui-helpers.ts +0 -144
- package/agent.bak.20260905-190020/extensions/skillsconf/tsconfig.json +0 -15
- package/agent.bak.20260905-190020/extensions/statusline/index.ts +0 -282
- package/agent.bak.20260905-190020/extensions/statusline/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/statusline/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/subagents/docs/design-plan.md +0 -568
- package/agent.bak.20260905-190020/extensions/subagents/docs/effect-v4-extension-guide.md +0 -354
- package/agent.bak.20260905-190020/extensions/subagents/docs/effect-v4-notes.md +0 -571
- package/agent.bak.20260905-190020/extensions/subagents/index.ts +0 -826
- package/agent.bak.20260905-190020/extensions/subagents/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/subagents/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/subagents/package-lock.json +0 -2244
- package/agent.bak.20260905-190020/extensions/subagents/package.json +0 -19
- package/agent.bak.20260905-190020/extensions/subagents/src/backend.ts +0 -73
- package/agent.bak.20260905-190020/extensions/subagents/src/backends/claude.ts +0 -701
- package/agent.bak.20260905-190020/extensions/subagents/src/backends/codex.ts +0 -1060
- package/agent.bak.20260905-190020/extensions/subagents/src/backends/pi.ts +0 -575
- package/agent.bak.20260905-190020/extensions/subagents/src/backends/stub.ts +0 -300
- package/agent.bak.20260905-190020/extensions/subagents/src/by-the-way.ts +0 -21
- package/agent.bak.20260905-190020/extensions/subagents/src/domain.ts +0 -253
- package/agent.bak.20260905-190020/extensions/subagents/src/format.ts +0 -74
- package/agent.bak.20260905-190020/extensions/subagents/src/manager.ts +0 -736
- package/agent.bak.20260905-190020/extensions/subagents/src/prompt.ts +0 -92
- package/agent.bak.20260905-190020/extensions/subagents/src/result-delivery.ts +0 -20
- package/agent.bak.20260905-190020/extensions/subagents/src/runtime.ts +0 -53
- package/agent.bak.20260905-190020/extensions/subagents/src/ui/takeover.ts +0 -583
- package/agent.bak.20260905-190020/extensions/subagents/src/ui/transcript.ts +0 -201
- package/agent.bak.20260905-190020/extensions/subagents/src/widget-order.ts +0 -121
- package/agent.bak.20260905-190020/extensions/subagents/test/by-the-way.test.ts +0 -29
- package/agent.bak.20260905-190020/extensions/subagents/test/claude.test.ts +0 -119
- package/agent.bak.20260905-190020/extensions/subagents/test/codex.test.ts +0 -102
- package/agent.bak.20260905-190020/extensions/subagents/test/context-usage.test.ts +0 -107
- package/agent.bak.20260905-190020/extensions/subagents/test/manager.test.ts +0 -276
- package/agent.bak.20260905-190020/extensions/subagents/test/result-delivery.test.ts +0 -27
- package/agent.bak.20260905-190020/extensions/subagents/test/takeover.test.ts +0 -29
- package/agent.bak.20260905-190020/extensions/subagents/tsconfig.json +0 -7
- package/agent.bak.20260905-190020/extensions/taste/index.ts +0 -443
- package/agent.bak.20260905-190020/extensions/taste/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/taste/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/todo/AGENTS.md +0 -38
- package/agent.bak.20260905-190020/extensions/todo/LICENSE +0 -21
- package/agent.bak.20260905-190020/extensions/todo/config.ts +0 -55
- package/agent.bak.20260905-190020/extensions/todo/index.ts +0 -151
- package/agent.bak.20260905-190020/extensions/todo/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/todo/install.sh +0 -21
- package/agent.bak.20260905-190020/extensions/todo/locales/de.json +0 -17
- package/agent.bak.20260905-190020/extensions/todo/locales/en.json +0 -15
- package/agent.bak.20260905-190020/extensions/todo/locales/es.json +0 -17
- package/agent.bak.20260905-190020/extensions/todo/locales/fr.json +0 -17
- package/agent.bak.20260905-190020/extensions/todo/locales/pt-BR.json +0 -17
- package/agent.bak.20260905-190020/extensions/todo/locales/pt.json +0 -17
- package/agent.bak.20260905-190020/extensions/todo/locales/ru.json +0 -17
- package/agent.bak.20260905-190020/extensions/todo/locales/uk.json +0 -17
- package/agent.bak.20260905-190020/extensions/todo/locales/zh.json +0 -17
- package/agent.bak.20260905-190020/extensions/todo/package-lock.json +0 -3358
- package/agent.bak.20260905-190020/extensions/todo/package.json +0 -67
- package/agent.bak.20260905-190020/extensions/todo/state/i18n-bridge.ts +0 -64
- package/agent.bak.20260905-190020/extensions/todo/state/invariants.ts +0 -20
- package/agent.bak.20260905-190020/extensions/todo/state/replay.ts +0 -38
- package/agent.bak.20260905-190020/extensions/todo/state/selectors.ts +0 -107
- package/agent.bak.20260905-190020/extensions/todo/state/state-reducer.ts +0 -326
- package/agent.bak.20260905-190020/extensions/todo/state/state.ts +0 -18
- package/agent.bak.20260905-190020/extensions/todo/state/store.ts +0 -82
- package/agent.bak.20260905-190020/extensions/todo/state/task-graph.ts +0 -57
- package/agent.bak.20260905-190020/extensions/todo/todo-overlay.ts +0 -204
- package/agent.bak.20260905-190020/extensions/todo/todo.ts +0 -155
- package/agent.bak.20260905-190020/extensions/todo/tool/response-envelope.ts +0 -109
- package/agent.bak.20260905-190020/extensions/todo/tool/types.ts +0 -206
- package/agent.bak.20260905-190020/extensions/todo/view/format.ts +0 -177
- package/agent.bak.20260905-190020/extensions/todo/widget-order.ts +0 -121
- package/agent.bak.20260905-190020/extensions/trim-context/README.md +0 -54
- package/agent.bak.20260905-190020/extensions/trim-context/index.ts +0 -487
- package/agent.bak.20260905-190020/extensions/trim-context/install.ps1 +0 -23
- package/agent.bak.20260905-190020/extensions/trim-context/install.sh +0 -21
- package/agent.bak.20260905-190020/keybindings.json +0 -7
|
@@ -1,354 +1,354 @@
|
|
|
1
|
-
# Building a pi extension on the Effect v4 setup
|
|
2
|
-
|
|
3
|
-
> Practical, migration-oriented companion to [`effect-v4-notes.md`](./effect-v4-notes.md).
|
|
4
|
-
> That file is the Effect API cheat-sheet (v3→v4 renames, child processes, concurrency);
|
|
5
|
-
> **this** file is how to stand up _one pi extension_ on the same toolchain and where to
|
|
6
|
-
> draw the line between "wrap in Effect" and "leave as plain TS".
|
|
7
|
-
>
|
|
8
|
-
> **Verified against** `effect@4.0.0-beta.98`, `@effect/platform-node@4.0.0-beta.98`,
|
|
9
|
-
> `@effect/tsgo@0.19.0`, `typescript@7.0.2` (checked 2026-07-13, in `extensions/subagents`).
|
|
10
|
-
> `npm run check` there passes clean — use it as the reference implementation.
|
|
11
|
-
>
|
|
12
|
-
> Audience: the agents migrating `firecrawl-search`, `ask-user`, `model-info`,
|
|
13
|
-
> `git-info`, `ui-customization`, and `copy-all`.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## 0. The one rule: Effect is for the async core, not the whole file
|
|
18
|
-
|
|
19
|
-
A pi extension's public surface is **plain callbacks** the host calls:
|
|
20
|
-
`export default function (pi: ExtensionAPI)`, `pi.registerTool({ …, async execute() })`,
|
|
21
|
-
`pi.registerCommand`, `pi.on(...)`, renderers. None of that changes. Effect lives _inside_
|
|
22
|
-
those callbacks — you run an effect at the top of `execute` and return its value.
|
|
23
|
-
|
|
24
|
-
Reach for Effect only where you actually get something from it:
|
|
25
|
-
|
|
26
|
-
- **Yes:** async work that needs typed errors, cancellation via the tool `AbortSignal`,
|
|
27
|
-
timeouts, retries/polling, or a resource whose lifetime must outlive one call
|
|
28
|
-
(child process, subscription) → child processes (`git-info`, `copy-all`), the
|
|
29
|
-
Firecrawl SDK calls (`firecrawl-search`), git/gh polling (`git-info`).
|
|
30
|
-
- **No / barely:** pure TUI popups and rendering (`ask-user`, `ui-customization`),
|
|
31
|
-
cross-extension channel plumbing, cost/token bookkeeping (`model-info`). These are
|
|
32
|
-
synchronous or already-Promise UI code; wrapping them in Effect adds ceremony and no
|
|
33
|
-
safety. Migrate them by keeping the logic and only touching whatever genuinely async
|
|
34
|
-
part benefits (usually nothing).
|
|
35
|
-
|
|
36
|
-
If an extension has no async core worth typing, the "migration" may be just adopting the
|
|
37
|
-
toolchain (§1) and leaving the body plain. Don't invent an Effect layer to have one.
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## 1. Per-extension toolchain (copy this exactly)
|
|
42
|
-
|
|
43
|
-
Each extension is its own npm package with its own `node_modules`. Replicate the pinned
|
|
44
|
-
setup — do **not** float the versions.
|
|
45
|
-
|
|
46
|
-
`package.json`:
|
|
47
|
-
|
|
48
|
-
```jsonc
|
|
49
|
-
{
|
|
50
|
-
"name": "<ext>",
|
|
51
|
-
"private": true,
|
|
52
|
-
"type": "module",
|
|
53
|
-
"scripts": {
|
|
54
|
-
"check": "tsc --noEmit -p .",
|
|
55
|
-
"prepare": "effect-tsgo patch", // patches the Effect LS into the tsgo binary
|
|
56
|
-
},
|
|
57
|
-
"dependencies": {
|
|
58
|
-
"effect": "4.0.0-beta.98", // EXACT pin, no ^
|
|
59
|
-
"@effect/platform-node": "4.0.0-beta.98", // only if you touch fs / child processes
|
|
60
|
-
},
|
|
61
|
-
"devDependencies": {
|
|
62
|
-
"@effect/tsgo": "^0.19.0",
|
|
63
|
-
"typescript": "^7.0.2",
|
|
64
|
-
},
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
`tsconfig.json` (extends the repo root, adds the Effect language-service plugin):
|
|
69
|
-
|
|
70
|
-
```jsonc
|
|
71
|
-
{
|
|
72
|
-
"extends": "../../tsconfig.json",
|
|
73
|
-
"compilerOptions": {
|
|
74
|
-
"plugins": [{ "name": "@effect/language-service" }],
|
|
75
|
-
},
|
|
76
|
-
"include": ["index.ts", "src/**/*.ts", "*.test.ts"],
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
The root `tsconfig.json` already sets `strict`, `module`/`moduleResolution: NodeNext`,
|
|
81
|
-
`verbatimModuleSyntax`, `allowImportingTsExtensions`, `target: ES2022`, `types: ["node"]`.
|
|
82
|
-
Keep local `.ts` imports written **with the `.ts` extension** (`./src/manager.ts`), matching
|
|
83
|
-
the house style.
|
|
84
|
-
|
|
85
|
-
### The LSP / language-service, precisely
|
|
86
|
-
|
|
87
|
-
- `typescript@7` is the **native (tsgo) TypeScript** — its `tsc` is a Go binary, and it's
|
|
88
|
-
what `npm run check` runs.
|
|
89
|
-
- `@effect/language-service` is **not an installed npm package** here (you won't find it in
|
|
90
|
-
`node_modules`). It's delivered by `effect-tsgo patch`, run automatically by the `prepare`
|
|
91
|
-
lifecycle script on `npm install`. The patch injects the Effect Language Service into the
|
|
92
|
-
tsgo binary; the tsconfig `plugins` entry then turns on Effect-aware editor diagnostics and
|
|
93
|
-
quickfixes (e.g. "yield missing services", floating effects).
|
|
94
|
-
- Practical sequence for a fresh/edited extension: `npm install` (runs the patch) →
|
|
95
|
-
`npm run check`. If editor diagnostics look stale, re-run `npx effect-tsgo patch`;
|
|
96
|
-
`npx effect-tsgo get-exe-path` prints the patched binary it resolved.
|
|
97
|
-
- The plugin drives the _editor_; it does not change `tsc` exit codes. `npm run check` is
|
|
98
|
-
still your ground-truth green/red signal.
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 2. The async boundary: one `ManagedRuntime` + a `runTool` helper
|
|
103
|
-
|
|
104
|
-
Every extension that uses Effect needs exactly this shape. Build **one** runtime lazily,
|
|
105
|
-
dispose it on shutdown, and funnel every tool handler through a single helper that turns
|
|
106
|
-
Effect exits into what pi expects (a value, or a thrown `Error`; interruption → a friendly
|
|
107
|
-
message). This is lifted verbatim from `src/runtime.ts` — reuse it.
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
// src/runtime.ts
|
|
111
|
-
import { Cause, Exit, Layer, ManagedRuntime, type Effect } from "effect";
|
|
112
|
-
import { NodeServices } from "@effect/platform-node"; // only if you need fs / processes
|
|
113
|
-
|
|
114
|
-
// Compose your services here (see §3). NodeServices.layer =
|
|
115
|
-
// ChildProcessSpawner | FileSystem | Path | Crypto | Stdio | Terminal.
|
|
116
|
-
const AppLayer = Layer.mergeAll(NodeServices.layer /*, MyServiceLive */);
|
|
117
|
-
|
|
118
|
-
export function createRuntime() {
|
|
119
|
-
return ManagedRuntime.make(AppLayer);
|
|
120
|
-
}
|
|
121
|
-
export type ExtRuntime = ReturnType<typeof createRuntime>;
|
|
122
|
-
|
|
123
|
-
/** Run an effect from an async handler: value on success, thrown Error otherwise. */
|
|
124
|
-
export async function runTool<A, E>(
|
|
125
|
-
runtime: ExtRuntime,
|
|
126
|
-
effect: Effect.Effect<A, E>,
|
|
127
|
-
options: { signal?: AbortSignal; interruptMessage?: string } = {},
|
|
128
|
-
) {
|
|
129
|
-
const exit = await runtime.runPromiseExit(
|
|
130
|
-
effect,
|
|
131
|
-
options.signal ? { signal: options.signal } : undefined,
|
|
132
|
-
);
|
|
133
|
-
if (Exit.isSuccess(exit)) return exit.value;
|
|
134
|
-
if (Cause.hasInterruptsOnly(exit.cause)) {
|
|
135
|
-
throw new Error(options.interruptMessage ?? "Operation was aborted.");
|
|
136
|
-
}
|
|
137
|
-
const [first] = Cause.prettyErrors(exit.cause);
|
|
138
|
-
throw new Error(first?.message ?? Cause.pretty(exit.cause));
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Wire it into the extension lifecycle (lazy build, dispose on shutdown):
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
// index.ts
|
|
146
|
-
export default function (pi: ExtensionAPI) {
|
|
147
|
-
let runtime: ExtRuntime | undefined;
|
|
148
|
-
const getRuntime = () => (runtime ??= createRuntime());
|
|
149
|
-
|
|
150
|
-
pi.registerTool({
|
|
151
|
-
name: "my_tool",
|
|
152
|
-
parameters: Type.Object({/* typebox */}),
|
|
153
|
-
async execute(_id, params, signal) {
|
|
154
|
-
return await runTool(getRuntime(), myEffect(params), {
|
|
155
|
-
signal,
|
|
156
|
-
interruptMessage: "Cancelled.",
|
|
157
|
-
});
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
pi.on("session_shutdown", async () => {
|
|
162
|
-
const closing = runtime;
|
|
163
|
-
runtime = undefined;
|
|
164
|
-
await closing?.dispose(); // runs all finalizers: kills scoped child processes, etc.
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Key facts:
|
|
170
|
-
|
|
171
|
-
- `runPromiseExit(effect, { signal })` — passing the tool's `AbortSignal` makes cancelling
|
|
172
|
-
the tool interrupt the fiber; scoped resources (child processes) are torn down.
|
|
173
|
-
- `runtime.runFork(effect)` for fire-and-forget background work (polling loops, §5).
|
|
174
|
-
- `dispose()` is the single teardown hook — put resource cleanup in Effect finalizers, not
|
|
175
|
-
in ad-hoc `session_shutdown` code.
|
|
176
|
-
- If an extension has **no** services (pure `Effect.tryPromise` calls, no fs/process), you
|
|
177
|
-
can skip `NodeServices.layer` and even skip `ManagedRuntime` — `Effect.runPromiseExit(effect, { signal })`
|
|
178
|
-
works standalone. Add the runtime only when you have a `Layer` to share.
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
## 3. Services, layers, errors (house style)
|
|
183
|
-
|
|
184
|
-
Mirror the subagents code. Class-style `Context.Service`, `Layer.effect`/`Layer.sync`,
|
|
185
|
-
`Data.TaggedError` for domain errors.
|
|
186
|
-
|
|
187
|
-
```ts
|
|
188
|
-
import { Context, Data, Effect, Layer } from "effect";
|
|
189
|
-
|
|
190
|
-
// Domain error — yieldable, tag-narrowable with Effect.catchTag:
|
|
191
|
-
export class GitError extends Data.TaggedError("GitError")<{
|
|
192
|
-
readonly message: string;
|
|
193
|
-
}> {}
|
|
194
|
-
|
|
195
|
-
// Service: the class value is the key AND the type.
|
|
196
|
-
export interface GitShape {
|
|
197
|
-
readonly status: Effect.Effect<string, GitError>;
|
|
198
|
-
}
|
|
199
|
-
export class Git extends Context.Service<Git, GitShape>()("gitinfo/Git") {}
|
|
200
|
-
|
|
201
|
-
// Layer building it (Layer.effect can use scoped resources; Layer.sync for pure):
|
|
202
|
-
export const GitLive: Layer.Layer<Git, never, ChildProcessSpawner> =
|
|
203
|
-
Layer.effect(
|
|
204
|
-
Git,
|
|
205
|
-
Effect.gen(function* () {
|
|
206
|
-
const spawner = yield* ChildProcessSpawner; // dependency, provided by NodeServices.layer
|
|
207
|
-
return Git.of({
|
|
208
|
-
status: spawner
|
|
209
|
-
.string(ChildProcess.make("git", ["status", "--porcelain"]))
|
|
210
|
-
.pipe(
|
|
211
|
-
Effect.mapError(
|
|
212
|
-
(cause) => new GitError({ message: String(cause) }),
|
|
213
|
-
),
|
|
214
|
-
),
|
|
215
|
-
});
|
|
216
|
-
}),
|
|
217
|
-
);
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Provide dependencies with `Layer.provide`, compose with `Layer.mergeAll` (see §2 `AppLayer`).
|
|
221
|
-
Full rename table (`Effect.fork`→`forkChild`, `catchAll`→`catch`, `Either`→`Result`, …) and
|
|
222
|
-
the child-process / concurrency APIs live in `effect-v4-notes.md` — don't re-derive them.
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
|
|
226
|
-
## 4. Recipe: wrapping a Promise SDK (firecrawl-search)
|
|
227
|
-
|
|
228
|
-
The Firecrawl client is Promise-based. Wrap each call in `Effect.tryPromise` with a typed
|
|
229
|
-
error; the callback receives an `AbortSignal` tied to fiber interruption — forward it to any
|
|
230
|
-
SDK that accepts one so tool cancellation propagates.
|
|
231
|
-
|
|
232
|
-
```ts
|
|
233
|
-
import { Data, Effect } from "effect";
|
|
234
|
-
|
|
235
|
-
class FirecrawlError extends Data.TaggedError("FirecrawlError")<{
|
|
236
|
-
readonly cause: unknown;
|
|
237
|
-
}> {}
|
|
238
|
-
|
|
239
|
-
const search = (client: Firecrawl, query: string) =>
|
|
240
|
-
Effect.tryPromise({
|
|
241
|
-
try: (signal) => client.search(query, {/* …, signal? if supported */}),
|
|
242
|
-
catch: (cause) => new FirecrawlError({ cause }),
|
|
243
|
-
});
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
There's no `Layer` here unless you want the client as a service. For a single tool this is
|
|
247
|
-
fine to call directly through `runTool` (or even plain `Effect.runPromiseExit`, §2). Keep the
|
|
248
|
-
existing `.env`/API-key reading and result truncation as plain TS — no reason to Effect-ify
|
|
249
|
-
string trimming.
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
## 5. Recipe: child processes + timeout + polling (git-info, copy-all)
|
|
254
|
-
|
|
255
|
-
`git-info` shells out to `git`/`gh` with per-command timeouts and polls on an interval;
|
|
256
|
-
`copy-all` pipes text into `pbcopy`. Two viable levels — pick the lightest that fits.
|
|
257
|
-
|
|
258
|
-
**Simple, one-shot, small:** if all you do is "run a command, capture stdout, with a
|
|
259
|
-
timeout," the Effect win is `Effect.timeout` + interruption killing the child. Use the
|
|
260
|
-
spawner service:
|
|
261
|
-
|
|
262
|
-
```ts
|
|
263
|
-
import { Effect } from "effect";
|
|
264
|
-
import { ChildProcess } from "effect/unstable/process";
|
|
265
|
-
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
|
|
266
|
-
|
|
267
|
-
const gitStatus = Effect.gen(function* () {
|
|
268
|
-
const spawner = yield* ChildProcessSpawner;
|
|
269
|
-
return yield* spawner
|
|
270
|
-
.string(ChildProcess.make("git", ["status", "--porcelain"], { cwd }))
|
|
271
|
-
.pipe(Effect.timeout("3 seconds")); // fails with Cause.TimeoutError (tag "TimeoutError")
|
|
272
|
-
});
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
Note the import gotcha: `ChildProcessSpawner` the **class** comes from the
|
|
276
|
-
`.../ChildProcessSpawner` submodule; the `effect/unstable/process` index gives you the
|
|
277
|
-
namespace. Provide `NodeServices.layer` (or `ChildProcessSpawner.layer`). Full command
|
|
278
|
-
builder / streaming / kill semantics are in `effect-v4-notes.md §6`.
|
|
279
|
-
|
|
280
|
-
**Polling on an interval:** replace `setInterval` with a forked, scheduled effect so it
|
|
281
|
-
cancels cleanly on dispose:
|
|
282
|
-
|
|
283
|
-
```ts
|
|
284
|
-
import { Effect, Schedule } from "effect";
|
|
285
|
-
|
|
286
|
-
const pollLoop = refresh.pipe(
|
|
287
|
-
Effect.catchCause(() => Effect.void), // don't let one failure kill the loop
|
|
288
|
-
Effect.repeat(Schedule.spaced("3 seconds")),
|
|
289
|
-
);
|
|
290
|
-
const fiber = runtime.runFork(pollLoop); // interrupted by runtime.dispose()
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
**When to stay plain:** `copy-all` spawning `pbcopy` is a trivial one-shot with no
|
|
294
|
-
cancellation need — the existing `node:child_process` + Promise wrapper is honestly fine.
|
|
295
|
-
Migrate it only for consistency; if you do, `Effect.callback` around `child.once("exit", …)`
|
|
296
|
-
(see notes §4) is the minimal wrapper. Don't add a service/layer for a clipboard write.
|
|
297
|
-
|
|
298
|
-
---
|
|
299
|
-
|
|
300
|
-
## 6. Recipe: UI popups & rendering (ask-user, ui-customization, model-info)
|
|
301
|
-
|
|
302
|
-
These are the "leave it mostly plain" cases.
|
|
303
|
-
|
|
304
|
-
- `ask-user` is a TUI popup that resolves a Promise when the user picks. That Promise already
|
|
305
|
-
models the one async thing. Effect adds nothing; if you want uniformity, wrap the final
|
|
306
|
-
await in `Effect.tryPromise` at the boundary and stop there. Do **not** build a service.
|
|
307
|
-
- `ui-customization` and `model-info` are renderers / event bookkeepers driven by
|
|
308
|
-
`pi.on(...)` and cross-extension channels (`shared/dashboard-state.ts`). Channels are a
|
|
309
|
-
pi-native mechanism — keep them. State counting and formatting stay synchronous TS.
|
|
310
|
-
- If `model-info` has a periodic "live update" tick, the §5 polling pattern applies; but a
|
|
311
|
-
plain timer here is also acceptable since there's no resource to tear down.
|
|
312
|
-
|
|
313
|
-
The migration bar for these: adopt the toolchain (§1) so they typecheck under TS7 + the
|
|
314
|
-
Effect LS, and only touch runtime code that has a real async/resource concern.
|
|
315
|
-
|
|
316
|
-
---
|
|
317
|
-
|
|
318
|
-
## 7. Verify — scoped to the one extension
|
|
319
|
-
|
|
320
|
-
Run everything from inside the extension directory so you never trigger a root/global build
|
|
321
|
-
or format:
|
|
322
|
-
|
|
323
|
-
```bash
|
|
324
|
-
cd extensions/<ext>
|
|
325
|
-
npm install # first time / after dep or script edits — runs `prepare` (effect-tsgo patch)
|
|
326
|
-
npm run check # tsc --noEmit -p . ← ground-truth green/red
|
|
327
|
-
npm run test # only if the extension defines tests; keep them minimal
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
`extensions/subagents` is the known-green reference: `npm run check` there exits 0 against
|
|
331
|
-
the pinned versions. If a migrated extension fails `check` with `Effect.fork`/`ServiceMap`/
|
|
332
|
-
`Either` errors, it's using stale v3/early-beta APIs — consult the rename table in
|
|
333
|
-
`effect-v4-notes.md`.
|
|
334
|
-
|
|
335
|
-
---
|
|
336
|
-
|
|
337
|
-
## 8. Don'ts (keep it lean)
|
|
338
|
-
|
|
339
|
-
1. **Don't float versions.** Pin `effect` and `@effect/platform-node` to the exact same
|
|
340
|
-
`4.0.0-beta.98`; `unstable/*` can break between betas.
|
|
341
|
-
2. **Don't Effect-ify pure/UI code.** No service or layer for a clipboard write, a string
|
|
342
|
-
truncation, or a popup. §0 is the test: is there a typed-error / cancellation / resource /
|
|
343
|
-
retry concern? If not, leave it.
|
|
344
|
-
3. **Don't guess APIs.** If it's not in this guide or `effect-v4-notes.md` and you haven't
|
|
345
|
-
grepped it in `node_modules/effect/dist/*.d.ts`, don't write it. Watch for hallucinated
|
|
346
|
-
`ServiceMap` (reverted to `Context`), `Effect.fork` (→ `forkChild`), `Effect.either`
|
|
347
|
-
(→ `Effect.result`).
|
|
348
|
-
4. **Don't hand-roll teardown.** Put cleanup in Effect finalizers and let `runtime.dispose()`
|
|
349
|
-
in `session_shutdown` run them.
|
|
350
|
-
5. **Don't over-test.** A `check` that passes plus one focused runtime test (where behavior
|
|
351
|
-
is non-obvious) beats a wall of defensive unit tests.
|
|
352
|
-
6. **Don't run root scripts.** No repo-root `tsc`, `prettier`, or `npm run format`; stay
|
|
353
|
-
inside `extensions/<ext>`.
|
|
354
|
-
</content>
|
|
1
|
+
# Building a pi extension on the Effect v4 setup
|
|
2
|
+
|
|
3
|
+
> Practical, migration-oriented companion to [`effect-v4-notes.md`](./effect-v4-notes.md).
|
|
4
|
+
> That file is the Effect API cheat-sheet (v3→v4 renames, child processes, concurrency);
|
|
5
|
+
> **this** file is how to stand up _one pi extension_ on the same toolchain and where to
|
|
6
|
+
> draw the line between "wrap in Effect" and "leave as plain TS".
|
|
7
|
+
>
|
|
8
|
+
> **Verified against** `effect@4.0.0-beta.98`, `@effect/platform-node@4.0.0-beta.98`,
|
|
9
|
+
> `@effect/tsgo@0.19.0`, `typescript@7.0.2` (checked 2026-07-13, in `extensions/subagents`).
|
|
10
|
+
> `npm run check` there passes clean — use it as the reference implementation.
|
|
11
|
+
>
|
|
12
|
+
> Audience: the agents migrating `firecrawl-search`, `ask-user`, `model-info`,
|
|
13
|
+
> `git-info`, `ui-customization`, and `copy-all`.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 0. The one rule: Effect is for the async core, not the whole file
|
|
18
|
+
|
|
19
|
+
A pi extension's public surface is **plain callbacks** the host calls:
|
|
20
|
+
`export default function (pi: ExtensionAPI)`, `pi.registerTool({ …, async execute() })`,
|
|
21
|
+
`pi.registerCommand`, `pi.on(...)`, renderers. None of that changes. Effect lives _inside_
|
|
22
|
+
those callbacks — you run an effect at the top of `execute` and return its value.
|
|
23
|
+
|
|
24
|
+
Reach for Effect only where you actually get something from it:
|
|
25
|
+
|
|
26
|
+
- **Yes:** async work that needs typed errors, cancellation via the tool `AbortSignal`,
|
|
27
|
+
timeouts, retries/polling, or a resource whose lifetime must outlive one call
|
|
28
|
+
(child process, subscription) → child processes (`git-info`, `copy-all`), the
|
|
29
|
+
Firecrawl SDK calls (`firecrawl-search`), git/gh polling (`git-info`).
|
|
30
|
+
- **No / barely:** pure TUI popups and rendering (`ask-user`, `ui-customization`),
|
|
31
|
+
cross-extension channel plumbing, cost/token bookkeeping (`model-info`). These are
|
|
32
|
+
synchronous or already-Promise UI code; wrapping them in Effect adds ceremony and no
|
|
33
|
+
safety. Migrate them by keeping the logic and only touching whatever genuinely async
|
|
34
|
+
part benefits (usually nothing).
|
|
35
|
+
|
|
36
|
+
If an extension has no async core worth typing, the "migration" may be just adopting the
|
|
37
|
+
toolchain (§1) and leaving the body plain. Don't invent an Effect layer to have one.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 1. Per-extension toolchain (copy this exactly)
|
|
42
|
+
|
|
43
|
+
Each extension is its own npm package with its own `node_modules`. Replicate the pinned
|
|
44
|
+
setup — do **not** float the versions.
|
|
45
|
+
|
|
46
|
+
`package.json`:
|
|
47
|
+
|
|
48
|
+
```jsonc
|
|
49
|
+
{
|
|
50
|
+
"name": "<ext>",
|
|
51
|
+
"private": true,
|
|
52
|
+
"type": "module",
|
|
53
|
+
"scripts": {
|
|
54
|
+
"check": "tsc --noEmit -p .",
|
|
55
|
+
"prepare": "effect-tsgo patch", // patches the Effect LS into the tsgo binary
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"effect": "4.0.0-beta.98", // EXACT pin, no ^
|
|
59
|
+
"@effect/platform-node": "4.0.0-beta.98", // only if you touch fs / child processes
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@effect/tsgo": "^0.19.0",
|
|
63
|
+
"typescript": "^7.0.2",
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`tsconfig.json` (extends the repo root, adds the Effect language-service plugin):
|
|
69
|
+
|
|
70
|
+
```jsonc
|
|
71
|
+
{
|
|
72
|
+
"extends": "../../tsconfig.json",
|
|
73
|
+
"compilerOptions": {
|
|
74
|
+
"plugins": [{ "name": "@effect/language-service" }],
|
|
75
|
+
},
|
|
76
|
+
"include": ["index.ts", "src/**/*.ts", "*.test.ts"],
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The root `tsconfig.json` already sets `strict`, `module`/`moduleResolution: NodeNext`,
|
|
81
|
+
`verbatimModuleSyntax`, `allowImportingTsExtensions`, `target: ES2022`, `types: ["node"]`.
|
|
82
|
+
Keep local `.ts` imports written **with the `.ts` extension** (`./src/manager.ts`), matching
|
|
83
|
+
the house style.
|
|
84
|
+
|
|
85
|
+
### The LSP / language-service, precisely
|
|
86
|
+
|
|
87
|
+
- `typescript@7` is the **native (tsgo) TypeScript** — its `tsc` is a Go binary, and it's
|
|
88
|
+
what `npm run check` runs.
|
|
89
|
+
- `@effect/language-service` is **not an installed npm package** here (you won't find it in
|
|
90
|
+
`node_modules`). It's delivered by `effect-tsgo patch`, run automatically by the `prepare`
|
|
91
|
+
lifecycle script on `npm install`. The patch injects the Effect Language Service into the
|
|
92
|
+
tsgo binary; the tsconfig `plugins` entry then turns on Effect-aware editor diagnostics and
|
|
93
|
+
quickfixes (e.g. "yield missing services", floating effects).
|
|
94
|
+
- Practical sequence for a fresh/edited extension: `npm install` (runs the patch) →
|
|
95
|
+
`npm run check`. If editor diagnostics look stale, re-run `npx effect-tsgo patch`;
|
|
96
|
+
`npx effect-tsgo get-exe-path` prints the patched binary it resolved.
|
|
97
|
+
- The plugin drives the _editor_; it does not change `tsc` exit codes. `npm run check` is
|
|
98
|
+
still your ground-truth green/red signal.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 2. The async boundary: one `ManagedRuntime` + a `runTool` helper
|
|
103
|
+
|
|
104
|
+
Every extension that uses Effect needs exactly this shape. Build **one** runtime lazily,
|
|
105
|
+
dispose it on shutdown, and funnel every tool handler through a single helper that turns
|
|
106
|
+
Effect exits into what pi expects (a value, or a thrown `Error`; interruption → a friendly
|
|
107
|
+
message). This is lifted verbatim from `src/runtime.ts` — reuse it.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
// src/runtime.ts
|
|
111
|
+
import { Cause, Exit, Layer, ManagedRuntime, type Effect } from "effect";
|
|
112
|
+
import { NodeServices } from "@effect/platform-node"; // only if you need fs / processes
|
|
113
|
+
|
|
114
|
+
// Compose your services here (see §3). NodeServices.layer =
|
|
115
|
+
// ChildProcessSpawner | FileSystem | Path | Crypto | Stdio | Terminal.
|
|
116
|
+
const AppLayer = Layer.mergeAll(NodeServices.layer /*, MyServiceLive */);
|
|
117
|
+
|
|
118
|
+
export function createRuntime() {
|
|
119
|
+
return ManagedRuntime.make(AppLayer);
|
|
120
|
+
}
|
|
121
|
+
export type ExtRuntime = ReturnType<typeof createRuntime>;
|
|
122
|
+
|
|
123
|
+
/** Run an effect from an async handler: value on success, thrown Error otherwise. */
|
|
124
|
+
export async function runTool<A, E>(
|
|
125
|
+
runtime: ExtRuntime,
|
|
126
|
+
effect: Effect.Effect<A, E>,
|
|
127
|
+
options: { signal?: AbortSignal; interruptMessage?: string } = {},
|
|
128
|
+
) {
|
|
129
|
+
const exit = await runtime.runPromiseExit(
|
|
130
|
+
effect,
|
|
131
|
+
options.signal ? { signal: options.signal } : undefined,
|
|
132
|
+
);
|
|
133
|
+
if (Exit.isSuccess(exit)) return exit.value;
|
|
134
|
+
if (Cause.hasInterruptsOnly(exit.cause)) {
|
|
135
|
+
throw new Error(options.interruptMessage ?? "Operation was aborted.");
|
|
136
|
+
}
|
|
137
|
+
const [first] = Cause.prettyErrors(exit.cause);
|
|
138
|
+
throw new Error(first?.message ?? Cause.pretty(exit.cause));
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Wire it into the extension lifecycle (lazy build, dispose on shutdown):
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
// index.ts
|
|
146
|
+
export default function (pi: ExtensionAPI) {
|
|
147
|
+
let runtime: ExtRuntime | undefined;
|
|
148
|
+
const getRuntime = () => (runtime ??= createRuntime());
|
|
149
|
+
|
|
150
|
+
pi.registerTool({
|
|
151
|
+
name: "my_tool",
|
|
152
|
+
parameters: Type.Object({/* typebox */}),
|
|
153
|
+
async execute(_id, params, signal) {
|
|
154
|
+
return await runTool(getRuntime(), myEffect(params), {
|
|
155
|
+
signal,
|
|
156
|
+
interruptMessage: "Cancelled.",
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
pi.on("session_shutdown", async () => {
|
|
162
|
+
const closing = runtime;
|
|
163
|
+
runtime = undefined;
|
|
164
|
+
await closing?.dispose(); // runs all finalizers: kills scoped child processes, etc.
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Key facts:
|
|
170
|
+
|
|
171
|
+
- `runPromiseExit(effect, { signal })` — passing the tool's `AbortSignal` makes cancelling
|
|
172
|
+
the tool interrupt the fiber; scoped resources (child processes) are torn down.
|
|
173
|
+
- `runtime.runFork(effect)` for fire-and-forget background work (polling loops, §5).
|
|
174
|
+
- `dispose()` is the single teardown hook — put resource cleanup in Effect finalizers, not
|
|
175
|
+
in ad-hoc `session_shutdown` code.
|
|
176
|
+
- If an extension has **no** services (pure `Effect.tryPromise` calls, no fs/process), you
|
|
177
|
+
can skip `NodeServices.layer` and even skip `ManagedRuntime` — `Effect.runPromiseExit(effect, { signal })`
|
|
178
|
+
works standalone. Add the runtime only when you have a `Layer` to share.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 3. Services, layers, errors (house style)
|
|
183
|
+
|
|
184
|
+
Mirror the subagents code. Class-style `Context.Service`, `Layer.effect`/`Layer.sync`,
|
|
185
|
+
`Data.TaggedError` for domain errors.
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import { Context, Data, Effect, Layer } from "effect";
|
|
189
|
+
|
|
190
|
+
// Domain error — yieldable, tag-narrowable with Effect.catchTag:
|
|
191
|
+
export class GitError extends Data.TaggedError("GitError")<{
|
|
192
|
+
readonly message: string;
|
|
193
|
+
}> {}
|
|
194
|
+
|
|
195
|
+
// Service: the class value is the key AND the type.
|
|
196
|
+
export interface GitShape {
|
|
197
|
+
readonly status: Effect.Effect<string, GitError>;
|
|
198
|
+
}
|
|
199
|
+
export class Git extends Context.Service<Git, GitShape>()("gitinfo/Git") {}
|
|
200
|
+
|
|
201
|
+
// Layer building it (Layer.effect can use scoped resources; Layer.sync for pure):
|
|
202
|
+
export const GitLive: Layer.Layer<Git, never, ChildProcessSpawner> =
|
|
203
|
+
Layer.effect(
|
|
204
|
+
Git,
|
|
205
|
+
Effect.gen(function* () {
|
|
206
|
+
const spawner = yield* ChildProcessSpawner; // dependency, provided by NodeServices.layer
|
|
207
|
+
return Git.of({
|
|
208
|
+
status: spawner
|
|
209
|
+
.string(ChildProcess.make("git", ["status", "--porcelain"]))
|
|
210
|
+
.pipe(
|
|
211
|
+
Effect.mapError(
|
|
212
|
+
(cause) => new GitError({ message: String(cause) }),
|
|
213
|
+
),
|
|
214
|
+
),
|
|
215
|
+
});
|
|
216
|
+
}),
|
|
217
|
+
);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Provide dependencies with `Layer.provide`, compose with `Layer.mergeAll` (see §2 `AppLayer`).
|
|
221
|
+
Full rename table (`Effect.fork`→`forkChild`, `catchAll`→`catch`, `Either`→`Result`, …) and
|
|
222
|
+
the child-process / concurrency APIs live in `effect-v4-notes.md` — don't re-derive them.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 4. Recipe: wrapping a Promise SDK (firecrawl-search)
|
|
227
|
+
|
|
228
|
+
The Firecrawl client is Promise-based. Wrap each call in `Effect.tryPromise` with a typed
|
|
229
|
+
error; the callback receives an `AbortSignal` tied to fiber interruption — forward it to any
|
|
230
|
+
SDK that accepts one so tool cancellation propagates.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { Data, Effect } from "effect";
|
|
234
|
+
|
|
235
|
+
class FirecrawlError extends Data.TaggedError("FirecrawlError")<{
|
|
236
|
+
readonly cause: unknown;
|
|
237
|
+
}> {}
|
|
238
|
+
|
|
239
|
+
const search = (client: Firecrawl, query: string) =>
|
|
240
|
+
Effect.tryPromise({
|
|
241
|
+
try: (signal) => client.search(query, {/* …, signal? if supported */}),
|
|
242
|
+
catch: (cause) => new FirecrawlError({ cause }),
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
There's no `Layer` here unless you want the client as a service. For a single tool this is
|
|
247
|
+
fine to call directly through `runTool` (or even plain `Effect.runPromiseExit`, §2). Keep the
|
|
248
|
+
existing `.env`/API-key reading and result truncation as plain TS — no reason to Effect-ify
|
|
249
|
+
string trimming.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## 5. Recipe: child processes + timeout + polling (git-info, copy-all)
|
|
254
|
+
|
|
255
|
+
`git-info` shells out to `git`/`gh` with per-command timeouts and polls on an interval;
|
|
256
|
+
`copy-all` pipes text into `pbcopy`. Two viable levels — pick the lightest that fits.
|
|
257
|
+
|
|
258
|
+
**Simple, one-shot, small:** if all you do is "run a command, capture stdout, with a
|
|
259
|
+
timeout," the Effect win is `Effect.timeout` + interruption killing the child. Use the
|
|
260
|
+
spawner service:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
import { Effect } from "effect";
|
|
264
|
+
import { ChildProcess } from "effect/unstable/process";
|
|
265
|
+
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
|
|
266
|
+
|
|
267
|
+
const gitStatus = Effect.gen(function* () {
|
|
268
|
+
const spawner = yield* ChildProcessSpawner;
|
|
269
|
+
return yield* spawner
|
|
270
|
+
.string(ChildProcess.make("git", ["status", "--porcelain"], { cwd }))
|
|
271
|
+
.pipe(Effect.timeout("3 seconds")); // fails with Cause.TimeoutError (tag "TimeoutError")
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Note the import gotcha: `ChildProcessSpawner` the **class** comes from the
|
|
276
|
+
`.../ChildProcessSpawner` submodule; the `effect/unstable/process` index gives you the
|
|
277
|
+
namespace. Provide `NodeServices.layer` (or `ChildProcessSpawner.layer`). Full command
|
|
278
|
+
builder / streaming / kill semantics are in `effect-v4-notes.md §6`.
|
|
279
|
+
|
|
280
|
+
**Polling on an interval:** replace `setInterval` with a forked, scheduled effect so it
|
|
281
|
+
cancels cleanly on dispose:
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
import { Effect, Schedule } from "effect";
|
|
285
|
+
|
|
286
|
+
const pollLoop = refresh.pipe(
|
|
287
|
+
Effect.catchCause(() => Effect.void), // don't let one failure kill the loop
|
|
288
|
+
Effect.repeat(Schedule.spaced("3 seconds")),
|
|
289
|
+
);
|
|
290
|
+
const fiber = runtime.runFork(pollLoop); // interrupted by runtime.dispose()
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**When to stay plain:** `copy-all` spawning `pbcopy` is a trivial one-shot with no
|
|
294
|
+
cancellation need — the existing `node:child_process` + Promise wrapper is honestly fine.
|
|
295
|
+
Migrate it only for consistency; if you do, `Effect.callback` around `child.once("exit", …)`
|
|
296
|
+
(see notes §4) is the minimal wrapper. Don't add a service/layer for a clipboard write.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 6. Recipe: UI popups & rendering (ask-user, ui-customization, model-info)
|
|
301
|
+
|
|
302
|
+
These are the "leave it mostly plain" cases.
|
|
303
|
+
|
|
304
|
+
- `ask-user` is a TUI popup that resolves a Promise when the user picks. That Promise already
|
|
305
|
+
models the one async thing. Effect adds nothing; if you want uniformity, wrap the final
|
|
306
|
+
await in `Effect.tryPromise` at the boundary and stop there. Do **not** build a service.
|
|
307
|
+
- `ui-customization` and `model-info` are renderers / event bookkeepers driven by
|
|
308
|
+
`pi.on(...)` and cross-extension channels (`shared/dashboard-state.ts`). Channels are a
|
|
309
|
+
pi-native mechanism — keep them. State counting and formatting stay synchronous TS.
|
|
310
|
+
- If `model-info` has a periodic "live update" tick, the §5 polling pattern applies; but a
|
|
311
|
+
plain timer here is also acceptable since there's no resource to tear down.
|
|
312
|
+
|
|
313
|
+
The migration bar for these: adopt the toolchain (§1) so they typecheck under TS7 + the
|
|
314
|
+
Effect LS, and only touch runtime code that has a real async/resource concern.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## 7. Verify — scoped to the one extension
|
|
319
|
+
|
|
320
|
+
Run everything from inside the extension directory so you never trigger a root/global build
|
|
321
|
+
or format:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
cd extensions/<ext>
|
|
325
|
+
npm install # first time / after dep or script edits — runs `prepare` (effect-tsgo patch)
|
|
326
|
+
npm run check # tsc --noEmit -p . ← ground-truth green/red
|
|
327
|
+
npm run test # only if the extension defines tests; keep them minimal
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
`extensions/subagents` is the known-green reference: `npm run check` there exits 0 against
|
|
331
|
+
the pinned versions. If a migrated extension fails `check` with `Effect.fork`/`ServiceMap`/
|
|
332
|
+
`Either` errors, it's using stale v3/early-beta APIs — consult the rename table in
|
|
333
|
+
`effect-v4-notes.md`.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## 8. Don'ts (keep it lean)
|
|
338
|
+
|
|
339
|
+
1. **Don't float versions.** Pin `effect` and `@effect/platform-node` to the exact same
|
|
340
|
+
`4.0.0-beta.98`; `unstable/*` can break between betas.
|
|
341
|
+
2. **Don't Effect-ify pure/UI code.** No service or layer for a clipboard write, a string
|
|
342
|
+
truncation, or a popup. §0 is the test: is there a typed-error / cancellation / resource /
|
|
343
|
+
retry concern? If not, leave it.
|
|
344
|
+
3. **Don't guess APIs.** If it's not in this guide or `effect-v4-notes.md` and you haven't
|
|
345
|
+
grepped it in `node_modules/effect/dist/*.d.ts`, don't write it. Watch for hallucinated
|
|
346
|
+
`ServiceMap` (reverted to `Context`), `Effect.fork` (→ `forkChild`), `Effect.either`
|
|
347
|
+
(→ `Effect.result`).
|
|
348
|
+
4. **Don't hand-roll teardown.** Put cleanup in Effect finalizers and let `runtime.dispose()`
|
|
349
|
+
in `session_shutdown` run them.
|
|
350
|
+
5. **Don't over-test.** A `check` that passes plus one focused runtime test (where behavior
|
|
351
|
+
is non-obvious) beats a wall of defensive unit tests.
|
|
352
|
+
6. **Don't run root scripts.** No repo-root `tsc`, `prettier`, or `npm run format`; stay
|
|
353
|
+
inside `extensions/<ext>`.
|
|
354
|
+
</content>
|