@vellumai/assistant 0.10.3 → 0.10.4-staging.1
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/openapi.yaml +73 -56
- package/package.json +1 -1
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
- package/src/__tests__/assistant-stream-state.test.ts +3 -76
- package/src/__tests__/background-workers-disk-pressure.test.ts +4 -2
- package/src/__tests__/channel-approval-routes.test.ts +21 -26
- package/src/__tests__/channel-delivery-store.test.ts +28 -0
- package/src/__tests__/channel-guardian.test.ts +82 -32
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +11 -19
- package/src/__tests__/channel-reply-delivery.test.ts +6 -2
- package/src/__tests__/compaction-ledger-store.test.ts +128 -0
- package/src/__tests__/config-loader-backfill.test.ts +148 -0
- package/src/__tests__/consult-deadline.test.ts +60 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
- package/src/__tests__/contact-store-user-file.test.ts +7 -10
- package/src/__tests__/contacts-relay-reads.test.ts +6 -9
- package/src/__tests__/contacts-write.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +4 -2
- package/src/__tests__/conversation-agent-loop.test.ts +98 -7
- package/src/__tests__/conversation-attention-telegram.test.ts +9 -11
- package/src/__tests__/conversation-error.test.ts +18 -0
- package/src/__tests__/conversation-fork-crud.test.ts +354 -24
- package/src/__tests__/conversation-title-service.test.ts +222 -201
- package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
- package/src/__tests__/delete-propagation.test.ts +5 -3
- package/src/__tests__/dm-backfill.test.ts +6 -4
- package/src/__tests__/emit-signal-routing-intent.test.ts +2 -6
- package/src/__tests__/guardian-binding-drift-heal.test.ts +43 -23
- package/src/__tests__/guardian-dispatch.test.ts +50 -5
- package/src/__tests__/guardian-routing-state.test.ts +6 -10
- package/src/__tests__/helpers/channel-test-adapter.ts +45 -12
- package/src/__tests__/helpers/create-guardian-binding.ts +15 -23
- package/src/__tests__/helpers/mock-logger.ts +1 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +96 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +87 -10
- package/src/__tests__/invite-redemption-service.test.ts +273 -53
- package/src/__tests__/invite-routes-http.test.ts +34 -0
- package/src/__tests__/invite-service-ipc.test.ts +65 -2
- package/src/__tests__/list-messages-page-latest.test.ts +173 -4
- package/src/__tests__/mcp-config-secret-boundary.test.ts +3 -0
- package/src/__tests__/non-member-access-request.test.ts +15 -13
- package/src/__tests__/onboarding-persona-write.test.ts +52 -22
- package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
- package/src/__tests__/persona-resolver.test.ts +75 -45
- package/src/__tests__/plugin-bootstrap.test.ts +13 -5
- package/src/__tests__/plugin-disabled-state.test.ts +190 -0
- package/src/__tests__/provider-usage-tracking.test.ts +1 -1
- package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +135 -0
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
- package/src/__tests__/reaction-persistence.test.ts +51 -4
- package/src/__tests__/relay-server.test.ts +88 -31
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -11
- package/src/__tests__/settings-routes.test.ts +32 -0
- package/src/__tests__/slack-block-formatting.test.ts +1 -38
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +13 -36
- package/src/__tests__/stt-hints.test.ts +6 -3
- package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
- package/src/__tests__/subagent-role-registry.test.ts +17 -4
- package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
- package/src/__tests__/subagent-tools.test.ts +398 -3
- package/src/__tests__/thread-backfill.test.ts +3 -3
- package/src/__tests__/tool-preview-lifecycle.test.ts +26 -10
- package/src/__tests__/tool-start-timestamp.test.ts +4 -3
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +37 -51
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -2
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -7
- package/src/__tests__/trusted-contact-multichannel.test.ts +16 -7
- package/src/__tests__/trusted-contact-verification.test.ts +79 -54
- package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
- package/src/__tests__/voice-invite-redemption.test.ts +183 -20
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +2 -2
- package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +196 -238
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +35 -47
- package/src/agent/loop-exclusive-tool.test.ts +19 -15
- package/src/agent/loop-native-web-search.test.ts +200 -0
- package/src/agent/loop.ts +108 -1
- package/src/api/responses/conversation-message.ts +9 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -4
- package/src/calls/__tests__/relay-setup-router.test.ts +10 -18
- package/src/calls/guardian-dispatch.ts +14 -11
- package/src/calls/inbound-trust-reader.ts +7 -1
- package/src/calls/relay-access-wait.ts +6 -6
- package/src/calls/relay-server.ts +22 -2
- package/src/calls/relay-setup-router.ts +10 -10
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
- package/src/cli/commands/contacts.ts +10 -7
- package/src/cli/commands/memory/__tests__/worker.test.ts +147 -17
- package/src/cli/commands/memory/worker.ts +97 -30
- package/src/cli/commands/plugins.ts +3 -146
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +17 -17
- package/src/cli/lib/__tests__/publish-plugin.test.ts +98 -0
- package/src/cli/lib/publish-plugin.ts +231 -1
- package/src/config/__tests__/sync-gated-profiles.test.ts +5 -7
- package/src/config/bundled-skills/subagent/SKILL.md +16 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
- package/src/config/call-site-defaults.ts +0 -6
- package/src/config/llm-resolver.ts +0 -3
- package/src/config/schemas/call-site-catalog.ts +0 -7
- package/src/config/schemas/heartbeat.ts +2 -5
- package/src/config/schemas/llm.ts +3 -12
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/seed-inference-profiles.ts +76 -35
- package/src/config/sync-gated-profiles.ts +0 -3
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +7 -8
- package/src/contacts/__tests__/member-write-relay.test.ts +35 -11
- package/src/contacts/contact-store.ts +27 -237
- package/src/contacts/contacts-write.ts +18 -58
- package/src/contacts/gateway-channel-read.ts +51 -0
- package/src/contacts/member-write-relay.ts +25 -31
- package/src/contacts/types.ts +3 -15
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
- package/src/daemon/conversation-agent-loop-handlers.ts +29 -10
- package/src/daemon/conversation-agent-loop.ts +68 -61
- package/src/daemon/conversation-error.ts +7 -10
- package/src/daemon/conversation-tool-setup.ts +0 -10
- package/src/daemon/conversation.ts +10 -0
- package/src/daemon/external-plugins-bootstrap.ts +8 -2
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -2
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -2
- package/src/daemon/handlers/__tests__/config-channels.test.ts +9 -14
- package/src/daemon/handlers/config-channels.ts +14 -29
- package/src/daemon/lifecycle.ts +16 -4
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/heartbeat/heartbeat-service.ts +5 -0
- package/src/home/relationship-state-writer.ts +5 -0
- package/src/memory/__tests__/embedding-cache.test.ts +136 -0
- package/src/memory/compaction-ledger-store.ts +107 -0
- package/src/memory/conversation-crud.ts +136 -61
- package/src/memory/conversation-title-service.ts +173 -24
- package/src/memory/embedding-backend.ts +8 -1
- package/src/memory/embedding-cache.ts +139 -0
- package/src/memory/jobs-worker.ts +75 -29
- package/src/memory/memory-retrospective-job.ts +5 -0
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +27 -5
- package/src/memory/migrations/302-create-compaction-events.ts +107 -0
- package/src/memory/migrations/303-add-conversation-creation-seq.ts +33 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +79 -6
- package/src/memory/schema/contacts.ts +6 -2
- package/src/memory/schema/conversations.ts +39 -0
- package/src/memory/steps.ts +1090 -367
- package/src/memory/worker-control.ts +104 -18
- package/src/memory/worker-process.ts +17 -0
- package/src/messaging/channel-binding-metadata.ts +31 -0
- package/src/messaging/channel-binding-schema.ts +51 -0
- package/src/messaging/providers/__tests__/callback-routing.test.ts +45 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +195 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +11 -0
- package/src/messaging/providers/a2a/deliver.ts +5 -1
- package/src/messaging/providers/a2a/transport.ts +10 -0
- package/src/messaging/providers/callback-routing.ts +48 -0
- package/src/messaging/providers/channel-transport.ts +55 -0
- package/src/messaging/providers/index.ts +65 -241
- package/src/messaging/providers/slack/binding-metadata.ts +62 -0
- package/src/messaging/providers/slack/transport.ts +92 -0
- package/src/messaging/providers/telegram-bot/transport.ts +51 -0
- package/src/messaging/providers/whatsapp/transport.ts +38 -0
- package/src/notifications/__tests__/broadcaster.test.ts +0 -8
- package/src/notifications/__tests__/connected-channels.test.ts +8 -36
- package/src/notifications/__tests__/destination-resolver.test.ts +12 -117
- package/src/notifications/destination-resolver.ts +7 -23
- package/src/notifications/emit-signal.ts +5 -11
- package/src/plugins/defaults/index.ts +0 -35
- package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +11 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +243 -2
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +167 -14
- package/src/plugins/disabled-state.ts +31 -0
- package/src/plugins/registry.ts +55 -12
- package/src/prompts/persona-resolver.ts +43 -11
- package/src/providers/call-site-routing.ts +41 -0
- package/src/providers/provider-send-message.ts +6 -0
- package/src/providers/ratelimit.ts +6 -0
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +6 -0
- package/src/providers/types.ts +13 -0
- package/src/providers/usage-tracking.ts +6 -0
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +30 -27
- package/src/runtime/__tests__/local-principal-trust.test.ts +16 -18
- package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +115 -168
- package/src/runtime/access-request-helper.ts +1 -2
- package/src/runtime/actor-trust-resolver.ts +44 -17
- package/src/runtime/anchored-guardian.test.ts +7 -54
- package/src/runtime/anchored-guardian.ts +4 -53
- package/src/runtime/assistant-stream-state.ts +12 -74
- package/src/runtime/channel-reply-delivery.ts +3 -8
- package/src/runtime/guardian-vellum-migration.ts +18 -16
- package/src/runtime/invite-redemption-service.ts +25 -10
- package/src/runtime/local-actor-identity.test.ts +108 -0
- package/src/runtime/local-actor-identity.ts +27 -20
- package/src/runtime/member-verdict-cache.ts +0 -0
- package/src/runtime/routes/__tests__/contact-routes.test.ts +100 -7
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +1 -2
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +2 -1
- package/src/runtime/routes/contact-routes.ts +40 -25
- package/src/runtime/routes/conversation-list-routes.ts +1 -29
- package/src/runtime/routes/conversation-routes.ts +27 -7
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -10
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +19 -0
- package/src/runtime/routes/settings-routes.ts +8 -3
- package/src/runtime/services/conversation-serializer.ts +6 -49
- package/src/runtime/slack-block-formatting.ts +0 -15
- package/src/runtime/trust-verdict-consumer.ts +36 -41
- package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
- package/src/{plugins/defaults/advisor/__tests__/transcript.test.ts → subagent/__tests__/consult-transcript.test.ts} +47 -10
- package/src/{plugins/defaults/advisor/steering.ts → subagent/consult-prompt.ts} +17 -39
- package/src/{plugins/defaults/advisor/transcript.ts → subagent/consult-transcript.ts} +18 -8
- package/src/subagent/index.ts +1 -1
- package/src/subagent/manager.ts +245 -33
- package/src/subagent/types.ts +8 -1
- package/src/tools/registry.ts +10 -3
- package/src/tools/subagent/consult-deadline.ts +49 -0
- package/src/tools/subagent/spawn.ts +234 -5
- package/src/util/logger.ts +9 -0
- package/src/util/platform.ts +14 -0
- package/src/workspace/migrations/031-drop-user-md.ts +232 -148
- package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -314
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
- package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
- package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
- package/src/plugins/defaults/advisor/config.ts +0 -21
- package/src/plugins/defaults/advisor/consult.ts +0 -197
- package/src/plugins/defaults/advisor/context-pack.ts +0 -288
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/advisor/package.json +0 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +0 -92
|
@@ -7,18 +7,31 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Subcommands:
|
|
9
9
|
*
|
|
10
|
-
* - `start` — spawn the worker process
|
|
11
|
-
*
|
|
12
|
-
* - `
|
|
10
|
+
* - `start` — spawn the worker process and enable `memory.worker.enabled`,
|
|
11
|
+
* standing the daemon's synchronous in-process runner down.
|
|
12
|
+
* - `stop` — SIGTERM the worker process and disable `memory.worker.enabled`,
|
|
13
|
+
* handing the queue back to the synchronous in-process runner.
|
|
14
|
+
* - `status` — report the worker process state, the `memory.worker.enabled`
|
|
15
|
+
* config value, and whether the synchronous in-process runner is going.
|
|
13
16
|
*
|
|
14
17
|
* All three run directly in the CLI process (transport: "local") — no IPC
|
|
15
|
-
* round-trip to the daemon.
|
|
18
|
+
* round-trip to the daemon. The daemon's worker supervisor re-reads
|
|
19
|
+
* `memory.worker.enabled` each poll and stands its synchronous runner down (or
|
|
20
|
+
* resumes it) accordingly, so flipping the flag here switches the running
|
|
21
|
+
* daemon's mode without a restart.
|
|
16
22
|
*/
|
|
17
23
|
|
|
18
24
|
import type { Command } from "commander";
|
|
19
25
|
|
|
26
|
+
import {
|
|
27
|
+
getConfigReadOnly,
|
|
28
|
+
loadRawConfig,
|
|
29
|
+
saveRawConfig,
|
|
30
|
+
setNestedValue,
|
|
31
|
+
} from "../../../config/loader.js";
|
|
20
32
|
import {
|
|
21
33
|
probeMemoryWorker,
|
|
34
|
+
probeSyncRunner,
|
|
22
35
|
spawnMemoryWorkerProcess,
|
|
23
36
|
} from "../../../memory/worker-control.js";
|
|
24
37
|
import { getMemoryWorkerPidPath } from "../../../util/platform.js";
|
|
@@ -26,6 +39,17 @@ import { registerCommand } from "../../lib/register-command.js";
|
|
|
26
39
|
import { log } from "../../logger.js";
|
|
27
40
|
import { shouldOutputJson, writeOutput } from "../../output.js";
|
|
28
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Persist `memory.worker.enabled` to the on-disk config via the shared
|
|
44
|
+
* raw-config helpers, so only this leaf changes (schema defaults are not baked
|
|
45
|
+
* into the file). The assistant picks the change up on its next config read.
|
|
46
|
+
*/
|
|
47
|
+
function setWorkerEnabled(enabled: boolean): void {
|
|
48
|
+
const raw = loadRawConfig();
|
|
49
|
+
setNestedValue(raw, "memory.worker.enabled", enabled);
|
|
50
|
+
saveRawConfig(raw);
|
|
51
|
+
}
|
|
52
|
+
|
|
29
53
|
// ---------------------------------------------------------------------------
|
|
30
54
|
// `start`
|
|
31
55
|
// ---------------------------------------------------------------------------
|
|
@@ -38,6 +62,9 @@ async function startWorker(
|
|
|
38
62
|
try {
|
|
39
63
|
result = await spawnMemoryWorkerProcess();
|
|
40
64
|
} catch (err) {
|
|
65
|
+
// Spawn failed — leave `memory.worker.enabled` untouched so the daemon's
|
|
66
|
+
// synchronous runner keeps draining the queue rather than standing down
|
|
67
|
+
// for a worker that never came up.
|
|
41
68
|
const msg = err instanceof Error ? err.message : String(err);
|
|
42
69
|
if (shouldOutputJson(cmd)) {
|
|
43
70
|
writeOutput(cmd, { ok: false, error: msg });
|
|
@@ -48,25 +75,28 @@ async function startWorker(
|
|
|
48
75
|
return;
|
|
49
76
|
}
|
|
50
77
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} else {
|
|
56
|
-
log.error(msg);
|
|
57
|
-
}
|
|
58
|
-
process.exitCode = 1;
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
78
|
+
// The worker process is up (freshly spawned or already running). Enable the
|
|
79
|
+
// flag so the daemon's supervisor stands its synchronous runner down (and so
|
|
80
|
+
// the daemon spawns the worker again on the next restart).
|
|
81
|
+
setWorkerEnabled(true);
|
|
61
82
|
|
|
62
83
|
if (shouldOutputJson(cmd)) {
|
|
63
84
|
writeOutput(cmd, {
|
|
64
85
|
ok: true,
|
|
65
86
|
pid: result.pid,
|
|
87
|
+
alreadyRunning: result.alreadyRunning,
|
|
66
88
|
pidPath: getMemoryWorkerPidPath(),
|
|
89
|
+
workerEnabled: true,
|
|
67
90
|
});
|
|
68
91
|
} else {
|
|
69
|
-
log.info(
|
|
92
|
+
log.info(
|
|
93
|
+
result.alreadyRunning
|
|
94
|
+
? `Memory worker is already running (PID ${result.pid})`
|
|
95
|
+
: `Memory worker started (PID ${result.pid})`,
|
|
96
|
+
);
|
|
97
|
+
log.info(
|
|
98
|
+
"Enabled memory.worker.enabled; the synchronous in-process runner will stand down",
|
|
99
|
+
);
|
|
70
100
|
}
|
|
71
101
|
}
|
|
72
102
|
|
|
@@ -75,15 +105,28 @@ async function startWorker(
|
|
|
75
105
|
// ---------------------------------------------------------------------------
|
|
76
106
|
|
|
77
107
|
function stopWorker(opts: { json?: boolean }, cmd: Command): void {
|
|
108
|
+
// Persist the preference first: `stop` means "hand the queue back to the
|
|
109
|
+
// synchronous in-process runner." Disabling the flag makes the daemon's
|
|
110
|
+
// supervisor resume processing in-process on its next poll and lines the next
|
|
111
|
+
// daemon restart up with synchronous mode; the SIGTERM below then stops the
|
|
112
|
+
// now-redundant worker process.
|
|
113
|
+
setWorkerEnabled(false);
|
|
114
|
+
|
|
78
115
|
const current = probeMemoryWorker();
|
|
79
116
|
if (current.status !== "running" || current.pid == null) {
|
|
80
|
-
|
|
117
|
+
// No worker process to signal — flipping the flag alone restores
|
|
118
|
+
// synchronous mode, so this is success, not an error.
|
|
81
119
|
if (shouldOutputJson(cmd)) {
|
|
82
|
-
writeOutput(cmd, {
|
|
120
|
+
writeOutput(cmd, {
|
|
121
|
+
ok: true,
|
|
122
|
+
workerWasRunning: false,
|
|
123
|
+
workerEnabled: false,
|
|
124
|
+
});
|
|
83
125
|
} else {
|
|
84
|
-
log.
|
|
126
|
+
log.info(
|
|
127
|
+
"Memory worker process was not running; disabled memory.worker.enabled (synchronous runner active)",
|
|
128
|
+
);
|
|
85
129
|
}
|
|
86
|
-
process.exitCode = 1;
|
|
87
130
|
return;
|
|
88
131
|
}
|
|
89
132
|
|
|
@@ -93,7 +136,7 @@ function stopWorker(opts: { json?: boolean }, cmd: Command): void {
|
|
|
93
136
|
} catch (err) {
|
|
94
137
|
const msg = err instanceof Error ? err.message : String(err);
|
|
95
138
|
if (shouldOutputJson(cmd)) {
|
|
96
|
-
writeOutput(cmd, { ok: false, error: msg, pid });
|
|
139
|
+
writeOutput(cmd, { ok: false, error: msg, pid, workerEnabled: false });
|
|
97
140
|
} else {
|
|
98
141
|
log.error(`Failed to stop memory worker (PID ${pid}): ${msg}`);
|
|
99
142
|
}
|
|
@@ -102,9 +145,12 @@ function stopWorker(opts: { json?: boolean }, cmd: Command): void {
|
|
|
102
145
|
}
|
|
103
146
|
|
|
104
147
|
if (shouldOutputJson(cmd)) {
|
|
105
|
-
writeOutput(cmd, { ok: true, pid });
|
|
148
|
+
writeOutput(cmd, { ok: true, pid, workerEnabled: false });
|
|
106
149
|
} else {
|
|
107
150
|
log.info(`Memory worker stop signal sent (PID ${pid})`);
|
|
151
|
+
log.info(
|
|
152
|
+
"Disabled memory.worker.enabled; the synchronous in-process runner will take over",
|
|
153
|
+
);
|
|
108
154
|
}
|
|
109
155
|
}
|
|
110
156
|
|
|
@@ -113,14 +159,25 @@ function stopWorker(opts: { json?: boolean }, cmd: Command): void {
|
|
|
113
159
|
// ---------------------------------------------------------------------------
|
|
114
160
|
|
|
115
161
|
function statusWorker(opts: { json?: boolean }, cmd: Command): void {
|
|
116
|
-
const
|
|
162
|
+
const worker = probeMemoryWorker();
|
|
163
|
+
const syncRunner = probeSyncRunner();
|
|
164
|
+
const workerEnabled = getConfigReadOnly().memory.worker.enabled;
|
|
165
|
+
|
|
117
166
|
if (shouldOutputJson(cmd)) {
|
|
118
|
-
writeOutput(cmd,
|
|
167
|
+
writeOutput(cmd, { ...worker, workerEnabled, syncRunner });
|
|
119
168
|
} else {
|
|
120
|
-
if (
|
|
121
|
-
log.info(`Memory worker is running (PID ${
|
|
169
|
+
if (worker.status === "running") {
|
|
170
|
+
log.info(`Memory worker process is running (PID ${worker.pid})`);
|
|
122
171
|
} else {
|
|
123
|
-
log.info("Memory worker is not running");
|
|
172
|
+
log.info("Memory worker process is not running");
|
|
173
|
+
}
|
|
174
|
+
log.info(`memory.worker.enabled: ${workerEnabled}`);
|
|
175
|
+
if (syncRunner.status === "running") {
|
|
176
|
+
log.info(
|
|
177
|
+
`Synchronous in-process runner is running (PID ${syncRunner.pid})`,
|
|
178
|
+
);
|
|
179
|
+
} else {
|
|
180
|
+
log.info("Synchronous in-process runner is not running");
|
|
124
181
|
}
|
|
125
182
|
}
|
|
126
183
|
}
|
|
@@ -139,7 +196,11 @@ export function registerMemoryWorkerCommand(memory: Command): void {
|
|
|
139
196
|
"after",
|
|
140
197
|
`
|
|
141
198
|
The memory worker processes embedding, consolidation, and cleanup jobs in a
|
|
142
|
-
separate OS process so they do not block the
|
|
199
|
+
separate OS process so they do not block the assistant's main event loop.
|
|
200
|
+
|
|
201
|
+
\`start\` enables memory.worker.enabled and \`stop\` disables it, so the
|
|
202
|
+
assistant's synchronous in-process runner stands down (start) or takes back over
|
|
203
|
+
(stop) without a restart.
|
|
143
204
|
|
|
144
205
|
Examples:
|
|
145
206
|
$ assistant memory worker start
|
|
@@ -149,7 +210,9 @@ Examples:
|
|
|
149
210
|
|
|
150
211
|
worker
|
|
151
212
|
.command("start")
|
|
152
|
-
.description(
|
|
213
|
+
.description(
|
|
214
|
+
"Start the memory worker process and enable memory.worker.enabled",
|
|
215
|
+
)
|
|
153
216
|
.option("--json", "Emit raw JSON instead of a formatted summary")
|
|
154
217
|
.action(async (opts: { json?: boolean }, cmd: Command) => {
|
|
155
218
|
await startWorker(opts, cmd);
|
|
@@ -157,7 +220,9 @@ Examples:
|
|
|
157
220
|
|
|
158
221
|
worker
|
|
159
222
|
.command("stop")
|
|
160
|
-
.description(
|
|
223
|
+
.description(
|
|
224
|
+
"Stop the memory worker process and disable memory.worker.enabled",
|
|
225
|
+
)
|
|
161
226
|
.option("--json", "Emit raw JSON instead of a formatted summary")
|
|
162
227
|
.action((opts: { json?: boolean }, cmd: Command) => {
|
|
163
228
|
stopWorker(opts, cmd);
|
|
@@ -165,7 +230,9 @@ Examples:
|
|
|
165
230
|
|
|
166
231
|
worker
|
|
167
232
|
.command("status")
|
|
168
|
-
.description(
|
|
233
|
+
.description(
|
|
234
|
+
"Report worker process state, memory.worker.enabled, and the synchronous runner",
|
|
235
|
+
)
|
|
169
236
|
.option("--json", "Emit raw JSON instead of a formatted summary")
|
|
170
237
|
.action((opts: { json?: boolean }, cmd: Command) => {
|
|
171
238
|
statusWorker(opts, cmd);
|
|
@@ -42,17 +42,7 @@ import {
|
|
|
42
42
|
PluginPinHistoryError,
|
|
43
43
|
resolvePinToMarketplaceCommit,
|
|
44
44
|
} from "../lib/plugin-pin-history.js";
|
|
45
|
-
import {
|
|
46
|
-
buildPublishPayload,
|
|
47
|
-
findPluginRoot,
|
|
48
|
-
formatPayloadForPrint,
|
|
49
|
-
formatPublishResult,
|
|
50
|
-
formatValidationResult,
|
|
51
|
-
postPublishRequest,
|
|
52
|
-
resolveGitContext,
|
|
53
|
-
resolvePlatformDeps,
|
|
54
|
-
validatePluginForPublish,
|
|
55
|
-
} from "../lib/publish-plugin.js";
|
|
45
|
+
import { runPublish } from "../lib/publish-plugin.js";
|
|
56
46
|
import { registerCommand } from "../lib/register-command.js";
|
|
57
47
|
import {
|
|
58
48
|
InvalidSearchPatternError,
|
|
@@ -561,141 +551,8 @@ $ assistant plugins publish --json`,
|
|
|
561
551
|
json?: boolean;
|
|
562
552
|
category?: string;
|
|
563
553
|
}) => {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const pluginDir = findPluginRoot(searchDir);
|
|
567
|
-
if (!pluginDir) {
|
|
568
|
-
console.error(
|
|
569
|
-
`No package.json found in ${searchDir} or any parent directory.`,
|
|
570
|
-
);
|
|
571
|
-
process.exitCode = 1;
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// 2. Validate the plugin
|
|
576
|
-
const validation = validatePluginForPublish(pluginDir);
|
|
577
|
-
if (!validation.valid) {
|
|
578
|
-
if (opts.json) {
|
|
579
|
-
process.stdout.write(
|
|
580
|
-
JSON.stringify({ ok: false, errors: validation.issues }) +
|
|
581
|
-
"\n",
|
|
582
|
-
);
|
|
583
|
-
} else {
|
|
584
|
-
console.error(formatValidationResult(validation));
|
|
585
|
-
}
|
|
586
|
-
process.exitCode = 1;
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (!opts.json && validation.warnings.length > 0) {
|
|
591
|
-
console.warn(formatValidationResult(validation));
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
// 3. Resolve git context
|
|
595
|
-
let git;
|
|
596
|
-
try {
|
|
597
|
-
git = await resolveGitContext(pluginDir);
|
|
598
|
-
} catch (err) {
|
|
599
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
600
|
-
console.error(`Git context resolution failed: ${message}`);
|
|
601
|
-
process.exitCode = 1;
|
|
602
|
-
return;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
if (git.dirty) {
|
|
606
|
-
console.warn(
|
|
607
|
-
"Warning: working tree is dirty. The pinned commit SHA should match a clean, pushed commit.",
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
if (!git.pushed) {
|
|
612
|
-
console.error(
|
|
613
|
-
`Commit ${git.sha.slice(0, 7)} has not been pushed to the remote. Push your changes first.`,
|
|
614
|
-
);
|
|
615
|
-
process.exitCode = 1;
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// 4. Determine category
|
|
620
|
-
const category = opts.category ?? "other";
|
|
621
|
-
|
|
622
|
-
// 5. Build the payload
|
|
623
|
-
const payload = buildPublishPayload(validation, git, category);
|
|
624
|
-
|
|
625
|
-
// 6. Handle --print mode
|
|
626
|
-
if (opts.print) {
|
|
627
|
-
if (opts.json) {
|
|
628
|
-
process.stdout.write(
|
|
629
|
-
JSON.stringify({ ok: true, payload }) + "\n",
|
|
630
|
-
);
|
|
631
|
-
} else {
|
|
632
|
-
console.log(formatPayloadForPrint(payload));
|
|
633
|
-
}
|
|
634
|
-
return;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
// 7. Confirm before submitting (unless --force or --json)
|
|
638
|
-
if (!opts.force && !opts.json) {
|
|
639
|
-
console.log("\nPlugin entry to submit:");
|
|
640
|
-
console.log(formatPayloadForPrint(payload));
|
|
641
|
-
console.log("");
|
|
642
|
-
const result = await confirmPrompt({
|
|
643
|
-
question: "Submit this entry to the Vellum marketplace? [y/N] ",
|
|
644
|
-
isTTY: Boolean(process.stdin.isTTY),
|
|
645
|
-
refuseNonInteractiveMessage:
|
|
646
|
-
"Refusing to publish non-interactively. Pass --force to confirm.",
|
|
647
|
-
});
|
|
648
|
-
if (result === "non-interactive") {
|
|
649
|
-
process.exitCode = 1;
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
// 8. Submit to the platform API
|
|
655
|
-
const deps = await resolvePlatformDeps();
|
|
656
|
-
if (!deps) {
|
|
657
|
-
const msg =
|
|
658
|
-
"Not connected to Vellum platform. Run `assistant platform connect` to connect, or use --print to generate the entry without submitting.";
|
|
659
|
-
if (opts.json) {
|
|
660
|
-
process.stdout.write(
|
|
661
|
-
JSON.stringify({
|
|
662
|
-
ok: false,
|
|
663
|
-
error: "not_connected",
|
|
664
|
-
message: msg,
|
|
665
|
-
}) + "\n",
|
|
666
|
-
);
|
|
667
|
-
} else {
|
|
668
|
-
console.error(msg);
|
|
669
|
-
}
|
|
670
|
-
process.exitCode = 1;
|
|
671
|
-
return;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
try {
|
|
675
|
-
const result = await postPublishRequest(payload, deps);
|
|
676
|
-
|
|
677
|
-
if (opts.json) {
|
|
678
|
-
process.stdout.write(JSON.stringify(result) + "\n");
|
|
679
|
-
} else {
|
|
680
|
-
console.log(formatPublishResult(result));
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
if (!result.ok) process.exitCode = 1;
|
|
684
|
-
} catch (err) {
|
|
685
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
686
|
-
if (opts.json) {
|
|
687
|
-
process.stdout.write(
|
|
688
|
-
JSON.stringify({
|
|
689
|
-
ok: false,
|
|
690
|
-
error: "request_failed",
|
|
691
|
-
message,
|
|
692
|
-
}) + "\n",
|
|
693
|
-
);
|
|
694
|
-
} else {
|
|
695
|
-
console.error(`Publish request failed: ${message}`);
|
|
696
|
-
}
|
|
697
|
-
process.exitCode = 1;
|
|
698
|
-
}
|
|
554
|
+
const ok = await runPublish(opts, { confirmPrompt });
|
|
555
|
+
if (!ok) process.exitCode = 1;
|
|
699
556
|
},
|
|
700
557
|
);
|
|
701
558
|
|
|
@@ -157,8 +157,8 @@ describe("listAllPlugins", () => {
|
|
|
157
157
|
test("includes default plugins with source=default", () => {
|
|
158
158
|
const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
|
|
159
159
|
const defaults = result.filter((p) => p.source === "default");
|
|
160
|
-
// All
|
|
161
|
-
expect(defaults.length).toBe(
|
|
160
|
+
// All 14 default plugins should be present.
|
|
161
|
+
expect(defaults.length).toBe(14);
|
|
162
162
|
// Names should all start with "default-".
|
|
163
163
|
expect(defaults.every((p) => p.name.startsWith("default-"))).toBe(true);
|
|
164
164
|
// None should be disabled by default in a fresh temp dir.
|
|
@@ -212,24 +212,24 @@ describe("listAllPlugins", () => {
|
|
|
212
212
|
});
|
|
213
213
|
|
|
214
214
|
test("detects disabled state for default plugins via stub directory", () => {
|
|
215
|
-
mkdirSync(join(pluginsDir, "default-
|
|
216
|
-
writeFileSync(join(pluginsDir, "default-
|
|
215
|
+
mkdirSync(join(pluginsDir, "default-compaction"), { recursive: true });
|
|
216
|
+
writeFileSync(join(pluginsDir, "default-compaction", ".disabled"), "");
|
|
217
217
|
|
|
218
218
|
const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
|
|
219
|
-
const
|
|
220
|
-
expect(
|
|
221
|
-
expect(
|
|
219
|
+
const compaction = result.find((p) => p.name === "default-compaction");
|
|
220
|
+
expect(compaction).toBeDefined();
|
|
221
|
+
expect(compaction!.disabled).toBe(true);
|
|
222
222
|
});
|
|
223
223
|
|
|
224
224
|
test("default stub directory is excluded from user listing", () => {
|
|
225
|
-
mkdirSync(join(pluginsDir, "default-
|
|
226
|
-
writeFileSync(join(pluginsDir, "default-
|
|
225
|
+
mkdirSync(join(pluginsDir, "default-compaction"), { recursive: true });
|
|
226
|
+
writeFileSync(join(pluginsDir, "default-compaction", ".disabled"), "");
|
|
227
227
|
|
|
228
228
|
const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
|
|
229
229
|
// Should appear exactly once, as a default entry (not a user entry).
|
|
230
|
-
const
|
|
231
|
-
expect(
|
|
232
|
-
expect(
|
|
230
|
+
const compactionEntries = result.filter((p) => p.name === "default-compaction");
|
|
231
|
+
expect(compactionEntries).toHaveLength(1);
|
|
232
|
+
expect(compactionEntries[0]!.source).toBe("default");
|
|
233
233
|
});
|
|
234
234
|
|
|
235
235
|
test("sort order: enabled user, disabled user, enabled default, disabled default", () => {
|
|
@@ -247,8 +247,8 @@ describe("listAllPlugins", () => {
|
|
|
247
247
|
writeFileSync(join(pluginsDir, "bbb-disabled", ".disabled"), "");
|
|
248
248
|
|
|
249
249
|
// Disable one default plugin
|
|
250
|
-
mkdirSync(join(pluginsDir, "default-
|
|
251
|
-
writeFileSync(join(pluginsDir, "default-
|
|
250
|
+
mkdirSync(join(pluginsDir, "default-compaction"), { recursive: true });
|
|
251
|
+
writeFileSync(join(pluginsDir, "default-compaction", ".disabled"), "");
|
|
252
252
|
|
|
253
253
|
const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
|
|
254
254
|
|
|
@@ -306,8 +306,8 @@ describe("listAllPlugins", () => {
|
|
|
306
306
|
|
|
307
307
|
test("default plugins have version from their manifest", () => {
|
|
308
308
|
const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
|
|
309
|
-
const
|
|
310
|
-
expect(
|
|
311
|
-
expect(
|
|
309
|
+
const compaction = result.find((p) => p.name === "default-compaction");
|
|
310
|
+
expect(compaction).toBeDefined();
|
|
311
|
+
expect(compaction!.packageJson?.version).toBeTruthy();
|
|
312
312
|
});
|
|
313
313
|
});
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
formatValidationResult,
|
|
12
12
|
type ParsedPackageJson,
|
|
13
13
|
type PublishValidation,
|
|
14
|
+
runPublish,
|
|
14
15
|
validatePluginForPublish,
|
|
15
16
|
} from "../publish-plugin.js";
|
|
16
17
|
|
|
@@ -200,6 +201,7 @@ describe("buildPublishPayload", () => {
|
|
|
200
201
|
repo: "me/my-plugin",
|
|
201
202
|
dirty: false,
|
|
202
203
|
pushed: true,
|
|
204
|
+
pluginPath: "",
|
|
203
205
|
};
|
|
204
206
|
|
|
205
207
|
const payload = buildPublishPayload(validation, git, "productivity");
|
|
@@ -208,12 +210,37 @@ describe("buildPublishPayload", () => {
|
|
|
208
210
|
expect(payload.source.source).toBe("github");
|
|
209
211
|
expect(payload.source.repo).toBe("me/my-plugin");
|
|
210
212
|
expect(payload.source.ref).toBe("e83c5163316f89bfbde7d9ab23ca2e25604af290");
|
|
213
|
+
expect(payload.source.path).toBeUndefined();
|
|
211
214
|
expect(payload.category).toBe("productivity");
|
|
212
215
|
expect(payload.description).toBe("Does cool stuff");
|
|
213
216
|
expect(payload.license).toBe("MIT");
|
|
214
217
|
expect(payload.homepage).toBe("https://github.com/me/my-plugin");
|
|
215
218
|
});
|
|
216
219
|
|
|
220
|
+
it("sets source.path for nested plugin roots", () => {
|
|
221
|
+
const validation: PublishValidation = {
|
|
222
|
+
valid: true,
|
|
223
|
+
issues: [],
|
|
224
|
+
warnings: [],
|
|
225
|
+
packageJson: {
|
|
226
|
+
name: "my-plugin",
|
|
227
|
+
version: "1.0.0",
|
|
228
|
+
peerDependencies: { "@vellumai/plugin-api": "^1.0.0" },
|
|
229
|
+
},
|
|
230
|
+
pluginDir: "/tmp/monorepo/packages/plugin",
|
|
231
|
+
};
|
|
232
|
+
const git = {
|
|
233
|
+
sha: "e83c5163316f89bfbde7d9ab23ca2e25604af290",
|
|
234
|
+
repo: "me/monorepo",
|
|
235
|
+
dirty: false,
|
|
236
|
+
pushed: true,
|
|
237
|
+
pluginPath: "packages/plugin",
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const payload = buildPublishPayload(validation, git, "other");
|
|
241
|
+
expect(payload.source.path).toBe("packages/plugin");
|
|
242
|
+
});
|
|
243
|
+
|
|
217
244
|
it("extracts homepage from repository.url when homepage is absent", () => {
|
|
218
245
|
const validation: PublishValidation = {
|
|
219
246
|
valid: true,
|
|
@@ -232,6 +259,7 @@ describe("buildPublishPayload", () => {
|
|
|
232
259
|
repo: "me/my-plugin",
|
|
233
260
|
dirty: false,
|
|
234
261
|
pushed: true,
|
|
262
|
+
pluginPath: "",
|
|
235
263
|
};
|
|
236
264
|
|
|
237
265
|
const payload = buildPublishPayload(validation, git, "other");
|
|
@@ -304,3 +332,73 @@ describe("formatValidationResult", () => {
|
|
|
304
332
|
expect(result).toContain("passed");
|
|
305
333
|
});
|
|
306
334
|
});
|
|
335
|
+
|
|
336
|
+
// ---------------------------------------------------------------------------
|
|
337
|
+
// runPublish (CLI entrypoint)
|
|
338
|
+
// ---------------------------------------------------------------------------
|
|
339
|
+
|
|
340
|
+
describe("runPublish", () => {
|
|
341
|
+
it("returns false on denied confirmation without submitting", async () => {
|
|
342
|
+
const dir = makePluginDir(tmpdir(), validPkg, { hooks: true });
|
|
343
|
+
// Initialize a git repo so resolveGitContext doesn't fail
|
|
344
|
+
const { execSync } = await import("node:child_process");
|
|
345
|
+
const gitEnv = {
|
|
346
|
+
...process.env,
|
|
347
|
+
GIT_AUTHOR_NAME: "Test",
|
|
348
|
+
GIT_AUTHOR_EMAIL: "test@test.com",
|
|
349
|
+
GIT_COMMITTER_NAME: "Test",
|
|
350
|
+
GIT_COMMITTER_EMAIL: "test@test.com",
|
|
351
|
+
};
|
|
352
|
+
execSync("git init && git add -A && git commit -m init", {
|
|
353
|
+
cwd: dir,
|
|
354
|
+
stdio: "ignore",
|
|
355
|
+
env: gitEnv,
|
|
356
|
+
});
|
|
357
|
+
execSync("git remote add origin https://github.com/test/test-plugin.git", {
|
|
358
|
+
cwd: dir,
|
|
359
|
+
stdio: "ignore",
|
|
360
|
+
env: gitEnv,
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
const ok = await runPublish(
|
|
364
|
+
{ path: dir, force: false, json: false },
|
|
365
|
+
{
|
|
366
|
+
confirmPrompt: async () => "denied",
|
|
367
|
+
},
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
expect(ok).toBe(false);
|
|
371
|
+
rmSync(dir, { recursive: true });
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("returns true on --print without submitting", async () => {
|
|
375
|
+
const dir = makePluginDir(tmpdir(), validPkg, { hooks: true });
|
|
376
|
+
|
|
377
|
+
const ok = await runPublish(
|
|
378
|
+
{ path: dir, print: true, json: true },
|
|
379
|
+
{
|
|
380
|
+
confirmPrompt: async () => {
|
|
381
|
+
throw new Error("should not be called");
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
expect(ok).toBe(true);
|
|
387
|
+
rmSync(dir, { recursive: true });
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("returns false when no package.json found", async () => {
|
|
391
|
+
const dir = mkdtempSync(join(tmpdir(), "no-pkg-"));
|
|
392
|
+
const ok = await runPublish(
|
|
393
|
+
{ path: dir, force: true, json: true },
|
|
394
|
+
{
|
|
395
|
+
confirmPrompt: async () => {
|
|
396
|
+
throw new Error("should not be called");
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
expect(ok).toBe(false);
|
|
402
|
+
rmSync(dir, { recursive: true });
|
|
403
|
+
});
|
|
404
|
+
});
|