@intentic/sandbox-contract 1.232.0 → 1.234.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 +11 -5
- package/dist/agent-catalog.d.ts +4 -2
- package/dist/agent-catalog.d.ts.map +1 -1
- package/dist/agent-catalog.js +20 -14
- package/dist/agent-catalog.js.map +1 -1
- package/dist/chores/chores.d.ts +1 -1
- package/dist/chores/chores.d.ts.map +1 -1
- package/dist/chores/chores.js +36 -1
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/probes.d.ts +1 -1
- package/dist/chores/probes.d.ts.map +1 -1
- package/dist/chores/probes.js +70 -0
- package/dist/chores/probes.js.map +1 -1
- package/dist/chores/stack.d.ts.map +1 -1
- package/dist/chores/stack.js +2 -1
- package/dist/chores/stack.js.map +1 -1
- package/dist/chores/verdict.d.ts +1 -1
- package/dist/chores/verdict.d.ts.map +1 -1
- package/dist/command-classes.d.ts +17 -0
- package/dist/command-classes.d.ts.map +1 -0
- package/dist/command-classes.js +189 -0
- package/dist/command-classes.js.map +1 -0
- package/dist/contracts/activity.contract.js +1 -1
- package/dist/contracts/activity.contract.js.map +1 -1
- package/dist/contracts/agent.contract.d.ts +40 -2
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +4 -1
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +24 -0
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +5 -1
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/automations.contract.d.ts +30 -0
- package/dist/contracts/automations.contract.d.ts.map +1 -1
- package/dist/contracts/automations.contract.js +2 -1
- package/dist/contracts/automations.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts +63 -0
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/capabilities.contract.js +3 -1
- package/dist/contracts/capabilities.contract.js.map +1 -1
- package/dist/contracts/chores.contract.d.ts +17 -0
- package/dist/contracts/chores.contract.d.ts.map +1 -1
- package/dist/contracts/chores.contract.js +2 -1
- package/dist/contracts/chores.contract.js.map +1 -1
- package/dist/contracts/ci.contract.js +2 -1
- package/dist/contracts/ci.contract.js.map +1 -1
- package/dist/contracts/claude.contract.js +2 -1
- package/dist/contracts/claude.contract.js.map +1 -1
- package/dist/contracts/cursor.contract.js +2 -1
- package/dist/contracts/cursor.contract.js.map +1 -1
- package/dist/contracts/drafts.contract.d.ts.map +1 -1
- package/dist/contracts/drafts.contract.js +2 -1
- package/dist/contracts/drafts.contract.js.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js +2 -1
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/exit.contract.d.ts.map +1 -1
- package/dist/contracts/exit.contract.js +2 -1
- package/dist/contracts/exit.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts +44 -0
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.js +4 -1
- package/dist/contracts/extensions.contract.js.map +1 -1
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.js +4 -1
- package/dist/contracts/git.contract.js.map +1 -1
- package/dist/contracts/grok.contract.d.ts.map +1 -1
- package/dist/contracts/grok.contract.js +2 -1
- package/dist/contracts/grok.contract.js.map +1 -1
- package/dist/contracts/history.contract.d.ts.map +1 -1
- package/dist/contracts/history.contract.js +2 -1
- package/dist/contracts/history.contract.js.map +1 -1
- package/dist/contracts/host.contract.d.ts +7 -0
- package/dist/contracts/host.contract.d.ts.map +1 -1
- package/dist/contracts/host.contract.js +4 -1
- package/dist/contracts/host.contract.js.map +1 -1
- package/dist/contracts/intentic.contract.d.ts.map +1 -1
- package/dist/contracts/intentic.contract.js +2 -1
- package/dist/contracts/intentic.contract.js.map +1 -1
- package/dist/contracts/inventory.contract.js +1 -1
- package/dist/contracts/inventory.contract.js.map +1 -1
- package/dist/contracts/issues.contract.d.ts +89 -0
- package/dist/contracts/issues.contract.d.ts.map +1 -0
- package/dist/contracts/issues.contract.js +50 -0
- package/dist/contracts/issues.contract.js.map +1 -0
- package/dist/contracts/logs.contract.d.ts.map +1 -1
- package/dist/contracts/logs.contract.js +1 -1
- package/dist/contracts/logs.contract.js.map +1 -1
- package/dist/contracts/loops.contract.js +2 -1
- package/dist/contracts/loops.contract.js.map +1 -1
- package/dist/contracts/panels.contract.d.ts.map +1 -1
- package/dist/contracts/panels.contract.js +2 -1
- package/dist/contracts/panels.contract.js.map +1 -1
- package/dist/contracts/personas.contract.js +2 -1
- package/dist/contracts/personas.contract.js.map +1 -1
- package/dist/contracts/ports.contract.d.ts.map +1 -1
- package/dist/contracts/ports.contract.js +2 -1
- package/dist/contracts/ports.contract.js.map +1 -1
- package/dist/contracts/prepush.contract.d.ts.map +1 -1
- package/dist/contracts/prepush.contract.js +2 -1
- package/dist/contracts/prepush.contract.js.map +1 -1
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/providers.contract.js +2 -1
- package/dist/contracts/providers.contract.js.map +1 -1
- package/dist/contracts/public.contract.d.ts.map +1 -1
- package/dist/contracts/public.contract.js +2 -1
- package/dist/contracts/public.contract.js.map +1 -1
- package/dist/contracts/push.contract.d.ts.map +1 -1
- package/dist/contracts/push.contract.js +2 -1
- package/dist/contracts/push.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +127 -84
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.js +10 -2
- package/dist/contracts/runner.contract.js.map +1 -1
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +2 -1
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.js +1 -1
- package/dist/contracts/sessions.contract.js.map +1 -1
- package/dist/contracts/settings.contract.d.ts +32 -0
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +3 -1
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/share.contract.d.ts.map +1 -1
- package/dist/contracts/share.contract.js +2 -1
- package/dist/contracts/share.contract.js.map +1 -1
- package/dist/contracts/skills.contract.d.ts.map +1 -1
- package/dist/contracts/skills.contract.js +2 -1
- package/dist/contracts/skills.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts +31 -16
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +6 -1
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.js +4 -1
- package/dist/contracts/translator.contract.js.map +1 -1
- package/dist/contracts/usage.contract.js +1 -1
- package/dist/contracts/usage.contract.js.map +1 -1
- package/dist/contracts/vpn.contract.d.ts.map +1 -1
- package/dist/contracts/vpn.contract.js +2 -1
- package/dist/contracts/vpn.contract.js.map +1 -1
- package/dist/contracts/webext.contract.d.ts +45 -0
- package/dist/contracts/webext.contract.d.ts.map +1 -0
- package/dist/contracts/webext.contract.js +12 -0
- package/dist/contracts/webext.contract.js.map +1 -0
- package/dist/contracts/workflows.contract.js +2 -1
- package/dist/contracts/workflows.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +2 -2
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +7 -1
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/credential-material.d.ts +2 -0
- package/dist/credential-material.d.ts.map +1 -0
- package/dist/credential-material.js +36 -0
- package/dist/credential-material.js.map +1 -0
- package/dist/definition-action.d.ts +7 -0
- package/dist/definition-action.d.ts.map +1 -0
- package/dist/definition-action.js +3 -0
- package/dist/definition-action.js.map +1 -0
- package/dist/definition.d.ts +132 -21
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +29 -7
- package/dist/definition.js.map +1 -1
- package/dist/events.d.ts +101 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +25 -1
- package/dist/events.js.map +1 -1
- package/dist/fast-tier.d.ts +1 -1
- package/dist/fast-tier.d.ts.map +1 -1
- package/dist/history-state.d.ts.map +1 -1
- package/dist/history-state.js +2 -0
- package/dist/history-state.js.map +1 -1
- package/dist/hostnames.d.ts +2 -0
- package/dist/hostnames.d.ts.map +1 -1
- package/dist/hostnames.js +3 -1
- package/dist/hostnames.js.map +1 -1
- package/dist/index.d.ts +411 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +56 -1
- package/dist/index.js.map +1 -1
- package/dist/listener-protocol.js +1 -1
- package/dist/listener-protocol.js.map +1 -1
- package/dist/quick-model.d.ts +1 -1
- package/dist/quick-model.d.ts.map +1 -1
- package/dist/runner-protocol.d.ts +18 -0
- package/dist/runner-protocol.d.ts.map +1 -1
- package/dist/runner-protocol.js +8 -4
- package/dist/runner-protocol.js.map +1 -1
- package/dist/runtime-state.d.ts +9 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +3 -0
- package/dist/runtime-state.js.map +1 -1
- package/dist/schemas/activity.d.ts +112 -0
- package/dist/schemas/activity.d.ts.map +1 -0
- package/dist/schemas/activity.js +70 -0
- package/dist/schemas/activity.js.map +1 -0
- package/dist/schemas/agent.d.ts +195 -0
- package/dist/schemas/agent.d.ts.map +1 -0
- package/dist/schemas/agent.js +171 -0
- package/dist/schemas/agent.js.map +1 -0
- package/dist/schemas/agents.d.ts +690 -0
- package/dist/schemas/agents.d.ts.map +1 -0
- package/dist/schemas/agents.js +314 -0
- package/dist/schemas/agents.js.map +1 -0
- package/dist/schemas/automations.d.ts +781 -0
- package/dist/schemas/automations.d.ts.map +1 -0
- package/dist/schemas/automations.js +223 -0
- package/dist/schemas/automations.js.map +1 -0
- package/dist/schemas/capabilities.d.ts +753 -0
- package/dist/schemas/capabilities.d.ts.map +1 -0
- package/dist/schemas/capabilities.js +269 -0
- package/dist/schemas/capabilities.js.map +1 -0
- package/dist/schemas/ci.d.ts +179 -0
- package/dist/schemas/ci.d.ts.map +1 -0
- package/dist/schemas/ci.js +99 -0
- package/dist/schemas/ci.js.map +1 -0
- package/dist/schemas/claude-gate.d.ts +13 -0
- package/dist/schemas/claude-gate.d.ts.map +1 -0
- package/dist/schemas/claude-gate.js +8 -0
- package/dist/schemas/claude-gate.js.map +1 -0
- package/dist/schemas/codebase-health.d.ts +56 -0
- package/dist/schemas/codebase-health.d.ts.map +1 -0
- package/dist/schemas/codebase-health.js +43 -0
- package/dist/schemas/codebase-health.js.map +1 -0
- package/dist/schemas/computers.d.ts +386 -0
- package/dist/schemas/computers.d.ts.map +1 -0
- package/dist/schemas/computers.js +107 -0
- package/dist/schemas/computers.js.map +1 -0
- package/dist/schemas/drafts.d.ts +84 -0
- package/dist/schemas/drafts.d.ts.map +1 -0
- package/dist/schemas/drafts.js +44 -0
- package/dist/schemas/drafts.js.map +1 -0
- package/dist/schemas/environment.d.ts +349 -0
- package/dist/schemas/environment.d.ts.map +1 -0
- package/dist/schemas/environment.js +111 -0
- package/dist/schemas/environment.js.map +1 -0
- package/dist/schemas/exit.d.ts +151 -0
- package/dist/schemas/exit.d.ts.map +1 -0
- package/dist/schemas/exit.js +115 -0
- package/dist/schemas/exit.js.map +1 -0
- package/dist/schemas/extension-updates.d.ts +1016 -0
- package/dist/schemas/extension-updates.d.ts.map +1 -0
- package/dist/schemas/extension-updates.js +199 -0
- package/dist/schemas/extension-updates.js.map +1 -0
- package/dist/schemas/fast-mode.d.ts +8 -0
- package/dist/schemas/fast-mode.d.ts.map +1 -0
- package/dist/schemas/fast-mode.js +3 -0
- package/dist/schemas/fast-mode.js.map +1 -0
- package/dist/schemas/git-history.d.ts +238 -0
- package/dist/schemas/git-history.d.ts.map +1 -0
- package/dist/schemas/git-history.js +152 -0
- package/dist/schemas/git-history.js.map +1 -0
- package/dist/schemas/git.d.ts +471 -0
- package/dist/schemas/git.d.ts.map +1 -0
- package/dist/schemas/git.js +204 -0
- package/dist/schemas/git.js.map +1 -0
- package/dist/schemas/history.d.ts +100 -0
- package/dist/schemas/history.d.ts.map +1 -0
- package/dist/schemas/history.js +54 -0
- package/dist/schemas/history.js.map +1 -0
- package/dist/schemas/hosts.d.ts +41 -0
- package/dist/schemas/hosts.d.ts.map +1 -0
- package/dist/schemas/hosts.js +18 -0
- package/dist/schemas/hosts.js.map +1 -0
- package/dist/schemas/intentic.d.ts +5 -0
- package/dist/schemas/intentic.d.ts.map +1 -0
- package/dist/schemas/intentic.js +3 -0
- package/dist/schemas/intentic.js.map +1 -0
- package/dist/schemas/internal.d.ts +8 -0
- package/dist/schemas/internal.d.ts.map +1 -0
- package/dist/schemas/internal.js +12 -0
- package/dist/schemas/internal.js.map +1 -0
- package/dist/schemas/inventory.d.ts +171 -0
- package/dist/schemas/inventory.d.ts.map +1 -0
- package/dist/schemas/inventory.js +51 -0
- package/dist/schemas/inventory.js.map +1 -0
- package/dist/schemas/issues.d.ts +324 -0
- package/dist/schemas/issues.d.ts.map +1 -0
- package/dist/schemas/issues.js +107 -0
- package/dist/schemas/issues.js.map +1 -0
- package/dist/schemas/logs.d.ts +67 -0
- package/dist/schemas/logs.d.ts.map +1 -0
- package/dist/schemas/logs.js +54 -0
- package/dist/schemas/logs.js.map +1 -0
- package/dist/schemas/loops.d.ts +415 -0
- package/dist/schemas/loops.d.ts.map +1 -0
- package/dist/schemas/loops.js +188 -0
- package/dist/schemas/loops.js.map +1 -0
- package/dist/schemas/maintenance.d.ts +618 -0
- package/dist/schemas/maintenance.d.ts.map +1 -0
- package/dist/schemas/maintenance.js +222 -0
- package/dist/schemas/maintenance.js.map +1 -0
- package/dist/schemas/marketplace.d.ts +64 -0
- package/dist/schemas/marketplace.d.ts.map +1 -0
- package/dist/schemas/marketplace.js +17 -0
- package/dist/schemas/marketplace.js.map +1 -0
- package/dist/schemas/panels.d.ts +61 -0
- package/dist/schemas/panels.d.ts.map +1 -0
- package/dist/schemas/panels.js +51 -0
- package/dist/schemas/panels.js.map +1 -0
- package/dist/schemas/personas.d.ts +122 -0
- package/dist/schemas/personas.d.ts.map +1 -0
- package/dist/schemas/personas.js +102 -0
- package/dist/schemas/personas.js.map +1 -0
- package/dist/schemas/plan-limits.d.ts +172 -0
- package/dist/schemas/plan-limits.d.ts.map +1 -0
- package/dist/schemas/plan-limits.js +126 -0
- package/dist/schemas/plan-limits.js.map +1 -0
- package/dist/schemas/ports.d.ts +71 -0
- package/dist/schemas/ports.d.ts.map +1 -0
- package/dist/schemas/ports.js +42 -0
- package/dist/schemas/ports.js.map +1 -0
- package/dist/schemas/provider-oauth.d.ts +128 -0
- package/dist/schemas/provider-oauth.d.ts.map +1 -0
- package/dist/schemas/provider-oauth.js +91 -0
- package/dist/schemas/provider-oauth.js.map +1 -0
- package/dist/schemas/provider-subscriptions.d.ts +9 -0
- package/dist/schemas/provider-subscriptions.d.ts.map +1 -0
- package/dist/schemas/provider-subscriptions.js +3 -0
- package/dist/schemas/provider-subscriptions.js.map +1 -0
- package/dist/schemas/public.d.ts +32 -0
- package/dist/schemas/public.d.ts.map +1 -0
- package/dist/schemas/public.js +29 -0
- package/dist/schemas/public.js.map +1 -0
- package/dist/schemas/push.d.ts +55 -0
- package/dist/schemas/push.d.ts.map +1 -0
- package/dist/schemas/push.js +60 -0
- package/dist/schemas/push.js.map +1 -0
- package/dist/schemas/secrets.d.ts +86 -0
- package/dist/schemas/secrets.d.ts.map +1 -0
- package/dist/schemas/secrets.js +51 -0
- package/dist/schemas/secrets.js.map +1 -0
- package/dist/schemas/sessions.d.ts +32 -0
- package/dist/schemas/sessions.d.ts.map +1 -0
- package/dist/schemas/sessions.js +11 -0
- package/dist/schemas/sessions.js.map +1 -0
- package/dist/schemas/settings.d.ts +554 -0
- package/dist/schemas/settings.d.ts.map +1 -0
- package/dist/schemas/settings.js +263 -0
- package/dist/schemas/settings.js.map +1 -0
- package/dist/schemas/share.d.ts +49 -0
- package/dist/schemas/share.d.ts.map +1 -0
- package/dist/schemas/share.js +26 -0
- package/dist/schemas/share.js.map +1 -0
- package/dist/schemas/shared.d.ts +22 -0
- package/dist/schemas/shared.d.ts.map +1 -0
- package/dist/schemas/shared.js +16 -0
- package/dist/schemas/shared.js.map +1 -0
- package/dist/schemas/system.d.ts +86 -0
- package/dist/schemas/system.d.ts.map +1 -0
- package/dist/schemas/system.js +64 -0
- package/dist/schemas/system.js.map +1 -0
- package/dist/schemas/terminal.d.ts +230 -0
- package/dist/schemas/terminal.d.ts.map +1 -0
- package/dist/schemas/terminal.js +133 -0
- package/dist/schemas/terminal.js.map +1 -0
- package/dist/schemas/usage.d.ts +113 -0
- package/dist/schemas/usage.d.ts.map +1 -0
- package/dist/schemas/usage.js +91 -0
- package/dist/schemas/usage.js.map +1 -0
- package/dist/schemas/vpn.d.ts +229 -0
- package/dist/schemas/vpn.d.ts.map +1 -0
- package/dist/schemas/vpn.js +115 -0
- package/dist/schemas/vpn.js.map +1 -0
- package/dist/schemas/webext.d.ts +122 -0
- package/dist/schemas/webext.d.ts.map +1 -0
- package/dist/schemas/webext.js +45 -0
- package/dist/schemas/webext.js.map +1 -0
- package/dist/schemas/workflows.d.ts +881 -0
- package/dist/schemas/workflows.d.ts.map +1 -0
- package/dist/schemas/workflows.js +164 -0
- package/dist/schemas/workflows.js.map +1 -0
- package/dist/schemas/workspace-repos.d.ts +143 -0
- package/dist/schemas/workspace-repos.d.ts.map +1 -0
- package/dist/schemas/workspace-repos.js +87 -0
- package/dist/schemas/workspace-repos.js.map +1 -0
- package/dist/schemas/workspace-search.d.ts +170 -0
- package/dist/schemas/workspace-search.d.ts.map +1 -0
- package/dist/schemas/workspace-search.js +85 -0
- package/dist/schemas/workspace-search.js.map +1 -0
- package/dist/schemas/workspace-setup.d.ts +48 -0
- package/dist/schemas/workspace-setup.d.ts.map +1 -0
- package/dist/schemas/workspace-setup.js +26 -0
- package/dist/schemas/workspace-setup.js.map +1 -0
- package/dist/schemas/workspace-tree.d.ts +120 -0
- package/dist/schemas/workspace-tree.d.ts.map +1 -0
- package/dist/schemas/workspace-tree.js +111 -0
- package/dist/schemas/workspace-tree.js.map +1 -0
- package/dist/webext-links.d.ts +14 -0
- package/dist/webext-links.d.ts.map +1 -0
- package/dist/webext-links.js +25 -0
- package/dist/webext-links.js.map +1 -0
- package/dist/webext-protocol.d.ts +8 -0
- package/dist/webext-protocol.d.ts.map +1 -0
- package/dist/webext-protocol.js +7 -0
- package/dist/webext-protocol.js.map +1 -0
- package/dist/workflow-faults.d.ts +1 -1
- package/dist/workflow-faults.d.ts.map +1 -1
- package/dist/workspace-state.d.ts +12 -8
- package/dist/workspace-state.d.ts.map +1 -1
- package/dist/workspace-state.js +15 -10
- package/dist/workspace-state.js.map +1 -1
- package/package.json +19 -8
- package/src/agent-catalog.test.ts +56 -55
- package/src/agent-catalog.ts +33 -33
- package/src/capability-ledger.test.ts +11 -2
- package/src/chores/chores.test.ts +1 -1
- package/src/chores/chores.ts +67 -2
- package/src/chores/probes.test.ts +65 -0
- package/src/chores/probes.ts +133 -1
- package/src/chores/stack.test.ts +19 -0
- package/src/chores/stack.ts +19 -3
- package/src/chores/verdict.test.ts +40 -20
- package/src/chores/verdict.ts +1 -1
- package/src/command-classes.test.ts +445 -0
- package/src/command-classes.ts +468 -0
- package/src/contracts/activity.contract.ts +1 -1
- package/src/contracts/agent.contract.ts +4 -13
- package/src/contracts/agents.contract.ts +6 -6
- package/src/contracts/automations.contract.ts +2 -2
- package/src/contracts/capabilities.contract.ts +3 -4
- package/src/contracts/chores.contract.ts +2 -1
- package/src/contracts/ci.contract.ts +2 -2
- package/src/contracts/claude.contract.ts +2 -2
- package/src/contracts/cursor.contract.ts +2 -2
- package/src/contracts/drafts.contract.ts +2 -1
- package/src/contracts/endpoints.contract.ts +2 -1
- package/src/contracts/exit.contract.ts +2 -1
- package/src/contracts/extensions.contract.ts +8 -7
- package/src/contracts/git.contract.ts +19 -18
- package/src/contracts/grok.contract.ts +2 -1
- package/src/contracts/history.contract.ts +2 -1
- package/src/contracts/host.contract.ts +4 -1
- package/src/contracts/intentic.contract.ts +2 -1
- package/src/contracts/inventory.contract.ts +1 -1
- package/src/contracts/issues.contract.ts +60 -0
- package/src/contracts/logs.contract.ts +7 -1
- package/src/contracts/loops.contract.ts +2 -2
- package/src/contracts/panels.contract.ts +2 -1
- package/src/contracts/personas.contract.ts +3 -3
- package/src/contracts/ports.contract.ts +3 -2
- package/src/contracts/prepush.contract.ts +2 -1
- package/src/contracts/providers.contract.ts +2 -1
- package/src/contracts/public.contract.ts +3 -2
- package/src/contracts/push.contract.ts +2 -1
- package/src/contracts/runner.contract.ts +18 -2
- package/src/contracts/secrets.contract.ts +2 -1
- package/src/contracts/sessions.contract.ts +1 -1
- package/src/contracts/settings.contract.ts +3 -9
- package/src/contracts/share.contract.ts +3 -2
- package/src/contracts/skills.contract.ts +2 -1
- package/src/contracts/system.contract.ts +6 -9
- package/src/contracts/translator.contract.ts +4 -1
- package/src/contracts/usage.contract.ts +1 -1
- package/src/contracts/vpn.contract.ts +2 -8
- package/src/contracts/webext.contract.ts +37 -0
- package/src/contracts/workflows.contract.ts +2 -2
- package/src/contracts/workspace.contract.ts +10 -12
- package/src/conversation-ids.test.ts +1 -1
- package/src/credential-material.test.ts +120 -0
- package/src/credential-material.ts +100 -0
- package/src/definition-action.ts +8 -0
- package/src/definition.ts +74 -10
- package/src/events.ts +84 -22
- package/src/fast-tier.ts +1 -1
- package/src/history-state.ts +17 -0
- package/src/host-protocol.ts +1 -1
- package/src/hostnames.test.ts +2 -2
- package/src/hostnames.ts +18 -2
- package/src/index.ts +65 -1
- package/src/listener-protocol.ts +1 -1
- package/src/quick-model.ts +1 -1
- package/src/routes.test.ts +4 -2
- package/src/runner-protocol.ts +35 -5
- package/src/runtime-state.ts +16 -0
- package/src/schemas/activity.ts +123 -0
- package/src/schemas/agent.ts +422 -0
- package/src/schemas/agents.ts +802 -0
- package/src/schemas/automations.ts +522 -0
- package/src/schemas/capabilities.ts +729 -0
- package/src/schemas/ci.ts +235 -0
- package/src/schemas/claude-gate.ts +13 -0
- package/src/schemas/codebase-health.ts +64 -0
- package/src/schemas/computers.ts +287 -0
- package/src/schemas/drafts.ts +108 -0
- package/src/schemas/environment.ts +276 -0
- package/src/schemas/exit.ts +222 -0
- package/src/schemas/extension-updates.ts +324 -0
- package/src/schemas/fast-mode.ts +8 -0
- package/src/schemas/git-history.ts +265 -0
- package/src/schemas/git.ts +430 -0
- package/src/schemas/history.ts +112 -0
- package/src/schemas/hosts.ts +37 -0
- package/src/schemas/intentic.ts +2 -0
- package/src/schemas/internal.ts +17 -0
- package/src/schemas/inventory.ts +68 -0
- package/src/schemas/issues.ts +279 -0
- package/src/schemas/logs.ts +96 -0
- package/src/schemas/loops.ts +401 -0
- package/src/schemas/maintenance.ts +471 -0
- package/src/schemas/marketplace.ts +23 -0
- package/src/schemas/panels.ts +99 -0
- package/src/schemas/personas.ts +281 -0
- package/src/schemas/plan-limits.ts +255 -0
- package/src/schemas/ports.ts +84 -0
- package/src/schemas/provider-oauth.ts +191 -0
- package/src/schemas/provider-subscriptions.ts +11 -0
- package/src/schemas/public.ts +52 -0
- package/src/schemas/push.ts +112 -0
- package/src/schemas/secrets.ts +68 -0
- package/src/schemas/sessions.ts +16 -0
- package/src/schemas/settings.ts +964 -0
- package/src/schemas/share.ts +71 -0
- package/src/schemas/shared.ts +32 -0
- package/src/schemas/system.ts +156 -0
- package/src/schemas/terminal.ts +288 -0
- package/src/schemas/usage.ts +303 -0
- package/src/{schemas.test.ts → schemas/version-seam.test.ts} +4 -2
- package/src/schemas/vpn.ts +215 -0
- package/src/schemas/webext.ts +108 -0
- package/src/schemas/workflows.ts +413 -0
- package/src/schemas/workspace-repos.ts +123 -0
- package/src/schemas/workspace-search.ts +141 -0
- package/src/schemas/workspace-setup.ts +43 -0
- package/src/schemas/workspace-tree.ts +234 -0
- package/src/title.test.ts +1 -1
- package/src/tunnel-ids.test.ts +3 -1
- package/src/webext-links.ts +90 -0
- package/src/webext-protocol.ts +27 -0
- package/src/workflow-faults.test.ts +1 -1
- package/src/workflow-faults.ts +1 -1
- package/src/workspace-state.test.ts +6 -4
- package/src/workspace-state.ts +35 -50
- package/dist/schemas.d.ts +0 -9909
- package/dist/schemas.d.ts.map +0 -1
- package/dist/schemas.js +0 -4288
- package/dist/schemas.js.map +0 -1
- package/src/schemas.ts +0 -10090
|
@@ -179,6 +179,71 @@ describe(`jscpd`, () => {
|
|
|
179
179
|
});
|
|
180
180
|
});
|
|
181
181
|
|
|
182
|
+
/* The mutation report is the cross-tool "mutation testing report schema", and the whole risk in this parser is
|
|
183
|
+
* the arithmetic rather than the shape: two of the eight statuses land on the counter-intuitive side, and getting
|
|
184
|
+
* either one backwards produces a number that looks plausible and is wrong. So the statuses are tested by name. */
|
|
185
|
+
describe(`mutation`, () => {
|
|
186
|
+
const report = (...mutants: readonly Record<string, unknown>[]) =>
|
|
187
|
+
JSON.stringify({
|
|
188
|
+
schemaVersion: `2.0`,
|
|
189
|
+
files: { "src/digest.ts": { language: `typescript`, source: `…`, mutants } },
|
|
190
|
+
});
|
|
191
|
+
const mutant = (status: string, line = 1) => ({
|
|
192
|
+
id: `${status}-${line}`,
|
|
193
|
+
mutatorName: `ConditionalExpression`,
|
|
194
|
+
replacement: `false`,
|
|
195
|
+
location: { start: { line, column: 1 }, end: { line, column: 9 } },
|
|
196
|
+
status,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test(`counts Killed and Timeout as caught, Survived and NoCoverage as missed`, () => {
|
|
200
|
+
// Stryker's own arithmetic, restated as a test because both halves read backwards at a glance: a mutant
|
|
201
|
+
// that HANGS the suite was noticed by it, and a mutant nothing ran cannot have been.
|
|
202
|
+
const facts = parse(`mutation`, report(mutant(`Killed`), mutant(`Timeout`), mutant(`Survived`), mutant(`NoCoverage`)));
|
|
203
|
+
expect(facts).toMatchObject({ id: `mutation`, mutation: { killed: 2, survived: 2, score: 50 } });
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test(`leaves mutants that never got a verdict out of the score entirely`, () => {
|
|
207
|
+
// One caught, one missed, and three with no answer: the score is 50%, not 20% and not 80%. Folding the
|
|
208
|
+
// undecided into either column is the mistake this pins.
|
|
209
|
+
const facts = parse(`mutation`, report(mutant(`Killed`), mutant(`Survived`), mutant(`CompileError`), mutant(`RuntimeError`), mutant(`Ignored`)));
|
|
210
|
+
expect(facts).toMatchObject({ id: `mutation`, mutation: { killed: 1, survived: 1, inconclusive: 3, score: 50 } });
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test(`names each survivor with the change that went unnoticed`, () => {
|
|
214
|
+
const facts = parse(`mutation`, report(mutant(`Survived`, 43)));
|
|
215
|
+
expect(facts).toMatchObject({
|
|
216
|
+
mutation: { survivors: [{ file: `src/digest.ts`, line: 43, mutator: `ConditionalExpression`, replacement: `false` }] },
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// A mutator that DELETES an expression reports an empty replacement, which would otherwise render as a blank
|
|
221
|
+
// in the panel and read as a missing field rather than as the removal it is.
|
|
222
|
+
test(`renders a deleted expression as a removal rather than as nothing`, () => {
|
|
223
|
+
const facts = parse(`mutation`, report({ ...mutant(`Survived`), replacement: `` }));
|
|
224
|
+
expect(facts).toMatchObject({ mutation: { survivors: [{ replacement: `(removed)` }] } });
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test(`a run with nothing to mutate is 100%, not a division by zero`, () => {
|
|
228
|
+
expect(parse(`mutation`, JSON.stringify({ schemaVersion: `2.0`, files: {} }))).toMatchObject({
|
|
229
|
+
mutation: { score: 100, killed: 0, survived: 0 },
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// The distinction the runner depends on: an empty `files` map is a real measurement, a MISSING one is output
|
|
234
|
+
// this parser did not understand, and reporting the second as a clean 100% is the one answer it must never give.
|
|
235
|
+
test(`output without a files map is a failure, not a clean repository`, () => {
|
|
236
|
+
expect(parse(`mutation`, JSON.stringify({ schemaVersion: `2.0` }))).toBeUndefined();
|
|
237
|
+
expect(parse(`mutation`, ``)).toBeUndefined();
|
|
238
|
+
expect(parse(`mutation`, JSON.stringify({ files: [] }))).toBeUndefined();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test(`survives a malformed mutant without losing the rest of the file's numbers`, () => {
|
|
242
|
+
const facts = parse(`mutation`, report(mutant(`Killed`), { nonsense: true }, mutant(`Survived`)));
|
|
243
|
+
expect(facts).toMatchObject({ mutation: { killed: 1, survived: 1, inconclusive: 1 } });
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
182
247
|
/* The UI sweep is the one probe whose output we produce ourselves, which removes the "their JSON moved" failure
|
|
183
248
|
* and replaces it with a worse one: a command of eleven piped ripgreps in which any single stage can silently
|
|
184
249
|
* contribute nothing. The marker line is what tells those two apart, and most of what is below is about it. */
|
package/src/chores/probes.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Advisory, Bundle, DeadCode, Duplication, OutdatedPackage, ProbeFacts, ProbeId, UiScan } from "../schemas.js";
|
|
1
|
+
import type { Advisory, Bundle, DeadCode, Duplication, MutationScore, OutdatedPackage, ProbeFacts, ProbeId, UiScan } from "../schemas/maintenance.js";
|
|
2
2
|
import type { IdiomRule } from "./stack.js";
|
|
3
3
|
import {
|
|
4
4
|
BYPASS_PATTERN,
|
|
@@ -227,6 +227,103 @@ const parseJscpd = (stdout: string): ProbeFacts | undefined => {
|
|
|
227
227
|
return { id: `jscpd`, duplication };
|
|
228
228
|
};
|
|
229
229
|
|
|
230
|
+
/* WHAT THE SUITE WOULD NOTICE IF THE CODE BROKE, from Stryker's report.
|
|
231
|
+
*
|
|
232
|
+
* The report is the cross-tool "mutation testing report schema": `files` maps a path to `{ mutants: [{ mutatorName,
|
|
233
|
+
* replacement, location.start.line, status }] }`. Statuses are Killed, Survived, NoCoverage, Timeout, CompileError,
|
|
234
|
+
* RuntimeError, Ignored, Pending.
|
|
235
|
+
*
|
|
236
|
+
* THE ARITHMETIC IS STRYKER'S, NOT OURS, and that is a deliberate constraint rather than laziness. A timeout counts
|
|
237
|
+
* as DETECTED (a mutant that hangs the suite is one the suite noticed) and NoCoverage counts as UNDETECTED (nothing
|
|
238
|
+
* ran, so nothing could have caught it). Both are counter-intuitive enough to be worth restating here, and both are
|
|
239
|
+
* what the tool's own score means — a row that recomputed them differently would be quietly arguing with the
|
|
240
|
+
* evidence printed underneath it.
|
|
241
|
+
*
|
|
242
|
+
* `Pending` is treated as inconclusive rather than dropped: an interrupted incremental run leaves them, and
|
|
243
|
+
* counting them either way would move the score for a reason that has nothing to do with the tests. */
|
|
244
|
+
const SURVIVOR_SAMPLE = 8;
|
|
245
|
+
const DETECTED = new Set([`Killed`, `Timeout`]);
|
|
246
|
+
const UNDETECTED = new Set([`Survived`, `NoCoverage`]);
|
|
247
|
+
|
|
248
|
+
type Survivor = MutationScore["survivors"][number];
|
|
249
|
+
|
|
250
|
+
// One file's mutant list, or nothing. Every shape this cannot recognise reads as "no mutants here" rather than
|
|
251
|
+
// throwing: a report with one malformed entry is still worth the rest of its numbers.
|
|
252
|
+
const mutantsOf = (raw: unknown): readonly Record<string, unknown>[] => {
|
|
253
|
+
if (typeof raw !== `object` || raw === null) {
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
const mutants = (raw as Record<string, unknown>)[`mutants`];
|
|
257
|
+
return Array.isArray(mutants) ? mutants.filter((entry): entry is Record<string, unknown> => typeof entry === `object` && entry !== null) : [];
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const lineOf = (mutant: Record<string, unknown>): number => {
|
|
261
|
+
const location = mutant[`location`];
|
|
262
|
+
const start = typeof location === `object` && location !== null ? (location as Record<string, unknown>)[`start`] : undefined;
|
|
263
|
+
const line = typeof start === `object` && start !== null ? (start as Record<string, unknown>)[`line`] : undefined;
|
|
264
|
+
return typeof line === `number` ? line : 0;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const survivorOf = (file: string, mutant: Record<string, unknown>): Survivor => ({
|
|
268
|
+
file,
|
|
269
|
+
line: lineOf(mutant),
|
|
270
|
+
mutator: asString(mutant[`mutatorName`]) ?? `?`,
|
|
271
|
+
// An empty replacement is meaningful — the mutator deleted the expression — so it is rendered as the removal
|
|
272
|
+
// it is rather than left blank for a reader to puzzle over.
|
|
273
|
+
replacement: asString(mutant[`replacement`]) ?? `(removed)`,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
interface Tally {
|
|
277
|
+
killed: number;
|
|
278
|
+
survived: number;
|
|
279
|
+
inconclusive: number;
|
|
280
|
+
readonly survivors: Survivor[];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const tallyMutants = (files: Record<string, unknown>): Tally => {
|
|
284
|
+
const tally: Tally = { killed: 0, survived: 0, inconclusive: 0, survivors: [] };
|
|
285
|
+
for (const [file, raw] of Object.entries(files)) {
|
|
286
|
+
for (const mutant of mutantsOf(raw)) {
|
|
287
|
+
const status = asString(mutant[`status`]) ?? ``;
|
|
288
|
+
if (DETECTED.has(status)) {
|
|
289
|
+
tally.killed++;
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
// Anything that is neither detected nor undetected never got a verdict — it would not compile, or the
|
|
293
|
+
// configuration ignored it. Counting it either way would move the score for a reason that has nothing
|
|
294
|
+
// to do with the tests.
|
|
295
|
+
if (!UNDETECTED.has(status)) {
|
|
296
|
+
tally.inconclusive++;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
tally.survived++;
|
|
300
|
+
tally.survivors.push(survivorOf(file, mutant));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return tally;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const parseMutation = (stdout: string): ProbeFacts | undefined => {
|
|
307
|
+
const files = asObject(stdout)?.[`files`];
|
|
308
|
+
// No `files` key at all means this is not a mutation report. An EMPTY one is a real answer (nothing was
|
|
309
|
+
// mutated) and a missing one is a parse failure, and the runner has to be able to tell them apart.
|
|
310
|
+
if (typeof files !== `object` || files === null || Array.isArray(files)) {
|
|
311
|
+
return undefined;
|
|
312
|
+
}
|
|
313
|
+
const tally = tallyMutants(files as Record<string, unknown>);
|
|
314
|
+
const valid = tally.killed + tally.survived;
|
|
315
|
+
const mutation: MutationScore = {
|
|
316
|
+
// Nothing to mutate scores 100 rather than NaN: there is no undetected fault in it, which is the honest
|
|
317
|
+
// reading and the one that keeps the chore quiet instead of dividing by zero.
|
|
318
|
+
score: valid === 0 ? 100 : Math.round((tally.killed / valid) * 100),
|
|
319
|
+
killed: tally.killed,
|
|
320
|
+
survived: tally.survived,
|
|
321
|
+
inconclusive: tally.inconclusive,
|
|
322
|
+
survivors: tally.survivors.slice(0, SURVIVOR_SAMPLE),
|
|
323
|
+
};
|
|
324
|
+
return { id: `mutation`, mutation };
|
|
325
|
+
};
|
|
326
|
+
|
|
230
327
|
/* THE UI SWEEP. The only probe here whose command is COMPOSED rather than written out, because its subject is a
|
|
231
328
|
* table (stack.ts) that will grow and a hand-written command would be a second copy of it going stale.
|
|
232
329
|
*
|
|
@@ -370,6 +467,9 @@ const parseBundle = (stdout: string): ProbeFacts | undefined => {
|
|
|
370
467
|
// immediately after, never something to keep, the cached ProbeResult is the artefact that survives. The same
|
|
371
468
|
// path the scheduled form of this chore uses (chores.ts), so a workspace running both keeps one copy.
|
|
372
469
|
const JSCPD_DIR = `/tmp/intentic-chore-jscpd`;
|
|
470
|
+
// Where Stryker's json reporter writes, which is its own default and not configurable per run on the CLI. Read
|
|
471
|
+
// from the repo directory the probe runs in, like jscpd's report above.
|
|
472
|
+
const MUTATION_REPORT = `reports/mutation/mutation.json`;
|
|
373
473
|
|
|
374
474
|
export const PROBES: readonly ProbeSpec[] = [
|
|
375
475
|
{
|
|
@@ -430,6 +530,38 @@ export const PROBES: readonly ProbeSpec[] = [
|
|
|
430
530
|
`cat ${JSCPD_DIR}/jscpd-report.json 2>/dev/null`,
|
|
431
531
|
parse: parseJscpd,
|
|
432
532
|
},
|
|
533
|
+
{
|
|
534
|
+
id: `mutation`,
|
|
535
|
+
title: `Test strength`,
|
|
536
|
+
measures: `how much of the code could break with every test still green`,
|
|
537
|
+
/* THE MOST EXPENSIVE PROBE HERE, and the tier does not really capture it: this runs the suite once per
|
|
538
|
+
* injected fault. `--incremental` is what makes it liveable — Stryker keeps a result file and re-runs only
|
|
539
|
+
* the mutants whose code or tests changed, so the first run costs what a full run costs and every one
|
|
540
|
+
* after it costs the diff. The monthly TTL is set against the FIRST run, not the incremental ones.
|
|
541
|
+
*
|
|
542
|
+
* Opt-in per repository, by the presence of a `stryker.conf.json`, and that is the load-bearing part of
|
|
543
|
+
* the design rather than a convenience. This monorepo has 65 packages with their own vitest configs and no
|
|
544
|
+
* root suite; mutating all of them unasked would be hours of CPU nobody agreed to spend. A repo says which
|
|
545
|
+
* code is worth the measurement by writing that file, which is also where `mutate` narrows the scope. */
|
|
546
|
+
tier: 2,
|
|
547
|
+
ttlMs: 30 * DAY_MS,
|
|
548
|
+
timeoutMs: 90 * 60_000,
|
|
549
|
+
/* Two conditions, and the config is the one that matters: Stryker being installed says the tool COULD run,
|
|
550
|
+
* the config says somebody decided it should. Without the second this would report "unavailable" on every
|
|
551
|
+
* repo that merely shares this monorepo's lockfile.
|
|
552
|
+
*
|
|
553
|
+
* The repo's OWN Stryker, never a floating one, for a reason measured rather than assumed: under
|
|
554
|
+
* `pnpm dlx` the plugin loader resolves from the working directory and finds nothing — "Cannot find
|
|
555
|
+
* TestRunner plugin \"vitest\". In fact, no TestRunner plugins were loaded" — and the runner has to agree
|
|
556
|
+
* with the vitest the repo actually runs. Same argument as knip above. */
|
|
557
|
+
available: `{ test -f stryker.conf.mjs || test -f stryker.conf.json; } && pnpm exec stryker --version >/dev/null 2>&1`,
|
|
558
|
+
unavailable: `no stryker config in this repo`,
|
|
559
|
+
// `|| true` for the same reason the others carry it: Stryker exits non-zero when the score is under its
|
|
560
|
+
// own threshold, which is an opinion about the number, not a failure to produce one. The judgement is the
|
|
561
|
+
// chore's, made from the score, and the runner decides by whether the parser recognised the report.
|
|
562
|
+
command: `pnpm exec stryker run --reporters json --incremental >/dev/null 2>&1 || true; cat ${MUTATION_REPORT} 2>/dev/null`,
|
|
563
|
+
parse: parseMutation,
|
|
564
|
+
},
|
|
433
565
|
{
|
|
434
566
|
id: `ui`,
|
|
435
567
|
title: `Front-end source`,
|
package/src/chores/stack.test.ts
CHANGED
|
@@ -108,6 +108,25 @@ describe(`the name two components share`, () => {
|
|
|
108
108
|
expect(componentStem(`src/components/Button/index.tsx`)).toBeUndefined();
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
+
/* The same argument, for the names the framework hands out rather than the author. A monorepo has one root
|
|
112
|
+
* per app and a Next App Router has one `page` per route, so these families form by construction: the thirty
|
|
113
|
+
* `page.tsx` of a thirty-route app would sort above every real finding the chore has. */
|
|
114
|
+
test(`framework entry names never form a family`, () => {
|
|
115
|
+
expect(componentStem(`apps/web/src/App.vue`)).toBeUndefined();
|
|
116
|
+
expect(componentStem(`apps/desktop/src/App.vue`)).toBeUndefined();
|
|
117
|
+
expect(componentStem(`app/dashboard/page.tsx`)).toBeUndefined();
|
|
118
|
+
expect(componentStem(`app/settings/layout.tsx`)).toBeUndefined();
|
|
119
|
+
expect(componentStem(`app/settings/not-found.tsx`)).toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// …and only on the whole name. A component that merely BEGINS with one is the author's own and keeps its
|
|
123
|
+
// stem, or the guard above would swallow half the components in a repo that prefixes them.
|
|
124
|
+
test(`a component that only starts with a framework name is kept`, () => {
|
|
125
|
+
expect(componentStem(`src/shell/AppShell.vue`)).toBe(`appshell`);
|
|
126
|
+
expect(componentStem(`src/ErrorBoundary.tsx`)).toBe(`errorboundary`);
|
|
127
|
+
expect(componentStem(`src/PageHeader.vue`)).toBe(`pageheader`);
|
|
128
|
+
});
|
|
129
|
+
|
|
111
130
|
/* The trap in stripping a trailing number. `H1` and `H2` are different components and reduce to the same
|
|
112
131
|
* single letter, so the stem is only accepted when what survives is still long enough to mean something:
|
|
113
132
|
* otherwise the untouched name is kept and the two stay apart. */
|
package/src/chores/stack.ts
CHANGED
|
@@ -220,6 +220,19 @@ const MIN_STEM = 3;
|
|
|
220
220
|
const QUALIFIER_PREFIX = /^(base|the)/;
|
|
221
221
|
const QUALIFIER_SUFFIX = /(v[0-9]+|new|old|legacy|copy|component|[0-9]+)$/;
|
|
222
222
|
|
|
223
|
+
/* NAMES THE FRAMEWORK CHOSE, NOT THE AUTHOR, and therefore never evidence of anything.
|
|
224
|
+
*
|
|
225
|
+
* A repository gets one of these per app (`app`, `main`, `root`) or one per route directory (Next's App Router
|
|
226
|
+
* mandates `page`, `layout`, `loading`, `error`, `not-found`, `template`, `default`) BY CONSTRUCTION, so two files
|
|
227
|
+
* sharing one is a fact about the framework and not about duplication. A monorepo with two front-ends has two
|
|
228
|
+
* `App.vue`; a thirty-route Next app has thirty `page.tsx`, which sorts to the top of the families list and becomes
|
|
229
|
+
* the loudest thing the chore says while being entirely false.
|
|
230
|
+
*
|
|
231
|
+
* Same argument as `index` below, and the same disposal. Matched against the whole base name rather than as a
|
|
232
|
+
* prefix, so `AppShell.vue` and `ErrorBoundary.tsx` are ordinary components and keep their own stems: the only
|
|
233
|
+
* files dropped are the ones that could not have been built twice in the first place. */
|
|
234
|
+
const FRAMEWORK_NAMES = new Set([`index`, `app`, `main`, `root`, `page`, `layout`, `loading`, `error`, `template`, `default`, `notfound`]);
|
|
235
|
+
|
|
223
236
|
/* THE NAME TWO COMPONENTS SHARE WHEN THEY ARE THE SAME COMPONENT TWICE, or `undefined` when the file has no
|
|
224
237
|
* name worth comparing.
|
|
225
238
|
*
|
|
@@ -228,14 +241,17 @@ const QUALIFIER_SUFFIX = /(v[0-9]+|new|old|legacy|copy|component|[0-9]+)$/;
|
|
|
228
241
|
* component is making a claim anyone can agree or disagree with in a second. A fuzzy distance would be right more
|
|
229
242
|
* often and checkable never, and an unarguable finding is one nobody can improve.
|
|
230
243
|
*
|
|
231
|
-
* `index` is dropped rather than normalised
|
|
232
|
-
*
|
|
244
|
+
* `index` is dropped rather than normalised, along with the rest of the framework's own vocabulary
|
|
245
|
+
* (FRAMEWORK_NAMES). Every barrel file in the repository is called it, and a family of forty index files is a
|
|
246
|
+
* finding about the naming convention rather than about any duplication. */
|
|
233
247
|
export const componentStem = (path: string): string | undefined => {
|
|
234
248
|
const file = normalizePath(path).split(`/`).pop() ?? ``;
|
|
235
249
|
// `.component.ts` loses both suffixes, `.vue` loses one, taking everything before the first dot handles both
|
|
236
250
|
// without a table, since a component's name is never the part after a dot.
|
|
237
251
|
const base = (file.split(`.`)[0] ?? ``).toLowerCase().replace(/[^a-z0-9]/g, ``);
|
|
238
|
-
|
|
252
|
+
// Tested before the stripping below, so a framework name is dropped on its own terms rather than after a
|
|
253
|
+
// qualifier rule has had a chance to turn it into something else.
|
|
254
|
+
if (base === `` || FRAMEWORK_NAMES.has(base)) {
|
|
239
255
|
return undefined;
|
|
240
256
|
}
|
|
241
257
|
const withoutSuffix = base.replace(QUALIFIER_SUFFIX, ``);
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
Bundle,
|
|
3
|
+
ChoreLedgerEntry,
|
|
4
|
+
ChorePackage,
|
|
5
|
+
ChoreShape,
|
|
6
|
+
ChoreSignals,
|
|
7
|
+
ChoresReport,
|
|
8
|
+
Duplication,
|
|
9
|
+
ProbeResult,
|
|
10
|
+
UiScan,
|
|
11
|
+
} from "../schemas/maintenance.js";
|
|
2
12
|
import { describe, expect, test } from "vitest";
|
|
3
13
|
import { choreById, CHORES } from "./chores.js";
|
|
4
14
|
import { assessReport, ledgerKey, unseenVerdicts } from "./verdict.js";
|
|
@@ -75,20 +85,21 @@ describe(`what "we have not measured this" means`, () => {
|
|
|
75
85
|
test(`a chore whose probe never ran is unavailable, not clear`, () => {
|
|
76
86
|
const verdict = verdictFor(report(), `security-advisories`);
|
|
77
87
|
expect(verdict.state).toBe(`unavailable`);
|
|
78
|
-
expect(verdict.detail).
|
|
88
|
+
expect(verdict.detail.join(` `)).toContain(`Security advisories`);
|
|
79
89
|
});
|
|
80
90
|
|
|
81
91
|
// The distinction that stops the panel reporting a green repository it has never looked at. A tool the repo
|
|
82
92
|
// does not have is not evidence of anything, and it carries the tool's own reason rather than an invented one.
|
|
83
93
|
test(`a probe the repository cannot run says so, and never badges`, () => {
|
|
94
|
+
const knipReason = `knip is not a devDependency`;
|
|
84
95
|
const input = report({
|
|
85
96
|
repos: [
|
|
86
|
-
{ repo: `app`, probes: [probe({ id: `knip`, state: `unavailable`, reason:
|
|
97
|
+
{ repo: `app`, probes: [probe({ id: `knip`, state: `unavailable`, reason: knipReason })], signals: signals() },
|
|
87
98
|
],
|
|
88
99
|
});
|
|
89
100
|
const verdict = verdictFor(input, `dead-code`);
|
|
90
101
|
expect(verdict.state).toBe(`unavailable`);
|
|
91
|
-
expect(verdict.detail[0]).toContain(
|
|
102
|
+
expect(verdict.detail[0]).toContain(knipReason);
|
|
92
103
|
expect(unseenVerdicts([verdict], {})).toEqual([]);
|
|
93
104
|
});
|
|
94
105
|
|
|
@@ -132,9 +143,10 @@ describe(`the ledger debounces; it cannot hide`, () => {
|
|
|
132
143
|
});
|
|
133
144
|
|
|
134
145
|
test(`an agent reporting the findings did not hold up clears the chore until the evidence changes`, () => {
|
|
146
|
+
const due = verdictFor(withAdvisories, `security-advisories`);
|
|
135
147
|
const verdict = verdictFor({ ...withAdvisories, ledger: [ledgerEntry({ outcome: `clean` })] }, `security-advisories`);
|
|
136
148
|
expect(verdict.state).toBe(`clear`);
|
|
137
|
-
expect(verdict.headline).toBe(
|
|
149
|
+
expect(verdict.headline).not.toBe(due.headline);
|
|
138
150
|
});
|
|
139
151
|
|
|
140
152
|
test(`a snooze silences a due chore without hiding it, and lapses on its own`, () => {
|
|
@@ -245,9 +257,10 @@ describe(`surveys are due because time passed, and say so`, () => {
|
|
|
245
257
|
});
|
|
246
258
|
|
|
247
259
|
test(`run inside the period is clear, and reports when it was read rather than claiming nothing to do`, () => {
|
|
248
|
-
const
|
|
260
|
+
const daysAgo = 10;
|
|
261
|
+
const verdict = verdictFor({ ...report(), ledger: [surveyLedger(NOW - daysAgo * DAY)] }, `standardize-patterns`);
|
|
249
262
|
expect(verdict.state).toBe(`clear`);
|
|
250
|
-
expect(verdict.headline).
|
|
263
|
+
expect(verdict.headline).toContain(String(daysAgo));
|
|
251
264
|
});
|
|
252
265
|
|
|
253
266
|
test(`run longer ago than the cadence is due again`, () => {
|
|
@@ -372,9 +385,11 @@ describe(`the prompts`, () => {
|
|
|
372
385
|
});
|
|
373
386
|
|
|
374
387
|
test(`tell an acting chore to keep the diff reviewable and a reporting chore not to edit at all`, () => {
|
|
375
|
-
|
|
388
|
+
const acting = dueVerdict().prompt ?? ``;
|
|
376
389
|
const survey = verdictFor(report(), `standardize-patterns`);
|
|
377
|
-
expect(
|
|
390
|
+
expect(acting).toContain(`left-pad`);
|
|
391
|
+
expect(acting).not.toBe(survey.prompt);
|
|
392
|
+
expect(survey.prompt).not.toBe(acting);
|
|
378
393
|
});
|
|
379
394
|
|
|
380
395
|
test(`every chore that can be due can produce a prompt`, () => {
|
|
@@ -443,7 +458,7 @@ describe(`what does not apply here`, () => {
|
|
|
443
458
|
test(`a repository with no documents is not asked to re-read its documentation`, () => {
|
|
444
459
|
const verdict = verdictFor(withShape({ docs: [] }), `documentation-drift`);
|
|
445
460
|
expect(verdict.state).toBe(`not-applicable`);
|
|
446
|
-
expect(verdict.headline).
|
|
461
|
+
expect(verdict.headline).toContain(`document`);
|
|
447
462
|
expect(verdict.prompt).toBeUndefined();
|
|
448
463
|
});
|
|
449
464
|
|
|
@@ -472,12 +487,13 @@ describe(`what does not apply here`, () => {
|
|
|
472
487
|
// fires forever in repositories where its subject does not exist. This is the regression that motivated
|
|
473
488
|
// making `applies` a required field on SurveySpec rather than an optional one.
|
|
474
489
|
test(`a tiny repository is not surveyed for cross-cutting patterns it cannot have`, () => {
|
|
490
|
+
const fileCount = 4;
|
|
475
491
|
const tiny = report({
|
|
476
|
-
repos: [{ repo: `app`, probes: [], signals: signals({ totals: { files:
|
|
492
|
+
repos: [{ repo: `app`, probes: [], signals: signals({ totals: { files: fileCount, symbols: 10, complexity: 5, hotspots: 0 } }) }],
|
|
477
493
|
});
|
|
478
494
|
const verdict = verdictFor(tiny, `standardize-patterns`);
|
|
479
495
|
expect(verdict.state).toBe(`not-applicable`);
|
|
480
|
-
expect(verdict.headline).
|
|
496
|
+
expect(verdict.headline).toContain(String(fileCount));
|
|
481
497
|
});
|
|
482
498
|
|
|
483
499
|
test(`applicability is decided before measurement, so a missing probe never masks it`, () => {
|
|
@@ -598,7 +614,9 @@ describe(`idioms the framework has replaced`, () => {
|
|
|
598
614
|
test(`names what is still in use and what replaced it`, () => {
|
|
599
615
|
const verdict = verdictFor(withProbes([uiProbe({ idioms: [idioms(`vue-options-api`, 3)] })]), `framework-idiom`);
|
|
600
616
|
expect(verdict.state).toBe(`due`);
|
|
601
|
-
expect(verdict.detail).
|
|
617
|
+
expect(verdict.detail[0]).toContain(`3 files`);
|
|
618
|
+
expect(verdict.detail[0]).toContain(`Options API`);
|
|
619
|
+
expect(verdict.detail[0]).toContain(`script setup`);
|
|
602
620
|
});
|
|
603
621
|
|
|
604
622
|
/* A migration in progress is a set that changes on every commit, so digesting the file identities, which is
|
|
@@ -642,8 +660,9 @@ describe(`components built twice`, () => {
|
|
|
642
660
|
`component-overlap`,
|
|
643
661
|
);
|
|
644
662
|
expect(verdict.state).toBe(`due`);
|
|
645
|
-
expect(verdict.headline).
|
|
646
|
-
expect(verdict.detail).
|
|
663
|
+
expect(verdict.headline).toContain(`1 name`);
|
|
664
|
+
expect(verdict.detail[0]).toContain(`button`);
|
|
665
|
+
expect(verdict.detail[0]).toContain(`ButtonV2.tsx`);
|
|
647
666
|
});
|
|
648
667
|
|
|
649
668
|
test(`components that merely coexist are not a finding`, () => {
|
|
@@ -663,7 +682,7 @@ describe(`components built twice`, () => {
|
|
|
663
682
|
`component-overlap`,
|
|
664
683
|
);
|
|
665
684
|
expect(shared.state).toBe(`due`);
|
|
666
|
-
expect(shared.headline).
|
|
685
|
+
expect(shared.headline).toContain(`clone`);
|
|
667
686
|
expect(oneSided.state).toBe(`clear`);
|
|
668
687
|
});
|
|
669
688
|
|
|
@@ -688,8 +707,10 @@ describe(`hard-coded styles`, () => {
|
|
|
688
707
|
`tailwind-arbitrary-values`,
|
|
689
708
|
);
|
|
690
709
|
expect(verdict.state).toBe(`due`);
|
|
691
|
-
expect(verdict.headline).
|
|
692
|
-
expect(verdict.
|
|
710
|
+
expect(verdict.headline).toContain(`13`);
|
|
711
|
+
expect(verdict.headline).toContain(`2 files`);
|
|
712
|
+
expect(verdict.detail[0]).toContain(`Checkout.vue`);
|
|
713
|
+
expect(verdict.detail[0]).toContain(`11`);
|
|
693
714
|
});
|
|
694
715
|
|
|
695
716
|
// Tailwind gates this one alone: a Vue repository with no Tailwind has no theme scale to have bypassed, and
|
|
@@ -700,7 +721,7 @@ describe(`hard-coded styles`, () => {
|
|
|
700
721
|
`tailwind-arbitrary-values`,
|
|
701
722
|
);
|
|
702
723
|
expect(verdict.state).toBe(`not-applicable`);
|
|
703
|
-
expect(verdict.headline).
|
|
724
|
+
expect(verdict.headline).toContain(`Tailwind`);
|
|
704
725
|
});
|
|
705
726
|
|
|
706
727
|
// And the framework gate the other four share, from the other side: deps come from shape, not from packages,
|
|
@@ -726,7 +747,6 @@ describe(`every chore says what would make it due`, () => {
|
|
|
726
747
|
|
|
727
748
|
test(`the criterion reaches the prompt, so the agent can tell us the rule was wrong`, () => {
|
|
728
749
|
const due = verdictFor(report({ repos: [{ repo: `app`, probes: [auditProbe([`left-pad`])], signals: signals() }] }), `security-advisories`);
|
|
729
|
-
expect(due.prompt).toContain(`You were woken because:`);
|
|
730
750
|
expect(due.prompt).toContain(due.chore.criterion);
|
|
731
751
|
});
|
|
732
752
|
});
|
package/src/chores/verdict.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChoreLedgerEntry, ChoresReport, ProbeId, ProbeResult } from "../schemas.js";
|
|
1
|
+
import type { ChoreLedgerEntry, ChoresReport, ProbeId, ProbeResult } from "../schemas/maintenance.js";
|
|
2
2
|
import { type Chore, type ChoreContext, type ChoreFinding, CHORES, chorePrompt } from "./chores.js";
|
|
3
3
|
import { probeSpec } from "./probes.js";
|
|
4
4
|
|