quiver-cli 0.8.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -45
- package/bin/quiver-cli.mjs +3 -1
- package/dist/cli.js +666 -436
- package/package.json +2 -2
- package/template/.agents/AGENTS.md +4 -3
- package/template/.agents/config.json +7 -0
- package/template/.agents/plugins/opencode/rtk.ts +34 -0
- package/template/.agents/skills/agent-browser/SKILL.md +1 -0
- package/template/.agents/skills/apps/skybridge/SKILL.md +4 -0
- package/template/.agents/skills/design/impeccable/SKILL.md +36 -118
- package/template/.agents/skills/design/impeccable/reference/adapt.md +1 -0
- package/template/.agents/skills/design/impeccable/reference/adapt.native.md +58 -0
- package/template/.agents/skills/design/impeccable/reference/android.md +40 -0
- package/template/.agents/skills/design/impeccable/reference/animate.md +73 -188
- package/template/.agents/skills/design/impeccable/reference/audit.md +12 -9
- package/template/.agents/skills/design/impeccable/reference/audit.native.md +139 -0
- package/template/.agents/skills/design/impeccable/reference/bolder.md +19 -101
- package/template/.agents/skills/design/impeccable/reference/clarify.md +59 -253
- package/template/.agents/skills/design/impeccable/reference/colorize.md +51 -222
- package/template/.agents/skills/design/impeccable/reference/craft-floor.md +42 -0
- package/template/.agents/skills/design/impeccable/reference/craft.md +3 -121
- package/template/.agents/skills/design/impeccable/reference/critique.md +44 -23
- package/template/.agents/skills/design/impeccable/reference/degraded/asset-producer.md +90 -0
- package/template/.agents/skills/design/impeccable/reference/degraded/documenter.md +24 -0
- package/template/.agents/skills/design/impeccable/reference/degraded/finish-reviewer.md +37 -0
- package/template/.agents/skills/design/impeccable/reference/degraded/manual-edit-applier.md +92 -0
- package/template/.agents/skills/design/impeccable/reference/delight.md +47 -279
- package/template/.agents/skills/design/impeccable/reference/distill.md +2 -2
- package/template/.agents/skills/design/impeccable/reference/doctor.md +53 -0
- package/template/.agents/skills/design/impeccable/reference/document.md +60 -73
- package/template/.agents/skills/design/impeccable/reference/harden.md +1 -12
- package/template/.agents/skills/design/impeccable/reference/hooks.md +20 -5
- package/template/.agents/skills/design/impeccable/reference/init.md +72 -119
- package/template/.agents/skills/design/impeccable/reference/ios.md +45 -0
- package/template/.agents/skills/design/impeccable/reference/layout.md +54 -131
- package/template/.agents/skills/design/impeccable/reference/live-setup.md +102 -0
- package/template/.agents/skills/design/impeccable/reference/live.md +116 -511
- package/template/.agents/skills/design/impeccable/reference/new-work.md +105 -0
- package/template/.agents/skills/design/impeccable/reference/{product.md → operate.md} +6 -5
- package/template/.agents/skills/design/impeccable/reference/optimize.md +4 -4
- package/template/.agents/skills/design/impeccable/reference/overdrive.md +1 -4
- package/template/.agents/skills/design/impeccable/reference/polish.md +68 -212
- package/template/.agents/skills/design/impeccable/reference/quieter.md +3 -3
- package/template/.agents/skills/design/impeccable/reference/routing.md +18 -0
- package/template/.agents/skills/design/impeccable/reference/shape.md +38 -144
- package/template/.agents/skills/design/impeccable/reference/typeset.md +51 -250
- package/template/.agents/skills/design/impeccable/reference/visualize.md +47 -0
- package/template/.agents/skills/design/impeccable/scripts/command-metadata.json +1 -1
- package/template/.agents/skills/design/impeccable/scripts/concept-seed.mjs +558 -0
- package/template/.agents/skills/design/impeccable/scripts/context-signals.mjs +119 -10
- package/template/.agents/skills/design/impeccable/scripts/context.mjs +534 -45
- package/template/.agents/skills/design/impeccable/scripts/critique-storage.mjs +18 -47
- package/template/.agents/skills/design/impeccable/scripts/detector/browser/injected/index.mjs +96 -10
- package/template/.agents/skills/design/impeccable/scripts/detector/cli/main.mjs +174 -26
- package/template/.agents/skills/design/impeccable/scripts/detector/design-system.mjs +233 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns-browser.js +3348 -203
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/browser/detect-url.mjs +102 -7
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/regex/detect-text.mjs +297 -97
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +187 -16
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/detect-html.mjs +41 -11
- package/template/.agents/skills/design/impeccable/scripts/detector/findings.mjs +7 -1
- package/template/.agents/skills/design/impeccable/scripts/detector/node/file-system.mjs +16 -2
- package/template/.agents/skills/design/impeccable/scripts/detector/registry/antipatterns.mjs +207 -38
- package/template/.agents/skills/design/impeccable/scripts/detector/rules/checks.mjs +3082 -173
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/constants.mjs +11 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/fonts.mjs +30 -0
- package/template/.agents/skills/design/impeccable/scripts/doctor.mjs +336 -0
- package/template/.agents/skills/design/impeccable/scripts/embed-prompt.mjs +133 -0
- package/template/.agents/skills/design/impeccable/scripts/generate-image.mjs +240 -0
- package/template/.agents/skills/design/impeccable/scripts/hook-admin.mjs +98 -18
- package/template/.agents/skills/design/impeccable/scripts/hook-before-edit.mjs +46 -6
- package/template/.agents/skills/design/impeccable/scripts/hook-lib.mjs +518 -50
- package/template/.agents/skills/design/impeccable/scripts/hook.mjs +25 -8
- package/template/.agents/skills/design/impeccable/scripts/lib/artifact-schema.mjs +93 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/composition-catalog.mjs +200 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/concept-catalog.mjs +357 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-config.mjs +27 -7
- package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-paths.mjs +17 -8
- package/template/.agents/skills/design/impeccable/scripts/lib/provider.mjs +5 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/roll-selection.mjs +362 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness-deep.mjs +457 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness-notice.mjs +169 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness.mjs +457 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/surface-briefs.mjs +151 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/target-slug.mjs +33 -0
- package/template/.agents/skills/design/impeccable/scripts/lib/template-extensions.mjs +146 -0
- package/template/.agents/skills/design/impeccable/scripts/live/accept-css.mjs +617 -0
- package/template/.agents/skills/design/impeccable/scripts/live/accept-verify.mjs +60 -0
- package/template/.agents/skills/design/impeccable/scripts/live/browser-script-parts.mjs +7 -1
- package/template/.agents/skills/design/impeccable/scripts/live/completion.mjs +10 -1
- package/template/.agents/skills/design/impeccable/scripts/live/event-validation.mjs +67 -5
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/astro.mjs +47 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/detect-utils.mjs +73 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/index.mjs +143 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/journal.mjs +197 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nextjs.mjs +49 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nuxt.mjs +161 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/script-src.mjs +17 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/static-html.mjs +26 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/sveltekit.mjs +71 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tag-strategy.mjs +247 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tanstack-start.mjs +70 -0
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/vite-generic.mjs +42 -0
- package/template/.agents/skills/design/impeccable/scripts/live/generation-preflight.mjs +149 -0
- package/template/.agents/skills/design/impeccable/scripts/live/instructions.mjs +142 -0
- package/template/.agents/skills/design/impeccable/scripts/live/poll-lanes.mjs +14 -0
- package/template/.agents/skills/design/impeccable/scripts/live/roots.mjs +508 -0
- package/template/.agents/skills/design/impeccable/scripts/live/session-store.mjs +324 -50
- package/template/.agents/skills/design/impeccable/scripts/live/source-lock.mjs +105 -0
- package/template/.agents/skills/design/impeccable/scripts/live/source-search.mjs +105 -0
- package/template/.agents/skills/design/impeccable/scripts/live/svelte-ast.mjs +961 -0
- package/template/.agents/skills/design/impeccable/scripts/live/svelte-component.mjs +588 -72
- package/template/.agents/skills/design/impeccable/scripts/live/sveltekit-adapter.mjs +59 -17
- package/template/.agents/skills/design/impeccable/scripts/live/tanstack-adapter.mjs +280 -0
- package/template/.agents/skills/design/impeccable/scripts/live/vocabulary.mjs +135 -0
- package/template/.agents/skills/design/impeccable/scripts/live-accept.mjs +210 -68
- package/template/.agents/skills/design/impeccable/scripts/live-browser.js +1562 -223
- package/template/.agents/skills/design/impeccable/scripts/live-commit-manual-edits.mjs +3 -0
- package/template/.agents/skills/design/impeccable/scripts/live-complete.mjs +33 -1
- package/template/.agents/skills/design/impeccable/scripts/live-inject.mjs +175 -255
- package/template/.agents/skills/design/impeccable/scripts/live-insert.mjs +26 -6
- package/template/.agents/skills/design/impeccable/scripts/live-manual-edit-evidence.mjs +6 -1
- package/template/.agents/skills/design/impeccable/scripts/live-poll.mjs +61 -16
- package/template/.agents/skills/design/impeccable/scripts/live-resume.mjs +39 -10
- package/template/.agents/skills/design/impeccable/scripts/live-server.mjs +573 -47
- package/template/.agents/skills/design/impeccable/scripts/live-status.mjs +17 -7
- package/template/.agents/skills/design/impeccable/scripts/live-wrap.mjs +124 -91
- package/template/.agents/skills/design/impeccable/scripts/live.mjs +88 -26
- package/template/.agents/skills/design/impeccable/scripts/palette.mjs +76 -81
- package/template/.agents/skills/design/impeccable/scripts/pin.mjs +18 -11
- package/template/.agents/skills/design/impeccable/scripts/serve-question.mjs +932 -0
- package/template/.agents/skills/design/impeccable/scripts/surface-brief.mjs +74 -0
- package/template/.agents/skills/design/shadcn/SKILL.md +46 -11
- package/template/.agents/skills/design/shadcn/cli.md +49 -16
- package/template/.agents/skills/design/shadcn/customization.md +14 -7
- package/template/.agents/skills/design/shadcn/evals/evals.json +30 -0
- package/template/.agents/skills/design/shadcn/mcp.md +27 -16
- package/template/.agents/skills/design/shadcn/registry.md +277 -0
- package/template/.agents/skills/design/shadcn/rules/chat.md +224 -0
- package/template/.agents/skills/design/shadcn/rules/composition.md +20 -2
- package/template/.agents/skills/design/shadcn/rules/styling.md +23 -0
- package/template/.agents/skills/find-skills/SKILL.md +2 -3
- package/template/.agents/skills/hono/SKILL.md +579 -0
- package/template/.agents/skills/integrations/langfuse/SKILL.md +10 -6
- package/template/.agents/skills/integrations/langfuse/references/ci-cd.md +41 -0
- package/template/.agents/skills/integrations/langfuse/references/cli.md +8 -0
- package/template/.agents/skills/integrations/langfuse/references/error-analysis.md +15 -27
- package/template/.agents/skills/integrations/langfuse/references/instrumentation.md +39 -52
- package/template/.agents/skills/integrations/langfuse/references/judge-calibration.md +5 -2
- package/template/.agents/skills/integrations/langfuse/references/prompt-engineering.md +35 -0
- package/template/.agents/skills/integrations/langfuse/references/prompt-migration.md +41 -196
- package/template/.agents/skills/integrations/langfuse/references/skill-feedback.md +3 -0
- package/template/.agents/skills/integrations/langfuse/references/trace-evaluator-upgrade.md +76 -0
- package/template/.agents/skills/integrations/langfuse/references/user-feedback.md +4 -0
- package/template/.agents/skills/integrations/langfuse/references/v4-project-migration.md +73 -0
- package/template/.agents/skills/supabase/CHANGELOG.md +71 -0
- package/template/.agents/skills/supabase/SKILL.md +145 -0
- package/template/.agents/skills/supabase/assets/feedback-issue-template.md +17 -0
- package/template/.agents/skills/supabase/references/skill-feedback.md +17 -0
- package/template/.agents/skills/supabase-postgres-best-practices/CHANGELOG.md +73 -0
- package/template/.agents/skills/supabase-postgres-best-practices/SKILL.md +64 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/_contributing.md +170 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/_sections.md +39 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/_template.md +34 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -0
- package/template/.agents/upstreams.json +34 -12
- package/template/.agents/skills/design/impeccable/reference/brand.md +0 -108
- package/template/.agents/skills/design/impeccable/reference/codex.md +0 -105
- package/template/.agents/skills/design/impeccable/reference/interaction-design.md +0 -189
- package/template/.agents/skills/integrations/langfuse/references/sdk-upgrade.md +0 -175
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ var __export = (target, all) => {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
// src/ui/prompts.ts
|
|
12
|
-
var clackPromise, warnedClackUnavailable, loadClack, QUIVER_ART, TAGLINE, colorEnabled, palette, block, banner, outro, step, info, success, warn, error,
|
|
12
|
+
var clackPromise, warnedClackUnavailable, loadClack, QUIVER_ART, TAGLINE, colorEnabled, palette, block, banner, outro, step, info, success, warn, error, selectGrouped, selectGroupedText;
|
|
13
13
|
var init_prompts = __esm({
|
|
14
14
|
"src/ui/prompts.ts"() {
|
|
15
15
|
"use strict";
|
|
@@ -96,23 +96,6 @@ ${message}
|
|
|
96
96
|
if (clack) clack.log.error(message);
|
|
97
97
|
else console.error(message);
|
|
98
98
|
};
|
|
99
|
-
password = async (message) => {
|
|
100
|
-
const clack = await loadClack();
|
|
101
|
-
if (clack) {
|
|
102
|
-
const value = await clack.password({ message });
|
|
103
|
-
if (clack.isCancel(value)) return null;
|
|
104
|
-
return value;
|
|
105
|
-
}
|
|
106
|
-
const { createInterface } = await import("readline");
|
|
107
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
108
|
-
const answer = await new Promise((res) => {
|
|
109
|
-
rl.question(`${message}: `, (a) => {
|
|
110
|
-
rl.close();
|
|
111
|
-
res(a);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
return answer.trim() || null;
|
|
115
|
-
};
|
|
116
99
|
selectGrouped = async ({
|
|
117
100
|
message,
|
|
118
101
|
groups,
|
|
@@ -326,7 +309,7 @@ var init_frontmatter = __esm({
|
|
|
326
309
|
// src/catalog/discover.ts
|
|
327
310
|
import { existsSync, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
328
311
|
import { relative as relative2, resolve as resolve2 } from "path";
|
|
329
|
-
var readConfig, discoverSkills, discoverCommands, discoverMcp, loadCatalog;
|
|
312
|
+
var readConfig, discoverSkills, discoverCommands, discoverMcp, discoverPlugins, loadCatalog;
|
|
330
313
|
var init_discover = __esm({
|
|
331
314
|
"src/catalog/discover.ts"() {
|
|
332
315
|
"use strict";
|
|
@@ -400,6 +383,20 @@ var init_discover = __esm({
|
|
|
400
383
|
configDigest: jsonDigest(servers[name])
|
|
401
384
|
}));
|
|
402
385
|
};
|
|
386
|
+
discoverPlugins = (root, config) => Object.entries(config.plugins ?? {}).sort(([a], [b]) => a.localeCompare(b)).map(([name, plugin]) => {
|
|
387
|
+
const absPath = resolve2(root, plugin.sourcePath);
|
|
388
|
+
if (!existsSync(absPath)) {
|
|
389
|
+
throw new Error(`Plugin "${name}" source not found: ${absPath}`);
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
name,
|
|
393
|
+
provider: plugin.provider,
|
|
394
|
+
sourcePath: plugin.sourcePath,
|
|
395
|
+
absPath,
|
|
396
|
+
digest: jsonDigest({ config: plugin, content: fileDigest(absPath) }),
|
|
397
|
+
requires: plugin.requires ?? []
|
|
398
|
+
};
|
|
399
|
+
});
|
|
403
400
|
loadCatalog = (catalog) => {
|
|
404
401
|
const { config, path } = readConfig(catalog.root);
|
|
405
402
|
return {
|
|
@@ -407,14 +404,15 @@ var init_discover = __esm({
|
|
|
407
404
|
configPath: path,
|
|
408
405
|
skills: discoverSkills(catalog.root),
|
|
409
406
|
commands: discoverCommands(catalog.root),
|
|
410
|
-
mcp: discoverMcp(config)
|
|
407
|
+
mcp: discoverMcp(config),
|
|
408
|
+
plugins: discoverPlugins(catalog.root, config)
|
|
411
409
|
};
|
|
412
410
|
};
|
|
413
411
|
}
|
|
414
412
|
});
|
|
415
413
|
|
|
416
414
|
// src/catalog/entries.ts
|
|
417
|
-
var skillToEntry, commandToEntry, mcpToEntry;
|
|
415
|
+
var skillToEntry, commandToEntry, mcpToEntry, pluginToEntry;
|
|
418
416
|
var init_entries = __esm({
|
|
419
417
|
"src/catalog/entries.ts"() {
|
|
420
418
|
"use strict";
|
|
@@ -437,6 +435,13 @@ var init_entries = __esm({
|
|
|
437
435
|
tools: null,
|
|
438
436
|
toolsFetchedAt: null
|
|
439
437
|
});
|
|
438
|
+
pluginToEntry = (plugin) => ({
|
|
439
|
+
type: "plugin",
|
|
440
|
+
provider: plugin.provider,
|
|
441
|
+
sourcePath: plugin.sourcePath,
|
|
442
|
+
digest: plugin.digest,
|
|
443
|
+
requires: plugin.requires
|
|
444
|
+
});
|
|
440
445
|
}
|
|
441
446
|
});
|
|
442
447
|
|
|
@@ -526,6 +531,12 @@ var init_materialize = __esm({
|
|
|
526
531
|
mkdirSync(dirname(dest), { recursive: true });
|
|
527
532
|
cpSync(command.absPath, dest, { force: true });
|
|
528
533
|
}
|
|
534
|
+
for (const plugin of catalog.plugins) {
|
|
535
|
+
if (!selection.plugins.includes(plugin.name)) continue;
|
|
536
|
+
const dest = resolve4(destRoot, plugin.sourcePath);
|
|
537
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
538
|
+
cpSync(plugin.absPath, dest, { force: true });
|
|
539
|
+
}
|
|
529
540
|
const filteredConfig = {};
|
|
530
541
|
if (catalog.config.shared) filteredConfig["shared"] = catalog.config.shared;
|
|
531
542
|
const mcpServers = {};
|
|
@@ -533,6 +544,14 @@ var init_materialize = __esm({
|
|
|
533
544
|
if (selection.mcp.includes(mcp.name)) mcpServers[mcp.name] = mcp.server;
|
|
534
545
|
}
|
|
535
546
|
if (Object.keys(mcpServers).length) filteredConfig["mcpServers"] = mcpServers;
|
|
547
|
+
const plugins = {};
|
|
548
|
+
for (const plugin of catalog.plugins) {
|
|
549
|
+
if (!selection.plugins.includes(plugin.name)) continue;
|
|
550
|
+
plugins[plugin.name] = catalog.config.plugins?.[plugin.name];
|
|
551
|
+
}
|
|
552
|
+
if (Object.keys(plugins).length) filteredConfig["plugins"] = plugins;
|
|
553
|
+
if (catalog.config.opencode) filteredConfig["opencode"] = catalog.config.opencode;
|
|
554
|
+
if (catalog.config.tui) filteredConfig["tui"] = catalog.config.tui;
|
|
536
555
|
if (catalog.config.claude) filteredConfig["claude"] = catalog.config.claude;
|
|
537
556
|
writeFileSync(
|
|
538
557
|
resolve4(destRoot, "config.json"),
|
|
@@ -568,53 +587,10 @@ var init_materialize = __esm({
|
|
|
568
587
|
|
|
569
588
|
// src/github/auth.ts
|
|
570
589
|
import { execFileSync } from "child_process";
|
|
571
|
-
|
|
572
|
-
chmodSync,
|
|
573
|
-
existsSync as existsSync4,
|
|
574
|
-
mkdirSync as mkdirSync2,
|
|
575
|
-
readFileSync as readFileSync4,
|
|
576
|
-
rmSync as rmSync2,
|
|
577
|
-
writeFileSync as writeFileSync2
|
|
578
|
-
} from "fs";
|
|
579
|
-
import { homedir } from "os";
|
|
580
|
-
import { resolve as resolve5 } from "path";
|
|
581
|
-
var configDir, authFilePath, readAuthFile, readStoredToken, writeStoredToken, deleteStoredToken, cachedToken, ghToken, resolveGithubToken, resetTokenCache, validateToken;
|
|
590
|
+
var cachedToken, ghToken, resolveGithubToken;
|
|
582
591
|
var init_auth = __esm({
|
|
583
592
|
"src/github/auth.ts"() {
|
|
584
593
|
"use strict";
|
|
585
|
-
configDir = () => {
|
|
586
|
-
const base = process.env["XDG_CONFIG_HOME"] || resolve5(homedir(), ".config");
|
|
587
|
-
return resolve5(base, "quiver");
|
|
588
|
-
};
|
|
589
|
-
authFilePath = () => resolve5(configDir(), "auth.json");
|
|
590
|
-
readAuthFile = () => {
|
|
591
|
-
const path = authFilePath();
|
|
592
|
-
if (!existsSync4(path)) return null;
|
|
593
|
-
try {
|
|
594
|
-
return JSON.parse(readFileSync4(path, "utf8"));
|
|
595
|
-
} catch {
|
|
596
|
-
return null;
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
readStoredToken = () => readAuthFile()?.github?.token ?? null;
|
|
600
|
-
writeStoredToken = (token, login2) => {
|
|
601
|
-
mkdirSync2(configDir(), { recursive: true });
|
|
602
|
-
const file = {
|
|
603
|
-
github: { token, login: login2, createdAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
604
|
-
};
|
|
605
|
-
writeFileSync2(authFilePath(), JSON.stringify(file, null, 2) + "\n", {
|
|
606
|
-
mode: 384
|
|
607
|
-
});
|
|
608
|
-
chmodSync(authFilePath(), 384);
|
|
609
|
-
resetTokenCache();
|
|
610
|
-
};
|
|
611
|
-
deleteStoredToken = () => {
|
|
612
|
-
const path = authFilePath();
|
|
613
|
-
if (!existsSync4(path)) return false;
|
|
614
|
-
rmSync2(path);
|
|
615
|
-
resetTokenCache();
|
|
616
|
-
return true;
|
|
617
|
-
};
|
|
618
594
|
ghToken = () => {
|
|
619
595
|
try {
|
|
620
596
|
const out = execFileSync("gh", ["auth", "token"], {
|
|
@@ -629,38 +605,14 @@ var init_auth = __esm({
|
|
|
629
605
|
};
|
|
630
606
|
resolveGithubToken = () => {
|
|
631
607
|
if (cachedToken !== void 0) return cachedToken;
|
|
632
|
-
cachedToken = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"] ??
|
|
608
|
+
cachedToken = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"] ?? ghToken();
|
|
633
609
|
return cachedToken;
|
|
634
610
|
};
|
|
635
|
-
resetTokenCache = () => {
|
|
636
|
-
cachedToken = void 0;
|
|
637
|
-
};
|
|
638
|
-
validateToken = async (token) => {
|
|
639
|
-
let res;
|
|
640
|
-
try {
|
|
641
|
-
res = await fetch("https://api.github.com/user", {
|
|
642
|
-
headers: {
|
|
643
|
-
Accept: "application/vnd.github+json",
|
|
644
|
-
"User-Agent": "quiver-cli",
|
|
645
|
-
Authorization: `Bearer ${token}`
|
|
646
|
-
}
|
|
647
|
-
});
|
|
648
|
-
} catch (err) {
|
|
649
|
-
return {
|
|
650
|
-
ok: false,
|
|
651
|
-
reason: err instanceof Error ? err.message : "fetch failed"
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
if (res.status === 401) return { ok: false, reason: "token is invalid or expired" };
|
|
655
|
-
if (!res.ok) return { ok: false, reason: `HTTP ${res.status}` };
|
|
656
|
-
const body = await res.json();
|
|
657
|
-
return { ok: true, login: body.login ?? "unknown" };
|
|
658
|
-
};
|
|
659
611
|
}
|
|
660
612
|
});
|
|
661
613
|
|
|
662
614
|
// src/github/api.ts
|
|
663
|
-
import { mkdirSync as
|
|
615
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
664
616
|
import { Readable } from "stream";
|
|
665
617
|
import { pipeline } from "stream/promises";
|
|
666
618
|
import * as tar from "tar";
|
|
@@ -678,13 +630,14 @@ var init_api = __esm({
|
|
|
678
630
|
if (token) h["Authorization"] = `Bearer ${token}`;
|
|
679
631
|
return h;
|
|
680
632
|
};
|
|
681
|
-
failureReason = (
|
|
682
|
-
if (
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
633
|
+
failureReason = (status) => {
|
|
634
|
+
if (status === 401)
|
|
635
|
+
return "authentication failed - set GITHUB_TOKEN or log in with the gh CLI";
|
|
636
|
+
if (status === 403 || status === 429)
|
|
637
|
+
return "rate-limited or access denied (set GITHUB_TOKEN or log in with the gh CLI)";
|
|
638
|
+
if (status === 404)
|
|
639
|
+
return "repo or ref not found (private repo? set GITHUB_TOKEN or log in with the gh CLI)";
|
|
640
|
+
return `HTTP ${status}`;
|
|
688
641
|
};
|
|
689
642
|
apiFetch = async (url) => {
|
|
690
643
|
let res;
|
|
@@ -721,7 +674,7 @@ var init_api = __esm({
|
|
|
721
674
|
);
|
|
722
675
|
if (!res.ok) return res;
|
|
723
676
|
if (!res.value.body) return { ok: false, reason: "empty tarball response" };
|
|
724
|
-
|
|
677
|
+
mkdirSync2(destDir, { recursive: true });
|
|
725
678
|
try {
|
|
726
679
|
await pipeline(
|
|
727
680
|
Readable.fromWeb(res.value.body),
|
|
@@ -746,9 +699,9 @@ __export(remote_exports, {
|
|
|
746
699
|
fetchRemoteCatalog: () => fetchRemoteCatalog,
|
|
747
700
|
parseGithubSource: () => parseGithubSource
|
|
748
701
|
});
|
|
749
|
-
import { existsSync as
|
|
750
|
-
import { homedir
|
|
751
|
-
import { dirname as dirname2, resolve as
|
|
702
|
+
import { existsSync as existsSync4, mkdtempSync, renameSync, rmSync as rmSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
703
|
+
import { homedir } from "os";
|
|
704
|
+
import { dirname as dirname2, resolve as resolve5 } from "path";
|
|
752
705
|
var parseGithubSource, catalogCacheRoot, catalogCacheDir, fetchRemoteCatalog;
|
|
753
706
|
var init_remote = __esm({
|
|
754
707
|
"src/catalog/remote.ts"() {
|
|
@@ -771,10 +724,10 @@ var init_remote = __esm({
|
|
|
771
724
|
return { repo: `${owner}/${repo}`, path: pathParts.join("/"), ref };
|
|
772
725
|
};
|
|
773
726
|
catalogCacheRoot = () => {
|
|
774
|
-
const base = process.env["XDG_CACHE_HOME"] ||
|
|
775
|
-
return
|
|
727
|
+
const base = process.env["XDG_CACHE_HOME"] || resolve5(homedir(), ".cache");
|
|
728
|
+
return resolve5(base, "quiver", "catalogs");
|
|
776
729
|
};
|
|
777
|
-
catalogCacheDir = (repo, sha) =>
|
|
730
|
+
catalogCacheDir = (repo, sha) => resolve5(catalogCacheRoot(), `${repo.replace("/", "-")}-${sha.slice(0, 12)}`);
|
|
778
731
|
fetchRemoteCatalog = async (source, options = {}) => {
|
|
779
732
|
const spec = parseGithubSource(source);
|
|
780
733
|
let ref = spec.ref;
|
|
@@ -794,22 +747,22 @@ var init_remote = __esm({
|
|
|
794
747
|
sha = commit.value;
|
|
795
748
|
}
|
|
796
749
|
const cacheDir = catalogCacheDir(spec.repo, sha);
|
|
797
|
-
if (!
|
|
798
|
-
|
|
750
|
+
if (!existsSync4(cacheDir)) {
|
|
751
|
+
mkdirSync3(dirname2(cacheDir), { recursive: true });
|
|
799
752
|
const tmp = mkdtempSync(`${cacheDir}.tmp-`);
|
|
800
753
|
const result = await downloadTarball(spec.repo, sha, tmp);
|
|
801
754
|
if (!result.ok) {
|
|
802
|
-
|
|
755
|
+
rmSync2(tmp, { recursive: true, force: true });
|
|
803
756
|
throw new Error(`Cannot download ${spec.repo}@${sha.slice(0, 12)}: ${result.reason}`);
|
|
804
757
|
}
|
|
805
758
|
try {
|
|
806
759
|
renameSync(tmp, cacheDir);
|
|
807
760
|
} catch {
|
|
808
|
-
|
|
761
|
+
rmSync2(tmp, { recursive: true, force: true });
|
|
809
762
|
}
|
|
810
763
|
}
|
|
811
|
-
const root = spec.path ?
|
|
812
|
-
if (!
|
|
764
|
+
const root = spec.path ? resolve5(cacheDir, spec.path) : cacheDir;
|
|
765
|
+
if (!existsSync4(root)) {
|
|
813
766
|
throw new Error(
|
|
814
767
|
`Catalog path "${spec.path}" not found in ${spec.repo}@${sha.slice(0, 12)}.`
|
|
815
768
|
);
|
|
@@ -820,21 +773,21 @@ var init_remote = __esm({
|
|
|
820
773
|
});
|
|
821
774
|
|
|
822
775
|
// src/catalog/resolve.ts
|
|
823
|
-
import { accessSync, constants, existsSync as
|
|
824
|
-
import { dirname as dirname3, relative as relative3, resolve as
|
|
776
|
+
import { accessSync, constants, existsSync as existsSync5 } from "fs";
|
|
777
|
+
import { dirname as dirname3, relative as relative3, resolve as resolve6, sep } from "path";
|
|
825
778
|
import { fileURLToPath } from "url";
|
|
826
779
|
var packageRoot, DEFAULT_CATALOG_SOURCE, resolveCatalog, isInstalledPackage, isBundledCatalog, isCatalogWritable;
|
|
827
780
|
var init_resolve = __esm({
|
|
828
781
|
"src/catalog/resolve.ts"() {
|
|
829
782
|
"use strict";
|
|
830
|
-
packageRoot =
|
|
783
|
+
packageRoot = resolve6(dirname3(fileURLToPath(import.meta.url)), "..");
|
|
831
784
|
DEFAULT_CATALOG_SOURCE = "local:template/.agents";
|
|
832
785
|
resolveCatalog = async (source = DEFAULT_CATALOG_SOURCE, options = {}) => {
|
|
833
786
|
const [scheme, ...rest] = source.split(":");
|
|
834
787
|
const spec = rest.join(":");
|
|
835
788
|
if (scheme === "local") {
|
|
836
|
-
const root =
|
|
837
|
-
if (!
|
|
789
|
+
const root = resolve6(packageRoot, spec);
|
|
790
|
+
if (!existsSync5(root)) {
|
|
838
791
|
throw new Error(`Catalog not found at ${root} (source: ${source}).`);
|
|
839
792
|
}
|
|
840
793
|
return { source, root };
|
|
@@ -879,7 +832,9 @@ var init_schema = __esm({
|
|
|
879
832
|
if (idx === -1) return null;
|
|
880
833
|
const type = id.slice(0, idx);
|
|
881
834
|
const name = id.slice(idx + 1);
|
|
882
|
-
if (type !== "skill" && type !== "command" && type !== "mcp")
|
|
835
|
+
if (type !== "skill" && type !== "command" && type !== "mcp" && type !== "plugin") {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
883
838
|
if (!name) return null;
|
|
884
839
|
return { type, name };
|
|
885
840
|
};
|
|
@@ -887,19 +842,19 @@ var init_schema = __esm({
|
|
|
887
842
|
});
|
|
888
843
|
|
|
889
844
|
// src/lockfile/io.ts
|
|
890
|
-
import { existsSync as
|
|
891
|
-
import { resolve as
|
|
845
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
846
|
+
import { resolve as resolve7 } from "path";
|
|
892
847
|
var lockfilePath, lockfileExists, readLockfile, writeLockfile, emptyLockfile;
|
|
893
848
|
var init_io = __esm({
|
|
894
849
|
"src/lockfile/io.ts"() {
|
|
895
850
|
"use strict";
|
|
896
851
|
init_schema();
|
|
897
|
-
lockfilePath = (targetRoot) =>
|
|
898
|
-
lockfileExists = (targetRoot) =>
|
|
852
|
+
lockfilePath = (targetRoot) => resolve7(targetRoot, LOCKFILE_NAME);
|
|
853
|
+
lockfileExists = (targetRoot) => existsSync6(lockfilePath(targetRoot));
|
|
899
854
|
readLockfile = (targetRoot) => {
|
|
900
855
|
const path = lockfilePath(targetRoot);
|
|
901
|
-
if (!
|
|
902
|
-
const parsed = JSON.parse(
|
|
856
|
+
if (!existsSync6(path)) return null;
|
|
857
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
903
858
|
if (parsed.version !== LOCKFILE_VERSION) {
|
|
904
859
|
throw new Error(
|
|
905
860
|
`Unsupported ${LOCKFILE_NAME} version ${parsed.version}; expected ${LOCKFILE_VERSION}.`
|
|
@@ -918,7 +873,7 @@ var init_io = __esm({
|
|
|
918
873
|
...lock.providers !== void 0 ? { providers: lock.providers } : {},
|
|
919
874
|
entries: sortedEntries
|
|
920
875
|
};
|
|
921
|
-
|
|
876
|
+
writeFileSync2(lockfilePath(targetRoot), JSON.stringify(ordered, null, 2) + "\n");
|
|
922
877
|
};
|
|
923
878
|
emptyLockfile = (catalogSource, remote = {}) => ({
|
|
924
879
|
version: LOCKFILE_VERSION,
|
|
@@ -990,7 +945,7 @@ var init_resolve2 = __esm({
|
|
|
990
945
|
});
|
|
991
946
|
|
|
992
947
|
// src/providers/claude.ts
|
|
993
|
-
import { resolve as
|
|
948
|
+
import { resolve as resolve8 } from "path";
|
|
994
949
|
var formatMcpJson, planClaude;
|
|
995
950
|
var init_claude = __esm({
|
|
996
951
|
"src/providers/claude.ts"() {
|
|
@@ -1005,33 +960,33 @@ var init_claude = __esm({
|
|
|
1005
960
|
const removeFiles = [];
|
|
1006
961
|
if (claudeSettings) {
|
|
1007
962
|
files.push({
|
|
1008
|
-
path:
|
|
963
|
+
path: resolve8(targetRoot, ".claude/settings.json"),
|
|
1009
964
|
content: JSON.stringify(claudeSettings, null, 2) + "\n"
|
|
1010
965
|
});
|
|
1011
966
|
}
|
|
1012
967
|
const mcp = formatMcpJson(mcpServers);
|
|
1013
|
-
const mcpPath =
|
|
968
|
+
const mcpPath = resolve8(targetRoot, ".mcp.json");
|
|
1014
969
|
if (mcp) files.push({ path: mcpPath, content: mcp });
|
|
1015
970
|
else removeFiles.push(mcpPath);
|
|
1016
971
|
const skillNames = selected.skills.map((s) => s.name);
|
|
1017
972
|
const commandFiles = selected.commands.map((c) => `${c.name}.md`);
|
|
1018
973
|
const symlinks = [
|
|
1019
974
|
...selected.skills.map((s) => ({
|
|
1020
|
-
path:
|
|
975
|
+
path: resolve8(targetRoot, ".claude/skills", s.name),
|
|
1021
976
|
target: s.absDir
|
|
1022
977
|
})),
|
|
1023
978
|
...selected.commands.map((c) => ({
|
|
1024
|
-
path:
|
|
979
|
+
path: resolve8(targetRoot, ".claude/commands", `${c.name}.md`),
|
|
1025
980
|
target: c.absPath
|
|
1026
981
|
}))
|
|
1027
982
|
];
|
|
1028
983
|
const managedDirs = [
|
|
1029
984
|
{
|
|
1030
|
-
path:
|
|
985
|
+
path: resolve8(targetRoot, ".claude/skills"),
|
|
1031
986
|
expected: new Set(skillNames)
|
|
1032
987
|
},
|
|
1033
988
|
{
|
|
1034
|
-
path:
|
|
989
|
+
path: resolve8(targetRoot, ".claude/commands"),
|
|
1035
990
|
expected: new Set(commandFiles)
|
|
1036
991
|
}
|
|
1037
992
|
];
|
|
@@ -1041,7 +996,7 @@ var init_claude = __esm({
|
|
|
1041
996
|
});
|
|
1042
997
|
|
|
1043
998
|
// src/providers/codex.ts
|
|
1044
|
-
import { resolve as
|
|
999
|
+
import { resolve as resolve9 } from "path";
|
|
1045
1000
|
import TOML from "@iarna/toml";
|
|
1046
1001
|
var buildConfig, planCodex;
|
|
1047
1002
|
var init_codex = __esm({
|
|
@@ -1085,7 +1040,7 @@ var init_codex = __esm({
|
|
|
1085
1040
|
const files = [];
|
|
1086
1041
|
const removeFiles = [];
|
|
1087
1042
|
const config = buildConfig(rawMcpServers);
|
|
1088
|
-
const path =
|
|
1043
|
+
const path = resolve9(targetRoot, ".codex/config.toml");
|
|
1089
1044
|
if (config) {
|
|
1090
1045
|
files.push({
|
|
1091
1046
|
path,
|
|
@@ -1101,19 +1056,19 @@ var init_codex = __esm({
|
|
|
1101
1056
|
|
|
1102
1057
|
// src/providers/fsops.ts
|
|
1103
1058
|
import {
|
|
1104
|
-
existsSync as
|
|
1059
|
+
existsSync as existsSync7,
|
|
1105
1060
|
lstatSync,
|
|
1106
|
-
mkdirSync as
|
|
1061
|
+
mkdirSync as mkdirSync4,
|
|
1107
1062
|
readdirSync as readdirSync3,
|
|
1108
|
-
readFileSync as
|
|
1063
|
+
readFileSync as readFileSync5,
|
|
1109
1064
|
readlinkSync,
|
|
1110
1065
|
rmdirSync,
|
|
1111
|
-
rmSync as
|
|
1066
|
+
rmSync as rmSync3,
|
|
1112
1067
|
symlinkSync,
|
|
1113
1068
|
unlinkSync,
|
|
1114
|
-
writeFileSync as
|
|
1069
|
+
writeFileSync as writeFileSync3
|
|
1115
1070
|
} from "fs";
|
|
1116
|
-
import { dirname as dirname4, relative as relative4, resolve as
|
|
1071
|
+
import { dirname as dirname4, relative as relative4, resolve as resolve10 } from "path";
|
|
1117
1072
|
var isENOENT, isMatchingSymlink, removePath, applyOutputs, checkOutputs;
|
|
1118
1073
|
var init_fsops = __esm({
|
|
1119
1074
|
"src/providers/fsops.ts"() {
|
|
@@ -1122,7 +1077,7 @@ var init_fsops = __esm({
|
|
|
1122
1077
|
isMatchingSymlink = (path, target) => {
|
|
1123
1078
|
const stats = lstatSync(path);
|
|
1124
1079
|
if (!stats.isSymbolicLink()) return false;
|
|
1125
|
-
return
|
|
1080
|
+
return resolve10(dirname4(path), readlinkSync(path)) === target;
|
|
1126
1081
|
};
|
|
1127
1082
|
removePath = (path) => {
|
|
1128
1083
|
let stats;
|
|
@@ -1133,7 +1088,7 @@ var init_fsops = __esm({
|
|
|
1133
1088
|
throw e;
|
|
1134
1089
|
}
|
|
1135
1090
|
if (stats.isSymbolicLink()) unlinkSync(path);
|
|
1136
|
-
else
|
|
1091
|
+
else rmSync3(path, { force: true, recursive: true });
|
|
1137
1092
|
};
|
|
1138
1093
|
applyOutputs = ({
|
|
1139
1094
|
files,
|
|
@@ -1146,22 +1101,22 @@ var init_fsops = __esm({
|
|
|
1146
1101
|
for (const out of files) {
|
|
1147
1102
|
let current = null;
|
|
1148
1103
|
try {
|
|
1149
|
-
current =
|
|
1104
|
+
current = readFileSync5(out.path, "utf8");
|
|
1150
1105
|
} catch (e) {
|
|
1151
1106
|
if (!isENOENT(e)) throw e;
|
|
1152
1107
|
}
|
|
1153
1108
|
if (current === out.content) continue;
|
|
1154
|
-
|
|
1155
|
-
|
|
1109
|
+
mkdirSync4(dirname4(out.path), { recursive: true });
|
|
1110
|
+
writeFileSync3(out.path, out.content);
|
|
1156
1111
|
result.generated.push(out.path);
|
|
1157
1112
|
}
|
|
1158
1113
|
for (const path of removeFiles) {
|
|
1159
|
-
if (!
|
|
1160
|
-
|
|
1114
|
+
if (!existsSync7(path)) continue;
|
|
1115
|
+
rmSync3(path, { force: true });
|
|
1161
1116
|
result.removed.push(path);
|
|
1162
1117
|
}
|
|
1163
1118
|
for (const path of removeDirs) {
|
|
1164
|
-
if (!
|
|
1119
|
+
if (!existsSync7(path)) continue;
|
|
1165
1120
|
removePath(path);
|
|
1166
1121
|
result.removed.push(path);
|
|
1167
1122
|
}
|
|
@@ -1172,7 +1127,7 @@ var init_fsops = __esm({
|
|
|
1172
1127
|
}
|
|
1173
1128
|
}
|
|
1174
1129
|
for (const link of symlinks) {
|
|
1175
|
-
|
|
1130
|
+
mkdirSync4(dirname4(link.path), { recursive: true });
|
|
1176
1131
|
try {
|
|
1177
1132
|
if (isMatchingSymlink(link.path, link.target)) continue;
|
|
1178
1133
|
} catch (e) {
|
|
@@ -1187,10 +1142,10 @@ var init_fsops = __esm({
|
|
|
1187
1142
|
result.linked.push(link.path);
|
|
1188
1143
|
}
|
|
1189
1144
|
for (const dir of managedDirs) {
|
|
1190
|
-
if (!
|
|
1145
|
+
if (!existsSync7(dir.path)) continue;
|
|
1191
1146
|
for (const child of readdirSync3(dir.path)) {
|
|
1192
1147
|
if (dir.expected.has(child)) continue;
|
|
1193
|
-
const childPath =
|
|
1148
|
+
const childPath = resolve10(dir.path, child);
|
|
1194
1149
|
removePath(childPath);
|
|
1195
1150
|
result.removed.push(childPath);
|
|
1196
1151
|
}
|
|
@@ -1207,7 +1162,7 @@ var init_fsops = __esm({
|
|
|
1207
1162
|
const problems = [];
|
|
1208
1163
|
for (const out of files) {
|
|
1209
1164
|
try {
|
|
1210
|
-
if (
|
|
1165
|
+
if (readFileSync5(out.path, "utf8") !== out.content) {
|
|
1211
1166
|
problems.push(`out of sync: ${out.path}`);
|
|
1212
1167
|
}
|
|
1213
1168
|
} catch (e) {
|
|
@@ -1216,10 +1171,10 @@ var init_fsops = __esm({
|
|
|
1216
1171
|
}
|
|
1217
1172
|
}
|
|
1218
1173
|
for (const path of removeFiles) {
|
|
1219
|
-
if (
|
|
1174
|
+
if (existsSync7(path)) problems.push(`stale (should be removed): ${path}`);
|
|
1220
1175
|
}
|
|
1221
1176
|
for (const path of removeDirs) {
|
|
1222
|
-
if (
|
|
1177
|
+
if (existsSync7(path)) problems.push(`stale (should be removed): ${path}`);
|
|
1223
1178
|
}
|
|
1224
1179
|
for (const link of symlinks) {
|
|
1225
1180
|
try {
|
|
@@ -1232,10 +1187,10 @@ var init_fsops = __esm({
|
|
|
1232
1187
|
}
|
|
1233
1188
|
}
|
|
1234
1189
|
for (const dir of managedDirs) {
|
|
1235
|
-
if (!
|
|
1190
|
+
if (!existsSync7(dir.path)) continue;
|
|
1236
1191
|
for (const child of readdirSync3(dir.path)) {
|
|
1237
1192
|
if (!dir.expected.has(child)) {
|
|
1238
|
-
problems.push(`unexpected shim: ${
|
|
1193
|
+
problems.push(`unexpected shim: ${resolve10(dir.path, child)}`);
|
|
1239
1194
|
}
|
|
1240
1195
|
}
|
|
1241
1196
|
}
|
|
@@ -1244,44 +1199,116 @@ var init_fsops = __esm({
|
|
|
1244
1199
|
}
|
|
1245
1200
|
});
|
|
1246
1201
|
|
|
1202
|
+
// src/providers/local-config.ts
|
|
1203
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1204
|
+
import { resolve as resolve11 } from "path";
|
|
1205
|
+
var localConfigPath, readLocalConfig, disabledMcpServers, setMcpEnabled;
|
|
1206
|
+
var init_local_config = __esm({
|
|
1207
|
+
"src/providers/local-config.ts"() {
|
|
1208
|
+
"use strict";
|
|
1209
|
+
localConfigPath = (targetRoot) => resolve11(targetRoot, ".agents", "config.local.json");
|
|
1210
|
+
readLocalConfig = (targetRoot) => {
|
|
1211
|
+
const path = localConfigPath(targetRoot);
|
|
1212
|
+
if (!existsSync8(path)) return {};
|
|
1213
|
+
return JSON.parse(readFileSync6(path, "utf8"));
|
|
1214
|
+
};
|
|
1215
|
+
disabledMcpServers = (targetRoot) => {
|
|
1216
|
+
const disabled = /* @__PURE__ */ new Set();
|
|
1217
|
+
const servers = readLocalConfig(targetRoot).mcpServers ?? {};
|
|
1218
|
+
for (const [name, override] of Object.entries(servers)) {
|
|
1219
|
+
if (override.enabled === false) disabled.add(name);
|
|
1220
|
+
}
|
|
1221
|
+
return disabled;
|
|
1222
|
+
};
|
|
1223
|
+
setMcpEnabled = (targetRoot, name, enabled) => {
|
|
1224
|
+
const config = readLocalConfig(targetRoot);
|
|
1225
|
+
const servers = { ...config.mcpServers ?? {} };
|
|
1226
|
+
if (enabled) delete servers[name];
|
|
1227
|
+
else servers[name] = { enabled: false };
|
|
1228
|
+
if (Object.keys(servers).length) config.mcpServers = servers;
|
|
1229
|
+
else delete config.mcpServers;
|
|
1230
|
+
const path = localConfigPath(targetRoot);
|
|
1231
|
+
if (Object.keys(config).length === 0) {
|
|
1232
|
+
rmSync4(path, { force: true });
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
writeFileSync4(path, JSON.stringify(config, null, 2) + "\n");
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1247
1240
|
// src/providers/opencode.ts
|
|
1241
|
+
import { existsSync as existsSync9 } from "fs";
|
|
1248
1242
|
import { resolve as resolve12 } from "path";
|
|
1249
|
-
var formatOpenCodeJson, planOpenCode;
|
|
1243
|
+
var formatOpenCodeJson, preserveEnvReference, preserveEnvReferences, planOpenCode;
|
|
1250
1244
|
var init_opencode = __esm({
|
|
1251
1245
|
"src/providers/opencode.ts"() {
|
|
1252
1246
|
"use strict";
|
|
1253
|
-
formatOpenCodeJson = (servers) => {
|
|
1254
|
-
if (Object.keys(servers).length === 0) return null;
|
|
1247
|
+
formatOpenCodeJson = (servers, overlay) => {
|
|
1248
|
+
if (Object.keys(servers).length === 0 && !overlay) return null;
|
|
1255
1249
|
const mcp = {};
|
|
1256
1250
|
for (const [name, server] of Object.entries(servers)) {
|
|
1257
1251
|
if (server.transport === "http") {
|
|
1258
1252
|
mcp[name] = {
|
|
1259
1253
|
type: "remote",
|
|
1260
|
-
url: server.url,
|
|
1261
|
-
...server.headers ? { headers: server.headers } : {}
|
|
1254
|
+
url: preserveEnvReference(server.url),
|
|
1255
|
+
...server.headers ? { headers: preserveEnvReferences(server.headers) } : {}
|
|
1262
1256
|
};
|
|
1263
1257
|
} else {
|
|
1264
1258
|
mcp[name] = {
|
|
1265
1259
|
type: "local",
|
|
1266
|
-
command: [server.command, ...server.args ?? []]
|
|
1267
|
-
|
|
1260
|
+
command: [server.command, ...server.args ?? []].map(
|
|
1261
|
+
preserveEnvReference
|
|
1262
|
+
),
|
|
1263
|
+
...server.env ? { environment: preserveEnvReferences(server.env) } : {}
|
|
1268
1264
|
};
|
|
1269
1265
|
}
|
|
1270
1266
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1267
|
+
const overlayMcp = overlay?.["mcp"] && typeof overlay["mcp"] === "object" ? overlay["mcp"] : {};
|
|
1268
|
+
const mergedMcp = { ...overlayMcp, ...mcp };
|
|
1269
|
+
const config = {
|
|
1270
|
+
...overlay,
|
|
1271
|
+
$schema: "https://opencode.ai/config.json",
|
|
1272
|
+
...Object.keys(mergedMcp).length ? { mcp: mergedMcp } : {}
|
|
1273
|
+
};
|
|
1274
|
+
return JSON.stringify(config, null, 2) + "\n";
|
|
1275
|
+
};
|
|
1276
|
+
preserveEnvReference = (value) => value.replace(/\$\{([^}]+)\}/g, "{env:$1}");
|
|
1277
|
+
preserveEnvReferences = (values) => Object.fromEntries(
|
|
1278
|
+
Object.entries(values).map(([key, value]) => [
|
|
1279
|
+
key,
|
|
1280
|
+
preserveEnvReference(value)
|
|
1281
|
+
])
|
|
1282
|
+
);
|
|
1277
1283
|
planOpenCode = (inputs) => {
|
|
1278
|
-
const {
|
|
1284
|
+
const {
|
|
1285
|
+
targetRoot,
|
|
1286
|
+
selected,
|
|
1287
|
+
rawMcpServers,
|
|
1288
|
+
opencodeConfig,
|
|
1289
|
+
tuiConfig
|
|
1290
|
+
} = inputs;
|
|
1279
1291
|
const files = [];
|
|
1280
1292
|
const removeFiles = [];
|
|
1281
|
-
const json = formatOpenCodeJson(
|
|
1293
|
+
const json = formatOpenCodeJson(rawMcpServers, opencodeConfig);
|
|
1282
1294
|
const jsonPath = resolve12(targetRoot, "opencode.json");
|
|
1283
1295
|
if (json) files.push({ path: jsonPath, content: json });
|
|
1284
1296
|
else removeFiles.push(jsonPath);
|
|
1297
|
+
const tuiPath = resolve12(targetRoot, ".opencode/tui.json");
|
|
1298
|
+
const tuiMarkerPath = resolve12(targetRoot, ".opencode/.quiver-tui");
|
|
1299
|
+
if (tuiConfig) {
|
|
1300
|
+
files.push({
|
|
1301
|
+
path: tuiPath,
|
|
1302
|
+
content: JSON.stringify(
|
|
1303
|
+
{ ...tuiConfig, $schema: "https://opencode.ai/tui.json" },
|
|
1304
|
+
null,
|
|
1305
|
+
2
|
|
1306
|
+
) + "\n"
|
|
1307
|
+
});
|
|
1308
|
+
files.push({ path: tuiMarkerPath, content: "managed by quiver\n" });
|
|
1309
|
+
} else if (existsSync9(tuiMarkerPath)) {
|
|
1310
|
+
removeFiles.push(tuiPath, tuiMarkerPath);
|
|
1311
|
+
}
|
|
1285
1312
|
const symlinks = [
|
|
1286
1313
|
...selected.skills.map((s) => ({
|
|
1287
1314
|
path: resolve12(targetRoot, ".opencode/skills", s.name),
|
|
@@ -1290,6 +1317,14 @@ var init_opencode = __esm({
|
|
|
1290
1317
|
...selected.commands.map((c) => ({
|
|
1291
1318
|
path: resolve12(targetRoot, ".opencode/commands", `${c.name}.md`),
|
|
1292
1319
|
target: c.absPath
|
|
1320
|
+
})),
|
|
1321
|
+
...selected.plugins.map((plugin) => ({
|
|
1322
|
+
path: resolve12(
|
|
1323
|
+
targetRoot,
|
|
1324
|
+
".opencode/plugins",
|
|
1325
|
+
`${plugin.name}${plugin.absPath.endsWith(".js") ? ".js" : ".ts"}`
|
|
1326
|
+
),
|
|
1327
|
+
target: plugin.absPath
|
|
1293
1328
|
}))
|
|
1294
1329
|
];
|
|
1295
1330
|
const managedDirs = [
|
|
@@ -1300,6 +1335,14 @@ var init_opencode = __esm({
|
|
|
1300
1335
|
{
|
|
1301
1336
|
path: resolve12(targetRoot, ".opencode/commands"),
|
|
1302
1337
|
expected: new Set(selected.commands.map((c) => `${c.name}.md`))
|
|
1338
|
+
},
|
|
1339
|
+
{
|
|
1340
|
+
path: resolve12(targetRoot, ".opencode/plugins"),
|
|
1341
|
+
expected: new Set(
|
|
1342
|
+
selected.plugins.map(
|
|
1343
|
+
(plugin) => `${plugin.name}${plugin.absPath.endsWith(".js") ? ".js" : ".ts"}`
|
|
1344
|
+
)
|
|
1345
|
+
)
|
|
1303
1346
|
}
|
|
1304
1347
|
];
|
|
1305
1348
|
return { files, removeFiles, symlinks, managedDirs };
|
|
@@ -1317,24 +1360,27 @@ var init_selection = __esm({
|
|
|
1317
1360
|
const skillNames = /* @__PURE__ */ new Set();
|
|
1318
1361
|
const commandNames = /* @__PURE__ */ new Set();
|
|
1319
1362
|
const mcpNames = /* @__PURE__ */ new Set();
|
|
1363
|
+
const pluginNames = /* @__PURE__ */ new Set();
|
|
1320
1364
|
for (const id of Object.keys(lock.entries)) {
|
|
1321
1365
|
const parsed = parseEntryId(id);
|
|
1322
1366
|
if (!parsed) continue;
|
|
1323
1367
|
if (parsed.type === "skill") skillNames.add(parsed.name);
|
|
1324
1368
|
else if (parsed.type === "command") commandNames.add(parsed.name);
|
|
1325
1369
|
else if (parsed.type === "mcp") mcpNames.add(parsed.name);
|
|
1370
|
+
else if (parsed.type === "plugin") pluginNames.add(parsed.name);
|
|
1326
1371
|
}
|
|
1327
1372
|
return {
|
|
1328
1373
|
skills: catalog.skills.filter((s) => skillNames.has(s.name)),
|
|
1329
1374
|
commands: catalog.commands.filter((c) => commandNames.has(c.name)),
|
|
1330
|
-
mcp: catalog.mcp.filter((m) => mcpNames.has(m.name))
|
|
1375
|
+
mcp: catalog.mcp.filter((m) => mcpNames.has(m.name)),
|
|
1376
|
+
plugins: catalog.plugins.filter((p) => pluginNames.has(p.name))
|
|
1331
1377
|
};
|
|
1332
1378
|
};
|
|
1333
1379
|
}
|
|
1334
1380
|
});
|
|
1335
1381
|
|
|
1336
1382
|
// src/providers/write.ts
|
|
1337
|
-
import { existsSync as
|
|
1383
|
+
import { existsSync as existsSync10, lstatSync as lstatSync2 } from "fs";
|
|
1338
1384
|
import { basename, relative as relative5, resolve as resolve13 } from "path";
|
|
1339
1385
|
var isLinkable, buildPlan, writeProviders, formatWriteResult, checkProviders;
|
|
1340
1386
|
var init_write = __esm({
|
|
@@ -1345,6 +1391,7 @@ var init_write = __esm({
|
|
|
1345
1391
|
init_claude();
|
|
1346
1392
|
init_codex();
|
|
1347
1393
|
init_fsops();
|
|
1394
|
+
init_local_config();
|
|
1348
1395
|
init_opencode();
|
|
1349
1396
|
init_selection();
|
|
1350
1397
|
isLinkable = (path) => {
|
|
@@ -1357,6 +1404,10 @@ var init_write = __esm({
|
|
|
1357
1404
|
buildPlan = (targetRoot, catalog, lock, onMissingEnv, onSkippedRootFile) => {
|
|
1358
1405
|
loadEnvLocal(targetRoot);
|
|
1359
1406
|
const selected = resolveSelection(catalog, lock);
|
|
1407
|
+
const disabled = disabledMcpServers(targetRoot);
|
|
1408
|
+
if (disabled.size) {
|
|
1409
|
+
selected.mcp = selected.mcp.filter((m) => !disabled.has(m.name));
|
|
1410
|
+
}
|
|
1360
1411
|
const rawMcpServers = {};
|
|
1361
1412
|
for (const mcp of selected.mcp) rawMcpServers[mcp.name] = mcp.server;
|
|
1362
1413
|
const mcpServers = interpolateEnvVars(rawMcpServers, onMissingEnv);
|
|
@@ -1367,7 +1418,9 @@ var init_write = __esm({
|
|
|
1367
1418
|
selected,
|
|
1368
1419
|
mcpServers,
|
|
1369
1420
|
rawMcpServers,
|
|
1370
|
-
claudeSettings: catalog.config.claude?.settings ?? null
|
|
1421
|
+
claudeSettings: catalog.config.claude?.settings ?? null,
|
|
1422
|
+
opencodeConfig: catalog.config.opencode ?? null,
|
|
1423
|
+
tuiConfig: catalog.config.tui ?? null
|
|
1371
1424
|
};
|
|
1372
1425
|
const active = lock.providers?.length ? lock.providers : [...PROVIDERS];
|
|
1373
1426
|
const planByProvider = {
|
|
@@ -1392,7 +1445,7 @@ var init_write = __esm({
|
|
|
1392
1445
|
}
|
|
1393
1446
|
const rootSymlinks = [];
|
|
1394
1447
|
const agentsMd = resolve13(agentsRoot, "AGENTS.md");
|
|
1395
|
-
if (
|
|
1448
|
+
if (existsSync10(agentsMd)) {
|
|
1396
1449
|
const rootAgents = resolve13(targetRoot, "AGENTS.md");
|
|
1397
1450
|
for (const link of [
|
|
1398
1451
|
{ path: rootAgents, target: agentsMd },
|
|
@@ -1458,15 +1511,16 @@ var init_write = __esm({
|
|
|
1458
1511
|
|
|
1459
1512
|
// src/commands/gitignore.ts
|
|
1460
1513
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
1461
|
-
import { existsSync as
|
|
1514
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
1462
1515
|
import { resolve as resolve14 } from "path";
|
|
1463
|
-
var HEADER, SECRETS_COMMENT, PROVIDER_ENTRIES, SHARED_ENTRIES, SECRET_ENTRIES, patchGitignore, ignoredSourcePaths;
|
|
1516
|
+
var HEADER, SECRETS_COMMENT, LOCAL_COMMENT, PROVIDER_ENTRIES, SHARED_ENTRIES, SECRET_ENTRIES, LOCAL_ENTRIES, patchGitignore, ensureLocalOverrideIgnored, ignoredSourcePaths;
|
|
1464
1517
|
var init_gitignore = __esm({
|
|
1465
1518
|
"src/commands/gitignore.ts"() {
|
|
1466
1519
|
"use strict";
|
|
1467
1520
|
init_schema();
|
|
1468
1521
|
HEADER = "# Generated by quiver (source of truth: .agents/ + quiver.lock)";
|
|
1469
1522
|
SECRETS_COMMENT = "# Local secrets for MCP env-var interpolation";
|
|
1523
|
+
LOCAL_COMMENT = "# Local overrides (quiver-cli enable/disable)";
|
|
1470
1524
|
PROVIDER_ENTRIES = {
|
|
1471
1525
|
claude: [".claude/", ".mcp.json"],
|
|
1472
1526
|
opencode: [".opencode/", "opencode.json"],
|
|
@@ -1474,9 +1528,10 @@ var init_gitignore = __esm({
|
|
|
1474
1528
|
};
|
|
1475
1529
|
SHARED_ENTRIES = ["AGENTS.md", "CLAUDE.md"];
|
|
1476
1530
|
SECRET_ENTRIES = [".env.local"];
|
|
1531
|
+
LOCAL_ENTRIES = [".agents/config.local.json"];
|
|
1477
1532
|
patchGitignore = (targetRoot, providers2) => {
|
|
1478
1533
|
const path = resolve14(targetRoot, ".gitignore");
|
|
1479
|
-
const current =
|
|
1534
|
+
const current = existsSync11(path) ? readFileSync7(path, "utf8") : "";
|
|
1480
1535
|
const lines = new Set(current.split("\n").map((l) => l.trim()));
|
|
1481
1536
|
const active = providers2?.length ? providers2 : [...PROVIDERS];
|
|
1482
1537
|
const shimEntries = [
|
|
@@ -1485,10 +1540,14 @@ var init_gitignore = __esm({
|
|
|
1485
1540
|
];
|
|
1486
1541
|
const missingShims = shimEntries.filter((e) => !lines.has(e));
|
|
1487
1542
|
const missingSecrets = SECRET_ENTRIES.filter((e) => !lines.has(e));
|
|
1488
|
-
|
|
1543
|
+
const missingLocal = LOCAL_ENTRIES.filter((e) => !lines.has(e));
|
|
1544
|
+
if (missingShims.length === 0 && missingSecrets.length === 0 && missingLocal.length === 0) {
|
|
1545
|
+
return false;
|
|
1546
|
+
}
|
|
1489
1547
|
const block2 = [];
|
|
1490
1548
|
if (missingShims.length) block2.push(HEADER, ...missingShims);
|
|
1491
1549
|
if (missingSecrets.length) block2.push(SECRETS_COMMENT, ...missingSecrets);
|
|
1550
|
+
if (missingLocal.length) block2.push(LOCAL_COMMENT, ...missingLocal);
|
|
1492
1551
|
const prefix = current && !current.endsWith("\n") ? "\n" : "";
|
|
1493
1552
|
writeFileSync5(
|
|
1494
1553
|
path,
|
|
@@ -1496,6 +1555,19 @@ var init_gitignore = __esm({
|
|
|
1496
1555
|
);
|
|
1497
1556
|
return true;
|
|
1498
1557
|
};
|
|
1558
|
+
ensureLocalOverrideIgnored = (targetRoot) => {
|
|
1559
|
+
const path = resolve14(targetRoot, ".gitignore");
|
|
1560
|
+
const current = existsSync11(path) ? readFileSync7(path, "utf8") : "";
|
|
1561
|
+
const lines = new Set(current.split("\n").map((l) => l.trim()));
|
|
1562
|
+
const missing = LOCAL_ENTRIES.filter((e) => !lines.has(e));
|
|
1563
|
+
if (!missing.length) return false;
|
|
1564
|
+
const prefix = current && !current.endsWith("\n") ? "\n" : "";
|
|
1565
|
+
writeFileSync5(
|
|
1566
|
+
path,
|
|
1567
|
+
current + prefix + (current ? "\n" : "") + [LOCAL_COMMENT, ...missing].join("\n") + "\n"
|
|
1568
|
+
);
|
|
1569
|
+
return true;
|
|
1570
|
+
};
|
|
1499
1571
|
ignoredSourcePaths = (targetRoot) => {
|
|
1500
1572
|
try {
|
|
1501
1573
|
const out = execFileSync2(
|
|
@@ -1535,12 +1607,24 @@ var init_select = __esm({
|
|
|
1535
1607
|
const s = entry.server;
|
|
1536
1608
|
return s.transport === "http" ? s.url : [s.command, ...s.args ?? []].filter(Boolean).join(" ");
|
|
1537
1609
|
};
|
|
1538
|
-
selectFromCatalog = async (catalog, {
|
|
1610
|
+
selectFromCatalog = async (catalog, {
|
|
1611
|
+
interactive,
|
|
1612
|
+
providers: providers2
|
|
1613
|
+
}) => {
|
|
1539
1614
|
const allSkills = catalog.skills.map((s) => s.name);
|
|
1540
1615
|
const allCommands = catalog.commands.map((c) => c.name);
|
|
1541
1616
|
const allMcp = catalog.mcp.map((m) => m.name);
|
|
1617
|
+
const availablePlugins = catalog.plugins.filter(
|
|
1618
|
+
(plugin) => providers2.includes(plugin.provider)
|
|
1619
|
+
);
|
|
1620
|
+
const allPlugins = availablePlugins.map((p) => p.name);
|
|
1542
1621
|
if (!interactive || !process.stdin.isTTY) {
|
|
1543
|
-
return {
|
|
1622
|
+
return {
|
|
1623
|
+
skills: allSkills,
|
|
1624
|
+
commands: allCommands,
|
|
1625
|
+
mcp: allMcp,
|
|
1626
|
+
plugins: allPlugins
|
|
1627
|
+
};
|
|
1544
1628
|
}
|
|
1545
1629
|
const groupNames = [...new Set(catalog.skills.map((s) => s.group))].sort(
|
|
1546
1630
|
(a, b) => a === "general" ? -1 : b === "general" ? 1 : a.localeCompare(b)
|
|
@@ -1595,7 +1679,21 @@ var init_select = __esm({
|
|
|
1595
1679
|
groups: mcpGroups,
|
|
1596
1680
|
initialValues: []
|
|
1597
1681
|
}) : [];
|
|
1598
|
-
|
|
1682
|
+
const plugins = availablePlugins.length ? await selectGrouped({
|
|
1683
|
+
message: "Select plugins (space toggles, a all, enter confirms)",
|
|
1684
|
+
groups: [
|
|
1685
|
+
{
|
|
1686
|
+
name: "opencode",
|
|
1687
|
+
items: availablePlugins.map((plugin) => ({
|
|
1688
|
+
value: plugin.name,
|
|
1689
|
+
label: plugin.name,
|
|
1690
|
+
hint: plugin.requires.length ? `requires: ${plugin.requires.join(", ")}` : void 0
|
|
1691
|
+
}))
|
|
1692
|
+
}
|
|
1693
|
+
],
|
|
1694
|
+
initialValues: []
|
|
1695
|
+
}) : [];
|
|
1696
|
+
return { skills, commands, mcp, plugins };
|
|
1599
1697
|
};
|
|
1600
1698
|
}
|
|
1601
1699
|
});
|
|
@@ -1637,11 +1735,12 @@ var init_init = __esm({
|
|
|
1637
1735
|
);
|
|
1638
1736
|
}
|
|
1639
1737
|
const sourceCatalog = loadCatalog(source);
|
|
1640
|
-
const selection = await selectFromCatalog(sourceCatalog, {
|
|
1641
|
-
interactive: !options.all
|
|
1642
|
-
});
|
|
1643
1738
|
const providers2 = await resolveProviders(options);
|
|
1644
1739
|
if (providers2 === null) return;
|
|
1740
|
+
const selection = await selectFromCatalog(sourceCatalog, {
|
|
1741
|
+
interactive: !options.all,
|
|
1742
|
+
providers: providers2
|
|
1743
|
+
});
|
|
1645
1744
|
const resolved = materializeCatalog(
|
|
1646
1745
|
options.targetRoot,
|
|
1647
1746
|
source,
|
|
@@ -1669,9 +1768,14 @@ var init_init = __esm({
|
|
|
1669
1768
|
lock.entries[entryId("mcp", mcp.name)] = mcpToEntry(mcp);
|
|
1670
1769
|
}
|
|
1671
1770
|
}
|
|
1771
|
+
for (const plugin of catalog.plugins) {
|
|
1772
|
+
if (selection.plugins.includes(plugin.name)) {
|
|
1773
|
+
lock.entries[entryId("plugin", plugin.name)] = pluginToEntry(plugin);
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1672
1776
|
writeLockfile(options.targetRoot, lock);
|
|
1673
1777
|
await step(
|
|
1674
|
-
`Wrote quiver.lock (${selection.skills.length} skills, ${selection.commands.length} commands, ${selection.mcp.length} MCP servers)`
|
|
1778
|
+
`Wrote quiver.lock (${selection.skills.length} skills, ${selection.commands.length} commands, ${selection.mcp.length} MCP servers, ${selection.plugins.length} plugins)`
|
|
1675
1779
|
);
|
|
1676
1780
|
const result = writeProviders(options.targetRoot, catalog, lock);
|
|
1677
1781
|
if (result.generated.length || result.linked.length) {
|
|
@@ -1705,7 +1809,7 @@ var init_init = __esm({
|
|
|
1705
1809
|
});
|
|
1706
1810
|
|
|
1707
1811
|
// src/catalog/repo.ts
|
|
1708
|
-
import { existsSync as
|
|
1812
|
+
import { existsSync as existsSync12 } from "fs";
|
|
1709
1813
|
import { resolve as resolve15 } from "path";
|
|
1710
1814
|
var repoCatalogRoot, repoCatalogExists, loadRepoCatalog;
|
|
1711
1815
|
var init_repo = __esm({
|
|
@@ -1713,7 +1817,7 @@ var init_repo = __esm({
|
|
|
1713
1817
|
"use strict";
|
|
1714
1818
|
init_discover();
|
|
1715
1819
|
repoCatalogRoot = (targetRoot) => resolve15(targetRoot, ".agents");
|
|
1716
|
-
repoCatalogExists = (targetRoot) =>
|
|
1820
|
+
repoCatalogExists = (targetRoot) => existsSync12(repoCatalogRoot(targetRoot));
|
|
1717
1821
|
loadRepoCatalog = (targetRoot, source) => {
|
|
1718
1822
|
const resolved = {
|
|
1719
1823
|
source,
|
|
@@ -1745,13 +1849,17 @@ var init_add = __esm({
|
|
|
1745
1849
|
add = async (options) => {
|
|
1746
1850
|
const id = options.positionals[0];
|
|
1747
1851
|
if (!id) {
|
|
1748
|
-
await error(
|
|
1852
|
+
await error(
|
|
1853
|
+
"Usage: quiver-cli add <skill:name|command:name|mcp:name|plugin:name>"
|
|
1854
|
+
);
|
|
1749
1855
|
process.exitCode = 1;
|
|
1750
1856
|
return;
|
|
1751
1857
|
}
|
|
1752
1858
|
const parsed = parseEntryId(id);
|
|
1753
1859
|
if (!parsed) {
|
|
1754
|
-
await error(
|
|
1860
|
+
await error(
|
|
1861
|
+
`Invalid id "${id}". Expected skill:<name>, command:<name>, mcp:<name> or plugin:<name>.`
|
|
1862
|
+
);
|
|
1755
1863
|
process.exitCode = 1;
|
|
1756
1864
|
return;
|
|
1757
1865
|
}
|
|
@@ -1772,16 +1880,25 @@ var init_add = __esm({
|
|
|
1772
1880
|
const skill = sourceCatalog.skills.find((s) => s.name === parsed.name);
|
|
1773
1881
|
const command = sourceCatalog.commands.find((c) => c.name === parsed.name);
|
|
1774
1882
|
const mcp = sourceCatalog.mcp.find((m) => m.name === parsed.name);
|
|
1775
|
-
const
|
|
1883
|
+
const plugin = sourceCatalog.plugins.find((p) => p.name === parsed.name);
|
|
1884
|
+
const entry = parsed.type === "skill" && skill ? skillToEntry(skill) : parsed.type === "command" && command ? commandToEntry(command) : parsed.type === "mcp" && mcp ? mcpToEntry(mcp) : parsed.type === "plugin" && plugin ? pluginToEntry(plugin) : null;
|
|
1776
1885
|
if (!entry) {
|
|
1777
1886
|
await error(`${id} not found in catalog.`);
|
|
1778
1887
|
process.exitCode = 1;
|
|
1779
1888
|
return;
|
|
1780
1889
|
}
|
|
1890
|
+
if (entry.type === "plugin" && lock.providers?.length && !lock.providers.includes(entry.provider)) {
|
|
1891
|
+
await error(
|
|
1892
|
+
`${id} requires the ${entry.provider} provider. Enable it with \`quiver-cli providers ${entry.provider}\` first.`
|
|
1893
|
+
);
|
|
1894
|
+
process.exitCode = 1;
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1781
1897
|
const selection = selectionFromLock(lock);
|
|
1782
1898
|
if (parsed.type === "skill") selection.skills.push(parsed.name);
|
|
1783
1899
|
if (parsed.type === "command") selection.commands.push(parsed.name);
|
|
1784
1900
|
if (parsed.type === "mcp") selection.mcp.push(parsed.name);
|
|
1901
|
+
if (parsed.type === "plugin") selection.plugins.push(parsed.name);
|
|
1785
1902
|
materializeCatalog(options.targetRoot, source, sourceCatalog, selection);
|
|
1786
1903
|
lock.entries[id] = entry;
|
|
1787
1904
|
writeLockfile(options.targetRoot, lock);
|
|
@@ -1790,13 +1907,19 @@ var init_add = __esm({
|
|
|
1790
1907
|
await success(`Added ${id}.`);
|
|
1791
1908
|
};
|
|
1792
1909
|
selectionFromLock = (lock) => {
|
|
1793
|
-
const selection = {
|
|
1910
|
+
const selection = {
|
|
1911
|
+
skills: [],
|
|
1912
|
+
commands: [],
|
|
1913
|
+
mcp: [],
|
|
1914
|
+
plugins: []
|
|
1915
|
+
};
|
|
1794
1916
|
for (const lid of Object.keys(lock.entries)) {
|
|
1795
1917
|
const p = parseEntryId(lid);
|
|
1796
1918
|
if (!p) continue;
|
|
1797
1919
|
if (p.type === "skill") selection.skills.push(p.name);
|
|
1798
1920
|
else if (p.type === "command") selection.commands.push(p.name);
|
|
1799
1921
|
else if (p.type === "mcp") selection.mcp.push(p.name);
|
|
1922
|
+
else if (p.type === "plugin") selection.plugins.push(p.name);
|
|
1800
1923
|
}
|
|
1801
1924
|
return selection;
|
|
1802
1925
|
};
|
|
@@ -1808,9 +1931,9 @@ var remove_exports = {};
|
|
|
1808
1931
|
__export(remove_exports, {
|
|
1809
1932
|
remove: () => remove
|
|
1810
1933
|
});
|
|
1811
|
-
import { existsSync as
|
|
1934
|
+
import { existsSync as existsSync13, readdirSync as readdirSync4, readFileSync as readFileSync8, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
1812
1935
|
import { resolve as resolve16 } from "path";
|
|
1813
|
-
var remove, cleanupEmptyGroups, rewriteRepoMcp;
|
|
1936
|
+
var remove, rewriteRepoPlugins, cleanupEmptyGroups, rewriteRepoMcp;
|
|
1814
1937
|
var init_remove = __esm({
|
|
1815
1938
|
"src/commands/remove.ts"() {
|
|
1816
1939
|
"use strict";
|
|
@@ -1823,7 +1946,9 @@ var init_remove = __esm({
|
|
|
1823
1946
|
remove = async (options) => {
|
|
1824
1947
|
const id = options.positionals[0];
|
|
1825
1948
|
if (!id) {
|
|
1826
|
-
await error(
|
|
1949
|
+
await error(
|
|
1950
|
+
"Usage: quiver remove <skill:name|command:name|mcp:name|plugin:name>"
|
|
1951
|
+
);
|
|
1827
1952
|
process.exitCode = 1;
|
|
1828
1953
|
return;
|
|
1829
1954
|
}
|
|
@@ -1844,30 +1969,45 @@ var init_remove = __esm({
|
|
|
1844
1969
|
await info(`${id} is not installed.`);
|
|
1845
1970
|
return;
|
|
1846
1971
|
}
|
|
1847
|
-
if (entry.type === "skill" || entry.type === "command") {
|
|
1972
|
+
if (entry.type === "skill" || entry.type === "command" || entry.type === "plugin") {
|
|
1848
1973
|
removeArtifact(options.targetRoot, entry.sourcePath);
|
|
1849
1974
|
cleanupEmptyGroups(options.targetRoot);
|
|
1850
1975
|
}
|
|
1851
1976
|
delete lock.entries[id];
|
|
1852
1977
|
writeLockfile(options.targetRoot, lock);
|
|
1853
1978
|
rewriteRepoMcp(options.targetRoot, lock);
|
|
1979
|
+
rewriteRepoPlugins(options.targetRoot, lock);
|
|
1854
1980
|
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
1855
1981
|
writeProviders(options.targetRoot, catalog, lock);
|
|
1856
1982
|
await success(`Removed ${id}.`);
|
|
1857
1983
|
};
|
|
1984
|
+
rewriteRepoPlugins = (targetRoot, lock) => {
|
|
1985
|
+
const configPath = resolve16(targetRoot, ".agents/config.json");
|
|
1986
|
+
if (!existsSync13(configPath)) return;
|
|
1987
|
+
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
1988
|
+
if (!config.plugins) return;
|
|
1989
|
+
const keep = new Set(
|
|
1990
|
+
Object.keys(lock.entries).map(parseEntryId).filter((p) => p?.type === "plugin").map((p) => p.name)
|
|
1991
|
+
);
|
|
1992
|
+
config.plugins = Object.fromEntries(
|
|
1993
|
+
Object.entries(config.plugins).filter(([name]) => keep.has(name))
|
|
1994
|
+
);
|
|
1995
|
+
if (!Object.keys(config.plugins).length) delete config.plugins;
|
|
1996
|
+
writeFileSync6(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1997
|
+
};
|
|
1858
1998
|
cleanupEmptyGroups = (targetRoot) => {
|
|
1859
1999
|
const skillsRoot = resolve16(targetRoot, ".agents/skills");
|
|
1860
|
-
if (!
|
|
2000
|
+
if (!existsSync13(skillsRoot)) return;
|
|
1861
2001
|
for (const entry of readdirSync4(skillsRoot, { withFileTypes: true })) {
|
|
1862
2002
|
if (!entry.isDirectory()) continue;
|
|
1863
2003
|
const dir = resolve16(skillsRoot, entry.name);
|
|
1864
|
-
if (
|
|
2004
|
+
if (existsSync13(resolve16(dir, "SKILL.md"))) continue;
|
|
1865
2005
|
if (readdirSync4(dir).length === 0) rmSync5(dir, { recursive: true, force: true });
|
|
1866
2006
|
}
|
|
1867
2007
|
};
|
|
1868
2008
|
rewriteRepoMcp = (targetRoot, lock) => {
|
|
1869
2009
|
const configPath = resolve16(targetRoot, ".agents/config.json");
|
|
1870
|
-
if (!
|
|
2010
|
+
if (!existsSync13(configPath)) return;
|
|
1871
2011
|
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
1872
2012
|
if (!config.mcpServers) return;
|
|
1873
2013
|
const keep = new Set(
|
|
@@ -1884,6 +2024,68 @@ var init_remove = __esm({
|
|
|
1884
2024
|
}
|
|
1885
2025
|
});
|
|
1886
2026
|
|
|
2027
|
+
// src/commands/toggle.ts
|
|
2028
|
+
var toggle_exports = {};
|
|
2029
|
+
__export(toggle_exports, {
|
|
2030
|
+
toggle: () => toggle
|
|
2031
|
+
});
|
|
2032
|
+
var toggle;
|
|
2033
|
+
var init_toggle = __esm({
|
|
2034
|
+
"src/commands/toggle.ts"() {
|
|
2035
|
+
"use strict";
|
|
2036
|
+
init_repo();
|
|
2037
|
+
init_io();
|
|
2038
|
+
init_schema();
|
|
2039
|
+
init_local_config();
|
|
2040
|
+
init_write();
|
|
2041
|
+
init_prompts();
|
|
2042
|
+
init_gitignore();
|
|
2043
|
+
toggle = async (options, enabled) => {
|
|
2044
|
+
const verb = enabled ? "enable" : "disable";
|
|
2045
|
+
const id = options.positionals[0];
|
|
2046
|
+
const parsed = id ? parseEntryId(id) : null;
|
|
2047
|
+
if (!parsed || parsed.type !== "mcp") {
|
|
2048
|
+
await error(`Usage: quiver-cli ${verb} mcp:<name>`);
|
|
2049
|
+
process.exitCode = 1;
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
const lock = readLockfile(options.targetRoot);
|
|
2053
|
+
if (!lock) {
|
|
2054
|
+
await error("No quiver.lock found. Run `quiver-cli init` first.");
|
|
2055
|
+
process.exitCode = 1;
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
2058
|
+
if (!repoCatalogExists(options.targetRoot)) {
|
|
2059
|
+
await error("No .agents/ directory found. Run `quiver-cli init` first.");
|
|
2060
|
+
process.exitCode = 1;
|
|
2061
|
+
return;
|
|
2062
|
+
}
|
|
2063
|
+
if (!lock.entries[id]) {
|
|
2064
|
+
const installed = Object.keys(lock.entries).map(parseEntryId).filter((p) => p?.type === "mcp").map((p) => p.name).sort((a, b) => a.localeCompare(b));
|
|
2065
|
+
await error(
|
|
2066
|
+
`${id} is not installed.` + (installed.length ? ` Installed MCP servers: ${installed.join(", ")}.` : " No MCP servers installed.")
|
|
2067
|
+
);
|
|
2068
|
+
process.exitCode = 1;
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
const disabled = disabledMcpServers(options.targetRoot);
|
|
2072
|
+
if (enabled !== disabled.has(parsed.name)) {
|
|
2073
|
+
await info(`${id} is already ${enabled ? "enabled" : "disabled"}.`);
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
setMcpEnabled(options.targetRoot, parsed.name, enabled);
|
|
2077
|
+
if (!enabled && ensureLocalOverrideIgnored(options.targetRoot)) {
|
|
2078
|
+
await step("Added .agents/config.local.json to .gitignore");
|
|
2079
|
+
}
|
|
2080
|
+
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
2081
|
+
writeProviders(options.targetRoot, catalog, lock);
|
|
2082
|
+
await success(
|
|
2083
|
+
enabled ? `Enabled ${id}.` : `Disabled ${id} locally (.agents/config.local.json). Re-enable with \`quiver-cli enable ${id}\`.`
|
|
2084
|
+
);
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
|
|
1887
2089
|
// src/commands/locksync.ts
|
|
1888
2090
|
var refreshLockDigests;
|
|
1889
2091
|
var init_locksync = __esm({
|
|
@@ -1894,6 +2096,7 @@ var init_locksync = __esm({
|
|
|
1894
2096
|
const skillByName = new Map(catalog.skills.map((s) => [s.name, s]));
|
|
1895
2097
|
const commandByName = new Map(catalog.commands.map((c) => [c.name, c]));
|
|
1896
2098
|
const mcpByName = new Map(catalog.mcp.map((m) => [m.name, m]));
|
|
2099
|
+
const pluginByName = new Map(catalog.plugins.map((p) => [p.name, p]));
|
|
1897
2100
|
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
1898
2101
|
if (entry.type === "skill") {
|
|
1899
2102
|
const cat = skillByName.get(id.slice("skill:".length));
|
|
@@ -1918,6 +2121,15 @@ var init_locksync = __esm({
|
|
|
1918
2121
|
entry.configDigest = cat.configDigest;
|
|
1919
2122
|
entry.transport = cat.server.transport;
|
|
1920
2123
|
}
|
|
2124
|
+
} else if (entry.type === "plugin") {
|
|
2125
|
+
const cat = pluginByName.get(id.slice("plugin:".length));
|
|
2126
|
+
if (!cat) continue;
|
|
2127
|
+
if (cat.digest !== entry.digest) {
|
|
2128
|
+
drift.push(`${id}: plugin content changed`);
|
|
2129
|
+
entry.digest = cat.digest;
|
|
2130
|
+
entry.sourcePath = cat.sourcePath;
|
|
2131
|
+
entry.requires = cat.requires;
|
|
2132
|
+
}
|
|
1921
2133
|
}
|
|
1922
2134
|
}
|
|
1923
2135
|
return drift;
|
|
@@ -1975,11 +2187,12 @@ var init_sync = __esm({
|
|
|
1975
2187
|
const haveSkills = new Set(catalog.skills.map((s) => s.name));
|
|
1976
2188
|
const haveCommands = new Set(catalog.commands.map((c) => c.name));
|
|
1977
2189
|
const haveMcp = new Set(catalog.mcp.map((m) => m.name));
|
|
2190
|
+
const havePlugins = new Set(catalog.plugins.map((p) => p.name));
|
|
1978
2191
|
const orphans = [];
|
|
1979
2192
|
for (const id of Object.keys(lock.entries)) {
|
|
1980
2193
|
const p = parseEntryId(id);
|
|
1981
2194
|
if (!p) continue;
|
|
1982
|
-
const present = p.type === "skill" && haveSkills.has(p.name) || p.type === "command" && haveCommands.has(p.name) || p.type === "mcp" && haveMcp.has(p.name);
|
|
2195
|
+
const present = p.type === "skill" && haveSkills.has(p.name) || p.type === "command" && haveCommands.has(p.name) || p.type === "mcp" && haveMcp.has(p.name) || p.type === "plugin" && havePlugins.has(p.name);
|
|
1983
2196
|
if (!present) orphans.push(id);
|
|
1984
2197
|
}
|
|
1985
2198
|
if (orphans.length) {
|
|
@@ -2085,7 +2298,7 @@ var update_exports = {};
|
|
|
2085
2298
|
__export(update_exports, {
|
|
2086
2299
|
update: () => update
|
|
2087
2300
|
});
|
|
2088
|
-
import { cpSync as cpSync2, mkdirSync as
|
|
2301
|
+
import { cpSync as cpSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync9, rmSync as rmSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
2089
2302
|
import { dirname as dirname5, resolve as resolve17 } from "path";
|
|
2090
2303
|
var update, applyUpdate, report;
|
|
2091
2304
|
var init_update = __esm({
|
|
@@ -2142,21 +2355,27 @@ var init_update = __esm({
|
|
|
2142
2355
|
sourceCatalog,
|
|
2143
2356
|
repoCatalog,
|
|
2144
2357
|
lock,
|
|
2145
|
-
options.force
|
|
2358
|
+
options.force,
|
|
2359
|
+
options.dryRun
|
|
2146
2360
|
);
|
|
2147
2361
|
if (report4.status === "updated") changed = true;
|
|
2148
2362
|
reports.push(report4);
|
|
2149
2363
|
}
|
|
2150
|
-
if (
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2364
|
+
if (!options.dryRun) {
|
|
2365
|
+
if (changed || catalogMoved) {
|
|
2366
|
+
writeLockfile(options.targetRoot, lock);
|
|
2367
|
+
}
|
|
2368
|
+
if (changed) {
|
|
2369
|
+
const { catalog } = loadRepoCatalog(
|
|
2370
|
+
options.targetRoot,
|
|
2371
|
+
lock.catalog.source
|
|
2372
|
+
);
|
|
2373
|
+
writeProviders(options.targetRoot, catalog, lock);
|
|
2374
|
+
}
|
|
2156
2375
|
}
|
|
2157
2376
|
report(reports, options);
|
|
2158
2377
|
};
|
|
2159
|
-
applyUpdate = (targetRoot, parsed, entry, sourceCatalog, repoCatalog, lock, force) => {
|
|
2378
|
+
applyUpdate = (targetRoot, parsed, entry, sourceCatalog, repoCatalog, lock, force, dryRun) => {
|
|
2160
2379
|
const id = `${parsed.type}:${parsed.name}`;
|
|
2161
2380
|
if (entry.type === "skill") {
|
|
2162
2381
|
const src2 = sourceCatalog.skills.find((s) => s.name === parsed.name);
|
|
@@ -2166,9 +2385,10 @@ var init_update = __esm({
|
|
|
2166
2385
|
if (repo2 && repo2.digest !== entry.digest && !force) {
|
|
2167
2386
|
return { id, status: "local-changes" };
|
|
2168
2387
|
}
|
|
2388
|
+
if (dryRun) return { id, status: "updated" };
|
|
2169
2389
|
const dest = resolve17(targetRoot, ".agents", src2.sourcePath);
|
|
2170
2390
|
rmSync6(dest, { recursive: true, force: true });
|
|
2171
|
-
|
|
2391
|
+
mkdirSync5(dirname5(dest), { recursive: true });
|
|
2172
2392
|
cpSync2(src2.absDir, dest, { recursive: true });
|
|
2173
2393
|
entry.digest = src2.digest;
|
|
2174
2394
|
entry.frontmatter = src2.frontmatter;
|
|
@@ -2183,13 +2403,38 @@ var init_update = __esm({
|
|
|
2183
2403
|
if (repo2 && repo2.digest !== entry.digest && !force) {
|
|
2184
2404
|
return { id, status: "local-changes" };
|
|
2185
2405
|
}
|
|
2406
|
+
if (dryRun) return { id, status: "updated" };
|
|
2186
2407
|
const dest = resolve17(targetRoot, ".agents", src2.sourcePath);
|
|
2187
|
-
|
|
2408
|
+
mkdirSync5(dirname5(dest), { recursive: true });
|
|
2188
2409
|
cpSync2(src2.absPath, dest, { force: true });
|
|
2189
2410
|
entry.digest = src2.digest;
|
|
2190
2411
|
entry.sourcePath = src2.sourcePath;
|
|
2191
2412
|
return { id, status: "updated" };
|
|
2192
2413
|
}
|
|
2414
|
+
if (entry.type === "plugin") {
|
|
2415
|
+
const src2 = sourceCatalog.plugins.find((p) => p.name === parsed.name);
|
|
2416
|
+
if (!src2) return { id, status: "not-in-catalog" };
|
|
2417
|
+
if (src2.digest === entry.digest) return { id, status: "up-to-date" };
|
|
2418
|
+
const repo2 = repoCatalog.plugins.find((p) => p.name === parsed.name);
|
|
2419
|
+
if (repo2 && repo2.digest !== entry.digest && !force) {
|
|
2420
|
+
return { id, status: "local-changes" };
|
|
2421
|
+
}
|
|
2422
|
+
if (dryRun) return { id, status: "updated" };
|
|
2423
|
+
const dest = resolve17(targetRoot, ".agents", src2.sourcePath);
|
|
2424
|
+
mkdirSync5(dirname5(dest), { recursive: true });
|
|
2425
|
+
cpSync2(src2.absPath, dest, { force: true });
|
|
2426
|
+
const configPath2 = resolve17(targetRoot, ".agents/config.json");
|
|
2427
|
+
const config2 = JSON.parse(readFileSync9(configPath2, "utf8"));
|
|
2428
|
+
config2.plugins = {
|
|
2429
|
+
...config2.plugins,
|
|
2430
|
+
[parsed.name]: sourceCatalog.config.plugins?.[parsed.name]
|
|
2431
|
+
};
|
|
2432
|
+
writeFileSync7(configPath2, JSON.stringify(config2, null, 2) + "\n");
|
|
2433
|
+
entry.digest = src2.digest;
|
|
2434
|
+
entry.sourcePath = src2.sourcePath;
|
|
2435
|
+
entry.requires = src2.requires;
|
|
2436
|
+
return { id, status: "updated" };
|
|
2437
|
+
}
|
|
2193
2438
|
const src = sourceCatalog.mcp.find((m) => m.name === parsed.name);
|
|
2194
2439
|
if (!src) return { id, status: "not-in-catalog" };
|
|
2195
2440
|
if (src.configDigest === entry.configDigest) return { id, status: "up-to-date" };
|
|
@@ -2197,6 +2442,7 @@ var init_update = __esm({
|
|
|
2197
2442
|
if (repo && repo.configDigest !== entry.configDigest && !force) {
|
|
2198
2443
|
return { id, status: "local-changes" };
|
|
2199
2444
|
}
|
|
2445
|
+
if (dryRun) return { id, status: "updated" };
|
|
2200
2446
|
const configPath = resolve17(targetRoot, ".agents", "config.json");
|
|
2201
2447
|
const config = JSON.parse(readFileSync9(configPath, "utf8"));
|
|
2202
2448
|
config.mcpServers = { ...config.mcpServers, [parsed.name]: src.server };
|
|
@@ -2214,6 +2460,7 @@ var init_update = __esm({
|
|
|
2214
2460
|
JSON.stringify(
|
|
2215
2461
|
{
|
|
2216
2462
|
ok: true,
|
|
2463
|
+
dryRun: options.dryRun,
|
|
2217
2464
|
updated: by("updated").map((r) => r.id),
|
|
2218
2465
|
upToDate: by("up-to-date").map((r) => r.id),
|
|
2219
2466
|
localChanges: by("local-changes").map((r) => r.id),
|
|
@@ -2227,7 +2474,8 @@ var init_update = __esm({
|
|
|
2227
2474
|
}
|
|
2228
2475
|
const c = palette();
|
|
2229
2476
|
const lines = [""];
|
|
2230
|
-
|
|
2477
|
+
const verb = options.dryRun ? "would update" : "updated";
|
|
2478
|
+
for (const r of by("updated")) lines.push(` ${c.cyan("\u2191")} ${r.id} ${verb}`);
|
|
2231
2479
|
for (const r of by("local-changes"))
|
|
2232
2480
|
lines.push(
|
|
2233
2481
|
` ${c.yellow("\u25B2")} ${r.id} ${c.yellow("local changes - skipped (use --force)")}`
|
|
@@ -2239,7 +2487,11 @@ var init_update = __esm({
|
|
|
2239
2487
|
const updated = by("updated").length;
|
|
2240
2488
|
lines.push(
|
|
2241
2489
|
"",
|
|
2242
|
-
` ${updated ?
|
|
2490
|
+
` ${updated ? options.dryRun ? c.cyan(
|
|
2491
|
+
`\u2191 ${updated} would be updated - run without --dry-run to apply`
|
|
2492
|
+
) : c.cyan(
|
|
2493
|
+
`\u2191 ${updated} updated - review and commit .agents/ + quiver.lock`
|
|
2494
|
+
) : c.green("\u2713 everything up to date with the catalog")}`,
|
|
2243
2495
|
""
|
|
2244
2496
|
);
|
|
2245
2497
|
block(lines);
|
|
@@ -2259,6 +2511,7 @@ var init_list = __esm({
|
|
|
2259
2511
|
init_repo();
|
|
2260
2512
|
init_io();
|
|
2261
2513
|
init_schema();
|
|
2514
|
+
init_local_config();
|
|
2262
2515
|
init_prompts();
|
|
2263
2516
|
truncate = (s, max) => {
|
|
2264
2517
|
const flat = s.replace(/\s+/g, " ").trim();
|
|
@@ -2287,16 +2540,19 @@ var init_list = __esm({
|
|
|
2287
2540
|
const skills = [];
|
|
2288
2541
|
const commands = [];
|
|
2289
2542
|
const mcp = [];
|
|
2543
|
+
const plugins = [];
|
|
2290
2544
|
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
2291
2545
|
const p = parseEntryId(id);
|
|
2292
2546
|
if (!p) continue;
|
|
2293
2547
|
if (entry.type === "skill") skills.push({ name: p.name, entry });
|
|
2294
2548
|
else if (entry.type === "command") commands.push({ name: p.name, entry });
|
|
2295
2549
|
else if (entry.type === "mcp") mcp.push({ name: p.name, entry });
|
|
2550
|
+
else if (entry.type === "plugin") plugins.push({ name: p.name, entry });
|
|
2296
2551
|
}
|
|
2297
|
-
for (const group of [skills, commands, mcp]) {
|
|
2552
|
+
for (const group of [skills, commands, mcp, plugins]) {
|
|
2298
2553
|
group.sort((a, b) => a.name.localeCompare(b.name));
|
|
2299
2554
|
}
|
|
2555
|
+
const disabled = disabledMcpServers(options.targetRoot);
|
|
2300
2556
|
if (options.json) {
|
|
2301
2557
|
console.log(
|
|
2302
2558
|
JSON.stringify(
|
|
@@ -2311,8 +2567,14 @@ var init_list = __esm({
|
|
|
2311
2567
|
mcp: mcp.map(({ name, entry }) => ({
|
|
2312
2568
|
name,
|
|
2313
2569
|
transport: entry.transport,
|
|
2570
|
+
enabled: !disabled.has(name),
|
|
2314
2571
|
detail: serverDetail2.get(name) ?? null,
|
|
2315
2572
|
toolCount: entry.tools ? Object.keys(entry.tools).length : null
|
|
2573
|
+
})),
|
|
2574
|
+
plugins: plugins.map(({ name, entry }) => ({
|
|
2575
|
+
name,
|
|
2576
|
+
provider: entry.provider,
|
|
2577
|
+
requires: entry.requires
|
|
2316
2578
|
}))
|
|
2317
2579
|
},
|
|
2318
2580
|
null,
|
|
@@ -2365,16 +2627,24 @@ var init_list = __esm({
|
|
|
2365
2627
|
count === null ? c.dim : c.green
|
|
2366
2628
|
);
|
|
2367
2629
|
const detail = serverDetail2.get(name);
|
|
2630
|
+
const off = disabled.has(name) ? ` ${c.yellow("disabled")}` : "";
|
|
2368
2631
|
lines.push(
|
|
2369
|
-
` ${name.padEnd(nameW)} ${entry.transport.padEnd(5)} ${tools}` + (detail ? ` ${c.dim(detail)}` : "")
|
|
2632
|
+
` ${name.padEnd(nameW)} ${entry.transport.padEnd(5)} ${tools}` + (detail ? ` ${c.dim(detail)}` : "") + off
|
|
2370
2633
|
);
|
|
2371
2634
|
}
|
|
2372
2635
|
}
|
|
2636
|
+
if (plugins.length) {
|
|
2637
|
+
lines.push("", ` ${c.bold("plugins")}`);
|
|
2638
|
+
for (const { name, entry } of plugins) {
|
|
2639
|
+
const requires = entry.requires.length ? ` ${c.dim(`requires: ${entry.requires.join(", ")}`)}` : "";
|
|
2640
|
+
lines.push(` ${name} ${c.dim(entry.provider)}${requires}`);
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2373
2643
|
const providers2 = lock.providers?.length ? lock.providers.join(", ") : "claude, opencode, codex";
|
|
2374
2644
|
lines.push(
|
|
2375
2645
|
"",
|
|
2376
2646
|
` ${c.bold(
|
|
2377
|
-
`${skills.length} skills \xB7 ${commands.length} commands \xB7 ${mcp.length} MCP servers`
|
|
2647
|
+
`${skills.length} skills \xB7 ${commands.length} commands \xB7 ${mcp.length} MCP servers \xB7 ${plugins.length} plugins`
|
|
2378
2648
|
)} ${c.dim(`providers: ${providers2}`)}`
|
|
2379
2649
|
);
|
|
2380
2650
|
if (missingTools) {
|
|
@@ -2386,84 +2656,6 @@ var init_list = __esm({
|
|
|
2386
2656
|
}
|
|
2387
2657
|
});
|
|
2388
2658
|
|
|
2389
|
-
// src/commands/status.ts
|
|
2390
|
-
var status_exports = {};
|
|
2391
|
-
__export(status_exports, {
|
|
2392
|
-
status: () => status
|
|
2393
|
-
});
|
|
2394
|
-
var status;
|
|
2395
|
-
var init_status = __esm({
|
|
2396
|
-
"src/commands/status.ts"() {
|
|
2397
|
-
"use strict";
|
|
2398
|
-
init_repo();
|
|
2399
|
-
init_io();
|
|
2400
|
-
init_schema();
|
|
2401
|
-
init_write();
|
|
2402
|
-
init_prompts();
|
|
2403
|
-
status = async (options) => {
|
|
2404
|
-
const lock = readLockfile(options.targetRoot);
|
|
2405
|
-
if (!lock) {
|
|
2406
|
-
if (options.json) console.log(JSON.stringify({ ok: false, error: "no-lockfile" }));
|
|
2407
|
-
else await error("No quiver.lock found. Run `quiver-cli init` first.");
|
|
2408
|
-
process.exitCode = 1;
|
|
2409
|
-
return;
|
|
2410
|
-
}
|
|
2411
|
-
if (!repoCatalogExists(options.targetRoot)) {
|
|
2412
|
-
if (options.json) console.log(JSON.stringify({ ok: false, error: "no-agents" }));
|
|
2413
|
-
else await error("No .agents/ directory found. Run `quiver-cli init` first.");
|
|
2414
|
-
process.exitCode = 1;
|
|
2415
|
-
return;
|
|
2416
|
-
}
|
|
2417
|
-
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
2418
|
-
const haveSkills = new Set(catalog.skills.map((s) => s.name));
|
|
2419
|
-
const haveCommands = new Set(catalog.commands.map((c) => c.name));
|
|
2420
|
-
const haveMcp = new Set(catalog.mcp.map((m) => m.name));
|
|
2421
|
-
const missing = [];
|
|
2422
|
-
const changed = [];
|
|
2423
|
-
const skillByName = new Map(catalog.skills.map((s) => [s.name, s]));
|
|
2424
|
-
const commandByName = new Map(catalog.commands.map((c) => [c.name, c]));
|
|
2425
|
-
const mcpByName = new Map(catalog.mcp.map((m) => [m.name, m]));
|
|
2426
|
-
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
2427
|
-
const p = parseEntryId(id);
|
|
2428
|
-
if (!p) continue;
|
|
2429
|
-
if (p.type === "skill") {
|
|
2430
|
-
if (!haveSkills.has(p.name)) missing.push(id);
|
|
2431
|
-
else if (entry.type === "skill" && skillByName.get(p.name).digest !== entry.digest)
|
|
2432
|
-
changed.push(id);
|
|
2433
|
-
} else if (p.type === "command") {
|
|
2434
|
-
if (!haveCommands.has(p.name)) missing.push(id);
|
|
2435
|
-
else if (entry.type === "command" && commandByName.get(p.name).digest !== entry.digest)
|
|
2436
|
-
changed.push(id);
|
|
2437
|
-
} else if (p.type === "mcp") {
|
|
2438
|
-
if (!haveMcp.has(p.name)) missing.push(id);
|
|
2439
|
-
else if (entry.type === "mcp" && mcpByName.get(p.name).configDigest !== entry.configDigest)
|
|
2440
|
-
changed.push(id);
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
const shimProblems = checkProviders(options.targetRoot, catalog, lock);
|
|
2444
|
-
const ok = missing.length === 0 && changed.length === 0 && shimProblems.length === 0;
|
|
2445
|
-
if (options.json) {
|
|
2446
|
-
console.log(JSON.stringify({ ok, missing, changed, shims: shimProblems }, null, 2));
|
|
2447
|
-
if (!ok) process.exitCode = 1;
|
|
2448
|
-
return;
|
|
2449
|
-
}
|
|
2450
|
-
if (ok) {
|
|
2451
|
-
await success("In sync: lockfile, .agents/ and provider shims agree.");
|
|
2452
|
-
return;
|
|
2453
|
-
}
|
|
2454
|
-
if (missing.length)
|
|
2455
|
-
await warn(`Missing in .agents/: ${missing.join(", ")}`);
|
|
2456
|
-
if (changed.length)
|
|
2457
|
-
await warn(`Content changed since lockfile: ${changed.join(", ")}`);
|
|
2458
|
-
if (shimProblems.length)
|
|
2459
|
-
await warn(`Provider shims out of date:
|
|
2460
|
-
- ${shimProblems.join("\n - ")}`);
|
|
2461
|
-
await info("Run `quiver-cli sync` to regenerate provider shims and refresh digests.");
|
|
2462
|
-
process.exitCode = 1;
|
|
2463
|
-
};
|
|
2464
|
-
}
|
|
2465
|
-
});
|
|
2466
|
-
|
|
2467
2659
|
// src/mcp/diff.ts
|
|
2468
2660
|
var diffSnapshots, isEmptyDiff;
|
|
2469
2661
|
var init_diff = __esm({
|
|
@@ -2598,9 +2790,12 @@ var init_snapshot = __esm({
|
|
|
2598
2790
|
var check_exports = {};
|
|
2599
2791
|
__export(check_exports, {
|
|
2600
2792
|
check: () => check,
|
|
2793
|
+
hasCommand: () => hasCommand,
|
|
2601
2794
|
summarize: () => summarize
|
|
2602
2795
|
});
|
|
2603
|
-
|
|
2796
|
+
import { accessSync as accessSync2, constants as constants2 } from "fs";
|
|
2797
|
+
import { delimiter, resolve as resolve18 } from "path";
|
|
2798
|
+
var check, report2, driftLines, list2, recommend, summarize, hasCommand, truncate2, fail;
|
|
2604
2799
|
var init_check = __esm({
|
|
2605
2800
|
"src/commands/check.ts"() {
|
|
2606
2801
|
"use strict";
|
|
@@ -2610,6 +2805,8 @@ var init_check = __esm({
|
|
|
2610
2805
|
init_diff();
|
|
2611
2806
|
init_introspect();
|
|
2612
2807
|
init_snapshot();
|
|
2808
|
+
init_local_config();
|
|
2809
|
+
init_write();
|
|
2613
2810
|
init_interpolate();
|
|
2614
2811
|
init_prompts();
|
|
2615
2812
|
check = async (options) => {
|
|
@@ -2624,8 +2821,10 @@ var init_check = __esm({
|
|
|
2624
2821
|
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
2625
2822
|
const skillByName = new Map(catalog.skills.map((s) => [s.name, s]));
|
|
2626
2823
|
const commandByName = new Map(catalog.commands.map((c) => [c.name, c]));
|
|
2824
|
+
const pluginByName = new Map(catalog.plugins.map((p) => [p.name, p]));
|
|
2627
2825
|
const skillDrift = [];
|
|
2628
|
-
const
|
|
2826
|
+
const pluginRequirements = [];
|
|
2827
|
+
const checked = { skills: 0, commands: 0, mcp: 0, plugins: 0 };
|
|
2629
2828
|
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
2630
2829
|
const p = parseEntryId(id);
|
|
2631
2830
|
if (!p) continue;
|
|
@@ -2639,15 +2838,33 @@ var init_check = __esm({
|
|
|
2639
2838
|
if (!cat) continue;
|
|
2640
2839
|
checked.commands += 1;
|
|
2641
2840
|
if (cat.digest !== entry.digest) skillDrift.push({ id, kind: "content" });
|
|
2841
|
+
} else if (entry.type === "plugin") {
|
|
2842
|
+
const cat = pluginByName.get(p.name);
|
|
2843
|
+
if (!cat) continue;
|
|
2844
|
+
checked.plugins += 1;
|
|
2845
|
+
if (cat.digest !== entry.digest) skillDrift.push({ id, kind: "content" });
|
|
2846
|
+
if (lock.providers?.length && !lock.providers.includes(entry.provider)) {
|
|
2847
|
+
continue;
|
|
2848
|
+
}
|
|
2849
|
+
for (const command of entry.requires) {
|
|
2850
|
+
if (!hasCommand(command)) pluginRequirements.push({ id, command });
|
|
2851
|
+
}
|
|
2642
2852
|
}
|
|
2643
2853
|
}
|
|
2854
|
+
const shimProblems = checkProviders(options.targetRoot, catalog, lock);
|
|
2644
2855
|
const mcpReports = [];
|
|
2856
|
+
const disabled = disabledMcpServers(options.targetRoot);
|
|
2645
2857
|
let lockChanged = false;
|
|
2646
2858
|
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
2859
|
+
if (options.offline) break;
|
|
2647
2860
|
if (entry.type !== "mcp") continue;
|
|
2648
2861
|
const p = parseEntryId(id);
|
|
2649
2862
|
const catMcp = catalog.mcp.find((m) => m.name === p.name);
|
|
2650
2863
|
if (!catMcp) continue;
|
|
2864
|
+
if (disabled.has(p.name)) {
|
|
2865
|
+
mcpReports.push({ id, status: "skipped", reason: "disabled locally" });
|
|
2866
|
+
continue;
|
|
2867
|
+
}
|
|
2651
2868
|
checked.mcp += 1;
|
|
2652
2869
|
const server = interpolateEnvVars(catMcp.server);
|
|
2653
2870
|
const res = await introspect(server, { allowStdio: options.introspectStdio });
|
|
@@ -2677,11 +2894,18 @@ var init_check = __esm({
|
|
|
2677
2894
|
}
|
|
2678
2895
|
}
|
|
2679
2896
|
if (lockChanged) writeLockfile(options.targetRoot, lock);
|
|
2680
|
-
const hasDrift = skillDrift.length > 0 || mcpReports.some((r) => r.status === "drift");
|
|
2897
|
+
const hasDrift = skillDrift.length > 0 || pluginRequirements.length > 0 || shimProblems.length > 0 || mcpReports.some((r) => r.status === "drift");
|
|
2681
2898
|
if (options.json) {
|
|
2682
2899
|
console.log(
|
|
2683
2900
|
JSON.stringify(
|
|
2684
|
-
{
|
|
2901
|
+
{
|
|
2902
|
+
ok: !hasDrift,
|
|
2903
|
+
checked,
|
|
2904
|
+
skillDrift,
|
|
2905
|
+
pluginRequirements,
|
|
2906
|
+
shims: shimProblems,
|
|
2907
|
+
mcp: mcpReports
|
|
2908
|
+
},
|
|
2685
2909
|
null,
|
|
2686
2910
|
2
|
|
2687
2911
|
)
|
|
@@ -2689,16 +2913,35 @@ var init_check = __esm({
|
|
|
2689
2913
|
if (hasDrift) process.exitCode = 1;
|
|
2690
2914
|
return;
|
|
2691
2915
|
}
|
|
2692
|
-
await report2(
|
|
2916
|
+
await report2(
|
|
2917
|
+
skillDrift,
|
|
2918
|
+
pluginRequirements,
|
|
2919
|
+
shimProblems,
|
|
2920
|
+
mcpReports,
|
|
2921
|
+
checked,
|
|
2922
|
+
options
|
|
2923
|
+
);
|
|
2693
2924
|
if (hasDrift) process.exitCode = 1;
|
|
2694
2925
|
};
|
|
2695
|
-
report2 = async (skillDrift, mcpReports, checked, options) => {
|
|
2926
|
+
report2 = async (skillDrift, pluginRequirements, shimProblems, mcpReports, checked, options) => {
|
|
2696
2927
|
if (skillDrift.length) {
|
|
2697
2928
|
await warn(
|
|
2698
|
-
`
|
|
2929
|
+
`Managed content changed since lockfile:
|
|
2699
2930
|
- ${skillDrift.map((s) => s.id).join("\n - ")}`
|
|
2700
2931
|
);
|
|
2701
2932
|
}
|
|
2933
|
+
if (pluginRequirements.length) {
|
|
2934
|
+
await warn(
|
|
2935
|
+
`Plugin requirements missing:
|
|
2936
|
+
- ${pluginRequirements.map((issue) => `${issue.id}: ${issue.command}`).join("\n - ")}`
|
|
2937
|
+
);
|
|
2938
|
+
}
|
|
2939
|
+
if (shimProblems.length) {
|
|
2940
|
+
await warn(
|
|
2941
|
+
`Provider shims out of date:
|
|
2942
|
+
- ${shimProblems.join("\n - ")}`
|
|
2943
|
+
);
|
|
2944
|
+
}
|
|
2702
2945
|
const skipped = mcpReports.filter((r) => r.status === "skipped");
|
|
2703
2946
|
if (skipped.length) {
|
|
2704
2947
|
const names = skipped.map((r) => parseEntryId(r.id)?.name ?? r.id);
|
|
@@ -2723,12 +2966,13 @@ var init_check = __esm({
|
|
|
2723
2966
|
- ${driftLines(r.diff, options.verbose).join("\n - ")}`);
|
|
2724
2967
|
}
|
|
2725
2968
|
const summary = summarize(checked);
|
|
2726
|
-
const hasDrift = skillDrift.length > 0 || drifted.length > 0;
|
|
2727
|
-
|
|
2969
|
+
const hasDrift = skillDrift.length > 0 || shimProblems.length > 0 || drifted.length > 0;
|
|
2970
|
+
const hasProblems = hasDrift || pluginRequirements.length > 0;
|
|
2971
|
+
if (!hasProblems) {
|
|
2728
2972
|
await success(`check passed: ${summary}, no drift detected.`);
|
|
2729
2973
|
} else {
|
|
2730
2974
|
await info(`checked ${summary}, drift detected.`);
|
|
2731
|
-
await recommend(skillDrift, drifted);
|
|
2975
|
+
await recommend(skillDrift, shimProblems, drifted);
|
|
2732
2976
|
}
|
|
2733
2977
|
};
|
|
2734
2978
|
driftLines = (diff, verbose) => {
|
|
@@ -2762,9 +3006,12 @@ var init_check = __esm({
|
|
|
2762
3006
|
const rest = names.length - sample;
|
|
2763
3007
|
return `${names.length} tools (${names.slice(0, sample).join(", ")}, \u2026 +${rest} more)`;
|
|
2764
3008
|
};
|
|
2765
|
-
recommend = async (skillDrift, drifted) => {
|
|
3009
|
+
recommend = async (skillDrift, shimProblems, drifted) => {
|
|
2766
3010
|
const c = palette();
|
|
2767
3011
|
const lines = ["to update the lockfile baseline:"];
|
|
3012
|
+
if (shimProblems.length) {
|
|
3013
|
+
lines.push(` ${c.cyan("quiver-cli sync")} regenerate provider shims`);
|
|
3014
|
+
}
|
|
2768
3015
|
if (drifted.length) {
|
|
2769
3016
|
lines.push(` ${c.cyan("quiver-cli check --accept")} accept the new MCP tool snapshots`);
|
|
2770
3017
|
}
|
|
@@ -2786,8 +3033,23 @@ var init_check = __esm({
|
|
|
2786
3033
|
if (c.skills) parts.push(plural(c.skills, "skill"));
|
|
2787
3034
|
if (c.commands) parts.push(plural(c.commands, "command"));
|
|
2788
3035
|
if (c.mcp) parts.push(plural(c.mcp, "MCP server"));
|
|
3036
|
+
if (c.plugins) parts.push(plural(c.plugins, "plugin"));
|
|
2789
3037
|
return parts.length ? parts.join(", ") : "nothing";
|
|
2790
3038
|
};
|
|
3039
|
+
hasCommand = (command) => {
|
|
3040
|
+
if (!/^[A-Za-z0-9._-]+$/.test(command)) return false;
|
|
3041
|
+
const extensions = process.platform === "win32" ? (process.env["PATHEXT"] ?? ".EXE;.CMD;.BAT;.COM").split(";") : [""];
|
|
3042
|
+
for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
|
|
3043
|
+
for (const extension of extensions) {
|
|
3044
|
+
try {
|
|
3045
|
+
accessSync2(resolve18(dir, command + extension), constants2.X_OK);
|
|
3046
|
+
return true;
|
|
3047
|
+
} catch {
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
return false;
|
|
3052
|
+
};
|
|
2791
3053
|
truncate2 = (s, max = 120) => s.length > max ? s.slice(0, max) + "\u2026" : s;
|
|
2792
3054
|
fail = async (options, code, message) => {
|
|
2793
3055
|
if (options.json) console.log(JSON.stringify({ ok: false, error: code }));
|
|
@@ -2800,14 +3062,14 @@ var init_check = __esm({
|
|
|
2800
3062
|
// src/catalog/upstreams.ts
|
|
2801
3063
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
2802
3064
|
import {
|
|
2803
|
-
existsSync as
|
|
3065
|
+
existsSync as existsSync14,
|
|
2804
3066
|
mkdtempSync as mkdtempSync2,
|
|
2805
3067
|
readFileSync as readFileSync10,
|
|
2806
3068
|
rmSync as rmSync7,
|
|
2807
3069
|
writeFileSync as writeFileSync8
|
|
2808
3070
|
} from "fs";
|
|
2809
3071
|
import { tmpdir } from "os";
|
|
2810
|
-
import { join, resolve as
|
|
3072
|
+
import { join, resolve as resolve19 } from "path";
|
|
2811
3073
|
var UPSTREAMS_FILE, upstreamsPath, loadUpstreams, writeUpstreams, fetchLatestCommit, fetchUpstreamDir, short, evaluateOrigin;
|
|
2812
3074
|
var init_upstreams = __esm({
|
|
2813
3075
|
"src/catalog/upstreams.ts"() {
|
|
@@ -2815,10 +3077,10 @@ var init_upstreams = __esm({
|
|
|
2815
3077
|
init_auth();
|
|
2816
3078
|
init_auth();
|
|
2817
3079
|
UPSTREAMS_FILE = "upstreams.json";
|
|
2818
|
-
upstreamsPath = (catalog) =>
|
|
3080
|
+
upstreamsPath = (catalog) => resolve19(catalog.root, UPSTREAMS_FILE);
|
|
2819
3081
|
loadUpstreams = (catalog) => {
|
|
2820
3082
|
const path = upstreamsPath(catalog);
|
|
2821
|
-
if (!
|
|
3083
|
+
if (!existsSync14(path)) return {};
|
|
2822
3084
|
return JSON.parse(readFileSync10(path, "utf8"));
|
|
2823
3085
|
};
|
|
2824
3086
|
writeUpstreams = (catalog, map) => {
|
|
@@ -2887,8 +3149,8 @@ var init_upstreams = __esm({
|
|
|
2887
3149
|
const msg = err instanceof Error && "stderr" in err ? String(err.stderr).trim().split("\n").pop() : err instanceof Error ? err.message : "git clone failed";
|
|
2888
3150
|
return { ok: false, reason: msg || "git clone failed" };
|
|
2889
3151
|
}
|
|
2890
|
-
const dir =
|
|
2891
|
-
if (!
|
|
3152
|
+
const dir = resolve19(tmp, origin.path);
|
|
3153
|
+
if (!existsSync14(resolve19(dir, "SKILL.md"))) {
|
|
2892
3154
|
cleanup();
|
|
2893
3155
|
return { ok: false, reason: `no SKILL.md at ${origin.path} in ${origin.repo}` };
|
|
2894
3156
|
}
|
|
@@ -2988,7 +3250,7 @@ var init_upstream = __esm({
|
|
|
2988
3250
|
guardWritableCatalog = async (catalog) => {
|
|
2989
3251
|
if (isCatalogWritable(catalog)) return false;
|
|
2990
3252
|
await error(
|
|
2991
|
-
"upstream is a catalog-maintenance command and the catalog here is not writable (the installed package or a remote cache).\nRun it inside the quiver-cli repo, or point at a writable local catalog with --catalog
|
|
3253
|
+
"upstream is a catalog-maintenance command and the catalog here is not writable (the installed package or a remote cache).\nRun it inside the quiver-cli repo, or point at a writable local catalog with --catalog=local:/absolute/path/.agents.\nTo update a consuming repo's installed entries, use quiver-cli check / quiver-cli update instead."
|
|
2992
3254
|
);
|
|
2993
3255
|
process.exitCode = 1;
|
|
2994
3256
|
return true;
|
|
@@ -3120,14 +3382,23 @@ var init_upstream = __esm({
|
|
|
3120
3382
|
lines.push(` ${mark[r.status]} ${c.bold(name)} ${detail} ${where}`);
|
|
3121
3383
|
}
|
|
3122
3384
|
block(lines);
|
|
3123
|
-
const drifted = sorted.filter(
|
|
3124
|
-
|
|
3125
|
-
)
|
|
3126
|
-
if (drifted.length) {
|
|
3385
|
+
const drifted = sorted.filter((r) => r.status === "drift");
|
|
3386
|
+
const curated = sorted.filter((r) => r.status === "drift-curated");
|
|
3387
|
+
if (drifted.length || curated.length) {
|
|
3127
3388
|
const hint = [""];
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3389
|
+
if (drifted.length) {
|
|
3390
|
+
hint.push(
|
|
3391
|
+
` ${c.cyan("quiver-cli upstream pull")} ${c.dim(
|
|
3392
|
+
`update the catalog copy (${drifted.map((r) => r.name).join(", ")})`
|
|
3393
|
+
)}`
|
|
3394
|
+
);
|
|
3395
|
+
}
|
|
3396
|
+
for (const r of curated) {
|
|
3397
|
+
hint.push(
|
|
3398
|
+
` ${c.yellow(r.name)}: ${c.dim(
|
|
3399
|
+
"curated \u2014 reconcile by hand, or upstream pull --force"
|
|
3400
|
+
)}`
|
|
3401
|
+
);
|
|
3131
3402
|
}
|
|
3132
3403
|
block(hint);
|
|
3133
3404
|
}
|
|
@@ -3163,83 +3434,6 @@ var init_upstream = __esm({
|
|
|
3163
3434
|
}
|
|
3164
3435
|
});
|
|
3165
3436
|
|
|
3166
|
-
// src/commands/login.ts
|
|
3167
|
-
var login_exports = {};
|
|
3168
|
-
__export(login_exports, {
|
|
3169
|
-
login: () => login
|
|
3170
|
-
});
|
|
3171
|
-
import process3 from "process";
|
|
3172
|
-
var login, promptToken, readStdin;
|
|
3173
|
-
var init_login = __esm({
|
|
3174
|
-
"src/commands/login.ts"() {
|
|
3175
|
-
"use strict";
|
|
3176
|
-
init_auth();
|
|
3177
|
-
init_prompts();
|
|
3178
|
-
login = async (options) => {
|
|
3179
|
-
const token = process3.stdin.isTTY ? await promptToken() : await readStdin();
|
|
3180
|
-
if (!token) {
|
|
3181
|
-
await error(
|
|
3182
|
-
"No token provided. Create a GitHub personal access token with `repo` read access and try again."
|
|
3183
|
-
);
|
|
3184
|
-
process3.exitCode = 1;
|
|
3185
|
-
return;
|
|
3186
|
-
}
|
|
3187
|
-
const validation = await validateToken(token);
|
|
3188
|
-
if (!validation.ok) {
|
|
3189
|
-
await error(`Token validation failed: ${validation.reason}`);
|
|
3190
|
-
process3.exitCode = 1;
|
|
3191
|
-
return;
|
|
3192
|
-
}
|
|
3193
|
-
writeStoredToken(token, validation.login);
|
|
3194
|
-
if (options.json) {
|
|
3195
|
-
console.log(JSON.stringify({ ok: true, login: validation.login }, null, 2));
|
|
3196
|
-
return;
|
|
3197
|
-
}
|
|
3198
|
-
await success(
|
|
3199
|
-
`Logged in as ${validation.login}. Token stored in ${authFilePath()}.`
|
|
3200
|
-
);
|
|
3201
|
-
};
|
|
3202
|
-
promptToken = async () => {
|
|
3203
|
-
await info(
|
|
3204
|
-
"Paste a GitHub personal access token (used for github: catalogs; needs read access to the catalog repo)."
|
|
3205
|
-
);
|
|
3206
|
-
const value = await password("GitHub token");
|
|
3207
|
-
return value?.trim() || null;
|
|
3208
|
-
};
|
|
3209
|
-
readStdin = async () => {
|
|
3210
|
-
let data = "";
|
|
3211
|
-
for await (const chunk of process3.stdin) data += chunk;
|
|
3212
|
-
return data.trim() || null;
|
|
3213
|
-
};
|
|
3214
|
-
}
|
|
3215
|
-
});
|
|
3216
|
-
|
|
3217
|
-
// src/commands/logout.ts
|
|
3218
|
-
var logout_exports = {};
|
|
3219
|
-
__export(logout_exports, {
|
|
3220
|
-
logout: () => logout
|
|
3221
|
-
});
|
|
3222
|
-
var logout;
|
|
3223
|
-
var init_logout = __esm({
|
|
3224
|
-
"src/commands/logout.ts"() {
|
|
3225
|
-
"use strict";
|
|
3226
|
-
init_auth();
|
|
3227
|
-
init_prompts();
|
|
3228
|
-
logout = async (options) => {
|
|
3229
|
-
const removed = deleteStoredToken();
|
|
3230
|
-
if (options.json) {
|
|
3231
|
-
console.log(JSON.stringify({ ok: true, removed }, null, 2));
|
|
3232
|
-
return;
|
|
3233
|
-
}
|
|
3234
|
-
if (removed) {
|
|
3235
|
-
await success(`Logged out. Removed ${authFilePath()}.`);
|
|
3236
|
-
} else {
|
|
3237
|
-
await info("Not logged in - nothing to remove.");
|
|
3238
|
-
}
|
|
3239
|
-
};
|
|
3240
|
-
}
|
|
3241
|
-
});
|
|
3242
|
-
|
|
3243
3437
|
// src/version/notifier.ts
|
|
3244
3438
|
var notifier_exports = {};
|
|
3245
3439
|
__export(notifier_exports, {
|
|
@@ -3249,9 +3443,9 @@ __export(notifier_exports, {
|
|
|
3249
3443
|
installHint: () => installHint,
|
|
3250
3444
|
notifierSuppressed: () => notifierSuppressed
|
|
3251
3445
|
});
|
|
3252
|
-
import { existsSync as
|
|
3253
|
-
import { homedir as
|
|
3254
|
-
import { dirname as dirname6, resolve as
|
|
3446
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
3447
|
+
import { homedir as homedir2 } from "os";
|
|
3448
|
+
import { dirname as dirname6, resolve as resolve20 } from "path";
|
|
3255
3449
|
var REGISTRY_URL, CHECK_TTL_MS, FETCH_TIMEOUT_MS, INSTALL_HINT, cacheFilePath, installHint, getCurrentVersion, compareSemver, readCache, writeCache, fetchLatestVersion, checkForUpdate, notifierSuppressed;
|
|
3256
3450
|
var init_notifier = __esm({
|
|
3257
3451
|
"src/version/notifier.ts"() {
|
|
@@ -3262,14 +3456,14 @@ var init_notifier = __esm({
|
|
|
3262
3456
|
FETCH_TIMEOUT_MS = 2e3;
|
|
3263
3457
|
INSTALL_HINT = "pnpm add -g quiver-cli";
|
|
3264
3458
|
cacheFilePath = () => {
|
|
3265
|
-
const base = process.env["XDG_CACHE_HOME"] ||
|
|
3266
|
-
return
|
|
3459
|
+
const base = process.env["XDG_CACHE_HOME"] || resolve20(homedir2(), ".cache");
|
|
3460
|
+
return resolve20(base, "quiver", "update-check.json");
|
|
3267
3461
|
};
|
|
3268
3462
|
installHint = () => INSTALL_HINT;
|
|
3269
3463
|
getCurrentVersion = () => {
|
|
3270
3464
|
try {
|
|
3271
3465
|
const pkg = JSON.parse(
|
|
3272
|
-
readFileSync11(
|
|
3466
|
+
readFileSync11(resolve20(packageRoot, "package.json"), "utf8")
|
|
3273
3467
|
);
|
|
3274
3468
|
return pkg.version;
|
|
3275
3469
|
} catch {
|
|
@@ -3295,7 +3489,7 @@ var init_notifier = __esm({
|
|
|
3295
3489
|
};
|
|
3296
3490
|
readCache = () => {
|
|
3297
3491
|
const path = cacheFilePath();
|
|
3298
|
-
if (!
|
|
3492
|
+
if (!existsSync15(path)) return null;
|
|
3299
3493
|
try {
|
|
3300
3494
|
return JSON.parse(readFileSync11(path, "utf8"));
|
|
3301
3495
|
} catch {
|
|
@@ -3305,7 +3499,7 @@ var init_notifier = __esm({
|
|
|
3305
3499
|
writeCache = (cache) => {
|
|
3306
3500
|
try {
|
|
3307
3501
|
const path = cacheFilePath();
|
|
3308
|
-
|
|
3502
|
+
mkdirSync6(dirname6(path), { recursive: true });
|
|
3309
3503
|
writeFileSync9(path, JSON.stringify(cache, null, 2) + "\n");
|
|
3310
3504
|
} catch {
|
|
3311
3505
|
}
|
|
@@ -3350,58 +3544,87 @@ var init_notifier = __esm({
|
|
|
3350
3544
|
|
|
3351
3545
|
// src/cli.ts
|
|
3352
3546
|
init_prompts();
|
|
3353
|
-
import
|
|
3354
|
-
var HELP = `quiver-cli - compose agent skills, commands & MCP servers into any repo
|
|
3547
|
+
import process3 from "process";
|
|
3548
|
+
var HELP = `quiver-cli - compose agent skills, commands, plugins & MCP servers into any repo
|
|
3355
3549
|
|
|
3356
3550
|
Usage:
|
|
3357
3551
|
quiver-cli <command> [options]
|
|
3358
3552
|
|
|
3359
3553
|
Commands:
|
|
3360
3554
|
init Interactive picker over the catalog; write native configs + quiver.lock
|
|
3361
|
-
add <id> Add
|
|
3555
|
+
add <id> Add an entry (skill:<name>, command:<name>, mcp:<name>, plugin:<name>)
|
|
3362
3556
|
remove <id> Remove a single entry; keep lockfile + configs consistent
|
|
3557
|
+
disable <id> Turn an MCP server off locally (mcp:<name>, gitignored override)
|
|
3558
|
+
enable <id> Turn a locally disabled MCP server back on
|
|
3363
3559
|
sync Regenerate provider configs from .agents/ (warns on drift)
|
|
3364
3560
|
providers [a,b] Change which tools get configs (claude, opencode, codex)
|
|
3365
3561
|
update [id] Pull newer catalog content into .agents/ (all or one entry)
|
|
3366
|
-
list Show installed entries (skills, commands, MCP tool counts)
|
|
3367
|
-
|
|
3368
|
-
|
|
3562
|
+
list Show installed entries (skills, commands, plugins, MCP tool counts)
|
|
3563
|
+
check Detect drift: skill digests, provider shims, MCP tool
|
|
3564
|
+
snapshots (--offline skips MCP re-introspection)
|
|
3369
3565
|
upstream Catalog maintenance: check source repos for skill updates
|
|
3370
3566
|
(run in the quiver-cli repo or with a writable --catalog)
|
|
3371
3567
|
upstream pull Pull latest upstream content into the catalog [skill]
|
|
3372
|
-
login Store a GitHub token for remote (github:) catalogs
|
|
3373
|
-
logout Remove the stored GitHub token
|
|
3374
3568
|
help Show this help
|
|
3375
3569
|
version Show the quiver-cli version
|
|
3376
3570
|
|
|
3377
3571
|
Options:
|
|
3378
3572
|
-f, --force Overwrite existing files
|
|
3379
3573
|
--all, -y Keep everything without prompting (non-interactive)
|
|
3380
|
-
--json Machine-readable output (
|
|
3574
|
+
--json Machine-readable output (check/upstream/list)
|
|
3381
3575
|
-V, --verbose Show full tool lists and description diffs (check)
|
|
3382
3576
|
--accept Record the current MCP tool snapshots as the new baseline (check)
|
|
3577
|
+
--offline Skip MCP re-introspection; check digests + shims only (check)
|
|
3578
|
+
--dry-run Report what would change without writing (update)
|
|
3383
3579
|
--providers=a,b Generate configs only for these tools (init, sync, providers)
|
|
3384
3580
|
--catalog=<source> Catalog source for init (e.g. github:owner/repo[/path][#ref])
|
|
3385
3581
|
--introspect-stdio Allow introspecting stdio MCP servers (runs foreign code)
|
|
3386
3582
|
-v, --version Show the quiver-cli version
|
|
3387
3583
|
`;
|
|
3584
|
+
var KNOWN_FLAGS = /* @__PURE__ */ new Set([
|
|
3585
|
+
"--force",
|
|
3586
|
+
"-f",
|
|
3587
|
+
"--all",
|
|
3588
|
+
"--yes",
|
|
3589
|
+
"-y",
|
|
3590
|
+
"--json",
|
|
3591
|
+
"--verbose",
|
|
3592
|
+
"-V",
|
|
3593
|
+
"--accept",
|
|
3594
|
+
"--offline",
|
|
3595
|
+
"--dry-run",
|
|
3596
|
+
"--introspect-stdio",
|
|
3597
|
+
"--help",
|
|
3598
|
+
"-h",
|
|
3599
|
+
"--version",
|
|
3600
|
+
"-v"
|
|
3601
|
+
]);
|
|
3602
|
+
var KNOWN_VALUE_FLAGS = ["--providers", "--catalog"];
|
|
3603
|
+
var isKnownFlag = (arg) => {
|
|
3604
|
+
if (KNOWN_FLAGS.has(arg)) return true;
|
|
3605
|
+
return KNOWN_VALUE_FLAGS.some((f) => arg.startsWith(`${f}=`));
|
|
3606
|
+
};
|
|
3388
3607
|
var parse2 = (argv) => {
|
|
3389
3608
|
const [command = "init", ...rest] = argv;
|
|
3390
3609
|
const flags = new Set(rest.filter((a) => a.startsWith("-")));
|
|
3391
3610
|
const positionals = rest.filter((a) => !a.startsWith("-"));
|
|
3611
|
+
const unknownFlags = [...flags].filter((a) => !isKnownFlag(a));
|
|
3392
3612
|
const providersFlag = rest.find((a) => a.startsWith("--providers="));
|
|
3393
3613
|
const providers2 = providersFlag ? providersFlag.slice("--providers=".length).split(",").map((p) => p.trim()).filter(Boolean) : null;
|
|
3394
3614
|
const catalogFlag = rest.find((a) => a.startsWith("--catalog="));
|
|
3395
3615
|
const catalog = catalogFlag ? catalogFlag.slice("--catalog=".length).trim() || null : null;
|
|
3396
3616
|
return {
|
|
3397
3617
|
command,
|
|
3618
|
+
unknownFlags,
|
|
3398
3619
|
options: {
|
|
3399
|
-
targetRoot:
|
|
3620
|
+
targetRoot: process3.cwd(),
|
|
3400
3621
|
force: flags.has("--force") || flags.has("-f"),
|
|
3401
3622
|
all: flags.has("--all") || flags.has("--yes") || flags.has("-y"),
|
|
3402
3623
|
json: flags.has("--json"),
|
|
3403
3624
|
verbose: flags.has("--verbose") || flags.has("-V"),
|
|
3404
3625
|
accept: flags.has("--accept"),
|
|
3626
|
+
offline: flags.has("--offline"),
|
|
3627
|
+
dryRun: flags.has("--dry-run"),
|
|
3405
3628
|
introspectStdio: flags.has("--introspect-stdio"),
|
|
3406
3629
|
providers: providers2,
|
|
3407
3630
|
catalog,
|
|
@@ -3410,13 +3633,22 @@ var parse2 = (argv) => {
|
|
|
3410
3633
|
};
|
|
3411
3634
|
};
|
|
3412
3635
|
var run = async () => {
|
|
3413
|
-
const { command, options } = parse2(
|
|
3414
|
-
if (
|
|
3636
|
+
const { command, options, unknownFlags } = parse2(process3.argv.slice(2));
|
|
3637
|
+
if (unknownFlags.length) {
|
|
3638
|
+
await error(
|
|
3639
|
+
`Unknown option${unknownFlags.length === 1 ? "" : "s"}: ${unknownFlags.join(", ")}
|
|
3640
|
+
`
|
|
3641
|
+
);
|
|
3642
|
+
console.log(HELP);
|
|
3643
|
+
process3.exitCode = 1;
|
|
3644
|
+
return;
|
|
3645
|
+
}
|
|
3646
|
+
if (process3.stdin.isTTY && !options.all) {
|
|
3415
3647
|
const { checkNodeForCommand: checkNodeForCommand2 } = await Promise.resolve().then(() => (init_node_guard(), node_guard_exports));
|
|
3416
3648
|
const guard = checkNodeForCommand2(command);
|
|
3417
3649
|
if (!guard.ok) {
|
|
3418
3650
|
await error(guard.message);
|
|
3419
|
-
|
|
3651
|
+
process3.exitCode = 1;
|
|
3420
3652
|
return;
|
|
3421
3653
|
}
|
|
3422
3654
|
}
|
|
@@ -3437,6 +3669,12 @@ var run = async () => {
|
|
|
3437
3669
|
await remove2(options);
|
|
3438
3670
|
break;
|
|
3439
3671
|
}
|
|
3672
|
+
case "enable":
|
|
3673
|
+
case "disable": {
|
|
3674
|
+
const { toggle: toggle2 } = await Promise.resolve().then(() => (init_toggle(), toggle_exports));
|
|
3675
|
+
await toggle2(options, command === "enable");
|
|
3676
|
+
break;
|
|
3677
|
+
}
|
|
3440
3678
|
case "sync": {
|
|
3441
3679
|
const { sync: sync2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
|
|
3442
3680
|
await sync2(options);
|
|
@@ -3458,11 +3696,6 @@ var run = async () => {
|
|
|
3458
3696
|
await list3(options);
|
|
3459
3697
|
break;
|
|
3460
3698
|
}
|
|
3461
|
-
case "status": {
|
|
3462
|
-
const { status: status2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
3463
|
-
await status2(options);
|
|
3464
|
-
break;
|
|
3465
|
-
}
|
|
3466
3699
|
case "check": {
|
|
3467
3700
|
const { check: check2 } = await Promise.resolve().then(() => (init_check(), check_exports));
|
|
3468
3701
|
await check2(options);
|
|
@@ -3473,16 +3706,6 @@ var run = async () => {
|
|
|
3473
3706
|
await upstream2(options);
|
|
3474
3707
|
break;
|
|
3475
3708
|
}
|
|
3476
|
-
case "login": {
|
|
3477
|
-
const { login: login2 } = await Promise.resolve().then(() => (init_login(), login_exports));
|
|
3478
|
-
await login2(options);
|
|
3479
|
-
break;
|
|
3480
|
-
}
|
|
3481
|
-
case "logout": {
|
|
3482
|
-
const { logout: logout2 } = await Promise.resolve().then(() => (init_logout(), logout_exports));
|
|
3483
|
-
await logout2(options);
|
|
3484
|
-
break;
|
|
3485
|
-
}
|
|
3486
3709
|
case "help":
|
|
3487
3710
|
case "--help":
|
|
3488
3711
|
case "-h":
|
|
@@ -3505,7 +3728,7 @@ var run = async () => {
|
|
|
3505
3728
|
console.error(`Unknown command: ${command}
|
|
3506
3729
|
`);
|
|
3507
3730
|
console.log(HELP);
|
|
3508
|
-
|
|
3731
|
+
process3.exitCode = 1;
|
|
3509
3732
|
}
|
|
3510
3733
|
if (!["version", "--version", "-v", "help", "--help", "-h"].includes(command)) {
|
|
3511
3734
|
await maybeNotifyUpdate(options.json);
|
|
@@ -3527,7 +3750,14 @@ ${c.yellow("\u25B2")} ${c.bold("update available")} ${c.dim(
|
|
|
3527
3750
|
} catch {
|
|
3528
3751
|
}
|
|
3529
3752
|
};
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3753
|
+
var main = () => {
|
|
3754
|
+
run().catch(async (err) => {
|
|
3755
|
+
await error(err instanceof Error ? err.message : String(err));
|
|
3756
|
+
process3.exitCode = 1;
|
|
3757
|
+
});
|
|
3758
|
+
};
|
|
3759
|
+
export {
|
|
3760
|
+
main,
|
|
3761
|
+
parse2 as parse,
|
|
3762
|
+
run
|
|
3763
|
+
};
|