total-recall-brain 3.45.0 → 3.46.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/bin/total-recall.mjs +4 -2
- package/frontend/dist/assets/index-BRYE1jmv.css +1 -0
- package/frontend/dist/assets/index-D1goIPjC.js +5598 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/dist/sw.js +5 -4
- package/frontend/src/App.tsx +183 -236
- package/frontend/src/api/auth-inventory.ts +62 -0
- package/frontend/src/api/memory.ts +13 -8
- package/frontend/src/api/plugin-credentials.ts +23 -0
- package/frontend/src/api/plugins.ts +37 -53
- package/frontend/src/api/workspace-drawers.ts +97 -0
- package/frontend/src/components/BrainSelector.tsx +9 -3
- package/frontend/src/components/plugins/PluginPanel.tsx +83 -42
- package/frontend/src/components/plugins/PluginSettings.tsx +10 -20
- package/frontend/src/components/plugins/PluginWorkspace.tsx +367 -0
- package/frontend/src/components/plugins/ScopedPluginCommands.tsx +142 -0
- package/frontend/src/components/plugins/plugin-frame.ts +44 -33
- package/frontend/src/components/plugins/scoped-plugin-operations.ts +28 -0
- package/frontend/src/components/workspace/DrawerChat.tsx +110 -0
- package/frontend/src/components/workspace/DrawerLayout.tsx +196 -0
- package/frontend/src/components/workspace/DrawerMarkup.tsx +49 -0
- package/frontend/src/components/workspace/PluginChunkLibrary.tsx +92 -0
- package/frontend/src/components/workspace/PluginHome.tsx +76 -0
- package/frontend/src/components/workspace/WorkspaceDrawers.tsx +96 -0
- package/frontend/src/components/workspace/WorkspacePage.tsx +95 -0
- package/frontend/src/components/workspace/usePluginDesign.ts +38 -0
- package/frontend/src/index.css +409 -136
- package/frontend/src/pages/HelpPage.tsx +15 -46
- package/frontend/src/pages/MemoryPage.tsx +19 -36
- package/frontend/src/pages/SettingsPage.tsx +1 -1
- package/metadata.plugin.schema.json +53 -227
- package/package.json +1 -1
- package/scaffold/.agent/skills/plugin/SKILL.md +13 -11
- package/scaffold/.agent/skills/plugin/evals/README.md +14 -21
- package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +15 -18
- package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +19 -24
- package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +12 -20
- package/scaffold/.agent/skills/plugin/evals/cases/04-home-collects-credential.mjs +35 -0
- package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +8 -28
- package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +85 -47
- package/scaffold/.agent/skills/plugin/evals/run.mjs +17 -18
- package/scaffold/.agent/skills/plugin/prompts/05-credentials.md +4 -4
- package/scaffold/.agent/skills/plugin/prompts/07-scaffold.md +2 -2
- package/scaffold/.agent/skills/plugin/prompts/08-verify.md +4 -4
- package/scaffold/.agent/skills/plugin/references/anti-patterns.md +2 -2
- package/scaffold/.agent/skills/plugin/references/generative-home.md +38 -0
- package/scaffold/.agent/skills/plugin/references/scaffold.md +5 -5
- package/scaffold/.agent/skills/plugin/references/surfaces.md +13 -4
- package/scaffold/.agent/skills/plugin/scripts/record.mjs +75 -153
- package/scaffold/.agent/skills/plugin/subagents/plugin-reviewer.md +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/DESIGN.md +76 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +3 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +20 -15
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +13 -51
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/access-overview.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/agent-login.md +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/baseline-audit.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-repository-binding.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-store-maintenance.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-password.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-sessions.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/endpoint-probe.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/google-sign-in.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/mesh-machines.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/passkey-enrollment.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/registered-brains.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/scoped-access-keys.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/secret-inventory.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/signing-key-rotation.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +375 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/{ui/DESIGN.md → DESIGN.md} +32 -21
- package/scaffold/.agent/skills/total-recall/plugins/automations/adapters.mjs +17 -1
- package/scaffold/.agent/skills/total-recall/plugins/automations/cli.mjs +10 -1
- package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +4 -3
- package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +11 -27
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/automations.js +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/control-ledger.md +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/local-inventory-triage.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/pending-control.md +39 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/run-evidence.md +41 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/schedule-vs-run-evidence.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/source-coverage.md +41 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/{card.js → home.js} +32 -27
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/DESIGN.md +53 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/cli.mjs +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/run-core.mjs +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +40 -40
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/config.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/detect.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/gate.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/init.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/report.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/run.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/snapshot.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/code-quality-report.mjs +55 -23
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/home.mjs +214 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/DESIGN.md +146 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +51 -34
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/command.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/create.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/history.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/library.md +49 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/list.md +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/promote.md +40 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/read.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/remove.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/rollback.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/show.md +53 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/status.md +40 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test-path.md +38 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test.md +46 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/update.md +32 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/home.js +533 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/DESIGN.md +110 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +13 -10
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/benchmark.md +49 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/coverage.md +53 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/models.md +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/pull.md +41 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/status.md +59 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/home.js +353 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/DESIGN.md +31 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/README.md +25 -1
- package/scaffold/.agent/skills/total-recall/plugins/git/cli.mjs +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/git/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/git/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +17 -27
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +30 -6
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/fleet.mjs +24 -6
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/secret-firewall.mjs +33 -7
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/undo.mjs +29 -5
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/unmerged.mjs +182 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/change-comparison.md +27 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/commit-identity.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/create-worktree.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/registered-worktrees.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/remove-worktree.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/repository-ledger.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/unmerged-work.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/upstream-divergence.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-conflict-triage.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-terminal.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/home.js +273 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/DESIGN.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +4 -5
- package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +9 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +37 -39
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +5 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/active-device-dispatch.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-probe.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-server.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/credential-readiness.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/elected-leader.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/enrollment-key.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/file-receipt.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-execution.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-presence.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/interactive-ssh.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/local-enrollment.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/mesh-policy.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/network-atlas.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-roster.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-selection-proof.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/owner-observations.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/peer-path.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/pinned-leader.md +24 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/reachability-evidence-ladder.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/recorded-login.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/remote-execution.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/secret-grants.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/{card.js → home.js} +93 -22
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/DESIGN.md +86 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +43 -22
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/chat.mjs +80 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/adapter-docs-freshness.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/chat-handoff.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/fleet-maintenance.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/harness-inventory.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-access.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-usage-verification.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/independent-review.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/managed-execution.md +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/official-documentation.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/quota-recovery.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/review-routing-decision.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/route-work.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/routing-evidence.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/run-ledger.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/home.js +198 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/DESIGN.md +75 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +2 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +17 -14
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +10 -44
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +5 -4
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +3 -4
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/ingest.mjs +23 -18
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +8 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +6 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +3 -5
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +21 -47
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +17 -6
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/auto-refresh.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/bootstrap-pages.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generate-wiki.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generator-settings.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/host-probe.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/ingest-preview.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-hygiene.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-topology.md +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/passage-search.md +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/propagation-plan.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/provider-credentials.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/refresh-report.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/task-evidence.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/upstream-record.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/watch-upstream.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/wiki-atlas.md +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +261 -513
- package/scaffold/.agent/skills/total-recall/plugins/security/DESIGN.md +84 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/README.md +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -19
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +2 -3
- package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +19 -52
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/device-evidence.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/evidence-desk.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/guided-device-review.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/host-and-network.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/https-headers.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/mesh-coverage.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/private-security-tools.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/single-origin-header-check.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/source-review.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/ssh-permission-plan.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/home.js +283 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/DESIGN.md +93 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/package-lock.json +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +5 -3
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/conformance.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/registry.md +37 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/repair.md +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/scaffold.md +33 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/status.md +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validate.md +34 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validation-diagnostics.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/workspace-registry-preflight.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/home.js +348 -0
- package/scaffold/.agent/skills/total-recall/references/operations.md +2 -0
- package/src/cli/api.mjs +3 -3
- package/src/cli/brief.mjs +3 -0
- package/src/cli/config.mjs +16 -0
- package/src/cli/connect.mjs +2 -7
- package/src/cli/plugin/chunks.mjs +145 -0
- package/src/cli/plugin/create.mjs +24 -52
- package/src/cli/plugin/index.mjs +20 -9
- package/src/cli/setup.mjs +2 -9
- package/src/cli/start.mjs +1 -0
- package/src/cli/startup.mjs +18 -0
- package/src/core/app-deploy/design-tokens.mjs +14 -9
- package/src/core/app-deploy/ui-elements.mjs +1 -1
- package/src/core/brain-registry.mjs +5 -0
- package/src/core/brain-updates.mjs +5 -1
- package/src/core/daemon-control.mjs +5 -1
- package/src/core/dashboard-bundle.mjs +261 -0
- package/src/core/ensure-dependencies.mjs +19 -15
- package/src/core/memory-brain.mjs +30 -8
- package/src/core/plugin-activation.mjs +63 -20
- package/src/core/plugin-contracts/{card.mjs → manifest.mjs} +23 -57
- package/src/core/plugin-contracts/startup-check.mjs +49 -0
- package/src/core/plugin-contracts/ui.mjs +9 -3
- package/src/core/plugin-distribution.mjs +6 -6
- package/src/core/plugin-lifecycle.mjs +58 -0
- package/src/core/plugin-loader.mjs +9 -5
- package/src/core/plugin-runner.mjs +21 -10
- package/src/core/plugin-startup-checks.mjs +44 -0
- package/src/core/plugin-state.mjs +19 -5
- package/src/core/plugin-store.mjs +30 -11
- package/src/core/project-id.mjs +15 -5
- package/src/core/required-plugins.mjs +31 -6
- package/src/core/schema.mjs +2 -0
- package/src/core/ssss-operation-service.mjs +1 -0
- package/src/core/startup-health.mjs +28 -3
- package/src/core/testing/plugin-fixture.mjs +22 -21
- package/src/core/throttled-fetch.mjs +25 -18
- package/src/core/ui-chunk-choice.mjs +77 -0
- package/src/core/ui-chunk.registry.json +23 -0
- package/src/core/ui-chunks.mjs +434 -0
- package/src/core/vault-cache.mjs +58 -59
- package/src/core/workspace-compositions.mjs +151 -0
- package/src/core/workspace-drawers.mjs +79 -0
- package/src/server/api.mjs +4 -27
- package/src/server/index.mjs +28 -21
- package/src/server/memory-events.mjs +31 -0
- package/src/server/plugin-brain-targets.mjs +89 -0
- package/src/server/rest.mjs +2 -0
- package/src/server/route-inventory.mjs +3 -2
- package/src/server/route-manifest.json +52 -4
- package/src/server/routes/_shared.mjs +7 -14
- package/src/server/routes/brains.mjs +29 -44
- package/src/server/routes/dashboard.mjs +26 -0
- package/src/server/routes/plugins.mjs +154 -45
- package/src/server/routes/ui-chunks.mjs +192 -0
- package/frontend/dist/assets/index-DACh1dhx.js +0 -5613
- package/frontend/dist/assets/index-DtwsDyFM.css +0 -1
- package/frontend/src/components/plugins/card/CardEngine.tsx +0 -108
- package/frontend/src/components/plugins/card/CardScenes.tsx +0 -103
- package/frontend/src/components/plugins/card/ExecutionPicker.tsx +0 -64
- package/frontend/src/components/plugins/card/args.ts +0 -28
- package/frontend/src/components/plugins/card/card.css +0 -32
- package/frontend/src/components/plugins/card/cli-line.ts +0 -13
- package/frontend/src/components/plugins/card/contract.ts +0 -91
- package/frontend/src/components/plugins/card/format.ts +0 -49
- package/frontend/src/components/plugins/card/runner-context.ts +0 -11
- package/frontend/src/components/plugins/card/runner.tsx +0 -43
- package/frontend/src/components/plugins/card/theme.ts +0 -35
- package/frontend/src/components/plugins/card/use-source.ts +0 -22
- package/frontend/src/components/plugins/card/widgets.tsx +0 -94
- package/frontend/src/components/plugins/workspace/WorkspaceHost.tsx +0 -23
- package/frontend/src/pages/PluginsPage.tsx +0 -1719
- package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +0 -47
- package/scaffold/.agent/skills/plugin/prompts/06-card.md +0 -46
- package/scaffold/.agent/skills/plugin/references/card.md +0 -90
- package/scaffold/.agent/skills/plugin/subagents/card-designer.md +0 -60
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +0 -67
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +0 -1179
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +0 -32
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +0 -588
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +0 -575
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +0 -32
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +0 -482
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/DESIGN.md +0 -100
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/card.js +0 -637
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/DESIGN.md +0 -217
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +0 -32
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +0 -1276
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +0 -45
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +0 -1401
- package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +0 -4
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +0 -41
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +0 -396
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +0 -98
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/DESIGN.md +0 -15
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/card.js +0 -182
|
@@ -2,6 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { failure, gitText, output, trJson } from './_support.mjs';
|
|
5
|
+
import { inspectUnmerged } from './unmerged.mjs';
|
|
5
6
|
|
|
6
7
|
const STALE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
7
8
|
|
|
@@ -23,15 +24,27 @@ export function registeredRepositories(ctx) {
|
|
|
23
24
|
return fallback;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* A registered brain need not be a git repository (personal workspace brains,
|
|
29
|
+
* plain folders); that is not a failure. A registered path that is gone is.
|
|
30
|
+
*/
|
|
31
|
+
export function registeredPathState(directory, ctx) {
|
|
32
|
+
if (!existsSync(directory)) return 'missing';
|
|
33
|
+
const inside = ctx.git(['-C', directory, 'rev-parse', '--is-inside-work-tree']);
|
|
34
|
+
return inside.status === 0 && String(inside.stdout).trim() === 'true' ? 'repository' : 'not-a-repository';
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
export function inspectRepository(directory, ctx, now = Date.now()) {
|
|
27
38
|
const local = { ...ctx, git: (args, options) => ctx.git(['-C', directory, ...args], options) };
|
|
28
39
|
const errors = [];
|
|
29
40
|
const report = { path: directory, dirty: null, unpushed: null, behind: null, diverged: null,
|
|
30
|
-
staleStashes: null, abandonedWorktrees: null, upstream: null, errors };
|
|
41
|
+
staleStashes: null, abandonedWorktrees: null, unmerged: null, upstream: null, errors };
|
|
31
42
|
const get = args => {
|
|
32
43
|
try { return gitText(local, args); } catch { errors.push(args[0]); return null; }
|
|
33
44
|
};
|
|
34
|
-
|
|
45
|
+
const state = registeredPathState(directory, ctx);
|
|
46
|
+
if (state === 'missing') return { ...report, error: 'Registered path does not exist' };
|
|
47
|
+
if (state === 'not-a-repository') return { ...report, notRepository: true };
|
|
35
48
|
const status = get(['status', '--porcelain=v1', '-z']);
|
|
36
49
|
if (status !== null) report.dirty = status.length > 0;
|
|
37
50
|
const upstream = local.git(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}']);
|
|
@@ -63,6 +76,11 @@ export function inspectRepository(directory, ctx, now = Date.now()) {
|
|
|
63
76
|
return !state.stdout && Number(last.stdout.trim()) * 1000 < now - STALE_MS
|
|
64
77
|
? [{ path: fields.worktree, reason: 'clean-with-old-head', candidate: true }] : [];
|
|
65
78
|
});
|
|
79
|
+
// Branches and worktrees holding work the default branch lacks (unmerged.mjs owns the rule).
|
|
80
|
+
try {
|
|
81
|
+
const unmerged = inspectUnmerged(directory, ctx);
|
|
82
|
+
if (unmerged.error) errors.push('unmerged'); else report.unmerged = unmerged.outstanding;
|
|
83
|
+
} catch { errors.push('unmerged'); }
|
|
66
84
|
return report;
|
|
67
85
|
}
|
|
68
86
|
|
|
@@ -90,7 +108,7 @@ function localReport(ctx, commit) {
|
|
|
90
108
|
if (commit) {
|
|
91
109
|
const contains = ctx.git(['-C', directory, 'cat-file', '-e', `${commit}^{commit}`]);
|
|
92
110
|
if (contains.status !== 0) {
|
|
93
|
-
if (
|
|
111
|
+
if (registeredPathState(directory, ctx) === 'missing') errors.push({ path: directory, error: 'Registered path does not exist' });
|
|
94
112
|
continue;
|
|
95
113
|
}
|
|
96
114
|
repositories.push(containingCheckouts(directory, commit, ctx));
|
|
@@ -141,9 +159,9 @@ async function run(args, ctx, where = false) {
|
|
|
141
159
|
if (args.includes('--all-nodes') || where && !args.includes('--local')) nodes.push(...remoteReports(ctx, commit));
|
|
142
160
|
const ok = nodes.every(node => !node.errors?.length);
|
|
143
161
|
const result = { ok, ...(where ? { commit } : {}), nodes };
|
|
144
|
-
const lines = nodes.flatMap(node => [node.node, ...node.repositories.map(repo => where
|
|
162
|
+
const lines = nodes.flatMap(node => [node.node, ...node.repositories.map(repo => repo.notRepository ? ` ${repo.path}: not a git repository` : where
|
|
145
163
|
? ` ${repo.path}: ${repo.checkouts.length} checkouts; ${repo.refs.length} refs`
|
|
146
|
-
: ` ${repo.path}: dirty=${repo.dirty ?? 'unknown'} unpushed=${repo.unpushed ?? 'unknown'} behind=${repo.behind ?? 'unknown'} diverged=${repo.diverged ?? 'unknown'} stale-stashes=${repo.staleStashes?.length ?? 'unknown'} abandoned-worktrees=${repo.abandonedWorktrees?.length ?? 'unknown'}`),
|
|
164
|
+
: ` ${repo.path}: dirty=${repo.dirty ?? 'unknown'} unpushed=${repo.unpushed ?? 'unknown'} behind=${repo.behind ?? 'unknown'} diverged=${repo.diverged ?? 'unknown'} stale-stashes=${repo.staleStashes?.length ?? 'unknown'} abandoned-worktrees=${repo.abandonedWorktrees?.length ?? 'unknown'} unmerged=${repo.unmerged ?? 'unknown'}`),
|
|
147
165
|
...(node.errors || []).map(e => ` unavailable: ${e.path || node.node}`)]);
|
|
148
166
|
output(ctx, result, lines.join('\n'));
|
|
149
167
|
return ok ? 0 : 1;
|
|
@@ -151,6 +169,6 @@ async function run(args, ctx, where = false) {
|
|
|
151
169
|
}
|
|
152
170
|
|
|
153
171
|
export const operations = {
|
|
154
|
-
fleet: { summary: 'Report repository state on this node or every mesh node', usage: 'fleet [--all-nodes] [--json]', run: (args, ctx) => run(args, ctx) },
|
|
172
|
+
fleet: { summary: 'Report repository state (including unmerged branches and worktrees) on this node or every mesh node', usage: 'fleet [--all-nodes] [--json]', run: (args, ctx) => run(args, ctx) },
|
|
155
173
|
where: { summary: 'Find machines and checkouts that contain a commit', usage: 'where <commit> [--local] [--json]', run: (args, ctx) => run(args, ctx, true) },
|
|
156
174
|
};
|
|
@@ -9,12 +9,37 @@ export function scanText(ctx, text) {
|
|
|
9
9
|
const result = spawnSync(ctx.env?.GIT_PLUGIN_TR_BIN || 'total-recall', ['auth', 'secret', 'scan', '--stdin', '--json'], {
|
|
10
10
|
cwd: ctx.cwd, env: ctx.env, input: text, encoding: 'utf8', shell: false, timeout: 120000, maxBuffer: 16 * 1024 * 1024,
|
|
11
11
|
});
|
|
12
|
-
if (result.error
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if (result.error) throw new Error(`auth secret scan could not start (${result.error.code || 'spawn failed'})`);
|
|
13
|
+
if (result.signal) throw new Error(`auth secret scan was stopped (${result.signal})`);
|
|
14
|
+
let reply = null;
|
|
15
|
+
try { reply = JSON.parse(result.stdout); } catch { /* named below; a parse error can quote the output */ }
|
|
16
|
+
if (![0, 1].includes(result.status) || !reply) throw new Error(scanFailure(result));
|
|
17
|
+
if (!Array.isArray(reply.keys)) throw new Error('auth secret scan returned no key list');
|
|
15
18
|
return reply.keys;
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Name why the scan gave no result without forwarding the child's output,
|
|
23
|
+
* which can hold credential material. A generic "could not complete" hid that
|
|
24
|
+
* auth was simply turned off for the repository (2026-11-12).
|
|
25
|
+
*/
|
|
26
|
+
function scanFailure(result) {
|
|
27
|
+
const stderr = String(result.stderr || '');
|
|
28
|
+
if (/Plugin auth is inactive/.test(stderr)) return 'the auth plugin is turned off for this repository; run total-recall plugin on auth';
|
|
29
|
+
if (/Unknown (plugin|command)|not installed/i.test(stderr)) return 'the auth plugin is not installed here or has no secret scan';
|
|
30
|
+
return `auth secret scan exited ${result.status} without a result`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The publishable part of a patch: everything except removed lines. A removed line is content the
|
|
35
|
+
* commit takes out; scanning it blocked the very commit that redacts a secret already in history
|
|
36
|
+
* (a project tracker, 2026-11-12). Added lines, headers, binary patches and the commit message
|
|
37
|
+
* are still scanned, and every staged or outgoing blob is scanned whole.
|
|
38
|
+
*/
|
|
39
|
+
export function publishedPatchText(patch) {
|
|
40
|
+
return String(patch).split('\n').filter((line) => !(line.startsWith('-') && !line.startsWith('---'))).join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
18
43
|
export function checkSecrets(args, ctx) {
|
|
19
44
|
const call = invocation(args, ctx);
|
|
20
45
|
if (!['commit', 'push'].includes(call.command) || helpOnly(args)) return;
|
|
@@ -25,7 +50,7 @@ export function checkSecrets(args, ctx) {
|
|
|
25
50
|
const chunks = [];
|
|
26
51
|
const add = value => chunks.push(Buffer.isBuffer(value) ? value.toString('utf8') : value);
|
|
27
52
|
if (call.command === 'commit') {
|
|
28
|
-
add(gitText(call.ctx, ['diff', '--cached', '--no-ext-diff', '--no-textconv', '--binary', '--']));
|
|
53
|
+
add(publishedPatchText(gitText(call.ctx, ['diff', '--cached', '--no-ext-diff', '--no-textconv', '--binary', '--'])));
|
|
29
54
|
const paths = gitText(call.ctx, ['diff', '--cached', '--name-only', '--diff-filter=ACMRT', '-z', '--']).split('\0').filter(Boolean);
|
|
30
55
|
for (const file of paths) {
|
|
31
56
|
const row = call.ctx.git(['show', `:${file}`], { encoding: null });
|
|
@@ -35,7 +60,7 @@ export function checkSecrets(args, ctx) {
|
|
|
35
60
|
} else {
|
|
36
61
|
const scanned = new Set();
|
|
37
62
|
for (const commit of outgoingCommits(call.ctx, call.args)) {
|
|
38
|
-
add(gitText(call.ctx, ['show', '--format=fuller', '--root', '--no-ext-diff', '--no-textconv', '--binary', commit, '--']));
|
|
63
|
+
add(publishedPatchText(gitText(call.ctx, ['show', '--format=fuller', '--root', '--no-ext-diff', '--no-textconv', '--binary', commit, '--'])));
|
|
39
64
|
// Raw blobs of the files this commit changed: a binary patch does not contain the original bytes.
|
|
40
65
|
const changed = gitText(call.ctx, ['diff-tree', '-r', '-z', '--root', '--no-commit-id', commit]).split('\0').filter(Boolean);
|
|
41
66
|
for (const entry of changed) {
|
|
@@ -58,8 +83,9 @@ export function checkSecrets(args, ctx) {
|
|
|
58
83
|
}
|
|
59
84
|
flush();
|
|
60
85
|
if (matches.size) return { refuse: `Auth secret match: ${[...matches].sort().join(', ')}` };
|
|
61
|
-
} catch {
|
|
62
|
-
|
|
86
|
+
} catch (error) {
|
|
87
|
+
// Our own messages only: git failures and scanFailure never carry file or secret content.
|
|
88
|
+
return { refuse: `Secret firewall could not complete: ${error.message}. Check auth store and repository access.` };
|
|
63
89
|
} finally { prospective?.cleanup(); }
|
|
64
90
|
}
|
|
65
91
|
|
|
@@ -38,6 +38,23 @@ function untrackedSnapshot(ctx, includeIgnored) {
|
|
|
38
38
|
} finally { rmSync(dir, { recursive: true, force: true }); }
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Tracked working-tree content as a commit on HEAD, through a private index. `git stash create`
|
|
43
|
+
* refuses while the index has unmerged paths, which blocked every conflict resolution
|
|
44
|
+
* (`checkout --theirs -- <file>`) with "Cannot save an undo snapshot". This keeps the content;
|
|
45
|
+
* an undo restores the files, not the merge state itself.
|
|
46
|
+
*/
|
|
47
|
+
function trackedSnapshot(ctx) {
|
|
48
|
+
const dir = mkdtempSync(path.join(os.tmpdir(), 'git-undo-tracked-'));
|
|
49
|
+
const env = { ...objectEnv(ctx), GIT_INDEX_FILE: path.join(dir, 'index') };
|
|
50
|
+
try {
|
|
51
|
+
gitText(ctx, ['read-tree', 'HEAD'], { env });
|
|
52
|
+
gitText(ctx, ['add', '--update', '--', '.'], { env });
|
|
53
|
+
const tree = gitText(ctx, ['write-tree'], { env }).trim();
|
|
54
|
+
return gitText(ctx, ['commit-tree', tree, '-p', 'HEAD', '-m', 'Git undo working tree'], { env }).trim();
|
|
55
|
+
} finally { rmSync(dir, { recursive: true, force: true }); }
|
|
56
|
+
}
|
|
57
|
+
|
|
41
58
|
export async function snapshot(ctx, command, { includeIgnored = false } = {}) {
|
|
42
59
|
const store = await stateStore(ctx);
|
|
43
60
|
const repository = repoId(ctx);
|
|
@@ -52,17 +69,24 @@ export async function snapshot(ctx, command, { includeIgnored = false } = {}) {
|
|
|
52
69
|
const head = gitText(ctx, ['rev-parse', '--verify', 'HEAD']).trim();
|
|
53
70
|
const sym = ctx.git(['symbolic-ref', '-q', 'HEAD']);
|
|
54
71
|
const status = gitText(ctx, ['status', '--porcelain=v1', '-z']);
|
|
55
|
-
|
|
72
|
+
let stash = null, tracked = null;
|
|
73
|
+
if (status) {
|
|
74
|
+
const created = ctx.git(['stash', 'create'], { env: objectEnv(ctx) });
|
|
75
|
+
if (!created.error && created.status === 0) stash = String(created.stdout).trim() || null;
|
|
76
|
+
// Only a conflicted index makes stash create refuse for a reason a content snapshot answers.
|
|
77
|
+
else if (gitText(ctx, ['ls-files', '--unmerged']).trim()) tracked = trackedSnapshot(ctx);
|
|
78
|
+
else throw new Error('git stash create failed');
|
|
79
|
+
}
|
|
56
80
|
const untracked = untrackedSnapshot(ctx, includeIgnored);
|
|
57
81
|
const stashes = gitText(ctx, ['stash', 'list', '--format=%H%x00%gs']).trim().split('\n').filter(Boolean).map(row => {
|
|
58
82
|
const [oid, message] = row.split('\0'); return { oid, message };
|
|
59
83
|
});
|
|
60
|
-
const objects = [...new Set([head, stash, untracked, ...refs.map(r => r.oid), ...stashes.map(r => r.oid)].filter(Boolean))];
|
|
84
|
+
const objects = [...new Set([head, stash, tracked, untracked, ...refs.map(r => r.oid), ...stashes.map(r => r.oid)].filter(Boolean))];
|
|
61
85
|
// Pin objects before the event is durable. Git GC must not remove a snapshot.
|
|
62
86
|
for (let i = 0; i < objects.length; i += 1) gitText(ctx, ['update-ref', `${backupPrefix}${id}/${i}`, objects[i]]);
|
|
63
87
|
const event = { id, type: 'git.snapshot', timestamp: new Date().toISOString(), repository, worktree,
|
|
64
88
|
command: [command[0]], refs, head, symbolicHead: sym.status === 0 ? sym.stdout.trim() : null,
|
|
65
|
-
stash, untracked, stashes, includeIgnored };
|
|
89
|
+
stash, tracked, untracked, stashes, includeIgnored };
|
|
66
90
|
store.append(event);
|
|
67
91
|
return event;
|
|
68
92
|
}
|
|
@@ -92,11 +116,11 @@ async function restore(ctx, event) {
|
|
|
92
116
|
else gitText(ctx, ['update-ref', '--no-deref', 'HEAD', event.head]);
|
|
93
117
|
gitText(ctx, ['reset', '--hard', event.head]);
|
|
94
118
|
if (event.stash) gitText(ctx, ['stash', 'apply', '--index', event.stash]);
|
|
95
|
-
|
|
119
|
+
for (const commit of [event.tracked, event.untracked].filter(Boolean)) {
|
|
96
120
|
const dir = mkdtempSync(path.join(os.tmpdir(), 'git-undo-restore-'));
|
|
97
121
|
const env = { ...ctx.env, GIT_INDEX_FILE: path.join(dir, 'index') };
|
|
98
122
|
try {
|
|
99
|
-
gitText(ctx, ['read-tree',
|
|
123
|
+
gitText(ctx, ['read-tree', commit], { env });
|
|
100
124
|
gitText(ctx, ['checkout-index', '--all', '--force'], { env });
|
|
101
125
|
} finally { rmSync(dir, { recursive: true, force: true }); }
|
|
102
126
|
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { failure, gitText, output } from './_support.mjs';
|
|
4
|
+
import { registeredPathState, registeredRepositories } from './fleet.mjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Work that never reached the default branch: local branches with commits the
|
|
8
|
+
* default branch does not contain, linked worktrees with uncommitted changes,
|
|
9
|
+
* and detached worktrees holding commits no branch contains (removing such a
|
|
10
|
+
* worktree loses them).
|
|
11
|
+
*
|
|
12
|
+
* Nothing reported this before. A week of drawer UI work sat on an unpushed
|
|
13
|
+
* branch with 256 uncommitted files in a worktree, and about 35 plugin
|
|
14
|
+
* worktrees sat beside it, while every status said the repositories were fine.
|
|
15
|
+
*
|
|
16
|
+
* A commit counts as landed when the default branch (local or origin) reaches
|
|
17
|
+
* it, or holds an equivalent patch (`git cherry`), so rebased and
|
|
18
|
+
* cherry-picked work is not reported. A squash merge is a different patch and
|
|
19
|
+
* still shows; delete the branch once it has landed. A branch the operator
|
|
20
|
+
* keeps on purpose (`git config --add totalrecall.keepBranch <name>`) is
|
|
21
|
+
* listed as kept and not counted.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const SUMMARY_LIMIT = 480;
|
|
25
|
+
|
|
26
|
+
function localCtx(ctx, directory) {
|
|
27
|
+
return { ...ctx, git: (args, options) => ctx.git(['-C', directory, ...args], options) };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const refExists = (local, ref) => local.git(['rev-parse', '--verify', '--quiet', `${ref}^{commit}`]).status === 0;
|
|
31
|
+
|
|
32
|
+
/** The default branch: origin's HEAD, else local main or master, else init.defaultBranch. */
|
|
33
|
+
export function defaultBranch(local) {
|
|
34
|
+
const originHead = local.git(['symbolic-ref', '--quiet', 'refs/remotes/origin/HEAD']);
|
|
35
|
+
const fromOrigin = originHead.status === 0 ? originHead.stdout.trim().replace(/^refs\/remotes\/origin\//, '') : null;
|
|
36
|
+
const configured = local.git(['config', '--get', 'init.defaultBranch']);
|
|
37
|
+
const candidates = [fromOrigin, 'main', 'master', configured.status === 0 ? configured.stdout.trim() : null].filter(Boolean);
|
|
38
|
+
for (const name of candidates) {
|
|
39
|
+
const localRef = `refs/heads/${name}`, remoteRef = `refs/remotes/origin/${name}`;
|
|
40
|
+
const refs = [localRef, remoteRef].filter(ref => refExists(local, ref));
|
|
41
|
+
if (refs.length) return { name, refs };
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Non-merge commits on `tip` that no default ref reaches and whose patch the default branch lacks. */
|
|
47
|
+
function uniqueCommits(local, tip, base) {
|
|
48
|
+
const unreached = gitText(local, ['rev-list', '--no-merges', tip, '--not', ...base.refs, '--']).split('\n').filter(Boolean);
|
|
49
|
+
if (!unreached.length) return [];
|
|
50
|
+
const cherry = new Set(gitText(local, ['cherry', base.refs[0], tip]).split('\n')
|
|
51
|
+
.filter(line => line.startsWith('+ ')).map(line => line.slice(2).trim()));
|
|
52
|
+
return unreached.filter(commit => cherry.has(commit));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseWorktrees(text) {
|
|
56
|
+
return text.split('\0\0').filter(Boolean).map(record => Object.fromEntries(record.split('\0').filter(Boolean).map(row => {
|
|
57
|
+
const i = row.indexOf(' ');
|
|
58
|
+
return i < 0 ? [row, true] : [row.slice(0, i), row.slice(i + 1)];
|
|
59
|
+
})));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Inspect one repository. Never fetches: remote refs are as of the last fetch. */
|
|
63
|
+
export function inspectUnmerged(directory, ctx) {
|
|
64
|
+
const local = localCtx(ctx, directory);
|
|
65
|
+
const report = { path: directory, defaultBranch: null, outstanding: 0, branches: [], kept: [], worktrees: [], prunable: [] };
|
|
66
|
+
const state = registeredPathState(directory, ctx);
|
|
67
|
+
if (state === 'missing') return { ...report, error: 'Registered path does not exist' };
|
|
68
|
+
if (state === 'not-a-repository') return { ...report, notRepository: true };
|
|
69
|
+
const root = gitText(local, ['rev-parse', '--path-format=absolute', '--show-toplevel']).trim();
|
|
70
|
+
report.path = root;
|
|
71
|
+
const base = defaultBranch(local);
|
|
72
|
+
if (!base) return { ...report, error: 'No default branch (no origin/HEAD, main, master or init.defaultBranch)' };
|
|
73
|
+
report.defaultBranch = base.name;
|
|
74
|
+
const keep = new Set(local.git(['config', '--get-all', 'totalrecall.keepBranch']).stdout?.split('\n').map(s => s.trim()).filter(Boolean) || []);
|
|
75
|
+
|
|
76
|
+
const trees = parseWorktrees(gitText(local, ['worktree', 'list', '--porcelain', '-z']));
|
|
77
|
+
const checkedOut = new Map(trees.filter(t => typeof t.branch === 'string').map(t => [t.branch.replace(/^refs\/heads\//, ''), t.worktree]));
|
|
78
|
+
|
|
79
|
+
const rows = gitText(local, ['for-each-ref', '--format=%(refname:short)%00%(objectname)%00%(committerdate:iso-strict)%00%(upstream:short)%00%(subject)', 'refs/heads']).split('\n').filter(Boolean);
|
|
80
|
+
for (const row of rows) {
|
|
81
|
+
const [branch, tip, lastCommitAt, upstream, subject] = row.split('\0');
|
|
82
|
+
if (branch === base.name) continue;
|
|
83
|
+
const unique = uniqueCommits(local, tip, base);
|
|
84
|
+
if (!unique.length) continue;
|
|
85
|
+
const onRemote = Number(gitText(local, ['rev-list', '--count', tip, '--not', '--remotes', '--']).trim()) === 0;
|
|
86
|
+
const entry = { branch, commits: unique.length, lastCommitAt, subject, upstream: upstream || null, pushed: onRemote, worktree: checkedOut.get(branch) || null };
|
|
87
|
+
if (keep.has(branch)) report.kept.push(entry); else report.branches.push(entry);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
trees.forEach((tree, index) => {
|
|
91
|
+
const primary = index === 0;
|
|
92
|
+
const branch = typeof tree.branch === 'string' ? tree.branch.replace(/^refs\/heads\//, '') : null;
|
|
93
|
+
if (tree.prunable || !existsSync(tree.worktree)) {
|
|
94
|
+
if (!primary) report.prunable.push({ path: tree.worktree, branch, reason: 'directory is gone; git worktree prune removes the record' });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// The primary checkout on the default branch is ongoing work on that branch, which audit and fleet report.
|
|
98
|
+
if (primary && branch === base.name) return;
|
|
99
|
+
const tctx = localCtx(ctx, tree.worktree);
|
|
100
|
+
const status = gitText(tctx, ['status', '--porcelain=v1', '-z']);
|
|
101
|
+
const uncommitted = status.split('\0').filter(entry => /^[ MADRCU?!]{2} /.test(entry)).length;
|
|
102
|
+
const orphanCommits = branch ? 0 : Number(gitText(tctx, ['rev-list', '--count', 'HEAD', '--not', '--branches', '--tags', '--remotes', '--']).trim());
|
|
103
|
+
if (!uncommitted && !orphanCommits) return;
|
|
104
|
+
report.worktrees.push({ path: tree.worktree, branch, detached: !branch, uncommitted, orphanCommits, locked: Boolean(tree.locked), primary });
|
|
105
|
+
});
|
|
106
|
+
report.outstanding = report.branches.length + report.worktrees.length;
|
|
107
|
+
return report;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function describeRepo(repo, home) {
|
|
111
|
+
const rel = p => (home && p.startsWith(`${home}${path.sep}`) ? `~${p.slice(home.length)}` : p);
|
|
112
|
+
const parts = [
|
|
113
|
+
...repo.branches.map(b => `branch ${b.branch} (+${b.commits}${b.pushed ? '' : ', not pushed'})`),
|
|
114
|
+
...repo.worktrees.map(w => `worktree ${rel(w.path)} (${[w.uncommitted ? `${w.uncommitted} uncommitted` : '', w.orphanCommits ? `${w.orphanCommits} commits on no branch` : ''].filter(Boolean).join(', ')})`),
|
|
115
|
+
];
|
|
116
|
+
return `${rel(repo.path)}: ${parts.join('; ')}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function summarize(repositories, home = process.env.HOME) {
|
|
120
|
+
const outstanding = repositories.reduce((n, repo) => n + repo.outstanding, 0);
|
|
121
|
+
const failed = repositories.filter(repo => repo.error);
|
|
122
|
+
if (!outstanding) {
|
|
123
|
+
const count = repositories.filter(repo => !repo.notRepository).length;
|
|
124
|
+
const scope = repositories.length === 1 ? 'in this repository' : `in ${count} repositories`;
|
|
125
|
+
return `No branch or worktree holds work outside the default branch ${scope}${failed.length ? `; ${failed.length} could not be read` : ''}.`;
|
|
126
|
+
}
|
|
127
|
+
const head = `${outstanding} branch${outstanding === 1 ? '' : 'es'} or worktree${outstanding === 1 ? '' : 's'} hold work not in the default branch: `;
|
|
128
|
+
let text = head;
|
|
129
|
+
const withWork = repositories.filter(repo => repo.outstanding);
|
|
130
|
+
for (let i = 0; i < withWork.length; i++) {
|
|
131
|
+
const next = `${i ? ' | ' : ''}${describeRepo(withWork[i], home)}`;
|
|
132
|
+
if (text.length + next.length > SUMMARY_LIMIT) { text += ` | and ${withWork.length - i} more repositor${withWork.length - i === 1 ? 'y' : 'ies'}`; break; }
|
|
133
|
+
text += next;
|
|
134
|
+
}
|
|
135
|
+
return `${text}${failed.length ? `. ${failed.length} repositor${failed.length === 1 ? 'y' : 'ies'} could not be read` : ''}. Details: total-recall git unmerged${repositories.length > 1 ? ' --registered' : ''}.`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function textReport(repositories, summary) {
|
|
139
|
+
const lines = [];
|
|
140
|
+
for (const repo of repositories) {
|
|
141
|
+
if (repo.error) { lines.push(`${repo.path}: ${repo.error}`); continue; }
|
|
142
|
+
if (repo.notRepository) continue;
|
|
143
|
+
if (!repo.outstanding && !repo.kept.length && !repo.prunable.length) continue;
|
|
144
|
+
lines.push(`${repo.path} (default ${repo.defaultBranch})`);
|
|
145
|
+
for (const b of repo.branches) lines.push(` branch ${b.branch}: ${b.commits} commit${b.commits === 1 ? '' : 's'} not in ${repo.defaultBranch}${b.pushed ? '' : ', not pushed'}; last ${b.lastCommitAt} "${b.subject}"${b.worktree ? `; checked out at ${b.worktree}` : ''}`);
|
|
146
|
+
for (const w of repo.worktrees) lines.push(` worktree ${w.path} (${w.branch || 'detached HEAD'}${w.locked ? ', locked' : ''}): ${w.uncommitted} uncommitted file${w.uncommitted === 1 ? '' : 's'}${w.orphanCommits ? `, ${w.orphanCommits} commit${w.orphanCommits === 1 ? '' : 's'} on no branch` : ''}`);
|
|
147
|
+
for (const b of repo.kept) lines.push(` kept ${b.branch}: ${b.commits} commit${b.commits === 1 ? '' : 's'} not in ${repo.defaultBranch} (totalrecall.keepBranch)`);
|
|
148
|
+
for (const p of repo.prunable) lines.push(` stale worktree record ${p.path}${p.branch ? ` (${p.branch})` : ''}: ${p.reason}`);
|
|
149
|
+
}
|
|
150
|
+
return [...lines, summary].join('\n');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function run(args, ctx) {
|
|
154
|
+
try {
|
|
155
|
+
const unknown = args.filter(a => a !== '--registered');
|
|
156
|
+
if (unknown.length) throw new Error('Use unmerged [--registered] [--json]');
|
|
157
|
+
let directories;
|
|
158
|
+
if (args.includes('--registered')) directories = registeredRepositories(ctx);
|
|
159
|
+
else {
|
|
160
|
+
const top = ctx.git(['rev-parse', '--path-format=absolute', '--show-toplevel']);
|
|
161
|
+
if (top.status !== 0) throw new Error('Not inside a git repository; use --registered for every registered repository');
|
|
162
|
+
directories = [top.stdout.trim()];
|
|
163
|
+
}
|
|
164
|
+
const repositories = directories.map(directory => {
|
|
165
|
+
try { return inspectUnmerged(directory, ctx); }
|
|
166
|
+
catch (error) { return { path: directory, error: error.message, outstanding: 0, branches: [], kept: [], worktrees: [], prunable: [] }; }
|
|
167
|
+
});
|
|
168
|
+
const ok = repositories.every(repo => !repo.error);
|
|
169
|
+
const outstanding = repositories.reduce((n, repo) => n + repo.outstanding, 0);
|
|
170
|
+
const summary = summarize(repositories);
|
|
171
|
+
output(ctx, { ok, outstanding, summary, repositories }, textReport(repositories, summary));
|
|
172
|
+
return ok ? 0 : 1;
|
|
173
|
+
} catch (error) { return failure(ctx, error); }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export const operations = {
|
|
177
|
+
unmerged: {
|
|
178
|
+
summary: 'Branches and worktrees whose commits or changes are not in the default branch',
|
|
179
|
+
usage: 'unmerged [--registered] [--json] keep a branch on purpose: git config --add totalrecall.keepBranch <name>',
|
|
180
|
+
run,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
title: Git change comparison
|
|
4
|
+
description: Compare unstaged, staged, or base-relative changes using the owner diff operation.
|
|
5
|
+
timestamp: "2026-11-08T09:20:00Z"
|
|
6
|
+
plugin: git
|
|
7
|
+
id: change-comparison
|
|
8
|
+
intents: [review git diff, check staged files, compare branch to base, read diff stats, show a patch]
|
|
9
|
+
surfaces: [page, right]
|
|
10
|
+
operations: [diff]
|
|
11
|
+
data: ["diff:/ok", "diff:/cached", "diff:/diffStat", "diff:/timestamp"]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.sentinel-diff { padding:var(--spacing-md); border-block:1px solid var(--color-border); background:var(--color-surface); }
|
|
16
|
+
.sentinel-diff h2 { margin-top:0; }
|
|
17
|
+
.sentinel-diff dt { color:var(--color-accent); }
|
|
18
|
+
.sentinel-diff dd { margin:0 0 .45em; }
|
|
19
|
+
</style>
|
|
20
|
+
<section class="sentinel-diff">
|
|
21
|
+
<h2>Choose a comparison</h2>
|
|
22
|
+
<dl>
|
|
23
|
+
<dt>Working tree</dt><dd>Read the current changes against the index.</dd>
|
|
24
|
+
<dt>Staged</dt><dd>Review the index against the selected base.</dd>
|
|
25
|
+
<dt>Patch</dt><dd>Use <code>--patch</code> for line changes. The Home displays file statistics.</dd>
|
|
26
|
+
</dl>
|
|
27
|
+
</section>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
title: Commit identity audit
|
|
4
|
+
description: Check whether a commit identity is configured and count machine addresses recorded in local history.
|
|
5
|
+
timestamp: "2026-11-08T09:20:00Z"
|
|
6
|
+
plugin: git
|
|
7
|
+
id: commit-identity
|
|
8
|
+
intents: [check git author identity, verify commit email, audit machine addresses, git author history]
|
|
9
|
+
surfaces: [page]
|
|
10
|
+
operations: [identity]
|
|
11
|
+
data: ["identity:/ok", "identity:/machineCommits"]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.sentinel-identity { padding:var(--spacing-md); border-inline-start:3px solid var(--color-accent); background:var(--color-surface); }
|
|
16
|
+
.sentinel-identity h2 { margin-top:0; }
|
|
17
|
+
.sentinel-identity p { color:var(--color-muted); }
|
|
18
|
+
</style>
|
|
19
|
+
<section class="sentinel-identity">
|
|
20
|
+
<h2>Check the configured author</h2>
|
|
21
|
+
<p>The identity audit checks Git’s current author configuration and counts commits with a machine-derived address. Review the count separately from the current configuration.</p>
|
|
22
|
+
</section>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
title: Create a detached worktree
|
|
4
|
+
description: Create a linked Git worktree from an explicit base ref and verify its resulting revision.
|
|
5
|
+
timestamp: "2026-11-08T09:20:00Z"
|
|
6
|
+
plugin: git
|
|
7
|
+
id: create-worktree
|
|
8
|
+
intents: [create git worktree, isolate git checkout, add detached worktree, choose worktree base]
|
|
9
|
+
surfaces: [page]
|
|
10
|
+
operations: [worktree-create]
|
|
11
|
+
data: ["worktree-create:/ok", "worktree-create:/head", "worktree-create:/detached"]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.sentinel-create { padding:var(--spacing-md); background:var(--color-surface); border-radius:var(--radius-md); }
|
|
16
|
+
.sentinel-create h2 { margin-top:0; }
|
|
17
|
+
.sentinel-create li::marker { color:var(--color-accent); }
|
|
18
|
+
</style>
|
|
19
|
+
<section class="sentinel-create">
|
|
20
|
+
<h2>Prepare an isolated checkout</h2>
|
|
21
|
+
<ol>
|
|
22
|
+
<li>Choose a destination and a base ref.</li>
|
|
23
|
+
<li>Confirm the destination before creation, then verify the detached revision.</li>
|
|
24
|
+
</ol>
|
|
25
|
+
</section>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
title: Registered Git worktrees
|
|
4
|
+
description: List the repository's main and linked worktrees and inspect their checked-out revisions.
|
|
5
|
+
timestamp: "2026-11-08T09:20:00Z"
|
|
6
|
+
plugin: git
|
|
7
|
+
id: registered-worktrees
|
|
8
|
+
intents: [list git worktrees, inspect linked worktrees, find detached worktree, show active checkouts]
|
|
9
|
+
surfaces: [page, right]
|
|
10
|
+
operations: [worktree-list]
|
|
11
|
+
data: ["worktree-list:/ok", "worktree-list:/worktrees/0/head"]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.sentinel-index { padding:var(--spacing-md); border:1px solid var(--color-border); background:var(--color-surface); }
|
|
16
|
+
.sentinel-index h2 { margin-top:0; }
|
|
17
|
+
.sentinel-index b { color:var(--color-accent); }
|
|
18
|
+
</style>
|
|
19
|
+
<section class="sentinel-index">
|
|
20
|
+
<h2>Read the worktree register</h2>
|
|
21
|
+
<p>Compare the revision and branch of each registered checkout. The Home labels <b>Main</b> and <b>Current</b> separately.</p>
|
|
22
|
+
</section>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
title: Remove a linked worktree
|
|
4
|
+
description: Review a registered linked worktree, confirm its target, and read the removal result.
|
|
5
|
+
timestamp: "2026-11-08T09:20:00Z"
|
|
6
|
+
plugin: git
|
|
7
|
+
id: remove-worktree
|
|
8
|
+
intents: [remove linked git worktree, clean up isolated checkout, review worktree removal, dirty worktree refused]
|
|
9
|
+
surfaces: [page]
|
|
10
|
+
operations: [worktree-remove]
|
|
11
|
+
data: ["worktree-remove:/ok", "worktree-remove:/removed"]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.sentinel-remove { padding:var(--spacing-md); border-inline-start:3px solid var(--color-danger); background:var(--color-surface); }
|
|
16
|
+
.sentinel-remove h2 { margin-top:0; }
|
|
17
|
+
.sentinel-remove small { color:var(--color-muted); }
|
|
18
|
+
</style>
|
|
19
|
+
<section class="sentinel-remove">
|
|
20
|
+
<h2>Confirm the linked checkout</h2>
|
|
21
|
+
<p>Select the worktree by path. The Home checks Git’s removal receipt before refreshing the register.</p>
|
|
22
|
+
<small>Git refuses ordinary removal when the worktree contains local changes.</small>
|
|
23
|
+
</section>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
title: Git repository ledger
|
|
4
|
+
description: Read the active checkout, local upstream comparison, dirty files, conflicts, and stashes.
|
|
5
|
+
timestamp: "2026-11-08T09:20:00Z"
|
|
6
|
+
plugin: git
|
|
7
|
+
id: repository-ledger
|
|
8
|
+
intents: [audit git repository, check working tree, git branch and upstream, count unpushed commits, show conflicts and stashes]
|
|
9
|
+
surfaces: [page, right]
|
|
10
|
+
panel: repository
|
|
11
|
+
operations: [audit]
|
|
12
|
+
data: ["audit:/headState", "audit:/upstreamStatus", "audit:/isClean", "audit:/unpushedCommits", "audit:/conflictedFiles", "audit:/totalDirty", "audit:/stashCount", "audit:/timestamp"]
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<style>
|
|
16
|
+
.sentinel-ledger { padding:var(--spacing-md); border-inline-start:3px solid var(--color-accent); color:var(--color-text); background:var(--color-surface); }
|
|
17
|
+
.sentinel-ledger h2 { margin:.3rem 0; font:600 clamp(1.55rem,5vw,2.2rem) var(--typography-heading-font-family,Georgia,serif); }
|
|
18
|
+
.sentinel-ledger p { margin:0; }
|
|
19
|
+
.sentinel-ledger small { text-transform:uppercase; letter-spacing:.11em; color:var(--color-accent); }
|
|
20
|
+
</style>
|
|
21
|
+
<header class="sentinel-ledger">
|
|
22
|
+
<small>Git</small>
|
|
23
|
+
<h2>Read the current checkout</h2>
|
|
24
|
+
<p>Review repository state and its registered worktrees. Ahead and behind come from the local tracking ref.</p>
|
|
25
|
+
</header>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
title: Work not in the default branch
|
|
4
|
+
description: Find branches with commits the default branch lacks, worktrees with uncommitted changes and detached worktrees holding commits on no branch.
|
|
5
|
+
timestamp: "2026-11-12T21:30:00Z"
|
|
6
|
+
plugin: git
|
|
7
|
+
id: unmerged-work
|
|
8
|
+
intents: [find unmerged branches, find unfinished worktrees, check for work that never landed, see what is not merged into main]
|
|
9
|
+
surfaces: [page, right]
|
|
10
|
+
operations: [unmerged]
|
|
11
|
+
data: ["unmerged:/outstanding", "unmerged:/summary", "unmerged:/repositories/0/branches", "unmerged:/repositories/0/worktrees", "unmerged:/repositories/0/kept"]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.sentinel-unmerged { padding:var(--spacing-md); border:1px solid var(--color-border); background:var(--color-surface); }
|
|
16
|
+
.sentinel-unmerged h2 { margin-top:0; }
|
|
17
|
+
.sentinel-unmerged b { color:var(--color-accent); }
|
|
18
|
+
</style>
|
|
19
|
+
<section class="sentinel-unmerged">
|
|
20
|
+
<h2>Land what is still outside the default branch</h2>
|
|
21
|
+
<p>Each branch shows its commits the default branch lacks and whether they are pushed. Each worktree shows its <b>uncommitted</b> files and any commits on no branch, which removing the worktree would lose. Merge or report every item before ending the work.</p>
|
|
22
|
+
</section>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
plugin: git
|
|
4
|
+
id: upstream-divergence
|
|
5
|
+
title: Check branch divergence before integration
|
|
6
|
+
description: Review upstream state and local ahead or behind counts before choosing a branch integration action.
|
|
7
|
+
timestamp: "2026-11-08T23:12:00Z"
|
|
8
|
+
intents: [check commits ahead and behind, inspect missing upstream, prepare branch integration]
|
|
9
|
+
surfaces: [page]
|
|
10
|
+
panel: repository
|
|
11
|
+
operations: [audit]
|
|
12
|
+
data: ["audit:/headState", "audit:/upstreamStatus", "audit:/unpushedCommits", "audit:/behindCommits"]
|
|
13
|
+
---
|
|
14
|
+
<section>
|
|
15
|
+
<h2>Read branch divergence</h2>
|
|
16
|
+
<p>Check whether this checkout has an upstream. On a tracked branch, compare commits ahead and behind, then check the working tree before selecting an integration action.</p>
|
|
17
|
+
</section>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
plugin: git
|
|
4
|
+
id: worktree-conflict-triage
|
|
5
|
+
title: Triage conflicts in a linked checkout
|
|
6
|
+
description: Find unresolved conflicts and distinguish them from staged, unstaged and untracked work before opening a diff.
|
|
7
|
+
timestamp: "2026-11-08T23:12:00Z"
|
|
8
|
+
intents: [triage merge conflicts, compare staged and unstaged work during a conflict, inspect dirty worktree before cleanup]
|
|
9
|
+
surfaces: [page]
|
|
10
|
+
panel: repository
|
|
11
|
+
operations: [audit, diff]
|
|
12
|
+
data: ["audit:/conflictedFiles", "audit:/stagedFiles", "audit:/unstagedFiles", "audit:/untrackedFiles", "diff:/diffStat"]
|
|
13
|
+
---
|
|
14
|
+
<section>
|
|
15
|
+
<h2>Separate conflicts from other local changes</h2>
|
|
16
|
+
<p>Read the conflict count first. Then open diff statistics for the relevant working or staged changes. Preserve the linked checkout until its local work is resolved.</p>
|
|
17
|
+
</section>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ui-chunk:chunk
|
|
3
|
+
title: Worktree compatibility commands
|
|
4
|
+
description: Use the owner compatibility command in the terminal to list, create, or remove linked worktrees.
|
|
5
|
+
timestamp: "2026-11-08T09:20:00Z"
|
|
6
|
+
plugin: git
|
|
7
|
+
id: worktree-terminal
|
|
8
|
+
intents: [git sentinel worktree command, worktree compatibility syntax, terminal git worktree list, worktree create remove alias]
|
|
9
|
+
surfaces: [page]
|
|
10
|
+
operations: [worktree]
|
|
11
|
+
data: ["worktree:/ok", "worktree:/worktrees/0/head", "worktree:/removed"]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.sentinel-terminal { padding:var(--spacing-md); border:1px dashed var(--color-border); background:var(--color-surface); }
|
|
16
|
+
.sentinel-terminal h2 { margin-top:0; }
|
|
17
|
+
.sentinel-terminal code { color:var(--color-accent); overflow-wrap:anywhere; }
|
|
18
|
+
</style>
|
|
19
|
+
<section class="sentinel-terminal">
|
|
20
|
+
<h2>Use the compatibility command</h2>
|
|
21
|
+
<p><code>total-recall git worktree-list</code> reads the register. Select <code>create</code> or <code>remove</code> with the required path for an explicit change.</p>
|
|
22
|
+
</section>
|