@yadsh/dsh-qa-surface 0.5.0 → 0.6.0
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 +194 -9
- package/compatibility.json +10 -1
- package/cordis.patch.yml +9 -0
- package/lib/account-remotes.js +10 -0
- package/lib/account-remotes.js.map +1 -1
- package/lib/accounts/errors.js.map +1 -1
- package/lib/accounts/file.js.map +1 -1
- package/lib/accounts/store.js +22 -0
- package/lib/accounts/store.js.map +1 -1
- package/lib/client/QaAccountsController.js +29 -0
- package/lib/client/QaAccountsController.js.map +1 -1
- package/lib/client/QaSessionController.js +168 -48
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +125 -56
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaSurfaceGuard.js +96 -0
- package/lib/client/QaSurfaceGuard.js.map +1 -0
- package/lib/client/QaTranscriptAdapter.js +11 -5
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/components/QaChangelog.js +31 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaComposer.js +1 -1
- package/lib/client/components/QaComposer.js.map +1 -1
- package/lib/client/components/QaHeader.js +2 -8
- package/lib/client/components/QaHeader.js.map +1 -1
- package/lib/client/components/QaMessage.js +20 -7
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/components/QaModal.js +24 -6
- package/lib/client/components/QaModal.js.map +1 -1
- package/lib/client/components/QaSidebar.js +2 -6
- package/lib/client/components/QaSidebar.js.map +1 -1
- package/lib/client/components/QaSourcesPanel.js +6 -5
- package/lib/client/components/QaSourcesPanel.js.map +1 -1
- package/lib/client/components/QaWidthHandle.js +21 -1
- package/lib/client/components/QaWidthHandle.js.map +1 -1
- package/lib/client/components/surface-utils.js +2 -0
- package/lib/client/components/surface-utils.js.map +1 -1
- package/lib/client/index.js +72 -24
- package/lib/client/index.js.map +1 -1
- package/lib/client/panels/PanelHost.js +209 -0
- package/lib/client/panels/PanelHost.js.map +1 -0
- package/lib/client/panels/PanelLauncher.js +39 -0
- package/lib/client/panels/PanelLauncher.js.map +1 -0
- package/lib/client/panels/contract.js +2 -0
- package/lib/client/panels/contract.js.map +1 -0
- package/lib/client/panels/index.js +2 -0
- package/lib/client/panels/index.js.map +1 -0
- package/lib/client/panels/registry.js +171 -0
- package/lib/client/panels/registry.js.map +1 -0
- package/lib/client/project-session-state.js +3 -0
- package/lib/client/project-session-state.js.map +1 -1
- package/lib/client/settings/card.js +2 -2
- package/lib/client/settings/card.js.map +1 -1
- package/lib/client/settings/sections/accounts.js +3 -1
- package/lib/client/settings/sections/accounts.js.map +1 -1
- package/lib/client/settings/sections/documents.js +88 -0
- package/lib/client/settings/sections/documents.js.map +1 -0
- package/lib/client/settings/sections/interface.js +2 -0
- package/lib/client/settings/sections/interface.js.map +1 -1
- package/lib/client/settings/sections.js +1 -0
- package/lib/client/settings/sections.js.map +1 -1
- package/lib/client/settings-extensions/contract.js +2 -0
- package/lib/client/settings-extensions/contract.js.map +1 -0
- package/lib/client/settings-extensions/index.js +2 -0
- package/lib/client/settings-extensions/index.js.map +1 -0
- package/lib/client/settings-extensions/registry.js +63 -0
- package/lib/client/settings-extensions/registry.js.map +1 -0
- package/lib/client/settlement.js +51 -5
- package/lib/client/settlement.js.map +1 -1
- package/lib/client/source-preview.js +24 -0
- package/lib/client/source-preview.js.map +1 -0
- package/lib/client/styles.js +157 -32
- package/lib/client/styles.js.map +1 -1
- package/lib/client/subagent-codenames.js +109 -0
- package/lib/client/subagent-codenames.js.map +1 -0
- package/lib/client/types.js +1 -0
- package/lib/client/types.js.map +1 -1
- package/lib/client/user-settings/GeneralSettingsPage.js +13 -0
- package/lib/client/user-settings/GeneralSettingsPage.js.map +1 -0
- package/lib/client/user-settings/ProfileSettingsPage.js +59 -0
- package/lib/client/user-settings/ProfileSettingsPage.js.map +1 -0
- package/lib/client/user-settings/SkillCatalog.js +23 -0
- package/lib/client/user-settings/SkillCatalog.js.map +1 -0
- package/lib/client/user-settings/SkillEditor.js +89 -0
- package/lib/client/user-settings/SkillEditor.js.map +1 -0
- package/lib/client/user-settings/SkillToolPicker.js +58 -0
- package/lib/client/user-settings/SkillToolPicker.js.map +1 -0
- package/lib/client/user-settings/SkillsSettingsPage.js +171 -0
- package/lib/client/user-settings/SkillsSettingsPage.js.map +1 -0
- package/lib/client/user-settings/StartersSettingsPage.js +78 -0
- package/lib/client/user-settings/StartersSettingsPage.js.map +1 -0
- package/lib/client/user-settings/UserSettingsDialog.js +50 -0
- package/lib/client/user-settings/UserSettingsDialog.js.map +1 -0
- package/lib/client/user-settings/copy.js +84 -0
- package/lib/client/user-settings/copy.js.map +1 -0
- package/lib/client/user-settings/draft.js +127 -0
- package/lib/client/user-settings/draft.js.map +1 -0
- package/lib/client/user-settings/fields.js +24 -0
- package/lib/client/user-settings/fields.js.map +1 -0
- package/lib/client.js +5467 -1379
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/accounts.js +30 -0
- package/lib/config-resolvers/accounts.js.map +1 -1
- package/lib/config-resolvers/defaults.js +23 -0
- package/lib/config-resolvers/defaults.js.map +1 -1
- package/lib/config-resolvers/tools.js +37 -0
- package/lib/config-resolvers/tools.js.map +1 -0
- package/lib/config-resolvers/ui.js +2 -0
- package/lib/config-resolvers/ui.js.map +1 -1
- package/lib/config.js +288 -0
- package/lib/config.js.map +1 -1
- package/lib/documents/artifacts/ids.js +43 -0
- package/lib/documents/artifacts/ids.js.map +1 -0
- package/lib/documents/artifacts/manifest.js +66 -0
- package/lib/documents/artifacts/manifest.js.map +1 -0
- package/lib/documents/artifacts/store.js +169 -0
- package/lib/documents/artifacts/store.js.map +1 -0
- package/lib/documents/capabilities.js +93 -0
- package/lib/documents/capabilities.js.map +1 -0
- package/lib/documents/config.js +302 -0
- package/lib/documents/config.js.map +1 -0
- package/lib/documents/defaults.js +78 -0
- package/lib/documents/defaults.js.map +1 -0
- package/lib/documents/errors.js +101 -0
- package/lib/documents/errors.js.map +1 -0
- package/lib/documents/index.js +80 -0
- package/lib/documents/index.js.map +1 -0
- package/lib/documents/inspect/facts.js +161 -0
- package/lib/documents/inspect/facts.js.map +1 -0
- package/lib/documents/inspect/zip.js +108 -0
- package/lib/documents/inspect/zip.js.map +1 -0
- package/lib/documents/markdown/directives.js +135 -0
- package/lib/documents/markdown/directives.js.map +1 -0
- package/lib/documents/markdown/frontmatter.js +35 -0
- package/lib/documents/markdown/frontmatter.js.map +1 -0
- package/lib/documents/markdown/normalize.js +113 -0
- package/lib/documents/markdown/normalize.js.map +1 -0
- package/lib/documents/orchestrator/assets.js +243 -0
- package/lib/documents/orchestrator/assets.js.map +1 -0
- package/lib/documents/orchestrator/convert-document.js +186 -0
- package/lib/documents/orchestrator/convert-document.js.map +1 -0
- package/lib/documents/orchestrator/create-document.js +292 -0
- package/lib/documents/orchestrator/create-document.js.map +1 -0
- package/lib/documents/orchestrator/extract-document.js +162 -0
- package/lib/documents/orchestrator/extract-document.js.map +1 -0
- package/lib/documents/orchestrator/inspect-document.js +89 -0
- package/lib/documents/orchestrator/inspect-document.js.map +1 -0
- package/lib/documents/orchestrator/runtime-deps.js +59 -0
- package/lib/documents/orchestrator/runtime-deps.js.map +1 -0
- package/lib/documents/orchestrator/scope.js +132 -0
- package/lib/documents/orchestrator/scope.js.map +1 -0
- package/lib/documents/providers/docling.js +247 -0
- package/lib/documents/providers/docling.js.map +1 -0
- package/lib/documents/providers/libreoffice.js +130 -0
- package/lib/documents/providers/libreoffice.js.map +1 -0
- package/lib/documents/providers/markitdown.js +89 -0
- package/lib/documents/providers/markitdown.js.map +1 -0
- package/lib/documents/providers/pandoc.js +161 -0
- package/lib/documents/providers/pandoc.js.map +1 -0
- package/lib/documents/providers/process.js +164 -0
- package/lib/documents/providers/process.js.map +1 -0
- package/lib/documents/providers/registry.js +152 -0
- package/lib/documents/providers/registry.js.map +1 -0
- package/lib/documents/providers/shared.js +75 -0
- package/lib/documents/providers/shared.js.map +1 -0
- package/lib/documents/runtime.js +114 -0
- package/lib/documents/runtime.js.map +1 -0
- package/lib/documents/security/file-types.js +188 -0
- package/lib/documents/security/file-types.js.map +1 -0
- package/lib/documents/security/limits.js +78 -0
- package/lib/documents/security/limits.js.map +1 -0
- package/lib/documents/security/mime.js +43 -0
- package/lib/documents/security/mime.js.map +1 -0
- package/lib/documents/security/paths.js +133 -0
- package/lib/documents/security/paths.js.map +1 -0
- package/lib/documents/templates/registry.js +147 -0
- package/lib/documents/templates/registry.js.map +1 -0
- package/lib/documents/templates/resolver.js +59 -0
- package/lib/documents/templates/resolver.js.map +1 -0
- package/lib/documents/tools/convert.js +125 -0
- package/lib/documents/tools/convert.js.map +1 -0
- package/lib/documents/tools/create.js +187 -0
- package/lib/documents/tools/create.js.map +1 -0
- package/lib/documents/tools/index.js +41 -0
- package/lib/documents/tools/index.js.map +1 -0
- package/lib/documents/tools/inspect.js +135 -0
- package/lib/documents/tools/inspect.js.map +1 -0
- package/lib/documents/tools/shared.js +88 -0
- package/lib/documents/tools/shared.js.map +1 -0
- package/lib/documents/tools/to-markdown.js +125 -0
- package/lib/documents/tools/to-markdown.js.map +1 -0
- package/lib/documents/types.js +12 -0
- package/lib/documents/types.js.map +1 -0
- package/lib/index.js +225 -20
- package/lib/index.js.map +1 -1
- package/lib/integration-principals.js +22 -0
- package/lib/integration-principals.js.map +1 -0
- package/lib/lockdown-policy.js +15 -3
- package/lib/lockdown-policy.js.map +1 -1
- package/lib/personal-skills/errors.js +9 -0
- package/lib/personal-skills/errors.js.map +1 -0
- package/lib/personal-skills/host.js +80 -0
- package/lib/personal-skills/host.js.map +1 -0
- package/lib/personal-skills/index.js +10 -0
- package/lib/personal-skills/index.js.map +1 -0
- package/lib/personal-skills/paths.js +127 -0
- package/lib/personal-skills/paths.js.map +1 -0
- package/lib/personal-skills/provider.js +109 -0
- package/lib/personal-skills/provider.js.map +1 -0
- package/lib/personal-skills/remotes.js +40 -0
- package/lib/personal-skills/remotes.js.map +1 -0
- package/lib/personal-skills/service.js +686 -0
- package/lib/personal-skills/service.js.map +1 -0
- package/lib/personal-skills/skill-file.js +278 -0
- package/lib/personal-skills/skill-file.js.map +1 -0
- package/lib/personal-skills/skill-format.js +202 -0
- package/lib/personal-skills/skill-format.js.map +1 -0
- package/lib/personal-skills/watcher.js +96 -0
- package/lib/personal-skills/watcher.js.map +1 -0
- package/lib/profile.js +6 -4
- package/lib/profile.js.map +1 -1
- package/lib/prompt-notes.js +19 -0
- package/lib/prompt-notes.js.map +1 -1
- package/lib/provenance/file-preview.js +68 -21
- package/lib/provenance/file-preview.js.map +1 -1
- package/lib/provenance/host-store.js +44 -11
- package/lib/provenance/host-store.js.map +1 -1
- package/lib/provenance/index.js +1 -0
- package/lib/provenance/index.js.map +1 -1
- package/lib/provenance/normalize.js +3 -1
- package/lib/provenance/normalize.js.map +1 -1
- package/lib/provenance/snapshot-store.js +154 -0
- package/lib/provenance/snapshot-store.js.map +1 -0
- package/lib/qa-tools/activation-detector.js +53 -0
- package/lib/qa-tools/activation-detector.js.map +1 -0
- package/lib/qa-tools/activation-manager.js +111 -0
- package/lib/qa-tools/activation-manager.js.map +1 -0
- package/lib/qa-tools/catalog.js +108 -0
- package/lib/qa-tools/catalog.js.map +1 -0
- package/lib/qa-tools/durable-marker.js +115 -0
- package/lib/qa-tools/durable-marker.js.map +1 -0
- package/lib/qa-tools/index.js +83 -0
- package/lib/qa-tools/index.js.map +1 -0
- package/lib/qa-tools/lifecycle.js +64 -0
- package/lib/qa-tools/lifecycle.js.map +1 -0
- package/lib/qa-tools/types.js +2 -0
- package/lib/qa-tools/types.js.map +1 -0
- package/lib/resolve-config.js +5 -0
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +35 -3
- package/lib/secure-session.js.map +1 -1
- package/lib/starters.js +117 -0
- package/lib/starters.js.map +1 -0
- package/lib/typert.host.js +767 -22
- package/lib/typert.remote-client.d.ts +17 -1
- package/lib/typert.remote-client.js +609 -17
- package/lib/types/account-remotes.d.ts +3 -1
- package/lib/types/accounts/errors.d.ts +1 -1
- package/lib/types/accounts/file.d.ts +10 -0
- package/lib/types/accounts/store.d.ts +7 -1
- package/lib/types/client/QaAccountsController.d.ts +7 -1
- package/lib/types/client/QaSessionController.d.ts +12 -0
- package/lib/types/client/QaSurface.d.ts +14 -4
- package/lib/types/client/QaSurfaceGuard.d.ts +27 -0
- package/lib/types/client/QaTranscriptAdapter.d.ts +7 -0
- package/lib/types/client/components/QaComposer.d.ts +3 -1
- package/lib/types/client/components/QaHeader.d.ts +3 -1
- package/lib/types/client/components/QaModal.d.ts +5 -4
- package/lib/types/client/components/QaSidebar.d.ts +8 -11
- package/lib/types/client/components/QaWidthHandle.d.ts +13 -0
- package/lib/types/client/index.d.ts +1 -0
- package/lib/types/client/panels/PanelHost.d.ts +18 -0
- package/lib/types/client/panels/PanelLauncher.d.ts +5 -0
- package/lib/types/client/panels/contract.d.ts +83 -0
- package/lib/types/client/panels/index.d.ts +3 -0
- package/lib/types/client/panels/registry.d.ts +40 -0
- package/lib/types/client/project-session-state.d.ts +5 -0
- package/lib/types/client/settings/sections/documents.d.ts +13 -0
- package/lib/types/client/settings/sections.d.ts +1 -0
- package/lib/types/client/settings-extensions/contract.d.ts +32 -0
- package/lib/types/client/settings-extensions/index.d.ts +3 -0
- package/lib/types/client/settings-extensions/registry.d.ts +15 -0
- package/lib/types/client/settlement.d.ts +41 -5
- package/lib/types/client/source-preview.d.ts +8 -0
- package/lib/types/client/styles.d.ts +2 -0
- package/lib/types/client/subagent-codenames.d.ts +18 -0
- package/lib/types/client/types.d.ts +35 -3
- package/lib/types/client/user-settings/GeneralSettingsPage.d.ts +14 -0
- package/lib/types/client/user-settings/ProfileSettingsPage.d.ts +18 -0
- package/lib/types/client/user-settings/SkillCatalog.d.ts +16 -0
- package/lib/types/client/user-settings/SkillEditor.d.ts +42 -0
- package/lib/types/client/user-settings/SkillToolPicker.d.ts +17 -0
- package/lib/types/client/user-settings/SkillsSettingsPage.d.ts +15 -0
- package/lib/types/client/user-settings/StartersSettingsPage.d.ts +14 -0
- package/lib/types/client/user-settings/UserSettingsDialog.d.ts +43 -0
- package/lib/types/client/user-settings/copy.d.ts +25 -0
- package/lib/types/client/user-settings/draft.d.ts +51 -0
- package/lib/types/client/user-settings/fields.d.ts +43 -0
- package/lib/types/config-resolvers/tools.d.ts +6 -0
- package/lib/types/documents/artifacts/ids.d.ts +14 -0
- package/lib/types/documents/artifacts/manifest.d.ts +32 -0
- package/lib/types/documents/artifacts/store.d.ts +67 -0
- package/lib/types/documents/capabilities.d.ts +32 -0
- package/lib/types/documents/config.d.ts +27 -0
- package/lib/types/documents/defaults.d.ts +161 -0
- package/lib/types/documents/errors.d.ts +42 -0
- package/lib/types/documents/index.d.ts +63 -0
- package/lib/types/documents/inspect/facts.d.ts +43 -0
- package/lib/types/documents/inspect/zip.d.ts +28 -0
- package/lib/types/documents/markdown/directives.d.ts +39 -0
- package/lib/types/documents/markdown/frontmatter.d.ts +15 -0
- package/lib/types/documents/markdown/normalize.d.ts +30 -0
- package/lib/types/documents/orchestrator/assets.d.ts +55 -0
- package/lib/types/documents/orchestrator/convert-document.d.ts +25 -0
- package/lib/types/documents/orchestrator/create-document.d.ts +18 -0
- package/lib/types/documents/orchestrator/extract-document.d.ts +24 -0
- package/lib/types/documents/orchestrator/inspect-document.d.ts +12 -0
- package/lib/types/documents/orchestrator/runtime-deps.d.ts +43 -0
- package/lib/types/documents/orchestrator/scope.d.ts +52 -0
- package/lib/types/documents/providers/docling.d.ts +54 -0
- package/lib/types/documents/providers/libreoffice.d.ts +40 -0
- package/lib/types/documents/providers/markitdown.d.ts +28 -0
- package/lib/types/documents/providers/pandoc.d.ts +42 -0
- package/lib/types/documents/providers/process.d.ts +54 -0
- package/lib/types/documents/providers/registry.d.ts +68 -0
- package/lib/types/documents/providers/shared.d.ts +27 -0
- package/lib/types/documents/runtime.d.ts +59 -0
- package/lib/types/documents/security/file-types.d.ts +39 -0
- package/lib/types/documents/security/limits.d.ts +24 -0
- package/lib/types/documents/security/mime.d.ts +13 -0
- package/lib/types/documents/security/paths.d.ts +38 -0
- package/lib/types/documents/templates/registry.d.ts +50 -0
- package/lib/types/documents/templates/resolver.d.ts +30 -0
- package/lib/types/documents/tools/convert.d.ts +9 -0
- package/lib/types/documents/tools/create.d.ts +14 -0
- package/lib/types/documents/tools/index.d.ts +33 -0
- package/lib/types/documents/tools/inspect.d.ts +9 -0
- package/lib/types/documents/tools/shared.d.ts +77 -0
- package/lib/types/documents/tools/to-markdown.d.ts +12 -0
- package/lib/types/documents/types.d.ts +294 -0
- package/lib/types/index.d.ts +75 -3
- package/lib/types/integration-principals.d.ts +9 -0
- package/lib/types/lockdown-policy.d.ts +12 -2
- package/lib/types/personal-skills/errors.d.ts +11 -0
- package/lib/types/personal-skills/host.d.ts +42 -0
- package/lib/types/personal-skills/index.d.ts +10 -0
- package/lib/types/personal-skills/paths.d.ts +39 -0
- package/lib/types/personal-skills/provider.d.ts +33 -0
- package/lib/types/personal-skills/remotes.d.ts +35 -0
- package/lib/types/personal-skills/service.d.ts +131 -0
- package/lib/types/personal-skills/skill-file.d.ts +64 -0
- package/lib/types/personal-skills/skill-format.d.ts +100 -0
- package/lib/types/personal-skills/watcher.d.ts +39 -0
- package/lib/types/profile.d.ts +13 -0
- package/lib/types/prompt-notes.d.ts +9 -0
- package/lib/types/provenance/file-preview.d.ts +47 -4
- package/lib/types/provenance/host-store.d.ts +7 -1
- package/lib/types/provenance/index.d.ts +1 -0
- package/lib/types/provenance/snapshot-store.d.ts +23 -0
- package/lib/types/qa-tools/activation-detector.d.ts +29 -0
- package/lib/types/qa-tools/activation-manager.d.ts +47 -0
- package/lib/types/qa-tools/catalog.d.ts +40 -0
- package/lib/types/qa-tools/durable-marker.d.ts +16 -0
- package/lib/types/qa-tools/index.d.ts +40 -0
- package/lib/types/qa-tools/lifecycle.d.ts +44 -0
- package/lib/types/qa-tools/types.d.ts +45 -0
- package/lib/types/secure-session.d.ts +24 -2
- package/lib/types/starters.d.ts +45 -0
- package/lib/types/types.d.ts +202 -3
- package/package.json +24 -11
- package/scripts/repair-session-events.mjs +260 -0
- package/lib/client/components/QaProfile.js +0 -64
- package/lib/client/components/QaProfile.js.map +0 -1
- package/lib/types/client/components/QaProfile.d.ts +0 -25
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { WorkspaceId } from "@deepseek-ai/dsh-workspace";
|
|
2
|
+
import { createQaUserSkillProvider } from "./provider.js";
|
|
3
|
+
import { QaPersonalSkills } from "./service.js";
|
|
4
|
+
import { QaSkillWatcher } from "./watcher.js";
|
|
5
|
+
/**
|
|
6
|
+
* Host owner of the personal-skills feature: the storage service, the DSH
|
|
7
|
+
* provider registration and the manual-edit watcher.
|
|
8
|
+
*
|
|
9
|
+
* The three are one unit because they share a single liveness contract — every
|
|
10
|
+
* write through the service, and every filesystem event the watcher observes,
|
|
11
|
+
* invalidates the same provider registration, so the catalog the model reads
|
|
12
|
+
* and the catalog the editor writes cannot drift apart. The provider is
|
|
13
|
+
* registered through `ctx.inject`, so a deployment without the skills service
|
|
14
|
+
* keeps the editor working and simply publishes nothing to DSH.
|
|
15
|
+
*/
|
|
16
|
+
export class QaPersonalSkillsHost {
|
|
17
|
+
service;
|
|
18
|
+
watcher;
|
|
19
|
+
options;
|
|
20
|
+
/**
|
|
21
|
+
* The registry's own invalidation callback, guarded by registration
|
|
22
|
+
* identity on its side: a reference kept past disposal is a no-op.
|
|
23
|
+
*/
|
|
24
|
+
invalidateCatalog;
|
|
25
|
+
disposeRegistration;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
const { ctx, logger } = options;
|
|
29
|
+
this.watcher = new QaSkillWatcher({
|
|
30
|
+
onChange: () => this.invalidateCatalog?.(),
|
|
31
|
+
onError: (message) => logger.warn("skill.watch-failed", { message }),
|
|
32
|
+
});
|
|
33
|
+
this.service = new QaPersonalSkills(ctx, {
|
|
34
|
+
getConfig: options.getConfig,
|
|
35
|
+
logger,
|
|
36
|
+
workspacePath: () => this.registeredWorkspacePath(),
|
|
37
|
+
invalidate: () => this.invalidateCatalog?.(),
|
|
38
|
+
onRootDiscovered: (root) => {
|
|
39
|
+
if (!options.getConfig().accounts.skills.watch)
|
|
40
|
+
return;
|
|
41
|
+
this.watcher.follow(root);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
ctx.inject(["skills"], (skillsCtx) => {
|
|
45
|
+
const registration = skillsCtx.skills.registerProvider((control) => {
|
|
46
|
+
this.invalidateCatalog = control.invalidate;
|
|
47
|
+
return createQaUserSkillProvider(control, this.service);
|
|
48
|
+
});
|
|
49
|
+
this.disposeRegistration = registration;
|
|
50
|
+
skillsCtx.effect(() => () => {
|
|
51
|
+
registration();
|
|
52
|
+
this.disposeRegistration = undefined;
|
|
53
|
+
this.invalidateCatalog = undefined;
|
|
54
|
+
}, "dsh-qa-surface.personal-skills-provider");
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Whether the DSH registry currently owns this deployment's provider. */
|
|
58
|
+
get registered() {
|
|
59
|
+
return this.disposeRegistration !== undefined;
|
|
60
|
+
}
|
|
61
|
+
dispose() {
|
|
62
|
+
this.watcher.dispose();
|
|
63
|
+
this.disposeRegistration?.();
|
|
64
|
+
this.disposeRegistration = undefined;
|
|
65
|
+
this.invalidateCatalog = undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The registered workspace path the per-account directories live under.
|
|
69
|
+
* Resolved per call: a deployment may register the workspace after this
|
|
70
|
+
* plugin loads.
|
|
71
|
+
*/
|
|
72
|
+
registeredWorkspacePath() {
|
|
73
|
+
const workspaceId = this.options.getConfig().session.workspaceId;
|
|
74
|
+
if (workspaceId === null)
|
|
75
|
+
return undefined;
|
|
76
|
+
return this.options.ctx.workspaceRegistry.get(WorkspaceId(workspaceId))
|
|
77
|
+
?.path;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/personal-skills/host.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { QaPersonalSkillError, } from "./errors.js";
|
|
2
|
+
export { QA_SKILL_TRASH_SUFFIX, resolveSkillRoots, skillDirectory, skillFilePath, } from "./paths.js";
|
|
3
|
+
export { normalizeAllowedTools, parseSkillFile, serializeSkillFile, skillFileBody, skillNameProblem, toJsonValue, } from "./skill-file.js";
|
|
4
|
+
export { skillFileBytes, skillRelativeRootProblem, skillRelativeRootSegments, validateSkillDraft, QA_SKILL_DEFAULT_RELATIVE_ROOT, QA_SKILL_DESCRIPTION_MAX, QA_SKILL_ENABLED_BY_DEFAULT, QA_SKILL_FILE_MAX_BYTES, QA_SKILL_MAX_BYTES_MAX, QA_SKILL_MAX_BYTES_MIN, QA_SKILL_MAX_TOOLS, QA_SKILL_NAME_MAX, QA_SKILL_NAME_PATTERN, QA_SKILL_WHEN_TO_USE_MAX, } from "./skill-format.js";
|
|
5
|
+
export { QA_USER_SKILLS_PROVIDER, QA_USER_SKILLS_RANK, QA_USER_SKILLS_SOURCE, createQaUserSkillProvider, } from "./provider.js";
|
|
6
|
+
export { QaPersonalSkills, } from "./service.js";
|
|
7
|
+
export { createQaPersonalSkillRemotes, } from "./remotes.js";
|
|
8
|
+
export { QaPersonalSkillsHost } from "./host.js";
|
|
9
|
+
export { QaSkillWatcher } from "./watcher.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/personal-skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,GAErB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,aAAa,GAEd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,WAAW,GAIZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,8BAA8B,EAC9B,wBAAwB,EACxB,2BAA2B,EAC3B,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,GAEzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,GAIjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,4BAA4B,GAE7B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { lstatSync, mkdirSync, readdirSync, realpathSync, } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { canonicalCandidate, pathIsInside } from "../user-workspace.js";
|
|
4
|
+
import { QaPersonalSkillError } from "./errors.js";
|
|
5
|
+
import { skillNameProblem, skillRelativeRootSegments } from "./skill-format.js";
|
|
6
|
+
/**
|
|
7
|
+
* Filesystem boundary of the personal-skills feature.
|
|
8
|
+
*
|
|
9
|
+
* Every path is derived, never accepted: the browser names a skill, the Host
|
|
10
|
+
* combines the authenticated account's own workspace directory with the
|
|
11
|
+
* configured relative root, and each step re-checks that the canonical result
|
|
12
|
+
* still sits below that account's root. Symlinked directories are refused
|
|
13
|
+
* rather than followed, so a link planted inside the personal root cannot
|
|
14
|
+
* move reads or writes to another account's storage.
|
|
15
|
+
*
|
|
16
|
+
* `.dsh/skills-trash` is the removal destination: the last segment of the
|
|
17
|
+
* configured relative root with a `-trash` suffix, so a deployment that moved
|
|
18
|
+
* its skill directory keeps the trash beside it.
|
|
19
|
+
*/
|
|
20
|
+
export const QA_SKILL_TRASH_SUFFIX = "-trash";
|
|
21
|
+
function samePath(left, right) {
|
|
22
|
+
return process.platform === "win32"
|
|
23
|
+
? left.toLowerCase() === right.toLowerCase()
|
|
24
|
+
: left === right;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Canonicalize a candidate below an already canonical parent. A path that
|
|
28
|
+
* resolves elsewhere — a symlinked directory, a junction, a replaced ancestor
|
|
29
|
+
* — is refused. `direct` additionally requires the result to be the parent's
|
|
30
|
+
* own child, which is what pins each skill to one directory level.
|
|
31
|
+
*/
|
|
32
|
+
function canonicalInside(parent, relative, reason, message, direct) {
|
|
33
|
+
let canonical;
|
|
34
|
+
try {
|
|
35
|
+
canonical = canonicalCandidate(path.join(parent, relative));
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw new QaPersonalSkillError("storage-unavailable", error instanceof Error ? error.message : String(error));
|
|
39
|
+
}
|
|
40
|
+
if (!pathIsInside(canonical, parent) ||
|
|
41
|
+
(direct && !samePath(path.dirname(canonical), parent))) {
|
|
42
|
+
throw new QaPersonalSkillError(reason, message);
|
|
43
|
+
}
|
|
44
|
+
return canonical;
|
|
45
|
+
}
|
|
46
|
+
/** Derive and verify every directory the feature touches for one account. */
|
|
47
|
+
export function resolveSkillRoots(personalRoot, relativeRoot) {
|
|
48
|
+
const segments = [...skillRelativeRootSegments(relativeRoot)];
|
|
49
|
+
const last = segments.pop();
|
|
50
|
+
if (last === undefined) {
|
|
51
|
+
throw new QaPersonalSkillError("storage-unavailable", "the configured personal-skills root names no directory");
|
|
52
|
+
}
|
|
53
|
+
const canonicalPersonal = canonicalCandidate(personalRoot);
|
|
54
|
+
const skills = canonicalInside(canonicalPersonal, path.join(...segments, last), "storage-unavailable", "the configured personal-skills root escapes this account's directory", false);
|
|
55
|
+
const trash = canonicalInside(canonicalPersonal, path.join(...segments, `${last}${QA_SKILL_TRASH_SUFFIX}`), "storage-unavailable", "the personal-skills trash directory escapes this account's directory", false);
|
|
56
|
+
return { personalRoot: canonicalPersonal, skills, trash };
|
|
57
|
+
}
|
|
58
|
+
/** The directory of one skill, validated against the account's skills root. */
|
|
59
|
+
export function skillDirectory(roots, name) {
|
|
60
|
+
const problem = skillNameProblem(name);
|
|
61
|
+
if (problem !== null) {
|
|
62
|
+
throw new QaPersonalSkillError("skill-name-invalid", `skill name is not usable: ${name}`);
|
|
63
|
+
}
|
|
64
|
+
return canonicalInside(roots.skills, name, "skill-name-invalid", "the skill directory escapes this account's skills root", true);
|
|
65
|
+
}
|
|
66
|
+
export function skillFilePath(roots, name) {
|
|
67
|
+
return path.join(skillDirectory(roots, name), "SKILL.md");
|
|
68
|
+
}
|
|
69
|
+
/** Whether the directory exists at all, without following a symlink. */
|
|
70
|
+
export function directoryExists(input) {
|
|
71
|
+
try {
|
|
72
|
+
const stat = lstatSync(input);
|
|
73
|
+
return stat.isDirectory() && !stat.isSymbolicLink();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Refuse a symlinked or non-directory entry where a real directory belongs. */
|
|
80
|
+
function assertPlainDirectory(input) {
|
|
81
|
+
const stat = lstatSync(input);
|
|
82
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
83
|
+
throw new QaPersonalSkillError("storage-unavailable", `personal skill storage must be a real directory: ${input}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Materialize the skills root inside one account's personal root. Creation is
|
|
88
|
+
* followed by a re-canonicalization, so a directory that appeared as a link
|
|
89
|
+
* between the check and the `mkdir` is still refused.
|
|
90
|
+
*/
|
|
91
|
+
export function ensureSkillRoots(roots) {
|
|
92
|
+
if (directoryExists(roots.skills)) {
|
|
93
|
+
assertPlainDirectory(roots.skills);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const parent = path.dirname(roots.skills);
|
|
98
|
+
if (directoryExists(parent))
|
|
99
|
+
assertPlainDirectory(parent);
|
|
100
|
+
mkdirSync(roots.skills, { recursive: true, mode: 0o700 });
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw new QaPersonalSkillError("storage-unavailable", error instanceof Error ? error.message : String(error));
|
|
104
|
+
}
|
|
105
|
+
assertPlainDirectory(roots.skills);
|
|
106
|
+
const verified = realpathSync.native(roots.skills);
|
|
107
|
+
if (!pathIsInside(verified, roots.personalRoot)) {
|
|
108
|
+
throw new QaPersonalSkillError("storage-unavailable", "personal skill storage escapes this account's directory");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** The skill subdirectories present for one account, sorted by name. */
|
|
112
|
+
export function listSkillDirectories(roots) {
|
|
113
|
+
let entries;
|
|
114
|
+
try {
|
|
115
|
+
entries = readdirSync(roots.skills, { withFileTypes: true });
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (error.code === "ENOENT")
|
|
119
|
+
return [];
|
|
120
|
+
throw new QaPersonalSkillError("storage-unavailable", error instanceof Error ? error.message : String(error));
|
|
121
|
+
}
|
|
122
|
+
return entries
|
|
123
|
+
.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."))
|
|
124
|
+
.map((entry) => entry.name)
|
|
125
|
+
.sort();
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/personal-skills/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery provider for one QA account's own skills.
|
|
3
|
+
*
|
|
4
|
+
* It exists because the shipped filesystem provider resolves the project root
|
|
5
|
+
* through the nearest `.git`, which for a personal QA directory inside a larger
|
|
6
|
+
* checkout would climb above the account and mix users together. This provider
|
|
7
|
+
* reads exactly one place — `<cwd>/.dsh/skills` where the cwd is a provisioned
|
|
8
|
+
* `.qa-users/<uuid>` directory — and replaces the filesystem layer inside the
|
|
9
|
+
* QA scope rather than adding a second one beside it.
|
|
10
|
+
*/
|
|
11
|
+
export const QA_USER_SKILLS_PROVIDER = "qa-user-skills";
|
|
12
|
+
/** Prompt-visible provenance label for a skill stored in an account directory. */
|
|
13
|
+
export const QA_USER_SKILLS_SOURCE = "qa-user";
|
|
14
|
+
/**
|
|
15
|
+
* Rank below the project layer (100) and the bundled layer (600): inside the
|
|
16
|
+
* QA scope a personal skill wins a same-named duplicate from any other layer.
|
|
17
|
+
*/
|
|
18
|
+
export const QA_USER_SKILLS_RANK = 50;
|
|
19
|
+
function locatorOf(value) {
|
|
20
|
+
const directory = value?.directory;
|
|
21
|
+
return typeof directory === "string" && directory !== ""
|
|
22
|
+
? directory
|
|
23
|
+
: undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The cwd a lookup is about. The registry's declared provider contract has
|
|
27
|
+
* only `cwd`, but it hands the caller's borrowed view options down as they
|
|
28
|
+
* are, so a scoped read also carries the calling agent — useful because an
|
|
29
|
+
* agent-scoped lookup does not always repeat the cwd.
|
|
30
|
+
*/
|
|
31
|
+
function lookupCwd(options) {
|
|
32
|
+
if (typeof options.cwd === "string" && options.cwd !== "")
|
|
33
|
+
return options.cwd;
|
|
34
|
+
const scope = options.scope;
|
|
35
|
+
const cwd = scope?.session?.header?.cwd;
|
|
36
|
+
return typeof cwd === "string" && cwd !== "" ? cwd : undefined;
|
|
37
|
+
}
|
|
38
|
+
function candidateOf(stored) {
|
|
39
|
+
const contents = stored.contents;
|
|
40
|
+
if (contents === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
return {
|
|
43
|
+
name: contents.name,
|
|
44
|
+
description: contents.description,
|
|
45
|
+
...(contents.whenToUse === null ? {} : { whenToUse: contents.whenToUse }),
|
|
46
|
+
invocation: {
|
|
47
|
+
modelInvocable: contents.modelInvocable,
|
|
48
|
+
userInvocable: contents.userInvocable,
|
|
49
|
+
},
|
|
50
|
+
source: QA_USER_SKILLS_SOURCE,
|
|
51
|
+
provider: QA_USER_SKILLS_PROVIDER,
|
|
52
|
+
resourceBase: { kind: "directory", path: stored.directory },
|
|
53
|
+
rank: QA_USER_SKILLS_RANK,
|
|
54
|
+
locator: { directory: stored.directoryName },
|
|
55
|
+
path: stored.filePath,
|
|
56
|
+
// The registry drops metadata from its summaries, so `allowed-tools` is
|
|
57
|
+
// readable here and by anyone who inspects a candidate — nothing in the
|
|
58
|
+
// harness enforces it, and nothing here claims otherwise.
|
|
59
|
+
metadata: { allowedTools: [...contents.allowedTools] },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function definitionOf(stored, candidate) {
|
|
63
|
+
const contents = stored.contents;
|
|
64
|
+
if (contents === undefined)
|
|
65
|
+
return undefined;
|
|
66
|
+
return { ...candidate, content: contents.body };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build the provider for one registration. The factory runs synchronously
|
|
70
|
+
* during `registerProvider` and all filesystem work stays inside
|
|
71
|
+
* `list`/`get`, which the registry calls per read.
|
|
72
|
+
*
|
|
73
|
+
* Note what the registry caches and what it does not: a loaded definition is
|
|
74
|
+
* never cached, so an edited body is visible to the next `get` immediately,
|
|
75
|
+
* while the candidate list behind a catalog summary is cached until something
|
|
76
|
+
* invalidates it. A save goes through the service, which invalidates; a file
|
|
77
|
+
* edited by hand is what the watcher exists for.
|
|
78
|
+
*/
|
|
79
|
+
export function createQaUserSkillProvider(control, skills) {
|
|
80
|
+
return {
|
|
81
|
+
name: QA_USER_SKILLS_PROVIDER,
|
|
82
|
+
list: async (options) => {
|
|
83
|
+
if (control.signal.aborted)
|
|
84
|
+
return [];
|
|
85
|
+
const cwd = lookupCwd(options);
|
|
86
|
+
if (cwd === undefined)
|
|
87
|
+
return [];
|
|
88
|
+
return skills
|
|
89
|
+
.discover(cwd)
|
|
90
|
+
.map(candidateOf)
|
|
91
|
+
.filter((candidate) => candidate !== undefined);
|
|
92
|
+
},
|
|
93
|
+
get: async (candidate, options) => {
|
|
94
|
+
if (control.signal.aborted)
|
|
95
|
+
return undefined;
|
|
96
|
+
const cwd = lookupCwd(options);
|
|
97
|
+
if (cwd === undefined)
|
|
98
|
+
return undefined;
|
|
99
|
+
const directory = locatorOf(candidate.locator);
|
|
100
|
+
if (directory === undefined)
|
|
101
|
+
return undefined;
|
|
102
|
+
const stored = skills.read(cwd, directory);
|
|
103
|
+
if (stored === undefined)
|
|
104
|
+
return undefined;
|
|
105
|
+
return definitionOf(stored, candidate);
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/personal-skills/provider.ts"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AACxD,kFAAkF;AAClF,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,CAAC;AAC/C;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAQtC,SAAS,SAAS,CAAC,KAAc;IAC/B,MAAM,SAAS,GAAI,KAAoC,EAAE,SAAS,CAAC;IACnE,OAAO,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,EAAE;QACtD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,SAAS,SAAS,CAAC,OAA2B;IAC5C,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,KAAK,EAAE;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC;IAC9E,MAAM,KAAK,GAAI,OAAwC,CAAC,KAAK,CAAC;IAC9D,MAAM,GAAG,GACP,KAGD,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC;IACxB,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC;AAED,SAAS,WAAW,CAAC,MAAqB;IACxC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC7C,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,GAAG,CAAC,QAAQ,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC;QACzE,UAAU,EAAE;YACV,cAAc,EAAE,QAAQ,CAAC,cAAc;YACvC,aAAa,EAAE,QAAQ,CAAC,aAAa;SACtC;QACD,MAAM,EAAE,qBAAqB;QAC7B,QAAQ,EAAE,uBAAuB;QACjC,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,SAAS,EAAE;QAC3D,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,aAAa,EAA2B;QACrE,IAAI,EAAE,MAAM,CAAC,QAAQ;QACrB,wEAAwE;QACxE,wEAAwE;QACxE,0DAA0D;QAC1D,QAAQ,EAAE,EAAE,YAAY,EAAE,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,EAAE;KACvD,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,MAAqB,EACrB,SAAyB;IAEzB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC7C,OAAO,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;AAClD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAA6B,EAC7B,MAAwB;IAExB,OAAO;QACL,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACtB,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;YAC/B,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;YACjC,OAAO,MAAM;iBACV,QAAQ,CAAC,GAAG,CAAC;iBACb,GAAG,CAAC,WAAW,CAAC;iBAChB,MAAM,CACL,CAAC,SAAS,EAA+B,EAAE,CAAC,SAAS,KAAK,SAAS,CACpE,CAAC;QACN,CAAC;QACD,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;YAChC,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,SAAS,CAAC;YAC7C,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;YAC/B,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YACxC,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAC/C,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC3C,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YAC3C,OAAO,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { QaPersonalSkillError } from "./errors.js";
|
|
2
|
+
export function createQaPersonalSkillRemotes(options) {
|
|
3
|
+
const { getConfig, logger, skills, accounts } = options;
|
|
4
|
+
/** The authenticated account behind the wire token; never a named user. */
|
|
5
|
+
const contextOf = (token) => {
|
|
6
|
+
const store = accounts.resolve(getConfig());
|
|
7
|
+
if (store === undefined) {
|
|
8
|
+
throw new Error("QA accounts are not enabled on this deployment.");
|
|
9
|
+
}
|
|
10
|
+
const user = accounts.run(() => store.requireUser(token));
|
|
11
|
+
return { userId: user.id };
|
|
12
|
+
};
|
|
13
|
+
const run = (operation, skill) => {
|
|
14
|
+
try {
|
|
15
|
+
return operation();
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error instanceof QaPersonalSkillError) {
|
|
19
|
+
logger.warn("skill.rejected", {
|
|
20
|
+
reason: error.reason,
|
|
21
|
+
...(skill === undefined ? {} : { skill }),
|
|
22
|
+
});
|
|
23
|
+
throw new Error(`QA personal skills refused the request (reason: ${error.reason})`, { cause: error });
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
list: (token) => run(() => ({ skills: skills.list(contextOf(token)) })),
|
|
30
|
+
get: (token, name) => run(() => skills.get(contextOf(token), name), name),
|
|
31
|
+
create: (token, input) => run(() => skills.create(contextOf(token), input), input.name),
|
|
32
|
+
update: (token, name, input) => run(() => skills.update(contextOf(token), name, input), name),
|
|
33
|
+
remove: (token, name, expectedRevision) => run(() => skills.remove(contextOf(token), name, expectedRevision), name),
|
|
34
|
+
tools: (token) => run(() => ({
|
|
35
|
+
tools: skills.tools(contextOf(token)),
|
|
36
|
+
})),
|
|
37
|
+
validate: (token, name, input) => run(() => skills.validate(contextOf(token), name, input), input.name),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=remotes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remotes.js","sourceRoot":"","sources":["../../src/personal-skills/remotes.ts"],"names":[],"mappings":"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"}
|