quiver-cli 0.7.0 → 1.0.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 +110 -45
- package/bin/quiver-cli.mjs +3 -1
- package/dist/cli.js +733 -499
- 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,
|
|
@@ -205,7 +188,13 @@ var init_node_guard = __esm({
|
|
|
205
188
|
"src/version/node-guard.ts"() {
|
|
206
189
|
"use strict";
|
|
207
190
|
MIN_NODE = "20.12.0";
|
|
208
|
-
INTERACTIVE_COMMANDS = /* @__PURE__ */ new Set([
|
|
191
|
+
INTERACTIVE_COMMANDS = /* @__PURE__ */ new Set([
|
|
192
|
+
"init",
|
|
193
|
+
"add",
|
|
194
|
+
"remove",
|
|
195
|
+
"rm",
|
|
196
|
+
"providers"
|
|
197
|
+
]);
|
|
209
198
|
parse = (v) => {
|
|
210
199
|
const [major = 0, minor = 0, patch = 0] = v.replace(/^v/, "").split(".").map((p) => Number.parseInt(p, 10) || 0);
|
|
211
200
|
return [major, minor, patch];
|
|
@@ -320,7 +309,7 @@ var init_frontmatter = __esm({
|
|
|
320
309
|
// src/catalog/discover.ts
|
|
321
310
|
import { existsSync, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
322
311
|
import { relative as relative2, resolve as resolve2 } from "path";
|
|
323
|
-
var readConfig, discoverSkills, discoverCommands, discoverMcp, loadCatalog;
|
|
312
|
+
var readConfig, discoverSkills, discoverCommands, discoverMcp, discoverPlugins, loadCatalog;
|
|
324
313
|
var init_discover = __esm({
|
|
325
314
|
"src/catalog/discover.ts"() {
|
|
326
315
|
"use strict";
|
|
@@ -394,6 +383,20 @@ var init_discover = __esm({
|
|
|
394
383
|
configDigest: jsonDigest(servers[name])
|
|
395
384
|
}));
|
|
396
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
|
+
});
|
|
397
400
|
loadCatalog = (catalog) => {
|
|
398
401
|
const { config, path } = readConfig(catalog.root);
|
|
399
402
|
return {
|
|
@@ -401,14 +404,15 @@ var init_discover = __esm({
|
|
|
401
404
|
configPath: path,
|
|
402
405
|
skills: discoverSkills(catalog.root),
|
|
403
406
|
commands: discoverCommands(catalog.root),
|
|
404
|
-
mcp: discoverMcp(config)
|
|
407
|
+
mcp: discoverMcp(config),
|
|
408
|
+
plugins: discoverPlugins(catalog.root, config)
|
|
405
409
|
};
|
|
406
410
|
};
|
|
407
411
|
}
|
|
408
412
|
});
|
|
409
413
|
|
|
410
414
|
// src/catalog/entries.ts
|
|
411
|
-
var skillToEntry, commandToEntry, mcpToEntry;
|
|
415
|
+
var skillToEntry, commandToEntry, mcpToEntry, pluginToEntry;
|
|
412
416
|
var init_entries = __esm({
|
|
413
417
|
"src/catalog/entries.ts"() {
|
|
414
418
|
"use strict";
|
|
@@ -431,6 +435,13 @@ var init_entries = __esm({
|
|
|
431
435
|
tools: null,
|
|
432
436
|
toolsFetchedAt: null
|
|
433
437
|
});
|
|
438
|
+
pluginToEntry = (plugin) => ({
|
|
439
|
+
type: "plugin",
|
|
440
|
+
provider: plugin.provider,
|
|
441
|
+
sourcePath: plugin.sourcePath,
|
|
442
|
+
digest: plugin.digest,
|
|
443
|
+
requires: plugin.requires
|
|
444
|
+
});
|
|
434
445
|
}
|
|
435
446
|
});
|
|
436
447
|
|
|
@@ -520,6 +531,12 @@ var init_materialize = __esm({
|
|
|
520
531
|
mkdirSync(dirname(dest), { recursive: true });
|
|
521
532
|
cpSync(command.absPath, dest, { force: true });
|
|
522
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
|
+
}
|
|
523
540
|
const filteredConfig = {};
|
|
524
541
|
if (catalog.config.shared) filteredConfig["shared"] = catalog.config.shared;
|
|
525
542
|
const mcpServers = {};
|
|
@@ -527,6 +544,14 @@ var init_materialize = __esm({
|
|
|
527
544
|
if (selection.mcp.includes(mcp.name)) mcpServers[mcp.name] = mcp.server;
|
|
528
545
|
}
|
|
529
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;
|
|
530
555
|
if (catalog.config.claude) filteredConfig["claude"] = catalog.config.claude;
|
|
531
556
|
writeFileSync(
|
|
532
557
|
resolve4(destRoot, "config.json"),
|
|
@@ -562,53 +587,10 @@ var init_materialize = __esm({
|
|
|
562
587
|
|
|
563
588
|
// src/github/auth.ts
|
|
564
589
|
import { execFileSync } from "child_process";
|
|
565
|
-
|
|
566
|
-
chmodSync,
|
|
567
|
-
existsSync as existsSync4,
|
|
568
|
-
mkdirSync as mkdirSync2,
|
|
569
|
-
readFileSync as readFileSync4,
|
|
570
|
-
rmSync as rmSync2,
|
|
571
|
-
writeFileSync as writeFileSync2
|
|
572
|
-
} from "fs";
|
|
573
|
-
import { homedir } from "os";
|
|
574
|
-
import { resolve as resolve5 } from "path";
|
|
575
|
-
var configDir, authFilePath, readAuthFile, readStoredToken, writeStoredToken, deleteStoredToken, cachedToken, ghToken, resolveGithubToken, resetTokenCache, validateToken;
|
|
590
|
+
var cachedToken, ghToken, resolveGithubToken;
|
|
576
591
|
var init_auth = __esm({
|
|
577
592
|
"src/github/auth.ts"() {
|
|
578
593
|
"use strict";
|
|
579
|
-
configDir = () => {
|
|
580
|
-
const base = process.env["XDG_CONFIG_HOME"] || resolve5(homedir(), ".config");
|
|
581
|
-
return resolve5(base, "quiver");
|
|
582
|
-
};
|
|
583
|
-
authFilePath = () => resolve5(configDir(), "auth.json");
|
|
584
|
-
readAuthFile = () => {
|
|
585
|
-
const path = authFilePath();
|
|
586
|
-
if (!existsSync4(path)) return null;
|
|
587
|
-
try {
|
|
588
|
-
return JSON.parse(readFileSync4(path, "utf8"));
|
|
589
|
-
} catch {
|
|
590
|
-
return null;
|
|
591
|
-
}
|
|
592
|
-
};
|
|
593
|
-
readStoredToken = () => readAuthFile()?.github?.token ?? null;
|
|
594
|
-
writeStoredToken = (token, login2) => {
|
|
595
|
-
mkdirSync2(configDir(), { recursive: true });
|
|
596
|
-
const file = {
|
|
597
|
-
github: { token, login: login2, createdAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
598
|
-
};
|
|
599
|
-
writeFileSync2(authFilePath(), JSON.stringify(file, null, 2) + "\n", {
|
|
600
|
-
mode: 384
|
|
601
|
-
});
|
|
602
|
-
chmodSync(authFilePath(), 384);
|
|
603
|
-
resetTokenCache();
|
|
604
|
-
};
|
|
605
|
-
deleteStoredToken = () => {
|
|
606
|
-
const path = authFilePath();
|
|
607
|
-
if (!existsSync4(path)) return false;
|
|
608
|
-
rmSync2(path);
|
|
609
|
-
resetTokenCache();
|
|
610
|
-
return true;
|
|
611
|
-
};
|
|
612
594
|
ghToken = () => {
|
|
613
595
|
try {
|
|
614
596
|
const out = execFileSync("gh", ["auth", "token"], {
|
|
@@ -623,38 +605,14 @@ var init_auth = __esm({
|
|
|
623
605
|
};
|
|
624
606
|
resolveGithubToken = () => {
|
|
625
607
|
if (cachedToken !== void 0) return cachedToken;
|
|
626
|
-
cachedToken = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"] ??
|
|
608
|
+
cachedToken = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"] ?? ghToken();
|
|
627
609
|
return cachedToken;
|
|
628
610
|
};
|
|
629
|
-
resetTokenCache = () => {
|
|
630
|
-
cachedToken = void 0;
|
|
631
|
-
};
|
|
632
|
-
validateToken = async (token) => {
|
|
633
|
-
let res;
|
|
634
|
-
try {
|
|
635
|
-
res = await fetch("https://api.github.com/user", {
|
|
636
|
-
headers: {
|
|
637
|
-
Accept: "application/vnd.github+json",
|
|
638
|
-
"User-Agent": "quiver-cli",
|
|
639
|
-
Authorization: `Bearer ${token}`
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
} catch (err) {
|
|
643
|
-
return {
|
|
644
|
-
ok: false,
|
|
645
|
-
reason: err instanceof Error ? err.message : "fetch failed"
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
if (res.status === 401) return { ok: false, reason: "token is invalid or expired" };
|
|
649
|
-
if (!res.ok) return { ok: false, reason: `HTTP ${res.status}` };
|
|
650
|
-
const body = await res.json();
|
|
651
|
-
return { ok: true, login: body.login ?? "unknown" };
|
|
652
|
-
};
|
|
653
611
|
}
|
|
654
612
|
});
|
|
655
613
|
|
|
656
614
|
// src/github/api.ts
|
|
657
|
-
import { mkdirSync as
|
|
615
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
658
616
|
import { Readable } from "stream";
|
|
659
617
|
import { pipeline } from "stream/promises";
|
|
660
618
|
import * as tar from "tar";
|
|
@@ -672,13 +630,14 @@ var init_api = __esm({
|
|
|
672
630
|
if (token) h["Authorization"] = `Bearer ${token}`;
|
|
673
631
|
return h;
|
|
674
632
|
};
|
|
675
|
-
failureReason = (
|
|
676
|
-
if (
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
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}`;
|
|
682
641
|
};
|
|
683
642
|
apiFetch = async (url) => {
|
|
684
643
|
let res;
|
|
@@ -715,7 +674,7 @@ var init_api = __esm({
|
|
|
715
674
|
);
|
|
716
675
|
if (!res.ok) return res;
|
|
717
676
|
if (!res.value.body) return { ok: false, reason: "empty tarball response" };
|
|
718
|
-
|
|
677
|
+
mkdirSync2(destDir, { recursive: true });
|
|
719
678
|
try {
|
|
720
679
|
await pipeline(
|
|
721
680
|
Readable.fromWeb(res.value.body),
|
|
@@ -740,9 +699,9 @@ __export(remote_exports, {
|
|
|
740
699
|
fetchRemoteCatalog: () => fetchRemoteCatalog,
|
|
741
700
|
parseGithubSource: () => parseGithubSource
|
|
742
701
|
});
|
|
743
|
-
import { existsSync as
|
|
744
|
-
import { homedir
|
|
745
|
-
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";
|
|
746
705
|
var parseGithubSource, catalogCacheRoot, catalogCacheDir, fetchRemoteCatalog;
|
|
747
706
|
var init_remote = __esm({
|
|
748
707
|
"src/catalog/remote.ts"() {
|
|
@@ -765,10 +724,10 @@ var init_remote = __esm({
|
|
|
765
724
|
return { repo: `${owner}/${repo}`, path: pathParts.join("/"), ref };
|
|
766
725
|
};
|
|
767
726
|
catalogCacheRoot = () => {
|
|
768
|
-
const base = process.env["XDG_CACHE_HOME"] ||
|
|
769
|
-
return
|
|
727
|
+
const base = process.env["XDG_CACHE_HOME"] || resolve5(homedir(), ".cache");
|
|
728
|
+
return resolve5(base, "quiver", "catalogs");
|
|
770
729
|
};
|
|
771
|
-
catalogCacheDir = (repo, sha) =>
|
|
730
|
+
catalogCacheDir = (repo, sha) => resolve5(catalogCacheRoot(), `${repo.replace("/", "-")}-${sha.slice(0, 12)}`);
|
|
772
731
|
fetchRemoteCatalog = async (source, options = {}) => {
|
|
773
732
|
const spec = parseGithubSource(source);
|
|
774
733
|
let ref = spec.ref;
|
|
@@ -788,22 +747,22 @@ var init_remote = __esm({
|
|
|
788
747
|
sha = commit.value;
|
|
789
748
|
}
|
|
790
749
|
const cacheDir = catalogCacheDir(spec.repo, sha);
|
|
791
|
-
if (!
|
|
792
|
-
|
|
750
|
+
if (!existsSync4(cacheDir)) {
|
|
751
|
+
mkdirSync3(dirname2(cacheDir), { recursive: true });
|
|
793
752
|
const tmp = mkdtempSync(`${cacheDir}.tmp-`);
|
|
794
753
|
const result = await downloadTarball(spec.repo, sha, tmp);
|
|
795
754
|
if (!result.ok) {
|
|
796
|
-
|
|
755
|
+
rmSync2(tmp, { recursive: true, force: true });
|
|
797
756
|
throw new Error(`Cannot download ${spec.repo}@${sha.slice(0, 12)}: ${result.reason}`);
|
|
798
757
|
}
|
|
799
758
|
try {
|
|
800
759
|
renameSync(tmp, cacheDir);
|
|
801
760
|
} catch {
|
|
802
|
-
|
|
761
|
+
rmSync2(tmp, { recursive: true, force: true });
|
|
803
762
|
}
|
|
804
763
|
}
|
|
805
|
-
const root = spec.path ?
|
|
806
|
-
if (!
|
|
764
|
+
const root = spec.path ? resolve5(cacheDir, spec.path) : cacheDir;
|
|
765
|
+
if (!existsSync4(root)) {
|
|
807
766
|
throw new Error(
|
|
808
767
|
`Catalog path "${spec.path}" not found in ${spec.repo}@${sha.slice(0, 12)}.`
|
|
809
768
|
);
|
|
@@ -814,21 +773,21 @@ var init_remote = __esm({
|
|
|
814
773
|
});
|
|
815
774
|
|
|
816
775
|
// src/catalog/resolve.ts
|
|
817
|
-
import { accessSync, constants, existsSync as
|
|
818
|
-
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";
|
|
819
778
|
import { fileURLToPath } from "url";
|
|
820
779
|
var packageRoot, DEFAULT_CATALOG_SOURCE, resolveCatalog, isInstalledPackage, isBundledCatalog, isCatalogWritable;
|
|
821
780
|
var init_resolve = __esm({
|
|
822
781
|
"src/catalog/resolve.ts"() {
|
|
823
782
|
"use strict";
|
|
824
|
-
packageRoot =
|
|
783
|
+
packageRoot = resolve6(dirname3(fileURLToPath(import.meta.url)), "..");
|
|
825
784
|
DEFAULT_CATALOG_SOURCE = "local:template/.agents";
|
|
826
785
|
resolveCatalog = async (source = DEFAULT_CATALOG_SOURCE, options = {}) => {
|
|
827
786
|
const [scheme, ...rest] = source.split(":");
|
|
828
787
|
const spec = rest.join(":");
|
|
829
788
|
if (scheme === "local") {
|
|
830
|
-
const root =
|
|
831
|
-
if (!
|
|
789
|
+
const root = resolve6(packageRoot, spec);
|
|
790
|
+
if (!existsSync5(root)) {
|
|
832
791
|
throw new Error(`Catalog not found at ${root} (source: ${source}).`);
|
|
833
792
|
}
|
|
834
793
|
return { source, root };
|
|
@@ -873,7 +832,9 @@ var init_schema = __esm({
|
|
|
873
832
|
if (idx === -1) return null;
|
|
874
833
|
const type = id.slice(0, idx);
|
|
875
834
|
const name = id.slice(idx + 1);
|
|
876
|
-
if (type !== "skill" && type !== "command" && type !== "mcp")
|
|
835
|
+
if (type !== "skill" && type !== "command" && type !== "mcp" && type !== "plugin") {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
877
838
|
if (!name) return null;
|
|
878
839
|
return { type, name };
|
|
879
840
|
};
|
|
@@ -881,19 +842,19 @@ var init_schema = __esm({
|
|
|
881
842
|
});
|
|
882
843
|
|
|
883
844
|
// src/lockfile/io.ts
|
|
884
|
-
import { existsSync as
|
|
885
|
-
import { resolve as
|
|
845
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
846
|
+
import { resolve as resolve7 } from "path";
|
|
886
847
|
var lockfilePath, lockfileExists, readLockfile, writeLockfile, emptyLockfile;
|
|
887
848
|
var init_io = __esm({
|
|
888
849
|
"src/lockfile/io.ts"() {
|
|
889
850
|
"use strict";
|
|
890
851
|
init_schema();
|
|
891
|
-
lockfilePath = (targetRoot) =>
|
|
892
|
-
lockfileExists = (targetRoot) =>
|
|
852
|
+
lockfilePath = (targetRoot) => resolve7(targetRoot, LOCKFILE_NAME);
|
|
853
|
+
lockfileExists = (targetRoot) => existsSync6(lockfilePath(targetRoot));
|
|
893
854
|
readLockfile = (targetRoot) => {
|
|
894
855
|
const path = lockfilePath(targetRoot);
|
|
895
|
-
if (!
|
|
896
|
-
const parsed = JSON.parse(
|
|
856
|
+
if (!existsSync6(path)) return null;
|
|
857
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
897
858
|
if (parsed.version !== LOCKFILE_VERSION) {
|
|
898
859
|
throw new Error(
|
|
899
860
|
`Unsupported ${LOCKFILE_NAME} version ${parsed.version}; expected ${LOCKFILE_VERSION}.`
|
|
@@ -912,7 +873,7 @@ var init_io = __esm({
|
|
|
912
873
|
...lock.providers !== void 0 ? { providers: lock.providers } : {},
|
|
913
874
|
entries: sortedEntries
|
|
914
875
|
};
|
|
915
|
-
|
|
876
|
+
writeFileSync2(lockfilePath(targetRoot), JSON.stringify(ordered, null, 2) + "\n");
|
|
916
877
|
};
|
|
917
878
|
emptyLockfile = (catalogSource, remote = {}) => ({
|
|
918
879
|
version: LOCKFILE_VERSION,
|
|
@@ -927,8 +888,64 @@ var init_io = __esm({
|
|
|
927
888
|
}
|
|
928
889
|
});
|
|
929
890
|
|
|
891
|
+
// src/providers/resolve.ts
|
|
892
|
+
var validateProviders, sameProviders, resolveProviders, selectProviders;
|
|
893
|
+
var init_resolve2 = __esm({
|
|
894
|
+
"src/providers/resolve.ts"() {
|
|
895
|
+
"use strict";
|
|
896
|
+
init_schema();
|
|
897
|
+
init_prompts();
|
|
898
|
+
validateProviders = (values) => {
|
|
899
|
+
const invalid = values.filter((v) => !isProvider(v));
|
|
900
|
+
if (invalid.length) return { invalid };
|
|
901
|
+
const seen = /* @__PURE__ */ new Set();
|
|
902
|
+
const providers2 = [];
|
|
903
|
+
for (const v of values) {
|
|
904
|
+
if (isProvider(v) && !seen.has(v)) {
|
|
905
|
+
seen.add(v);
|
|
906
|
+
providers2.push(v);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return { providers: providers2 };
|
|
910
|
+
};
|
|
911
|
+
sameProviders = (a, b) => a.length === b.length && (/* @__PURE__ */ new Set([...a, ...b])).size === a.length;
|
|
912
|
+
resolveProviders = async (options) => {
|
|
913
|
+
if (options.providers) {
|
|
914
|
+
const { providers: providers2, invalid } = validateProviders(options.providers);
|
|
915
|
+
if (invalid) {
|
|
916
|
+
await error(
|
|
917
|
+
`Unknown provider(s): ${invalid.join(", ")}. Valid: ${PROVIDERS.join(", ")}.`
|
|
918
|
+
);
|
|
919
|
+
process.exitCode = 1;
|
|
920
|
+
return null;
|
|
921
|
+
}
|
|
922
|
+
return providers2;
|
|
923
|
+
}
|
|
924
|
+
if (options.all || !process.stdin.isTTY) return [...PROVIDERS];
|
|
925
|
+
return selectProviders([...PROVIDERS]);
|
|
926
|
+
};
|
|
927
|
+
selectProviders = async (initialValues) => {
|
|
928
|
+
const picked = await selectGrouped({
|
|
929
|
+
message: "Generate configs for (space toggles, enter confirms)",
|
|
930
|
+
groups: [
|
|
931
|
+
{
|
|
932
|
+
name: "providers",
|
|
933
|
+
items: [
|
|
934
|
+
{ value: "claude", label: "Claude Code" },
|
|
935
|
+
{ value: "opencode", label: "opencode" },
|
|
936
|
+
{ value: "codex", label: "Codex" }
|
|
937
|
+
]
|
|
938
|
+
}
|
|
939
|
+
],
|
|
940
|
+
initialValues
|
|
941
|
+
});
|
|
942
|
+
return picked.length ? picked : initialValues;
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
|
|
930
947
|
// src/providers/claude.ts
|
|
931
|
-
import { resolve as
|
|
948
|
+
import { resolve as resolve8 } from "path";
|
|
932
949
|
var formatMcpJson, planClaude;
|
|
933
950
|
var init_claude = __esm({
|
|
934
951
|
"src/providers/claude.ts"() {
|
|
@@ -943,33 +960,33 @@ var init_claude = __esm({
|
|
|
943
960
|
const removeFiles = [];
|
|
944
961
|
if (claudeSettings) {
|
|
945
962
|
files.push({
|
|
946
|
-
path:
|
|
963
|
+
path: resolve8(targetRoot, ".claude/settings.json"),
|
|
947
964
|
content: JSON.stringify(claudeSettings, null, 2) + "\n"
|
|
948
965
|
});
|
|
949
966
|
}
|
|
950
967
|
const mcp = formatMcpJson(mcpServers);
|
|
951
|
-
const mcpPath =
|
|
968
|
+
const mcpPath = resolve8(targetRoot, ".mcp.json");
|
|
952
969
|
if (mcp) files.push({ path: mcpPath, content: mcp });
|
|
953
970
|
else removeFiles.push(mcpPath);
|
|
954
971
|
const skillNames = selected.skills.map((s) => s.name);
|
|
955
972
|
const commandFiles = selected.commands.map((c) => `${c.name}.md`);
|
|
956
973
|
const symlinks = [
|
|
957
974
|
...selected.skills.map((s) => ({
|
|
958
|
-
path:
|
|
975
|
+
path: resolve8(targetRoot, ".claude/skills", s.name),
|
|
959
976
|
target: s.absDir
|
|
960
977
|
})),
|
|
961
978
|
...selected.commands.map((c) => ({
|
|
962
|
-
path:
|
|
979
|
+
path: resolve8(targetRoot, ".claude/commands", `${c.name}.md`),
|
|
963
980
|
target: c.absPath
|
|
964
981
|
}))
|
|
965
982
|
];
|
|
966
983
|
const managedDirs = [
|
|
967
984
|
{
|
|
968
|
-
path:
|
|
985
|
+
path: resolve8(targetRoot, ".claude/skills"),
|
|
969
986
|
expected: new Set(skillNames)
|
|
970
987
|
},
|
|
971
988
|
{
|
|
972
|
-
path:
|
|
989
|
+
path: resolve8(targetRoot, ".claude/commands"),
|
|
973
990
|
expected: new Set(commandFiles)
|
|
974
991
|
}
|
|
975
992
|
];
|
|
@@ -979,7 +996,7 @@ var init_claude = __esm({
|
|
|
979
996
|
});
|
|
980
997
|
|
|
981
998
|
// src/providers/codex.ts
|
|
982
|
-
import { resolve as
|
|
999
|
+
import { resolve as resolve9 } from "path";
|
|
983
1000
|
import TOML from "@iarna/toml";
|
|
984
1001
|
var buildConfig, planCodex;
|
|
985
1002
|
var init_codex = __esm({
|
|
@@ -1023,7 +1040,7 @@ var init_codex = __esm({
|
|
|
1023
1040
|
const files = [];
|
|
1024
1041
|
const removeFiles = [];
|
|
1025
1042
|
const config = buildConfig(rawMcpServers);
|
|
1026
|
-
const path =
|
|
1043
|
+
const path = resolve9(targetRoot, ".codex/config.toml");
|
|
1027
1044
|
if (config) {
|
|
1028
1045
|
files.push({
|
|
1029
1046
|
path,
|
|
@@ -1039,19 +1056,19 @@ var init_codex = __esm({
|
|
|
1039
1056
|
|
|
1040
1057
|
// src/providers/fsops.ts
|
|
1041
1058
|
import {
|
|
1042
|
-
existsSync as
|
|
1059
|
+
existsSync as existsSync7,
|
|
1043
1060
|
lstatSync,
|
|
1044
|
-
mkdirSync as
|
|
1061
|
+
mkdirSync as mkdirSync4,
|
|
1045
1062
|
readdirSync as readdirSync3,
|
|
1046
|
-
readFileSync as
|
|
1063
|
+
readFileSync as readFileSync5,
|
|
1047
1064
|
readlinkSync,
|
|
1048
1065
|
rmdirSync,
|
|
1049
|
-
rmSync as
|
|
1066
|
+
rmSync as rmSync3,
|
|
1050
1067
|
symlinkSync,
|
|
1051
1068
|
unlinkSync,
|
|
1052
|
-
writeFileSync as
|
|
1069
|
+
writeFileSync as writeFileSync3
|
|
1053
1070
|
} from "fs";
|
|
1054
|
-
import { dirname as dirname4, relative as relative4, resolve as
|
|
1071
|
+
import { dirname as dirname4, relative as relative4, resolve as resolve10 } from "path";
|
|
1055
1072
|
var isENOENT, isMatchingSymlink, removePath, applyOutputs, checkOutputs;
|
|
1056
1073
|
var init_fsops = __esm({
|
|
1057
1074
|
"src/providers/fsops.ts"() {
|
|
@@ -1060,7 +1077,7 @@ var init_fsops = __esm({
|
|
|
1060
1077
|
isMatchingSymlink = (path, target) => {
|
|
1061
1078
|
const stats = lstatSync(path);
|
|
1062
1079
|
if (!stats.isSymbolicLink()) return false;
|
|
1063
|
-
return
|
|
1080
|
+
return resolve10(dirname4(path), readlinkSync(path)) === target;
|
|
1064
1081
|
};
|
|
1065
1082
|
removePath = (path) => {
|
|
1066
1083
|
let stats;
|
|
@@ -1071,7 +1088,7 @@ var init_fsops = __esm({
|
|
|
1071
1088
|
throw e;
|
|
1072
1089
|
}
|
|
1073
1090
|
if (stats.isSymbolicLink()) unlinkSync(path);
|
|
1074
|
-
else
|
|
1091
|
+
else rmSync3(path, { force: true, recursive: true });
|
|
1075
1092
|
};
|
|
1076
1093
|
applyOutputs = ({
|
|
1077
1094
|
files,
|
|
@@ -1084,22 +1101,22 @@ var init_fsops = __esm({
|
|
|
1084
1101
|
for (const out of files) {
|
|
1085
1102
|
let current = null;
|
|
1086
1103
|
try {
|
|
1087
|
-
current =
|
|
1104
|
+
current = readFileSync5(out.path, "utf8");
|
|
1088
1105
|
} catch (e) {
|
|
1089
1106
|
if (!isENOENT(e)) throw e;
|
|
1090
1107
|
}
|
|
1091
1108
|
if (current === out.content) continue;
|
|
1092
|
-
|
|
1093
|
-
|
|
1109
|
+
mkdirSync4(dirname4(out.path), { recursive: true });
|
|
1110
|
+
writeFileSync3(out.path, out.content);
|
|
1094
1111
|
result.generated.push(out.path);
|
|
1095
1112
|
}
|
|
1096
1113
|
for (const path of removeFiles) {
|
|
1097
|
-
if (!
|
|
1098
|
-
|
|
1114
|
+
if (!existsSync7(path)) continue;
|
|
1115
|
+
rmSync3(path, { force: true });
|
|
1099
1116
|
result.removed.push(path);
|
|
1100
1117
|
}
|
|
1101
1118
|
for (const path of removeDirs) {
|
|
1102
|
-
if (!
|
|
1119
|
+
if (!existsSync7(path)) continue;
|
|
1103
1120
|
removePath(path);
|
|
1104
1121
|
result.removed.push(path);
|
|
1105
1122
|
}
|
|
@@ -1110,7 +1127,7 @@ var init_fsops = __esm({
|
|
|
1110
1127
|
}
|
|
1111
1128
|
}
|
|
1112
1129
|
for (const link of symlinks) {
|
|
1113
|
-
|
|
1130
|
+
mkdirSync4(dirname4(link.path), { recursive: true });
|
|
1114
1131
|
try {
|
|
1115
1132
|
if (isMatchingSymlink(link.path, link.target)) continue;
|
|
1116
1133
|
} catch (e) {
|
|
@@ -1125,10 +1142,10 @@ var init_fsops = __esm({
|
|
|
1125
1142
|
result.linked.push(link.path);
|
|
1126
1143
|
}
|
|
1127
1144
|
for (const dir of managedDirs) {
|
|
1128
|
-
if (!
|
|
1145
|
+
if (!existsSync7(dir.path)) continue;
|
|
1129
1146
|
for (const child of readdirSync3(dir.path)) {
|
|
1130
1147
|
if (dir.expected.has(child)) continue;
|
|
1131
|
-
const childPath =
|
|
1148
|
+
const childPath = resolve10(dir.path, child);
|
|
1132
1149
|
removePath(childPath);
|
|
1133
1150
|
result.removed.push(childPath);
|
|
1134
1151
|
}
|
|
@@ -1145,7 +1162,7 @@ var init_fsops = __esm({
|
|
|
1145
1162
|
const problems = [];
|
|
1146
1163
|
for (const out of files) {
|
|
1147
1164
|
try {
|
|
1148
|
-
if (
|
|
1165
|
+
if (readFileSync5(out.path, "utf8") !== out.content) {
|
|
1149
1166
|
problems.push(`out of sync: ${out.path}`);
|
|
1150
1167
|
}
|
|
1151
1168
|
} catch (e) {
|
|
@@ -1154,10 +1171,10 @@ var init_fsops = __esm({
|
|
|
1154
1171
|
}
|
|
1155
1172
|
}
|
|
1156
1173
|
for (const path of removeFiles) {
|
|
1157
|
-
if (
|
|
1174
|
+
if (existsSync7(path)) problems.push(`stale (should be removed): ${path}`);
|
|
1158
1175
|
}
|
|
1159
1176
|
for (const path of removeDirs) {
|
|
1160
|
-
if (
|
|
1177
|
+
if (existsSync7(path)) problems.push(`stale (should be removed): ${path}`);
|
|
1161
1178
|
}
|
|
1162
1179
|
for (const link of symlinks) {
|
|
1163
1180
|
try {
|
|
@@ -1170,10 +1187,10 @@ var init_fsops = __esm({
|
|
|
1170
1187
|
}
|
|
1171
1188
|
}
|
|
1172
1189
|
for (const dir of managedDirs) {
|
|
1173
|
-
if (!
|
|
1190
|
+
if (!existsSync7(dir.path)) continue;
|
|
1174
1191
|
for (const child of readdirSync3(dir.path)) {
|
|
1175
1192
|
if (!dir.expected.has(child)) {
|
|
1176
|
-
problems.push(`unexpected shim: ${
|
|
1193
|
+
problems.push(`unexpected shim: ${resolve10(dir.path, child)}`);
|
|
1177
1194
|
}
|
|
1178
1195
|
}
|
|
1179
1196
|
}
|
|
@@ -1183,61 +1200,111 @@ var init_fsops = __esm({
|
|
|
1183
1200
|
});
|
|
1184
1201
|
|
|
1185
1202
|
// src/providers/opencode.ts
|
|
1186
|
-
import {
|
|
1187
|
-
|
|
1203
|
+
import { existsSync as existsSync8 } from "fs";
|
|
1204
|
+
import { resolve as resolve11 } from "path";
|
|
1205
|
+
var formatOpenCodeJson, preserveEnvReference, preserveEnvReferences, planOpenCode;
|
|
1188
1206
|
var init_opencode = __esm({
|
|
1189
1207
|
"src/providers/opencode.ts"() {
|
|
1190
1208
|
"use strict";
|
|
1191
|
-
formatOpenCodeJson = (servers) => {
|
|
1192
|
-
if (Object.keys(servers).length === 0) return null;
|
|
1209
|
+
formatOpenCodeJson = (servers, overlay) => {
|
|
1210
|
+
if (Object.keys(servers).length === 0 && !overlay) return null;
|
|
1193
1211
|
const mcp = {};
|
|
1194
1212
|
for (const [name, server] of Object.entries(servers)) {
|
|
1195
1213
|
if (server.transport === "http") {
|
|
1196
1214
|
mcp[name] = {
|
|
1197
1215
|
type: "remote",
|
|
1198
|
-
url: server.url,
|
|
1199
|
-
...server.headers ? { headers: server.headers } : {}
|
|
1216
|
+
url: preserveEnvReference(server.url),
|
|
1217
|
+
...server.headers ? { headers: preserveEnvReferences(server.headers) } : {}
|
|
1200
1218
|
};
|
|
1201
1219
|
} else {
|
|
1202
1220
|
mcp[name] = {
|
|
1203
1221
|
type: "local",
|
|
1204
|
-
command: [server.command, ...server.args ?? []]
|
|
1205
|
-
|
|
1222
|
+
command: [server.command, ...server.args ?? []].map(
|
|
1223
|
+
preserveEnvReference
|
|
1224
|
+
),
|
|
1225
|
+
...server.env ? { environment: preserveEnvReferences(server.env) } : {}
|
|
1206
1226
|
};
|
|
1207
1227
|
}
|
|
1208
1228
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1229
|
+
const overlayMcp = overlay?.["mcp"] && typeof overlay["mcp"] === "object" ? overlay["mcp"] : {};
|
|
1230
|
+
const mergedMcp = { ...overlayMcp, ...mcp };
|
|
1231
|
+
const config = {
|
|
1232
|
+
...overlay,
|
|
1233
|
+
$schema: "https://opencode.ai/config.json",
|
|
1234
|
+
...Object.keys(mergedMcp).length ? { mcp: mergedMcp } : {}
|
|
1235
|
+
};
|
|
1236
|
+
return JSON.stringify(config, null, 2) + "\n";
|
|
1237
|
+
};
|
|
1238
|
+
preserveEnvReference = (value) => value.replace(/\$\{([^}]+)\}/g, "{env:$1}");
|
|
1239
|
+
preserveEnvReferences = (values) => Object.fromEntries(
|
|
1240
|
+
Object.entries(values).map(([key, value]) => [
|
|
1241
|
+
key,
|
|
1242
|
+
preserveEnvReference(value)
|
|
1243
|
+
])
|
|
1244
|
+
);
|
|
1215
1245
|
planOpenCode = (inputs) => {
|
|
1216
|
-
const {
|
|
1246
|
+
const {
|
|
1247
|
+
targetRoot,
|
|
1248
|
+
selected,
|
|
1249
|
+
rawMcpServers,
|
|
1250
|
+
opencodeConfig,
|
|
1251
|
+
tuiConfig
|
|
1252
|
+
} = inputs;
|
|
1217
1253
|
const files = [];
|
|
1218
1254
|
const removeFiles = [];
|
|
1219
|
-
const json = formatOpenCodeJson(
|
|
1220
|
-
const jsonPath =
|
|
1255
|
+
const json = formatOpenCodeJson(rawMcpServers, opencodeConfig);
|
|
1256
|
+
const jsonPath = resolve11(targetRoot, "opencode.json");
|
|
1221
1257
|
if (json) files.push({ path: jsonPath, content: json });
|
|
1222
1258
|
else removeFiles.push(jsonPath);
|
|
1259
|
+
const tuiPath = resolve11(targetRoot, ".opencode/tui.json");
|
|
1260
|
+
const tuiMarkerPath = resolve11(targetRoot, ".opencode/.quiver-tui");
|
|
1261
|
+
if (tuiConfig) {
|
|
1262
|
+
files.push({
|
|
1263
|
+
path: tuiPath,
|
|
1264
|
+
content: JSON.stringify(
|
|
1265
|
+
{ ...tuiConfig, $schema: "https://opencode.ai/tui.json" },
|
|
1266
|
+
null,
|
|
1267
|
+
2
|
|
1268
|
+
) + "\n"
|
|
1269
|
+
});
|
|
1270
|
+
files.push({ path: tuiMarkerPath, content: "managed by quiver\n" });
|
|
1271
|
+
} else if (existsSync8(tuiMarkerPath)) {
|
|
1272
|
+
removeFiles.push(tuiPath, tuiMarkerPath);
|
|
1273
|
+
}
|
|
1223
1274
|
const symlinks = [
|
|
1224
1275
|
...selected.skills.map((s) => ({
|
|
1225
|
-
path:
|
|
1276
|
+
path: resolve11(targetRoot, ".opencode/skills", s.name),
|
|
1226
1277
|
target: s.absDir
|
|
1227
1278
|
})),
|
|
1228
1279
|
...selected.commands.map((c) => ({
|
|
1229
|
-
path:
|
|
1280
|
+
path: resolve11(targetRoot, ".opencode/commands", `${c.name}.md`),
|
|
1230
1281
|
target: c.absPath
|
|
1282
|
+
})),
|
|
1283
|
+
...selected.plugins.map((plugin) => ({
|
|
1284
|
+
path: resolve11(
|
|
1285
|
+
targetRoot,
|
|
1286
|
+
".opencode/plugins",
|
|
1287
|
+
`${plugin.name}${plugin.absPath.endsWith(".js") ? ".js" : ".ts"}`
|
|
1288
|
+
),
|
|
1289
|
+
target: plugin.absPath
|
|
1231
1290
|
}))
|
|
1232
1291
|
];
|
|
1233
1292
|
const managedDirs = [
|
|
1234
1293
|
{
|
|
1235
|
-
path:
|
|
1294
|
+
path: resolve11(targetRoot, ".opencode/skills"),
|
|
1236
1295
|
expected: new Set(selected.skills.map((s) => s.name))
|
|
1237
1296
|
},
|
|
1238
1297
|
{
|
|
1239
|
-
path:
|
|
1298
|
+
path: resolve11(targetRoot, ".opencode/commands"),
|
|
1240
1299
|
expected: new Set(selected.commands.map((c) => `${c.name}.md`))
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
path: resolve11(targetRoot, ".opencode/plugins"),
|
|
1303
|
+
expected: new Set(
|
|
1304
|
+
selected.plugins.map(
|
|
1305
|
+
(plugin) => `${plugin.name}${plugin.absPath.endsWith(".js") ? ".js" : ".ts"}`
|
|
1306
|
+
)
|
|
1307
|
+
)
|
|
1241
1308
|
}
|
|
1242
1309
|
];
|
|
1243
1310
|
return { files, removeFiles, symlinks, managedDirs };
|
|
@@ -1255,17 +1322,20 @@ var init_selection = __esm({
|
|
|
1255
1322
|
const skillNames = /* @__PURE__ */ new Set();
|
|
1256
1323
|
const commandNames = /* @__PURE__ */ new Set();
|
|
1257
1324
|
const mcpNames = /* @__PURE__ */ new Set();
|
|
1325
|
+
const pluginNames = /* @__PURE__ */ new Set();
|
|
1258
1326
|
for (const id of Object.keys(lock.entries)) {
|
|
1259
1327
|
const parsed = parseEntryId(id);
|
|
1260
1328
|
if (!parsed) continue;
|
|
1261
1329
|
if (parsed.type === "skill") skillNames.add(parsed.name);
|
|
1262
1330
|
else if (parsed.type === "command") commandNames.add(parsed.name);
|
|
1263
1331
|
else if (parsed.type === "mcp") mcpNames.add(parsed.name);
|
|
1332
|
+
else if (parsed.type === "plugin") pluginNames.add(parsed.name);
|
|
1264
1333
|
}
|
|
1265
1334
|
return {
|
|
1266
1335
|
skills: catalog.skills.filter((s) => skillNames.has(s.name)),
|
|
1267
1336
|
commands: catalog.commands.filter((c) => commandNames.has(c.name)),
|
|
1268
|
-
mcp: catalog.mcp.filter((m) => mcpNames.has(m.name))
|
|
1337
|
+
mcp: catalog.mcp.filter((m) => mcpNames.has(m.name)),
|
|
1338
|
+
plugins: catalog.plugins.filter((p) => pluginNames.has(p.name))
|
|
1269
1339
|
};
|
|
1270
1340
|
};
|
|
1271
1341
|
}
|
|
@@ -1273,8 +1343,8 @@ var init_selection = __esm({
|
|
|
1273
1343
|
|
|
1274
1344
|
// src/providers/write.ts
|
|
1275
1345
|
import { existsSync as existsSync9, lstatSync as lstatSync2 } from "fs";
|
|
1276
|
-
import { basename, resolve as
|
|
1277
|
-
var isLinkable, buildPlan, writeProviders, checkProviders;
|
|
1346
|
+
import { basename, relative as relative5, resolve as resolve12 } from "path";
|
|
1347
|
+
var isLinkable, buildPlan, writeProviders, formatWriteResult, checkProviders;
|
|
1278
1348
|
var init_write = __esm({
|
|
1279
1349
|
"src/providers/write.ts"() {
|
|
1280
1350
|
"use strict";
|
|
@@ -1298,14 +1368,16 @@ var init_write = __esm({
|
|
|
1298
1368
|
const rawMcpServers = {};
|
|
1299
1369
|
for (const mcp of selected.mcp) rawMcpServers[mcp.name] = mcp.server;
|
|
1300
1370
|
const mcpServers = interpolateEnvVars(rawMcpServers, onMissingEnv);
|
|
1301
|
-
const agentsRoot =
|
|
1371
|
+
const agentsRoot = resolve12(targetRoot, ".agents");
|
|
1302
1372
|
const inputs = {
|
|
1303
1373
|
targetRoot,
|
|
1304
1374
|
agentsRoot,
|
|
1305
1375
|
selected,
|
|
1306
1376
|
mcpServers,
|
|
1307
1377
|
rawMcpServers,
|
|
1308
|
-
claudeSettings: catalog.config.claude?.settings ?? null
|
|
1378
|
+
claudeSettings: catalog.config.claude?.settings ?? null,
|
|
1379
|
+
opencodeConfig: catalog.config.opencode ?? null,
|
|
1380
|
+
tuiConfig: catalog.config.tui ?? null
|
|
1309
1381
|
};
|
|
1310
1382
|
const active = lock.providers?.length ? lock.providers : [...PROVIDERS];
|
|
1311
1383
|
const planByProvider = {
|
|
@@ -1329,12 +1401,12 @@ var init_write = __esm({
|
|
|
1329
1401
|
}
|
|
1330
1402
|
}
|
|
1331
1403
|
const rootSymlinks = [];
|
|
1332
|
-
const agentsMd =
|
|
1404
|
+
const agentsMd = resolve12(agentsRoot, "AGENTS.md");
|
|
1333
1405
|
if (existsSync9(agentsMd)) {
|
|
1334
|
-
const rootAgents =
|
|
1406
|
+
const rootAgents = resolve12(targetRoot, "AGENTS.md");
|
|
1335
1407
|
for (const link of [
|
|
1336
1408
|
{ path: rootAgents, target: agentsMd },
|
|
1337
|
-
{ path:
|
|
1409
|
+
{ path: resolve12(targetRoot, "CLAUDE.md"), target: rootAgents }
|
|
1338
1410
|
]) {
|
|
1339
1411
|
if (isLinkable(link.path)) rootSymlinks.push(link);
|
|
1340
1412
|
else onSkippedRootFile?.(basename(link.path));
|
|
@@ -1371,6 +1443,21 @@ var init_write = __esm({
|
|
|
1371
1443
|
}
|
|
1372
1444
|
return result;
|
|
1373
1445
|
};
|
|
1446
|
+
formatWriteResult = (targetRoot, result) => {
|
|
1447
|
+
const rel = (p) => relative5(targetRoot, p) || p;
|
|
1448
|
+
const lines = [];
|
|
1449
|
+
const groups = [
|
|
1450
|
+
["generated", result.generated],
|
|
1451
|
+
["linked", result.linked],
|
|
1452
|
+
["removed", result.removed]
|
|
1453
|
+
];
|
|
1454
|
+
for (const [label, paths] of groups) {
|
|
1455
|
+
if (!paths.length) continue;
|
|
1456
|
+
lines.push(` ${label}:`);
|
|
1457
|
+
for (const p of [...paths].map(rel).sort()) lines.push(` - ${p}`);
|
|
1458
|
+
}
|
|
1459
|
+
return lines;
|
|
1460
|
+
};
|
|
1374
1461
|
checkProviders = (targetRoot, catalog, lock) => {
|
|
1375
1462
|
const plan = buildPlan(targetRoot, catalog, lock, () => {
|
|
1376
1463
|
});
|
|
@@ -1381,8 +1468,8 @@ var init_write = __esm({
|
|
|
1381
1468
|
|
|
1382
1469
|
// src/commands/gitignore.ts
|
|
1383
1470
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
1384
|
-
import { existsSync as existsSync10, readFileSync as
|
|
1385
|
-
import { resolve as
|
|
1471
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
1472
|
+
import { resolve as resolve13 } from "path";
|
|
1386
1473
|
var HEADER, SECRETS_COMMENT, PROVIDER_ENTRIES, SHARED_ENTRIES, SECRET_ENTRIES, patchGitignore, ignoredSourcePaths;
|
|
1387
1474
|
var init_gitignore = __esm({
|
|
1388
1475
|
"src/commands/gitignore.ts"() {
|
|
@@ -1397,11 +1484,11 @@ var init_gitignore = __esm({
|
|
|
1397
1484
|
};
|
|
1398
1485
|
SHARED_ENTRIES = ["AGENTS.md", "CLAUDE.md"];
|
|
1399
1486
|
SECRET_ENTRIES = [".env.local"];
|
|
1400
|
-
patchGitignore = (targetRoot,
|
|
1401
|
-
const path =
|
|
1402
|
-
const current = existsSync10(path) ?
|
|
1487
|
+
patchGitignore = (targetRoot, providers2) => {
|
|
1488
|
+
const path = resolve13(targetRoot, ".gitignore");
|
|
1489
|
+
const current = existsSync10(path) ? readFileSync6(path, "utf8") : "";
|
|
1403
1490
|
const lines = new Set(current.split("\n").map((l) => l.trim()));
|
|
1404
|
-
const active =
|
|
1491
|
+
const active = providers2?.length ? providers2 : [...PROVIDERS];
|
|
1405
1492
|
const shimEntries = [
|
|
1406
1493
|
...active.flatMap((p) => PROVIDER_ENTRIES[p]),
|
|
1407
1494
|
...SHARED_ENTRIES
|
|
@@ -1413,7 +1500,7 @@ var init_gitignore = __esm({
|
|
|
1413
1500
|
if (missingShims.length) block2.push(HEADER, ...missingShims);
|
|
1414
1501
|
if (missingSecrets.length) block2.push(SECRETS_COMMENT, ...missingSecrets);
|
|
1415
1502
|
const prefix = current && !current.endsWith("\n") ? "\n" : "";
|
|
1416
|
-
|
|
1503
|
+
writeFileSync4(
|
|
1417
1504
|
path,
|
|
1418
1505
|
current + prefix + (current ? "\n" : "") + block2.join("\n") + "\n"
|
|
1419
1506
|
);
|
|
@@ -1458,12 +1545,24 @@ var init_select = __esm({
|
|
|
1458
1545
|
const s = entry.server;
|
|
1459
1546
|
return s.transport === "http" ? s.url : [s.command, ...s.args ?? []].filter(Boolean).join(" ");
|
|
1460
1547
|
};
|
|
1461
|
-
selectFromCatalog = async (catalog, {
|
|
1548
|
+
selectFromCatalog = async (catalog, {
|
|
1549
|
+
interactive,
|
|
1550
|
+
providers: providers2
|
|
1551
|
+
}) => {
|
|
1462
1552
|
const allSkills = catalog.skills.map((s) => s.name);
|
|
1463
1553
|
const allCommands = catalog.commands.map((c) => c.name);
|
|
1464
1554
|
const allMcp = catalog.mcp.map((m) => m.name);
|
|
1555
|
+
const availablePlugins = catalog.plugins.filter(
|
|
1556
|
+
(plugin) => providers2.includes(plugin.provider)
|
|
1557
|
+
);
|
|
1558
|
+
const allPlugins = availablePlugins.map((p) => p.name);
|
|
1465
1559
|
if (!interactive || !process.stdin.isTTY) {
|
|
1466
|
-
return {
|
|
1560
|
+
return {
|
|
1561
|
+
skills: allSkills,
|
|
1562
|
+
commands: allCommands,
|
|
1563
|
+
mcp: allMcp,
|
|
1564
|
+
plugins: allPlugins
|
|
1565
|
+
};
|
|
1467
1566
|
}
|
|
1468
1567
|
const groupNames = [...new Set(catalog.skills.map((s) => s.group))].sort(
|
|
1469
1568
|
(a, b) => a === "general" ? -1 : b === "general" ? 1 : a.localeCompare(b)
|
|
@@ -1518,7 +1617,21 @@ var init_select = __esm({
|
|
|
1518
1617
|
groups: mcpGroups,
|
|
1519
1618
|
initialValues: []
|
|
1520
1619
|
}) : [];
|
|
1521
|
-
|
|
1620
|
+
const plugins = availablePlugins.length ? await selectGrouped({
|
|
1621
|
+
message: "Select plugins (space toggles, a all, enter confirms)",
|
|
1622
|
+
groups: [
|
|
1623
|
+
{
|
|
1624
|
+
name: "opencode",
|
|
1625
|
+
items: availablePlugins.map((plugin) => ({
|
|
1626
|
+
value: plugin.name,
|
|
1627
|
+
label: plugin.name,
|
|
1628
|
+
hint: plugin.requires.length ? `requires: ${plugin.requires.join(", ")}` : void 0
|
|
1629
|
+
}))
|
|
1630
|
+
}
|
|
1631
|
+
],
|
|
1632
|
+
initialValues: []
|
|
1633
|
+
}) : [];
|
|
1634
|
+
return { skills, commands, mcp, plugins };
|
|
1522
1635
|
};
|
|
1523
1636
|
}
|
|
1524
1637
|
});
|
|
@@ -1528,7 +1641,7 @@ var init_exports = {};
|
|
|
1528
1641
|
__export(init_exports, {
|
|
1529
1642
|
init: () => init
|
|
1530
1643
|
});
|
|
1531
|
-
var init
|
|
1644
|
+
var init;
|
|
1532
1645
|
var init_init = __esm({
|
|
1533
1646
|
"src/commands/init.ts"() {
|
|
1534
1647
|
"use strict";
|
|
@@ -1538,6 +1651,7 @@ var init_init = __esm({
|
|
|
1538
1651
|
init_resolve();
|
|
1539
1652
|
init_io();
|
|
1540
1653
|
init_schema();
|
|
1654
|
+
init_resolve2();
|
|
1541
1655
|
init_write();
|
|
1542
1656
|
init_interpolate();
|
|
1543
1657
|
init_prompts();
|
|
@@ -1559,11 +1673,12 @@ var init_init = __esm({
|
|
|
1559
1673
|
);
|
|
1560
1674
|
}
|
|
1561
1675
|
const sourceCatalog = loadCatalog(source);
|
|
1676
|
+
const providers2 = await resolveProviders(options);
|
|
1677
|
+
if (providers2 === null) return;
|
|
1562
1678
|
const selection = await selectFromCatalog(sourceCatalog, {
|
|
1563
|
-
interactive: !options.all
|
|
1679
|
+
interactive: !options.all,
|
|
1680
|
+
providers: providers2
|
|
1564
1681
|
});
|
|
1565
|
-
const providers = await resolveProviders(options);
|
|
1566
|
-
if (providers === null) return;
|
|
1567
1682
|
const resolved = materializeCatalog(
|
|
1568
1683
|
options.targetRoot,
|
|
1569
1684
|
source,
|
|
@@ -1575,7 +1690,7 @@ var init_init = __esm({
|
|
|
1575
1690
|
ref: source.ref ?? null,
|
|
1576
1691
|
resolved: source.resolved ?? null
|
|
1577
1692
|
});
|
|
1578
|
-
lock.providers =
|
|
1693
|
+
lock.providers = providers2;
|
|
1579
1694
|
for (const skill of catalog.skills) {
|
|
1580
1695
|
if (selection.skills.includes(skill.name)) {
|
|
1581
1696
|
lock.entries[entryId("skill", skill.name)] = skillToEntry(skill);
|
|
@@ -1591,9 +1706,14 @@ var init_init = __esm({
|
|
|
1591
1706
|
lock.entries[entryId("mcp", mcp.name)] = mcpToEntry(mcp);
|
|
1592
1707
|
}
|
|
1593
1708
|
}
|
|
1709
|
+
for (const plugin of catalog.plugins) {
|
|
1710
|
+
if (selection.plugins.includes(plugin.name)) {
|
|
1711
|
+
lock.entries[entryId("plugin", plugin.name)] = pluginToEntry(plugin);
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1594
1714
|
writeLockfile(options.targetRoot, lock);
|
|
1595
1715
|
await step(
|
|
1596
|
-
`Wrote quiver.lock (${selection.skills.length} skills, ${selection.commands.length} commands, ${selection.mcp.length} MCP servers)`
|
|
1716
|
+
`Wrote quiver.lock (${selection.skills.length} skills, ${selection.commands.length} commands, ${selection.mcp.length} MCP servers, ${selection.plugins.length} plugins)`
|
|
1597
1717
|
);
|
|
1598
1718
|
const result = writeProviders(options.targetRoot, catalog, lock);
|
|
1599
1719
|
if (result.generated.length || result.linked.length) {
|
|
@@ -1601,7 +1721,7 @@ var init_init = __esm({
|
|
|
1601
1721
|
`Provider configs: ${result.generated.length} generated, ${result.linked.length} linked`
|
|
1602
1722
|
);
|
|
1603
1723
|
}
|
|
1604
|
-
if (patchGitignore(options.targetRoot,
|
|
1724
|
+
if (patchGitignore(options.targetRoot, providers2)) {
|
|
1605
1725
|
await step("Updated .gitignore (generated shims + .env.local ignored)");
|
|
1606
1726
|
}
|
|
1607
1727
|
const ignored = ignoredSourcePaths(options.targetRoot);
|
|
@@ -1623,47 +1743,18 @@ var init_init = __esm({
|
|
|
1623
1743
|
"Done. Commit .agents/ and quiver.lock; restart your AI tool to load the config."
|
|
1624
1744
|
);
|
|
1625
1745
|
};
|
|
1626
|
-
resolveProviders = async (options) => {
|
|
1627
|
-
if (options.providers) {
|
|
1628
|
-
const invalid = options.providers.filter((p) => !isProvider(p));
|
|
1629
|
-
if (invalid.length) {
|
|
1630
|
-
await error(
|
|
1631
|
-
`Unknown provider(s): ${invalid.join(", ")}. Valid: ${PROVIDERS.join(", ")}.`
|
|
1632
|
-
);
|
|
1633
|
-
process.exitCode = 1;
|
|
1634
|
-
return null;
|
|
1635
|
-
}
|
|
1636
|
-
return options.providers.filter(isProvider);
|
|
1637
|
-
}
|
|
1638
|
-
if (options.all || !process.stdin.isTTY) return [...PROVIDERS];
|
|
1639
|
-
const picked = await selectGrouped({
|
|
1640
|
-
message: "Generate configs for (space toggles, enter confirms)",
|
|
1641
|
-
groups: [
|
|
1642
|
-
{
|
|
1643
|
-
name: "providers",
|
|
1644
|
-
items: [
|
|
1645
|
-
{ value: "claude", label: "Claude Code" },
|
|
1646
|
-
{ value: "opencode", label: "opencode" },
|
|
1647
|
-
{ value: "codex", label: "Codex" }
|
|
1648
|
-
]
|
|
1649
|
-
}
|
|
1650
|
-
],
|
|
1651
|
-
initialValues: [...PROVIDERS]
|
|
1652
|
-
});
|
|
1653
|
-
return picked.length ? picked : [...PROVIDERS];
|
|
1654
|
-
};
|
|
1655
1746
|
}
|
|
1656
1747
|
});
|
|
1657
1748
|
|
|
1658
1749
|
// src/catalog/repo.ts
|
|
1659
1750
|
import { existsSync as existsSync11 } from "fs";
|
|
1660
|
-
import { resolve as
|
|
1751
|
+
import { resolve as resolve14 } from "path";
|
|
1661
1752
|
var repoCatalogRoot, repoCatalogExists, loadRepoCatalog;
|
|
1662
1753
|
var init_repo = __esm({
|
|
1663
1754
|
"src/catalog/repo.ts"() {
|
|
1664
1755
|
"use strict";
|
|
1665
1756
|
init_discover();
|
|
1666
|
-
repoCatalogRoot = (targetRoot) =>
|
|
1757
|
+
repoCatalogRoot = (targetRoot) => resolve14(targetRoot, ".agents");
|
|
1667
1758
|
repoCatalogExists = (targetRoot) => existsSync11(repoCatalogRoot(targetRoot));
|
|
1668
1759
|
loadRepoCatalog = (targetRoot, source) => {
|
|
1669
1760
|
const resolved = {
|
|
@@ -1696,13 +1787,17 @@ var init_add = __esm({
|
|
|
1696
1787
|
add = async (options) => {
|
|
1697
1788
|
const id = options.positionals[0];
|
|
1698
1789
|
if (!id) {
|
|
1699
|
-
await error(
|
|
1790
|
+
await error(
|
|
1791
|
+
"Usage: quiver-cli add <skill:name|command:name|mcp:name|plugin:name>"
|
|
1792
|
+
);
|
|
1700
1793
|
process.exitCode = 1;
|
|
1701
1794
|
return;
|
|
1702
1795
|
}
|
|
1703
1796
|
const parsed = parseEntryId(id);
|
|
1704
1797
|
if (!parsed) {
|
|
1705
|
-
await error(
|
|
1798
|
+
await error(
|
|
1799
|
+
`Invalid id "${id}". Expected skill:<name>, command:<name>, mcp:<name> or plugin:<name>.`
|
|
1800
|
+
);
|
|
1706
1801
|
process.exitCode = 1;
|
|
1707
1802
|
return;
|
|
1708
1803
|
}
|
|
@@ -1723,16 +1818,25 @@ var init_add = __esm({
|
|
|
1723
1818
|
const skill = sourceCatalog.skills.find((s) => s.name === parsed.name);
|
|
1724
1819
|
const command = sourceCatalog.commands.find((c) => c.name === parsed.name);
|
|
1725
1820
|
const mcp = sourceCatalog.mcp.find((m) => m.name === parsed.name);
|
|
1726
|
-
const
|
|
1821
|
+
const plugin = sourceCatalog.plugins.find((p) => p.name === parsed.name);
|
|
1822
|
+
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;
|
|
1727
1823
|
if (!entry) {
|
|
1728
1824
|
await error(`${id} not found in catalog.`);
|
|
1729
1825
|
process.exitCode = 1;
|
|
1730
1826
|
return;
|
|
1731
1827
|
}
|
|
1828
|
+
if (entry.type === "plugin" && lock.providers?.length && !lock.providers.includes(entry.provider)) {
|
|
1829
|
+
await error(
|
|
1830
|
+
`${id} requires the ${entry.provider} provider. Enable it with \`quiver-cli providers ${entry.provider}\` first.`
|
|
1831
|
+
);
|
|
1832
|
+
process.exitCode = 1;
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1732
1835
|
const selection = selectionFromLock(lock);
|
|
1733
1836
|
if (parsed.type === "skill") selection.skills.push(parsed.name);
|
|
1734
1837
|
if (parsed.type === "command") selection.commands.push(parsed.name);
|
|
1735
1838
|
if (parsed.type === "mcp") selection.mcp.push(parsed.name);
|
|
1839
|
+
if (parsed.type === "plugin") selection.plugins.push(parsed.name);
|
|
1736
1840
|
materializeCatalog(options.targetRoot, source, sourceCatalog, selection);
|
|
1737
1841
|
lock.entries[id] = entry;
|
|
1738
1842
|
writeLockfile(options.targetRoot, lock);
|
|
@@ -1741,13 +1845,19 @@ var init_add = __esm({
|
|
|
1741
1845
|
await success(`Added ${id}.`);
|
|
1742
1846
|
};
|
|
1743
1847
|
selectionFromLock = (lock) => {
|
|
1744
|
-
const selection = {
|
|
1848
|
+
const selection = {
|
|
1849
|
+
skills: [],
|
|
1850
|
+
commands: [],
|
|
1851
|
+
mcp: [],
|
|
1852
|
+
plugins: []
|
|
1853
|
+
};
|
|
1745
1854
|
for (const lid of Object.keys(lock.entries)) {
|
|
1746
1855
|
const p = parseEntryId(lid);
|
|
1747
1856
|
if (!p) continue;
|
|
1748
1857
|
if (p.type === "skill") selection.skills.push(p.name);
|
|
1749
1858
|
else if (p.type === "command") selection.commands.push(p.name);
|
|
1750
1859
|
else if (p.type === "mcp") selection.mcp.push(p.name);
|
|
1860
|
+
else if (p.type === "plugin") selection.plugins.push(p.name);
|
|
1751
1861
|
}
|
|
1752
1862
|
return selection;
|
|
1753
1863
|
};
|
|
@@ -1759,9 +1869,9 @@ var remove_exports = {};
|
|
|
1759
1869
|
__export(remove_exports, {
|
|
1760
1870
|
remove: () => remove
|
|
1761
1871
|
});
|
|
1762
|
-
import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as
|
|
1763
|
-
import { resolve as
|
|
1764
|
-
var remove, cleanupEmptyGroups, rewriteRepoMcp;
|
|
1872
|
+
import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync7, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
1873
|
+
import { resolve as resolve15 } from "path";
|
|
1874
|
+
var remove, rewriteRepoPlugins, cleanupEmptyGroups, rewriteRepoMcp;
|
|
1765
1875
|
var init_remove = __esm({
|
|
1766
1876
|
"src/commands/remove.ts"() {
|
|
1767
1877
|
"use strict";
|
|
@@ -1774,7 +1884,9 @@ var init_remove = __esm({
|
|
|
1774
1884
|
remove = async (options) => {
|
|
1775
1885
|
const id = options.positionals[0];
|
|
1776
1886
|
if (!id) {
|
|
1777
|
-
await error(
|
|
1887
|
+
await error(
|
|
1888
|
+
"Usage: quiver remove <skill:name|command:name|mcp:name|plugin:name>"
|
|
1889
|
+
);
|
|
1778
1890
|
process.exitCode = 1;
|
|
1779
1891
|
return;
|
|
1780
1892
|
}
|
|
@@ -1795,31 +1907,46 @@ var init_remove = __esm({
|
|
|
1795
1907
|
await info(`${id} is not installed.`);
|
|
1796
1908
|
return;
|
|
1797
1909
|
}
|
|
1798
|
-
if (entry.type === "skill" || entry.type === "command") {
|
|
1910
|
+
if (entry.type === "skill" || entry.type === "command" || entry.type === "plugin") {
|
|
1799
1911
|
removeArtifact(options.targetRoot, entry.sourcePath);
|
|
1800
1912
|
cleanupEmptyGroups(options.targetRoot);
|
|
1801
1913
|
}
|
|
1802
1914
|
delete lock.entries[id];
|
|
1803
1915
|
writeLockfile(options.targetRoot, lock);
|
|
1804
1916
|
rewriteRepoMcp(options.targetRoot, lock);
|
|
1917
|
+
rewriteRepoPlugins(options.targetRoot, lock);
|
|
1805
1918
|
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
1806
1919
|
writeProviders(options.targetRoot, catalog, lock);
|
|
1807
1920
|
await success(`Removed ${id}.`);
|
|
1808
1921
|
};
|
|
1922
|
+
rewriteRepoPlugins = (targetRoot, lock) => {
|
|
1923
|
+
const configPath = resolve15(targetRoot, ".agents/config.json");
|
|
1924
|
+
if (!existsSync12(configPath)) return;
|
|
1925
|
+
const config = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
1926
|
+
if (!config.plugins) return;
|
|
1927
|
+
const keep = new Set(
|
|
1928
|
+
Object.keys(lock.entries).map(parseEntryId).filter((p) => p?.type === "plugin").map((p) => p.name)
|
|
1929
|
+
);
|
|
1930
|
+
config.plugins = Object.fromEntries(
|
|
1931
|
+
Object.entries(config.plugins).filter(([name]) => keep.has(name))
|
|
1932
|
+
);
|
|
1933
|
+
if (!Object.keys(config.plugins).length) delete config.plugins;
|
|
1934
|
+
writeFileSync5(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1935
|
+
};
|
|
1809
1936
|
cleanupEmptyGroups = (targetRoot) => {
|
|
1810
|
-
const skillsRoot =
|
|
1937
|
+
const skillsRoot = resolve15(targetRoot, ".agents/skills");
|
|
1811
1938
|
if (!existsSync12(skillsRoot)) return;
|
|
1812
1939
|
for (const entry of readdirSync4(skillsRoot, { withFileTypes: true })) {
|
|
1813
1940
|
if (!entry.isDirectory()) continue;
|
|
1814
|
-
const dir =
|
|
1815
|
-
if (existsSync12(
|
|
1816
|
-
if (readdirSync4(dir).length === 0)
|
|
1941
|
+
const dir = resolve15(skillsRoot, entry.name);
|
|
1942
|
+
if (existsSync12(resolve15(dir, "SKILL.md"))) continue;
|
|
1943
|
+
if (readdirSync4(dir).length === 0) rmSync4(dir, { recursive: true, force: true });
|
|
1817
1944
|
}
|
|
1818
1945
|
};
|
|
1819
1946
|
rewriteRepoMcp = (targetRoot, lock) => {
|
|
1820
|
-
const configPath =
|
|
1947
|
+
const configPath = resolve15(targetRoot, ".agents/config.json");
|
|
1821
1948
|
if (!existsSync12(configPath)) return;
|
|
1822
|
-
const config = JSON.parse(
|
|
1949
|
+
const config = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
1823
1950
|
if (!config.mcpServers) return;
|
|
1824
1951
|
const keep = new Set(
|
|
1825
1952
|
Object.keys(lock.entries).map(parseEntryId).filter((p) => p?.type === "mcp").map((p) => p.name)
|
|
@@ -1830,7 +1957,7 @@ var init_remove = __esm({
|
|
|
1830
1957
|
}
|
|
1831
1958
|
if (Object.keys(kept).length) config.mcpServers = kept;
|
|
1832
1959
|
else delete config.mcpServers;
|
|
1833
|
-
|
|
1960
|
+
writeFileSync5(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1834
1961
|
};
|
|
1835
1962
|
}
|
|
1836
1963
|
});
|
|
@@ -1845,6 +1972,7 @@ var init_locksync = __esm({
|
|
|
1845
1972
|
const skillByName = new Map(catalog.skills.map((s) => [s.name, s]));
|
|
1846
1973
|
const commandByName = new Map(catalog.commands.map((c) => [c.name, c]));
|
|
1847
1974
|
const mcpByName = new Map(catalog.mcp.map((m) => [m.name, m]));
|
|
1975
|
+
const pluginByName = new Map(catalog.plugins.map((p) => [p.name, p]));
|
|
1848
1976
|
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
1849
1977
|
if (entry.type === "skill") {
|
|
1850
1978
|
const cat = skillByName.get(id.slice("skill:".length));
|
|
@@ -1869,6 +1997,15 @@ var init_locksync = __esm({
|
|
|
1869
1997
|
entry.configDigest = cat.configDigest;
|
|
1870
1998
|
entry.transport = cat.server.transport;
|
|
1871
1999
|
}
|
|
2000
|
+
} else if (entry.type === "plugin") {
|
|
2001
|
+
const cat = pluginByName.get(id.slice("plugin:".length));
|
|
2002
|
+
if (!cat) continue;
|
|
2003
|
+
if (cat.digest !== entry.digest) {
|
|
2004
|
+
drift.push(`${id}: plugin content changed`);
|
|
2005
|
+
entry.digest = cat.digest;
|
|
2006
|
+
entry.sourcePath = cat.sourcePath;
|
|
2007
|
+
entry.requires = cat.requires;
|
|
2008
|
+
}
|
|
1872
2009
|
}
|
|
1873
2010
|
}
|
|
1874
2011
|
return drift;
|
|
@@ -1888,6 +2025,7 @@ var init_sync = __esm({
|
|
|
1888
2025
|
init_repo();
|
|
1889
2026
|
init_io();
|
|
1890
2027
|
init_schema();
|
|
2028
|
+
init_resolve2();
|
|
1891
2029
|
init_write();
|
|
1892
2030
|
init_prompts();
|
|
1893
2031
|
init_gitignore();
|
|
@@ -1904,15 +2042,33 @@ var init_sync = __esm({
|
|
|
1904
2042
|
process.exitCode = 1;
|
|
1905
2043
|
return;
|
|
1906
2044
|
}
|
|
2045
|
+
if (options.providers) {
|
|
2046
|
+
const { providers: valid, invalid } = validateProviders(options.providers);
|
|
2047
|
+
if (invalid) {
|
|
2048
|
+
await error(
|
|
2049
|
+
`Unknown provider(s): ${invalid.join(", ")}. Valid: ${PROVIDERS.join(", ")}.`
|
|
2050
|
+
);
|
|
2051
|
+
process.exitCode = 1;
|
|
2052
|
+
return;
|
|
2053
|
+
}
|
|
2054
|
+
if (!valid.length) {
|
|
2055
|
+
await error("At least one provider is required.");
|
|
2056
|
+
process.exitCode = 1;
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
lock.providers = valid;
|
|
2060
|
+
await step(`Providers set to: ${valid.join(", ")}`);
|
|
2061
|
+
}
|
|
1907
2062
|
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
1908
2063
|
const haveSkills = new Set(catalog.skills.map((s) => s.name));
|
|
1909
2064
|
const haveCommands = new Set(catalog.commands.map((c) => c.name));
|
|
1910
2065
|
const haveMcp = new Set(catalog.mcp.map((m) => m.name));
|
|
2066
|
+
const havePlugins = new Set(catalog.plugins.map((p) => p.name));
|
|
1911
2067
|
const orphans = [];
|
|
1912
2068
|
for (const id of Object.keys(lock.entries)) {
|
|
1913
2069
|
const p = parseEntryId(id);
|
|
1914
2070
|
if (!p) continue;
|
|
1915
|
-
const present = p.type === "skill" && haveSkills.has(p.name) || p.type === "command" && haveCommands.has(p.name) || p.type === "mcp" && haveMcp.has(p.name);
|
|
2071
|
+
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);
|
|
1916
2072
|
if (!present) orphans.push(id);
|
|
1917
2073
|
}
|
|
1918
2074
|
if (orphans.length) {
|
|
@@ -1936,6 +2092,79 @@ var init_sync = __esm({
|
|
|
1936
2092
|
await success(
|
|
1937
2093
|
`Synced: ${result.generated.length} generated, ${result.linked.length} linked, ${result.removed.length} removed`
|
|
1938
2094
|
);
|
|
2095
|
+
const detail = formatWriteResult(options.targetRoot, result);
|
|
2096
|
+
if (detail.length) block(detail);
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2101
|
+
// src/commands/providers.ts
|
|
2102
|
+
var providers_exports = {};
|
|
2103
|
+
__export(providers_exports, {
|
|
2104
|
+
providers: () => providers
|
|
2105
|
+
});
|
|
2106
|
+
var providers;
|
|
2107
|
+
var init_providers = __esm({
|
|
2108
|
+
"src/commands/providers.ts"() {
|
|
2109
|
+
"use strict";
|
|
2110
|
+
init_repo();
|
|
2111
|
+
init_io();
|
|
2112
|
+
init_schema();
|
|
2113
|
+
init_resolve2();
|
|
2114
|
+
init_write();
|
|
2115
|
+
init_prompts();
|
|
2116
|
+
providers = async (options) => {
|
|
2117
|
+
const lock = readLockfile(options.targetRoot);
|
|
2118
|
+
if (!lock) {
|
|
2119
|
+
await error("No quiver.lock found. Run `quiver-cli init` first.");
|
|
2120
|
+
process.exitCode = 1;
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
if (!repoCatalogExists(options.targetRoot)) {
|
|
2124
|
+
await error("No .agents/ directory found. Run `quiver-cli init` first.");
|
|
2125
|
+
process.exitCode = 1;
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
const current = lock.providers?.length ? lock.providers : [...PROVIDERS];
|
|
2129
|
+
const explicit = options.providers ?? (options.positionals[0] ? options.positionals[0].split(",").map((p) => p.trim()).filter(Boolean) : null);
|
|
2130
|
+
let next;
|
|
2131
|
+
if (explicit) {
|
|
2132
|
+
const { providers: valid, invalid } = validateProviders(explicit);
|
|
2133
|
+
if (invalid) {
|
|
2134
|
+
await error(
|
|
2135
|
+
`Unknown provider(s): ${invalid.join(", ")}. Valid: ${PROVIDERS.join(", ")}.`
|
|
2136
|
+
);
|
|
2137
|
+
process.exitCode = 1;
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
next = valid;
|
|
2141
|
+
} else if (process.stdin.isTTY && !options.all) {
|
|
2142
|
+
next = await selectProviders(current);
|
|
2143
|
+
} else {
|
|
2144
|
+
await error(
|
|
2145
|
+
`No providers given. Usage: quiver-cli providers <${PROVIDERS.join(",")}>`
|
|
2146
|
+
);
|
|
2147
|
+
process.exitCode = 1;
|
|
2148
|
+
return;
|
|
2149
|
+
}
|
|
2150
|
+
if (!next.length) {
|
|
2151
|
+
await error("At least one provider is required.");
|
|
2152
|
+
process.exitCode = 1;
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
if (sameProviders(next, current)) {
|
|
2156
|
+
await info(`Providers already set to: ${current.join(", ")}.`);
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
lock.providers = next;
|
|
2160
|
+
writeLockfile(options.targetRoot, lock);
|
|
2161
|
+
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
2162
|
+
const result = writeProviders(options.targetRoot, catalog, lock);
|
|
2163
|
+
await success(
|
|
2164
|
+
`Providers set to ${next.join(", ")}: ${result.generated.length} generated, ${result.linked.length} linked, ${result.removed.length} removed`
|
|
2165
|
+
);
|
|
2166
|
+
const detail = formatWriteResult(options.targetRoot, result);
|
|
2167
|
+
if (detail.length) block(detail);
|
|
1939
2168
|
};
|
|
1940
2169
|
}
|
|
1941
2170
|
});
|
|
@@ -1945,8 +2174,8 @@ var update_exports = {};
|
|
|
1945
2174
|
__export(update_exports, {
|
|
1946
2175
|
update: () => update
|
|
1947
2176
|
});
|
|
1948
|
-
import { cpSync as cpSync2, mkdirSync as
|
|
1949
|
-
import { dirname as dirname5, resolve as
|
|
2177
|
+
import { cpSync as cpSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync8, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
2178
|
+
import { dirname as dirname5, resolve as resolve16 } from "path";
|
|
1950
2179
|
var update, applyUpdate, report;
|
|
1951
2180
|
var init_update = __esm({
|
|
1952
2181
|
"src/commands/update.ts"() {
|
|
@@ -2002,21 +2231,27 @@ var init_update = __esm({
|
|
|
2002
2231
|
sourceCatalog,
|
|
2003
2232
|
repoCatalog,
|
|
2004
2233
|
lock,
|
|
2005
|
-
options.force
|
|
2234
|
+
options.force,
|
|
2235
|
+
options.dryRun
|
|
2006
2236
|
);
|
|
2007
2237
|
if (report4.status === "updated") changed = true;
|
|
2008
2238
|
reports.push(report4);
|
|
2009
2239
|
}
|
|
2010
|
-
if (
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2240
|
+
if (!options.dryRun) {
|
|
2241
|
+
if (changed || catalogMoved) {
|
|
2242
|
+
writeLockfile(options.targetRoot, lock);
|
|
2243
|
+
}
|
|
2244
|
+
if (changed) {
|
|
2245
|
+
const { catalog } = loadRepoCatalog(
|
|
2246
|
+
options.targetRoot,
|
|
2247
|
+
lock.catalog.source
|
|
2248
|
+
);
|
|
2249
|
+
writeProviders(options.targetRoot, catalog, lock);
|
|
2250
|
+
}
|
|
2016
2251
|
}
|
|
2017
2252
|
report(reports, options);
|
|
2018
2253
|
};
|
|
2019
|
-
applyUpdate = (targetRoot, parsed, entry, sourceCatalog, repoCatalog, lock, force) => {
|
|
2254
|
+
applyUpdate = (targetRoot, parsed, entry, sourceCatalog, repoCatalog, lock, force, dryRun) => {
|
|
2020
2255
|
const id = `${parsed.type}:${parsed.name}`;
|
|
2021
2256
|
if (entry.type === "skill") {
|
|
2022
2257
|
const src2 = sourceCatalog.skills.find((s) => s.name === parsed.name);
|
|
@@ -2026,9 +2261,10 @@ var init_update = __esm({
|
|
|
2026
2261
|
if (repo2 && repo2.digest !== entry.digest && !force) {
|
|
2027
2262
|
return { id, status: "local-changes" };
|
|
2028
2263
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2264
|
+
if (dryRun) return { id, status: "updated" };
|
|
2265
|
+
const dest = resolve16(targetRoot, ".agents", src2.sourcePath);
|
|
2266
|
+
rmSync5(dest, { recursive: true, force: true });
|
|
2267
|
+
mkdirSync5(dirname5(dest), { recursive: true });
|
|
2032
2268
|
cpSync2(src2.absDir, dest, { recursive: true });
|
|
2033
2269
|
entry.digest = src2.digest;
|
|
2034
2270
|
entry.frontmatter = src2.frontmatter;
|
|
@@ -2043,13 +2279,38 @@ var init_update = __esm({
|
|
|
2043
2279
|
if (repo2 && repo2.digest !== entry.digest && !force) {
|
|
2044
2280
|
return { id, status: "local-changes" };
|
|
2045
2281
|
}
|
|
2046
|
-
|
|
2047
|
-
|
|
2282
|
+
if (dryRun) return { id, status: "updated" };
|
|
2283
|
+
const dest = resolve16(targetRoot, ".agents", src2.sourcePath);
|
|
2284
|
+
mkdirSync5(dirname5(dest), { recursive: true });
|
|
2048
2285
|
cpSync2(src2.absPath, dest, { force: true });
|
|
2049
2286
|
entry.digest = src2.digest;
|
|
2050
2287
|
entry.sourcePath = src2.sourcePath;
|
|
2051
2288
|
return { id, status: "updated" };
|
|
2052
2289
|
}
|
|
2290
|
+
if (entry.type === "plugin") {
|
|
2291
|
+
const src2 = sourceCatalog.plugins.find((p) => p.name === parsed.name);
|
|
2292
|
+
if (!src2) return { id, status: "not-in-catalog" };
|
|
2293
|
+
if (src2.digest === entry.digest) return { id, status: "up-to-date" };
|
|
2294
|
+
const repo2 = repoCatalog.plugins.find((p) => p.name === parsed.name);
|
|
2295
|
+
if (repo2 && repo2.digest !== entry.digest && !force) {
|
|
2296
|
+
return { id, status: "local-changes" };
|
|
2297
|
+
}
|
|
2298
|
+
if (dryRun) return { id, status: "updated" };
|
|
2299
|
+
const dest = resolve16(targetRoot, ".agents", src2.sourcePath);
|
|
2300
|
+
mkdirSync5(dirname5(dest), { recursive: true });
|
|
2301
|
+
cpSync2(src2.absPath, dest, { force: true });
|
|
2302
|
+
const configPath2 = resolve16(targetRoot, ".agents/config.json");
|
|
2303
|
+
const config2 = JSON.parse(readFileSync8(configPath2, "utf8"));
|
|
2304
|
+
config2.plugins = {
|
|
2305
|
+
...config2.plugins,
|
|
2306
|
+
[parsed.name]: sourceCatalog.config.plugins?.[parsed.name]
|
|
2307
|
+
};
|
|
2308
|
+
writeFileSync6(configPath2, JSON.stringify(config2, null, 2) + "\n");
|
|
2309
|
+
entry.digest = src2.digest;
|
|
2310
|
+
entry.sourcePath = src2.sourcePath;
|
|
2311
|
+
entry.requires = src2.requires;
|
|
2312
|
+
return { id, status: "updated" };
|
|
2313
|
+
}
|
|
2053
2314
|
const src = sourceCatalog.mcp.find((m) => m.name === parsed.name);
|
|
2054
2315
|
if (!src) return { id, status: "not-in-catalog" };
|
|
2055
2316
|
if (src.configDigest === entry.configDigest) return { id, status: "up-to-date" };
|
|
@@ -2057,10 +2318,11 @@ var init_update = __esm({
|
|
|
2057
2318
|
if (repo && repo.configDigest !== entry.configDigest && !force) {
|
|
2058
2319
|
return { id, status: "local-changes" };
|
|
2059
2320
|
}
|
|
2060
|
-
|
|
2061
|
-
const
|
|
2321
|
+
if (dryRun) return { id, status: "updated" };
|
|
2322
|
+
const configPath = resolve16(targetRoot, ".agents", "config.json");
|
|
2323
|
+
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
2062
2324
|
config.mcpServers = { ...config.mcpServers, [parsed.name]: src.server };
|
|
2063
|
-
|
|
2325
|
+
writeFileSync6(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
2064
2326
|
entry.configDigest = src.configDigest;
|
|
2065
2327
|
entry.transport = src.server.transport;
|
|
2066
2328
|
entry.tools = null;
|
|
@@ -2074,6 +2336,7 @@ var init_update = __esm({
|
|
|
2074
2336
|
JSON.stringify(
|
|
2075
2337
|
{
|
|
2076
2338
|
ok: true,
|
|
2339
|
+
dryRun: options.dryRun,
|
|
2077
2340
|
updated: by("updated").map((r) => r.id),
|
|
2078
2341
|
upToDate: by("up-to-date").map((r) => r.id),
|
|
2079
2342
|
localChanges: by("local-changes").map((r) => r.id),
|
|
@@ -2087,7 +2350,8 @@ var init_update = __esm({
|
|
|
2087
2350
|
}
|
|
2088
2351
|
const c = palette();
|
|
2089
2352
|
const lines = [""];
|
|
2090
|
-
|
|
2353
|
+
const verb = options.dryRun ? "would update" : "updated";
|
|
2354
|
+
for (const r of by("updated")) lines.push(` ${c.cyan("\u2191")} ${r.id} ${verb}`);
|
|
2091
2355
|
for (const r of by("local-changes"))
|
|
2092
2356
|
lines.push(
|
|
2093
2357
|
` ${c.yellow("\u25B2")} ${r.id} ${c.yellow("local changes - skipped (use --force)")}`
|
|
@@ -2099,7 +2363,11 @@ var init_update = __esm({
|
|
|
2099
2363
|
const updated = by("updated").length;
|
|
2100
2364
|
lines.push(
|
|
2101
2365
|
"",
|
|
2102
|
-
` ${updated ?
|
|
2366
|
+
` ${updated ? options.dryRun ? c.cyan(
|
|
2367
|
+
`\u2191 ${updated} would be updated - run without --dry-run to apply`
|
|
2368
|
+
) : c.cyan(
|
|
2369
|
+
`\u2191 ${updated} updated - review and commit .agents/ + quiver.lock`
|
|
2370
|
+
) : c.green("\u2713 everything up to date with the catalog")}`,
|
|
2103
2371
|
""
|
|
2104
2372
|
);
|
|
2105
2373
|
block(lines);
|
|
@@ -2147,14 +2415,16 @@ var init_list = __esm({
|
|
|
2147
2415
|
const skills = [];
|
|
2148
2416
|
const commands = [];
|
|
2149
2417
|
const mcp = [];
|
|
2418
|
+
const plugins = [];
|
|
2150
2419
|
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
2151
2420
|
const p = parseEntryId(id);
|
|
2152
2421
|
if (!p) continue;
|
|
2153
2422
|
if (entry.type === "skill") skills.push({ name: p.name, entry });
|
|
2154
2423
|
else if (entry.type === "command") commands.push({ name: p.name, entry });
|
|
2155
2424
|
else if (entry.type === "mcp") mcp.push({ name: p.name, entry });
|
|
2425
|
+
else if (entry.type === "plugin") plugins.push({ name: p.name, entry });
|
|
2156
2426
|
}
|
|
2157
|
-
for (const group of [skills, commands, mcp]) {
|
|
2427
|
+
for (const group of [skills, commands, mcp, plugins]) {
|
|
2158
2428
|
group.sort((a, b) => a.name.localeCompare(b.name));
|
|
2159
2429
|
}
|
|
2160
2430
|
if (options.json) {
|
|
@@ -2173,6 +2443,11 @@ var init_list = __esm({
|
|
|
2173
2443
|
transport: entry.transport,
|
|
2174
2444
|
detail: serverDetail2.get(name) ?? null,
|
|
2175
2445
|
toolCount: entry.tools ? Object.keys(entry.tools).length : null
|
|
2446
|
+
})),
|
|
2447
|
+
plugins: plugins.map(({ name, entry }) => ({
|
|
2448
|
+
name,
|
|
2449
|
+
provider: entry.provider,
|
|
2450
|
+
requires: entry.requires
|
|
2176
2451
|
}))
|
|
2177
2452
|
},
|
|
2178
2453
|
null,
|
|
@@ -2230,12 +2505,19 @@ var init_list = __esm({
|
|
|
2230
2505
|
);
|
|
2231
2506
|
}
|
|
2232
2507
|
}
|
|
2233
|
-
|
|
2508
|
+
if (plugins.length) {
|
|
2509
|
+
lines.push("", ` ${c.bold("plugins")}`);
|
|
2510
|
+
for (const { name, entry } of plugins) {
|
|
2511
|
+
const requires = entry.requires.length ? ` ${c.dim(`requires: ${entry.requires.join(", ")}`)}` : "";
|
|
2512
|
+
lines.push(` ${name} ${c.dim(entry.provider)}${requires}`);
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
const providers2 = lock.providers?.length ? lock.providers.join(", ") : "claude, opencode, codex";
|
|
2234
2516
|
lines.push(
|
|
2235
2517
|
"",
|
|
2236
2518
|
` ${c.bold(
|
|
2237
|
-
`${skills.length} skills \xB7 ${commands.length} commands \xB7 ${mcp.length} MCP servers`
|
|
2238
|
-
)} ${c.dim(`providers: ${
|
|
2519
|
+
`${skills.length} skills \xB7 ${commands.length} commands \xB7 ${mcp.length} MCP servers \xB7 ${plugins.length} plugins`
|
|
2520
|
+
)} ${c.dim(`providers: ${providers2}`)}`
|
|
2239
2521
|
);
|
|
2240
2522
|
if (missingTools) {
|
|
2241
2523
|
lines.push(` ${c.dim("run 'quiver-cli check' to populate tool counts")}`);
|
|
@@ -2246,84 +2528,6 @@ var init_list = __esm({
|
|
|
2246
2528
|
}
|
|
2247
2529
|
});
|
|
2248
2530
|
|
|
2249
|
-
// src/commands/status.ts
|
|
2250
|
-
var status_exports = {};
|
|
2251
|
-
__export(status_exports, {
|
|
2252
|
-
status: () => status
|
|
2253
|
-
});
|
|
2254
|
-
var status;
|
|
2255
|
-
var init_status = __esm({
|
|
2256
|
-
"src/commands/status.ts"() {
|
|
2257
|
-
"use strict";
|
|
2258
|
-
init_repo();
|
|
2259
|
-
init_io();
|
|
2260
|
-
init_schema();
|
|
2261
|
-
init_write();
|
|
2262
|
-
init_prompts();
|
|
2263
|
-
status = async (options) => {
|
|
2264
|
-
const lock = readLockfile(options.targetRoot);
|
|
2265
|
-
if (!lock) {
|
|
2266
|
-
if (options.json) console.log(JSON.stringify({ ok: false, error: "no-lockfile" }));
|
|
2267
|
-
else await error("No quiver.lock found. Run `quiver-cli init` first.");
|
|
2268
|
-
process.exitCode = 1;
|
|
2269
|
-
return;
|
|
2270
|
-
}
|
|
2271
|
-
if (!repoCatalogExists(options.targetRoot)) {
|
|
2272
|
-
if (options.json) console.log(JSON.stringify({ ok: false, error: "no-agents" }));
|
|
2273
|
-
else await error("No .agents/ directory found. Run `quiver-cli init` first.");
|
|
2274
|
-
process.exitCode = 1;
|
|
2275
|
-
return;
|
|
2276
|
-
}
|
|
2277
|
-
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
2278
|
-
const haveSkills = new Set(catalog.skills.map((s) => s.name));
|
|
2279
|
-
const haveCommands = new Set(catalog.commands.map((c) => c.name));
|
|
2280
|
-
const haveMcp = new Set(catalog.mcp.map((m) => m.name));
|
|
2281
|
-
const missing = [];
|
|
2282
|
-
const changed = [];
|
|
2283
|
-
const skillByName = new Map(catalog.skills.map((s) => [s.name, s]));
|
|
2284
|
-
const commandByName = new Map(catalog.commands.map((c) => [c.name, c]));
|
|
2285
|
-
const mcpByName = new Map(catalog.mcp.map((m) => [m.name, m]));
|
|
2286
|
-
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
2287
|
-
const p = parseEntryId(id);
|
|
2288
|
-
if (!p) continue;
|
|
2289
|
-
if (p.type === "skill") {
|
|
2290
|
-
if (!haveSkills.has(p.name)) missing.push(id);
|
|
2291
|
-
else if (entry.type === "skill" && skillByName.get(p.name).digest !== entry.digest)
|
|
2292
|
-
changed.push(id);
|
|
2293
|
-
} else if (p.type === "command") {
|
|
2294
|
-
if (!haveCommands.has(p.name)) missing.push(id);
|
|
2295
|
-
else if (entry.type === "command" && commandByName.get(p.name).digest !== entry.digest)
|
|
2296
|
-
changed.push(id);
|
|
2297
|
-
} else if (p.type === "mcp") {
|
|
2298
|
-
if (!haveMcp.has(p.name)) missing.push(id);
|
|
2299
|
-
else if (entry.type === "mcp" && mcpByName.get(p.name).configDigest !== entry.configDigest)
|
|
2300
|
-
changed.push(id);
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
const shimProblems = checkProviders(options.targetRoot, catalog, lock);
|
|
2304
|
-
const ok = missing.length === 0 && changed.length === 0 && shimProblems.length === 0;
|
|
2305
|
-
if (options.json) {
|
|
2306
|
-
console.log(JSON.stringify({ ok, missing, changed, shims: shimProblems }, null, 2));
|
|
2307
|
-
if (!ok) process.exitCode = 1;
|
|
2308
|
-
return;
|
|
2309
|
-
}
|
|
2310
|
-
if (ok) {
|
|
2311
|
-
await success("In sync: lockfile, .agents/ and provider shims agree.");
|
|
2312
|
-
return;
|
|
2313
|
-
}
|
|
2314
|
-
if (missing.length)
|
|
2315
|
-
await warn(`Missing in .agents/: ${missing.join(", ")}`);
|
|
2316
|
-
if (changed.length)
|
|
2317
|
-
await warn(`Content changed since lockfile: ${changed.join(", ")}`);
|
|
2318
|
-
if (shimProblems.length)
|
|
2319
|
-
await warn(`Provider shims out of date:
|
|
2320
|
-
- ${shimProblems.join("\n - ")}`);
|
|
2321
|
-
await info("Run `quiver-cli sync` to regenerate provider shims and refresh digests.");
|
|
2322
|
-
process.exitCode = 1;
|
|
2323
|
-
};
|
|
2324
|
-
}
|
|
2325
|
-
});
|
|
2326
|
-
|
|
2327
2531
|
// src/mcp/diff.ts
|
|
2328
2532
|
var diffSnapshots, isEmptyDiff;
|
|
2329
2533
|
var init_diff = __esm({
|
|
@@ -2458,9 +2662,12 @@ var init_snapshot = __esm({
|
|
|
2458
2662
|
var check_exports = {};
|
|
2459
2663
|
__export(check_exports, {
|
|
2460
2664
|
check: () => check,
|
|
2665
|
+
hasCommand: () => hasCommand,
|
|
2461
2666
|
summarize: () => summarize
|
|
2462
2667
|
});
|
|
2463
|
-
|
|
2668
|
+
import { accessSync as accessSync2, constants as constants2 } from "fs";
|
|
2669
|
+
import { delimiter, resolve as resolve17 } from "path";
|
|
2670
|
+
var check, report2, driftLines, list2, recommend, summarize, hasCommand, truncate2, fail;
|
|
2464
2671
|
var init_check = __esm({
|
|
2465
2672
|
"src/commands/check.ts"() {
|
|
2466
2673
|
"use strict";
|
|
@@ -2470,6 +2677,7 @@ var init_check = __esm({
|
|
|
2470
2677
|
init_diff();
|
|
2471
2678
|
init_introspect();
|
|
2472
2679
|
init_snapshot();
|
|
2680
|
+
init_write();
|
|
2473
2681
|
init_interpolate();
|
|
2474
2682
|
init_prompts();
|
|
2475
2683
|
check = async (options) => {
|
|
@@ -2484,8 +2692,10 @@ var init_check = __esm({
|
|
|
2484
2692
|
const { catalog } = loadRepoCatalog(options.targetRoot, lock.catalog.source);
|
|
2485
2693
|
const skillByName = new Map(catalog.skills.map((s) => [s.name, s]));
|
|
2486
2694
|
const commandByName = new Map(catalog.commands.map((c) => [c.name, c]));
|
|
2695
|
+
const pluginByName = new Map(catalog.plugins.map((p) => [p.name, p]));
|
|
2487
2696
|
const skillDrift = [];
|
|
2488
|
-
const
|
|
2697
|
+
const pluginRequirements = [];
|
|
2698
|
+
const checked = { skills: 0, commands: 0, mcp: 0, plugins: 0 };
|
|
2489
2699
|
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
2490
2700
|
const p = parseEntryId(id);
|
|
2491
2701
|
if (!p) continue;
|
|
@@ -2499,11 +2709,24 @@ var init_check = __esm({
|
|
|
2499
2709
|
if (!cat) continue;
|
|
2500
2710
|
checked.commands += 1;
|
|
2501
2711
|
if (cat.digest !== entry.digest) skillDrift.push({ id, kind: "content" });
|
|
2712
|
+
} else if (entry.type === "plugin") {
|
|
2713
|
+
const cat = pluginByName.get(p.name);
|
|
2714
|
+
if (!cat) continue;
|
|
2715
|
+
checked.plugins += 1;
|
|
2716
|
+
if (cat.digest !== entry.digest) skillDrift.push({ id, kind: "content" });
|
|
2717
|
+
if (lock.providers?.length && !lock.providers.includes(entry.provider)) {
|
|
2718
|
+
continue;
|
|
2719
|
+
}
|
|
2720
|
+
for (const command of entry.requires) {
|
|
2721
|
+
if (!hasCommand(command)) pluginRequirements.push({ id, command });
|
|
2722
|
+
}
|
|
2502
2723
|
}
|
|
2503
2724
|
}
|
|
2725
|
+
const shimProblems = checkProviders(options.targetRoot, catalog, lock);
|
|
2504
2726
|
const mcpReports = [];
|
|
2505
2727
|
let lockChanged = false;
|
|
2506
2728
|
for (const [id, entry] of Object.entries(lock.entries)) {
|
|
2729
|
+
if (options.offline) break;
|
|
2507
2730
|
if (entry.type !== "mcp") continue;
|
|
2508
2731
|
const p = parseEntryId(id);
|
|
2509
2732
|
const catMcp = catalog.mcp.find((m) => m.name === p.name);
|
|
@@ -2537,11 +2760,18 @@ var init_check = __esm({
|
|
|
2537
2760
|
}
|
|
2538
2761
|
}
|
|
2539
2762
|
if (lockChanged) writeLockfile(options.targetRoot, lock);
|
|
2540
|
-
const hasDrift = skillDrift.length > 0 || mcpReports.some((r) => r.status === "drift");
|
|
2763
|
+
const hasDrift = skillDrift.length > 0 || pluginRequirements.length > 0 || shimProblems.length > 0 || mcpReports.some((r) => r.status === "drift");
|
|
2541
2764
|
if (options.json) {
|
|
2542
2765
|
console.log(
|
|
2543
2766
|
JSON.stringify(
|
|
2544
|
-
{
|
|
2767
|
+
{
|
|
2768
|
+
ok: !hasDrift,
|
|
2769
|
+
checked,
|
|
2770
|
+
skillDrift,
|
|
2771
|
+
pluginRequirements,
|
|
2772
|
+
shims: shimProblems,
|
|
2773
|
+
mcp: mcpReports
|
|
2774
|
+
},
|
|
2545
2775
|
null,
|
|
2546
2776
|
2
|
|
2547
2777
|
)
|
|
@@ -2549,16 +2779,35 @@ var init_check = __esm({
|
|
|
2549
2779
|
if (hasDrift) process.exitCode = 1;
|
|
2550
2780
|
return;
|
|
2551
2781
|
}
|
|
2552
|
-
await report2(
|
|
2782
|
+
await report2(
|
|
2783
|
+
skillDrift,
|
|
2784
|
+
pluginRequirements,
|
|
2785
|
+
shimProblems,
|
|
2786
|
+
mcpReports,
|
|
2787
|
+
checked,
|
|
2788
|
+
options
|
|
2789
|
+
);
|
|
2553
2790
|
if (hasDrift) process.exitCode = 1;
|
|
2554
2791
|
};
|
|
2555
|
-
report2 = async (skillDrift, mcpReports, checked, options) => {
|
|
2792
|
+
report2 = async (skillDrift, pluginRequirements, shimProblems, mcpReports, checked, options) => {
|
|
2556
2793
|
if (skillDrift.length) {
|
|
2557
2794
|
await warn(
|
|
2558
|
-
`
|
|
2795
|
+
`Managed content changed since lockfile:
|
|
2559
2796
|
- ${skillDrift.map((s) => s.id).join("\n - ")}`
|
|
2560
2797
|
);
|
|
2561
2798
|
}
|
|
2799
|
+
if (pluginRequirements.length) {
|
|
2800
|
+
await warn(
|
|
2801
|
+
`Plugin requirements missing:
|
|
2802
|
+
- ${pluginRequirements.map((issue) => `${issue.id}: ${issue.command}`).join("\n - ")}`
|
|
2803
|
+
);
|
|
2804
|
+
}
|
|
2805
|
+
if (shimProblems.length) {
|
|
2806
|
+
await warn(
|
|
2807
|
+
`Provider shims out of date:
|
|
2808
|
+
- ${shimProblems.join("\n - ")}`
|
|
2809
|
+
);
|
|
2810
|
+
}
|
|
2562
2811
|
const skipped = mcpReports.filter((r) => r.status === "skipped");
|
|
2563
2812
|
if (skipped.length) {
|
|
2564
2813
|
const names = skipped.map((r) => parseEntryId(r.id)?.name ?? r.id);
|
|
@@ -2583,12 +2832,13 @@ var init_check = __esm({
|
|
|
2583
2832
|
- ${driftLines(r.diff, options.verbose).join("\n - ")}`);
|
|
2584
2833
|
}
|
|
2585
2834
|
const summary = summarize(checked);
|
|
2586
|
-
const hasDrift = skillDrift.length > 0 || drifted.length > 0;
|
|
2587
|
-
|
|
2835
|
+
const hasDrift = skillDrift.length > 0 || shimProblems.length > 0 || drifted.length > 0;
|
|
2836
|
+
const hasProblems = hasDrift || pluginRequirements.length > 0;
|
|
2837
|
+
if (!hasProblems) {
|
|
2588
2838
|
await success(`check passed: ${summary}, no drift detected.`);
|
|
2589
2839
|
} else {
|
|
2590
2840
|
await info(`checked ${summary}, drift detected.`);
|
|
2591
|
-
await recommend(skillDrift, drifted);
|
|
2841
|
+
await recommend(skillDrift, shimProblems, drifted);
|
|
2592
2842
|
}
|
|
2593
2843
|
};
|
|
2594
2844
|
driftLines = (diff, verbose) => {
|
|
@@ -2622,9 +2872,12 @@ var init_check = __esm({
|
|
|
2622
2872
|
const rest = names.length - sample;
|
|
2623
2873
|
return `${names.length} tools (${names.slice(0, sample).join(", ")}, \u2026 +${rest} more)`;
|
|
2624
2874
|
};
|
|
2625
|
-
recommend = async (skillDrift, drifted) => {
|
|
2875
|
+
recommend = async (skillDrift, shimProblems, drifted) => {
|
|
2626
2876
|
const c = palette();
|
|
2627
2877
|
const lines = ["to update the lockfile baseline:"];
|
|
2878
|
+
if (shimProblems.length) {
|
|
2879
|
+
lines.push(` ${c.cyan("quiver-cli sync")} regenerate provider shims`);
|
|
2880
|
+
}
|
|
2628
2881
|
if (drifted.length) {
|
|
2629
2882
|
lines.push(` ${c.cyan("quiver-cli check --accept")} accept the new MCP tool snapshots`);
|
|
2630
2883
|
}
|
|
@@ -2646,8 +2899,23 @@ var init_check = __esm({
|
|
|
2646
2899
|
if (c.skills) parts.push(plural(c.skills, "skill"));
|
|
2647
2900
|
if (c.commands) parts.push(plural(c.commands, "command"));
|
|
2648
2901
|
if (c.mcp) parts.push(plural(c.mcp, "MCP server"));
|
|
2902
|
+
if (c.plugins) parts.push(plural(c.plugins, "plugin"));
|
|
2649
2903
|
return parts.length ? parts.join(", ") : "nothing";
|
|
2650
2904
|
};
|
|
2905
|
+
hasCommand = (command) => {
|
|
2906
|
+
if (!/^[A-Za-z0-9._-]+$/.test(command)) return false;
|
|
2907
|
+
const extensions = process.platform === "win32" ? (process.env["PATHEXT"] ?? ".EXE;.CMD;.BAT;.COM").split(";") : [""];
|
|
2908
|
+
for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
|
|
2909
|
+
for (const extension of extensions) {
|
|
2910
|
+
try {
|
|
2911
|
+
accessSync2(resolve17(dir, command + extension), constants2.X_OK);
|
|
2912
|
+
return true;
|
|
2913
|
+
} catch {
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
return false;
|
|
2918
|
+
};
|
|
2651
2919
|
truncate2 = (s, max = 120) => s.length > max ? s.slice(0, max) + "\u2026" : s;
|
|
2652
2920
|
fail = async (options, code, message) => {
|
|
2653
2921
|
if (options.json) console.log(JSON.stringify({ ok: false, error: code }));
|
|
@@ -2662,9 +2930,9 @@ import { execFileSync as execFileSync3 } from "child_process";
|
|
|
2662
2930
|
import {
|
|
2663
2931
|
existsSync as existsSync13,
|
|
2664
2932
|
mkdtempSync as mkdtempSync2,
|
|
2665
|
-
readFileSync as
|
|
2666
|
-
rmSync as
|
|
2667
|
-
writeFileSync as
|
|
2933
|
+
readFileSync as readFileSync9,
|
|
2934
|
+
rmSync as rmSync6,
|
|
2935
|
+
writeFileSync as writeFileSync7
|
|
2668
2936
|
} from "fs";
|
|
2669
2937
|
import { tmpdir } from "os";
|
|
2670
2938
|
import { join, resolve as resolve18 } from "path";
|
|
@@ -2679,10 +2947,10 @@ var init_upstreams = __esm({
|
|
|
2679
2947
|
loadUpstreams = (catalog) => {
|
|
2680
2948
|
const path = upstreamsPath(catalog);
|
|
2681
2949
|
if (!existsSync13(path)) return {};
|
|
2682
|
-
return JSON.parse(
|
|
2950
|
+
return JSON.parse(readFileSync9(path, "utf8"));
|
|
2683
2951
|
};
|
|
2684
2952
|
writeUpstreams = (catalog, map) => {
|
|
2685
|
-
|
|
2953
|
+
writeFileSync7(upstreamsPath(catalog), JSON.stringify(map, null, 2) + "\n");
|
|
2686
2954
|
};
|
|
2687
2955
|
fetchLatestCommit = async (origin) => {
|
|
2688
2956
|
const url = `https://api.github.com/repos/${origin.repo}/commits?path=${encodeURIComponent(origin.path)}&sha=${encodeURIComponent(origin.ref)}&per_page=1`;
|
|
@@ -2721,7 +2989,7 @@ var init_upstreams = __esm({
|
|
|
2721
2989
|
};
|
|
2722
2990
|
fetchUpstreamDir = (origin) => {
|
|
2723
2991
|
const tmp = mkdtempSync2(join(tmpdir(), "quiver-pull-"));
|
|
2724
|
-
const cleanup = () =>
|
|
2992
|
+
const cleanup = () => rmSync6(tmp, { recursive: true, force: true });
|
|
2725
2993
|
const git = (args, cwd) => {
|
|
2726
2994
|
execFileSync3("git", args, {
|
|
2727
2995
|
cwd,
|
|
@@ -2796,7 +3064,7 @@ var upstream_exports = {};
|
|
|
2796
3064
|
__export(upstream_exports, {
|
|
2797
3065
|
upstream: () => upstream
|
|
2798
3066
|
});
|
|
2799
|
-
import { cpSync as cpSync3, rmSync as
|
|
3067
|
+
import { cpSync as cpSync3, rmSync as rmSync7 } from "fs";
|
|
2800
3068
|
var upstream, guardWritableCatalog, STATUS_ORDER, pull, report3, countByStatus;
|
|
2801
3069
|
var init_upstream = __esm({
|
|
2802
3070
|
"src/commands/upstream.ts"() {
|
|
@@ -2848,7 +3116,7 @@ var init_upstream = __esm({
|
|
|
2848
3116
|
guardWritableCatalog = async (catalog) => {
|
|
2849
3117
|
if (isCatalogWritable(catalog)) return false;
|
|
2850
3118
|
await error(
|
|
2851
|
-
"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
|
|
3119
|
+
"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."
|
|
2852
3120
|
);
|
|
2853
3121
|
process.exitCode = 1;
|
|
2854
3122
|
return true;
|
|
@@ -2906,7 +3174,7 @@ var init_upstream = __esm({
|
|
|
2906
3174
|
continue;
|
|
2907
3175
|
}
|
|
2908
3176
|
try {
|
|
2909
|
-
|
|
3177
|
+
rmSync7(skill.absDir, { recursive: true, force: true });
|
|
2910
3178
|
cpSync3(fetched.dir, skill.absDir, { recursive: true, dereference: true });
|
|
2911
3179
|
} finally {
|
|
2912
3180
|
fetched.cleanup();
|
|
@@ -2980,14 +3248,23 @@ var init_upstream = __esm({
|
|
|
2980
3248
|
lines.push(` ${mark[r.status]} ${c.bold(name)} ${detail} ${where}`);
|
|
2981
3249
|
}
|
|
2982
3250
|
block(lines);
|
|
2983
|
-
const drifted = sorted.filter(
|
|
2984
|
-
|
|
2985
|
-
)
|
|
2986
|
-
if (drifted.length) {
|
|
3251
|
+
const drifted = sorted.filter((r) => r.status === "drift");
|
|
3252
|
+
const curated = sorted.filter((r) => r.status === "drift-curated");
|
|
3253
|
+
if (drifted.length || curated.length) {
|
|
2987
3254
|
const hint = [""];
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
3255
|
+
if (drifted.length) {
|
|
3256
|
+
hint.push(
|
|
3257
|
+
` ${c.cyan("quiver-cli upstream pull")} ${c.dim(
|
|
3258
|
+
`update the catalog copy (${drifted.map((r) => r.name).join(", ")})`
|
|
3259
|
+
)}`
|
|
3260
|
+
);
|
|
3261
|
+
}
|
|
3262
|
+
for (const r of curated) {
|
|
3263
|
+
hint.push(
|
|
3264
|
+
` ${c.yellow(r.name)}: ${c.dim(
|
|
3265
|
+
"curated \u2014 reconcile by hand, or upstream pull --force"
|
|
3266
|
+
)}`
|
|
3267
|
+
);
|
|
2991
3268
|
}
|
|
2992
3269
|
block(hint);
|
|
2993
3270
|
}
|
|
@@ -3023,83 +3300,6 @@ var init_upstream = __esm({
|
|
|
3023
3300
|
}
|
|
3024
3301
|
});
|
|
3025
3302
|
|
|
3026
|
-
// src/commands/login.ts
|
|
3027
|
-
var login_exports = {};
|
|
3028
|
-
__export(login_exports, {
|
|
3029
|
-
login: () => login
|
|
3030
|
-
});
|
|
3031
|
-
import process3 from "process";
|
|
3032
|
-
var login, promptToken, readStdin;
|
|
3033
|
-
var init_login = __esm({
|
|
3034
|
-
"src/commands/login.ts"() {
|
|
3035
|
-
"use strict";
|
|
3036
|
-
init_auth();
|
|
3037
|
-
init_prompts();
|
|
3038
|
-
login = async (options) => {
|
|
3039
|
-
const token = process3.stdin.isTTY ? await promptToken() : await readStdin();
|
|
3040
|
-
if (!token) {
|
|
3041
|
-
await error(
|
|
3042
|
-
"No token provided. Create a GitHub personal access token with `repo` read access and try again."
|
|
3043
|
-
);
|
|
3044
|
-
process3.exitCode = 1;
|
|
3045
|
-
return;
|
|
3046
|
-
}
|
|
3047
|
-
const validation = await validateToken(token);
|
|
3048
|
-
if (!validation.ok) {
|
|
3049
|
-
await error(`Token validation failed: ${validation.reason}`);
|
|
3050
|
-
process3.exitCode = 1;
|
|
3051
|
-
return;
|
|
3052
|
-
}
|
|
3053
|
-
writeStoredToken(token, validation.login);
|
|
3054
|
-
if (options.json) {
|
|
3055
|
-
console.log(JSON.stringify({ ok: true, login: validation.login }, null, 2));
|
|
3056
|
-
return;
|
|
3057
|
-
}
|
|
3058
|
-
await success(
|
|
3059
|
-
`Logged in as ${validation.login}. Token stored in ${authFilePath()}.`
|
|
3060
|
-
);
|
|
3061
|
-
};
|
|
3062
|
-
promptToken = async () => {
|
|
3063
|
-
await info(
|
|
3064
|
-
"Paste a GitHub personal access token (used for github: catalogs; needs read access to the catalog repo)."
|
|
3065
|
-
);
|
|
3066
|
-
const value = await password("GitHub token");
|
|
3067
|
-
return value?.trim() || null;
|
|
3068
|
-
};
|
|
3069
|
-
readStdin = async () => {
|
|
3070
|
-
let data = "";
|
|
3071
|
-
for await (const chunk of process3.stdin) data += chunk;
|
|
3072
|
-
return data.trim() || null;
|
|
3073
|
-
};
|
|
3074
|
-
}
|
|
3075
|
-
});
|
|
3076
|
-
|
|
3077
|
-
// src/commands/logout.ts
|
|
3078
|
-
var logout_exports = {};
|
|
3079
|
-
__export(logout_exports, {
|
|
3080
|
-
logout: () => logout
|
|
3081
|
-
});
|
|
3082
|
-
var logout;
|
|
3083
|
-
var init_logout = __esm({
|
|
3084
|
-
"src/commands/logout.ts"() {
|
|
3085
|
-
"use strict";
|
|
3086
|
-
init_auth();
|
|
3087
|
-
init_prompts();
|
|
3088
|
-
logout = async (options) => {
|
|
3089
|
-
const removed = deleteStoredToken();
|
|
3090
|
-
if (options.json) {
|
|
3091
|
-
console.log(JSON.stringify({ ok: true, removed }, null, 2));
|
|
3092
|
-
return;
|
|
3093
|
-
}
|
|
3094
|
-
if (removed) {
|
|
3095
|
-
await success(`Logged out. Removed ${authFilePath()}.`);
|
|
3096
|
-
} else {
|
|
3097
|
-
await info("Not logged in - nothing to remove.");
|
|
3098
|
-
}
|
|
3099
|
-
};
|
|
3100
|
-
}
|
|
3101
|
-
});
|
|
3102
|
-
|
|
3103
3303
|
// src/version/notifier.ts
|
|
3104
3304
|
var notifier_exports = {};
|
|
3105
3305
|
__export(notifier_exports, {
|
|
@@ -3109,8 +3309,8 @@ __export(notifier_exports, {
|
|
|
3109
3309
|
installHint: () => installHint,
|
|
3110
3310
|
notifierSuppressed: () => notifierSuppressed
|
|
3111
3311
|
});
|
|
3112
|
-
import { existsSync as existsSync14, mkdirSync as
|
|
3113
|
-
import { homedir as
|
|
3312
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
3313
|
+
import { homedir as homedir2 } from "os";
|
|
3114
3314
|
import { dirname as dirname6, resolve as resolve19 } from "path";
|
|
3115
3315
|
var REGISTRY_URL, CHECK_TTL_MS, FETCH_TIMEOUT_MS, INSTALL_HINT, cacheFilePath, installHint, getCurrentVersion, compareSemver, readCache, writeCache, fetchLatestVersion, checkForUpdate, notifierSuppressed;
|
|
3116
3316
|
var init_notifier = __esm({
|
|
@@ -3122,14 +3322,14 @@ var init_notifier = __esm({
|
|
|
3122
3322
|
FETCH_TIMEOUT_MS = 2e3;
|
|
3123
3323
|
INSTALL_HINT = "pnpm add -g quiver-cli";
|
|
3124
3324
|
cacheFilePath = () => {
|
|
3125
|
-
const base = process.env["XDG_CACHE_HOME"] || resolve19(
|
|
3325
|
+
const base = process.env["XDG_CACHE_HOME"] || resolve19(homedir2(), ".cache");
|
|
3126
3326
|
return resolve19(base, "quiver", "update-check.json");
|
|
3127
3327
|
};
|
|
3128
3328
|
installHint = () => INSTALL_HINT;
|
|
3129
3329
|
getCurrentVersion = () => {
|
|
3130
3330
|
try {
|
|
3131
3331
|
const pkg = JSON.parse(
|
|
3132
|
-
|
|
3332
|
+
readFileSync10(resolve19(packageRoot, "package.json"), "utf8")
|
|
3133
3333
|
);
|
|
3134
3334
|
return pkg.version;
|
|
3135
3335
|
} catch {
|
|
@@ -3157,7 +3357,7 @@ var init_notifier = __esm({
|
|
|
3157
3357
|
const path = cacheFilePath();
|
|
3158
3358
|
if (!existsSync14(path)) return null;
|
|
3159
3359
|
try {
|
|
3160
|
-
return JSON.parse(
|
|
3360
|
+
return JSON.parse(readFileSync10(path, "utf8"));
|
|
3161
3361
|
} catch {
|
|
3162
3362
|
return null;
|
|
3163
3363
|
}
|
|
@@ -3165,8 +3365,8 @@ var init_notifier = __esm({
|
|
|
3165
3365
|
writeCache = (cache) => {
|
|
3166
3366
|
try {
|
|
3167
3367
|
const path = cacheFilePath();
|
|
3168
|
-
|
|
3169
|
-
|
|
3368
|
+
mkdirSync6(dirname6(path), { recursive: true });
|
|
3369
|
+
writeFileSync8(path, JSON.stringify(cache, null, 2) + "\n");
|
|
3170
3370
|
} catch {
|
|
3171
3371
|
}
|
|
3172
3372
|
};
|
|
@@ -3210,72 +3410,109 @@ var init_notifier = __esm({
|
|
|
3210
3410
|
|
|
3211
3411
|
// src/cli.ts
|
|
3212
3412
|
init_prompts();
|
|
3213
|
-
import
|
|
3214
|
-
var HELP = `quiver-cli - compose agent skills, commands & MCP servers into any repo
|
|
3413
|
+
import process3 from "process";
|
|
3414
|
+
var HELP = `quiver-cli - compose agent skills, commands, plugins & MCP servers into any repo
|
|
3215
3415
|
|
|
3216
3416
|
Usage:
|
|
3217
3417
|
quiver-cli <command> [options]
|
|
3218
3418
|
|
|
3219
3419
|
Commands:
|
|
3220
3420
|
init Interactive picker over the catalog; write native configs + quiver.lock
|
|
3221
|
-
add <id> Add
|
|
3421
|
+
add <id> Add an entry (skill:<name>, command:<name>, mcp:<name>, plugin:<name>)
|
|
3222
3422
|
remove <id> Remove a single entry; keep lockfile + configs consistent
|
|
3223
3423
|
sync Regenerate provider configs from .agents/ (warns on drift)
|
|
3424
|
+
providers [a,b] Change which tools get configs (claude, opencode, codex)
|
|
3224
3425
|
update [id] Pull newer catalog content into .agents/ (all or one entry)
|
|
3225
|
-
list Show installed entries (skills, commands, MCP tool counts)
|
|
3226
|
-
|
|
3227
|
-
|
|
3426
|
+
list Show installed entries (skills, commands, plugins, MCP tool counts)
|
|
3427
|
+
check Detect drift: skill digests, provider shims, MCP tool
|
|
3428
|
+
snapshots (--offline skips MCP re-introspection)
|
|
3228
3429
|
upstream Catalog maintenance: check source repos for skill updates
|
|
3229
3430
|
(run in the quiver-cli repo or with a writable --catalog)
|
|
3230
3431
|
upstream pull Pull latest upstream content into the catalog [skill]
|
|
3231
|
-
login Store a GitHub token for remote (github:) catalogs
|
|
3232
|
-
logout Remove the stored GitHub token
|
|
3233
3432
|
help Show this help
|
|
3234
3433
|
version Show the quiver-cli version
|
|
3235
3434
|
|
|
3236
3435
|
Options:
|
|
3237
3436
|
-f, --force Overwrite existing files
|
|
3238
3437
|
--all, -y Keep everything without prompting (non-interactive)
|
|
3239
|
-
--json Machine-readable output (
|
|
3438
|
+
--json Machine-readable output (check/upstream/list)
|
|
3240
3439
|
-V, --verbose Show full tool lists and description diffs (check)
|
|
3241
3440
|
--accept Record the current MCP tool snapshots as the new baseline (check)
|
|
3242
|
-
--
|
|
3441
|
+
--offline Skip MCP re-introspection; check digests + shims only (check)
|
|
3442
|
+
--dry-run Report what would change without writing (update)
|
|
3443
|
+
--providers=a,b Generate configs only for these tools (init, sync, providers)
|
|
3243
3444
|
--catalog=<source> Catalog source for init (e.g. github:owner/repo[/path][#ref])
|
|
3244
3445
|
--introspect-stdio Allow introspecting stdio MCP servers (runs foreign code)
|
|
3245
3446
|
-v, --version Show the quiver-cli version
|
|
3246
3447
|
`;
|
|
3448
|
+
var KNOWN_FLAGS = /* @__PURE__ */ new Set([
|
|
3449
|
+
"--force",
|
|
3450
|
+
"-f",
|
|
3451
|
+
"--all",
|
|
3452
|
+
"--yes",
|
|
3453
|
+
"-y",
|
|
3454
|
+
"--json",
|
|
3455
|
+
"--verbose",
|
|
3456
|
+
"-V",
|
|
3457
|
+
"--accept",
|
|
3458
|
+
"--offline",
|
|
3459
|
+
"--dry-run",
|
|
3460
|
+
"--introspect-stdio",
|
|
3461
|
+
"--help",
|
|
3462
|
+
"-h",
|
|
3463
|
+
"--version",
|
|
3464
|
+
"-v"
|
|
3465
|
+
]);
|
|
3466
|
+
var KNOWN_VALUE_FLAGS = ["--providers", "--catalog"];
|
|
3467
|
+
var isKnownFlag = (arg) => {
|
|
3468
|
+
if (KNOWN_FLAGS.has(arg)) return true;
|
|
3469
|
+
return KNOWN_VALUE_FLAGS.some((f) => arg.startsWith(`${f}=`));
|
|
3470
|
+
};
|
|
3247
3471
|
var parse2 = (argv) => {
|
|
3248
3472
|
const [command = "init", ...rest] = argv;
|
|
3249
3473
|
const flags = new Set(rest.filter((a) => a.startsWith("-")));
|
|
3250
3474
|
const positionals = rest.filter((a) => !a.startsWith("-"));
|
|
3475
|
+
const unknownFlags = [...flags].filter((a) => !isKnownFlag(a));
|
|
3251
3476
|
const providersFlag = rest.find((a) => a.startsWith("--providers="));
|
|
3252
|
-
const
|
|
3477
|
+
const providers2 = providersFlag ? providersFlag.slice("--providers=".length).split(",").map((p) => p.trim()).filter(Boolean) : null;
|
|
3253
3478
|
const catalogFlag = rest.find((a) => a.startsWith("--catalog="));
|
|
3254
3479
|
const catalog = catalogFlag ? catalogFlag.slice("--catalog=".length).trim() || null : null;
|
|
3255
3480
|
return {
|
|
3256
3481
|
command,
|
|
3482
|
+
unknownFlags,
|
|
3257
3483
|
options: {
|
|
3258
|
-
targetRoot:
|
|
3484
|
+
targetRoot: process3.cwd(),
|
|
3259
3485
|
force: flags.has("--force") || flags.has("-f"),
|
|
3260
3486
|
all: flags.has("--all") || flags.has("--yes") || flags.has("-y"),
|
|
3261
3487
|
json: flags.has("--json"),
|
|
3262
3488
|
verbose: flags.has("--verbose") || flags.has("-V"),
|
|
3263
3489
|
accept: flags.has("--accept"),
|
|
3490
|
+
offline: flags.has("--offline"),
|
|
3491
|
+
dryRun: flags.has("--dry-run"),
|
|
3264
3492
|
introspectStdio: flags.has("--introspect-stdio"),
|
|
3265
|
-
providers,
|
|
3493
|
+
providers: providers2,
|
|
3266
3494
|
catalog,
|
|
3267
3495
|
positionals
|
|
3268
3496
|
}
|
|
3269
3497
|
};
|
|
3270
3498
|
};
|
|
3271
3499
|
var run = async () => {
|
|
3272
|
-
const { command, options } = parse2(
|
|
3273
|
-
if (
|
|
3500
|
+
const { command, options, unknownFlags } = parse2(process3.argv.slice(2));
|
|
3501
|
+
if (unknownFlags.length) {
|
|
3502
|
+
await error(
|
|
3503
|
+
`Unknown option${unknownFlags.length === 1 ? "" : "s"}: ${unknownFlags.join(", ")}
|
|
3504
|
+
`
|
|
3505
|
+
);
|
|
3506
|
+
console.log(HELP);
|
|
3507
|
+
process3.exitCode = 1;
|
|
3508
|
+
return;
|
|
3509
|
+
}
|
|
3510
|
+
if (process3.stdin.isTTY && !options.all) {
|
|
3274
3511
|
const { checkNodeForCommand: checkNodeForCommand2 } = await Promise.resolve().then(() => (init_node_guard(), node_guard_exports));
|
|
3275
3512
|
const guard = checkNodeForCommand2(command);
|
|
3276
3513
|
if (!guard.ok) {
|
|
3277
3514
|
await error(guard.message);
|
|
3278
|
-
|
|
3515
|
+
process3.exitCode = 1;
|
|
3279
3516
|
return;
|
|
3280
3517
|
}
|
|
3281
3518
|
}
|
|
@@ -3301,6 +3538,11 @@ var run = async () => {
|
|
|
3301
3538
|
await sync2(options);
|
|
3302
3539
|
break;
|
|
3303
3540
|
}
|
|
3541
|
+
case "providers": {
|
|
3542
|
+
const { providers: providers2 } = await Promise.resolve().then(() => (init_providers(), providers_exports));
|
|
3543
|
+
await providers2(options);
|
|
3544
|
+
break;
|
|
3545
|
+
}
|
|
3304
3546
|
case "update": {
|
|
3305
3547
|
const { update: update2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
3306
3548
|
await update2(options);
|
|
@@ -3312,11 +3554,6 @@ var run = async () => {
|
|
|
3312
3554
|
await list3(options);
|
|
3313
3555
|
break;
|
|
3314
3556
|
}
|
|
3315
|
-
case "status": {
|
|
3316
|
-
const { status: status2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
3317
|
-
await status2(options);
|
|
3318
|
-
break;
|
|
3319
|
-
}
|
|
3320
3557
|
case "check": {
|
|
3321
3558
|
const { check: check2 } = await Promise.resolve().then(() => (init_check(), check_exports));
|
|
3322
3559
|
await check2(options);
|
|
@@ -3327,16 +3564,6 @@ var run = async () => {
|
|
|
3327
3564
|
await upstream2(options);
|
|
3328
3565
|
break;
|
|
3329
3566
|
}
|
|
3330
|
-
case "login": {
|
|
3331
|
-
const { login: login2 } = await Promise.resolve().then(() => (init_login(), login_exports));
|
|
3332
|
-
await login2(options);
|
|
3333
|
-
break;
|
|
3334
|
-
}
|
|
3335
|
-
case "logout": {
|
|
3336
|
-
const { logout: logout2 } = await Promise.resolve().then(() => (init_logout(), logout_exports));
|
|
3337
|
-
await logout2(options);
|
|
3338
|
-
break;
|
|
3339
|
-
}
|
|
3340
3567
|
case "help":
|
|
3341
3568
|
case "--help":
|
|
3342
3569
|
case "-h":
|
|
@@ -3359,7 +3586,7 @@ var run = async () => {
|
|
|
3359
3586
|
console.error(`Unknown command: ${command}
|
|
3360
3587
|
`);
|
|
3361
3588
|
console.log(HELP);
|
|
3362
|
-
|
|
3589
|
+
process3.exitCode = 1;
|
|
3363
3590
|
}
|
|
3364
3591
|
if (!["version", "--version", "-v", "help", "--help", "-h"].includes(command)) {
|
|
3365
3592
|
await maybeNotifyUpdate(options.json);
|
|
@@ -3381,7 +3608,14 @@ ${c.yellow("\u25B2")} ${c.bold("update available")} ${c.dim(
|
|
|
3381
3608
|
} catch {
|
|
3382
3609
|
}
|
|
3383
3610
|
};
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3611
|
+
var main = () => {
|
|
3612
|
+
run().catch(async (err) => {
|
|
3613
|
+
await error(err instanceof Error ? err.message : String(err));
|
|
3614
|
+
process3.exitCode = 1;
|
|
3615
|
+
});
|
|
3616
|
+
};
|
|
3617
|
+
export {
|
|
3618
|
+
main,
|
|
3619
|
+
parse2 as parse,
|
|
3620
|
+
run
|
|
3621
|
+
};
|