total-recall-brain 3.40.1 → 3.40.2
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 +152 -41
- package/bin/total-recall.mjs +16 -76
- package/docs/reference/cli-reference.md +10 -10
- package/extension/background.js +6 -2
- package/extension/config.js +8 -0
- package/extension/lib/brain-client.js +29 -4
- package/extension/options/options.html +1 -0
- package/extension/sidepanel/sidepanel.html +1 -0
- package/frontend/dist/assets/{index-CvQRdT2j.css → index-AGUes-VG.css} +1 -1
- package/frontend/dist/assets/index-Bt5iVPZj.js +5618 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/src/api/keys.ts +9 -2
- package/frontend/src/api/plugins.ts +4 -0
- package/frontend/src/components/plugins/card/CardEngine.tsx +2 -1
- package/frontend/src/components/plugins/card/card.css +1 -1
- package/frontend/src/pages/IntegrationsPage.tsx +315 -8
- package/frontend/src/pages/PluginsPage.tsx +532 -87
- package/package.json +6 -5
- package/scaffold/.agent/skills/meta-harness/references/optimized/original.md +1 -1
- package/scaffold/.agent/skills/meta-harness/references/optimized/section-09.md +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +10 -10
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -6
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +0 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/browser-session.mjs +309 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +44 -34
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/google-oauth.mjs +6 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-catalog.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-rotation-recipes.mjs +118 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/routes/auth.mjs +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-env-export.mjs +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-remote-deploy.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-rotate.mjs +24 -6
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +164 -123
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +65 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +76 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +290 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +446 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +152 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +71 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +175 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/README.md +84 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/cli.mjs +79 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/check.mjs +6 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/report.mjs +6 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/run-core.mjs +27 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/snapshot.mjs +163 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +757 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/config.schema.json +86 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/detect.mjs +89 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report-data.mjs +145 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report.mjs +210 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/state.mjs +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +2869 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +28 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +186 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +272 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/code-quality-report.mjs +129 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/README.md +73 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/cli.mjs +375 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/examples/commands/echo-tool.mjs +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/examples/commands/group.mjs +262 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/examples/commands/project-id.mjs +74 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +2869 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +31 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +221 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/schemas/cli_command.schema.json +107 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/skills/composable-cli/SKILL.md +63 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/command.mjs +313 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/compile.mjs +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/compose.mjs +144 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/contract.mjs +110 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/library.mjs +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/registry.mjs +192 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/resolve.mjs +221 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/risk.mjs +126 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/ssss-documents.mjs +29 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +273 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/README.md +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/cli.mjs +310 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +2826 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +11 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +62 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +297 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/README.md +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/cli.mjs +258 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +4005 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +125 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +278 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +9 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +6 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +4721 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +3 -21
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +14 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +10 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/headscale-client.mjs +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/leader-election.mjs +4 -13
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh-access-verify.mjs +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh-files.mjs +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +2 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/test-support/memory-root.mjs +14 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +124 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +4097 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +12 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +165 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/ingest.mjs +127 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +279 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +539 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/README.md +67 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +932 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +3256 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +297 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +4 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/skills/security/SKILL.md +37 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/android.mjs +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/devices.mjs +94 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/machines.mjs +164 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/scanner.mjs +41 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/windows.mjs +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +95 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +98 -0
- package/scaffold/.agent/skills/total-recall/references/auth.md +1 -1
- package/src/cli/brief.mjs +33 -9
- package/src/cli/command.mjs +2 -7
- package/src/cli/config.mjs +1 -0
- package/src/cli/connect.mjs +5 -0
- package/src/cli/context.mjs +2 -1
- package/src/cli/daemon.mjs +36 -1
- package/src/cli/doctor.mjs +6 -0
- package/src/cli/harness.mjs +3 -0
- package/src/cli/help.mjs +26 -0
- package/src/cli/init.mjs +4 -4
- package/src/cli/memory-entry.mjs +1 -0
- package/src/cli/memory-init.mjs +2 -0
- package/src/cli/plugin/index.mjs +11 -0
- package/src/cli/plugin/install.mjs +2 -1
- package/src/cli/rebuild.mjs +3 -1
- package/src/cli/startup.mjs +2 -1
- package/src/cli/update.mjs +19 -0
- package/src/core/automatic-brain-updates.mjs +67 -0
- package/src/core/brain-updates.mjs +21 -2
- package/src/core/cli-commands.mjs +71 -0
- package/src/core/cli-maintenance.mjs +45 -0
- package/src/core/cli-quick-reference.mjs +20 -0
- package/src/core/cli-semantic-index.mjs +722 -0
- package/src/core/context-compiler.mjs +27 -1
- package/src/core/crons.mjs +2 -13
- package/src/core/daemon-control.mjs +6 -4
- package/src/core/daemon-loop.mjs +12 -8
- package/src/core/default-plugins.mjs +5 -0
- package/src/core/global-brain-updates.mjs +39 -0
- package/src/core/mesh-brain-updates.mjs +30 -0
- package/src/core/meta-harness.mjs +108 -0
- package/src/core/plugin-dependencies.mjs +2 -1
- package/src/core/plugin-loader.mjs +2 -1
- package/src/core/plugin-runner.mjs +12 -4
- package/src/core/plugin-setup.mjs +20 -0
- package/src/core/plugin-store.mjs +22 -4
- package/src/core/plugin-tasks.mjs +1 -1
- package/src/core/project-brain.mjs +2 -0
- package/src/core/project-status.mjs +64 -0
- package/src/core/required-plugins.mjs +46 -0
- package/src/core/scaffold-plugins.mjs +17 -3
- package/src/core/source-brain-updates.mjs +47 -0
- package/src/core/startup-health.mjs +5 -3
- package/src/core/surface.mjs +44 -10
- package/src/server/routes/extension.mjs +53 -8
- package/templates/onboarding-interview.md +1 -1
- package/frontend/dist/assets/index-SOVUlZqm.js +0 -5596
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# tr-plugin-composable-cli
|
|
2
|
+
|
|
3
|
+
Total Recall composable CLI plugin: create, compose, register, test and safely run custom verbs; every command listed in the instruction surfaces.
|
|
4
|
+
|
|
5
|
+
## Status: v0.2.0 — Implementation in progress
|
|
6
|
+
|
|
7
|
+
See `docs/projects/in-progress/` for the audit, PRD, architecture, development plan and tracker.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
src/
|
|
13
|
+
command.mjs — Core CRUD for command files (create/read/update/remove/list)
|
|
14
|
+
contract.mjs — Standard CLI contract: --help, --json envelope, exit codes 0/1/2/3, --background
|
|
15
|
+
compose.mjs — tr() composition helper (in-process for native custom commands, subprocess + --json for built-ins)
|
|
16
|
+
risk.mjs — Risk classes (read/write/money/dns-cert/production-deploy/secret-revoke), dry-run gate
|
|
17
|
+
registry.mjs — cli_command SSSS documents, version history, rollback
|
|
18
|
+
resolve.mjs — Scope search (project→group→global), shadow detection, group membership
|
|
19
|
+
schemas/
|
|
20
|
+
cli_command.schema.json — SSSS document schema for registered commands
|
|
21
|
+
cli.mjs — Plugin CLI entry point (composable-cli create|read|update|...)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Key Concepts
|
|
25
|
+
|
|
26
|
+
### v2 Command Format
|
|
27
|
+
Commands export both `meta` (name, description, risk class, version) and a default function receiving `(args, context)` with `tr`, `json`, `dryRun`, and `log`:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
export const meta = { name: 'my-cmd', description: '...', risk: 'read', version: 2 };
|
|
31
|
+
export default async function main(args, { tr, json, dryRun, log }) { ... }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Risk Gate
|
|
35
|
+
Commands of class `money`, `dns-cert`, `production-deploy`, or `secret-revoke` require `--yes` to execute. Without `--yes`, they print a plan and exit 3.
|
|
36
|
+
|
|
37
|
+
### Registry
|
|
38
|
+
Every command has a sibling `cli_command` SSSS document (`<name>.md`) beside its code, with provenance, risk class, version, author, and timestamps. History is kept in `.history/<name>/v*.mjs`.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
Into a Total Recall brain: `total-recall plugin install <git url of this repo>`.
|
|
43
|
+
|
|
44
|
+
## Tests
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
node --test test/*.test.mjs
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Existing test files cover: CRUD operations, shadow detection, risk gate, native-only command validation, registry round-trip, history, composition contract, and scope resolution.
|
|
51
|
+
|
|
52
|
+
## Readiness reconciliation — 2026-09-30
|
|
53
|
+
|
|
54
|
+
[Canonical correction plan](docs/projects/in-progress/COMPOSABLE_CLI_PLUGIN/COMPOSABLE_CLI_PLUGIN_PROJECT_TRACKER.md). No fresh suite was run against this external repository HEAD during the documentation review. Run `npm test` and configured gates on the Mac mini in a bounded background job. The Total Recall central preview is unwired static UI and is not an operational demonstration of this plugin.
|
|
55
|
+
|
|
56
|
+
- **PIC-042:** src/registry.mjs rollback restores a code snapshot but its fm rewrite preserves the old code_sha256 (line 230); writes bypass the host SSSS operation path.
|
|
57
|
+
- **PIC-043:** cli.mjs:256 test only prints a filename; promote at line 271 copies files without registering a plugin manifest command. Central ComposableCLIPreview.tsx:122 is a read-only terminal.
|
|
58
|
+
|
|
59
|
+
Durable capability state must use validated SSSS operations. Delivery requires a real clean-install command/UI walkthrough, explicit unavailable/error states and actual result provenance. Tests may use synthetic fixtures; shipped capability behavior may not.
|
|
60
|
+
|
|
61
|
+
## Use it two ways
|
|
62
|
+
|
|
63
|
+
This plugin is a reusable brick, so a new project does not start from zero.
|
|
64
|
+
|
|
65
|
+
**Add it to a project (for apps you build and ship).** From the project directory:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
total-recall plugin vendor https://github.com/gregiteen/tr-plugin-composable-cli.git
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
This copies the plugin's source, skills, tests and docs into `bricks/composable-cli` and records it in `tr-bricks.json`. Your project then owns that code: edit it, test it in your own gates, and ship it with no runtime dependency on this plugin or on Total Recall. Combine as many bricks as the project needs. List them with `total-recall plugin bricks`.
|
|
72
|
+
|
|
73
|
+
**Use it directly with Total Recall (for your own machines and workflow).** Install it with `total-recall plugin install https://github.com/gregiteen/tr-plugin-composable-cli.git` and run `total-recall composable-cli`. Manage its credentials with `total-recall auth secret` and its skills with `total-recall skill`.
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Composable CLI CLI Handler
|
|
4
|
+
* Executed via: npx total-recall composable-cli <subcommand>
|
|
5
|
+
*
|
|
6
|
+
* Also serves as the `command` subcommand entry point:
|
|
7
|
+
* total-recall command <create|read|update|remove|list|show|history|rollback|test|promote>
|
|
8
|
+
*/
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import {
|
|
11
|
+
commandCreate,
|
|
12
|
+
commandRead,
|
|
13
|
+
commandUpdate,
|
|
14
|
+
commandRemove,
|
|
15
|
+
commandList,
|
|
16
|
+
safeCommandName,
|
|
17
|
+
} from './src/command.mjs';
|
|
18
|
+
import { writeRegistry, readRegistry, listHistory, rollback, snapshotForHistory } from './src/registry.mjs';
|
|
19
|
+
import { detectShadow, getCommandTargets, resolveCommand, shadowWarning } from './src/resolve.mjs';
|
|
20
|
+
import { validateRisk, hasRiskGate } from './src/risk.mjs';
|
|
21
|
+
import { EXIT_CODES } from './src/contract.mjs';
|
|
22
|
+
import fs from 'node:fs';
|
|
23
|
+
import { buildCliLibrary } from './src/library.mjs';
|
|
24
|
+
import { MUTATIONS, compileCommandMutation } from './src/compile.mjs';
|
|
25
|
+
import { deleteCommandDocument } from './src/ssss-documents.mjs';
|
|
26
|
+
|
|
27
|
+
function resolveCommandsDir() {
|
|
28
|
+
return path.join(process.cwd(), '.agent', 'commands');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Determine the scope for a new command.
|
|
33
|
+
* Checks project, then global based on --global flag.
|
|
34
|
+
*/
|
|
35
|
+
function detectScope(args, commandsDir) {
|
|
36
|
+
if (args.includes('--global')) {
|
|
37
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
38
|
+
const globalDir = path.join(homeDir, '.agent', 'commands');
|
|
39
|
+
return { scope: 'global', dir: globalDir };
|
|
40
|
+
}
|
|
41
|
+
// Check for --group <id>
|
|
42
|
+
const gi = args.indexOf('--group');
|
|
43
|
+
if (gi >= 0 && args[gi + 1]) {
|
|
44
|
+
const groupId = args[gi + 1];
|
|
45
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
46
|
+
const groupDir = path.join(homeDir, '.agent', 'commands', 'groups', groupId);
|
|
47
|
+
return { scope: 'group', dir: groupDir };
|
|
48
|
+
}
|
|
49
|
+
return { scope: 'project', dir: commandsDir };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const IMPLEMENTED = {
|
|
53
|
+
library: async (args) => {
|
|
54
|
+
const catalog = await buildCliLibrary();
|
|
55
|
+
const index = args.indexOf('--plugin');
|
|
56
|
+
if (index >= 0) {
|
|
57
|
+
const id = args[index + 1];
|
|
58
|
+
if (!id || !catalog.plugins.some(plugin => plugin.id === id)) throw new Error('Selected plugin is not installed');
|
|
59
|
+
catalog.plugins = catalog.plugins.filter(plugin => plugin.id === id);
|
|
60
|
+
catalog.commands = catalog.commands.filter(command => command.plugin === id);
|
|
61
|
+
catalog.composedCommands = [];
|
|
62
|
+
}
|
|
63
|
+
if (args.includes('--json')) console.log(JSON.stringify(catalog));
|
|
64
|
+
else {
|
|
65
|
+
for (const command of catalog.commands) console.log(`${command.command} [${command.effect || 'undeclared effect'}] — ${command.description}`);
|
|
66
|
+
for (const command of catalog.composedCommands) console.log(`${command.command} [${command.risk || 'undeclared risk'}] — ${command.description}`);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
create: async (args) => {
|
|
70
|
+
const name = args[0];
|
|
71
|
+
const code = args[1];
|
|
72
|
+
const commandsDir = resolveCommandsDir();
|
|
73
|
+
|
|
74
|
+
// Parse description, risk from args
|
|
75
|
+
const di = args.indexOf('--description');
|
|
76
|
+
const description = di >= 0 ? args[di + 1] : undefined;
|
|
77
|
+
const ri = args.indexOf('--risk');
|
|
78
|
+
const risk = ri >= 0 ? args[ri + 1] : 'write';
|
|
79
|
+
const fromPlugin = args.findIndex((a) => a === '--from-plugin');
|
|
80
|
+
const pluginDir = fromPlugin >= 0 ? args[fromPlugin + 1] : undefined;
|
|
81
|
+
const configForSkill = args.findIndex((a) => a === '--config-for-skill');
|
|
82
|
+
const skillId = configForSkill >= 0 ? args[configForSkill + 1] : undefined;
|
|
83
|
+
|
|
84
|
+
// Detect scope
|
|
85
|
+
const { scope, dir } = detectScope(args, commandsDir);
|
|
86
|
+
|
|
87
|
+
// Shadow detection: refuse built-in names, warn on scope shadowing
|
|
88
|
+
const warning = shadowWarning(name);
|
|
89
|
+
if (warning && warning.startsWith("'")) {
|
|
90
|
+
// Built-in — refuse
|
|
91
|
+
const err = new Error(warning);
|
|
92
|
+
err.exitCode = EXIT_CODES.USAGE;
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
if (warning) {
|
|
96
|
+
console.error(warning);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const commandPath = commandCreate({
|
|
100
|
+
name,
|
|
101
|
+
code,
|
|
102
|
+
description,
|
|
103
|
+
risk,
|
|
104
|
+
commandsDir: dir,
|
|
105
|
+
fromPlugin: pluginDir,
|
|
106
|
+
configForSkill: skillId,
|
|
107
|
+
repoRoot: process.cwd(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Write registry document
|
|
111
|
+
const author = process.env.AGENT_ID || 'user';
|
|
112
|
+
writeRegistry({
|
|
113
|
+
name,
|
|
114
|
+
commandsDir: dir,
|
|
115
|
+
scope,
|
|
116
|
+
risk: risk || 'write',
|
|
117
|
+
version: 1,
|
|
118
|
+
author,
|
|
119
|
+
description: description || '',
|
|
120
|
+
source: fromPlugin ? 'from-plugin' : configForSkill ? 'config-for-skill' : 'inline',
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
console.log(` Created command: ${name} -> ${commandPath} (${scope})`);
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
read: async (args) => {
|
|
127
|
+
const name = args[0];
|
|
128
|
+
const commandsDir = resolveCommandsDir();
|
|
129
|
+
const { scope, dir } = detectScope(args, commandsDir);
|
|
130
|
+
console.log(commandRead(name, dir));
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
update: async (args) => {
|
|
134
|
+
const name = args[0];
|
|
135
|
+
const code = args[1];
|
|
136
|
+
const commandsDir = resolveCommandsDir();
|
|
137
|
+
|
|
138
|
+
// Parse optional metadata tags
|
|
139
|
+
const di = args.indexOf('--description');
|
|
140
|
+
const description = di >= 0 ? args[di + 1] : undefined;
|
|
141
|
+
const ri = args.indexOf('--risk');
|
|
142
|
+
const risk = ri >= 0 ? args[ri + 1] : undefined;
|
|
143
|
+
|
|
144
|
+
const { dir } = detectScope(args, commandsDir);
|
|
145
|
+
|
|
146
|
+
// Snapshot current version before updating
|
|
147
|
+
snapshotForHistory(name, dir);
|
|
148
|
+
|
|
149
|
+
commandUpdate({
|
|
150
|
+
name,
|
|
151
|
+
code,
|
|
152
|
+
description,
|
|
153
|
+
risk,
|
|
154
|
+
commandsDir: dir,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Bump registry version
|
|
158
|
+
const doc = readRegistry(name, dir);
|
|
159
|
+
if (doc) {
|
|
160
|
+
writeRegistry({
|
|
161
|
+
name,
|
|
162
|
+
commandsDir: dir,
|
|
163
|
+
scope: doc.scope || 'project',
|
|
164
|
+
risk: risk || doc.risk || 'write',
|
|
165
|
+
version: (doc.version || 0) + 1,
|
|
166
|
+
author: doc.author || 'user',
|
|
167
|
+
description: description || doc.description || '',
|
|
168
|
+
source: doc.source || 'inline',
|
|
169
|
+
background: doc.background_allowed || false,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
console.log(` Updated command: ${name}`);
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
remove: async (args) => {
|
|
177
|
+
const name = args[0];
|
|
178
|
+
const commandsDir = resolveCommandsDir();
|
|
179
|
+
const { dir } = detectScope(args, commandsDir);
|
|
180
|
+
const docPath = path.join(dir, `${name}.md`);
|
|
181
|
+
safeCommandName(name);
|
|
182
|
+
if (fs.existsSync(docPath)) deleteCommandDocument(docPath);
|
|
183
|
+
commandRemove(name, dir);
|
|
184
|
+
console.log(` Removed command: ${name}`);
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
list: async (args) => {
|
|
188
|
+
const json = args.includes('--json');
|
|
189
|
+
const commandsDir = resolveCommandsDir();
|
|
190
|
+
const targets = getCommandTargets({ cwd: process.cwd() });
|
|
191
|
+
const items = commandList(targets);
|
|
192
|
+
if (json) {
|
|
193
|
+
console.log(JSON.stringify(items));
|
|
194
|
+
} else {
|
|
195
|
+
if (!items.length) {
|
|
196
|
+
console.log('No custom commands found.');
|
|
197
|
+
} else {
|
|
198
|
+
for (const item of items) {
|
|
199
|
+
console.log(` - ${item.name} (${item.scope}, ${item.path})${item.description ? ' — ' + item.description : ''}${item.risk ? ' [' + item.risk + ']' : ''}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
show: async (args) => {
|
|
206
|
+
const name = args[0];
|
|
207
|
+
const json = args.includes('--json');
|
|
208
|
+
const commandsDir = resolveCommandsDir();
|
|
209
|
+
const { dir } = detectScope(args, commandsDir);
|
|
210
|
+
|
|
211
|
+
const code = commandRead(name, dir);
|
|
212
|
+
const doc = readRegistry(name, dir);
|
|
213
|
+
|
|
214
|
+
if (json) {
|
|
215
|
+
console.log(JSON.stringify({ registry: doc || null, code }));
|
|
216
|
+
} else {
|
|
217
|
+
if (doc) {
|
|
218
|
+
console.log(`Command: ${doc.name}`);
|
|
219
|
+
console.log(`Scope: ${doc.scope}`);
|
|
220
|
+
console.log(`Risk: ${doc.risk}`);
|
|
221
|
+
console.log(`Version: ${doc.version}`);
|
|
222
|
+
console.log(`Author: ${doc.author}`);
|
|
223
|
+
console.log(`Created: ${doc.created}`);
|
|
224
|
+
console.log(`Updated: ${doc.updated}`);
|
|
225
|
+
if (doc.description) console.log(`Description: ${doc.description}`);
|
|
226
|
+
console.log('');
|
|
227
|
+
}
|
|
228
|
+
console.log(code);
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
history: async (args) => {
|
|
233
|
+
const name = args[0];
|
|
234
|
+
const json = args.includes('--json');
|
|
235
|
+
const commandsDir = resolveCommandsDir();
|
|
236
|
+
const { dir } = detectScope(args, commandsDir);
|
|
237
|
+
const versions = listHistory(name, dir);
|
|
238
|
+
if (json) {
|
|
239
|
+
console.log(JSON.stringify({ name, versions }));
|
|
240
|
+
} else {
|
|
241
|
+
if (!versions.length) {
|
|
242
|
+
console.log(`No history for '${name}'.`);
|
|
243
|
+
} else {
|
|
244
|
+
console.log(`History for '${name}':`);
|
|
245
|
+
for (const v of versions) {
|
|
246
|
+
console.log(` v${v}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
rollback: async (args) => {
|
|
253
|
+
const name = args[0];
|
|
254
|
+
const version = parseInt(args[1], 10);
|
|
255
|
+
const commandsDir = resolveCommandsDir();
|
|
256
|
+
const { dir } = detectScope(args, commandsDir);
|
|
257
|
+
if (isNaN(version)) {
|
|
258
|
+
const err = new Error('Usage: command rollback <name> <version>');
|
|
259
|
+
err.exitCode = EXIT_CODES.USAGE;
|
|
260
|
+
throw err;
|
|
261
|
+
}
|
|
262
|
+
rollback(name, version, dir);
|
|
263
|
+
console.log(` Rolled back '${name}' to v${version}`);
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
test: async (args) => {
|
|
267
|
+
const name = args[0];
|
|
268
|
+
const json = args.includes('--json');
|
|
269
|
+
const commandsDir = resolveCommandsDir();
|
|
270
|
+
const { dir } = detectScope(args, commandsDir);
|
|
271
|
+
const testFile = path.join(dir, `${name}.test.mjs`);
|
|
272
|
+
if (!fs.existsSync(testFile)) {
|
|
273
|
+
const err = new Error(`No test file found for '${name}' at ${testFile}`);
|
|
274
|
+
err.exitCode = EXIT_CODES.ERROR;
|
|
275
|
+
throw err;
|
|
276
|
+
}
|
|
277
|
+
console.log(`Test file for '${name}' found at ${testFile}. Run with: node --test ${testFile}`);
|
|
278
|
+
if (json) console.log(JSON.stringify({ name, testFile }));
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
promote: async (args) => {
|
|
282
|
+
const name = args[0];
|
|
283
|
+
const pi = args.indexOf('--to-plugin');
|
|
284
|
+
const pluginDir = pi >= 0 ? args[pi + 1] : undefined;
|
|
285
|
+
const commandsDir = resolveCommandsDir();
|
|
286
|
+
const { dir } = detectScope(args, commandsDir);
|
|
287
|
+
|
|
288
|
+
if (!pluginDir) {
|
|
289
|
+
const err = new Error('Usage: command promote <name> --to-plugin <dir>');
|
|
290
|
+
err.exitCode = EXIT_CODES.USAGE;
|
|
291
|
+
throw err;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const cmdPath = path.join(dir, `${name}.mjs`);
|
|
295
|
+
if (!fs.existsSync(cmdPath)) {
|
|
296
|
+
const err = new Error(`Command '${name}' does not exist in ${dir}.`);
|
|
297
|
+
err.exitCode = EXIT_CODES.ERROR;
|
|
298
|
+
throw err;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Copy command file and test into the plugin directory
|
|
302
|
+
fs.mkdirSync(path.join(pluginDir, 'commands'), { recursive: true });
|
|
303
|
+
fs.copyFileSync(cmdPath, path.join(pluginDir, 'commands', `${name}.mjs`));
|
|
304
|
+
|
|
305
|
+
const testPath = path.join(dir, `${name}.test.mjs`);
|
|
306
|
+
if (fs.existsSync(testPath)) {
|
|
307
|
+
fs.copyFileSync(testPath, path.join(pluginDir, 'commands', `${name}.test.mjs`));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
console.log(` Promoted '${name}' to plugin at ${pluginDir}/commands/`);
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
export async function run(argv = [], dependencies = {}) {
|
|
315
|
+
const args = Array.isArray(argv) ? argv.slice(3) : [];
|
|
316
|
+
const sub = args[0] || 'status';
|
|
317
|
+
const json = args.includes('--json');
|
|
318
|
+
|
|
319
|
+
if (sub === 'status' || sub === '--help' || sub === '-h' || sub === 'help') {
|
|
320
|
+
if (sub === '--help' || sub === '-h' || sub === 'help') {
|
|
321
|
+
console.log(`
|
|
322
|
+
total-recall composable-cli — Dynamic agent command composition engine
|
|
323
|
+
|
|
324
|
+
Usage:
|
|
325
|
+
total-recall composable-cli status [--json]
|
|
326
|
+
total-recall composable-cli library [--plugin <id>] [--json]
|
|
327
|
+
total-recall composable-cli create <name> "<code>" [--global] [--description "…"] [--risk <class>]
|
|
328
|
+
total-recall composable-cli read <name> [--global]
|
|
329
|
+
total-recall composable-cli update <name> "<code>" [--global] [--description "…"] [--risk <class>]
|
|
330
|
+
total-recall composable-cli remove <name> [--global]
|
|
331
|
+
total-recall composable-cli list [--global] [--json]
|
|
332
|
+
total-recall composable-cli show <name> [--global]
|
|
333
|
+
total-recall composable-cli history <name> [--global]
|
|
334
|
+
total-recall composable-cli rollback <name> [--version <n>] [--global]
|
|
335
|
+
total-recall composable-cli test <name> [--global]
|
|
336
|
+
total-recall composable-cli promote <name> --plugin <dir>
|
|
337
|
+
|
|
338
|
+
Or use the primary verb:
|
|
339
|
+
total-recall command <create|read|update|remove|list|…>
|
|
340
|
+
`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const status = {
|
|
344
|
+
plugin: 'composable-cli',
|
|
345
|
+
implemented: ['status', ...Object.keys(IMPLEMENTED)],
|
|
346
|
+
scope: {
|
|
347
|
+
project: resolveCommandsDir(),
|
|
348
|
+
global: process.env.HOME ? path.join(process.env.HOME, '.agent', 'commands') : undefined,
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
if (json) console.log(JSON.stringify(status));
|
|
352
|
+
else {
|
|
353
|
+
console.log(`Composable CLI v0.2.0 — implemented subcommands: ${status.implemented.join(', ')}`);
|
|
354
|
+
console.log(`Project commands: ${status.scope.project}`);
|
|
355
|
+
if (status.scope.global) console.log(`Global commands: ${status.scope.global}`);
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (IMPLEMENTED[sub]) {
|
|
361
|
+
try {
|
|
362
|
+
await IMPLEMENTED[sub](args.slice(1));
|
|
363
|
+
if (MUTATIONS.has(sub)) await compileCommandMutation(args.slice(1), dependencies);
|
|
364
|
+
} catch (err) {
|
|
365
|
+
console.error(`Error: ${err.message}`);
|
|
366
|
+
process.exitCode = err.exitCode || 1;
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
console.error(`Composable CLI: "${sub}" is not implemented.`);
|
|
372
|
+
process.exitCode = 2;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export default run;
|
package/scaffold/.agent/skills/total-recall/plugins/composable-cli/examples/commands/echo-tool.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Auto-generated custom CLI command: echo-tool
|
|
2
|
+
// @description Generic example command demonstrating the composable CLI contract.
|
|
3
|
+
// @risk read
|
|
4
|
+
export async function run(argv = []) {
|
|
5
|
+
const args = Array.isArray(argv) ? argv.slice(3) : [];
|
|
6
|
+
const json = args.includes('--json');
|
|
7
|
+
const payload = {
|
|
8
|
+
ok: true,
|
|
9
|
+
timestamp: new Date().toISOString(),
|
|
10
|
+
args: args.filter((a) => a !== '--json'),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
if (json) {
|
|
14
|
+
console.log(JSON.stringify(payload));
|
|
15
|
+
} else {
|
|
16
|
+
console.log('Echo tool executed successfully.');
|
|
17
|
+
console.log(`Received args: ${payload.args.join(' ')}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default async function (args = []) {
|
|
22
|
+
console.log(`Echo tool received: ${args.join(' ')}`);
|
|
23
|
+
}
|