@crouton-kit/crouter 0.3.11 → 0.3.12
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/crtrd +2 -0
- package/dist/builtin-personas/design/base.md +9 -0
- package/dist/builtin-personas/design/orchestrator.md +10 -0
- package/dist/builtin-personas/developer/base.md +9 -0
- package/dist/builtin-personas/developer/orchestrator.md +12 -0
- package/dist/builtin-personas/explore/base.md +9 -0
- package/dist/builtin-personas/explore/orchestrator.md +9 -0
- package/dist/builtin-personas/general/base.md +5 -0
- package/dist/builtin-personas/general/orchestrator.md +7 -0
- package/dist/builtin-personas/orchestration-kernel.md +71 -0
- package/dist/builtin-personas/plan/base.md +7 -0
- package/dist/builtin-personas/plan/orchestrator.md +12 -0
- package/dist/builtin-personas/review/base.md +7 -0
- package/dist/builtin-personas/review/orchestrator.md +9 -0
- package/dist/builtin-personas/runtime-base.md +39 -0
- package/dist/builtin-personas/spec/base.md +7 -0
- package/dist/builtin-personas/spec/orchestrator.md +10 -0
- package/dist/builtin-skills/skills/design/SKILL.md +51 -0
- package/dist/builtin-skills/skills/development/SKILL.md +109 -0
- package/dist/builtin-skills/skills/planning/SKILL.md +59 -0
- package/dist/builtin-skills/skills/spec/SKILL.md +83 -0
- package/dist/cli.js +14 -6
- package/dist/commands/{mode.d.ts → attention.d.ts} +1 -1
- package/dist/commands/attention.js +152 -0
- package/dist/commands/canvas.d.ts +2 -0
- package/dist/commands/canvas.js +35 -0
- package/dist/commands/daemon.d.ts +2 -0
- package/dist/commands/daemon.js +111 -0
- package/dist/commands/dashboard.d.ts +2 -0
- package/dist/commands/dashboard.js +65 -0
- package/dist/commands/human/prompts.d.ts +5 -0
- package/dist/commands/human/prompts.js +269 -0
- package/dist/commands/human/queue.d.ts +3 -0
- package/dist/commands/human/queue.js +133 -0
- package/dist/commands/human/shared.d.ts +43 -0
- package/dist/commands/human/shared.js +107 -0
- package/dist/commands/human.js +10 -454
- package/dist/commands/node.d.ts +2 -0
- package/dist/commands/node.js +354 -0
- package/dist/commands/pkg/market-inspect.d.ts +1 -0
- package/dist/commands/pkg/market-inspect.js +157 -0
- package/dist/commands/pkg/market-manage.d.ts +1 -0
- package/dist/commands/pkg/market-manage.js +316 -0
- package/dist/commands/pkg/market.d.ts +1 -0
- package/dist/commands/pkg/market.js +16 -0
- package/dist/commands/pkg/plugin-inspect.d.ts +1 -0
- package/dist/commands/pkg/plugin-inspect.js +142 -0
- package/dist/commands/pkg/plugin-manage.d.ts +1 -0
- package/dist/commands/pkg/plugin-manage.js +294 -0
- package/dist/commands/pkg/plugin.d.ts +1 -0
- package/dist/commands/pkg/plugin.js +16 -0
- package/dist/commands/pkg/shared.d.ts +5 -0
- package/dist/commands/pkg/shared.js +61 -0
- package/dist/commands/pkg.js +3 -1004
- package/dist/commands/push.d.ts +3 -0
- package/dist/commands/push.js +159 -0
- package/dist/commands/revive.d.ts +2 -0
- package/dist/commands/revive.js +64 -0
- package/dist/commands/skill/author.d.ts +3 -0
- package/dist/commands/skill/author.js +147 -0
- package/dist/commands/skill/find.d.ts +4 -0
- package/dist/commands/skill/find.js +254 -0
- package/dist/commands/skill/read.d.ts +1 -0
- package/dist/commands/skill/read.js +89 -0
- package/dist/commands/skill/shared.d.ts +19 -0
- package/dist/commands/skill/shared.js +207 -0
- package/dist/commands/skill/state.d.ts +3 -0
- package/dist/commands/skill/state.js +69 -0
- package/dist/commands/skill.js +6 -691
- package/dist/commands/sys/config.d.ts +1 -0
- package/dist/commands/sys/config.js +186 -0
- package/dist/commands/sys/doctor.d.ts +1 -0
- package/dist/commands/sys/doctor.js +369 -0
- package/dist/commands/sys/shared.d.ts +3 -0
- package/dist/commands/sys/shared.js +24 -0
- package/dist/commands/sys/update.d.ts +2 -0
- package/dist/commands/sys/update.js +114 -0
- package/dist/commands/sys.js +4 -694
- package/dist/core/__tests__/argv-parser.test.js +19 -1
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +100 -0
- package/dist/core/__tests__/canvas.test.js +154 -0
- package/dist/core/__tests__/reset.test.js +105 -0
- package/dist/core/canvas/attention.d.ts +24 -0
- package/dist/core/canvas/attention.js +94 -0
- package/dist/core/canvas/canvas.d.ts +40 -0
- package/dist/core/canvas/canvas.js +210 -0
- package/dist/core/canvas/db.d.ts +7 -0
- package/dist/core/canvas/db.js +61 -0
- package/dist/core/canvas/index.d.ts +4 -0
- package/dist/core/canvas/index.js +6 -0
- package/dist/core/canvas/paths.d.ts +16 -0
- package/dist/core/canvas/paths.js +62 -0
- package/dist/core/canvas/render.d.ts +30 -0
- package/dist/core/canvas/render.js +186 -0
- package/dist/core/canvas/types.d.ts +87 -0
- package/dist/core/canvas/types.js +8 -0
- package/dist/core/command.d.ts +5 -0
- package/dist/core/command.js +35 -10
- package/dist/core/feed/feed.d.ts +43 -0
- package/dist/core/feed/feed.js +116 -0
- package/dist/core/feed/inbox.d.ts +50 -0
- package/dist/core/feed/inbox.js +124 -0
- package/dist/core/help.js +5 -3
- package/dist/core/io.d.ts +15 -1
- package/dist/core/io.js +56 -6
- package/dist/core/personas/index.d.ts +12 -0
- package/dist/core/personas/index.js +10 -0
- package/dist/core/personas/loader.d.ts +44 -0
- package/dist/core/personas/loader.js +157 -0
- package/dist/core/personas/resolve.d.ts +36 -0
- package/dist/core/personas/resolve.js +110 -0
- package/dist/core/render.d.ts +11 -0
- package/dist/core/render.js +126 -0
- package/dist/core/resolver.d.ts +10 -0
- package/dist/core/resolver.js +109 -1
- package/dist/core/runtime/front-door.d.ts +10 -0
- package/dist/core/runtime/front-door.js +97 -0
- package/dist/core/runtime/kickoff.d.ts +23 -0
- package/dist/core/runtime/kickoff.js +134 -0
- package/dist/core/runtime/launch.d.ts +34 -0
- package/dist/core/runtime/launch.js +85 -0
- package/dist/core/runtime/nodes.d.ts +38 -0
- package/dist/core/runtime/nodes.js +95 -0
- package/dist/core/runtime/presence.d.ts +38 -0
- package/dist/core/runtime/presence.js +152 -0
- package/dist/core/runtime/promote.d.ts +30 -0
- package/dist/core/runtime/promote.js +105 -0
- package/dist/core/runtime/reset.d.ts +13 -0
- package/dist/core/runtime/reset.js +97 -0
- package/dist/core/runtime/revive.d.ts +26 -0
- package/dist/core/runtime/revive.js +89 -0
- package/dist/core/runtime/roadmap.d.ts +12 -0
- package/dist/core/runtime/roadmap.js +52 -0
- package/dist/core/runtime/spawn.d.ts +33 -0
- package/dist/core/runtime/spawn.js +118 -0
- package/dist/core/runtime/stop-guard.d.ts +18 -0
- package/dist/core/runtime/stop-guard.js +33 -0
- package/dist/core/runtime/tmux.d.ts +88 -0
- package/dist/core/runtime/tmux.js +198 -0
- package/dist/core/spawn.d.ts +17 -197
- package/dist/core/spawn.js +16 -539
- package/dist/daemon/crtrd-cli.js +4 -0
- package/dist/daemon/crtrd.d.ts +20 -0
- package/dist/daemon/crtrd.js +200 -0
- package/dist/daemon/manage.d.ts +17 -0
- package/dist/daemon/manage.js +57 -0
- package/dist/pi-extensions/canvas-inbox-watcher.d.ts +16 -0
- package/dist/pi-extensions/canvas-inbox-watcher.js +229 -0
- package/dist/pi-extensions/canvas-nav.d.ts +32 -0
- package/dist/pi-extensions/canvas-nav.js +536 -0
- package/dist/pi-extensions/canvas-stophook.d.ts +17 -0
- package/dist/pi-extensions/canvas-stophook.js +373 -0
- package/package.json +6 -5
- package/dist/commands/agent.d.ts +0 -6
- package/dist/commands/agent.js +0 -585
- package/dist/commands/debug.d.ts +0 -3
- package/dist/commands/debug.js +0 -192
- package/dist/commands/job.d.ts +0 -11
- package/dist/commands/job.js +0 -384
- package/dist/commands/mode.js +0 -231
- package/dist/commands/plan.d.ts +0 -4
- package/dist/commands/plan.js +0 -322
- package/dist/commands/spec.d.ts +0 -3
- package/dist/commands/spec.js +0 -299
- package/dist/core/__tests__/flow-leaves.test.js +0 -248
- package/dist/core/__tests__/job.test.js +0 -310
- package/dist/core/__tests__/jobs.test.js +0 -98
- package/dist/core/__tests__/spawn.test.js +0 -138
- package/dist/core/__tests__/subagents.test.d.ts +0 -1
- package/dist/core/__tests__/subagents.test.js +0 -75
- package/dist/core/jobs.d.ts +0 -107
- package/dist/core/jobs.js +0 -565
- package/dist/core/subagents.d.ts +0 -18
- package/dist/core/subagents.js +0 -163
- package/dist/prompts/agent.d.ts +0 -27
- package/dist/prompts/agent.js +0 -184
- package/dist/prompts/debug.d.ts +0 -8
- package/dist/prompts/debug.js +0 -44
- /package/dist/core/__tests__/{flow-leaves.test.d.ts → canvas-inbox-watcher.test.d.ts} +0 -0
- /package/dist/core/__tests__/{job.test.d.ts → canvas.test.d.ts} +0 -0
- /package/dist/core/__tests__/{jobs.test.d.ts → reset.test.d.ts} +0 -0
- /package/dist/{core/__tests__/spawn.test.d.ts → daemon/crtrd-cli.d.ts} +0 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { join, isAbsolute } from 'node:path';
|
|
2
|
+
import { renameSync } from 'node:fs';
|
|
3
|
+
import { defineBranch, defineLeaf } from '../../core/command.js';
|
|
4
|
+
import { notFound } from '../../core/errors.js';
|
|
5
|
+
import { listAllMarketplaces, findMarketplaceByName } from '../../core/resolver.js';
|
|
6
|
+
import { resolveScopeArg, requireScopeRoot } from '../../core/scope.js';
|
|
7
|
+
import { updateConfig, updateState, ensureScopeInitialized, readConfig } from '../../core/config.js';
|
|
8
|
+
import { pathExists, ensureDir, removePath, linkOrCopy, isSymlink, nowIso } from '../../core/fs-utils.js';
|
|
9
|
+
import { clone, pull, deriveNameFromUrl, currentSha } from '../../core/git.js';
|
|
10
|
+
import { readMarketplaceManifest, readPluginManifest } from '../../core/manifest.js';
|
|
11
|
+
import { resolveInstallScope } from './shared.js';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// market.manage.add
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
const marketAdd = defineLeaf({
|
|
16
|
+
name: 'add',
|
|
17
|
+
help: {
|
|
18
|
+
name: 'pkg market manage add',
|
|
19
|
+
summary: 'add a marketplace by git URL',
|
|
20
|
+
params: [
|
|
21
|
+
{ kind: 'flag', name: 'url', type: 'string', required: true, constraint: 'Git URL of the marketplace repo.' },
|
|
22
|
+
{ kind: 'flag', name: 'ref', type: 'string', required: false, constraint: 'Git ref to track. Default: main.' },
|
|
23
|
+
{ kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'One of: user, project. Default: project if available, else user.' },
|
|
24
|
+
],
|
|
25
|
+
output: [
|
|
26
|
+
{ name: 'name', type: 'string', required: true, constraint: 'Marketplace name as declared in marketplace.json.' },
|
|
27
|
+
{ name: 'scope', type: 'string', required: true, constraint: 'Scope the marketplace was added into.' },
|
|
28
|
+
{ name: 'path', type: 'string', required: true, constraint: 'Absolute path to the cloned marketplace directory.' },
|
|
29
|
+
],
|
|
30
|
+
outputKind: 'object',
|
|
31
|
+
effects: ['Clones the marketplace repo. Registers the marketplace in config.json.'],
|
|
32
|
+
},
|
|
33
|
+
run: async (input) => {
|
|
34
|
+
const url = input['url'];
|
|
35
|
+
const ref = input['ref'];
|
|
36
|
+
const scopeInput = input['scope'];
|
|
37
|
+
const scope = resolveInstallScope(scopeInput);
|
|
38
|
+
const root = requireScopeRoot(scope);
|
|
39
|
+
ensureScopeInitialized(scope, root);
|
|
40
|
+
const tempName = deriveNameFromUrl(url);
|
|
41
|
+
const mktsDir = join(root, 'marketplaces');
|
|
42
|
+
ensureDir(mktsDir);
|
|
43
|
+
const tempDest = join(mktsDir, tempName);
|
|
44
|
+
if (pathExists(tempDest)) {
|
|
45
|
+
removePath(tempDest);
|
|
46
|
+
}
|
|
47
|
+
clone(url, tempDest, { depth: 1, ref: ref !== undefined ? ref : undefined });
|
|
48
|
+
const manifest = readMarketplaceManifest(tempDest);
|
|
49
|
+
if (!manifest) {
|
|
50
|
+
removePath(tempDest);
|
|
51
|
+
throw notFound(`marketplace manifest not found at ${tempDest}/.crouter-marketplace/marketplace.json — not a valid marketplace`);
|
|
52
|
+
}
|
|
53
|
+
const finalName = manifest.name;
|
|
54
|
+
const finalDest = join(mktsDir, finalName);
|
|
55
|
+
if (finalName !== tempName) {
|
|
56
|
+
if (pathExists(finalDest)) {
|
|
57
|
+
removePath(finalDest);
|
|
58
|
+
}
|
|
59
|
+
renameSync(tempDest, finalDest);
|
|
60
|
+
}
|
|
61
|
+
const effectiveRef = ref !== undefined ? ref : 'main';
|
|
62
|
+
updateConfig(scope, (cfg) => {
|
|
63
|
+
cfg.marketplaces[finalName] = {
|
|
64
|
+
url,
|
|
65
|
+
ref: effectiveRef,
|
|
66
|
+
installed_at: nowIso(),
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
return { name: finalName, scope, path: finalDest };
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// market.manage.remove
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
const marketRemove = defineLeaf({
|
|
76
|
+
name: 'remove',
|
|
77
|
+
help: {
|
|
78
|
+
name: 'pkg market manage remove',
|
|
79
|
+
summary: 'remove a marketplace and its directory',
|
|
80
|
+
params: [
|
|
81
|
+
{ kind: 'positional', name: 'name', type: 'string', required: true, constraint: 'Marketplace name to remove.' },
|
|
82
|
+
{ kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'One of: user, project.' },
|
|
83
|
+
],
|
|
84
|
+
output: [
|
|
85
|
+
{ name: 'name', type: 'string', required: true, constraint: 'Removed marketplace name.' },
|
|
86
|
+
{ name: 'removed', type: 'boolean', required: true, constraint: 'Always true on success.' },
|
|
87
|
+
],
|
|
88
|
+
outputKind: 'object',
|
|
89
|
+
effects: ['Deletes the marketplace directory. Removes the entry from config.json.'],
|
|
90
|
+
},
|
|
91
|
+
run: async (input) => {
|
|
92
|
+
const name = input['name'];
|
|
93
|
+
const scopeInput = input['scope'];
|
|
94
|
+
let targetScope;
|
|
95
|
+
let mktRoot;
|
|
96
|
+
if (scopeInput !== undefined) {
|
|
97
|
+
const resolved = resolveScopeArg(scopeInput);
|
|
98
|
+
if (resolved !== 'all' && resolved !== 'builtin') {
|
|
99
|
+
const s = resolved;
|
|
100
|
+
const found = findMarketplaceByName(name, s);
|
|
101
|
+
if (!found)
|
|
102
|
+
throw notFound(`marketplace not found: ${name} (scope: ${s})`);
|
|
103
|
+
targetScope = s;
|
|
104
|
+
mktRoot = found.root;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const found = findMarketplaceByName(name);
|
|
108
|
+
if (!found)
|
|
109
|
+
throw notFound(`marketplace not found: ${name}`);
|
|
110
|
+
targetScope = found.scope;
|
|
111
|
+
mktRoot = found.root;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const found = findMarketplaceByName(name);
|
|
116
|
+
if (!found)
|
|
117
|
+
throw notFound(`marketplace not found: ${name}`);
|
|
118
|
+
targetScope = found.scope;
|
|
119
|
+
mktRoot = found.root;
|
|
120
|
+
}
|
|
121
|
+
const scope = targetScope;
|
|
122
|
+
const scopeRootPath = requireScopeRoot(scope);
|
|
123
|
+
const plgDir = join(scopeRootPath, 'plugins');
|
|
124
|
+
const cfg = readConfig(scope);
|
|
125
|
+
const pluginsToRemove = [];
|
|
126
|
+
for (const [pluginName, entry] of Object.entries(cfg.plugins)) {
|
|
127
|
+
if (entry.source_marketplace === name) {
|
|
128
|
+
pluginsToRemove.push(pluginName);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const pluginName of pluginsToRemove) {
|
|
132
|
+
const pluginPath = join(plgDir, pluginName);
|
|
133
|
+
removePath(pluginPath);
|
|
134
|
+
}
|
|
135
|
+
removePath(mktRoot);
|
|
136
|
+
updateConfig(scope, (c) => {
|
|
137
|
+
delete c.marketplaces[name];
|
|
138
|
+
for (const pluginName of pluginsToRemove) {
|
|
139
|
+
delete c.plugins[pluginName];
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
return { name, removed: true };
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
// market.manage.update
|
|
147
|
+
// Single marketplace: blocking. All marketplaces: job handle.
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
const marketUpdate = defineLeaf({
|
|
150
|
+
name: 'update',
|
|
151
|
+
help: {
|
|
152
|
+
name: 'pkg market manage update',
|
|
153
|
+
summary: 'git pull updates for one or all registered marketplaces',
|
|
154
|
+
params: [
|
|
155
|
+
{ kind: 'flag', name: 'marketplace', type: 'string', required: false, constraint: 'Marketplace name to update. Omit to update all (returns a job handle).' },
|
|
156
|
+
],
|
|
157
|
+
output: [
|
|
158
|
+
{ name: 'updated', type: 'object[]', required: false, constraint: 'Present for single (blocking) path: [{name, updated, sha}].' },
|
|
159
|
+
{ name: 'updated', type: 'object[]', required: true, constraint: 'One entry per marketplace processed: {name, updated, sha}.' },
|
|
160
|
+
],
|
|
161
|
+
outputKind: 'object',
|
|
162
|
+
effects: ['Runs git pull in marketplace directories.'],
|
|
163
|
+
},
|
|
164
|
+
run: async (input) => {
|
|
165
|
+
const name = input['marketplace'];
|
|
166
|
+
async function doUpdate(targets) {
|
|
167
|
+
const results = [];
|
|
168
|
+
for (const target of targets) {
|
|
169
|
+
const shaBefore = currentSha(target.root);
|
|
170
|
+
const res = pull(target.root);
|
|
171
|
+
if (res.status !== 0) {
|
|
172
|
+
results.push({ name: target.name, updated: false, sha: shaBefore !== null ? shaBefore : '' });
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const shaAfter = currentSha(target.root);
|
|
176
|
+
const updated = shaBefore !== shaAfter;
|
|
177
|
+
const freshManifest = readMarketplaceManifest(target.root);
|
|
178
|
+
updateState(target.scope, (s) => {
|
|
179
|
+
if (s.marketplaces[target.name] === undefined) {
|
|
180
|
+
s.marketplaces[target.name] = {};
|
|
181
|
+
}
|
|
182
|
+
s.marketplaces[target.name].last_updated = nowIso();
|
|
183
|
+
});
|
|
184
|
+
const cfg = readConfig(target.scope);
|
|
185
|
+
for (const [pluginName, entry] of Object.entries(cfg.plugins)) {
|
|
186
|
+
if (entry.source_marketplace !== target.name)
|
|
187
|
+
continue;
|
|
188
|
+
const scopeRootPath = requireScopeRoot(target.scope);
|
|
189
|
+
const pluginPath = join(scopeRootPath, 'plugins', pluginName);
|
|
190
|
+
if (isSymlink(pluginPath)) {
|
|
191
|
+
// content updated by marketplace pull above
|
|
192
|
+
}
|
|
193
|
+
else if (pathExists(pluginPath)) {
|
|
194
|
+
pull(pluginPath);
|
|
195
|
+
}
|
|
196
|
+
if (freshManifest !== null) {
|
|
197
|
+
const pluginEntry = freshManifest.plugins.find((p) => p.name === pluginName);
|
|
198
|
+
if (pluginEntry !== undefined && pluginEntry.version !== undefined) {
|
|
199
|
+
updateConfig(target.scope, (c) => {
|
|
200
|
+
if (c.plugins[pluginName] !== undefined) {
|
|
201
|
+
c.plugins[pluginName].version = pluginEntry.version;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
updateState(target.scope, (s) => {
|
|
207
|
+
if (s.plugins[pluginName] === undefined) {
|
|
208
|
+
s.plugins[pluginName] = {};
|
|
209
|
+
}
|
|
210
|
+
s.plugins[pluginName].last_updated = nowIso();
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
results.push({ name: target.name, updated, sha: shaAfter !== null ? shaAfter : '' });
|
|
214
|
+
}
|
|
215
|
+
return results;
|
|
216
|
+
}
|
|
217
|
+
if (name !== undefined) {
|
|
218
|
+
// Single marketplace — blocking
|
|
219
|
+
const found = findMarketplaceByName(name);
|
|
220
|
+
if (!found)
|
|
221
|
+
throw notFound(`marketplace not found: ${name}`);
|
|
222
|
+
const results = await doUpdate([{ name: found.name, scope: found.scope, root: found.root }]);
|
|
223
|
+
return { updated: results };
|
|
224
|
+
}
|
|
225
|
+
// All marketplaces — run synchronously (the underlying git pulls are sync).
|
|
226
|
+
const all = listAllMarketplaces();
|
|
227
|
+
const targets = all.map((m) => ({ name: m.name, scope: m.scope, root: m.root }));
|
|
228
|
+
const results = await doUpdate(targets);
|
|
229
|
+
return { updated: results };
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
// market.manage.install
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
const marketInstall = defineLeaf({
|
|
236
|
+
name: 'install',
|
|
237
|
+
help: {
|
|
238
|
+
name: 'pkg market manage install',
|
|
239
|
+
summary: 'install a plugin from an added marketplace by plugin name',
|
|
240
|
+
params: [
|
|
241
|
+
{ kind: 'flag', name: 'marketplace', type: 'string', required: true, constraint: 'Marketplace name (must already be added via `pkg market manage add`).' },
|
|
242
|
+
{ kind: 'flag', name: 'plugin', type: 'string', required: true, constraint: 'Plugin name as listed in the marketplace manifest.' },
|
|
243
|
+
{ kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'One of: user, project. Default: project if available, else user.' },
|
|
244
|
+
],
|
|
245
|
+
output: [
|
|
246
|
+
{ name: 'name', type: 'string', required: true, constraint: 'Installed plugin name.' },
|
|
247
|
+
{ name: 'scope', type: 'string', required: true, constraint: 'Scope the plugin was installed into.' },
|
|
248
|
+
{ name: 'path', type: 'string', required: true, constraint: 'Absolute path to the installed plugin directory.' },
|
|
249
|
+
],
|
|
250
|
+
outputKind: 'object',
|
|
251
|
+
effects: ['Clones or copies the plugin from the marketplace into the scope plugins directory. Registers the plugin in config.json with source_marketplace set.'],
|
|
252
|
+
},
|
|
253
|
+
run: async (input) => {
|
|
254
|
+
const mktName = input['marketplace'];
|
|
255
|
+
const pluginName = input['plugin'];
|
|
256
|
+
const scopeInput = input['scope'];
|
|
257
|
+
const mkt = findMarketplaceByName(mktName);
|
|
258
|
+
if (!mkt)
|
|
259
|
+
throw notFound(`marketplace not found: ${mktName}`);
|
|
260
|
+
const entry = mkt.manifest.plugins.find((p) => p.name === pluginName);
|
|
261
|
+
if (!entry)
|
|
262
|
+
throw notFound(`plugin "${pluginName}" not found in marketplace "${mktName}"`);
|
|
263
|
+
const destScope = resolveInstallScope(scopeInput);
|
|
264
|
+
const destRoot = requireScopeRoot(destScope);
|
|
265
|
+
ensureScopeInitialized(destScope, destRoot);
|
|
266
|
+
const destPluginDir = join(destRoot, 'plugins', pluginName);
|
|
267
|
+
const source = entry.source;
|
|
268
|
+
const isRelativePath = source.startsWith('./') ||
|
|
269
|
+
source.startsWith('../') ||
|
|
270
|
+
(!source.includes('://') && !isAbsolute(source));
|
|
271
|
+
if (isRelativePath) {
|
|
272
|
+
const sourcePath = join(mkt.root, source);
|
|
273
|
+
if (!pathExists(sourcePath)) {
|
|
274
|
+
throw notFound(`plugin source path does not exist: ${sourcePath}`);
|
|
275
|
+
}
|
|
276
|
+
linkOrCopy(sourcePath, destPluginDir);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
if (pathExists(destPluginDir)) {
|
|
280
|
+
removePath(destPluginDir);
|
|
281
|
+
}
|
|
282
|
+
clone(source, destPluginDir, { depth: 1 });
|
|
283
|
+
}
|
|
284
|
+
const pluginManifest = readPluginManifest(destPluginDir);
|
|
285
|
+
if (!pluginManifest) {
|
|
286
|
+
removePath(destPluginDir);
|
|
287
|
+
throw notFound(`plugin manifest not found at ${destPluginDir}/.crouter-plugin/plugin.json`);
|
|
288
|
+
}
|
|
289
|
+
const version = entry.version !== undefined ? entry.version : pluginManifest.version;
|
|
290
|
+
updateConfig(destScope, (cfg) => {
|
|
291
|
+
const pluginCfg = {
|
|
292
|
+
enabled: true,
|
|
293
|
+
source_marketplace: mktName,
|
|
294
|
+
};
|
|
295
|
+
if (version !== undefined) {
|
|
296
|
+
pluginCfg.version = version;
|
|
297
|
+
}
|
|
298
|
+
cfg.plugins[pluginName] = pluginCfg;
|
|
299
|
+
});
|
|
300
|
+
return { name: pluginName, scope: destScope, path: destPluginDir };
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
export const marketManageBranch = defineBranch({
|
|
304
|
+
name: 'manage',
|
|
305
|
+
help: {
|
|
306
|
+
name: 'pkg market manage',
|
|
307
|
+
summary: 'add, remove, update, or install from marketplaces',
|
|
308
|
+
children: [
|
|
309
|
+
{ name: 'add', desc: 'add a marketplace by git URL', useWhen: 'registering a new marketplace source' },
|
|
310
|
+
{ name: 'remove', desc: 'remove a marketplace', useWhen: 'unregistering a marketplace' },
|
|
311
|
+
{ name: 'update', desc: 'pull latest marketplace index', useWhen: 'refreshing the marketplace plugin list' },
|
|
312
|
+
{ name: 'install', desc: 'install a plugin from a marketplace', useWhen: 'adding a plugin sourced from a registered marketplace' },
|
|
313
|
+
],
|
|
314
|
+
},
|
|
315
|
+
children: [marketAdd, marketRemove, marketUpdate, marketInstall],
|
|
316
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const marketBranch: import("../../core/command.js").BranchDef;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineBranch } from '../../core/command.js';
|
|
2
|
+
import { marketManageBranch } from './market-manage.js';
|
|
3
|
+
import { marketInspectBranch } from './market-inspect.js';
|
|
4
|
+
export const marketBranch = defineBranch({
|
|
5
|
+
name: 'market',
|
|
6
|
+
help: {
|
|
7
|
+
name: 'pkg market',
|
|
8
|
+
summary: 'manage and browse plugin marketplaces',
|
|
9
|
+
model: 'Marketplaces are git repos containing a .crouter-marketplace/marketplace.json index of plugins.',
|
|
10
|
+
children: [
|
|
11
|
+
{ name: 'manage', desc: 'add, remove, update, install', useWhen: 'changing marketplace or marketplace-sourced plugin state' },
|
|
12
|
+
{ name: 'inspect', desc: 'list or browse marketplaces', useWhen: 'reading marketplace metadata' },
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
children: [marketManageBranch, marketInspectBranch],
|
|
16
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const pluginInspectBranch: import("../../core/command.js").BranchDef;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { defineBranch, defineLeaf } from '../../core/command.js';
|
|
2
|
+
import { notFound } from '../../core/errors.js';
|
|
3
|
+
import { paginate } from '../../core/pagination.js';
|
|
4
|
+
import { listInstalledPlugins, findPluginByName, listSkillsInPlugin, } from '../../core/resolver.js';
|
|
5
|
+
import { resolveScopeArg, projectScopeRoot } from '../../core/scope.js';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// plugin.inspect.list
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const pluginList = defineLeaf({
|
|
10
|
+
name: 'list',
|
|
11
|
+
help: {
|
|
12
|
+
name: 'pkg plugin inspect list',
|
|
13
|
+
summary: 'paginated list of installed plugins',
|
|
14
|
+
params: [
|
|
15
|
+
{ kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project', 'all'], required: false, constraint: 'Default: all.' },
|
|
16
|
+
{ kind: 'flag', name: 'include-disabled', type: 'bool', required: false, constraint: 'Include disabled plugins. Default: false.' },
|
|
17
|
+
{ kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: 'Default 50, max 200.' },
|
|
18
|
+
{ kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: 'Opaque token from next_cursor. Omit on first call.' },
|
|
19
|
+
],
|
|
20
|
+
output: [
|
|
21
|
+
{ name: 'items', type: 'object[]', required: true, constraint: 'Each: {name, scope, version?, enabled, source_marketplace?, path}. Sorted by scope then name ascending.' },
|
|
22
|
+
{ name: 'next_cursor', type: 'string | null', required: true, constraint: 'null means no more items.' },
|
|
23
|
+
{ name: 'total', type: 'integer | null', required: true, constraint: 'Exact when cheap; null otherwise.' },
|
|
24
|
+
],
|
|
25
|
+
outputKind: 'object',
|
|
26
|
+
effects: ['None. Read-only.'],
|
|
27
|
+
},
|
|
28
|
+
run: async (input) => {
|
|
29
|
+
const scopeInput = input['scope'];
|
|
30
|
+
const includeDisabled = input['includeDisabled'] ?? false;
|
|
31
|
+
const limitRaw = input['limit'];
|
|
32
|
+
const limit = limitRaw !== undefined ? Math.min(Math.max(1, limitRaw), 200) : 50;
|
|
33
|
+
const cursor = input['cursor'];
|
|
34
|
+
let scopesToScan;
|
|
35
|
+
if (scopeInput !== undefined) {
|
|
36
|
+
const resolved = resolveScopeArg(scopeInput);
|
|
37
|
+
scopesToScan = resolved === 'all'
|
|
38
|
+
? ['project', 'user'].filter((s) => s !== 'project' || projectScopeRoot() !== null)
|
|
39
|
+
: [resolved];
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
scopesToScan = ['project', 'user'].filter((s) => s !== 'project' || projectScopeRoot() !== null);
|
|
43
|
+
}
|
|
44
|
+
const all = scopesToScan
|
|
45
|
+
.flatMap((s) => listInstalledPlugins(s))
|
|
46
|
+
.filter((p) => includeDisabled || p.enabled)
|
|
47
|
+
.sort((a, b) => {
|
|
48
|
+
if (a.scope === 'project' && b.scope !== 'project')
|
|
49
|
+
return -1;
|
|
50
|
+
if (a.scope !== 'project' && b.scope === 'project')
|
|
51
|
+
return 1;
|
|
52
|
+
return a.name.localeCompare(b.name);
|
|
53
|
+
});
|
|
54
|
+
const result = paginate(all, { limit, cursor: cursor !== undefined ? cursor : undefined }, {
|
|
55
|
+
defaultLimit: 50,
|
|
56
|
+
maxLimit: 200,
|
|
57
|
+
keyOf: (p) => `${p.scope}:${p.name}`,
|
|
58
|
+
total: 'count',
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
items: result.items.map((p) => ({
|
|
62
|
+
name: p.name,
|
|
63
|
+
scope: p.scope,
|
|
64
|
+
version: p.version,
|
|
65
|
+
enabled: p.enabled,
|
|
66
|
+
source_marketplace: p.sourceMarketplace,
|
|
67
|
+
path: p.root,
|
|
68
|
+
})),
|
|
69
|
+
next_cursor: result.next_cursor,
|
|
70
|
+
total: result.total,
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// plugin.inspect.show
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
const pluginShow = defineLeaf({
|
|
78
|
+
name: 'show',
|
|
79
|
+
help: {
|
|
80
|
+
name: 'pkg plugin inspect show',
|
|
81
|
+
summary: 'read plugin manifest and metadata by name',
|
|
82
|
+
params: [
|
|
83
|
+
{ kind: 'positional', name: 'name', type: 'string', required: true, constraint: 'Plugin name.' },
|
|
84
|
+
{ kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'One of: user, project. Narrows resolution.' },
|
|
85
|
+
],
|
|
86
|
+
output: [
|
|
87
|
+
{ name: 'name', type: 'string', required: true, constraint: 'Plugin name.' },
|
|
88
|
+
{ name: 'scope', type: 'string', required: true, constraint: 'Scope the plugin is installed in.' },
|
|
89
|
+
{ name: 'path', type: 'string', required: true, constraint: 'Absolute path to the plugin directory.' },
|
|
90
|
+
{ name: 'enabled', type: 'boolean', required: true, constraint: 'Whether the plugin is active.' },
|
|
91
|
+
{ name: 'manifest', type: 'object', required: true, constraint: 'Full plugin.json contents.' },
|
|
92
|
+
{ name: 'skills', type: 'object[]', required: true, constraint: 'Each: {name, path, enabled}. Skills provided by the plugin.' },
|
|
93
|
+
],
|
|
94
|
+
outputKind: 'object',
|
|
95
|
+
effects: ['None. Read-only.'],
|
|
96
|
+
},
|
|
97
|
+
run: async (input) => {
|
|
98
|
+
const name = input['name'];
|
|
99
|
+
const scopeInput = input['scope'];
|
|
100
|
+
let found;
|
|
101
|
+
if (scopeInput !== undefined) {
|
|
102
|
+
const resolved = resolveScopeArg(scopeInput);
|
|
103
|
+
if (resolved === 'all' || resolved === 'builtin') {
|
|
104
|
+
found = findPluginByName(name);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
found = findPluginByName(name, resolved);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
found = findPluginByName(name);
|
|
112
|
+
}
|
|
113
|
+
if (found === null) {
|
|
114
|
+
throw notFound(`plugin not found: ${name}`);
|
|
115
|
+
}
|
|
116
|
+
const skills = listSkillsInPlugin(found);
|
|
117
|
+
return {
|
|
118
|
+
name: found.name,
|
|
119
|
+
scope: found.scope,
|
|
120
|
+
path: found.root,
|
|
121
|
+
enabled: found.enabled,
|
|
122
|
+
manifest: found.manifest,
|
|
123
|
+
skills: skills.map((s) => ({
|
|
124
|
+
name: s.name,
|
|
125
|
+
path: s.path,
|
|
126
|
+
enabled: s.enabled,
|
|
127
|
+
})),
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
export const pluginInspectBranch = defineBranch({
|
|
132
|
+
name: 'inspect',
|
|
133
|
+
help: {
|
|
134
|
+
name: 'pkg plugin inspect',
|
|
135
|
+
summary: 'read plugin metadata without modifying state',
|
|
136
|
+
children: [
|
|
137
|
+
{ name: 'list', desc: 'paginated list of installed plugins', useWhen: 'enumerating what plugins are installed' },
|
|
138
|
+
{ name: 'show', desc: 'read plugin manifest and skill inventory', useWhen: 'inspecting a specific plugin\'s details' },
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
children: [pluginList, pluginShow],
|
|
142
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const pluginManageBranch: import("../../core/command.js").BranchDef;
|