@intentic/sandbox-contract 1.248.0 → 1.249.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 +18 -15
- package/dist/chores/chores.d.ts.map +1 -1
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/digest.d.ts.map +1 -1
- package/dist/chores/digest.js.map +1 -1
- package/dist/chores/extension-update.d.ts.map +1 -1
- package/dist/chores/extension-update.js.map +1 -1
- package/dist/chores/fix-deps.d.ts.map +1 -1
- package/dist/chores/fix-deps.js.map +1 -1
- package/dist/chores/index.d.ts +2 -2
- package/dist/chores/index.d.ts.map +1 -1
- package/dist/chores/index.js +1 -1
- package/dist/chores/index.js.map +1 -1
- package/dist/chores/probes.d.ts.map +1 -1
- package/dist/chores/probes.js.map +1 -1
- package/dist/chores/prompt.d.ts.map +1 -1
- package/dist/chores/prompt.js.map +1 -1
- package/dist/chores/stack.d.ts.map +1 -1
- package/dist/chores/stack.js.map +1 -1
- package/dist/chores/verdict.d.ts +7 -1
- package/dist/chores/verdict.d.ts.map +1 -1
- package/dist/chores/verdict.js +8 -0
- package/dist/chores/verdict.js.map +1 -1
- package/dist/contracts/accounts.contract.d.ts.map +1 -1
- package/dist/contracts/accounts.contract.js.map +1 -1
- package/dist/contracts/activity.contract.d.ts +1 -0
- package/dist/contracts/activity.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.d.ts +12 -205
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +2 -1
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +228 -54
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +11 -2
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/automations.contract.d.ts +35 -17
- package/dist/contracts/automations.contract.d.ts.map +1 -1
- package/dist/contracts/automations.contract.js +10 -1
- package/dist/contracts/automations.contract.js.map +1 -1
- package/dist/contracts/capabilities.contract.d.ts +0 -12
- package/dist/contracts/capabilities.contract.d.ts.map +1 -1
- package/dist/contracts/capabilities.contract.js +1 -1
- package/dist/contracts/capabilities.contract.js.map +1 -1
- package/dist/contracts/chores.contract.d.ts.map +1 -1
- package/dist/contracts/chores.contract.js.map +1 -1
- package/dist/contracts/ci.contract.d.ts +9 -0
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts.map +1 -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 +1 -1
- package/dist/contracts/exit.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.js.map +1 -1
- package/dist/contracts/git.contract.d.ts +45 -6
- package/dist/contracts/git.contract.d.ts.map +1 -1
- package/dist/contracts/git.contract.js +9 -9
- package/dist/contracts/git.contract.js.map +1 -1
- package/dist/contracts/host.contract.d.ts +2 -0
- package/dist/contracts/host.contract.d.ts.map +1 -1
- package/dist/contracts/host.contract.js.map +1 -1
- package/dist/contracts/intentic.contract.js +1 -1
- package/dist/contracts/intentic.contract.js.map +1 -1
- package/dist/contracts/logs.contract.d.ts.map +1 -1
- package/dist/contracts/logs.contract.js.map +1 -1
- package/dist/contracts/loops.contract.d.ts.map +1 -1
- package/dist/contracts/loops.contract.js.map +1 -1
- package/dist/contracts/personas.contract.d.ts +1 -0
- package/dist/contracts/personas.contract.d.ts.map +1 -1
- package/dist/contracts/personas.contract.js +1 -1
- package/dist/contracts/personas.contract.js.map +1 -1
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/providers.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +97 -171
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.js +2 -2
- package/dist/contracts/runner.contract.js.map +1 -1
- package/dist/contracts/safety.contract.d.ts.map +1 -1
- package/dist/contracts/safety.contract.js +1 -1
- package/dist/contracts/safety.contract.js.map +1 -1
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +2 -41
- package/dist/contracts/sessions.contract.d.ts.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 +8 -18
- package/dist/contracts/settings.contract.d.ts.map +1 -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.map +1 -1
- package/dist/contracts/skills.contract.d.ts.map +1 -1
- package/dist/contracts/skills.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts +49 -73
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +12 -2
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/contracts/usage.contract.d.ts.map +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 +1 -1
- package/dist/contracts/vpn.contract.js.map +1 -1
- package/dist/contracts/webext.contract.d.ts.map +1 -1
- package/dist/contracts/webext.contract.js.map +1 -1
- package/dist/contracts/workflows.contract.d.ts +7 -6
- package/dist/contracts/workflows.contract.d.ts.map +1 -1
- package/dist/contracts/workflows.contract.js +12 -3
- package/dist/contracts/workflows.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/events/agent-events.d.ts +1237 -0
- package/dist/events/agent-events.d.ts.map +1 -0
- package/dist/events/agent-events.js +226 -0
- package/dist/events/agent-events.js.map +1 -0
- package/dist/events/cards.d.ts +404 -0
- package/dist/events/cards.d.ts.map +1 -0
- package/dist/events/cards.js +179 -0
- package/dist/events/cards.js.map +1 -0
- package/dist/events/resume.d.ts +23 -0
- package/dist/events/resume.d.ts.map +1 -0
- package/dist/events/resume.js +31 -0
- package/dist/events/resume.js.map +1 -0
- package/dist/events/system-events.d.ts +615 -0
- package/dist/events/system-events.d.ts.map +1 -0
- package/dist/events/system-events.js +64 -0
- package/dist/events/system-events.js.map +1 -0
- package/dist/events/transcript.d.ts +1755 -0
- package/dist/events/transcript.d.ts.map +1 -0
- package/dist/events/transcript.js +205 -0
- package/dist/events/transcript.js.map +1 -0
- package/dist/ids/conversation-ids.d.ts +8 -0
- package/dist/ids/conversation-ids.d.ts.map +1 -0
- package/dist/{conversation-ids.js → ids/conversation-ids.js} +13 -0
- package/dist/ids/conversation-ids.js.map +1 -0
- package/dist/ids/hostnames.d.ts.map +1 -0
- package/dist/ids/hostnames.js.map +1 -0
- package/dist/ids/session-names.d.ts.map +1 -0
- package/dist/ids/session-names.js.map +1 -0
- package/dist/ids/share-paths.d.ts.map +1 -0
- package/dist/ids/share-paths.js.map +1 -0
- package/dist/{tunnel-ids.d.ts → ids/tunnel-ids.d.ts} +1 -0
- package/dist/ids/tunnel-ids.d.ts.map +1 -0
- package/dist/{tunnel-ids.js → ids/tunnel-ids.js} +1 -0
- package/dist/ids/tunnel-ids.js.map +1 -0
- package/dist/index.d.ts +423 -450
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -46
- package/dist/index.js.map +1 -1
- package/dist/{agent-catalog.d.ts → models/agent-catalog.d.ts} +2 -2
- package/dist/models/agent-catalog.d.ts.map +1 -0
- package/dist/models/agent-catalog.js.map +1 -0
- package/dist/models/agent-runtimes.d.ts.map +1 -0
- package/dist/models/agent-runtimes.js.map +1 -0
- package/dist/{fast-tier.d.ts → models/fast-tier.d.ts} +1 -1
- package/dist/models/fast-tier.d.ts.map +1 -0
- package/dist/models/fast-tier.js.map +1 -0
- package/dist/models/model-order.d.ts.map +1 -0
- package/dist/models/model-order.js.map +1 -0
- package/dist/{model-pins.d.ts → models/model-pins.d.ts} +1 -1
- package/dist/models/model-pins.d.ts.map +1 -0
- package/dist/models/model-pins.js.map +1 -0
- package/dist/{model-roles.d.ts → models/model-roles.d.ts} +0 -33
- package/dist/models/model-roles.d.ts.map +1 -0
- package/dist/{model-roles.js → models/model-roles.js} +0 -35
- package/dist/models/model-roles.js.map +1 -0
- package/dist/{plan-pools.d.ts → models/plan-pools.d.ts} +1 -1
- package/dist/models/plan-pools.d.ts.map +1 -0
- package/dist/models/plan-pools.js.map +1 -0
- package/dist/models/prompt-complexity.d.ts.map +1 -0
- package/dist/models/prompt-complexity.js.map +1 -0
- package/dist/models/provider-specs.d.ts.map +1 -0
- package/dist/models/provider-specs.js.map +1 -0
- package/dist/policy/approvals-execution.d.ts.map +1 -0
- package/dist/policy/approvals-execution.js.map +1 -0
- package/dist/{batch-runs.d.ts → policy/batch-runs.d.ts} +5 -1
- package/dist/policy/batch-runs.d.ts.map +1 -0
- package/dist/{batch-runs.js → policy/batch-runs.js} +10 -7
- package/dist/policy/batch-runs.js.map +1 -0
- package/dist/policy/capability-env.d.ts.map +1 -0
- package/dist/policy/capability-env.js.map +1 -0
- package/dist/policy/capability-secrets.d.ts.map +1 -0
- package/dist/policy/capability-secrets.js.map +1 -0
- package/dist/{card-status.d.ts → policy/card-status.d.ts} +2 -2
- package/dist/policy/card-status.d.ts.map +1 -0
- package/dist/{card-status.js → policy/card-status.js} +1 -5
- package/dist/policy/card-status.js.map +1 -0
- package/dist/{command-classes.d.ts → policy/command-classes.d.ts} +6 -2
- package/dist/policy/command-classes.d.ts.map +1 -0
- package/dist/{command-classes.js → policy/command-classes.js} +48 -11
- package/dist/policy/command-classes.js.map +1 -0
- package/dist/{command-run.d.ts → policy/command-run.d.ts} +1 -1
- package/dist/policy/command-run.d.ts.map +1 -0
- package/dist/policy/command-run.js.map +1 -0
- package/dist/policy/control-scopes.d.ts +16 -0
- package/dist/policy/control-scopes.d.ts.map +1 -0
- package/dist/policy/control-scopes.js +26 -0
- package/dist/policy/control-scopes.js.map +1 -0
- package/dist/policy/credential-material.d.ts.map +1 -0
- package/dist/policy/credential-material.js.map +1 -0
- package/dist/policy/needs-action.d.ts.map +1 -0
- package/dist/policy/needs-action.js.map +1 -0
- package/dist/policy/output-fields.d.ts.map +1 -0
- package/dist/policy/output-fields.js.map +1 -0
- package/dist/policy/overlay-lint.d.ts.map +1 -0
- package/dist/policy/overlay-lint.js.map +1 -0
- package/dist/policy/owner-ticket.d.ts.map +1 -0
- package/dist/{owner-ticket.js → policy/owner-ticket.js} +1 -1
- package/dist/policy/owner-ticket.js.map +1 -0
- package/dist/{safety-policy.d.ts → policy/safety-policy.d.ts} +6 -5
- package/dist/policy/safety-policy.d.ts.map +1 -0
- package/dist/{safety-policy.js → policy/safety-policy.js} +12 -12
- package/dist/policy/safety-policy.js.map +1 -0
- package/dist/policy/search-globs.d.ts.map +1 -0
- package/dist/policy/search-globs.js.map +1 -0
- package/dist/protocol/container-requirements.d.ts +20 -0
- package/dist/protocol/container-requirements.d.ts.map +1 -0
- package/dist/protocol/container-requirements.js +23 -0
- package/dist/protocol/container-requirements.js.map +1 -0
- package/dist/{host-protocol.d.ts → protocol/host-protocol.d.ts} +1 -0
- package/dist/protocol/host-protocol.d.ts.map +1 -0
- package/dist/{host-protocol.js → protocol/host-protocol.js} +1 -0
- package/dist/protocol/host-protocol.js.map +1 -0
- package/dist/protocol/ingress-contract.d.ts.map +1 -0
- package/dist/{ingress-contract.js → protocol/ingress-contract.js} +1 -1
- package/dist/protocol/ingress-contract.js.map +1 -0
- package/dist/protocol/ingress-protocol.d.ts.map +1 -0
- package/dist/protocol/ingress-protocol.js.map +1 -0
- package/dist/protocol/listener-protocol.d.ts.map +1 -0
- package/dist/{listener-protocol.js → protocol/listener-protocol.js} +1 -1
- package/dist/protocol/listener-protocol.js.map +1 -0
- package/dist/{peer-dial.d.ts → protocol/peer-dial.d.ts} +4 -1
- package/dist/protocol/peer-dial.d.ts.map +1 -0
- package/dist/{peer-dial.js → protocol/peer-dial.js} +51 -10
- package/dist/protocol/peer-dial.js.map +1 -0
- package/dist/protocol/peer-mcp-server.d.ts.map +1 -0
- package/dist/protocol/peer-mcp-server.js.map +1 -0
- package/dist/protocol/request-id.d.ts.map +1 -0
- package/dist/protocol/request-id.js.map +1 -0
- package/dist/protocol/routes.d.ts.map +1 -0
- package/dist/protocol/routes.js.map +1 -0
- package/dist/{runner-protocol.d.ts → protocol/runner-protocol.d.ts} +1 -0
- package/dist/protocol/runner-protocol.d.ts.map +1 -0
- package/dist/{runner-protocol.js → protocol/runner-protocol.js} +2 -1
- package/dist/protocol/runner-protocol.js.map +1 -0
- package/dist/protocol/sse.d.ts.map +1 -0
- package/dist/protocol/sse.js.map +1 -0
- package/dist/{terminal-protocol.d.ts → protocol/terminal-protocol.d.ts} +1 -3
- package/dist/protocol/terminal-protocol.d.ts.map +1 -0
- package/dist/protocol/terminal-protocol.js.map +1 -0
- package/dist/protocol/webext-links.d.ts.map +1 -0
- package/dist/protocol/webext-links.js.map +1 -0
- package/dist/{webext-protocol.d.ts → protocol/webext-protocol.d.ts} +1 -0
- package/dist/protocol/webext-protocol.d.ts.map +1 -0
- package/dist/{webext-protocol.js → protocol/webext-protocol.js} +1 -0
- package/dist/protocol/webext-protocol.js.map +1 -0
- package/dist/schemas/activity.d.ts +2 -0
- package/dist/schemas/activity.d.ts.map +1 -1
- package/dist/schemas/activity.js +4 -0
- package/dist/schemas/activity.js.map +1 -1
- package/dist/schemas/agent.d.ts +16 -4
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +21 -4
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +17 -4
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +15 -4
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/approvals.d.ts.map +1 -1
- package/dist/schemas/approvals.js.map +1 -1
- package/dist/schemas/automations.d.ts +54 -28
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/automations.js +26 -8
- package/dist/schemas/automations.js.map +1 -1
- package/dist/schemas/capabilities.d.ts +0 -8
- package/dist/schemas/capabilities.d.ts.map +1 -1
- package/dist/schemas/capabilities.js +0 -4
- package/dist/schemas/capabilities.js.map +1 -1
- package/dist/schemas/ci.d.ts +10 -0
- package/dist/schemas/ci.d.ts.map +1 -1
- package/dist/schemas/ci.js +9 -1
- package/dist/schemas/ci.js.map +1 -1
- package/dist/schemas/codebase-health.d.ts.map +1 -1
- package/dist/schemas/codebase-health.js.map +1 -1
- package/dist/schemas/devices.d.ts +90 -0
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +10 -1
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/engines.d.ts.map +1 -1
- package/dist/schemas/engines.js.map +1 -1
- package/dist/schemas/environment.d.ts.map +1 -1
- package/dist/schemas/environment.js.map +1 -1
- package/dist/schemas/exit.d.ts.map +1 -1
- package/dist/schemas/exit.js.map +1 -1
- package/dist/schemas/extension-updates.d.ts.map +1 -1
- package/dist/schemas/extension-updates.js.map +1 -1
- package/dist/schemas/git-history.d.ts.map +1 -1
- package/dist/schemas/git-history.js.map +1 -1
- package/dist/schemas/git.d.ts +80 -16
- package/dist/schemas/git.d.ts.map +1 -1
- package/dist/schemas/git.js +37 -25
- package/dist/schemas/git.js.map +1 -1
- package/dist/schemas/history.d.ts.map +1 -1
- package/dist/schemas/history.js.map +1 -1
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/inventory.d.ts.map +1 -1
- package/dist/schemas/inventory.js.map +1 -1
- package/dist/schemas/issues.d.ts +0 -1
- package/dist/schemas/issues.d.ts.map +1 -1
- package/dist/schemas/issues.js +0 -1
- package/dist/schemas/issues.js.map +1 -1
- package/dist/schemas/logs.d.ts.map +1 -1
- package/dist/schemas/logs.js.map +1 -1
- package/dist/schemas/loops.d.ts.map +1 -1
- package/dist/schemas/loops.js +1 -1
- package/dist/schemas/loops.js.map +1 -1
- package/dist/schemas/maintenance.d.ts.map +1 -1
- package/dist/schemas/maintenance.js.map +1 -1
- package/dist/schemas/marketplace.d.ts +0 -4
- package/dist/schemas/marketplace.d.ts.map +1 -1
- package/dist/schemas/panels.d.ts.map +1 -1
- package/dist/schemas/panels.js.map +1 -1
- package/dist/schemas/personas.d.ts +2 -1
- package/dist/schemas/personas.d.ts.map +1 -1
- package/dist/schemas/personas.js +6 -2
- package/dist/schemas/personas.js.map +1 -1
- package/dist/schemas/plan-limits.d.ts +2 -4
- package/dist/schemas/plan-limits.d.ts.map +1 -1
- package/dist/schemas/plan-limits.js +5 -8
- package/dist/schemas/plan-limits.js.map +1 -1
- package/dist/schemas/ports.d.ts.map +1 -1
- package/dist/schemas/ports.js.map +1 -1
- package/dist/schemas/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/provider-oauth.js.map +1 -1
- package/dist/schemas/provider-subscriptions.d.ts +1 -1
- package/dist/schemas/provider-subscriptions.d.ts.map +1 -1
- package/dist/schemas/provider-subscriptions.js +1 -1
- package/dist/schemas/provider-subscriptions.js.map +1 -1
- package/dist/schemas/public.d.ts.map +1 -1
- package/dist/schemas/public.js.map +1 -1
- package/dist/schemas/push.d.ts.map +1 -1
- package/dist/schemas/push.js.map +1 -1
- package/dist/schemas/secrets.d.ts.map +1 -1
- package/dist/schemas/secrets.js.map +1 -1
- package/dist/schemas/settings.d.ts +6 -9
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +16 -5
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/share.d.ts.map +1 -1
- package/dist/schemas/share.js.map +1 -1
- package/dist/schemas/shared.d.ts +4 -0
- package/dist/schemas/shared.d.ts.map +1 -1
- package/dist/schemas/shared.js +3 -0
- package/dist/schemas/shared.js.map +1 -1
- package/dist/schemas/system.d.ts +6 -0
- package/dist/schemas/system.d.ts.map +1 -1
- package/dist/schemas/system.js +10 -0
- package/dist/schemas/system.js.map +1 -1
- package/dist/schemas/terminal.d.ts.map +1 -1
- package/dist/schemas/terminal.js.map +1 -1
- package/dist/schemas/usage.d.ts.map +1 -1
- package/dist/schemas/usage.js.map +1 -1
- package/dist/schemas/vpn.d.ts.map +1 -1
- package/dist/schemas/vpn.js.map +1 -1
- package/dist/schemas/webext.d.ts.map +1 -1
- package/dist/schemas/webext.js.map +1 -1
- package/dist/schemas/workflows.d.ts +66 -9
- package/dist/schemas/workflows.d.ts.map +1 -1
- package/dist/schemas/workflows.js +6 -5
- package/dist/schemas/workflows.js.map +1 -1
- package/dist/schemas/workspace-repos.d.ts.map +1 -1
- package/dist/schemas/workspace-repos.js.map +1 -1
- package/dist/schemas/workspace-search.d.ts.map +1 -1
- package/dist/schemas/workspace-search.js.map +1 -1
- package/dist/schemas/workspace-setup.d.ts.map +1 -1
- package/dist/schemas/workspace-setup.js.map +1 -1
- package/dist/schemas/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace-tree.js.map +1 -1
- package/dist/state/arrival.d.ts.map +1 -0
- package/dist/{arrival.js → state/arrival.js} +1 -1
- package/dist/state/arrival.js.map +1 -0
- package/dist/state/contract-lock.d.ts.map +1 -0
- package/dist/{contract-lock.js → state/contract-lock.js} +1 -1
- package/dist/state/contract-lock.js.map +1 -0
- package/dist/{definition.d.ts → state/definition.d.ts} +21 -17
- package/dist/state/definition.d.ts.map +1 -0
- package/dist/{definition.js → state/definition.js} +4 -4
- package/dist/state/definition.js.map +1 -0
- package/dist/state/history-state.d.ts.map +1 -0
- package/dist/{history-state.js → state/history-state.js} +1 -0
- package/dist/state/history-state.js.map +1 -0
- package/dist/state/runtime-state.d.ts.map +1 -0
- package/dist/state/runtime-state.js.map +1 -0
- package/dist/state/starter.d.ts.map +1 -0
- package/dist/state/starter.js.map +1 -0
- package/dist/state/state-portability.d.ts.map +1 -0
- package/dist/state/state-portability.js.map +1 -0
- package/dist/state/versions.d.ts.map +1 -0
- package/dist/state/versions.js.map +1 -0
- package/dist/{workspace-state.d.ts → state/workspace-state.d.ts} +8 -0
- package/dist/state/workspace-state.d.ts.map +1 -0
- package/dist/{workspace-state.js → state/workspace-state.js} +25 -0
- package/dist/state/workspace-state.js.map +1 -0
- package/dist/{documents.d.ts → text/documents.d.ts} +1 -1
- package/dist/text/documents.d.ts.map +1 -0
- package/dist/{documents.js → text/documents.js} +1 -1
- package/dist/text/documents.js.map +1 -0
- package/dist/text/embed.d.ts.map +1 -0
- package/dist/text/embed.js.map +1 -0
- package/dist/text/mentions.d.ts.map +1 -0
- package/dist/text/mentions.js.map +1 -0
- package/dist/text/model-answer.d.ts +3 -0
- package/dist/text/model-answer.d.ts.map +1 -0
- package/dist/text/model-answer.js +3 -0
- package/dist/text/model-answer.js.map +1 -0
- package/dist/text/path-refs.d.ts.map +1 -0
- package/dist/text/path-refs.js.map +1 -0
- package/dist/{shell-regions.d.ts → text/shell-regions.d.ts} +1 -1
- package/dist/text/shell-regions.d.ts.map +1 -0
- package/dist/text/shell-regions.js.map +1 -0
- package/dist/text/title.d.ts.map +1 -0
- package/dist/text/title.js.map +1 -0
- package/dist/{transcript-fold.d.ts → text/transcript-fold.d.ts} +2 -1
- package/dist/text/transcript-fold.d.ts.map +1 -0
- package/dist/{transcript-fold.js → text/transcript-fold.js} +2 -16
- package/dist/text/transcript-fold.js.map +1 -0
- package/dist/text/whisper.d.ts +3 -0
- package/dist/text/whisper.d.ts.map +1 -0
- package/dist/text/whisper.js +11 -0
- package/dist/text/whisper.js.map +1 -0
- package/dist/{workflow-faults.d.ts → text/workflow-faults.d.ts} +1 -1
- package/dist/text/workflow-faults.d.ts.map +1 -0
- package/dist/{workflow-faults.js → text/workflow-faults.js} +1 -1
- package/dist/text/workflow-faults.js.map +1 -0
- package/package.json +70 -70
- package/src/chores/chores.test.ts +4 -10
- package/src/chores/chores.ts +148 -392
- package/src/chores/digest.ts +8 -28
- package/src/chores/extension-update.ts +3 -8
- package/src/chores/fix-deps.ts +4 -18
- package/src/chores/index.ts +2 -2
- package/src/chores/probes.test.ts +7 -43
- package/src/chores/probes.ts +62 -167
- package/src/chores/prompt.ts +10 -34
- package/src/chores/stack.test.ts +6 -45
- package/src/chores/stack.ts +27 -118
- package/src/chores/verdict.test.ts +101 -80
- package/src/chores/verdict.ts +54 -99
- package/src/contracts/accounts.contract.ts +4 -19
- package/src/contracts/agent.contract.ts +7 -22
- package/src/contracts/agents.contract.ts +25 -71
- package/src/contracts/automations.contract.ts +14 -30
- package/src/contracts/capabilities.contract.ts +8 -35
- package/src/contracts/chores.contract.ts +4 -15
- package/src/contracts/endpoints.contract.ts +5 -22
- package/src/contracts/exit.contract.ts +7 -30
- package/src/contracts/extensions.contract.ts +8 -30
- package/src/contracts/git.contract.ts +25 -49
- package/src/contracts/host.contract.ts +9 -44
- package/src/contracts/intentic.contract.ts +1 -1
- package/src/contracts/logs.contract.ts +3 -13
- package/src/contracts/loops.contract.ts +9 -40
- package/src/contracts/personas.contract.ts +10 -35
- package/src/contracts/providers.contract.ts +4 -17
- package/src/contracts/runner.contract.ts +12 -39
- package/src/contracts/safety.contract.ts +5 -14
- package/src/contracts/secrets.contract.ts +4 -22
- package/src/contracts/sessions.contract.ts +1 -1
- package/src/contracts/settings.contract.ts +4 -10
- package/src/contracts/share.contract.ts +3 -9
- package/src/contracts/skills.contract.ts +4 -15
- package/src/contracts/system.contract.ts +26 -52
- package/src/contracts/usage.contract.ts +7 -21
- package/src/contracts/vpn.contract.ts +9 -16
- package/src/contracts/webext.contract.ts +9 -25
- package/src/contracts/workflows.contract.ts +34 -58
- package/src/contracts/workspace.contract.ts +19 -50
- package/src/events/agent-events.ts +345 -0
- package/src/events/cards.ts +286 -0
- package/src/{events.test.ts → events/resume.test.ts} +4 -19
- package/src/events/resume.ts +60 -0
- package/src/events/system-events.ts +139 -0
- package/src/events/transcript.ts +320 -0
- package/src/{conversation-ids.test.ts → ids/conversation-ids.test.ts} +25 -13
- package/src/ids/conversation-ids.ts +178 -0
- package/src/ids/hostnames.ts +129 -0
- package/src/ids/session-names.ts +29 -0
- package/src/ids/share-paths.ts +43 -0
- package/src/{tunnel-ids.test.ts → ids/tunnel-ids.test.ts} +1 -14
- package/src/ids/tunnel-ids.ts +29 -0
- package/src/index.ts +71 -87
- package/src/{agent-catalog.test.ts → models/agent-catalog.test.ts} +19 -93
- package/src/models/agent-catalog.ts +174 -0
- package/src/models/agent-runtimes.ts +201 -0
- package/src/models/capability-ledger.test.ts +84 -0
- package/src/{fast-tier.test.ts → models/fast-tier.test.ts} +7 -18
- package/src/models/fast-tier.ts +36 -0
- package/src/{model-order.test.ts → models/model-order.test.ts} +19 -40
- package/src/models/model-order.ts +163 -0
- package/src/{model-pins.test.ts → models/model-pins.test.ts} +12 -46
- package/src/models/model-pins.ts +57 -0
- package/src/models/model-roles.test.ts +38 -0
- package/src/models/model-roles.ts +180 -0
- package/src/{plan-pools.test.ts → models/plan-pools.test.ts} +6 -11
- package/src/models/plan-pools.ts +65 -0
- package/src/{prompt-complexity.test.ts → models/prompt-complexity.test.ts} +8 -60
- package/src/models/prompt-complexity.ts +215 -0
- package/src/{provider-specs.test.ts → models/provider-specs.test.ts} +18 -47
- package/src/models/provider-specs.ts +272 -0
- package/src/policy/approvals-execution.ts +58 -0
- package/src/{batch-runs.test.ts → policy/batch-runs.test.ts} +4 -20
- package/src/policy/batch-runs.ts +137 -0
- package/src/policy/capability-secrets.ts +5 -0
- package/src/{card-status.ts → policy/card-status.ts} +11 -26
- package/src/{command-classes.test.ts → policy/command-classes.test.ts} +11 -118
- package/src/policy/command-classes.ts +395 -0
- package/src/policy/command-run.ts +65 -0
- package/src/policy/control-scopes.ts +38 -0
- package/src/{credential-material.test.ts → policy/credential-material.test.ts} +4 -26
- package/src/policy/credential-material.ts +91 -0
- package/src/policy/needs-action.ts +5 -0
- package/src/policy/output-fields.ts +86 -0
- package/src/policy/overlay-lint.ts +100 -0
- package/src/{owner-ticket.test.ts → policy/owner-ticket.test.ts} +1 -1
- package/src/{owner-ticket.ts → policy/owner-ticket.ts} +9 -31
- package/src/policy/safety-policy.test.ts +84 -0
- package/src/policy/safety-policy.ts +142 -0
- package/src/policy/search-globs.ts +60 -0
- package/src/protocol/container-requirements.test.ts +72 -0
- package/src/protocol/container-requirements.ts +58 -0
- package/src/protocol/host-protocol.ts +29 -0
- package/src/protocol/ingress-contract.ts +103 -0
- package/src/{ingress-protocol.test.ts → protocol/ingress-protocol.test.ts} +25 -90
- package/src/protocol/ingress-protocol.ts +441 -0
- package/src/protocol/listener-protocol.ts +75 -0
- package/src/{peer-dial.test.ts → protocol/peer-dial.test.ts} +52 -1
- package/src/protocol/peer-dial.ts +207 -0
- package/src/{peer-mcp-server.ts → protocol/peer-mcp-server.ts} +16 -41
- package/src/protocol/request-id.ts +5 -0
- package/src/{routes.test.ts → protocol/routes.test.ts} +14 -22
- package/src/protocol/routes.ts +159 -0
- package/src/protocol/runner-protocol.ts +197 -0
- package/src/protocol/terminal-protocol.ts +13 -0
- package/src/protocol/webext-links.ts +50 -0
- package/src/protocol/webext-protocol.ts +24 -0
- package/src/schemas/activity.ts +22 -30
- package/src/schemas/agent.ts +130 -238
- package/src/schemas/agents.ts +165 -483
- package/src/schemas/approvals.ts +23 -71
- package/src/schemas/automations.ts +142 -250
- package/src/schemas/capabilities.ts +127 -414
- package/src/schemas/ci.ts +56 -108
- package/src/schemas/codebase-health.ts +7 -11
- package/src/schemas/devices.ts +98 -321
- package/src/schemas/engines.ts +16 -44
- package/src/schemas/environment.ts +41 -91
- package/src/schemas/exit.ts +24 -81
- package/src/schemas/extension-updates.ts +42 -87
- package/src/schemas/git-history.ts +30 -84
- package/src/schemas/git.ts +141 -256
- package/src/schemas/history.ts +14 -40
- package/src/schemas/hosts.ts +9 -15
- package/src/schemas/inventory.ts +8 -10
- package/src/schemas/issues.ts +66 -134
- package/src/schemas/logs.ts +15 -34
- package/src/schemas/loops.ts +46 -163
- package/src/schemas/maintenance.ts +47 -172
- package/src/schemas/panels.ts +20 -45
- package/src/schemas/personas.ts +50 -200
- package/src/schemas/plan-limits.ts +58 -197
- package/src/schemas/ports.ts +14 -32
- package/src/schemas/provider-oauth.ts +23 -76
- package/src/schemas/provider-subscriptions.ts +4 -13
- package/src/schemas/public.ts +4 -15
- package/src/schemas/push.ts +8 -36
- package/src/schemas/secrets.ts +20 -64
- package/src/schemas/settings.ts +175 -600
- package/src/schemas/share.ts +14 -32
- package/src/schemas/shared.ts +14 -13
- package/src/schemas/system.ts +46 -78
- package/src/schemas/terminal.ts +41 -120
- package/src/schemas/usage.ts +44 -233
- package/src/schemas/version-seam.test.ts +9 -26
- package/src/schemas/vpn.ts +27 -64
- package/src/schemas/webext.ts +22 -53
- package/src/schemas/workflows.ts +57 -183
- package/src/schemas/workspace-repos.ts +12 -24
- package/src/schemas/workspace-search.ts +17 -35
- package/src/schemas/workspace-setup.ts +4 -11
- package/src/schemas/workspace-tree.ts +32 -91
- package/src/state/arrival.ts +109 -0
- package/src/state/contract-lock.test.ts +17 -0
- package/src/state/contract-lock.ts +49 -0
- package/src/state/definition.ts +143 -0
- package/src/state/history-state.ts +103 -0
- package/src/{runtime-state.test.ts → state/runtime-state.test.ts} +3 -10
- package/src/state/runtime-state.ts +62 -0
- package/src/state/starter.ts +5 -0
- package/src/state/state-portability.ts +27 -0
- package/src/state/versions.ts +26 -0
- package/src/{workspace-state.test.ts → state/workspace-state.test.ts} +65 -172
- package/src/state/workspace-state.ts +669 -0
- package/src/{documents.test.ts → text/documents.test.ts} +1 -1
- package/src/text/documents.ts +42 -0
- package/src/text/embed.ts +132 -0
- package/src/text/mentions.ts +21 -0
- package/src/text/model-answer.ts +9 -0
- package/src/text/path-refs.ts +39 -0
- package/src/text/shell-regions.ts +224 -0
- package/src/{title.test.ts → text/title.test.ts} +13 -32
- package/src/text/title.ts +202 -0
- package/src/{transcript-fold.test.ts → text/transcript-fold.test.ts} +5 -83
- package/src/{transcript-fold.ts → text/transcript-fold.ts} +65 -170
- package/src/text/whisper.test.ts +19 -0
- package/src/text/whisper.ts +17 -0
- package/src/{workflow-faults.test.ts → text/workflow-faults.test.ts} +6 -24
- package/src/{workflow-faults.ts → text/workflow-faults.ts} +20 -60
- package/dist/agent-catalog.d.ts.map +0 -1
- package/dist/agent-catalog.js.map +0 -1
- package/dist/agent-runtimes.d.ts.map +0 -1
- package/dist/agent-runtimes.js.map +0 -1
- package/dist/approvals-execution.d.ts.map +0 -1
- package/dist/approvals-execution.js.map +0 -1
- package/dist/arrival.d.ts.map +0 -1
- package/dist/arrival.js.map +0 -1
- package/dist/batch-runs.d.ts.map +0 -1
- package/dist/batch-runs.js.map +0 -1
- package/dist/capability-env.d.ts.map +0 -1
- package/dist/capability-env.js.map +0 -1
- package/dist/capability-secrets.d.ts.map +0 -1
- package/dist/capability-secrets.js.map +0 -1
- package/dist/card-status.d.ts.map +0 -1
- package/dist/card-status.js.map +0 -1
- package/dist/command-classes.d.ts.map +0 -1
- package/dist/command-classes.js.map +0 -1
- package/dist/command-run.d.ts.map +0 -1
- package/dist/command-run.js.map +0 -1
- package/dist/contract-lock.d.ts.map +0 -1
- package/dist/contract-lock.js.map +0 -1
- package/dist/conversation-ids.d.ts +0 -4
- package/dist/conversation-ids.d.ts.map +0 -1
- package/dist/conversation-ids.js.map +0 -1
- package/dist/credential-material.d.ts.map +0 -1
- package/dist/credential-material.js.map +0 -1
- package/dist/definition.d.ts.map +0 -1
- package/dist/definition.js.map +0 -1
- package/dist/documents.d.ts.map +0 -1
- package/dist/documents.js.map +0 -1
- package/dist/embed.d.ts.map +0 -1
- package/dist/embed.js.map +0 -1
- package/dist/events.d.ts +0 -4336
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js +0 -725
- package/dist/events.js.map +0 -1
- package/dist/fast-tier.d.ts.map +0 -1
- package/dist/fast-tier.js.map +0 -1
- package/dist/history-state.d.ts.map +0 -1
- package/dist/history-state.js.map +0 -1
- package/dist/host-protocol.d.ts.map +0 -1
- package/dist/host-protocol.js.map +0 -1
- package/dist/hostnames.d.ts.map +0 -1
- package/dist/hostnames.js.map +0 -1
- package/dist/ingress-contract.d.ts.map +0 -1
- package/dist/ingress-contract.js.map +0 -1
- package/dist/ingress-protocol.d.ts.map +0 -1
- package/dist/ingress-protocol.js.map +0 -1
- package/dist/listener-protocol.d.ts.map +0 -1
- package/dist/listener-protocol.js.map +0 -1
- package/dist/mentions.d.ts.map +0 -1
- package/dist/mentions.js.map +0 -1
- package/dist/model-order.d.ts.map +0 -1
- package/dist/model-order.js.map +0 -1
- package/dist/model-pins.d.ts.map +0 -1
- package/dist/model-pins.js.map +0 -1
- package/dist/model-roles.d.ts.map +0 -1
- package/dist/model-roles.js.map +0 -1
- package/dist/needs-action.d.ts.map +0 -1
- package/dist/needs-action.js.map +0 -1
- package/dist/output-fields.d.ts.map +0 -1
- package/dist/output-fields.js.map +0 -1
- package/dist/overlay-lint.d.ts.map +0 -1
- package/dist/overlay-lint.js.map +0 -1
- package/dist/owner-ticket.d.ts.map +0 -1
- package/dist/owner-ticket.js.map +0 -1
- package/dist/path-refs.d.ts.map +0 -1
- package/dist/path-refs.js.map +0 -1
- package/dist/peer-dial.d.ts.map +0 -1
- package/dist/peer-dial.js.map +0 -1
- package/dist/peer-mcp-server.d.ts.map +0 -1
- package/dist/peer-mcp-server.js.map +0 -1
- package/dist/plan-pools.d.ts.map +0 -1
- package/dist/plan-pools.js.map +0 -1
- package/dist/prompt-complexity.d.ts.map +0 -1
- package/dist/prompt-complexity.js.map +0 -1
- package/dist/provider-specs.d.ts.map +0 -1
- package/dist/provider-specs.js.map +0 -1
- package/dist/request-id.d.ts.map +0 -1
- package/dist/request-id.js.map +0 -1
- package/dist/routes.d.ts.map +0 -1
- package/dist/routes.js.map +0 -1
- package/dist/runner-protocol.d.ts.map +0 -1
- package/dist/runner-protocol.js.map +0 -1
- package/dist/runtime-state.d.ts.map +0 -1
- package/dist/runtime-state.js.map +0 -1
- package/dist/safety-policy.d.ts.map +0 -1
- package/dist/safety-policy.js.map +0 -1
- package/dist/search-globs.d.ts.map +0 -1
- package/dist/search-globs.js.map +0 -1
- package/dist/session-names.d.ts.map +0 -1
- package/dist/session-names.js.map +0 -1
- package/dist/share-paths.d.ts.map +0 -1
- package/dist/share-paths.js.map +0 -1
- package/dist/shell-regions.d.ts.map +0 -1
- package/dist/shell-regions.js.map +0 -1
- package/dist/sse.d.ts.map +0 -1
- package/dist/sse.js.map +0 -1
- package/dist/starter.d.ts.map +0 -1
- package/dist/starter.js.map +0 -1
- package/dist/state-portability.d.ts.map +0 -1
- package/dist/state-portability.js.map +0 -1
- package/dist/terminal-protocol.d.ts.map +0 -1
- package/dist/terminal-protocol.js.map +0 -1
- package/dist/title.d.ts.map +0 -1
- package/dist/title.js.map +0 -1
- package/dist/transcript-fold.d.ts.map +0 -1
- package/dist/transcript-fold.js.map +0 -1
- package/dist/tunnel-ids.d.ts.map +0 -1
- package/dist/tunnel-ids.js.map +0 -1
- package/dist/versions.d.ts.map +0 -1
- package/dist/versions.js.map +0 -1
- package/dist/webext-links.d.ts.map +0 -1
- package/dist/webext-links.js.map +0 -1
- package/dist/webext-protocol.d.ts.map +0 -1
- package/dist/webext-protocol.js.map +0 -1
- package/dist/workflow-faults.d.ts.map +0 -1
- package/dist/workflow-faults.js.map +0 -1
- package/dist/workspace-state.d.ts.map +0 -1
- package/dist/workspace-state.js.map +0 -1
- package/src/agent-catalog.ts +0 -316
- package/src/agent-runtimes.ts +0 -419
- package/src/approvals-execution.ts +0 -96
- package/src/arrival.ts +0 -160
- package/src/batch-runs.ts +0 -188
- package/src/capability-ledger.test.ts +0 -140
- package/src/capability-secrets.ts +0 -20
- package/src/command-classes.ts +0 -617
- package/src/command-run.ts +0 -78
- package/src/contract-lock.test.ts +0 -23
- package/src/contract-lock.ts +0 -66
- package/src/conversation-ids.ts +0 -207
- package/src/credential-material.ts +0 -181
- package/src/definition.ts +0 -207
- package/src/documents.ts +0 -67
- package/src/embed.ts +0 -164
- package/src/events.ts +0 -1870
- package/src/fast-tier.ts +0 -72
- package/src/history-state.ts +0 -174
- package/src/host-protocol.ts +0 -36
- package/src/hostnames.ts +0 -180
- package/src/ingress-contract.ts +0 -157
- package/src/ingress-protocol.ts +0 -625
- package/src/listener-protocol.ts +0 -96
- package/src/mentions.ts +0 -25
- package/src/model-order.ts +0 -262
- package/src/model-pins.ts +0 -132
- package/src/model-roles.test.ts +0 -52
- package/src/model-roles.ts +0 -320
- package/src/needs-action.ts +0 -14
- package/src/output-fields.ts +0 -111
- package/src/overlay-lint.ts +0 -116
- package/src/path-refs.ts +0 -59
- package/src/peer-dial.ts +0 -163
- package/src/plan-pools.ts +0 -92
- package/src/prompt-complexity.ts +0 -334
- package/src/provider-specs.ts +0 -432
- package/src/request-id.ts +0 -41
- package/src/routes.ts +0 -219
- package/src/runner-protocol.ts +0 -239
- package/src/runtime-state.ts +0 -140
- package/src/safety-policy.test.ts +0 -88
- package/src/safety-policy.ts +0 -258
- package/src/search-globs.ts +0 -76
- package/src/session-names.ts +0 -44
- package/src/share-paths.ts +0 -68
- package/src/shell-regions.ts +0 -289
- package/src/starter.ts +0 -13
- package/src/state-portability.ts +0 -56
- package/src/terminal-protocol.ts +0 -16
- package/src/title.ts +0 -267
- package/src/tunnel-ids.ts +0 -57
- package/src/versions.ts +0 -48
- package/src/webext-links.ts +0 -90
- package/src/webext-protocol.ts +0 -27
- package/src/workspace-state.ts +0 -1090
- /package/dist/{hostnames.d.ts → ids/hostnames.d.ts} +0 -0
- /package/dist/{hostnames.js → ids/hostnames.js} +0 -0
- /package/dist/{session-names.d.ts → ids/session-names.d.ts} +0 -0
- /package/dist/{session-names.js → ids/session-names.js} +0 -0
- /package/dist/{share-paths.d.ts → ids/share-paths.d.ts} +0 -0
- /package/dist/{share-paths.js → ids/share-paths.js} +0 -0
- /package/dist/{agent-catalog.js → models/agent-catalog.js} +0 -0
- /package/dist/{agent-runtimes.d.ts → models/agent-runtimes.d.ts} +0 -0
- /package/dist/{agent-runtimes.js → models/agent-runtimes.js} +0 -0
- /package/dist/{fast-tier.js → models/fast-tier.js} +0 -0
- /package/dist/{model-order.d.ts → models/model-order.d.ts} +0 -0
- /package/dist/{model-order.js → models/model-order.js} +0 -0
- /package/dist/{model-pins.js → models/model-pins.js} +0 -0
- /package/dist/{plan-pools.js → models/plan-pools.js} +0 -0
- /package/dist/{prompt-complexity.d.ts → models/prompt-complexity.d.ts} +0 -0
- /package/dist/{prompt-complexity.js → models/prompt-complexity.js} +0 -0
- /package/dist/{provider-specs.d.ts → models/provider-specs.d.ts} +0 -0
- /package/dist/{provider-specs.js → models/provider-specs.js} +0 -0
- /package/dist/{approvals-execution.d.ts → policy/approvals-execution.d.ts} +0 -0
- /package/dist/{approvals-execution.js → policy/approvals-execution.js} +0 -0
- /package/dist/{capability-env.d.ts → policy/capability-env.d.ts} +0 -0
- /package/dist/{capability-env.js → policy/capability-env.js} +0 -0
- /package/dist/{capability-secrets.d.ts → policy/capability-secrets.d.ts} +0 -0
- /package/dist/{capability-secrets.js → policy/capability-secrets.js} +0 -0
- /package/dist/{command-run.js → policy/command-run.js} +0 -0
- /package/dist/{credential-material.d.ts → policy/credential-material.d.ts} +0 -0
- /package/dist/{credential-material.js → policy/credential-material.js} +0 -0
- /package/dist/{needs-action.d.ts → policy/needs-action.d.ts} +0 -0
- /package/dist/{needs-action.js → policy/needs-action.js} +0 -0
- /package/dist/{output-fields.d.ts → policy/output-fields.d.ts} +0 -0
- /package/dist/{output-fields.js → policy/output-fields.js} +0 -0
- /package/dist/{overlay-lint.d.ts → policy/overlay-lint.d.ts} +0 -0
- /package/dist/{overlay-lint.js → policy/overlay-lint.js} +0 -0
- /package/dist/{owner-ticket.d.ts → policy/owner-ticket.d.ts} +0 -0
- /package/dist/{search-globs.d.ts → policy/search-globs.d.ts} +0 -0
- /package/dist/{search-globs.js → policy/search-globs.js} +0 -0
- /package/dist/{ingress-contract.d.ts → protocol/ingress-contract.d.ts} +0 -0
- /package/dist/{ingress-protocol.d.ts → protocol/ingress-protocol.d.ts} +0 -0
- /package/dist/{ingress-protocol.js → protocol/ingress-protocol.js} +0 -0
- /package/dist/{listener-protocol.d.ts → protocol/listener-protocol.d.ts} +0 -0
- /package/dist/{peer-mcp-server.d.ts → protocol/peer-mcp-server.d.ts} +0 -0
- /package/dist/{peer-mcp-server.js → protocol/peer-mcp-server.js} +0 -0
- /package/dist/{request-id.d.ts → protocol/request-id.d.ts} +0 -0
- /package/dist/{request-id.js → protocol/request-id.js} +0 -0
- /package/dist/{routes.d.ts → protocol/routes.d.ts} +0 -0
- /package/dist/{routes.js → protocol/routes.js} +0 -0
- /package/dist/{sse.d.ts → protocol/sse.d.ts} +0 -0
- /package/dist/{sse.js → protocol/sse.js} +0 -0
- /package/dist/{terminal-protocol.js → protocol/terminal-protocol.js} +0 -0
- /package/dist/{webext-links.d.ts → protocol/webext-links.d.ts} +0 -0
- /package/dist/{webext-links.js → protocol/webext-links.js} +0 -0
- /package/dist/{arrival.d.ts → state/arrival.d.ts} +0 -0
- /package/dist/{contract-lock.d.ts → state/contract-lock.d.ts} +0 -0
- /package/dist/{history-state.d.ts → state/history-state.d.ts} +0 -0
- /package/dist/{runtime-state.d.ts → state/runtime-state.d.ts} +0 -0
- /package/dist/{runtime-state.js → state/runtime-state.js} +0 -0
- /package/dist/{starter.d.ts → state/starter.d.ts} +0 -0
- /package/dist/{starter.js → state/starter.js} +0 -0
- /package/dist/{state-portability.d.ts → state/state-portability.d.ts} +0 -0
- /package/dist/{state-portability.js → state/state-portability.js} +0 -0
- /package/dist/{versions.d.ts → state/versions.d.ts} +0 -0
- /package/dist/{versions.js → state/versions.js} +0 -0
- /package/dist/{embed.d.ts → text/embed.d.ts} +0 -0
- /package/dist/{embed.js → text/embed.js} +0 -0
- /package/dist/{mentions.d.ts → text/mentions.d.ts} +0 -0
- /package/dist/{mentions.js → text/mentions.js} +0 -0
- /package/dist/{path-refs.d.ts → text/path-refs.d.ts} +0 -0
- /package/dist/{path-refs.js → text/path-refs.js} +0 -0
- /package/dist/{shell-regions.js → text/shell-regions.js} +0 -0
- /package/dist/{title.d.ts → text/title.d.ts} +0 -0
- /package/dist/{title.js → text/title.js} +0 -0
- /package/src/{hostnames.test.ts → ids/hostnames.test.ts} +0 -0
- /package/src/{share-paths.test.ts → ids/share-paths.test.ts} +0 -0
- /package/src/{capability-env.ts → policy/capability-env.ts} +0 -0
- /package/src/{overlay-lint.test.ts → policy/overlay-lint.test.ts} +0 -0
- /package/src/{search-globs.test.ts → policy/search-globs.test.ts} +0 -0
- /package/src/{ingress-contract.test.ts → protocol/ingress-contract.test.ts} +0 -0
- /package/src/{peer-mcp-server.test.ts → protocol/peer-mcp-server.test.ts} +0 -0
- /package/src/{sse.ts → protocol/sse.ts} +0 -0
- /package/src/{versions.test.ts → state/versions.test.ts} +0 -0
- /package/src/{embed.test.ts → text/embed.test.ts} +0 -0
- /package/src/{mentions.test.ts → text/mentions.test.ts} +0 -0
- /package/src/{path-refs.test.ts → text/path-refs.test.ts} +0 -0
package/src/chores/chores.ts
CHANGED
|
@@ -4,43 +4,14 @@ import { CHORE_INVARIANTS, composeAsk, REPORT_INVARIANTS, TRIAGE_NOTE } from "./
|
|
|
4
4
|
import { componentStem, frameworksOf, idiomRule, normalizePath, UI_FRAMEWORKS, usesTailwind } from "./stack.js";
|
|
5
5
|
import { WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG } from "./workspace-scope.js";
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* sprint board, and that a person cannot notice is overdue by looking at their editor. The engineering problem is
|
|
11
|
-
* not finding such work, any linter will hand you a thousand findings, it is deciding which of them is worth
|
|
12
|
-
* interrupting somebody about, on a surface they will still be reading in six months.
|
|
13
|
-
*
|
|
14
|
-
* Three rules, and every entry below obeys all three:
|
|
15
|
-
*
|
|
16
|
-
* 1. DELTAS, NOT ABSOLUTES. "38 packages are undocumented" is a statistic; it will be true every day for a year,
|
|
17
|
-
* and a tile lit every day teaches the eye to stop seeing the rail. "A package appeared that nothing explains"
|
|
18
|
-
* is an event. So a chore's `digest` is built from the IDENTITIES of what it found, which packages, which
|
|
19
|
-
* advisories, which files, and the rail speaks when that set changes, not while it is merely non-empty. The
|
|
20
|
-
* standing count still shows inside the panel, next to the thing it describes, which is where a statistic
|
|
21
|
-
* belongs.
|
|
22
|
-
*
|
|
23
|
-
* 2. LEADER-RELATIVE, NOT TUNED. Nowhere in here is there a threshold that would need a different value for a
|
|
24
|
-
* Rust repo, a fresh scaffold, or a ten-year monolith, with one deliberate exception (duplication's 5%, which
|
|
25
|
-
* is a percentage of the tree and therefore already scale-free). "Three times the median of its own ranking"
|
|
26
|
-
* needs no calibration and cannot rot.
|
|
27
|
-
*
|
|
28
|
-
* 3. THE EVIDENCE IS THE TRUTH; THE LEDGER ONLY DEBOUNCES. Nothing here can be ticked off. A chore goes quiet
|
|
29
|
-
* because the measurement moved, which means someone fixing it by hand, or an unrelated change fixing it by
|
|
30
|
-
* accident, is registered exactly like a chore turn doing it. The ledger's only power is to stop the rail
|
|
31
|
-
* repeating itself about evidence a turn has already been spent on (verdict.ts).
|
|
32
|
-
*
|
|
33
|
-
* What is NOT here is as deliberate. There is no composite score, no letter grade, no "health: 78%". Those are
|
|
34
|
-
* not comparable across projects, cannot be checked by the reader, and turn a set of specific, arguable findings
|
|
35
|
-
* into one number nobody can act on. And no chore is ever created enabled-and-hidden: a chore that runs is a
|
|
36
|
-
* turn that spends money and writes to the workspace, so it is either something the owner started or an
|
|
37
|
-
* automation they can see in a list. */
|
|
7
|
+
// Routine maintenance a repo is owed, surfaced only as events: a chore's `digest` is built from the identities of what
|
|
8
|
+
// changed, not a count, so ordinary drift never rebadges. Thresholds are leader-relative, not a per-repo tuned number.
|
|
9
|
+
// A chore goes quiet only because the measurement itself moved; nothing here is manually ticked off.
|
|
38
10
|
|
|
39
11
|
export type ChoreStance = "act" | "report";
|
|
40
12
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
* which carries the argument and the words the panel groups under. */
|
|
13
|
+
// What kind of claim a chore makes on someone's attention, from an active risk to a periodic review; see CHORE_KINDS
|
|
14
|
+
// for the order and the words the panel groups under.
|
|
44
15
|
export type ChoreKind = "carrying" | "accruing" | "drifting" | "surveying";
|
|
45
16
|
|
|
46
17
|
export interface ChoreContext {
|
|
@@ -53,104 +24,57 @@ export interface ChoreContext {
|
|
|
53
24
|
readonly nowMs: number;
|
|
54
25
|
}
|
|
55
26
|
|
|
56
|
-
// What a chore found, when it found anything
|
|
27
|
+
// What a chore found, when it found anything; `undefined` from `assess` is the healthy, common case.
|
|
57
28
|
export interface ChoreFinding {
|
|
58
|
-
// One line, in numbers
|
|
29
|
+
// One line, in numbers; the reader decides from this alone whether to open anything.
|
|
59
30
|
readonly headline: string;
|
|
60
|
-
// The evidence
|
|
61
|
-
// checkable rather than something to be believed.
|
|
31
|
+
// The evidence, one claim per line; what makes the headline checkable, not just believed.
|
|
62
32
|
readonly detail: readonly string[];
|
|
63
|
-
// The identity of
|
|
33
|
+
// The identity of this evidence; see digest.ts, it is what the rail's transitions are measured against.
|
|
64
34
|
readonly digest: string;
|
|
65
|
-
// `warning` is for a risk
|
|
66
|
-
// else is `info`, including large and ugly numbers, because "there is a lot of it" is not an emergency.
|
|
35
|
+
// `warning` is for a risk carried right now (a live advisory, an EOL runtime); everything else is `info`.
|
|
67
36
|
readonly severity: "info" | "warning";
|
|
68
|
-
// The numbers again, in the agent's terms, for the prompt's "Why:" line
|
|
37
|
+
// The numbers again, in the agent's terms, for the prompt's "Why:" line; exact, the agent may recount them.
|
|
69
38
|
readonly why: string;
|
|
70
39
|
}
|
|
71
40
|
|
|
72
41
|
export interface Chore {
|
|
73
42
|
readonly id: string;
|
|
74
43
|
readonly title: string;
|
|
75
|
-
// An app icon name
|
|
76
|
-
// this library must not depend on the UI kit to name a glyph.
|
|
44
|
+
// An app icon name, left as a plain string so this library doesn't depend on the UI kit to name a glyph.
|
|
77
45
|
readonly icon: string;
|
|
78
46
|
// The one-line standing description, shown whether or not the chore is currently due.
|
|
79
47
|
readonly description: string;
|
|
80
|
-
|
|
81
|
-
* order and the panel's grouping, and it is a FIELD rather than a comment above the array for exactly that
|
|
82
|
-
* reason: the reading order is the one editorial claim this surface makes, and a claim spelled as a comment
|
|
83
|
-
* beside a hand-maintained list is one nobody can check and the compiler cannot keep. */
|
|
48
|
+
// A field, not a comment, so the book's reading order is compiler-checked, not hand-maintained.
|
|
84
49
|
readonly kind: ChoreKind;
|
|
85
|
-
|
|
86
|
-
* the evidence below it and disagree.
|
|
87
|
-
*
|
|
88
|
-
* This is not decoration. A row that says "4 majors waiting" and nothing else is asking to be taken on
|
|
89
|
-
* trust; the same row saying "shown because: a dependency is a major version behind" is a claim someone can
|
|
90
|
-
* argue with, and arguing with it is how the book gets better. It rides into the prompt too, so the agent is
|
|
91
|
-
* told the rule it was woken by rather than left to infer it from the numbers.
|
|
92
|
-
*
|
|
93
|
-
* Kept as prose next to the code that implements it, which means it can drift from it, the tests below
|
|
94
|
-
* cannot check English. The rule for writing one: say the THRESHOLD, not the subject. "Duplication is high"
|
|
95
|
-
* is a topic; "more than 5% of the tree is duplicated" is a criterion. */
|
|
50
|
+
// The threshold this chore is due by, stated as a criterion a reader can check and disagree with, not a topic.
|
|
96
51
|
readonly criterion: string;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
*
|
|
100
|
-
* Distinct from `assess`, and the distinction is the whole point: `assess` asks whether the answer is yes,
|
|
101
|
-
* this asks whether the question makes sense. "Re-read the documentation against the code" in a repository
|
|
102
|
-
* with no documentation is not a chore that is currently clear, it is one that will never apply here, and
|
|
103
|
-
* showing it as clear says we checked something we cannot check. A chore that does not apply is dropped from
|
|
104
|
-
* the panel entirely; a line under the panel's list records that it was considered.
|
|
105
|
-
*
|
|
106
|
-
* A BARE CAUSE, "no Dockerfile", never "this repository ships no Dockerfile, so there is no image to slim".
|
|
107
|
-
* Same spelling as `ProbeSpec.unavailable`, and for the same reason both surfaces need: one absent
|
|
108
|
-
* package.json rules out five chores, and five sentences saying so at length is the wall of text this phrasing
|
|
109
|
-
* exists to prevent. The panel groups by this string, so the CONSEQUENCE, which chores it costs, is the list
|
|
110
|
-
* beside it rather than a clause repeated inside every entry. Identical causes must be spelled identically or
|
|
111
|
-
* they group apart.
|
|
112
|
-
*
|
|
113
|
-
* Reads `signals` rather than probes on purpose: applicability is about what the repository IS, which is a
|
|
114
|
-
* fact the daemon holds without measuring anything. If a gate needed a probe it would be describing the
|
|
115
|
-
* answer rather than the question. */
|
|
52
|
+
// Whether the question makes sense here, distinct from `assess`; undefined means yes, else a bare cause spelled
|
|
53
|
+
// identically to group by.
|
|
116
54
|
readonly applies?: (signals: ChoreSignals) => string | undefined;
|
|
117
|
-
// Whether the turn
|
|
118
|
-
// report-stance chore is told in words that editing would be a surprise.
|
|
55
|
+
// Whether the turn may change anything; not a hint, it selects the invariants block and is stated to the agent.
|
|
119
56
|
readonly stance: ChoreStance;
|
|
120
|
-
// Probes that must have run and succeeded
|
|
121
|
-
// rendered greyed, never badged, and never mistaken for a clean result.
|
|
57
|
+
// Probes that must have run and succeeded first; missing means unavailable, shown greyed, never mistaken for clean.
|
|
122
58
|
readonly needs: readonly ProbeId[];
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
* eyes" has no measurement and its value is entirely in being done periodically. */
|
|
59
|
+
// How long until this is worth doing again regardless of what changed: a backstop for a measured chore, the whole
|
|
60
|
+
// trigger for a survey.
|
|
126
61
|
readonly cadenceMs: number;
|
|
127
|
-
//
|
|
128
|
-
//
|
|
62
|
+
// Named rather than inferred from an empty `needs`: a survey has no measurement, and the panel says which kind of
|
|
63
|
+
// row this is.
|
|
129
64
|
readonly survey?: true;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
*
|
|
133
|
-
* The two modes are genuinely different and both are wanted. The Maintenance panel is EVIDENCE-driven: it
|
|
134
|
-
* reads what the daemon already measured and offers a turn against a specific finding you can read first. An
|
|
135
|
-
* automation is SCHEDULE-driven: it wakes on a clock, at 3am, with nobody watching. So an automation cannot
|
|
136
|
-
* carry a finding, there is no verdict at fire time, and instead it carries a GUARD: a shell one-liner that
|
|
137
|
-
* runs for free on the sandbox's own clock and exits non-zero to skip, so the half that costs a turn only
|
|
138
|
-
* starts when there is something to start it for.
|
|
139
|
-
*
|
|
140
|
-
* `report` is where the guard leaves its findings. A guard's stdout is discarded on success (only a FAILING
|
|
141
|
-
* guard's output survives, as the skip reason), so a file is how the free deterministic half hands what it
|
|
142
|
-
* found to the expensive half. */
|
|
65
|
+
// Wakes on a clock, unattended, so it carries a guard (a shell one-liner, exits non-zero to skip) instead of a
|
|
66
|
+
// finding.
|
|
143
67
|
readonly automation?: {
|
|
144
68
|
readonly cron: string;
|
|
145
69
|
readonly guard: string;
|
|
146
70
|
readonly note: string;
|
|
147
71
|
readonly report: string;
|
|
148
|
-
// How the woken turn is told what it is looking at,
|
|
72
|
+
// How the woken turn is told what it is looking at, in place of a finding.
|
|
149
73
|
readonly woke: string;
|
|
150
74
|
};
|
|
151
75
|
readonly assess: (context: ChoreContext) => ChoreFinding | undefined;
|
|
152
|
-
// The prompt's three
|
|
153
|
-
//
|
|
76
|
+
// The prompt's three parts: `diagnosis` explains the numbers, `goal` is the shape to move toward (never a design),
|
|
77
|
+
// `done` is agent-falsifiable.
|
|
154
78
|
readonly diagnosis: string;
|
|
155
79
|
readonly goal: string;
|
|
156
80
|
readonly done: string;
|
|
@@ -158,32 +82,28 @@ export interface Chore {
|
|
|
158
82
|
|
|
159
83
|
const DAY_MS = 86_400_000;
|
|
160
84
|
|
|
161
|
-
|
|
162
|
-
* inputs to a turn that starts moments later, never something to keep, and deliberately the SAME paths the
|
|
163
|
-
* probe runner uses, so a workspace that runs both does not keep two copies of the same measurement. */
|
|
85
|
+
// Where a scheduled chore's guard leaves its report; under /tmp since these feed a turn moments later, not kept.
|
|
164
86
|
const AUDIT_REPORT = `/tmp/intentic-chore-audit.json`;
|
|
165
87
|
const KNIP_REPORT = `/tmp/intentic-chore-knip.json`;
|
|
166
88
|
const JSCPD_DIR = `/tmp/intentic-chore-jscpd`;
|
|
167
89
|
const JSCPD_REPORT = `${JSCPD_DIR}/jscpd-report.json`;
|
|
168
90
|
|
|
169
|
-
// How a repo is named to a person
|
|
170
|
-
//
|
|
171
|
-
// called "root", so it is spelled out here, once, rather than at every call site that builds a prompt.
|
|
91
|
+
// How a repo is named to a person or an agent; "root" (the wire id for the workspace's own repo) reads as a real
|
|
92
|
+
// directory name to an agent, so it is spelled out here once rather than at every call site.
|
|
172
93
|
export const repoLabel = (repo: string): string => (repo === `root` || repo === `` ? `the workspace root repository` : repo);
|
|
173
94
|
|
|
174
|
-
// The same repository, named for a
|
|
175
|
-
//
|
|
176
|
-
// the name on its own, and "the workspace root repository" truncates to "the workspace root reposi…" there.
|
|
95
|
+
// The same repository, named for a narrow column or chip; `repoLabel`'s prose truncates badly there ("the
|
|
96
|
+
// workspace root reposi…").
|
|
177
97
|
export const repoName = (repo: string): string => (repo === `root` || repo === `` ? `workspace root` : repo);
|
|
178
98
|
|
|
179
99
|
const plural = (count: number, one: string, many = `${one}s`): string => `${count} ${count === 1 ? one : many}`;
|
|
180
100
|
|
|
181
|
-
// One outdated dependency, as the panel lists it
|
|
182
|
-
//
|
|
101
|
+
// One outdated dependency, as the panel lists it; the semver step leads, since it decides whether the row is a
|
|
102
|
+
// morning's work or a project.
|
|
183
103
|
const outdatedLine = (entry: OutdatedPackage): string => `${entry.kind} · ${entry.name} ${entry.current} → ${entry.latest}`;
|
|
184
104
|
|
|
185
|
-
// The
|
|
186
|
-
//
|
|
105
|
+
// The facts of a probe that actually ran; anything else (never run, unavailable, failed) reads as absent, so
|
|
106
|
+
// assess() can't mistake an unmeasured repo for a clean one.
|
|
187
107
|
const factsOf = <T extends ProbeId>(context: ChoreContext, id: T): Extract<NonNullable<ProbeResult["facts"]>, { id: T }> | undefined => {
|
|
188
108
|
const probe = context.probes.get(id);
|
|
189
109
|
if (probe?.state !== `ok` || probe.facts === undefined || probe.facts.id !== id) {
|
|
@@ -196,11 +116,9 @@ const factsOf = <T extends ProbeId>(context: ChoreContext, id: T): Extract<NonNu
|
|
|
196
116
|
|
|
197
117
|
const BLOCKING = new Set<Advisory["severity"]>([`critical`, `high`]);
|
|
198
118
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
* prompt rather than flattened, a moderate advisory in a build-time-only tool badging red is how `warning` stops
|
|
203
|
-
* meaning anything within a week. */
|
|
119
|
+
// Security is the only chore with no cadence: an advisory isn't something that becomes worth reading after 30
|
|
120
|
+
// days. Also the only one that reaches `warning` routinely, so the bar is critical-or-high with production/dev carried
|
|
121
|
+
// to the prompt.
|
|
204
122
|
const security: Chore = {
|
|
205
123
|
id: `security-advisories`,
|
|
206
124
|
title: `Patch security advisories`,
|
|
@@ -240,13 +158,12 @@ const security: Chore = {
|
|
|
240
158
|
(advisory) =>
|
|
241
159
|
`${advisory.severity} · ${advisory.name}, ${advisory.title}${advisory.patched === undefined ? ` (no patch yet)` : ``}`,
|
|
242
160
|
),
|
|
243
|
-
// Identities, not counts: every advisory that appears or is fixed is genuinely news,
|
|
244
|
-
//
|
|
161
|
+
// Identities, not counts: every advisory that appears or is fixed is genuinely news, with no ordinary drift
|
|
162
|
+
// to absorb.
|
|
245
163
|
digest: digestOf(...blocking.map((advisory) => `${advisory.name}@${advisory.severity}`).toSorted()),
|
|
246
164
|
severity: production.length > 0 ? `warning` : `info`,
|
|
247
|
-
// Named, not counted
|
|
248
|
-
//
|
|
249
|
-
// would be reading a different tree by then.
|
|
165
|
+
// Named, not counted; re-deriving the list itself would be slow, and pnpm audit would read a different tree
|
|
166
|
+
// by then.
|
|
250
167
|
why:
|
|
251
168
|
`pnpm audit reports ${plural(blocking.length, `high or critical advisory`, `high or critical advisories`)} against ` +
|
|
252
169
|
`${repoLabel(context.repo)}, ${production.length} reaching a production dependency path, ${patchable.length} with a published patched range: ` +
|
|
@@ -262,10 +179,8 @@ const security: Chore = {
|
|
|
262
179
|
done: `Done when \`pnpm audit\` reports fewer high/critical advisories than it did, and the repository's type-check and tests pass.`,
|
|
263
180
|
};
|
|
264
181
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
* built from WHICH packages have a major waiting, and a new one appearing is the event. The total count rides
|
|
268
|
-
* along bucketed (digest.ts) so that ordinary drift, which is constant, does not read as news. */
|
|
182
|
+
// Majors are the finding, the total is context: the digest is keyed to which packages have a major waiting, with
|
|
183
|
+
// the count riding along bucketed so ordinary drift doesn't read as news.
|
|
269
184
|
const OUTDATED_NOISE_FLOOR = 20;
|
|
270
185
|
|
|
271
186
|
const dependencies: Chore = {
|
|
@@ -285,8 +200,8 @@ const dependencies: Chore = {
|
|
|
285
200
|
return undefined;
|
|
286
201
|
}
|
|
287
202
|
const majors = facts.packages.filter((entry) => entry.kind === `major`);
|
|
288
|
-
//
|
|
289
|
-
//
|
|
203
|
+
// A healthy repo, not a chore: the floor is on the total, since minors and patches are only worth a turn in
|
|
204
|
+
// bulk.
|
|
290
205
|
if (majors.length === 0 && facts.packages.length < OUTDATED_NOISE_FLOOR) {
|
|
291
206
|
return undefined;
|
|
292
207
|
}
|
|
@@ -298,8 +213,8 @@ const dependencies: Chore = {
|
|
|
298
213
|
detail: majors.toSorted((left, right) => left.name.localeCompare(right.name)).map(outdatedLine),
|
|
299
214
|
digest: digestOf(...majors.map((entry) => `${entry.name}@${entry.latest}`).toSorted(), `total:${bucketOf(facts.packages.length)}`),
|
|
300
215
|
severity: `info`,
|
|
301
|
-
//
|
|
302
|
-
//
|
|
216
|
+
// Majors are named since they are what the turn is about; minors and patches are a bulk operation the agent
|
|
217
|
+
// enumerates itself.
|
|
303
218
|
why:
|
|
304
219
|
`pnpm outdated reports ${plural(facts.packages.length, `dependency`, `dependencies`)} behind the registry in ` +
|
|
305
220
|
`${repoLabel(context.repo)}, ${majors.length} of them by a major version` +
|
|
@@ -315,9 +230,8 @@ const dependencies: Chore = {
|
|
|
315
230
|
done: `Done when the repository's type-check and tests pass, and your summary names every major you took and every one you left, with the reason.`,
|
|
316
231
|
};
|
|
317
232
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
* light together are three chances to teach someone to ignore the rail. */
|
|
233
|
+
// knip's counts folded into one chore rather than split by kind: unused files, exports and dependencies are the
|
|
234
|
+
// same finding, fixed in one pass.
|
|
321
235
|
const deadCode: Chore = {
|
|
322
236
|
id: `dead-code`,
|
|
323
237
|
title: `Clear out dead code`,
|
|
@@ -331,9 +245,8 @@ const deadCode: Chore = {
|
|
|
331
245
|
cadenceMs: 14 * DAY_MS,
|
|
332
246
|
automation: {
|
|
333
247
|
cron: `0 3 * * *`,
|
|
334
|
-
// Two gates
|
|
335
|
-
//
|
|
336
|
-
// rather than downloading a floating version that would disagree with its knip.json.
|
|
248
|
+
// Two gates so a repo that never adopted knip reads differently from one that's clean; `pnpm exec` resolves the
|
|
249
|
+
// repo's own devDependency.
|
|
337
250
|
guard:
|
|
338
251
|
`pnpm exec knip --version >/dev/null 2>&1 || { echo "knip is not a devDependency of this repo"; exit 1; }; ` +
|
|
339
252
|
`pnpm exec knip --reporter json > ${KNIP_REPORT} && { echo "no dead code"; exit 1; }`,
|
|
@@ -354,12 +267,12 @@ const deadCode: Chore = {
|
|
|
354
267
|
return {
|
|
355
268
|
headline: `${plural(files, `unreferenced file`)}, ${plural(exports + types, `unused export`)}, ${plural(unusedDeps + devDependencies, `unused dependency`, `unused dependencies`)}`,
|
|
356
269
|
detail: sample.map((path) => `unreferenced · ${path}`),
|
|
357
|
-
//
|
|
358
|
-
//
|
|
270
|
+
// File identities carry the news (a newly-dead file is an event); export/dependency counts ride along
|
|
271
|
+
// bucketed, since they drift constantly.
|
|
359
272
|
digest: digestOf(...sample.toSorted(), `exports:${bucketOf(exports + types)}`, `deps:${bucketOf(unusedDeps + devDependencies)}`),
|
|
360
273
|
severity: `info`,
|
|
361
|
-
// The sample
|
|
362
|
-
//
|
|
274
|
+
// The sample, not the full list: this measurement is hours old, and the goal tells the agent to re-run knip
|
|
275
|
+
// for the rest.
|
|
363
276
|
why:
|
|
364
277
|
`knip reports ${plural(files, `unreferenced file`)}, ${exports + types} unused exports and ` +
|
|
365
278
|
`${unusedDeps + devDependencies} unused dependencies in ${repoLabel(context.repo)}` +
|
|
@@ -376,11 +289,9 @@ const deadCode: Chore = {
|
|
|
376
289
|
done: `Done when knip reports fewer findings, the repository's type-check and tests pass, and nothing you deleted is reachable from another package.`,
|
|
377
290
|
};
|
|
378
291
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
* design judgement, and an agent that "collapses duplication" unattended produces exactly the abstraction that
|
|
383
|
-
* gets deleted a year later. */
|
|
292
|
+
// Report-stance: most duplication shouldn't be removed (generated files, deliberate test repetition, lookalikes
|
|
293
|
+
// with different owners); deciding which copies must change together is a design judgement no unattended agent should
|
|
294
|
+
// make.
|
|
384
295
|
const DUPLICATION_FLOOR = 5;
|
|
385
296
|
|
|
386
297
|
const duplication: Chore = {
|
|
@@ -395,8 +306,7 @@ const duplication: Chore = {
|
|
|
395
306
|
cadenceMs: 30 * DAY_MS,
|
|
396
307
|
automation: {
|
|
397
308
|
cron: `0 3 * * 1`,
|
|
398
|
-
// Gated on the percentage
|
|
399
|
-
// report is noise that would wake an agent every week to say nothing actionable.
|
|
309
|
+
// Gated on the percentage, not "any clone at all" (which every repo has); below this the report is noise.
|
|
400
310
|
guard:
|
|
401
311
|
`pnpm dlx jscpd ${WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG} --reporters json --output ${JSCPD_DIR} --min-lines 12 --threshold 100 . >/dev/null 2>&1; ` +
|
|
402
312
|
`[ "$(jq '.statistics.total.percentage // 0 | floor' ${JSCPD_REPORT} 2>/dev/null || echo 0)" -ge ${DUPLICATION_FLOOR} ]`,
|
|
@@ -413,8 +323,8 @@ const duplication: Chore = {
|
|
|
413
323
|
return {
|
|
414
324
|
headline: `${percentage.toFixed(1)}% of the tree is duplicated, across ${plural(clones, `clone`)}`,
|
|
415
325
|
detail: top.map((clone) => `${clone.lines} lines · ${clone.first} ↔ ${clone.second}`),
|
|
416
|
-
// A whole percentage point is the smallest move worth calling news; the biggest clones' identities
|
|
417
|
-
//
|
|
326
|
+
// A whole percentage point is the smallest move worth calling news; the biggest clones' identities carry
|
|
327
|
+
// the rest.
|
|
418
328
|
digest: digestOf(`pct:${Math.round(percentage)}`, ...top.map((clone) => `${clone.first}|${clone.second}`).toSorted()),
|
|
419
329
|
severity: `info`,
|
|
420
330
|
why:
|
|
@@ -431,24 +341,9 @@ const duplication: Chore = {
|
|
|
431
341
|
done: `Done when every clone in the report has either a named extraction or a one-line reason it should stay.`,
|
|
432
342
|
};
|
|
433
343
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
* A green suite is not evidence that the code is checked. Coverage says a line RAN; it cannot say an assertion
|
|
438
|
-
* depended on what the line produced. The gap between those two is where a model's tests live: they execute
|
|
439
|
-
* everything and assert almost nothing, and every gate here says yes to them — they type-check, they lint, they
|
|
440
|
-
* pass.
|
|
441
|
-
*
|
|
442
|
-
* MEASURED IN THIS REPOSITORY, on sandbox-contract's own chore module: 109 hand-written tests, and 16 of 58
|
|
443
|
-
* injected faults survived. The one worth reading is in `bucketOf`, whose comment in digest.ts argues at length
|
|
444
|
-
* that the zero boundary is load-bearing. Move that boundary and the suite stays green, because the test holding
|
|
445
|
-
* it is written relationally — `expect(bucketOf(0)).not.toBe(bucketOf(1))` — and with the boundary moved the two
|
|
446
|
-
* values are still different. The careful, un-brittle assertion is precisely the one that cannot see the change.
|
|
447
|
-
*
|
|
448
|
-
* THE FLOOR IS LOW ON PURPOSE. 60% is where Stryker's own default report turns red, and it is far under what a
|
|
449
|
-
* well-tested module scores, because this chore is looking for suites that are decorative rather than suites that
|
|
450
|
-
* are imperfect. A threshold near the good number would badge every honest package in the repo, which is how a
|
|
451
|
-
* maintenance surface teaches people to ignore it. */
|
|
344
|
+
// The only chore whose evidence is about the tests, not the code: a green suite proves a line ran, not that
|
|
345
|
+
// anything depended on what it produced. The floor is set low on purpose, to catch decorative suites, not to grade good
|
|
346
|
+
// ones.
|
|
452
347
|
const MUTATION_FLOOR = 60;
|
|
453
348
|
|
|
454
349
|
const testStrength: Chore = {
|
|
@@ -460,11 +355,8 @@ const testStrength: Chore = {
|
|
|
460
355
|
criterion: `Stryker's mutation score for the repo is under ${MUTATION_FLOOR}%.`,
|
|
461
356
|
stance: `act`,
|
|
462
357
|
needs: [`mutation`],
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
* exactly the number that should have said so. The probe is still the most expensive one here, and
|
|
466
|
-
* `--incremental` is what makes a weekly cadence affordable: the first run costs a full run, every one after it
|
|
467
|
-
* costs the mutants whose code or tests changed. */
|
|
358
|
+
// Weekly: `--incremental` makes this affordable, the first run costs a full run, every one after costs only what
|
|
359
|
+
// changed.
|
|
468
360
|
cadenceMs: 7 * DAY_MS,
|
|
469
361
|
assess: (context) => {
|
|
470
362
|
const facts = factsOf(context, `mutation`);
|
|
@@ -474,13 +366,11 @@ const testStrength: Chore = {
|
|
|
474
366
|
const { score, killed, survived, survivors } = facts.mutation;
|
|
475
367
|
return {
|
|
476
368
|
headline: `${survived} injected faults went unnoticed, ${score}% of them caught`,
|
|
477
|
-
// The survivors themselves, not the score
|
|
478
|
-
//
|
|
369
|
+
// The survivors themselves, not the score; a named line with the change nothing objected to is a morning's
|
|
370
|
+
// work already.
|
|
479
371
|
detail: survivors.map((one) => `${one.file}:${one.line} · ${one.mutator} → ${one.replacement} · survived`),
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
* ride along, so a NEW weak spot appearing speaks even while the number holds steady — which is the
|
|
483
|
-
* case that matters, because that is a test somebody just wrote. */
|
|
372
|
+
// Bucketed so ordinary score drift isn't news; survivors' identities ride along, so a new weak spot speaks
|
|
373
|
+
// even at a steady score.
|
|
484
374
|
digest: digestOf(`bucket:${bucketOf(100 - score)}`, ...survivors.map((one) => `${one.file}:${one.line}`).toSorted()),
|
|
485
375
|
severity: `info`,
|
|
486
376
|
why:
|
|
@@ -498,12 +388,8 @@ const testStrength: Chore = {
|
|
|
498
388
|
done: `Done when every named survivor has either a new assertion that fails without the change, or a one-line note saying why it cannot be observed.`,
|
|
499
389
|
};
|
|
500
390
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
* a coverage statistic
|
|
504
|
-
* and would be one if the rail read it directly. It does not: the digest is the SET of undocumented package
|
|
505
|
-
* directories, so a long-standing backlog goes quiet after it is seen once, and a package appearing that nothing
|
|
506
|
-
* explains is an event that speaks. That is the whole difference between this being useful and being a nag. */
|
|
391
|
+
// Evidence is a package with no README, which is its architecture document here. The digest is the set of
|
|
392
|
+
// undocumented directories, so a long-standing backlog goes quiet after being seen once.
|
|
507
393
|
const documentation: Chore = {
|
|
508
394
|
id: `documentation-refresh`,
|
|
509
395
|
title: `Document what nothing explains`,
|
|
@@ -539,16 +425,9 @@ const documentation: Chore = {
|
|
|
539
425
|
done: `Done when every package you named has a document that a newcomer could use to find the file they need, and no other file changed.`,
|
|
540
426
|
};
|
|
541
427
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
* are genuinely arguable:
|
|
546
|
-
*
|
|
547
|
-
* volatile AND depended-on a hotspot that is also a key module: every edit ripples outward.
|
|
548
|
-
* out of proportion branching three times the median of its own ranking: tangled, not merely busy.
|
|
549
|
-
*
|
|
550
|
-
* Both are relative to the same list the user is reading, so nothing here needs tuning per repository or per
|
|
551
|
-
* language, and a healthy repo produces an empty set rather than a top five. */
|
|
428
|
+
// Reports only the two shapes worth arguing about in a hotspot ranking:
|
|
429
|
+
// - volatile and depended-on: a hotspot that is also a key module, every edit ripples outward.
|
|
430
|
+
// - out of proportion: branching three times the median of its own ranking.
|
|
552
431
|
const COMPLEXITY_MULTIPLE = 3;
|
|
553
432
|
|
|
554
433
|
const median = (values: readonly number[]): number => {
|
|
@@ -571,8 +450,8 @@ const complexity: Chore = {
|
|
|
571
450
|
needs: [],
|
|
572
451
|
cadenceMs: 30 * DAY_MS,
|
|
573
452
|
assess: (context) => {
|
|
574
|
-
// A half-built index ranks whatever it has finished reading,
|
|
575
|
-
//
|
|
453
|
+
// A half-built index ranks whatever it has finished reading, not the repository; better to say nothing than
|
|
454
|
+
// target the wrong file.
|
|
576
455
|
if (!context.signals.indexed || context.signals.hotspots.length === 0) {
|
|
577
456
|
return undefined;
|
|
578
457
|
}
|
|
@@ -605,11 +484,7 @@ const complexity: Chore = {
|
|
|
605
484
|
done: `Done when \`iq hotspots\` reports materially fewer branch points for that file, the repository's checks pass, and no importer changed meaning.`,
|
|
606
485
|
};
|
|
607
486
|
|
|
608
|
-
|
|
609
|
-
* are a fact about the day this file was last edited rather than a live feed. That is the right trade for a
|
|
610
|
-
* signal that moves twice a year and must work on a box with no outbound access, but it does mean this table is
|
|
611
|
-
* maintenance in its own right, and a major missing from it reads as "not end-of-life", which is the safe way to
|
|
612
|
-
* be wrong. Source: nodejs/Release. */
|
|
487
|
+
// A static table, current only as of this file's last edit; no network call. Source: nodejs/Release.
|
|
613
488
|
const NODE_EOL: Readonly<Record<number, string>> = {
|
|
614
489
|
16: `2023-09-11`,
|
|
615
490
|
18: `2025-04-30`,
|
|
@@ -617,8 +492,7 @@ const NODE_EOL: Readonly<Record<number, string>> = {
|
|
|
617
492
|
22: `2027-04-30`,
|
|
618
493
|
24: `2028-04-30`,
|
|
619
494
|
};
|
|
620
|
-
// How far ahead of
|
|
621
|
-
// work, telling someone the day security patches stop is telling them too late to do anything but scramble.
|
|
495
|
+
// How far ahead of end-of-life the chore starts speaking; a quarter, since moving a runtime is planned work.
|
|
622
496
|
const EOL_HORIZON_MS = 90 * DAY_MS;
|
|
623
497
|
|
|
624
498
|
const runtime: Chore = {
|
|
@@ -644,7 +518,7 @@ const runtime: Chore = {
|
|
|
644
518
|
}
|
|
645
519
|
const past = context.nowMs >= eolMs;
|
|
646
520
|
const days = Math.round(Math.abs(eolMs - context.nowMs) / DAY_MS);
|
|
647
|
-
// Which packages would have to be argued with, so the finding names the work
|
|
521
|
+
// Which packages would have to be argued with, so the finding names the work, not just the fact.
|
|
648
522
|
const pinned = context.signals.packages.filter((entry) => entry.engines?.[`node`] !== undefined);
|
|
649
523
|
return {
|
|
650
524
|
headline: past
|
|
@@ -655,7 +529,7 @@ const runtime: Chore = {
|
|
|
655
529
|
`end of life · ${eol}`,
|
|
656
530
|
...pinned.map((entry) => `pinned · ${entry.name} requires node ${entry.engines?.[`node`] ?? ``}`),
|
|
657
531
|
],
|
|
658
|
-
// The state, not the date: a countdown would mint a new digest every single day
|
|
532
|
+
// The state, not the date: a countdown would mint a new digest, and badge, every single day.
|
|
659
533
|
digest: digestOf(`node:${major}`, past ? `eol` : `approaching`),
|
|
660
534
|
severity: past ? `warning` : `info`,
|
|
661
535
|
why:
|
|
@@ -671,11 +545,8 @@ const runtime: Chore = {
|
|
|
671
545
|
done: `Done when the pins name a supported release, the repository's type-check and tests pass on it, and anything needing a rebuild is named as such.`,
|
|
672
546
|
};
|
|
673
547
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
* somebody added the second one without removing the first, both are now in the bundle, and new code picks
|
|
677
|
-
* whichever the neighbouring file used. The table below is deliberately short and only names categories where
|
|
678
|
-
* having two is genuinely a mistake, not, say, two test runners, which is an ordinary migration. */
|
|
548
|
+
// Evidence for a question usually asked as a vibe: two libraries solving the same problem is a fact, not an
|
|
549
|
+
// opinion. The table is short, naming only categories where having two is a genuine mistake, not an ordinary migration.
|
|
679
550
|
const CATEGORIES: readonly { readonly category: string; readonly members: readonly string[] }[] = [
|
|
680
551
|
{ category: `date handling`, members: [`moment`, `dayjs`, `date-fns`, `luxon`, `js-joda`] },
|
|
681
552
|
{ category: `HTTP clients`, members: [`axios`, `got`, `node-fetch`, `superagent`, `undici`, `request`] },
|
|
@@ -724,61 +595,31 @@ const libraries: Chore = {
|
|
|
724
595
|
done: `Done when every overlapping pair has a recommendation with a call-site count behind it, or a reason the overlap is fine.`,
|
|
725
596
|
};
|
|
726
597
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
* probe, and split across the reading order in CHORES, since where a row belongs is decided by what KIND of
|
|
731
|
-
* finding it is, not by which file paragraph it was written in.
|
|
732
|
-
*
|
|
733
|
-
* They gate on `shape.deps` rather than on `signals.packages`, and that is not interchangeable. `packages` is
|
|
734
|
-
* populated from pnpm-workspace.yaml, so it is EMPTY for a repository that is not a monorepo, which is what a
|
|
735
|
-
* Vite app, a Next app and an Angular CLI project all are. A framework gate reading it would be permanently dark
|
|
736
|
-
* in the overwhelming majority of the repositories these four were written for, and dark silently: the chores
|
|
737
|
-
* would not appear, the footer would say the repository has no packages, and nothing would look broken.
|
|
738
|
-
*
|
|
739
|
-
* All four also say something the rest of the book does not have to. A component, a class name and a bundle chunk
|
|
740
|
-
* are things nobody sees the whole of, you read one component at a time, and the tenth copy of a button looks
|
|
741
|
-
* exactly like the first nine did. That is the same argument the whole surface rests on, just further from the
|
|
742
|
-
* places a compiler will ever help. */
|
|
598
|
+
// Four chores that only exist where a UI framework does; gated on `shape.deps`, not `signals.packages` (empty
|
|
599
|
+
// for a non-monorepo app, which would leave the gate permanently and silently dark). All four catch things nobody sees
|
|
600
|
+
// the whole of at once: a component, a class name, a bundle chunk.
|
|
743
601
|
|
|
744
|
-
// How many rows
|
|
745
|
-
//
|
|
602
|
+
// How many evidence rows a UI finding lists before it is a wall, not a list; the standing count still leads the
|
|
603
|
+
// headline.
|
|
746
604
|
const DETAIL_LIMIT = 8;
|
|
747
605
|
|
|
748
606
|
const FRAMEWORK_LABELS = UI_FRAMEWORKS.map((framework) => framework.label).join(`, `);
|
|
749
607
|
|
|
750
|
-
// One gate, one cause, four chores
|
|
751
|
-
// stale
|
|
608
|
+
// One gate, one cause, four chores; built from the framework table so a framework added to stack.ts can't leave
|
|
609
|
+
// a stale name behind in the reason.
|
|
752
610
|
const needsFramework = (signals: ChoreSignals): string | undefined =>
|
|
753
611
|
frameworksOf(signals.shape.deps).length > 0 ? undefined : `no ${FRAMEWORK_LABELS}`;
|
|
754
612
|
|
|
755
613
|
const bytesLabel = (bytes: number): string => (bytes >= 1024 * 1024 ? `${(bytes / (1024 * 1024)).toFixed(1)} MB` : `${Math.round(bytes / 1024)} kB`);
|
|
756
614
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
*
|
|
760
|
-
* The criterion is a SHARE, and that is deliberate, it is the second exception to the book's leader-relative
|
|
761
|
-
* rule, and it earns the same defence duplication's 5% does. A byte threshold would need a different value for a
|
|
762
|
-
* marketing page and an IDE, would be argued about forever, and would be wrong the moment either one grew. "One
|
|
763
|
-
* chunk is more than half of everything you ship" needs no calibration: it says the build is not split, which is
|
|
764
|
-
* true or false at any size. A well-split app has its largest chunk well under this whatever it weighs, and a
|
|
765
|
-
* small app that genuinely is one chunk trips it and is right to, that IS its entire download.
|
|
766
|
-
*
|
|
767
|
-
* Report-stance. Where the split boundaries go is a routing and product decision, and an agent that lazily
|
|
768
|
-
* imported things unattended at three in the morning would be making it. */
|
|
615
|
+
// The criterion is a share of total size, not a byte threshold, since a byte value would need a different number
|
|
616
|
+
// per app. Report-stance: where to split is a product decision no unattended agent should make.
|
|
769
617
|
const BUNDLE_SHARE_FLOOR = 50;
|
|
770
|
-
// Below this there is no ranking to be an outlier in
|
|
771
|
-
// divided, and the largest of them is over half by arithmetic rather than by fault.
|
|
618
|
+
// Below this there is no ranking to be an outlier in; the largest asset is over half by arithmetic, not by fault.
|
|
772
619
|
const BUNDLE_MIN_ASSETS = 3;
|
|
773
620
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
* Without this the digest changes on every single build, because a content hash changing is the entire point of a
|
|
777
|
-
* content hash. The chore would badge after every `pnpm build` while reporting nothing new, which is precisely
|
|
778
|
-
* the lit-every-day failure the digest exists to prevent.
|
|
779
|
-
*
|
|
780
|
-
* Eight or more characters containing a digit, immediately before the final extension: long enough to leave
|
|
781
|
-
* `vendor-react.js` and `.min.js` alone, specific enough to catch Vite's `-DlAUqK2U` and webpack's `.9f2a1b0c`. */
|
|
621
|
+
// Strips a build asset's content hash (`vendor-DlAUqK2U.js` → `vendor.js`) so the digest doesn't change on every
|
|
622
|
+
// build; long and specific enough to leave `vendor-react.js` alone but catch Vite's and webpack's hash formats.
|
|
782
623
|
const stableAsset = (path: string): string => path.replace(/[.-](?=[A-Za-z0-9_-]*[0-9])[A-Za-z0-9_-]{8,}(\.[a-z0-9]+)$/, `$1`);
|
|
783
624
|
|
|
784
625
|
const bundleWeight: Chore = {
|
|
@@ -801,8 +642,8 @@ const bundleWeight: Chore = {
|
|
|
801
642
|
if (assets.length < BUNDLE_MIN_ASSETS || totalGzip === 0) {
|
|
802
643
|
return undefined;
|
|
803
644
|
}
|
|
804
|
-
// By
|
|
805
|
-
//
|
|
645
|
+
// By gzip, not raw bytes: what's on disk isn't what crosses the wire, and a compressible asset isn't the
|
|
646
|
+
// download this is about.
|
|
806
647
|
const ranked = assets.toSorted((left, right) => right.gzip - left.gzip);
|
|
807
648
|
const largest = ranked[0];
|
|
808
649
|
if (largest === undefined) {
|
|
@@ -817,8 +658,8 @@ const bundleWeight: Chore = {
|
|
|
817
658
|
detail: ranked
|
|
818
659
|
.slice(0, DETAIL_LIMIT)
|
|
819
660
|
.map((asset) => `${bytesLabel(asset.gzip)} gzipped · ${asset.path} (${bytesLabel(asset.bytes)} on disk)`),
|
|
820
|
-
// The bucketed total and
|
|
821
|
-
//
|
|
661
|
+
// The bucketed total and hash-stripped identities of the biggest chunks; a rebuild of the same code stays
|
|
662
|
+
// silent, a new heavy chunk doesn't.
|
|
822
663
|
digest: digestOf(
|
|
823
664
|
`total:${bucketOf(totalGzip)}`,
|
|
824
665
|
...ranked
|
|
@@ -826,7 +667,7 @@ const bundleWeight: Chore = {
|
|
|
826
667
|
.map((asset) => stableAsset(asset.path))
|
|
827
668
|
.toSorted(),
|
|
828
669
|
),
|
|
829
|
-
// Not a risk being carried, however large
|
|
670
|
+
// Not a risk being carried, however large; `warning` is reserved for something with a clock on it.
|
|
830
671
|
severity: `info`,
|
|
831
672
|
why:
|
|
832
673
|
`The build output in ${dir}/ of ${repoLabel(context.repo)} is ${bytesLabel(totalGzip)} gzipped across ` +
|
|
@@ -847,14 +688,8 @@ const bundleWeight: Chore = {
|
|
|
847
688
|
done: `Done when every recommendation names a specific import boundary and the bytes it would move out of the first download.`,
|
|
848
689
|
};
|
|
849
690
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
*
|
|
853
|
-
* The digest is the one place this chore differs in shape from its neighbours, and it has to. Digesting the file
|
|
854
|
-
* identities, the way the documentation chore does, would re-badge every time anyone touched any of two hundred
|
|
855
|
-
* files, because a migration in progress is a set that changes constantly. So it digests the BUCKETED COUNT per
|
|
856
|
-
* idiom instead: a kind of legacy code appearing where there was none speaks, real progress through a bucket
|
|
857
|
-
* speaks, and one more file drifting in or out of a set of two hundred does not. */
|
|
691
|
+
// Digests the bucketed count per idiom, not file identities: a migration in progress is a set that changes
|
|
692
|
+
// constantly, so a new kind of legacy code appearing, or real progress through a bucket, is what speaks.
|
|
858
693
|
const frameworkIdiom: Chore = {
|
|
859
694
|
id: `framework-idiom`,
|
|
860
695
|
title: `Finish the framework migrations`,
|
|
@@ -871,18 +706,9 @@ const frameworkIdiom: Chore = {
|
|
|
871
706
|
if (facts === undefined) {
|
|
872
707
|
return undefined;
|
|
873
708
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
* AN IDIOM THIS BUILD HAS NEVER HEARD OF. The daemon composes the sweep from its own copy of the table, so
|
|
878
|
-
* a sandbox image ahead of the browser can report a rule that has no label or replacement here, and a row
|
|
879
|
-
* saying "42 files use react-foo" with no idea what to do about them is worse than no row.
|
|
880
|
-
*
|
|
881
|
-
* AN IDIOM BELONGING TO A FRAMEWORK THIS REPOSITORY DOES NOT USE. A probe's command is a fixed string, so
|
|
882
|
-
* every rule in the table is swept in every repository, and an Angular pattern gets its chance in a Vue
|
|
883
|
-
* codebase: `RouterModule.forRoot` inside a comment, a `*ngIf` in an example string, and, the case that
|
|
884
|
-
* caught this, the book's own rule table quoting its own patterns back at it. What the repository
|
|
885
|
-
* DECLARES is the arbiter, the same `deps` the gate above reads. */
|
|
709
|
+
// Drops rules for two cases: an idiom this build's daemon doesn't know about (a sandbox ahead of the browser),
|
|
710
|
+
// and an idiom belonging to a framework this repository doesn't declare using (a probe scans every rule
|
|
711
|
+
// everywhere).
|
|
886
712
|
const frameworks = new Set(frameworksOf(context.signals.shape.deps).map((framework) => framework.id));
|
|
887
713
|
const found = facts.scan.idioms.flatMap(({ id, files }) => {
|
|
888
714
|
const rule = idiomRule(id);
|
|
@@ -917,21 +743,9 @@ const frameworkIdiom: Chore = {
|
|
|
917
743
|
done: `Done when a re-scan reports fewer files on that idiom, the repository's type-check and tests pass, and every file you skipped has a one-line reason.`,
|
|
918
744
|
};
|
|
919
745
|
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
* code and neither knows the other exists.
|
|
924
|
-
*
|
|
925
|
-
* TWO KINDS OF EVIDENCE, and they catch opposite failures. A NAME FAMILY catches components that were written
|
|
926
|
-
* separately and never shared a line, `BaseButton.vue` and `ButtonV2.tsx` reduce to the same stem, and no clone
|
|
927
|
-
* detector will ever connect them. A CLONE PAIR catches the reverse: two components with unrelated names doing
|
|
928
|
-
* the same work, which is what jscpd is actually good at, filtered to the pairs where both sides are components
|
|
929
|
-
* so it is a finding about the UI rather than a slice of the repo-wide duplication chore.
|
|
930
|
-
*
|
|
931
|
-
* It needs jscpd rather than reading it if present. Half a measurement would let the row claim it had looked for
|
|
932
|
-
* shared logic in a repository where that sweep has never run, the exact "measured and found nothing" lie the
|
|
933
|
-
* `unavailable` state exists to make impossible. jscpd is already running weekly for the duplication chore in any
|
|
934
|
-
* Node repository, so the honest choice is also the free one. */
|
|
746
|
+
// Two kinds of evidence: a name family catches components written separately that never shared a line; a clone
|
|
747
|
+
// pair catches unrelated names doing the same work. Needs jscpd rather than reading it if present, so it never claims
|
|
748
|
+
// to have looked when it hasn't.
|
|
935
749
|
const componentOverlap: Chore = {
|
|
936
750
|
id: `component-overlap`,
|
|
937
751
|
title: `Settle on one component per job`,
|
|
@@ -960,9 +774,8 @@ const componentOverlap: Chore = {
|
|
|
960
774
|
.filter(([, paths]) => paths.length > 1)
|
|
961
775
|
.map(([stem, paths]) => ({ stem, paths: paths.toSorted() }))
|
|
962
776
|
.toSorted((left, right) => right.paths.length - left.paths.length);
|
|
963
|
-
// Only
|
|
964
|
-
//
|
|
965
|
-
// one fact.
|
|
777
|
+
// Only clones with a component on both sides; one shared with a utility module is the duplication chore's
|
|
778
|
+
// finding, not this one.
|
|
966
779
|
const inventory = new Set(ui.scan.components.map(normalizePath));
|
|
967
780
|
const pairs = jscpd.duplication.top.filter(
|
|
968
781
|
(clone) => inventory.has(normalizePath(clone.first)) && inventory.has(normalizePath(clone.second)),
|
|
@@ -980,8 +793,8 @@ const componentOverlap: Chore = {
|
|
|
980
793
|
...families.slice(0, DETAIL_LIMIT).map((family) => `${family.stem} · ${family.paths.join(`, `)}`),
|
|
981
794
|
...pairs.map((clone) => `${clone.lines} shared lines · ${normalizePath(clone.first)} ↔ ${normalizePath(clone.second)}`),
|
|
982
795
|
],
|
|
983
|
-
// Identities on both halves: every component
|
|
984
|
-
//
|
|
796
|
+
// Identities on both halves: every component joining or leaving a family, and every clone pair, is a new
|
|
797
|
+
// fact, not drift.
|
|
985
798
|
digest: digestOf(
|
|
986
799
|
...families.map((family) => `${family.stem}:${family.paths.join(`+`)}`).toSorted(),
|
|
987
800
|
...pairs.map((clone) => `${normalizePath(clone.first)}|${normalizePath(clone.second)}`).toSorted(),
|
|
@@ -1011,15 +824,8 @@ const componentOverlap: Chore = {
|
|
|
1011
824
|
done: `Done when every group has either a component to keep with a call-site count, a shared unit to extract with a home, or a reason it is fine.`,
|
|
1012
825
|
};
|
|
1013
826
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
* spells the bypass out loud, `bg-[#3b82f6]` is the palette being stepped around, in the markup, in a form no
|
|
1017
|
-
* reviewer can miss and no linter mentions.
|
|
1018
|
-
*
|
|
1019
|
-
* Deliberately NOT every arbitrary value. `grid-cols-[1fr_auto]` is the feature working as intended and there is
|
|
1020
|
-
* no token it should have been; matching those would make this an objection to Tailwind rather than a finding
|
|
1021
|
-
* about this repository. Only colours and pixel sizes, which are the two things the theme definitely already has
|
|
1022
|
-
* an answer for. */
|
|
827
|
+
// Only colours and pixel sizes, not every arbitrary value (`grid-cols-[1fr_auto]` is the feature working as
|
|
828
|
+
// intended); those are the two things the theme already has an answer for.
|
|
1023
829
|
const tailwindBypass: Chore = {
|
|
1024
830
|
id: `tailwind-arbitrary-values`,
|
|
1025
831
|
title: `Put hard-coded styles back on the scale`,
|
|
@@ -1045,9 +851,8 @@ const tailwindBypass: Chore = {
|
|
|
1045
851
|
return {
|
|
1046
852
|
headline: `${plural(total, `hard-coded value`)} across ${plural(bypasses.length, `file`)}`,
|
|
1047
853
|
detail: worst.map((entry) => `${entry.path} · ${plural(entry.count, `value`)}`),
|
|
1048
|
-
//
|
|
1049
|
-
//
|
|
1050
|
-
// markup and neither is worth interrupting somebody about.
|
|
854
|
+
// Worst files by identity lead; the spread and total ride along bucketed, since both drift by one with
|
|
855
|
+
// every markup edit.
|
|
1051
856
|
digest: digestOf(...worst.map((entry) => entry.path).toSorted(), `files:${bucketOf(bypasses.length)}`, `total:${bucketOf(total)}`),
|
|
1052
857
|
severity: `info`,
|
|
1053
858
|
why:
|
|
@@ -1069,23 +874,9 @@ const tailwindBypass: Chore = {
|
|
|
1069
874
|
done: `Done when a re-scan reports fewer hard-coded values, nothing renders differently, and every value you left has a one-line reason.`,
|
|
1070
875
|
};
|
|
1071
876
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
* because it has not been done in a quarter, which is a claim the panel can show and the reader can check.
|
|
1076
|
-
*
|
|
1077
|
-
* All of them are report-stance. A survey that starts editing is the most surprising thing this surface could do,
|
|
1078
|
-
* and none of them has a specific enough finding to justify a diff.
|
|
1079
|
-
*
|
|
1080
|
-
* A SURVEY NEEDS ITS `applies` GATE MORE THAN A MEASURED CHORE DOES, not less, and this is the trap the shape of
|
|
1081
|
-
* the thing sets. A measured chore is gated by its own evidence for free: no undocumented packages, no finding,
|
|
1082
|
-
* no row. A survey has no evidence to be absent, "90 days have passed" is true of every repository in the
|
|
1083
|
-
* world, so without a gate it fires everywhere, forever, including in the repositories where its subject does
|
|
1084
|
-
* not exist. "Re-read the documentation against the code" in a repository with no documentation is the exact
|
|
1085
|
-
* failure, and it is not a hypothetical: it is what this helper did before the gate existed.
|
|
1086
|
-
*
|
|
1087
|
-
* An options object rather than the eight positional arguments this grew into: `id, title, icon, description,
|
|
1088
|
-
* diagnosis, goal, done, 90` reads as nothing at all at the call site, and the gate would have made it nine. */
|
|
877
|
+
// Chores with no measurement at all, triggered by the calendar; the ledger is what makes that trigger honest.
|
|
878
|
+
// All are report-stance. `applies` matters more here than for a measured chore: a survey has no evidence to be absent,
|
|
879
|
+
// so an ungated one fires everywhere, forever.
|
|
1089
880
|
interface SurveySpec {
|
|
1090
881
|
readonly id: string;
|
|
1091
882
|
readonly title: string;
|
|
@@ -1095,9 +886,8 @@ interface SurveySpec {
|
|
|
1095
886
|
readonly goal: string;
|
|
1096
887
|
readonly done: string;
|
|
1097
888
|
readonly cadenceDays: number;
|
|
1098
|
-
// What must exist
|
|
1099
|
-
//
|
|
1100
|
-
// say so out loud, with `() => undefined`.
|
|
889
|
+
// What must exist for this review to have a subject; required, not optional, since a survey that applies everywhere
|
|
890
|
+
// must say so explicitly.
|
|
1101
891
|
readonly applies: (signals: ChoreSignals) => string | undefined;
|
|
1102
892
|
}
|
|
1103
893
|
|
|
@@ -1106,9 +896,8 @@ const survey = ({ id, title, icon, description, diagnosis, goal, done, cadenceDa
|
|
|
1106
896
|
title,
|
|
1107
897
|
icon,
|
|
1108
898
|
description,
|
|
1109
|
-
// Not a
|
|
1110
|
-
//
|
|
1111
|
-
// them to it in both directions.
|
|
899
|
+
// Not a SurveySpec parameter: a survey has no measurement, so "due because it has been that long" is the surveying
|
|
900
|
+
// kind.
|
|
1112
901
|
kind: `surveying`,
|
|
1113
902
|
criterion: `${cadenceDays} days have passed since this review was last run.`,
|
|
1114
903
|
applies,
|
|
@@ -1116,8 +905,7 @@ const survey = ({ id, title, icon, description, diagnosis, goal, done, cadenceDa
|
|
|
1116
905
|
needs: [],
|
|
1117
906
|
cadenceMs: cadenceDays * DAY_MS,
|
|
1118
907
|
survey: true,
|
|
1119
|
-
// A survey's evidence is that time
|
|
1120
|
-
// quarter, and a run inside that quarter settles it until the next one begins.
|
|
908
|
+
// A survey's evidence is that time passed, so the digest is the period it is due for: one badge per cadence window.
|
|
1121
909
|
assess: (context) => ({
|
|
1122
910
|
headline: `Not surveyed in ${cadenceDays} days`,
|
|
1123
911
|
detail: [`Cadence · every ${cadenceDays} days`],
|
|
@@ -1130,9 +918,8 @@ const survey = ({ id, title, icon, description, diagnosis, goal, done, cadenceDa
|
|
|
1130
918
|
done,
|
|
1131
919
|
});
|
|
1132
920
|
|
|
1133
|
-
// Below this a
|
|
1134
|
-
//
|
|
1135
|
-
// scaffold that is mostly config and lockfiles does not pass it by accident.
|
|
921
|
+
// Below this a repo is too small for cross-cutting patterns to have diverged; counted in indexed files so a config-only
|
|
922
|
+
// scaffold doesn't pass by accident.
|
|
1136
923
|
const PATTERNS_FLOOR = 25;
|
|
1137
924
|
|
|
1138
925
|
const patterns = survey({
|
|
@@ -1148,8 +935,8 @@ const patterns = survey({
|
|
|
1148
935
|
`estimate the size of the conversion. Do not convert anything.`,
|
|
1149
936
|
done: `Done when each concern has a named convention, a reference file, and a count of the sites that diverge from it.`,
|
|
1150
937
|
cadenceDays: 90,
|
|
1151
|
-
// The one cause that is a measurement
|
|
1152
|
-
//
|
|
938
|
+
// The one cause that is a measurement, not an absence; every size-gated chore uses this same string so they group
|
|
939
|
+
// together.
|
|
1153
940
|
applies: (signals) => (signals.totals.files >= PATTERNS_FLOOR ? undefined : `only ${signals.totals.files} indexed files`),
|
|
1154
941
|
});
|
|
1155
942
|
|
|
@@ -1169,15 +956,8 @@ const deprecated = survey({
|
|
|
1169
956
|
applies: (signals) => (signals.shape.packageManifest ? undefined : `no package.json`),
|
|
1170
957
|
});
|
|
1171
958
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
* re-read, and the first thing an owner of a fresh workspace sees is an offer to re-read documentation they have
|
|
1175
|
-
* never written. That is not a chore being wrong about a threshold, it is the surface admitting it never looked.
|
|
1176
|
-
*
|
|
1177
|
-
* Note which fact it gates on: the MAP, not the directory. An empty `docs/architecture/` is a directory somebody
|
|
1178
|
-
* made and never filled, and a gate on the directory would put the chore back exactly where it started. The
|
|
1179
|
-
* survey then reads the package READMEs too, they are the package pages, but a repo with no map has not been
|
|
1180
|
-
* documented at all, and that is the case worth staying quiet for. */
|
|
959
|
+
// Gated on the docs map existing, not the directory: an empty docs/architecture/ is undocumented too. Also
|
|
960
|
+
// reads the package READMEs, but a repo with no map hasn't been documented at all.
|
|
1181
961
|
const documentationDrift = survey({
|
|
1182
962
|
id: `documentation-drift`,
|
|
1183
963
|
title: `Re-read the documentation against the code`,
|
|
@@ -1193,12 +973,8 @@ const documentationDrift = survey({
|
|
|
1193
973
|
applies: (signals) => (signals.shape.docs.length > 0 ? undefined : `no architecture documents`),
|
|
1194
974
|
});
|
|
1195
975
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
* to find out would be a strange thing for a maintenance panel to do, so both are gated on the artefact itself.
|
|
1199
|
-
* Together they are the argument for `applies` being first-class rather than folded into `assess`: neither has
|
|
1200
|
-
* any evidence to be absent, and in a repository with no pipeline and no image both would otherwise sit in the
|
|
1201
|
-
* list forever, permanently due, describing work that cannot be done. */
|
|
976
|
+
// Both surveys, since nothing here can measure pipeline caching or image bloat without running them; gated on
|
|
977
|
+
// the artefact itself so a repo with neither doesn't sit permanently due.
|
|
1202
978
|
const pipelines = survey({
|
|
1203
979
|
id: `ci-hygiene`,
|
|
1204
980
|
title: `Tighten the CI pipeline`,
|
|
@@ -1231,25 +1007,9 @@ const images = survey({
|
|
|
1231
1007
|
applies: (signals) => (signals.shape.dockerfiles.length > 0 ? undefined : `no Dockerfile`),
|
|
1232
1008
|
});
|
|
1233
1009
|
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
*
|
|
1238
|
-
* This used to be a comment above a hand-sorted array, the four kinds named in prose, the order maintained by
|
|
1239
|
-
* whoever added the last chore, and nothing anywhere that could check the two agreed. It was also thrown away at
|
|
1240
|
-
* render: the panel listed every chore in one flat column, so the single editorial claim this surface makes
|
|
1241
|
-
* ("a live advisory and a quarterly re-read are not the same kind of thing") was invisible and therefore
|
|
1242
|
-
* unarguable, on a page whose whole design is that every claim shows its working.
|
|
1243
|
-
*
|
|
1244
|
-
* So the kinds are data. They order the book here, they group the rows in the panel, and `caption` is the
|
|
1245
|
-
* sentence the panel puts beside each group so the grouping argues for itself.
|
|
1246
|
-
*
|
|
1247
|
-
* Ordering is by KIND, not by whether a given repository will see them: a chore that does not apply is dropped
|
|
1248
|
-
* from that repository's list entirely (verdict.ts), so the reading order never has holes in it. It is also why
|
|
1249
|
-
* a block of chores written together does not READ together: the front-end four are one paragraph in this file
|
|
1250
|
-
* because they share a gate and a probe, and `kind` is what puts a Vue repository's bundle row next to its
|
|
1251
|
-
* dependency row rather than in a "front-end" section at the bottom. Where a chore is written and where it is
|
|
1252
|
-
* ranked are two separate facts, and only one of them is a product decision. */
|
|
1010
|
+
// The panel's reading order, as data rather than a hand-sorted array: `kind` orders the book and groups the
|
|
1011
|
+
// panel's rows, `caption` argues for the grouping. Ordered by kind, not by which repository will see them; a
|
|
1012
|
+
// non-applicable chore is dropped entirely, so the order never has holes.
|
|
1253
1013
|
export interface ChoreKindSpec {
|
|
1254
1014
|
readonly kind: ChoreKind;
|
|
1255
1015
|
// Title case, because the panel renders it as a group heading rather than as a sentence.
|
|
@@ -1265,8 +1025,8 @@ export const CHORE_KINDS: readonly ChoreKindSpec[] = [
|
|
|
1265
1025
|
{ kind: `surveying`, label: `Surveying`, caption: `periodic reads with nothing measuring them, due because it has been that long` },
|
|
1266
1026
|
];
|
|
1267
1027
|
|
|
1268
|
-
// Declaration order
|
|
1269
|
-
//
|
|
1028
|
+
// Declaration order decides nothing but order within a kind (the sort below is stable); this is where a chore
|
|
1029
|
+
// is written, CHORE_KINDS is where it is ranked.
|
|
1270
1030
|
const BOOK: readonly Chore[] = [
|
|
1271
1031
|
security,
|
|
1272
1032
|
runtime,
|
|
@@ -1290,20 +1050,17 @@ const BOOK: readonly Chore[] = [
|
|
|
1290
1050
|
|
|
1291
1051
|
const KIND_ORDER: readonly ChoreKind[] = CHORE_KINDS.map(({ kind }) => kind);
|
|
1292
1052
|
|
|
1293
|
-
// Sorted
|
|
1294
|
-
//
|
|
1053
|
+
// Sorted, not filtered into groups, so a kind missing from the list above sorts to the front, visible, instead of
|
|
1054
|
+
// vanishing.
|
|
1295
1055
|
export const CHORES: readonly Chore[] = BOOK.toSorted((left, right) => KIND_ORDER.indexOf(left.kind) - KIND_ORDER.indexOf(right.kind));
|
|
1296
1056
|
|
|
1297
1057
|
export const choreById = (id: string): Chore | undefined => CHORES.find((chore) => chore.id === id);
|
|
1298
1058
|
|
|
1299
|
-
// The prompt for one chore
|
|
1300
|
-
//
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
*
|
|
1305
|
-
* Workspace-wide rather than per repository: an automation's guard runs at the workspace root on the sandbox's
|
|
1306
|
-
* clock, and it has no repo argument to be scoped by. */
|
|
1059
|
+
// The prompt for one chore, built here rather than in the view, so the panel, the badge's tooltip and an
|
|
1060
|
+
// unattended automation all describe the same turn.
|
|
1061
|
+
// Same four parts as a finding-driven turn, with the guard's own report standing in for the finding, since at
|
|
1062
|
+
// 3am there is no verdict to quote. Workspace-wide: an automation's guard runs at the root with no repo argument to
|
|
1063
|
+
// scope it.
|
|
1307
1064
|
export const choreAutomationPrompt = (chore: Chore): string | undefined =>
|
|
1308
1065
|
chore.automation === undefined
|
|
1309
1066
|
? undefined
|
|
@@ -1319,9 +1076,8 @@ export const choreAutomationPrompt = (chore: Chore): string | undefined =>
|
|
|
1319
1076
|
export const chorePrompt = (chore: Chore, finding: ChoreFinding, repo: string): string =>
|
|
1320
1077
|
composeAsk({
|
|
1321
1078
|
subject: `${chore.title} in ${repoLabel(repo)}.`,
|
|
1322
|
-
// The
|
|
1323
|
-
//
|
|
1324
|
-
// useful thing a chore turn can report back, and the only way the book gets better.
|
|
1079
|
+
// The rule before the numbers: an agent told the criterion, not just the count, can report that the criterion
|
|
1080
|
+
// itself was wrong.
|
|
1325
1081
|
why: `${finding.why} You were woken because: ${chore.criterion} ${TRIAGE_NOTE}`,
|
|
1326
1082
|
diagnosis: chore.diagnosis,
|
|
1327
1083
|
goal: chore.goal,
|