tarsk 0.6.87 → 0.6.88
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/dist/bundled-skills/email-me/SKILL.md +15 -0
- package/dist/bundled-skills/email-me/scripts/__tests__/email_me.test.js +64 -0
- package/dist/bundled-skills/email-me/scripts/email_me.js +45 -0
- package/dist/bundled-skills/handoff/SKILL.md +19 -0
- package/dist/bundled-skills/tarsk-agent/SKILL.md +372 -0
- package/dist/bundled-skills/tarsk-ask-user/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-ask-user/scripts/ask_user.js +101 -0
- package/dist/bundled-skills/tarsk-bash/SKILL.md +17 -0
- package/dist/bundled-skills/tarsk-bash/scripts/bash.js +248 -0
- package/dist/bundled-skills/tarsk-browser/SKILL.md +17 -0
- package/dist/bundled-skills/tarsk-browser/scripts/browser.js +252 -0
- package/dist/bundled-skills/tarsk-chat-title/SKILL.md +14 -0
- package/dist/bundled-skills/tarsk-chat-title/scripts/chat_title.js +37 -0
- package/dist/bundled-skills/tarsk-connect-mcp/SKILL.md +23 -0
- package/dist/bundled-skills/tarsk-connect-mcp/scripts/__tests__/connect_mcp.test.js +68 -0
- package/dist/bundled-skills/tarsk-connect-mcp/scripts/connect_mcp.js +119 -0
- package/dist/bundled-skills/tarsk-create-project/SKILL.md +25 -0
- package/dist/bundled-skills/tarsk-create-project/scripts/__tests__/create_project.test.js +94 -0
- package/dist/bundled-skills/tarsk-create-project/scripts/create_project.js +88 -0
- package/dist/bundled-skills/tarsk-edit/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-edit/scripts/edit.js +118 -0
- package/dist/bundled-skills/tarsk-execute-skill-script/SKILL.md +19 -0
- package/dist/bundled-skills/tarsk-execute-skill-script/scripts/execute_skill_script.js +77 -0
- package/dist/bundled-skills/tarsk-fetch/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-fetch/scripts/fetch.js +38 -0
- package/dist/bundled-skills/tarsk-find/SKILL.md +16 -0
- package/dist/bundled-skills/tarsk-find/scripts/find.js +78 -0
- package/dist/bundled-skills/tarsk-find-images/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-find-images/scripts/find_images.js +78 -0
- package/dist/bundled-skills/tarsk-generate-image/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-generate-image/scripts/generate_image.js +55 -0
- package/dist/bundled-skills/tarsk-get-observation/SKILL.md +19 -0
- package/dist/bundled-skills/tarsk-get-observation/scripts/get_observation.js +293 -0
- package/dist/bundled-skills/tarsk-grep/SKILL.md +16 -0
- package/dist/bundled-skills/tarsk-grep/scripts/grep.js +174 -0
- package/dist/bundled-skills/tarsk-history/SKILL.md +15 -0
- package/dist/bundled-skills/tarsk-history/scripts/history.js +68 -0
- package/dist/bundled-skills/tarsk-improve/SKILL.md +232 -0
- package/dist/bundled-skills/tarsk-improve/references/signals.md +16 -0
- package/dist/bundled-skills/tarsk-improve/scripts/durable-runs.ts +635 -0
- package/dist/bundled-skills/tarsk-improve/scripts/ensure-exported.ts +238 -0
- package/dist/bundled-skills/tarsk-improve/scripts/export-tool-skills-lib.ts +299 -0
- package/dist/bundled-skills/tarsk-improve/scripts/summarize-session.ts +126 -0
- package/dist/bundled-skills/tarsk-jobs/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-jobs/scripts/job_kill.js +45 -0
- package/dist/bundled-skills/tarsk-jobs/scripts/job_list.js +64 -0
- package/dist/bundled-skills/tarsk-jobs/scripts/job_output.js +66 -0
- package/dist/bundled-skills/tarsk-notes/SKILL.md +17 -0
- package/dist/bundled-skills/tarsk-notes/scripts/notes.js +86 -0
- package/dist/bundled-skills/tarsk-projects/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-projects/scripts/projects.js +54 -0
- package/dist/bundled-skills/tarsk-prompt-project/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-prompt-project/scripts/prompt_project.js +58 -0
- package/dist/bundled-skills/tarsk-propose-branch/SKILL.md +16 -0
- package/dist/bundled-skills/tarsk-propose-branch/scripts/propose_branch.js +45 -0
- package/dist/bundled-skills/tarsk-read/SKILL.md +17 -0
- package/dist/bundled-skills/tarsk-read/scripts/read.js +331 -0
- package/dist/bundled-skills/tarsk-read-skill/SKILL.md +16 -0
- package/dist/bundled-skills/tarsk-read-skill/scripts/read_skill.js +37 -0
- package/dist/bundled-skills/tarsk-read-skill-reference/SKILL.md +19 -0
- package/dist/bundled-skills/tarsk-read-skill-reference/scripts/read_skill_reference.js +60 -0
- package/dist/bundled-skills/tarsk-run-js/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-run-js/scripts/run_js.js +192 -0
- package/dist/bundled-skills/tarsk-tasks/SKILL.md +18 -0
- package/dist/bundled-skills/tarsk-tasks/scripts/tasks.js +96 -0
- package/dist/bundled-skills/tarsk-todo/SKILL.md +16 -0
- package/dist/bundled-skills/tarsk-todo/scripts/todo.js +165 -0
- package/dist/bundled-skills/tarsk-web-search/SKILL.md +15 -0
- package/dist/bundled-skills/tarsk-web-search/scripts/web_search.js +120 -0
- package/dist/bundled-skills/tarsk-write/SKILL.md +16 -0
- package/dist/bundled-skills/tarsk-write/scripts/write.js +57 -0
- package/dist/index.js +215804 -210026
- package/dist/node_modules/@libsql/darwin-arm64/README.md +3 -0
- package/dist/node_modules/@libsql/{darwin-x64 → darwin-arm64}/index.node +0 -0
- package/dist/node_modules/@libsql/{darwin-x64 → darwin-arm64}/package.json +6 -6
- package/dist/public/assets/account-view-DkuCOxkE.js +1 -0
- package/dist/public/assets/{alert-dialog-DVaEQlVa.js → alert-dialog-BcZULJsX.js} +1 -1
- package/dist/public/assets/api-B_GSyYGh.js +1 -0
- package/dist/public/assets/api-C4ukGdyH.js +2 -0
- package/dist/public/assets/{async-error-boundary-DH6Sqgmt.js → async-error-boundary-FT8_xvjy.js} +1 -1
- package/dist/public/assets/browser-tab-DCjHytQ8.js +12 -0
- package/dist/public/assets/button-DDaJhJP1.js +1 -0
- package/dist/public/assets/{card-BkOGFps5.js → card-DAc45J1v.js} +1 -1
- package/dist/public/assets/chat-dock-context-a2bV9cnz.js +1 -0
- package/dist/public/assets/chat-handlers-context-2xSKzkKa.js +9 -0
- package/dist/public/assets/commit-dialog-C1oUFznJ.js +1 -0
- package/dist/public/assets/{commit-error-dialog-D3S6kRVr.js → commit-error-dialog--NTHg7Aw.js} +1 -1
- package/dist/public/assets/{commit-method-fields-BEKfSRyW.js → commit-method-fields-Xt3vbwUg.js} +1 -1
- package/dist/public/assets/{conversation-history-view-CVMD8hUU.js → conversation-history-view-CdfE7JTD.js} +1 -1
- package/dist/public/assets/{create-project-dialog-nquqlloK.js → create-project-dialog-BdR6iQE9.js} +2 -2
- package/dist/public/assets/{create-project-workspace-C4tXAUWJ.js → create-project-workspace-DSTTGom_.js} +2 -2
- package/dist/public/assets/create-repo-dialog-gw-8Rpdm.js +1 -0
- package/dist/public/assets/{delete-confirm-dialog-SpYpU1AX.js → delete-confirm-dialog-D1N86piR.js} +1 -1
- package/dist/public/assets/dialog-D_12AsZd.js +1 -0
- package/dist/public/assets/diff-view-B6JJNyn1.js +4 -0
- package/dist/public/assets/{dist-NcyjV9Gu.js → dist-2xH_pFmV.js} +1 -1
- package/dist/public/assets/{dist-BTu7PDzc.js → dist-AbkJBHH5.js} +1 -1
- package/dist/public/assets/{dist-lFBinzor.js → dist-B-h6Wj39.js} +1 -1
- package/dist/public/assets/dist-CgbWuuq4.js +1 -0
- package/dist/public/assets/{dist-f54JuzFV.js → dist-DOz2WXwX.js} +1 -1
- package/dist/public/assets/{dist-CqrmQxmV.js → dist-DfnQ9YJh.js} +1 -1
- package/dist/public/assets/{dist-BOfRC57H.js → dist-JGbQ_EJY.js} +1 -1
- package/dist/public/assets/{dist-ButPmyjr.js → dist-pCVg1Jdl.js} +1 -1
- package/dist/public/assets/dist-v_MvKS2-.js +2 -0
- package/dist/public/assets/{es2015-CE7VcoOH.js → es2015-eNVkKfFF.js} +1 -1
- package/dist/public/assets/{explorer-file-drop-CEbBlDEp.js → explorer-file-drop-CzyAqZgf.js} +1 -1
- package/dist/public/assets/{explorer-monaco-editor-Bgo9Y1cP.js → explorer-monaco-editor-ChJZBFy5.js} +1 -1
- package/dist/public/assets/explorer-tab-view-CiUPh4uK.js +2 -0
- package/dist/public/assets/explorer-tree-BA12VLz_.js +1 -0
- package/dist/public/assets/{explorer-view-BuTa_0Uq.js → explorer-view-Daxl93oM.js} +3 -3
- package/dist/public/assets/git-history-dialog-Dqj1p35g.js +1 -0
- package/dist/public/assets/index-CoY8DilQ.js +97 -0
- package/dist/public/assets/index-D14wLW4o.css +1 -0
- package/dist/public/assets/{label-C31qF5zZ.js → label-BCs5CZEs.js} +1 -1
- package/dist/public/assets/markdown-renderer-D2VcKU4g.js +10 -0
- package/dist/public/assets/{mcp-manager-C3K_62H2.js → mcp-manager-D1HmLT3t.js} +1 -1
- package/dist/public/assets/{minus-l6BdrAEk.js → minus-CgQcbBQT.js} +1 -1
- package/dist/public/assets/{model-list-controls-DwW8S18v.js → model-list-controls-rXmaDp2r.js} +1 -1
- package/dist/public/assets/onboarding-dialog-DSqBJyBa.js +1 -0
- package/dist/public/assets/{pill-tabs-CmvvHdKG.js → pill-tabs-DtdTmrg7.js} +1 -1
- package/dist/public/assets/progress-indicator-hJ74ac5W.js +1 -0
- package/dist/public/assets/project-coding-view-DP4qKePE.js +1 -0
- package/dist/public/assets/{project-danger-zone-view-D18k4pUF.js → project-danger-zone-view-CGxIenpr.js} +1 -1
- package/dist/public/assets/{project-env-vars-view-BWFqoaFD.js → project-env-vars-view-DKyQkh7h.js} +1 -1
- package/dist/public/assets/project-model-aliases-view-BewwJZAx.js +1 -0
- package/dist/public/assets/project-settings-view-CE4nAz5B.js +1 -0
- package/dist/public/assets/{project-tools-view-DT87KPjE.js → project-tools-view-CbDfst02.js} +1 -1
- package/dist/public/assets/providers-list-view-BtwccvX2.js +1 -0
- package/dist/public/assets/pull-request-dialog-nKYATjbm.js +1 -0
- package/dist/public/assets/pull-with-changes-dialog-zzoFzCv4.js +1 -0
- package/dist/public/assets/push-before-pr-dialog-DH91JHEC.js +1 -0
- package/dist/public/assets/remote-media-url-CyuN31H_.js +1 -0
- package/dist/public/assets/{scroll-area-BWc4OPsj.js → scroll-area-CGEZ1gAL.js} +1 -1
- package/dist/public/assets/{select-B6RizwDW.js → select-BR2pG61R.js} +1 -1
- package/dist/public/assets/settings-general-tabs-view-BWR0UX2P.js +2 -0
- package/dist/public/assets/settings-general-view-BhtrDmJH.js +1 -0
- package/dist/public/assets/{settings-list-D35rpAof.js → settings-list-Dgip9HpD.js} +1 -1
- package/dist/public/assets/settings-logs-view-CS29x4VT.js +5 -0
- package/dist/public/assets/settings-mcp-servers-view-B5ithpfh.js +5 -0
- package/dist/public/assets/settings-models-view-DS7nm54P.js +1 -0
- package/dist/public/assets/settings-plugins-view-avaUE36r.js +2 -0
- package/dist/public/assets/settings-providers-view-B39k1iRQ.js +2 -0
- package/dist/public/assets/settings-remote-machines-view-BXondQG_.js +1 -0
- package/dist/public/assets/settings-setup-view-I5MGUi_D.js +2 -0
- package/dist/public/assets/settings-skills-view-BKrUABbi.js +2 -0
- package/dist/public/assets/{settings-slack-view-DkclyaBc.js → settings-slack-view-B0p-96GC.js} +1 -1
- package/dist/public/assets/settings-slash-commands-view-DA1scWv1.js +1 -0
- package/dist/public/assets/{settings-statistics-view-B03ZZjEy.js → settings-statistics-view-B3g6BD7p.js} +1 -1
- package/dist/public/assets/settings-storage-view-BJvjhI4f.js +1 -0
- package/dist/public/assets/settings-subagents-view-BziLwvNq.js +2 -0
- package/dist/public/assets/settings-system-prompt-view-BqAk56cD.js +1 -0
- package/dist/public/assets/{settings-tab-bar-ajzyt79U.js → settings-tab-bar-DYzU_lmi.js} +1 -1
- package/dist/public/assets/settings-view-zjMs7jNe.js +2 -0
- package/dist/public/assets/{slug-utils-D2jhPz-o.js → slug-utils-CO6nui1C.js} +1 -1
- package/dist/public/assets/square-CtxvwmM2.js +1 -0
- package/dist/public/assets/store-W78TGOIO.js +8 -0
- package/dist/public/assets/{table-C3Hc0Gwy.js → table-CQMqIW_-.js} +1 -1
- package/dist/public/assets/task-utils-BZPVmvY4.js +1 -0
- package/dist/public/assets/tasks-view-wFf77AQX.js +1 -0
- package/dist/public/assets/{terminal-panel-DCKqScJu.js → terminal-panel-Bm_ZelN-.js} +2 -2
- package/dist/public/assets/{toggle-group-DqSxGqvP.js → toggle-group-CPmseZfb.js} +1 -1
- package/dist/public/assets/{tooltip-CJKJfu0l.js → tooltip-CqwCZ7wt.js} +1 -1
- package/dist/public/assets/{use-account-settings-query-AUeOqKvo.js → use-account-settings-query-C-zOdREq.js} +1 -1
- package/dist/public/assets/{use-active-dock-panel-instance-BvAhUd_V.js → use-active-dock-panel-instance-4Ss8lB9K.js} +1 -1
- package/dist/public/assets/use-browser-overlay-block-CO1pUEAZ.js +1 -0
- package/dist/public/assets/use-git-check-CumqGAvN.js +1 -0
- package/dist/public/assets/{use-installed-ai-files-iy_AB0dN.js → use-installed-ai-files-DQey9Zm3.js} +1 -1
- package/dist/public/assets/use-open-chat-dock-panel-DqfWJ8e8.js +1 -0
- package/dist/public/assets/use-projects-CizIH2Fa.js +2 -0
- package/dist/public/assets/utils-CqsIXqSC.js +1 -0
- package/dist/public/assets/web-BNWoiS4w.js +1 -0
- package/dist/public/assets/web-CGP-jEpi.js +1 -0
- package/dist/public/assets/web-CKC9gpFi.js +1 -0
- package/dist/public/assets/web-Dlo3GwCf.js +1 -0
- package/dist/public/fonts/schibsted-grotesk-latin-ext-wght-normal.woff2 +0 -0
- package/dist/public/fonts/schibsted-grotesk-latin-wght-normal.woff2 +0 -0
- package/dist/public/index.html +45 -45
- package/package.json +6 -6
- package/dist/node_modules/@libsql/darwin-x64/README.md +0 -3
- package/dist/public/assets/account-view-5q3pHEHY.js +0 -1
- package/dist/public/assets/ai-spinner-DHwhlk4j.js +0 -1
- package/dist/public/assets/api-BdebJfuN.js +0 -1
- package/dist/public/assets/api-COO2LfdU.js +0 -2
- package/dist/public/assets/browser-overlay-block-CiDtkfup.js +0 -1
- package/dist/public/assets/browser-tab-CVdYLmW5.js +0 -12
- package/dist/public/assets/button-Dp5XDZNR.js +0 -1
- package/dist/public/assets/chat-dock-context-ymLoO90X.js +0 -1
- package/dist/public/assets/checkbox-D-BV8-Z_.js +0 -1
- package/dist/public/assets/commit-dialog-CEbCFh1x.js +0 -1
- package/dist/public/assets/create-repo-dialog-B5IE3pUJ.js +0 -1
- package/dist/public/assets/dialog-pHPeIGaB.js +0 -1
- package/dist/public/assets/diff-view-Cy6nPdX-.js +0 -4
- package/dist/public/assets/dist-D5vgS4RP.js +0 -2
- package/dist/public/assets/explorer-tab-view-C-8QZO9S.js +0 -2
- package/dist/public/assets/explorer-tree-HrLSFgcI.js +0 -1
- package/dist/public/assets/git-history-dialog-ClfF5IOn.js +0 -1
- package/dist/public/assets/index-BBLA5zVt.css +0 -1
- package/dist/public/assets/index-CalVAwXj.js +0 -104
- package/dist/public/assets/markdown-renderer-DXRBG7uP.js +0 -10
- package/dist/public/assets/onboarding-dialog-BtLy0wjC.js +0 -1
- package/dist/public/assets/progress-indicator-4zQXqOqP.js +0 -1
- package/dist/public/assets/project-coding-view-CyJwnJes.js +0 -1
- package/dist/public/assets/project-model-aliases-view-D3tYNkkM.js +0 -1
- package/dist/public/assets/project-settings-view-0oN9vFvD.js +0 -1
- package/dist/public/assets/providers-list-view-DCnh0W-5.js +0 -1
- package/dist/public/assets/pull-request-dialog-BdJxYQwu.js +0 -1
- package/dist/public/assets/pull-with-changes-dialog-Do9x9neW.js +0 -1
- package/dist/public/assets/push-before-pr-dialog-C-9z2O0-.js +0 -1
- package/dist/public/assets/remote-media-url-B8OFqxOM.js +0 -1
- package/dist/public/assets/settings-general-tabs-view-Dcek-ysB.js +0 -2
- package/dist/public/assets/settings-general-view-DhA2N6G5.js +0 -1
- package/dist/public/assets/settings-logs-view-eEUTIMeb.js +0 -5
- package/dist/public/assets/settings-mcp-servers-view-_oeuVkUe.js +0 -5
- package/dist/public/assets/settings-models-view-DW-ZmVup.js +0 -1
- package/dist/public/assets/settings-plugins-view-DTooco_c.js +0 -2
- package/dist/public/assets/settings-providers-view-CEeJkhg9.js +0 -2
- package/dist/public/assets/settings-remote-machines-view--UB8GlCK.js +0 -1
- package/dist/public/assets/settings-setup-view-DFL6DlYS.js +0 -2
- package/dist/public/assets/settings-skills-view-xS569-Kb.js +0 -2
- package/dist/public/assets/settings-slash-commands-view-DrCiayfq.js +0 -1
- package/dist/public/assets/settings-storage-view-CQnaVOt_.js +0 -1
- package/dist/public/assets/settings-subagents-view-DIctUJcE.js +0 -2
- package/dist/public/assets/settings-system-prompt-view-BMDbrFRR.js +0 -1
- package/dist/public/assets/settings-view-8M6sbGiX.js +0 -2
- package/dist/public/assets/store-CxUwqrZ5.js +0 -8
- package/dist/public/assets/task-utils-WAei2PDi.js +0 -1
- package/dist/public/assets/tasks-view-DKyqgGdE.js +0 -1
- package/dist/public/assets/use-browser-overlay-block-z9imTmiZ.js +0 -1
- package/dist/public/assets/use-git-check-B_5Jak2s.js +0 -1
- package/dist/public/assets/use-open-chat-dock-panel-w3hc5Vxn.js +0 -1
- package/dist/public/assets/use-projects-BmhAMgxB.js +0 -2
- package/dist/public/assets/utils-mYB1USG6.js +0 -1
- package/dist/public/assets/web-C6Gm4nQ0.js +0 -1
- package/dist/public/assets/web-DFlyNg8o.js +0 -1
- package/dist/public/assets/web-DlEPs8Xe.js +0 -1
- package/dist/public/assets/web-Gx3xReQH.js +0 -1
- package/dist/public/backgrounds/arctic-tundra.avif +0 -0
- package/dist/public/backgrounds/autumn-leaves.avif +0 -0
- package/dist/public/backgrounds/coastal-cliff.avif +0 -0
- package/dist/public/backgrounds/floating-waterfall.avif +0 -0
- package/dist/public/backgrounds/forest-path.avif +0 -0
- package/dist/public/backgrounds/garden-path.avif +0 -0
- package/dist/public/backgrounds/glow-marsh.avif +0 -0
- package/dist/public/backgrounds/golden-wheat.avif +0 -0
- package/dist/public/backgrounds/moon-desert.avif +0 -0
- package/dist/public/backgrounds/night-pond.avif +0 -0
- package/dist/public/backgrounds/prairie-grassland.avif +0 -0
- package/dist/public/backgrounds/river-winding.avif +0 -0
- package/dist/public/backgrounds/salt-flat.avif +0 -0
- package/dist/public/backgrounds/salt-marsh.avif +0 -0
- package/dist/public/backgrounds/sandy-beach.avif +0 -0
- package/dist/public/backgrounds/snow-river.avif +0 -0
- package/dist/public/backgrounds/sunset-pond.avif +0 -0
- package/dist/public/fonts/plus-jakarta-sans-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/public/fonts/plus-jakarta-sans-latin-ext-wght-normal.woff2 +0 -0
- package/dist/public/fonts/plus-jakarta-sans-latin-wght-normal.woff2 +0 -0
- package/dist/public/fonts/plus-jakarta-sans-vietnamese-wght-normal.woff2 +0 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @ts-nocheck — bun script outside cli/tsconfig (no Node/Bun types in staged vp check)
|
|
3
|
+
/**
|
|
4
|
+
* Ensure every bundled `tarsk-*` Skill exists under the project's
|
|
5
|
+
* `.agents/skills` so Tool skill edits hit the project copy, not the
|
|
6
|
+
* read-only bundled original.
|
|
7
|
+
*
|
|
8
|
+
* `--prune` is the cleanup pass: it deletes project copies that still match
|
|
9
|
+
* bundled and creates nothing, so only `tarsk-*` Skills that actually differ
|
|
10
|
+
* stay in the repo. The host also prunes on chat load.
|
|
11
|
+
*
|
|
12
|
+
* In the Tarsk checkout the built-ins are the repo's own files, so this script
|
|
13
|
+
* copies nothing (`skipped: tarsk-checkout`) and you edit
|
|
14
|
+
* `cli/bundled-skills/tarsk-*` directly. User repos still get project copies.
|
|
15
|
+
*
|
|
16
|
+
* Usage (from the project / thread checkout root):
|
|
17
|
+
* bun .agents/skills/tarsk-improve/scripts/ensure-exported.ts
|
|
18
|
+
* bun <bundled>/tarsk-improve/scripts/ensure-exported.ts --project-skills .agents/skills
|
|
19
|
+
* bun .agents/skills/tarsk-improve/scripts/ensure-exported.ts --prune
|
|
20
|
+
*
|
|
21
|
+
* Options:
|
|
22
|
+
* --project-skills <dir> Target .agents/skills (default: <cwd>/.agents/skills)
|
|
23
|
+
* --bundled <dir> Bundled-skills root (default: auto-detect)
|
|
24
|
+
* --prune Delete project copies that match bundled; create nothing
|
|
25
|
+
* --json Print machine-readable JSON
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { existsSync } from "node:fs";
|
|
29
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
30
|
+
import { fileURLToPath } from "node:url";
|
|
31
|
+
import {
|
|
32
|
+
exportToolSkillsFrom,
|
|
33
|
+
isTarskCheckout,
|
|
34
|
+
listEditableToolSkills,
|
|
35
|
+
pruneUnchangedToolSkills,
|
|
36
|
+
type ExportToolSkillsResult,
|
|
37
|
+
type ToolSkillPruneResult,
|
|
38
|
+
} from "./export-tool-skills-lib.js";
|
|
39
|
+
|
|
40
|
+
function readFlagValue(args: string[], flag: string): string | undefined {
|
|
41
|
+
const index = args.indexOf(flag);
|
|
42
|
+
if (index === -1) return undefined;
|
|
43
|
+
const value = args[index + 1];
|
|
44
|
+
if (!value || value.startsWith("--")) return undefined;
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function scriptDir(): string {
|
|
49
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** `…/tarsk-improve/scripts` → skill root → parent (bundled-skills or .agents/skills). */
|
|
53
|
+
function skillPackageParent(): string {
|
|
54
|
+
return resolve(scriptDir(), "../..");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function looksLikeBundledRoot(dir: string): boolean {
|
|
58
|
+
return (
|
|
59
|
+
existsSync(join(dir, "tarsk-read", "SKILL.md")) ||
|
|
60
|
+
existsSync(join(dir, "tarsk-agent", "SKILL.md"))
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function resolveBundledRoot(flag?: string): string | null {
|
|
65
|
+
if (flag) {
|
|
66
|
+
const resolved = resolve(flag);
|
|
67
|
+
return existsSync(resolved) ? resolved : null;
|
|
68
|
+
}
|
|
69
|
+
if (process.env.TARSK_BUNDLED_SKILLS) {
|
|
70
|
+
const fromEnv = resolve(process.env.TARSK_BUNDLED_SKILLS);
|
|
71
|
+
if (existsSync(fromEnv)) return fromEnv;
|
|
72
|
+
}
|
|
73
|
+
const parent = skillPackageParent();
|
|
74
|
+
// Prefer the checkout's built-in tree. The script's own package parent is last:
|
|
75
|
+
// in a project copy that parent *is* `.agents/skills`, the export target.
|
|
76
|
+
const candidates = [
|
|
77
|
+
join(process.cwd(), "cli", "bundled-skills"),
|
|
78
|
+
join(process.cwd(), "bundled-skills"),
|
|
79
|
+
join(process.cwd(), "dist", "bundled-skills"),
|
|
80
|
+
parent,
|
|
81
|
+
];
|
|
82
|
+
for (const candidate of candidates) {
|
|
83
|
+
if (candidate === resolveProjectSkillsDir()) continue;
|
|
84
|
+
if (looksLikeBundledRoot(candidate)) return candidate;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function resolveProjectSkillsDir(flag?: string): string {
|
|
90
|
+
if (flag) return resolve(flag);
|
|
91
|
+
const parent = skillPackageParent();
|
|
92
|
+
// Already living under the project's .agents/skills/tarsk-improve
|
|
93
|
+
if (basename(parent) === "skills" && basename(dirname(parent)) === ".agents") {
|
|
94
|
+
return parent;
|
|
95
|
+
}
|
|
96
|
+
return join(process.cwd(), ".agents", "skills");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function printHuman(result: ExportToolSkillsResult): void {
|
|
100
|
+
console.log("# Tool skill export");
|
|
101
|
+
console.log(`bundled: ${result.bundledRoot ?? "(missing)"}`);
|
|
102
|
+
console.log(`project: ${result.projectSkillsDir}`);
|
|
103
|
+
if (result.skipped === "tarsk-checkout") {
|
|
104
|
+
console.log("");
|
|
105
|
+
console.log("Tarsk checkout: the built-ins are this repo's own files, so nothing was copied.");
|
|
106
|
+
console.log(`Edit cli/bundled-skills/tarsk-* directly (${result.bundledRoot}).`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
console.log(`copied: ${result.copied.length ? result.copied.join(", ") : "(none)"}`);
|
|
110
|
+
console.log(
|
|
111
|
+
`overwritten: ${result.overwritten.length ? result.overwritten.join(", ") : "(none)"}`,
|
|
112
|
+
);
|
|
113
|
+
console.log(`left (already present): ${result.left.length}`);
|
|
114
|
+
console.log("");
|
|
115
|
+
console.log("## Editable Tool skills (project copies)");
|
|
116
|
+
if (result.editableToolSkills.length === 0) {
|
|
117
|
+
console.log("(none — export may have failed; re-run the export command above)");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
for (const name of result.editableToolSkills) {
|
|
121
|
+
console.log(`- ${join(result.projectSkillsDir, name)}`);
|
|
122
|
+
}
|
|
123
|
+
console.log("");
|
|
124
|
+
console.log(
|
|
125
|
+
"Edit only these project paths. Do not edit cli/bundled-skills or other built-in roots.",
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function printPruneHuman(result: ToolSkillPruneResult): void {
|
|
130
|
+
console.log("# Tool skill prune");
|
|
131
|
+
console.log(`bundled: ${result.bundledRoot ?? "(missing)"}`);
|
|
132
|
+
console.log(`project: ${result.projectSkillsDir}`);
|
|
133
|
+
console.log(
|
|
134
|
+
`removed (matched bundled): ${result.removed.length ? result.removed.join(", ") : "(none)"}`,
|
|
135
|
+
);
|
|
136
|
+
console.log(`kept (differs): ${result.kept.length ? result.kept.join(", ") : "(none)"}`);
|
|
137
|
+
console.log("");
|
|
138
|
+
console.log("## Editable Tool skills (project copies that differ)");
|
|
139
|
+
if (result.editableToolSkills.length === 0) {
|
|
140
|
+
console.log("(none — no project Tool skill differs from bundled yet)");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
for (const name of result.editableToolSkills) {
|
|
144
|
+
console.log(`- ${join(result.projectSkillsDir, name)}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function printExportResult(result: ExportToolSkillsResult, asJson: boolean): void {
|
|
149
|
+
if (asJson) console.log(JSON.stringify(result, null, 2));
|
|
150
|
+
else printHuman(result);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function printPruneResult(result: ToolSkillPruneResult, asJson: boolean): void {
|
|
154
|
+
if (asJson) console.log(JSON.stringify(result, null, 2));
|
|
155
|
+
else printPruneHuman(result);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Fallback when no bundled-skills root can be found: report the project copies
|
|
160
|
+
* already on disk without comparing. Returns the process exit code (0 when at
|
|
161
|
+
* least one editable Tool skill exists).
|
|
162
|
+
*/
|
|
163
|
+
async function reportMissingBundledRoot(
|
|
164
|
+
projectSkillsDir: string,
|
|
165
|
+
options: { prune: boolean; asJson: boolean },
|
|
166
|
+
): Promise<number> {
|
|
167
|
+
console.error(
|
|
168
|
+
"Could not find bundled-skills. Pass --bundled <dir> or set TARSK_BUNDLED_SKILLS. " +
|
|
169
|
+
"If Tool skills are already under .agents/skills, list them and continue editing those copies.",
|
|
170
|
+
);
|
|
171
|
+
const existing = await listEditableToolSkills(projectSkillsDir);
|
|
172
|
+
if (options.prune) {
|
|
173
|
+
printPruneResult(
|
|
174
|
+
{
|
|
175
|
+
removed: [],
|
|
176
|
+
kept: existing,
|
|
177
|
+
editableToolSkills: existing,
|
|
178
|
+
projectSkillsDir,
|
|
179
|
+
bundledRoot: null,
|
|
180
|
+
},
|
|
181
|
+
options.asJson,
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
printExportResult(
|
|
185
|
+
{
|
|
186
|
+
copied: [],
|
|
187
|
+
overwritten: [],
|
|
188
|
+
left: existing,
|
|
189
|
+
editableToolSkills: existing,
|
|
190
|
+
projectSkillsDir,
|
|
191
|
+
bundledRoot: null,
|
|
192
|
+
},
|
|
193
|
+
options.asJson,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
return existing.length > 0 ? 0 : 1;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function main(): Promise<void> {
|
|
200
|
+
const argv = process.argv.slice(2);
|
|
201
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
202
|
+
console.error(`Usage:
|
|
203
|
+
bun …/tarsk-improve/scripts/ensure-exported.ts [--project-skills <dir>] [--bundled <dir>] [--prune] [--json]
|
|
204
|
+
`);
|
|
205
|
+
process.exit(0);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const asJson = argv.includes("--json");
|
|
209
|
+
const prune = argv.includes("--prune");
|
|
210
|
+
const projectSkillsDir = resolveProjectSkillsDir(readFlagValue(argv, "--project-skills"));
|
|
211
|
+
const bundledRoot = resolveBundledRoot(readFlagValue(argv, "--bundled"));
|
|
212
|
+
if (!bundledRoot) {
|
|
213
|
+
process.exit(await reportMissingBundledRoot(projectSkillsDir, { prune, asJson }));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (prune) {
|
|
217
|
+
const result = await pruneUnchangedToolSkills(bundledRoot, projectSkillsDir);
|
|
218
|
+
printPruneResult(result, asJson);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (isTarskCheckout(bundledRoot) && !asJson) {
|
|
223
|
+
console.log("# Tool skill export");
|
|
224
|
+
console.log(`bundled: ${bundledRoot}`);
|
|
225
|
+
console.log(`project: ${projectSkillsDir}`);
|
|
226
|
+
console.log("");
|
|
227
|
+
console.log("Tarsk checkout: the built-ins are this repo's own files, so nothing was copied.");
|
|
228
|
+
console.log(`Edit cli/bundled-skills/tarsk-* directly (${bundledRoot}).`);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const result = await exportToolSkillsFrom(bundledRoot, projectSkillsDir);
|
|
233
|
+
printExportResult(result, asJson);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (import.meta.main) {
|
|
237
|
+
await main();
|
|
238
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
// @ts-nocheck — bun script outside cli/tsconfig (no Node/Bun types in staged vp check)
|
|
2
|
+
/**
|
|
3
|
+
* Shared Tool skill export rules used by both the host (`export-tool-skills.ts`)
|
|
4
|
+
* and this skill's `ensure-exported.ts`.
|
|
5
|
+
*
|
|
6
|
+
* - `exportToolSkillsFrom` copies `tarsk-*` copies for editing (deliberate).
|
|
7
|
+
* - `pruneUnchangedToolSkills` deletes copies that match bundled, so the repo
|
|
8
|
+
* only ever keeps `tarsk-*` skills that actually differ from the built-in.
|
|
9
|
+
*
|
|
10
|
+
* In the Tarsk checkout the built-ins *are* the repo's own files, so
|
|
11
|
+
* `exportToolSkillsFrom` copies nothing (`skipped: "tarsk-checkout"`);
|
|
12
|
+
* `isTarskCheckout` is how every caller tells the two repos apart.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { cp, mkdir, readFile, readdir, rm } from "node:fs/promises";
|
|
16
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
17
|
+
import { join, resolve } from "node:path";
|
|
18
|
+
|
|
19
|
+
export type ExportAction = "copy" | "overwrite" | "leave";
|
|
20
|
+
|
|
21
|
+
export interface ExportToolSkillsResult {
|
|
22
|
+
copied: string[];
|
|
23
|
+
overwritten: string[];
|
|
24
|
+
left: string[];
|
|
25
|
+
/** Project dirs for Skills that publish Tools (have front matter `tools:`). */
|
|
26
|
+
editableToolSkills: string[];
|
|
27
|
+
projectSkillsDir: string;
|
|
28
|
+
bundledRoot: string | null;
|
|
29
|
+
/** Set when nothing was copied because the built-ins live in this repo. */
|
|
30
|
+
skipped?: "tarsk-checkout";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function readPackageName(manifestPath: string): string | null {
|
|
34
|
+
if (!existsSync(manifestPath)) return null;
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
37
|
+
return typeof parsed.name === "string" ? parsed.name : null;
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* True only in the Tarsk checkout itself: `<bundledRoot>/..` is the `tarsk` CLI
|
|
45
|
+
* package, or its parent is the `tarsk-monorepo` root. Every user project fails
|
|
46
|
+
* this, so a user's repo still gets real project copies to edit.
|
|
47
|
+
*/
|
|
48
|
+
export function isTarskCheckout(bundledRoot: string): boolean {
|
|
49
|
+
const cliDir = resolve(bundledRoot, "..");
|
|
50
|
+
if (readPackageName(join(cliDir, "package.json")) === "tarsk") return true;
|
|
51
|
+
return readPackageName(join(cliDir, "..", "package.json")) === "tarsk-monorepo";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function parseSemver(
|
|
55
|
+
version: string | undefined,
|
|
56
|
+
): { major: number; minor: number; patch: number } | null {
|
|
57
|
+
if (!version) return null;
|
|
58
|
+
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version.trim());
|
|
59
|
+
if (!match) return null;
|
|
60
|
+
return {
|
|
61
|
+
major: Number(match[1]),
|
|
62
|
+
minor: Number(match[2]),
|
|
63
|
+
patch: Number(match[3]),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Decide whether to copy, overwrite, or leave a project Skill alone.
|
|
69
|
+
* Missing project → copy. Equal version → leave. Bundled major higher → overwrite. Else leave.
|
|
70
|
+
*/
|
|
71
|
+
export function decideExportAction(args: {
|
|
72
|
+
projectExists: boolean;
|
|
73
|
+
bundledVersion: string | undefined;
|
|
74
|
+
projectVersion: string | undefined;
|
|
75
|
+
}): ExportAction {
|
|
76
|
+
if (!args.projectExists) return "copy";
|
|
77
|
+
if (args.bundledVersion === args.projectVersion) return "leave";
|
|
78
|
+
const bundled = parseSemver(args.bundledVersion);
|
|
79
|
+
const project = parseSemver(args.projectVersion);
|
|
80
|
+
if (bundled && project && bundled.major > project.major) return "overwrite";
|
|
81
|
+
return "leave";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function parseFrontmatter(content: string): Record<string, unknown> {
|
|
85
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
86
|
+
if (!match) return {};
|
|
87
|
+
const metadata: Record<string, unknown> = {};
|
|
88
|
+
let currentList: string[] | null = null;
|
|
89
|
+
let currentKey: string | null = null;
|
|
90
|
+
for (const rawLine of match[1].split("\n")) {
|
|
91
|
+
const line = rawLine.trimEnd();
|
|
92
|
+
const listItem = line.match(/^\s*-\s+(.+)$/);
|
|
93
|
+
if (listItem && currentKey) {
|
|
94
|
+
if (!currentList) {
|
|
95
|
+
currentList = [];
|
|
96
|
+
metadata[currentKey] = currentList;
|
|
97
|
+
}
|
|
98
|
+
currentList.push(listItem[1].replace(/^["']|["']$/g, ""));
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
102
|
+
if (!kv) continue;
|
|
103
|
+
currentKey = kv[1];
|
|
104
|
+
currentList = null;
|
|
105
|
+
const value = kv[2].trim();
|
|
106
|
+
if (value === "" || value === "|" || value === ">") {
|
|
107
|
+
currentList = [];
|
|
108
|
+
metadata[currentKey] = currentList;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
metadata[currentKey] = value.replace(/^["']|["']$/g, "");
|
|
112
|
+
}
|
|
113
|
+
return metadata;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function readSkillMeta(skillDir: string): Promise<{ version?: string; tools: string[] }> {
|
|
117
|
+
const skillFile = join(skillDir, "SKILL.md");
|
|
118
|
+
if (!existsSync(skillFile)) return { tools: [] };
|
|
119
|
+
const content = await readFile(skillFile, "utf-8");
|
|
120
|
+
const meta = parseFrontmatter(content);
|
|
121
|
+
const tools = Array.isArray(meta.tools)
|
|
122
|
+
? meta.tools.filter((item): item is string => typeof item === "string")
|
|
123
|
+
: [];
|
|
124
|
+
const version = typeof meta.version === "string" ? meta.version : undefined;
|
|
125
|
+
return { version, tools };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function skillPublishesTools(skillDir: string): Promise<boolean> {
|
|
129
|
+
const meta = await readSkillMeta(skillDir);
|
|
130
|
+
return meta.tools.length > 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Export bundled `tarsk-*` Skills from `bundledRoot` into `projectSkillsDir`.
|
|
135
|
+
*/
|
|
136
|
+
export async function exportToolSkillsFrom(
|
|
137
|
+
bundledRoot: string,
|
|
138
|
+
projectSkillsDir: string,
|
|
139
|
+
): Promise<ExportToolSkillsResult> {
|
|
140
|
+
const result: ExportToolSkillsResult = {
|
|
141
|
+
copied: [],
|
|
142
|
+
overwritten: [],
|
|
143
|
+
left: [],
|
|
144
|
+
editableToolSkills: [],
|
|
145
|
+
projectSkillsDir,
|
|
146
|
+
bundledRoot,
|
|
147
|
+
};
|
|
148
|
+
if (!existsSync(bundledRoot)) {
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
if (isTarskCheckout(bundledRoot)) {
|
|
152
|
+
// The built-ins are the repo's own files here; a project copy would only
|
|
153
|
+
// duplicate them and add noise to `git status`.
|
|
154
|
+
return { ...result, skipped: "tarsk-checkout" };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await mkdir(projectSkillsDir, { recursive: true });
|
|
158
|
+
const entries = await readdir(bundledRoot, { withFileTypes: true });
|
|
159
|
+
|
|
160
|
+
for (const entry of entries) {
|
|
161
|
+
if (!entry.isDirectory() || !entry.name.startsWith("tarsk-")) continue;
|
|
162
|
+
|
|
163
|
+
const bundledDir = join(bundledRoot, entry.name);
|
|
164
|
+
const projectDir = join(projectSkillsDir, entry.name);
|
|
165
|
+
const bundledMeta = await readSkillMeta(bundledDir);
|
|
166
|
+
const projectExists = existsSync(projectDir);
|
|
167
|
+
const projectMeta = projectExists ? await readSkillMeta(projectDir) : { tools: [] };
|
|
168
|
+
const action = decideExportAction({
|
|
169
|
+
projectExists,
|
|
170
|
+
bundledVersion: bundledMeta.version,
|
|
171
|
+
projectVersion: projectMeta.version,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (action === "leave") {
|
|
175
|
+
result.left.push(entry.name);
|
|
176
|
+
} else {
|
|
177
|
+
if (projectExists) {
|
|
178
|
+
await rm(projectDir, { recursive: true, force: true });
|
|
179
|
+
}
|
|
180
|
+
await cp(bundledDir, projectDir, { recursive: true });
|
|
181
|
+
if (action === "copy") {
|
|
182
|
+
result.copied.push(entry.name);
|
|
183
|
+
} else {
|
|
184
|
+
result.overwritten.push(entry.name);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const editableDir = join(projectSkillsDir, entry.name);
|
|
189
|
+
if (existsSync(editableDir) && (await skillPublishesTools(editableDir))) {
|
|
190
|
+
result.editableToolSkills.push(entry.name);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
result.editableToolSkills.sort((a, b) => a.localeCompare(b));
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface ToolSkillPruneResult {
|
|
199
|
+
/** Project copies deleted because they matched the bundled Skill byte-for-byte. */
|
|
200
|
+
removed: string[];
|
|
201
|
+
/** Project copies retained because they differ from the bundled Skill. */
|
|
202
|
+
kept: string[];
|
|
203
|
+
/** Retained project copies that publish Tools (front matter `tools:`). */
|
|
204
|
+
editableToolSkills: string[];
|
|
205
|
+
projectSkillsDir: string;
|
|
206
|
+
bundledRoot: string | null;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Sorted relative file paths of every regular file under `dir` (recursive). */
|
|
210
|
+
async function listRelativeFiles(dir: string, base = ""): Promise<string[]> {
|
|
211
|
+
const out: string[] = [];
|
|
212
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
213
|
+
const rel = base ? `${base}/${entry.name}` : entry.name;
|
|
214
|
+
if (entry.isDirectory()) {
|
|
215
|
+
out.push(...(await listRelativeFiles(join(dir, entry.name), rel)));
|
|
216
|
+
} else if (entry.isFile()) {
|
|
217
|
+
out.push(rel);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return out.sort();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** True when two Skill directories hold the same files with identical bytes. */
|
|
224
|
+
async function dirsEqual(a: string, b: string): Promise<boolean> {
|
|
225
|
+
const aFiles = await listRelativeFiles(a);
|
|
226
|
+
const bFiles = await listRelativeFiles(b);
|
|
227
|
+
if (aFiles.length !== bFiles.length) return false;
|
|
228
|
+
for (let index = 0; index < aFiles.length; index += 1) {
|
|
229
|
+
if (aFiles[index] !== bFiles[index]) return false;
|
|
230
|
+
}
|
|
231
|
+
for (const rel of aFiles) {
|
|
232
|
+
const [contentA, contentB] = await Promise.all([
|
|
233
|
+
readFile(join(a, rel)),
|
|
234
|
+
readFile(join(b, rel)),
|
|
235
|
+
]);
|
|
236
|
+
if (!contentA.equals(contentB)) return false;
|
|
237
|
+
}
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Delete `tarsk-*` project copies that still match the bundled Skill exactly.
|
|
243
|
+
* Never creates a copy: a project Skill exists only because someone edited it.
|
|
244
|
+
* Copies that differ from bundled are kept.
|
|
245
|
+
*/
|
|
246
|
+
export async function pruneUnchangedToolSkills(
|
|
247
|
+
bundledRoot: string,
|
|
248
|
+
projectSkillsDir: string,
|
|
249
|
+
): Promise<ToolSkillPruneResult> {
|
|
250
|
+
const result: ToolSkillPruneResult = {
|
|
251
|
+
removed: [],
|
|
252
|
+
kept: [],
|
|
253
|
+
editableToolSkills: [],
|
|
254
|
+
projectSkillsDir,
|
|
255
|
+
bundledRoot,
|
|
256
|
+
};
|
|
257
|
+
if (!existsSync(projectSkillsDir)) {
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
for (const entry of await readdir(projectSkillsDir, { withFileTypes: true })) {
|
|
262
|
+
if (!entry.isDirectory() || !entry.name.startsWith("tarsk-")) continue;
|
|
263
|
+
|
|
264
|
+
const projectDir = join(projectSkillsDir, entry.name);
|
|
265
|
+
const bundledDir = join(bundledRoot, entry.name);
|
|
266
|
+
if (existsSync(bundledDir) && (await dirsEqual(projectDir, bundledDir))) {
|
|
267
|
+
await rm(projectDir, { recursive: true, force: true });
|
|
268
|
+
result.removed.push(entry.name);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
result.kept.push(entry.name);
|
|
273
|
+
if (await skillPublishesTools(projectDir)) {
|
|
274
|
+
result.editableToolSkills.push(entry.name);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const byName = (a: string, b: string): number => a.localeCompare(b);
|
|
279
|
+
result.removed.sort(byName);
|
|
280
|
+
result.kept.sort(byName);
|
|
281
|
+
result.editableToolSkills.sort(byName);
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* List `tarsk-*` project Skills that publish Tools (have front matter `tools:`).
|
|
287
|
+
*/
|
|
288
|
+
export async function listEditableToolSkills(projectSkillsDir: string): Promise<string[]> {
|
|
289
|
+
if (!existsSync(projectSkillsDir)) return [];
|
|
290
|
+
const names: string[] = [];
|
|
291
|
+
for (const entry of await readdir(projectSkillsDir, { withFileTypes: true })) {
|
|
292
|
+
if (!entry.isDirectory() || !entry.name.startsWith("tarsk-")) continue;
|
|
293
|
+
if (await skillPublishesTools(join(projectSkillsDir, entry.name))) {
|
|
294
|
+
names.push(entry.name);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
names.sort((a, b) => a.localeCompare(b));
|
|
298
|
+
return names;
|
|
299
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @ts-nocheck — bun script outside cli/tsconfig (no Node/Bun types in staged vp check)
|
|
3
|
+
/**
|
|
4
|
+
* Summarize Tarsk agent runs for tarsk-improve: tool failures, repeats, and
|
|
5
|
+
* turn/token waste that point at Tool skill fixes.
|
|
6
|
+
*
|
|
7
|
+
* Usage (from project root, after ensure-exported):
|
|
8
|
+
* bun .agents/skills/tarsk-improve/scripts/summarize-session.ts
|
|
9
|
+
* bun .agents/skills/tarsk-improve/scripts/summarize-session.ts --conversation <id>
|
|
10
|
+
* bun .agents/skills/tarsk-improve/scripts/summarize-session.ts --since 24h
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
COMMON_USAGE_FLAGS,
|
|
15
|
+
abortedCallCount,
|
|
16
|
+
cacheReadPercent,
|
|
17
|
+
failedCalls,
|
|
18
|
+
failureDetail,
|
|
19
|
+
formatContextTrend,
|
|
20
|
+
formatStopReasons,
|
|
21
|
+
formatToolHistogram,
|
|
22
|
+
isProjectConfigToolCall,
|
|
23
|
+
largestResults,
|
|
24
|
+
loadRunsFromArgs,
|
|
25
|
+
printNoRunsHint,
|
|
26
|
+
printRunHeader,
|
|
27
|
+
repeatedCallCount,
|
|
28
|
+
retriesAfterFailureCount,
|
|
29
|
+
toolHistogram,
|
|
30
|
+
type Run,
|
|
31
|
+
} from "./durable-runs.js";
|
|
32
|
+
|
|
33
|
+
const MAX_FAILURES_SHOWN = 12;
|
|
34
|
+
|
|
35
|
+
function printUsage(): void {
|
|
36
|
+
console.error(`Usage:
|
|
37
|
+
bun .agents/skills/tarsk-improve/scripts/summarize-session.ts [options]
|
|
38
|
+
|
|
39
|
+
Summarizes recent agent runs from tarsk.db for Tool skill improvement.
|
|
40
|
+
|
|
41
|
+
${COMMON_USAGE_FLAGS}
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Higher = more waste. Project-config tool calls are not counted as productive work. */
|
|
46
|
+
export function wasteScore(run: Run): number {
|
|
47
|
+
const productiveTools = run.calls.filter((call) => !isProjectConfigToolCall(call)).length;
|
|
48
|
+
return (
|
|
49
|
+
run.modelCalls +
|
|
50
|
+
failedCalls(run.calls).length * 2 +
|
|
51
|
+
retriesAfterFailureCount(run.calls) * 2 +
|
|
52
|
+
repeatedCallCount(run.calls) +
|
|
53
|
+
run.providerErrors * 2 +
|
|
54
|
+
productiveTools * 0.1
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function printRun(run: Run, index: number): void {
|
|
59
|
+
const projectConfigCalls = run.calls.filter(isProjectConfigToolCall).length;
|
|
60
|
+
const failures = failedCalls(run.calls);
|
|
61
|
+
const cachePercent = cacheReadPercent(run);
|
|
62
|
+
|
|
63
|
+
console.log(`## Run ${index + 1} (waste score ${wasteScore(run).toFixed(1)})`);
|
|
64
|
+
printRunHeader(run);
|
|
65
|
+
console.log(`- duration: ${run.durationSec === undefined ? "?" : `${run.durationSec}s`}`);
|
|
66
|
+
console.log(`- agent turns (model calls): ${run.modelCalls}`);
|
|
67
|
+
console.log(`- stop reasons: ${formatStopReasons(run) || "(none)"}`);
|
|
68
|
+
console.log(`- tool calls: ${run.calls.length}`);
|
|
69
|
+
console.log(`- project-config tool calls (excluded): ${projectConfigCalls}`);
|
|
70
|
+
console.log(
|
|
71
|
+
`- tool failures: ${failures.length} (user aborts not counted: ${abortedCallCount(run.calls)})`,
|
|
72
|
+
);
|
|
73
|
+
console.log(`- identical repeated calls: ${repeatedCallCount(run.calls)}`);
|
|
74
|
+
console.log(`- retried a failed call unchanged: ${retriesAfterFailureCount(run.calls)}`);
|
|
75
|
+
console.log(`- provider errors: ${run.providerErrors}`);
|
|
76
|
+
console.log(`- context resets (compaction / rollover): ${run.resets}`);
|
|
77
|
+
console.log(`- context tokens: ${formatContextTrend(run)}`);
|
|
78
|
+
console.log(
|
|
79
|
+
`- cache: read ${cachePercent === undefined ? "n/a" : `${cachePercent}%`} of input, wrote ${run.cacheWriteTokens} tokens`,
|
|
80
|
+
);
|
|
81
|
+
console.log(`- output tokens: ${run.outputTokens} (reasoning ${run.reasoningTokens})`);
|
|
82
|
+
console.log(`- cost: $${run.costTotal.toFixed(4)}`);
|
|
83
|
+
console.log(`- largest tool results: ${largestResults(run.calls) || "(none)"}`);
|
|
84
|
+
console.log(`- tools (all): ${formatToolHistogram(toolHistogram(run.calls))}`);
|
|
85
|
+
console.log(
|
|
86
|
+
`- tools (excl. project config): ${formatToolHistogram(toolHistogram(run.calls, { exclProjectConfig: true }))}`,
|
|
87
|
+
);
|
|
88
|
+
if (failures.length > 0) {
|
|
89
|
+
console.log(`- failures:`);
|
|
90
|
+
for (const failure of failures.slice(0, MAX_FAILURES_SHOWN)) {
|
|
91
|
+
console.log(` - ${failure.name}: ${failureDetail(failure, 100)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
console.log("");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function main(): void {
|
|
98
|
+
const argv = process.argv.slice(2);
|
|
99
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
100
|
+
printUsage();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const { runs, args } = loadRunsFromArgs(argv);
|
|
105
|
+
const withActivity = runs.filter((run) => run.modelCalls > 0);
|
|
106
|
+
const shown = [...withActivity]
|
|
107
|
+
.sort((a, b) => wasteScore(b) - wasteScore(a))
|
|
108
|
+
.slice(0, args.limit);
|
|
109
|
+
|
|
110
|
+
console.log(`# Tarsk improve — session summary`);
|
|
111
|
+
console.log(
|
|
112
|
+
`Runs loaded: ${runs.length}; with agent activity: ${withActivity.length} (showing top ${shown.length} by waste score)\n`,
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
for (const [index, run] of shown.entries()) {
|
|
116
|
+
printRun(run, index);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (shown.length === 0) {
|
|
120
|
+
printNoRunsHint();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (import.meta.main) {
|
|
125
|
+
main();
|
|
126
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tarsk-jobs
|
|
3
|
+
description: >-
|
|
4
|
+
Tarsk Tool skill publishing: job_list, job_output, job_kill.
|
|
5
|
+
version: 2.1.0
|
|
6
|
+
tools:
|
|
7
|
+
- job_list
|
|
8
|
+
- job_output
|
|
9
|
+
- job_kill
|
|
10
|
+
disable-model-invocation: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# tarsk-jobs
|
|
14
|
+
|
|
15
|
+
Publishes: job_list, job_output, job_kill.
|
|
16
|
+
|
|
17
|
+
Logic and formatting live in `scripts/`. Owner-scoped registry access and kill
|
|
18
|
+
are `context.jobs` (CLI host).
|