@vellumai/assistant 0.8.11 → 0.8.12-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +15 -17
- package/README.md +0 -6
- package/bun.lock +6 -122
- package/node_modules/@vellumai/gateway-client/bun.lock +1 -0
- package/node_modules/@vellumai/gateway-client/package.json +3 -1
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +87 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +3 -5
- package/openapi.yaml +633 -4
- package/package.json +1 -3
- package/src/__tests__/adaptive-thinking-repair.test.ts +185 -0
- package/src/__tests__/agent-loop-compaction-events.test.ts +7 -6
- package/src/__tests__/anthropic-provider.test.ts +129 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +4 -1
- package/src/__tests__/btw-routes.test.ts +7 -34
- package/src/__tests__/checker.test.ts +6 -12
- package/src/__tests__/config-loader-backfill.test.ts +4 -2
- package/src/__tests__/config-loader-quarantine-notice.test.ts +167 -0
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-error.test.ts +2 -6
- package/src/__tests__/conversation-history-web-search.test.ts +8 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/disk-pressure-tools.test.ts +1 -1
- package/src/__tests__/exploration-drift-hook.test.ts +692 -0
- package/src/__tests__/filing-service.test.ts +8 -3
- package/src/__tests__/guardian-action-store.test.ts +0 -167
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -1
- package/src/__tests__/heartbeat-service.test.ts +5 -2
- package/src/__tests__/identity-intro-cache.test.ts +12 -5
- package/src/__tests__/identity-routes.test.ts +16 -57
- package/src/__tests__/injector-chain.test.ts +8 -3
- package/src/__tests__/injector-config-quarantine-notice.test.ts +115 -0
- package/src/__tests__/llm-catalog-parity.test.ts +16 -0
- package/src/__tests__/llm-usage-store.test.ts +11 -0
- package/src/__tests__/log-export-workspace.test.ts +468 -3
- package/src/__tests__/memory-v2-static-injector.test.ts +22 -0
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +19 -8
- package/src/__tests__/openai-provider.test.ts +34 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +0 -1
- package/src/__tests__/recurrence-engine.test.ts +45 -0
- package/src/__tests__/schedule-routes.test.ts +34 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
- package/src/__tests__/script-proxy-conversation-manager.test.ts +10 -5
- package/src/__tests__/secret-fixtures.ts +20 -0
- package/src/__tests__/skill-tool-factory.test.ts +49 -0
- package/src/__tests__/subagent-role-registry.test.ts +24 -1
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +109 -11
- package/src/__tests__/tool-approval-handler.test.ts +85 -0
- package/src/__tests__/tool-audit-listener.test.ts +86 -0
- package/src/__tests__/tool-error-hook.test.ts +1 -0
- package/src/__tests__/tool-result-spool.test.ts +337 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
- package/src/__tests__/validate-input.test.ts +95 -1
- package/src/__tests__/workspace-migration-098-remove-stale-updates-bulletin-file.test.ts +65 -0
- package/src/__tests__/workspace-migration-099-disable-cache-one-shot-callsites.test.ts +139 -0
- package/src/__tests__/workspace-migration-100-upgrade-quality-profile-to-fable-5.test.ts +174 -0
- package/src/__tests__/workspace-migration-101-upgrade-balanced-economy-to-minimax-m3.test.ts +162 -0
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +45 -95
- package/src/acp/__tests__/agent-process.test.ts +315 -2
- package/src/acp/__tests__/prepare-agent-env.test.ts +79 -5
- package/src/acp/agent-process.ts +163 -34
- package/src/acp/prepare-agent-env.ts +55 -15
- package/src/agent/loop.ts +81 -24
- package/src/api/events/usage-progress.ts +28 -0
- package/src/api/index.ts +6 -0
- package/src/background-wake/wake-intent-hooks.test.ts +2 -0
- package/src/bundler/app-bundler.ts +25 -42
- package/src/bundler/app-compiler.ts +8 -0
- package/src/calls/call-controller.ts +1 -1
- package/src/cli/commands/plugins.ts +248 -15
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +318 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +16 -9
- package/src/cli/lib/__tests__/plugin-artifact.test.ts +183 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +158 -0
- package/src/cli/lib/__tests__/plugin-fingerprint.test.ts +245 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +307 -0
- package/src/cli/lib/inspect-plugin.ts +252 -0
- package/src/cli/lib/install-from-github.ts +214 -21
- package/src/cli/lib/list-installed-plugins.ts +17 -6
- package/src/cli/lib/plugin-artifact.ts +103 -0
- package/src/cli/lib/plugin-details.ts +18 -1
- package/src/cli/lib/plugin-fingerprint.ts +197 -0
- package/src/cli/lib/upgrade-plugin.ts +225 -0
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -2
- package/src/config/call-site-defaults.ts +13 -2
- package/src/config/feature-flag-registry.json +8 -16
- package/src/config/loader.ts +52 -59
- package/src/config/schema.ts +0 -2
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +10 -0
- package/src/config/schemas/llm.ts +10 -0
- package/src/config/schemas/memory-v2.ts +13 -0
- package/src/config/schemas/memory-v3.ts +92 -0
- package/src/config/seed-inference-profiles.ts +4 -8
- package/src/context/post-turn-tool-result-truncation.ts +32 -18
- package/src/context/tool-result-spool.ts +104 -0
- package/src/credential-execution/feature-gates.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +41 -16
- package/src/daemon/conversation-error.ts +6 -15
- package/src/daemon/conversation.ts +9 -0
- package/src/daemon/disk-pressure-policy.ts +0 -1
- package/src/daemon/lifecycle.ts +1 -20
- package/src/daemon/message-types/conversations.ts +2 -15
- package/src/daemon/trust-context.ts +1 -1
- package/src/events/tool-audit-listener.ts +40 -9
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
- package/src/home/__tests__/home-content-refresh.test.ts +114 -0
- package/src/home/__tests__/suggested-prompts.test.ts +86 -5
- package/src/home/home-content-refresh.ts +43 -31
- package/src/home/home-greeting-cache.ts +8 -1
- package/src/home/home-greeting.ts +13 -9
- package/src/home/suggested-prompts.ts +77 -24
- package/src/ipc/routes/trust-rules.test.ts +66 -72
- package/src/media/image-credentials.ts +2 -2
- package/src/memory/__tests__/compaction-log-store-clickhouse.test.ts +432 -0
- package/src/memory/{compaction-log-writer-clickhouse.ts → compaction-log-store-clickhouse.ts} +264 -55
- package/src/memory/conversation-attention-store.ts +1 -0
- package/src/memory/conversation-bootstrap.ts +18 -9
- package/src/memory/conversation-crud.ts +12 -2
- package/src/memory/conversation-title-service.ts +53 -9
- package/src/memory/delivery-channels.ts +0 -69
- package/src/memory/graph/extraction-job.ts +0 -15
- package/src/memory/guardian-action-store.ts +1 -376
- package/src/memory/llm-usage-store.ts +5 -1
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +2 -2
- package/src/memory/v2/__tests__/consolidation-job.test.ts +183 -2
- package/src/memory/v2/__tests__/injection.test.ts +70 -0
- package/src/memory/v2/__tests__/static-context.test.ts +12 -0
- package/src/memory/v2/consolidation-job.ts +93 -9
- package/src/memory/v2/injection.ts +53 -0
- package/src/memory/v2/prompts/consolidation.ts +1 -0
- package/src/memory/v2/static-context.ts +13 -1
- package/src/memory/v2/sweep-job.ts +1 -1
- package/src/memory/v2/types.ts +5 -0
- package/src/plugin-api/types.ts +7 -0
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +300 -0
- package/src/plugins/defaults/exploration-drift/package.json +15 -0
- package/src/plugins/defaults/index.ts +25 -0
- package/src/plugins/defaults/memory-retrieval/injectors.ts +132 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/card.test.ts +92 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +2 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fresh-set.test.ts +52 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +2 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +136 -5
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +17 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +6 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +5 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +68 -4
- package/src/plugins/defaults/memory-v3-shadow/card.ts +49 -5
- package/src/plugins/defaults/memory-v3-shadow/fresh-set.ts +59 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +4 -2
- package/src/plugins/defaults/memory-v3-shadow/learned-edges.test.ts +169 -0
- package/src/plugins/defaults/memory-v3-shadow/learned-edges.ts +178 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +115 -26
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -9
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +144 -22
- package/src/plugins/defaults/memory-v3-shadow/types.ts +24 -6
- package/src/plugins/defaults/title-generate/hooks/stop.ts +13 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +16 -0
- package/src/prompts/cache-boundary.ts +17 -0
- package/src/prompts/sections.ts +50 -17
- package/src/prompts/system-prompt.ts +12 -4
- package/src/prompts/templates/system-sections.ts +22 -0
- package/src/providers/__tests__/unparseable-tool-args.test.ts +53 -0
- package/src/providers/anthropic/client.ts +74 -28
- package/src/providers/gemini/client.ts +5 -1
- package/src/providers/minimax/client.ts +9 -0
- package/src/providers/model-catalog.ts +28 -0
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/chat-completions-provider.ts +4 -2
- package/src/providers/openai/responses-provider.ts +7 -2
- package/src/providers/retry.ts +8 -0
- package/src/providers/types.ts +11 -0
- package/src/providers/unparseable-tool-args.ts +56 -0
- package/src/runtime/AGENTS.md +6 -0
- package/src/runtime/__tests__/agent-wake.test.ts +2 -2
- package/src/runtime/agent-wake.ts +5 -5
- package/src/runtime/background-job-runner.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +150 -3
- package/src/runtime/migrations/vbundle-import-analyzer.ts +29 -6
- package/src/runtime/migrations/vbundle-import-policy.ts +23 -0
- package/src/runtime/migrations/vbundle-importer.ts +9 -4
- package/src/runtime/migrations/vbundle-streaming-importer.ts +8 -3
- package/src/runtime/pre-first-message-gate.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +241 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +132 -0
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +97 -185
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +348 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +3 -3
- package/src/runtime/routes/btw-routes.ts +0 -14
- package/src/runtime/routes/conversation-compaction-routes.ts +86 -19
- package/src/runtime/routes/conversation-list-routes.ts +77 -5
- package/src/runtime/routes/conversation-management-routes.ts +54 -0
- package/src/runtime/routes/conversation-query-routes.ts +79 -4
- package/src/runtime/routes/gateway-log-routes.ts +14 -64
- package/src/runtime/routes/home-feed-routes.ts +10 -0
- package/src/runtime/routes/identity-intro-cache.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +76 -20
- package/src/runtime/routes/inbound-message-handler.ts +0 -36
- package/src/runtime/routes/log-export-routes.ts +143 -96
- package/src/runtime/routes/plugins-routes.ts +380 -0
- package/src/runtime/routes/redact-staged-export.ts +259 -0
- package/src/runtime/routes/schedule-routes.ts +19 -2
- package/src/runtime/routes/trust-rules-routes.ts +14 -67
- package/src/schedule/recurrence-engine.ts +34 -0
- package/src/schedule/scheduler.ts +1 -0
- package/src/security/redact-json.ts +61 -0
- package/src/skills/validate-input.ts +41 -1
- package/src/subagent/types.ts +26 -1
- package/src/telemetry/types.ts +15 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +6 -1
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/apps/executors.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +19 -8
- package/src/tools/tool-approval-handler.ts +31 -0
- package/src/usage/types.ts +8 -1
- package/src/util/platform.ts +16 -0
- package/src/watcher/engine.ts +1 -0
- package/src/workspace/adaptive-thinking-repair.ts +113 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +70 -67
- package/src/workspace/migrations/098-remove-stale-updates-bulletin-file.ts +31 -0
- package/src/workspace/migrations/099-disable-cache-one-shot-callsites.ts +81 -0
- package/src/workspace/migrations/100-upgrade-quality-profile-to-fable-5.ts +86 -0
- package/src/workspace/migrations/101-upgrade-balanced-economy-to-minimax-m3.ts +70 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +0 -202
- package/src/__tests__/conversation-starters-cadence.test.ts +0 -161
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -322
- package/src/__tests__/guardian-action-followup-store.test.ts +0 -373
- package/src/__tests__/guardian-action-late-reply.test.ts +0 -1083
- package/src/__tests__/update-bulletin-job.test.ts +0 -292
- package/src/config/schemas/updates.ts +0 -14
- package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +0 -227
- package/src/memory/conversation-starters-cadence.ts +0 -78
- package/src/prompts/update-bulletin-job.ts +0 -180
- package/src/runtime/guardian-action-followup-executor.ts +0 -306
|
@@ -6,12 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
|
-
import {
|
|
9
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
10
10
|
import { readFile, stat, writeFile } from "node:fs/promises";
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
|
|
14
|
-
import archiver from "archiver";
|
|
15
14
|
import JSZip from "jszip";
|
|
16
15
|
|
|
17
16
|
import { getApp, getAppDirPath, isMultifileApp } from "../memory/app-store.js";
|
|
@@ -37,6 +36,14 @@ export interface BundleResult {
|
|
|
37
36
|
iconImageBase64?: string;
|
|
38
37
|
}
|
|
39
38
|
|
|
39
|
+
function generateZipBuffer(zip: JSZip): Promise<Buffer> {
|
|
40
|
+
return zip.generateAsync({
|
|
41
|
+
type: "nodebuffer",
|
|
42
|
+
compression: "DEFLATE",
|
|
43
|
+
compressionOptions: { level: 9 },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
function isDefaultMainScaffold(source: string): boolean {
|
|
41
48
|
const normalized = source.replace(/\s+/g, " ").trim();
|
|
42
49
|
return (
|
|
@@ -177,54 +184,31 @@ export async function packageApp(
|
|
|
177
184
|
const bundleFilename = `${safeName}-${uniqueSuffix}.vellum`;
|
|
178
185
|
const bundlePath = join(tmpdir(), bundleFilename);
|
|
179
186
|
|
|
180
|
-
|
|
181
|
-
const output = createWriteStream(bundlePath);
|
|
182
|
-
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
183
|
-
|
|
184
|
-
output.on("close", () => resolve());
|
|
185
|
-
output.on("error", (err: Error) => reject(err));
|
|
186
|
-
archive.on("error", (err: Error) => reject(err));
|
|
187
|
-
archive.on("warning", (err: Error) => {
|
|
188
|
-
// Only reject on fatal warnings
|
|
189
|
-
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
190
|
-
reject(err);
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
archive.pipe(output);
|
|
187
|
+
const zip = new JSZip();
|
|
195
188
|
|
|
196
|
-
|
|
197
|
-
|
|
189
|
+
// Add manifest.json at root level
|
|
190
|
+
zip.file("manifest.json", serializeManifest(manifest));
|
|
198
191
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
192
|
+
// Add compiled dist/ files
|
|
193
|
+
for (const file of compiledFiles) {
|
|
194
|
+
zip.file(file.name, file.data);
|
|
195
|
+
}
|
|
203
196
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
197
|
+
// Include app icon if one was generated
|
|
198
|
+
const iconPath = join(appDir, "icon.png");
|
|
199
|
+
if (existsSync(iconPath)) {
|
|
200
|
+
zip.file("icon.png", readFileSync(iconPath));
|
|
201
|
+
}
|
|
209
202
|
|
|
210
|
-
|
|
211
|
-
});
|
|
203
|
+
await writeFile(bundlePath, await generateZipBuffer(zip));
|
|
212
204
|
|
|
213
205
|
// Sign the bundle if a signing callback is provided
|
|
214
206
|
if (requestSignature) {
|
|
215
207
|
try {
|
|
216
208
|
const signatureJson = await signBundle(bundlePath, requestSignature);
|
|
217
209
|
|
|
218
|
-
// Re-open the zip and add signature.json
|
|
219
|
-
const zipBuffer = await readFile(bundlePath);
|
|
220
|
-
const zip = await JSZip.loadAsync(zipBuffer);
|
|
221
210
|
zip.file("signature.json", JSON.stringify(signatureJson, null, 2));
|
|
222
|
-
|
|
223
|
-
type: "nodebuffer",
|
|
224
|
-
compression: "DEFLATE",
|
|
225
|
-
compressionOptions: { level: 9 },
|
|
226
|
-
});
|
|
227
|
-
await writeFile(bundlePath, signedBuffer);
|
|
211
|
+
await writeFile(bundlePath, await generateZipBuffer(zip));
|
|
228
212
|
|
|
229
213
|
bundlerLog.info({ appId }, "Bundle signed successfully");
|
|
230
214
|
} catch (err) {
|
|
@@ -250,9 +234,8 @@ export async function packageApp(
|
|
|
250
234
|
|
|
251
235
|
// Read icon for inclusion in the response
|
|
252
236
|
let iconImageBase64: string | undefined;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
iconImageBase64 = readFileSync(iconFilePath).toString("base64");
|
|
237
|
+
if (existsSync(iconPath)) {
|
|
238
|
+
iconImageBase64 = readFileSync(iconPath).toString("base64");
|
|
256
239
|
}
|
|
257
240
|
|
|
258
241
|
return { bundlePath, manifest, iconImageBase64 };
|
|
@@ -454,6 +454,14 @@ async function runCompile(appDir: string): Promise<CompileResult> {
|
|
|
454
454
|
if (existsSync(htmlSrc)) {
|
|
455
455
|
let html = await readFile(htmlSrc, "utf-8");
|
|
456
456
|
|
|
457
|
+
// Strip source-file script tags (e.g. <script src="/src/main.tsx">) that
|
|
458
|
+
// models often write in Vite style; browsers cannot load raw TSX/TS/JSX.
|
|
459
|
+
// The compiled main.js tag is injected below instead.
|
|
460
|
+
html = html.replace(
|
|
461
|
+
/<script\b[^>]*\bsrc=["'][^"']*\.(?:tsx|ts|jsx)["'][^>]*>\s*<\/script>\s*/gi,
|
|
462
|
+
"",
|
|
463
|
+
);
|
|
464
|
+
|
|
457
465
|
// Check if CSS output was produced
|
|
458
466
|
const distFiles = await readdir(distDir);
|
|
459
467
|
const hasCss = distFiles.some((f) => f.endsWith(".css"));
|
|
@@ -1312,7 +1312,7 @@ export class CallController {
|
|
|
1312
1312
|
|
|
1313
1313
|
// Mark the linked guardian action request as timed out and
|
|
1314
1314
|
// send expiry notices to guardian destinations. Deliveries
|
|
1315
|
-
// must be captured before
|
|
1315
|
+
// must be captured before expiring the request changes
|
|
1316
1316
|
// their status.
|
|
1317
1317
|
const pendingActionRequest = getPendingCanonicalRequestByCallSessionId(
|
|
1318
1318
|
this.callSessionId,
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
import type { Command } from "commander";
|
|
11
11
|
|
|
12
12
|
import { confirmPrompt } from "../lib/confirm-prompt.js";
|
|
13
|
+
import {
|
|
14
|
+
inspectPlugin,
|
|
15
|
+
type PluginInspection,
|
|
16
|
+
PluginInspectNotFoundError,
|
|
17
|
+
} from "../lib/inspect-plugin.js";
|
|
13
18
|
import {
|
|
14
19
|
DEFAULT_PLUGIN_REF,
|
|
15
20
|
installPlugin,
|
|
@@ -18,6 +23,7 @@ import {
|
|
|
18
23
|
PluginNotFoundError,
|
|
19
24
|
} from "../lib/install-from-github.js";
|
|
20
25
|
import { listInstalledPlugins } from "../lib/list-installed-plugins.js";
|
|
26
|
+
import type { FingerprintComparison } from "../lib/plugin-fingerprint.js";
|
|
21
27
|
import { registerCommand } from "../lib/register-command.js";
|
|
22
28
|
import {
|
|
23
29
|
InvalidSearchPatternError,
|
|
@@ -27,6 +33,11 @@ import {
|
|
|
27
33
|
PluginNotInstalledError,
|
|
28
34
|
uninstallPlugin,
|
|
29
35
|
} from "../lib/uninstall-plugin.js";
|
|
36
|
+
import {
|
|
37
|
+
PluginNotUpgradableError,
|
|
38
|
+
type PluginUpgradeResult,
|
|
39
|
+
upgradePlugin,
|
|
40
|
+
} from "../lib/upgrade-plugin.js";
|
|
30
41
|
import { getCliLogger } from "../logger.js";
|
|
31
42
|
|
|
32
43
|
const log = getCliLogger("plugins");
|
|
@@ -41,15 +52,19 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
41
52
|
"after",
|
|
42
53
|
`
|
|
43
54
|
Examples:
|
|
44
|
-
$ assistant plugins install
|
|
45
|
-
$ assistant plugins install
|
|
46
|
-
$ assistant plugins install
|
|
55
|
+
$ assistant plugins install example
|
|
56
|
+
$ assistant plugins install example --force
|
|
57
|
+
$ assistant plugins install example --ref my-feature-branch
|
|
47
58
|
$ assistant plugins list
|
|
48
59
|
$ assistant plugins list --json
|
|
49
|
-
$ assistant plugins
|
|
50
|
-
$ assistant plugins
|
|
51
|
-
$ assistant plugins
|
|
52
|
-
$ assistant plugins
|
|
60
|
+
$ assistant plugins inspect example
|
|
61
|
+
$ assistant plugins inspect example --json
|
|
62
|
+
$ assistant plugins upgrade example
|
|
63
|
+
$ assistant plugins upgrade example --dry-run
|
|
64
|
+
$ assistant plugins search example
|
|
65
|
+
$ assistant plugins search "^example"
|
|
66
|
+
$ assistant plugins search example --json
|
|
67
|
+
$ assistant plugins uninstall example`,
|
|
53
68
|
);
|
|
54
69
|
|
|
55
70
|
plugins
|
|
@@ -147,6 +162,55 @@ Examples:
|
|
|
147
162
|
);
|
|
148
163
|
});
|
|
149
164
|
|
|
165
|
+
plugins
|
|
166
|
+
.command("inspect <name>")
|
|
167
|
+
.description(
|
|
168
|
+
"Show a plugin's local install metadata and the marketplace pin, and whether an update is available",
|
|
169
|
+
)
|
|
170
|
+
.option("--json", "Emit machine-readable JSON instead of a summary")
|
|
171
|
+
.action(async (name: string, opts: { json?: boolean }) => {
|
|
172
|
+
try {
|
|
173
|
+
const inspection = await inspectPlugin(
|
|
174
|
+
{ name },
|
|
175
|
+
{ fetch: globalThis.fetch.bind(globalThis) },
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
if (opts.json) {
|
|
179
|
+
process.stdout.write(JSON.stringify(inspection, null, 2) + "\n");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Logged after the JSON early-return: the CLI logger writes
|
|
184
|
+
// info to stdout, which would otherwise corrupt --json output.
|
|
185
|
+
log.info(
|
|
186
|
+
{
|
|
187
|
+
name: inspection.name,
|
|
188
|
+
installed: inspection.installed,
|
|
189
|
+
status: inspection.status,
|
|
190
|
+
},
|
|
191
|
+
"plugin inspect",
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
for (const line of formatInspection(inspection)) {
|
|
195
|
+
console.log(line);
|
|
196
|
+
}
|
|
197
|
+
} catch (err) {
|
|
198
|
+
if (err instanceof PluginInspectNotFoundError) {
|
|
199
|
+
console.error(err.message);
|
|
200
|
+
process.exitCode = 1;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (err instanceof InvalidPluginNameError) {
|
|
204
|
+
console.error(err.message);
|
|
205
|
+
process.exitCode = 1;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
209
|
+
console.error(`Plugin inspect failed: ${message}`);
|
|
210
|
+
process.exitCode = 1;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
150
214
|
plugins
|
|
151
215
|
.command("search <query>")
|
|
152
216
|
.description(
|
|
@@ -160,9 +224,13 @@ Examples:
|
|
|
160
224
|
{ fetch: globalThis.fetch.bind(globalThis) },
|
|
161
225
|
);
|
|
162
226
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
227
|
+
if (opts.json) {
|
|
228
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Logged after the JSON early-return: the CLI logger writes info
|
|
233
|
+
// to stdout, which would otherwise corrupt --json output.
|
|
166
234
|
log.info(
|
|
167
235
|
{
|
|
168
236
|
query: result.query,
|
|
@@ -172,11 +240,6 @@ Examples:
|
|
|
172
240
|
"external plugin search",
|
|
173
241
|
);
|
|
174
242
|
|
|
175
|
-
if (opts.json) {
|
|
176
|
-
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
243
|
if (result.matches.length === 0) {
|
|
181
244
|
console.log(`No plugins matched "${result.query}".`);
|
|
182
245
|
return;
|
|
@@ -253,6 +316,176 @@ Examples:
|
|
|
253
316
|
process.exitCode = 1;
|
|
254
317
|
}
|
|
255
318
|
});
|
|
319
|
+
|
|
320
|
+
plugins
|
|
321
|
+
.command("upgrade <name>")
|
|
322
|
+
.description(
|
|
323
|
+
"Upgrade an installed plugin to the marketplace's current pin",
|
|
324
|
+
)
|
|
325
|
+
.option(
|
|
326
|
+
"--dry-run",
|
|
327
|
+
"Show what would change without modifying the install",
|
|
328
|
+
)
|
|
329
|
+
.option("--json", "Emit machine-readable JSON instead of a summary")
|
|
330
|
+
.action(
|
|
331
|
+
async (name: string, opts: { dryRun?: boolean; json?: boolean }) => {
|
|
332
|
+
try {
|
|
333
|
+
const result = await upgradePlugin(
|
|
334
|
+
{ name, dryRun: opts.dryRun },
|
|
335
|
+
{ fetch: globalThis.fetch.bind(globalThis) },
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
if (opts.json) {
|
|
339
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Logged after the JSON early-return: the CLI logger writes
|
|
344
|
+
// info to stdout, which would otherwise corrupt --json output.
|
|
345
|
+
log.info(
|
|
346
|
+
{
|
|
347
|
+
name: result.name,
|
|
348
|
+
outcome: result.outcome,
|
|
349
|
+
from: result.fromCommit,
|
|
350
|
+
to: result.toCommit,
|
|
351
|
+
},
|
|
352
|
+
"plugin upgrade",
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
for (const line of formatUpgrade(result)) {
|
|
356
|
+
console.log(line);
|
|
357
|
+
}
|
|
358
|
+
} catch (err) {
|
|
359
|
+
if (
|
|
360
|
+
err instanceof PluginNotInstalledError ||
|
|
361
|
+
err instanceof PluginNotUpgradableError ||
|
|
362
|
+
err instanceof InvalidPluginNameError
|
|
363
|
+
) {
|
|
364
|
+
console.error(err.message);
|
|
365
|
+
process.exitCode = 1;
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
369
|
+
console.error(`Plugin upgrade failed: ${message}`);
|
|
370
|
+
process.exitCode = 1;
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
);
|
|
256
374
|
},
|
|
257
375
|
});
|
|
258
376
|
}
|
|
377
|
+
|
|
378
|
+
/** Abbreviate a commit SHA for display; passes through non-SHA / null values. */
|
|
379
|
+
function shortSha(sha: string | null): string {
|
|
380
|
+
return sha ? sha.slice(0, 7) : "—";
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** Human-readable status line for an inspection result. */
|
|
384
|
+
function statusLine(inspection: PluginInspection): string {
|
|
385
|
+
const { status, local, remote } = inspection;
|
|
386
|
+
switch (status) {
|
|
387
|
+
case "up-to-date":
|
|
388
|
+
return "up to date";
|
|
389
|
+
case "update-available":
|
|
390
|
+
return `update available (${shortSha(local?.commit ?? null)} → ${shortSha(
|
|
391
|
+
remote?.commit ?? null,
|
|
392
|
+
)})`;
|
|
393
|
+
case "not-installed":
|
|
394
|
+
return "not installed";
|
|
395
|
+
case "not-in-marketplace":
|
|
396
|
+
return "installed (not in marketplace)";
|
|
397
|
+
case "unknown-provenance":
|
|
398
|
+
return "unknown — reinstall to record provenance";
|
|
399
|
+
case "remote-unavailable":
|
|
400
|
+
return "installed (marketplace unavailable)";
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Summarize local edits relative to the install-time fingerprint. Reports
|
|
406
|
+
* "unknown" when no baseline was recorded (an older or manually-copied
|
|
407
|
+
* install), "none" when the on-disk tree matches, or a per-category count.
|
|
408
|
+
*/
|
|
409
|
+
function localEditsLine(changes: FingerprintComparison | null): string {
|
|
410
|
+
if (!changes)
|
|
411
|
+
return "unknown (no recorded baseline; reinstall to record one)";
|
|
412
|
+
if (changes.clean) return "none";
|
|
413
|
+
const parts = [
|
|
414
|
+
`${changes.modified.length} modified`,
|
|
415
|
+
`${changes.added.length} added`,
|
|
416
|
+
`${changes.removed.length} removed`,
|
|
417
|
+
];
|
|
418
|
+
return parts.join(", ");
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** Render an inspection as aligned, human-readable summary lines. */
|
|
422
|
+
function formatInspection(inspection: PluginInspection): string[] {
|
|
423
|
+
const { name, local, remote, remoteError } = inspection;
|
|
424
|
+
const lines: string[] = [`${name} plugin`];
|
|
425
|
+
const row = (label: string, value: string) =>
|
|
426
|
+
lines.push(` ${label.padEnd(11)} ${value}`);
|
|
427
|
+
|
|
428
|
+
row("status", statusLine(inspection));
|
|
429
|
+
|
|
430
|
+
if (local) {
|
|
431
|
+
const installedAt = local.installedAt
|
|
432
|
+
? ` (${local.installedAt.slice(0, 10)})`
|
|
433
|
+
: "";
|
|
434
|
+
row("installed", `${shortSha(local.commit)}${installedAt}`);
|
|
435
|
+
row("local edits", localEditsLine(local.localChanges));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (remote) {
|
|
439
|
+
const where = remote.path ? `${remote.repo}/${remote.path}` : remote.repo;
|
|
440
|
+
row(
|
|
441
|
+
"remote pin",
|
|
442
|
+
`${shortSha(remote.commit)} (${where}, ${remote.marketplaceRef})`,
|
|
443
|
+
);
|
|
444
|
+
} else if (remoteError) {
|
|
445
|
+
row("remote", `unavailable — ${remoteError}`);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const version = local?.version ?? null;
|
|
449
|
+
if (version) row("version", version);
|
|
450
|
+
|
|
451
|
+
const license = remote?.license ?? null;
|
|
452
|
+
const homepage = remote?.homepage ?? null;
|
|
453
|
+
if (license && homepage) row("license", `${license} homepage ${homepage}`);
|
|
454
|
+
else if (license) row("license", license);
|
|
455
|
+
else if (homepage) row("homepage", homepage);
|
|
456
|
+
|
|
457
|
+
const description = remote?.description ?? local?.description ?? null;
|
|
458
|
+
if (description) row("description", description);
|
|
459
|
+
|
|
460
|
+
for (const issue of local?.issues ?? []) row("issue", issue);
|
|
461
|
+
|
|
462
|
+
return lines;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** Render an upgrade result as human-readable summary lines. */
|
|
466
|
+
function formatUpgrade(result: PluginUpgradeResult): string[] {
|
|
467
|
+
const { name, fromCommit, toCommit } = result;
|
|
468
|
+
const move = `${shortSha(fromCommit)} → ${shortSha(toCommit)}`;
|
|
469
|
+
const provenanceNote = result.provenanceWasUnknown
|
|
470
|
+
? " (previous install had no recorded provenance)"
|
|
471
|
+
: "";
|
|
472
|
+
|
|
473
|
+
switch (result.outcome) {
|
|
474
|
+
case "already-up-to-date":
|
|
475
|
+
return [`"${name}" is already up to date (${shortSha(toCommit)}).`];
|
|
476
|
+
case "would-upgrade":
|
|
477
|
+
return [
|
|
478
|
+
`"${name}" would upgrade ${move}${provenanceNote} (dry run; no changes made).`,
|
|
479
|
+
];
|
|
480
|
+
case "upgraded": {
|
|
481
|
+
const count =
|
|
482
|
+
result.fileCount === null
|
|
483
|
+
? ""
|
|
484
|
+
: ` (${result.fileCount} file${result.fileCount === 1 ? "" : "s"})`;
|
|
485
|
+
return [
|
|
486
|
+
`Upgraded "${name}" ${move}${count}${provenanceNote} → ${result.target}`,
|
|
487
|
+
"Restart the assistant to pick up the upgrade.",
|
|
488
|
+
];
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|