@vellumai/assistant 0.6.0 → 0.6.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/AGENTS.md +4 -0
- package/ARCHITECTURE.md +68 -15
- package/Dockerfile +2 -2
- package/bun.lock +6 -2
- package/docker-entrypoint.sh +42 -1
- package/docs/architecture/integrations.md +1 -1
- package/docs/architecture/memory.md +21 -24
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
- package/openapi.yaml +539 -4
- package/package.json +5 -1
- package/src/__tests__/anthropic-provider.test.ts +160 -95
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +47 -1
- package/src/__tests__/app-source-watcher.test.ts +159 -0
- package/src/__tests__/assistant-event-hub.test.ts +30 -0
- package/src/__tests__/checker.test.ts +138 -172
- package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +5 -0
- package/src/__tests__/context-overflow-approval.test.ts +5 -5
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +4 -6
- package/src/__tests__/conversation-agent-loop.test.ts +4 -51
- package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
- package/src/__tests__/conversation-directories-parse.test.ts +105 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
- package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
- package/src/__tests__/conversation-wipe.test.ts +2 -6
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
- package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +0 -2
- package/src/__tests__/date-context.test.ts +76 -210
- package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
- package/src/__tests__/file-list-tool.test.ts +219 -0
- package/src/__tests__/first-greeting.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +180 -3
- package/src/__tests__/identity-routes.test.ts +328 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
- package/src/__tests__/injection-block.test.ts +24 -0
- package/src/__tests__/inline-command-runner.test.ts +7 -5
- package/src/__tests__/install-skill-routing.test.ts +7 -6
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +15 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
- package/src/__tests__/llm-context-normalization.test.ts +18 -18
- package/src/__tests__/llm-context-route-provider.test.ts +101 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +162 -0
- package/src/__tests__/log-export-workspace.test.ts +257 -100
- package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
- package/src/__tests__/mcp-abort-signal.test.ts +5 -0
- package/src/__tests__/mcp-client-auth.test.ts +5 -0
- package/src/__tests__/memory-recall-log-store.test.ts +132 -0
- package/src/__tests__/migration-export-streaming.test.ts +304 -0
- package/src/__tests__/migration-import-commit-http.test.ts +11 -10
- package/src/__tests__/mock-fetch.ts +87 -0
- package/src/__tests__/navigate-settings-tab.test.ts +14 -1
- package/src/__tests__/notification-broadcaster.test.ts +65 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
- package/src/__tests__/onboarding-template-contract.test.ts +63 -14
- package/src/__tests__/parser.test.ts +32 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
- package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
- package/src/__tests__/permission-mode-sse.test.ts +418 -0
- package/src/__tests__/permission-mode-store.test.ts +277 -0
- package/src/__tests__/permission-mode.test.ts +101 -0
- package/src/__tests__/pkb-autoinject.test.ts +96 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
- package/src/__tests__/profiler-routes.test.ts +502 -0
- package/src/__tests__/profiler-run-store.test.ts +441 -0
- package/src/__tests__/proxy-approval-callback.test.ts +4 -75
- package/src/__tests__/registry.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +0 -2
- package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
- package/src/__tests__/sandbox-host-parity.test.ts +5 -4
- package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
- package/src/__tests__/search-skills-unified.test.ts +4 -3
- package/src/__tests__/send-endpoint-busy.test.ts +42 -3
- package/src/__tests__/set-permission-mode.test.ts +274 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +12 -0
- package/src/__tests__/skill-memory.test.ts +2 -783
- package/src/__tests__/strip-memory-injections.test.ts +187 -0
- package/src/__tests__/subagent-detail.test.ts +84 -0
- package/src/__tests__/subagent-disposal.test.ts +308 -0
- package/src/__tests__/subagent-manager-notify.test.ts +19 -10
- package/src/__tests__/subagent-notify-parent.test.ts +390 -0
- package/src/__tests__/subagent-role-registry.test.ts +108 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
- package/src/__tests__/subagent-tools.test.ts +464 -4
- package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
- package/src/__tests__/task-memory-cleanup.test.ts +12 -12
- package/src/__tests__/terminal-sandbox.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +16 -29
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
- package/src/__tests__/tool-executor.test.ts +4 -27
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/top-level-renderer.test.ts +10 -13
- package/src/__tests__/transport-hints-queue.test.ts +77 -0
- package/src/__tests__/trust-store.test.ts +4 -4
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +116 -2
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
- package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
- package/src/__tests__/workspace-policy.test.ts +2 -7
- package/src/agent/loop.ts +6 -29
- package/src/approvals/guardian-request-resolvers.ts +24 -0
- package/src/avatar/traits-png-sync.ts +3 -3
- package/src/channels/types.ts +5 -0
- package/src/cli/__tests__/run-assistant-command.ts +56 -0
- package/src/cli/__tests__/unknown-command.test.ts +33 -0
- package/src/cli/commands/__tests__/email-download.test.ts +245 -0
- package/src/cli/commands/__tests__/email-list.test.ts +192 -0
- package/src/cli/commands/__tests__/email-register.test.ts +186 -0
- package/src/cli/commands/__tests__/email-send.test.ts +291 -0
- package/src/cli/commands/__tests__/email-status.test.ts +181 -0
- package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
- package/src/cli/commands/__tests__/routes.test.ts +562 -0
- package/src/cli/commands/conversations.ts +1 -8
- package/src/cli/commands/default-action.ts +68 -1
- package/src/cli/commands/email.ts +584 -835
- package/src/cli/commands/memory.ts +1 -34
- package/src/cli/commands/notifications.ts +7 -2
- package/src/cli/commands/oauth/__tests__/connect.test.ts +27 -0
- package/src/cli/commands/oauth/connect.ts +25 -5
- package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
- package/src/cli/commands/routes.ts +396 -0
- package/src/cli/commands/skills.ts +130 -20
- package/src/cli/program.ts +11 -2
- package/src/cli.ts +1 -120
- package/src/config/assistant-feature-flags.ts +59 -55
- package/src/config/bundled-skills/app-builder/SKILL.md +91 -5
- package/src/config/bundled-skills/gmail/SKILL.md +13 -8
- package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +7 -0
- package/src/config/bundled-skills/schedule/SKILL.md +22 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
- package/src/config/bundled-skills/settings/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
- package/src/config/bundled-skills/slack/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/SKILL.md +43 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
- package/src/config/env-registry.ts +63 -0
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +8 -0
- package/src/config/schemas/filing.ts +51 -0
- package/src/config/schemas/heartbeat.ts +15 -12
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/security.ts +14 -0
- package/src/config/schemas/services.ts +8 -0
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/managed-catalog.ts +3 -7
- package/src/daemon/app-source-watcher.ts +93 -0
- package/src/daemon/config-watcher.ts +85 -3
- package/src/daemon/context-overflow-approval.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +20 -0
- package/src/daemon/conversation-agent-loop.ts +179 -65
- package/src/daemon/conversation-attachments.ts +0 -1
- package/src/daemon/conversation-history.ts +4 -19
- package/src/daemon/conversation-lifecycle.ts +8 -14
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +30 -8
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +359 -308
- package/src/daemon/conversation-surfaces.ts +65 -0
- package/src/daemon/conversation-tool-setup.ts +44 -17
- package/src/daemon/conversation-workspace.ts +1 -2
- package/src/daemon/conversation.ts +19 -3
- package/src/daemon/date-context.ts +26 -53
- package/src/daemon/first-greeting.ts +1 -1
- package/src/daemon/handlers/conversations.ts +5 -7
- package/src/daemon/handlers/shared.test.ts +143 -0
- package/src/daemon/handlers/shared.ts +70 -5
- package/src/daemon/handlers/skills.ts +11 -18
- package/src/daemon/lifecycle.ts +220 -158
- package/src/daemon/message-types/conversations.ts +29 -6
- package/src/daemon/message-types/messages.ts +9 -2
- package/src/daemon/message-types/notifications.ts +12 -0
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +18 -0
- package/src/daemon/profiler-run-store.ts +557 -0
- package/src/daemon/server.ts +87 -10
- package/src/daemon/shutdown-handlers.ts +5 -0
- package/src/daemon/tool-side-effects.ts +23 -3
- package/src/daemon/transport-hints.ts +33 -0
- package/src/export/transcript-formatter.ts +148 -0
- package/src/filing/filing-service.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +96 -7
- package/src/index.ts +1 -1
- package/src/mcp/client.ts +6 -0
- package/src/mcp/mcp-oauth-provider.ts +149 -27
- package/src/memory/admin.ts +33 -32
- package/src/memory/app-store.ts +69 -0
- package/src/memory/conversation-bootstrap.ts +1 -1
- package/src/memory/conversation-crud.ts +151 -117
- package/src/memory/conversation-directories.ts +39 -0
- package/src/memory/conversation-group-migration.ts +66 -6
- package/src/memory/conversation-queries.ts +58 -12
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/db-init.ts +182 -376
- package/src/memory/embedding-local.ts +1 -1
- package/src/memory/graph/bootstrap.ts +75 -66
- package/src/memory/graph/capability-seed.ts +167 -17
- package/src/memory/graph/consolidation.ts +38 -4
- package/src/memory/graph/conversation-graph-memory.ts +133 -104
- package/src/memory/graph/extraction-job.ts +9 -4
- package/src/memory/graph/extraction.ts +66 -23
- package/src/memory/graph/graph-memory-state-store.ts +37 -0
- package/src/memory/graph/graph-search.ts +29 -15
- package/src/memory/graph/injection.ts +38 -8
- package/src/memory/graph/inspect.ts +12 -3
- package/src/memory/graph/retriever.ts +365 -262
- package/src/memory/graph/store.test.ts +48 -0
- package/src/memory/graph/store.ts +150 -11
- package/src/memory/graph/tool-handlers.ts +84 -209
- package/src/memory/graph/tools.ts +8 -52
- package/src/memory/graph/types.ts +24 -0
- package/src/memory/group-crud.ts +25 -9
- package/src/memory/job-handlers/cleanup.ts +44 -1
- package/src/memory/jobs-store.ts +70 -60
- package/src/memory/jobs-worker.ts +44 -28
- package/src/memory/llm-request-log-store.ts +96 -12
- package/src/memory/memory-recall-log-store.ts +49 -5
- package/src/memory/migrations/203-drop-memory-items-tables.ts +33 -1
- package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
- package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
- package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
- package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
- package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/conversations.ts +14 -0
- package/src/memory/schema/infrastructure.ts +8 -1
- package/src/memory/schema/memory-core.ts +0 -51
- package/src/memory/schema/memory-graph.ts +15 -0
- package/src/memory/task-memory-cleanup.ts +30 -11
- package/src/messaging/provider.ts +1 -1
- package/src/notifications/broadcaster.ts +6 -0
- package/src/notifications/conversation-pairing.ts +12 -4
- package/src/notifications/copy-composer.ts +86 -0
- package/src/notifications/decision-engine.ts +35 -0
- package/src/notifications/emit-signal.ts +14 -0
- package/src/notifications/signal.ts +11 -0
- package/src/oauth/platform-connection.test.ts +2 -2
- package/src/oauth/seed-providers.ts +1 -0
- package/src/permissions/checker.ts +15 -4
- package/src/permissions/defaults.ts +7 -8
- package/src/permissions/permission-mode-store.ts +180 -0
- package/src/permissions/permission-mode.ts +31 -0
- package/src/permissions/prompter.ts +0 -2
- package/src/permissions/workspace-policy.ts +9 -0
- package/src/platform/client.ts +1 -1
- package/src/prompts/system-prompt.ts +59 -7
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
- package/src/prompts/templates/BOOTSTRAP.md +76 -162
- package/src/prompts/templates/HEARTBEAT.md +3 -1
- package/src/prompts/templates/SOUL.md +30 -9
- package/src/prompts/templates/UPDATES.md +8 -0
- package/src/providers/anthropic/client.ts +107 -219
- package/src/runtime/assistant-event-hub.ts +22 -0
- package/src/runtime/auth/route-policy.ts +23 -0
- package/src/runtime/auth/token-service.ts +8 -0
- package/src/runtime/http-server.ts +32 -2
- package/src/runtime/http-types.ts +12 -1
- package/src/runtime/migrations/vbundle-builder.ts +389 -3
- package/src/runtime/migrations/vbundle-importer.ts +8 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
- package/src/runtime/routes/app-management-routes.ts +1 -11
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
- package/src/runtime/routes/archive-utils.ts +29 -0
- package/src/runtime/routes/avatar-routes.ts +2 -9
- package/src/runtime/routes/btw-routes.ts +14 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +185 -0
- package/src/runtime/routes/conversation-management-routes.ts +1 -14
- package/src/runtime/routes/conversation-query-routes.ts +49 -3
- package/src/runtime/routes/conversation-routes.ts +270 -44
- package/src/runtime/routes/group-routes.ts +22 -8
- package/src/runtime/routes/heartbeat-routes.ts +4 -10
- package/src/runtime/routes/identity-routes.ts +53 -18
- package/src/runtime/routes/llm-context-normalization.ts +14 -10
- package/src/runtime/routes/log-export/AGENTS.md +104 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
- package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
- package/src/runtime/routes/log-export-routes.ts +41 -278
- package/src/runtime/routes/memory-item-routes.test.ts +168 -233
- package/src/runtime/routes/migration-routes.ts +18 -7
- package/src/runtime/routes/profiler-routes.ts +350 -0
- package/src/runtime/routes/schedule-routes.ts +27 -12
- package/src/runtime/routes/settings-routes.ts +95 -8
- package/src/runtime/routes/subagents-routes.ts +28 -7
- package/src/runtime/routes/user-route-dispatcher.ts +223 -0
- package/src/runtime/routes/user-routes.ts +41 -0
- package/src/runtime/routes/workspace-routes.ts +0 -1
- package/src/schedule/schedule-store.ts +30 -0
- package/src/schedule/scheduler.ts +45 -18
- package/src/skills/catalog-install.ts +10 -2
- package/src/skills/inline-command-runner.ts +12 -14
- package/src/skills/managed-store.ts +2 -2
- package/src/skills/skill-memory.ts +1 -293
- package/src/subagent/index.ts +13 -3
- package/src/subagent/manager.ts +308 -29
- package/src/subagent/types.ts +68 -0
- package/src/tasks/task-runner.ts +4 -4
- package/src/tools/apps/executors.ts +29 -4
- package/src/tools/filesystem/list.ts +93 -0
- package/src/tools/permission-checker.ts +78 -18
- package/src/tools/registry.ts +4 -0
- package/src/tools/schedule/create.ts +3 -0
- package/src/tools/schedule/list.ts +1 -0
- package/src/tools/schedule/update.ts +6 -0
- package/src/tools/secret-detection-handler.ts +0 -1
- package/src/tools/shared/filesystem/errors.ts +5 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
- package/src/tools/shared/filesystem/types.ts +17 -0
- package/src/tools/shared/shell-output.ts +31 -2
- package/src/tools/skills/sandbox-runner.ts +3 -6
- package/src/tools/subagent/abort.ts +12 -2
- package/src/tools/subagent/message.ts +9 -2
- package/src/tools/subagent/notify-parent.ts +79 -0
- package/src/tools/subagent/read.ts +29 -8
- package/src/tools/subagent/resolve.ts +21 -0
- package/src/tools/subagent/spawn.ts +2 -0
- package/src/tools/subagent/status.ts +11 -1
- package/src/tools/system/avatar-generator.ts +3 -3
- package/src/tools/system/register.ts +23 -0
- package/src/tools/system/set-permission-mode.ts +103 -0
- package/src/tools/terminal/parser.ts +30 -5
- package/src/tools/terminal/safe-env.ts +16 -1
- package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
- package/src/tools/terminal/sandbox.ts +4 -1
- package/src/tools/terminal/shell.ts +3 -5
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +2 -3
- package/src/util/logger.ts +1 -1
- package/src/util/platform.ts +50 -17
- package/src/watcher/provider-types.ts +1 -1
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
- package/src/workspace/migrations/029-seed-pkb.ts +85 -0
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/top-level-renderer.ts +5 -9
- package/src/__tests__/cli-memory.test.ts +0 -377
- package/src/__tests__/clipboard.test.ts +0 -88
- package/src/cli/cli-memory.ts +0 -179
- package/src/util/clipboard.ts +0 -34
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
getMemorySystemStatus,
|
|
8
8
|
queryMemory,
|
|
9
9
|
requestMemoryBackfill,
|
|
10
|
-
requestMemoryCleanup,
|
|
11
10
|
requestMemoryRebuildIndex,
|
|
12
11
|
requestReextract,
|
|
13
12
|
} from "../../memory/admin.js";
|
|
@@ -106,38 +105,6 @@ Examples:
|
|
|
106
105
|
log.info(`Queued backfill job: ${jobId}`);
|
|
107
106
|
});
|
|
108
107
|
|
|
109
|
-
memory
|
|
110
|
-
.command("cleanup")
|
|
111
|
-
.description("Queue cleanup jobs for stale superseded items")
|
|
112
|
-
.option(
|
|
113
|
-
"--retention-ms <ms>",
|
|
114
|
-
"Optional retention threshold in milliseconds"
|
|
115
|
-
)
|
|
116
|
-
.addHelpText(
|
|
117
|
-
"after",
|
|
118
|
-
`
|
|
119
|
-
Queues a background cleanup job to remove memory items that have been
|
|
120
|
-
superseded by newer, corrected facts past the retention threshold.
|
|
121
|
-
|
|
122
|
-
The optional --retention-ms flag sets the minimum age (in milliseconds) a
|
|
123
|
-
record must have before it is eligible for cleanup. If omitted, the system
|
|
124
|
-
default retention period is used.
|
|
125
|
-
|
|
126
|
-
Examples:
|
|
127
|
-
$ assistant memory cleanup
|
|
128
|
-
$ assistant memory cleanup --retention-ms 86400000`
|
|
129
|
-
)
|
|
130
|
-
.action((opts: { retentionMs?: string }) => {
|
|
131
|
-
initializeDb();
|
|
132
|
-
const retentionMs = opts.retentionMs
|
|
133
|
-
? Number.parseInt(opts.retentionMs, 10)
|
|
134
|
-
: undefined;
|
|
135
|
-
requestMemoryCleanup(
|
|
136
|
-
Number.isFinite(retentionMs) ? retentionMs : undefined
|
|
137
|
-
);
|
|
138
|
-
log.info("Memory cleanup requested (legacy items table dropped)");
|
|
139
|
-
});
|
|
140
|
-
|
|
141
108
|
memory
|
|
142
109
|
.command("cleanup-segments")
|
|
143
110
|
.description("Remove short segments that waste retrieval budget")
|
|
@@ -270,7 +237,7 @@ extraction prompt. This is useful after updating the extraction prompt
|
|
|
270
237
|
(e.g. importance scoring rework) to re-score and re-extract memories
|
|
271
238
|
from historically important conversations.
|
|
272
239
|
|
|
273
|
-
The command resets extraction checkpoints so the
|
|
240
|
+
The command resets extraction checkpoints so the graph extraction handler
|
|
274
241
|
re-processes all messages. Existing memories are provided as supersession
|
|
275
242
|
context — the new extraction can supersede old flat-fact memories with
|
|
276
243
|
richer, properly-scored replacements.
|
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
NOTIFICATION_SOURCE_EVENT_NAMES,
|
|
11
11
|
} from "../../notifications/signal.js";
|
|
12
12
|
import type { NotificationChannel } from "../../notifications/types.js";
|
|
13
|
+
import {
|
|
14
|
+
initAuthSigningKey,
|
|
15
|
+
resolveSigningKey,
|
|
16
|
+
} from "../../runtime/auth/token-service.js";
|
|
13
17
|
import { initializeDb } from "../db.js";
|
|
14
18
|
import { log } from "../logger.js";
|
|
15
19
|
import { shouldOutputJson, writeOutput } from "../output.js";
|
|
@@ -159,7 +163,7 @@ Examples:
|
|
|
159
163
|
visibleInSourceNow: boolean;
|
|
160
164
|
deadlineAt?: string;
|
|
161
165
|
preferredChannels?: string;
|
|
162
|
-
|
|
166
|
+
sessionId?: string;
|
|
163
167
|
dedupeKey?: string;
|
|
164
168
|
},
|
|
165
169
|
cmd: Command,
|
|
@@ -251,8 +255,9 @@ Examples:
|
|
|
251
255
|
}
|
|
252
256
|
|
|
253
257
|
initializeDb();
|
|
258
|
+
initAuthSigningKey(resolveSigningKey());
|
|
254
259
|
|
|
255
|
-
const sourceContextId = opts.
|
|
260
|
+
const sourceContextId = opts.sessionId ?? `cli-${Date.now()}`;
|
|
256
261
|
|
|
257
262
|
const result = await emitNotificationSignal({
|
|
258
263
|
sourceEventName: opts.sourceEventName,
|
|
@@ -668,6 +668,33 @@ describe("assistant oauth connect", () => {
|
|
|
668
668
|
expect(parsed.error).toContain("apps upsert");
|
|
669
669
|
});
|
|
670
670
|
|
|
671
|
+
// -------------------------------------------------------------------------
|
|
672
|
+
// Manual-token providers (slack_channel, telegram)
|
|
673
|
+
// -------------------------------------------------------------------------
|
|
674
|
+
|
|
675
|
+
test("manual-token provider returns error directing to credentials command", async () => {
|
|
676
|
+
mockGetProvider = () => ({
|
|
677
|
+
providerKey: "slack_channel",
|
|
678
|
+
authUrl: "urn:manual-token",
|
|
679
|
+
tokenUrl: "urn:manual-token",
|
|
680
|
+
managedServiceConfigKey: null,
|
|
681
|
+
});
|
|
682
|
+
mockIsManagedMode = () => false;
|
|
683
|
+
|
|
684
|
+
const { exitCode, stdout } = await runCommand([
|
|
685
|
+
"connect",
|
|
686
|
+
"slack_channel",
|
|
687
|
+
"--json",
|
|
688
|
+
]);
|
|
689
|
+
expect(exitCode).toBe(1);
|
|
690
|
+
const parsed = JSON.parse(stdout);
|
|
691
|
+
expect(parsed.ok).toBe(false);
|
|
692
|
+
expect(parsed.error).toContain("manual token configuration");
|
|
693
|
+
expect(parsed.error).toContain("assistant credentials set");
|
|
694
|
+
expect(parsed.error).toContain("--service");
|
|
695
|
+
expect(parsed.error).toContain("--field");
|
|
696
|
+
});
|
|
697
|
+
|
|
671
698
|
// -------------------------------------------------------------------------
|
|
672
699
|
// Orchestrator error propagation
|
|
673
700
|
// -------------------------------------------------------------------------
|
|
@@ -2,6 +2,7 @@ import { createServer, type Server } from "node:http";
|
|
|
2
2
|
|
|
3
3
|
import type { Command } from "commander";
|
|
4
4
|
|
|
5
|
+
import { getIsContainerized } from "../../../config/env-registry.js";
|
|
5
6
|
import { orchestrateOAuthConnect } from "../../../oauth/connect-orchestrator.js";
|
|
6
7
|
import {
|
|
7
8
|
getAppByProviderAndClientId,
|
|
@@ -178,15 +179,23 @@ Examples:
|
|
|
178
179
|
|
|
179
180
|
// When opening the browser, start a local server to show a nice
|
|
180
181
|
// completion page instead of redirecting to the platform website.
|
|
182
|
+
//
|
|
183
|
+
// In containerized mode the loopback server is unreachable from
|
|
184
|
+
// the host browser, so redirect to the platform's own completion
|
|
185
|
+
// page instead.
|
|
181
186
|
let redirectServer:
|
|
182
187
|
| { redirectUrl: string; cleanup: () => void }
|
|
183
188
|
| undefined;
|
|
184
189
|
if (opts.browser !== false) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
if (getIsContainerized()) {
|
|
191
|
+
body.redirect_after_connect = "/account/oauth/desktop-complete";
|
|
192
|
+
} else {
|
|
193
|
+
try {
|
|
194
|
+
redirectServer = await startManagedRedirectServer(provider);
|
|
195
|
+
body.redirect_after_connect = redirectServer.redirectUrl;
|
|
196
|
+
} catch {
|
|
197
|
+
// Non-fatal — fall back to platform default redirect
|
|
198
|
+
}
|
|
190
199
|
}
|
|
191
200
|
}
|
|
192
201
|
|
|
@@ -327,6 +336,17 @@ Examples:
|
|
|
327
336
|
// BYO PATH
|
|
328
337
|
// =============================================================
|
|
329
338
|
|
|
339
|
+
// Manual-token providers (slack_channel, telegram) don't use
|
|
340
|
+
// OAuth2 browser flows — credentials are configured via
|
|
341
|
+
// `assistant credentials` or chat setup instead.
|
|
342
|
+
if (providerRow.authUrl === "urn:manual-token") {
|
|
343
|
+
writeError(
|
|
344
|
+
`"${provider}" uses manual token configuration, not an OAuth browser flow. ` +
|
|
345
|
+
`Set the token with: assistant credentials set <token_value> --service ${provider} --field <field_name>`,
|
|
346
|
+
);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
330
350
|
// a. Resolve client credentials from the DB
|
|
331
351
|
const dbApp = opts.clientId
|
|
332
352
|
? getAppByProviderAndClientId(provider, opts.clientId)
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
import { getConfig } from "../../config/loader.js";
|
|
7
|
+
import { getPublicBaseUrl } from "../../inbound/public-ingress-urls.js";
|
|
8
|
+
import { getWorkspaceRoutesDir } from "../../util/platform.js";
|
|
9
|
+
import { log } from "../logger.js";
|
|
10
|
+
|
|
11
|
+
/** HTTP methods that can be exported from a handler module. */
|
|
12
|
+
const HTTP_METHODS = [
|
|
13
|
+
"GET",
|
|
14
|
+
"POST",
|
|
15
|
+
"PUT",
|
|
16
|
+
"PATCH",
|
|
17
|
+
"DELETE",
|
|
18
|
+
"HEAD",
|
|
19
|
+
"OPTIONS",
|
|
20
|
+
] as const;
|
|
21
|
+
|
|
22
|
+
type HttpMethod = (typeof HTTP_METHODS)[number];
|
|
23
|
+
|
|
24
|
+
/** Supported file extensions for handler modules. */
|
|
25
|
+
const HANDLER_EXTENSIONS = [".ts", ".js"] as const;
|
|
26
|
+
|
|
27
|
+
type HandlerExtension = (typeof HANDLER_EXTENSIONS)[number];
|
|
28
|
+
|
|
29
|
+
interface DiscoveredRoute {
|
|
30
|
+
/** Route path relative to /x/ prefix (e.g. "my-app/status"). */
|
|
31
|
+
routePath: string;
|
|
32
|
+
/** Absolute path to the handler file. */
|
|
33
|
+
filePath: string;
|
|
34
|
+
/** HTTP methods exported by the handler module. */
|
|
35
|
+
methods: HttpMethod[];
|
|
36
|
+
/** Optional description exported by the handler module. */
|
|
37
|
+
description?: string;
|
|
38
|
+
/** File size in bytes. */
|
|
39
|
+
fileSize: number;
|
|
40
|
+
/** Last modified time as ISO string. */
|
|
41
|
+
modifiedAt: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Load a handler module and extract its exported HTTP methods and description.
|
|
46
|
+
*/
|
|
47
|
+
async function inspectModule(
|
|
48
|
+
filePath: string,
|
|
49
|
+
): Promise<{ methods: HttpMethod[]; description?: string }> {
|
|
50
|
+
const stat = statSync(filePath);
|
|
51
|
+
const mod = (await import(`${filePath}?t=${stat.mtimeMs}`)) as Record<
|
|
52
|
+
string,
|
|
53
|
+
unknown
|
|
54
|
+
>;
|
|
55
|
+
|
|
56
|
+
const methods: HttpMethod[] = [];
|
|
57
|
+
for (const method of HTTP_METHODS) {
|
|
58
|
+
if (typeof mod[method] === "function") {
|
|
59
|
+
methods.push(method);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const description =
|
|
64
|
+
typeof mod.description === "string" ? mod.description : undefined;
|
|
65
|
+
|
|
66
|
+
return { methods, description };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Recursively scan the routes directory for handler files (.ts, .js).
|
|
71
|
+
* Returns discovered routes sorted alphabetically by route path.
|
|
72
|
+
*/
|
|
73
|
+
async function discoverRoutes(routesDir: string): Promise<DiscoveredRoute[]> {
|
|
74
|
+
if (!existsSync(routesDir)) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const routes: DiscoveredRoute[] = [];
|
|
79
|
+
|
|
80
|
+
function scanDir(dir: string): void {
|
|
81
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
const fullPath = join(dir, entry.name);
|
|
84
|
+
if (entry.isDirectory()) {
|
|
85
|
+
scanDir(fullPath);
|
|
86
|
+
} else if (entry.isFile()) {
|
|
87
|
+
const ext = HANDLER_EXTENSIONS.find((e) => entry.name.endsWith(e)) as
|
|
88
|
+
| HandlerExtension
|
|
89
|
+
| undefined;
|
|
90
|
+
if (!ext) continue;
|
|
91
|
+
|
|
92
|
+
const relativePath = relative(routesDir, fullPath);
|
|
93
|
+
const withoutExt = relativePath.slice(0, -ext.length);
|
|
94
|
+
|
|
95
|
+
// Convert filesystem path to route path:
|
|
96
|
+
// - Strip /index suffix for index file convention
|
|
97
|
+
// - Replace backslashes with forward slashes (Windows compat)
|
|
98
|
+
let routePath = withoutExt.replace(/\\/g, "/");
|
|
99
|
+
if (routePath.endsWith("/index")) {
|
|
100
|
+
routePath = routePath.slice(0, -"/index".length);
|
|
101
|
+
} else if (routePath === "index") {
|
|
102
|
+
routePath = "";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
routes.push({
|
|
106
|
+
routePath,
|
|
107
|
+
filePath: fullPath,
|
|
108
|
+
methods: [],
|
|
109
|
+
description: undefined,
|
|
110
|
+
fileSize: 0,
|
|
111
|
+
modifiedAt: "",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
scanDir(routesDir);
|
|
118
|
+
|
|
119
|
+
// Load each module to detect exported methods and description
|
|
120
|
+
for (const route of routes) {
|
|
121
|
+
try {
|
|
122
|
+
const stat = statSync(route.filePath);
|
|
123
|
+
route.fileSize = stat.size;
|
|
124
|
+
route.modifiedAt = stat.mtime.toISOString();
|
|
125
|
+
|
|
126
|
+
const { methods, description } = await inspectModule(route.filePath);
|
|
127
|
+
route.methods = methods;
|
|
128
|
+
route.description = description;
|
|
129
|
+
} catch {
|
|
130
|
+
// If a module fails to load, keep it in the list with empty methods
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return routes.sort((a, b) => a.routePath.localeCompare(b.routePath));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Try to resolve the public base URL for building full endpoint URLs.
|
|
139
|
+
* Returns null if no public URL is configured (non-fatal for CLI display).
|
|
140
|
+
*/
|
|
141
|
+
function tryGetPublicBaseUrl(): string | null {
|
|
142
|
+
try {
|
|
143
|
+
const config = getConfig();
|
|
144
|
+
return getPublicBaseUrl(config);
|
|
145
|
+
} catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Format a list of HTTP methods for display, abbreviating DELETE to DEL.
|
|
152
|
+
*/
|
|
153
|
+
function formatMethods(methods: HttpMethod[]): string {
|
|
154
|
+
return methods.map((m) => (m === "DELETE" ? "DEL" : m)).join(",");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function registerRoutesCommand(program: Command): void {
|
|
158
|
+
const routes = program
|
|
159
|
+
.command("routes")
|
|
160
|
+
.description("Manage user-defined HTTP route handlers under /x/*");
|
|
161
|
+
|
|
162
|
+
routes.addHelpText(
|
|
163
|
+
"after",
|
|
164
|
+
`
|
|
165
|
+
User-defined routes let you expose custom HTTP endpoints by dropping handler
|
|
166
|
+
files into /workspace/routes/. Each file exports named HTTP method functions
|
|
167
|
+
(GET, POST, etc.) and becomes reachable at /x/<path>.
|
|
168
|
+
|
|
169
|
+
Routes are managed by creating and deleting files — no add/remove commands
|
|
170
|
+
needed.
|
|
171
|
+
|
|
172
|
+
Examples:
|
|
173
|
+
$ assistant routes list
|
|
174
|
+
$ assistant routes list --json
|
|
175
|
+
$ assistant routes inspect my-dashboard-api/submit`,
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
routes
|
|
179
|
+
.command("list")
|
|
180
|
+
.description("List all user-defined route handlers and their public URLs")
|
|
181
|
+
.option("--json", "Machine-readable JSON output")
|
|
182
|
+
.addHelpText(
|
|
183
|
+
"after",
|
|
184
|
+
`
|
|
185
|
+
Scans /workspace/routes/ for handler files (.ts, .js) and displays the route
|
|
186
|
+
path, exported HTTP methods, optional description, and file location.
|
|
187
|
+
|
|
188
|
+
Examples:
|
|
189
|
+
$ assistant routes list
|
|
190
|
+
$ assistant routes list --json`,
|
|
191
|
+
)
|
|
192
|
+
.action(async (opts: { json?: boolean }) => {
|
|
193
|
+
try {
|
|
194
|
+
const routesDir = getWorkspaceRoutesDir();
|
|
195
|
+
const discovered = await discoverRoutes(routesDir);
|
|
196
|
+
|
|
197
|
+
if (opts.json) {
|
|
198
|
+
const publicBase = tryGetPublicBaseUrl();
|
|
199
|
+
const items = discovered.map((r) => ({
|
|
200
|
+
routePath: `/x/${r.routePath}`,
|
|
201
|
+
methods: r.methods,
|
|
202
|
+
description: r.description ?? null,
|
|
203
|
+
filePath: relative(routesDir, r.filePath),
|
|
204
|
+
publicUrl: publicBase ? `${publicBase}/x/${r.routePath}` : null,
|
|
205
|
+
}));
|
|
206
|
+
console.log(JSON.stringify({ ok: true, routes: items }));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (discovered.length === 0) {
|
|
211
|
+
log.info("No route handlers found in /workspace/routes/.");
|
|
212
|
+
log.info(
|
|
213
|
+
"Create a .ts or .js file exporting named HTTP method functions (GET, POST, etc.).",
|
|
214
|
+
);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const publicBase = tryGetPublicBaseUrl();
|
|
219
|
+
|
|
220
|
+
log.info("");
|
|
221
|
+
// Table header
|
|
222
|
+
const routeCol = "ROUTE PATH";
|
|
223
|
+
const methodsCol = "METHODS";
|
|
224
|
+
const descCol = "DESCRIPTION";
|
|
225
|
+
const fileCol = "FILE";
|
|
226
|
+
|
|
227
|
+
// Calculate column widths
|
|
228
|
+
const routeWidth = Math.max(
|
|
229
|
+
routeCol.length,
|
|
230
|
+
...discovered.map((r) => `/x/${r.routePath}`.length),
|
|
231
|
+
);
|
|
232
|
+
const methodsWidth = Math.max(
|
|
233
|
+
methodsCol.length,
|
|
234
|
+
...discovered.map((r) => formatMethods(r.methods).length),
|
|
235
|
+
);
|
|
236
|
+
const descWidth = Math.max(
|
|
237
|
+
descCol.length,
|
|
238
|
+
...discovered.map((r) => (r.description ?? "").length),
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const header = [
|
|
242
|
+
routeCol.padEnd(routeWidth),
|
|
243
|
+
methodsCol.padEnd(methodsWidth),
|
|
244
|
+
descCol.padEnd(descWidth),
|
|
245
|
+
fileCol,
|
|
246
|
+
].join(" ");
|
|
247
|
+
|
|
248
|
+
log.info(` ${header}`);
|
|
249
|
+
|
|
250
|
+
for (const route of discovered) {
|
|
251
|
+
const cols = [
|
|
252
|
+
`/x/${route.routePath}`.padEnd(routeWidth),
|
|
253
|
+
formatMethods(route.methods).padEnd(methodsWidth),
|
|
254
|
+
(route.description ?? "").padEnd(descWidth),
|
|
255
|
+
`routes/${relative(routesDir, route.filePath)}`,
|
|
256
|
+
].join(" ");
|
|
257
|
+
log.info(` ${cols}`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
log.info("");
|
|
261
|
+
const countLabel = discovered.length === 1 ? "route" : "routes";
|
|
262
|
+
const summary = `${discovered.length} ${countLabel}`;
|
|
263
|
+
if (publicBase) {
|
|
264
|
+
log.info(` ${summary} • Public base: ${publicBase}`);
|
|
265
|
+
} else {
|
|
266
|
+
log.info(` ${summary}`);
|
|
267
|
+
}
|
|
268
|
+
log.info("");
|
|
269
|
+
} catch (err) {
|
|
270
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
271
|
+
if (opts.json) {
|
|
272
|
+
console.log(JSON.stringify({ ok: false, error: msg }));
|
|
273
|
+
} else {
|
|
274
|
+
log.error(`Error: ${msg}`);
|
|
275
|
+
}
|
|
276
|
+
process.exitCode = 1;
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
routes
|
|
281
|
+
.command("inspect <path>")
|
|
282
|
+
.description("Show details of a specific user-defined route handler")
|
|
283
|
+
.option("--json", "Machine-readable JSON output")
|
|
284
|
+
.addHelpText(
|
|
285
|
+
"after",
|
|
286
|
+
`
|
|
287
|
+
Arguments:
|
|
288
|
+
path Route path relative to /x/ (e.g. "my-dashboard-api/submit").
|
|
289
|
+
Do not include the /x/ prefix.
|
|
290
|
+
|
|
291
|
+
Loads the handler file and displays exported methods, description, file path,
|
|
292
|
+
public URL, file size, and last modified time.
|
|
293
|
+
|
|
294
|
+
Examples:
|
|
295
|
+
$ assistant routes inspect my-dashboard-api/submit
|
|
296
|
+
$ assistant routes inspect items --json`,
|
|
297
|
+
)
|
|
298
|
+
.action(async (routePath: string, opts: { json?: boolean }) => {
|
|
299
|
+
try {
|
|
300
|
+
const routesDir = getWorkspaceRoutesDir();
|
|
301
|
+
const filePath = resolveHandlerFile(routesDir, routePath);
|
|
302
|
+
|
|
303
|
+
if (!filePath) {
|
|
304
|
+
const msg = `No handler file found for route path "${routePath}"`;
|
|
305
|
+
if (opts.json) {
|
|
306
|
+
console.log(JSON.stringify({ ok: false, error: msg }));
|
|
307
|
+
} else {
|
|
308
|
+
log.error(msg);
|
|
309
|
+
log.info("Expected file at one of:");
|
|
310
|
+
for (const ext of HANDLER_EXTENSIONS) {
|
|
311
|
+
log.info(` ${join(routesDir, `${routePath}${ext}`)}`);
|
|
312
|
+
log.info(` ${join(routesDir, routePath, `index${ext}`)}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
process.exitCode = 1;
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const stat = statSync(filePath);
|
|
320
|
+
const { methods, description } = await inspectModule(filePath);
|
|
321
|
+
const publicBase = tryGetPublicBaseUrl();
|
|
322
|
+
const publicUrl = publicBase ? `${publicBase}/x/${routePath}` : null;
|
|
323
|
+
|
|
324
|
+
if (opts.json) {
|
|
325
|
+
console.log(
|
|
326
|
+
JSON.stringify({
|
|
327
|
+
ok: true,
|
|
328
|
+
route: {
|
|
329
|
+
routePath: `/x/${routePath}`,
|
|
330
|
+
methods,
|
|
331
|
+
description: description ?? null,
|
|
332
|
+
filePath,
|
|
333
|
+
publicUrl,
|
|
334
|
+
fileSize: stat.size,
|
|
335
|
+
modifiedAt: stat.mtime.toISOString(),
|
|
336
|
+
},
|
|
337
|
+
}),
|
|
338
|
+
);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
log.info("");
|
|
343
|
+
log.info(` Route: /x/${routePath}`);
|
|
344
|
+
log.info(
|
|
345
|
+
` Methods: ${methods.join(", ") || "(none)"} (detected from named exports)`,
|
|
346
|
+
);
|
|
347
|
+
if (description) {
|
|
348
|
+
log.info(` Description: ${description}`);
|
|
349
|
+
}
|
|
350
|
+
log.info(` File: ${filePath}`);
|
|
351
|
+
if (publicUrl) {
|
|
352
|
+
log.info(` Public URL: ${publicUrl}`);
|
|
353
|
+
}
|
|
354
|
+
log.info(` File Size: ${stat.size} bytes`);
|
|
355
|
+
log.info(` Modified: ${stat.mtime.toISOString()}`);
|
|
356
|
+
log.info("");
|
|
357
|
+
} catch (err) {
|
|
358
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
359
|
+
if (opts.json) {
|
|
360
|
+
console.log(JSON.stringify({ ok: false, error: msg }));
|
|
361
|
+
} else {
|
|
362
|
+
log.error(`Error: ${msg}`);
|
|
363
|
+
}
|
|
364
|
+
process.exitCode = 1;
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Resolve a route path to a handler file on disk.
|
|
371
|
+
* Mirrors the resolution logic from UserRouteDispatcher.
|
|
372
|
+
*/
|
|
373
|
+
function resolveHandlerFile(
|
|
374
|
+
routesDir: string,
|
|
375
|
+
routePath: string,
|
|
376
|
+
): string | null {
|
|
377
|
+
const basePath = join(routesDir, routePath);
|
|
378
|
+
|
|
379
|
+
// Direct file match
|
|
380
|
+
for (const ext of HANDLER_EXTENSIONS) {
|
|
381
|
+
const candidate = `${basePath}${ext}`;
|
|
382
|
+
if (existsSync(candidate)) {
|
|
383
|
+
return candidate;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Index file convention
|
|
388
|
+
for (const ext of HANDLER_EXTENSIONS) {
|
|
389
|
+
const candidate = join(basePath, `index${ext}`);
|
|
390
|
+
if (existsSync(candidate)) {
|
|
391
|
+
return candidate;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return null;
|
|
396
|
+
}
|