dotdo 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/README.md +238 -0
- package/cli/agent.ts +72 -0
- package/cli/bin.js +44 -0
- package/cli/bin.ts +38 -0
- package/cli/build.ts +157 -0
- package/cli/commands/auth/login.ts +14 -0
- package/cli/commands/auth/logout.ts +6 -0
- package/cli/commands/auth/whoami.ts +16 -0
- package/cli/commands/deploy-multi.ts +245 -0
- package/cli/commands/dev/deploy.ts +100 -0
- package/cli/commands/dev/dev.ts +95 -0
- package/cli/commands/dev/logs.ts +91 -0
- package/cli/commands/dev-local.ts +88 -0
- package/cli/commands/do-ops.ts +314 -0
- package/cli/commands/index.ts +100 -0
- package/cli/commands/init.ts +247 -0
- package/cli/commands/introspect/emitter.ts +315 -0
- package/cli/commands/introspect/index.ts +193 -0
- package/cli/commands/link.ts +598 -0
- package/cli/commands/snippets.ts +415 -0
- package/cli/commands/tunnel.ts +239 -0
- package/cli/device-auth.ts +289 -0
- package/cli/fallback.ts +12 -0
- package/cli/index.ts +121 -0
- package/cli/main.ts +246 -0
- package/cli/mcp-stdio.ts +790 -0
- package/cli/package.json +62 -0
- package/cli/runtime/do-registry.ts +193 -0
- package/cli/runtime/embedded-db.ts +344 -0
- package/cli/runtime/index.ts +9 -0
- package/cli/runtime/miniflare-adapter.ts +162 -0
- package/cli/sandbox.ts +82 -0
- package/cli/src/args.ts +174 -0
- package/cli/src/auth.ts +55 -0
- package/cli/src/commands/call.ts +84 -0
- package/cli/src/commands/charge.ts +96 -0
- package/cli/src/commands/config.ts +115 -0
- package/cli/src/commands/email.ts +112 -0
- package/cli/src/commands/llm.ts +115 -0
- package/cli/src/commands/queue.ts +134 -0
- package/cli/src/commands/text.ts +86 -0
- package/cli/src/config.ts +185 -0
- package/cli/src/output.ts +246 -0
- package/cli/src/rpc.ts +192 -0
- package/cli/utils/config.ts +282 -0
- package/cli/utils/detect.ts +73 -0
- package/cli/utils/index.ts +15 -0
- package/cli/utils/logger.ts +232 -0
- package/dist/ai/template-literals.js +2 -2
- package/dist/ai/template-literals.js.map +1 -1
- package/dist/api/middleware/auth.js +3 -2
- package/dist/api/middleware/auth.js.map +1 -1
- package/dist/db/iceberg/inverted-index.js +1 -1
- package/dist/db/iceberg/inverted-index.js.map +1 -1
- package/dist/db/iceberg/puffin.js.map +1 -1
- package/dist/db/json-indexes.js.map +1 -1
- package/dist/db/objects.js.map +1 -1
- package/dist/db/primitives/dag-scheduler/index.js +1 -1
- package/dist/db/primitives/dag-scheduler/index.js.map +1 -1
- package/dist/db/primitives/observability.js.map +1 -1
- package/dist/db/primitives/schema-evolution.js.map +1 -1
- package/dist/db/primitives/temporal-store.js.map +1 -1
- package/dist/db/primitives/typed-column-store.js.map +1 -1
- package/dist/db/primitives/utils/duration.js.map +1 -1
- package/dist/db/primitives/utils/murmur3.js +12 -14
- package/dist/db/primitives/utils/murmur3.js.map +1 -1
- package/dist/db/primitives/window-manager.js.map +1 -1
- package/dist/db/stores.js.map +1 -1
- package/dist/db/things.js.map +1 -1
- package/dist/lib/DODispatcher.js +2 -2
- package/dist/lib/DODispatcher.js.map +1 -1
- package/dist/lib/auto-wiring.js.map +1 -1
- package/dist/lib/channels/email.js +1 -1
- package/dist/lib/channels/email.js.map +1 -1
- package/dist/lib/channels/slack-blockkit.js.map +1 -1
- package/dist/lib/cloudflare/ai.js +1 -1
- package/dist/lib/cloudflare/ai.js.map +1 -1
- package/dist/lib/cloudflare/kv.js +1 -1
- package/dist/lib/cloudflare/kv.js.map +1 -1
- package/dist/lib/cloudflare/r2.js +3 -3
- package/dist/lib/cloudflare/r2.js.map +1 -1
- package/dist/lib/cloudflare/vectorize.js.map +1 -1
- package/dist/lib/cloudflare/workflows.js.map +1 -1
- package/dist/lib/executors/AgenticFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/CodeFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/GenerativeFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/HumanFunctionExecutor.js +1 -1
- package/dist/lib/executors/HumanFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/ParallelStepExecutor.js.map +1 -1
- package/dist/lib/experiments.js.map +1 -1
- package/dist/lib/flags/store.js.map +1 -1
- package/dist/lib/functions/FunctionComposition.js.map +1 -1
- package/dist/lib/functions/FunctionMiddleware.js.map +1 -1
- package/dist/lib/functions/FunctionRegistry.js.map +1 -1
- package/dist/lib/humans/templates.js.map +1 -1
- package/dist/lib/identity.js +2 -2
- package/dist/lib/identity.js.map +1 -1
- package/dist/lib/logging/index.js.map +1 -1
- package/dist/lib/mixins/bash.js +1 -73
- package/dist/lib/mixins/bash.js.map +1 -1
- package/dist/lib/mixins/git.js +0 -5
- package/dist/lib/mixins/git.js.map +1 -1
- package/dist/lib/mixins/npm.js.map +1 -1
- package/dist/lib/noun-id.js.map +1 -1
- package/dist/lib/rate-limit/sliding-window.js.map +1 -1
- package/dist/lib/rpc/bindings.js.map +1 -1
- package/dist/lib/safe-stringify.js.map +1 -1
- package/dist/lib/sandbox/miniflare-sandbox.js.map +1 -1
- package/dist/lib/sqids.js.map +1 -1
- package/dist/lib/sql/adapters/node-sql-parser.js.map +1 -1
- package/dist/lib/sql/adapters/pgsql-parser.js +19 -18
- package/dist/lib/sql/adapters/pgsql-parser.js.map +1 -1
- package/dist/metrics/hunch.js.map +1 -1
- package/dist/objects/API.js +1 -1
- package/dist/objects/API.js.map +1 -1
- package/dist/objects/Agent.js.map +1 -1
- package/dist/objects/Browser.js.map +1 -1
- package/dist/objects/CLI.js.map +1 -1
- package/dist/objects/DOBase.js.map +1 -1
- package/dist/objects/DOCache.js +153 -0
- package/dist/objects/DOCache.js.map +1 -0
- package/dist/objects/DOFull.js.map +1 -1
- package/dist/objects/Entity.js.map +1 -1
- package/dist/objects/Human.js.map +1 -1
- package/dist/objects/IcebergMetadataDO.js.map +1 -1
- package/dist/objects/IntegrationsDO.js.map +1 -1
- package/dist/objects/ObservabilityBroadcaster.js.map +1 -1
- package/dist/objects/Package.js.map +1 -1
- package/dist/objects/Product.js +1 -1
- package/dist/objects/Product.js.map +1 -1
- package/dist/objects/SaaS.js.map +1 -1
- package/dist/objects/SandboxDO.js.map +1 -1
- package/dist/objects/Service.js.map +1 -1
- package/dist/objects/VectorShardDO.js +9 -7
- package/dist/objects/VectorShardDO.js.map +1 -1
- package/dist/objects/Workflow.js.map +1 -1
- package/dist/objects/WorkflowFactory.js.map +1 -1
- package/dist/objects/WorkflowRuntime.js.map +1 -1
- package/dist/objects/lifecycle/Branch.js.map +1 -1
- package/dist/objects/lifecycle/Clone.js +1 -1
- package/dist/objects/lifecycle/Clone.js.map +1 -1
- package/dist/objects/lifecycle/Compact.js.map +1 -1
- package/dist/objects/lifecycle/Shard.js.map +1 -1
- package/dist/objects/persistence/checkpoint-manager.js.map +1 -1
- package/dist/objects/persistence/migration-runner.js.map +1 -1
- package/dist/objects/persistence/replication-manager.js +2 -2
- package/dist/objects/persistence/replication-manager.js.map +1 -1
- package/dist/objects/persistence/tiered-storage-manager.js.map +1 -1
- package/dist/objects/persistence/wal-manager.js.map +1 -1
- package/dist/objects/transport/auth-layer.js.map +1 -1
- package/dist/objects/transport/chain.js.map +1 -1
- package/dist/objects/transport/mcp-server.js +7 -6
- package/dist/objects/transport/mcp-server.js.map +1 -1
- package/dist/objects/transport/rest-autowire.js +3 -2
- package/dist/objects/transport/rest-autowire.js.map +1 -1
- package/dist/objects/transport/rest-router.js.map +1 -1
- package/dist/objects/transport/rpc-server.js +18 -15
- package/dist/objects/transport/rpc-server.js.map +1 -1
- package/dist/objects/transport/shared.js +2 -1
- package/dist/objects/transport/shared.js.map +1 -1
- package/dist/snippets/artifacts-ingest.js.map +1 -1
- package/dist/snippets/artifacts-serve.js.map +1 -1
- package/dist/snippets/search.js.map +1 -1
- package/dist/workflows/ScheduleManager.js.map +1 -1
- package/dist/workflows/StepResultStorage.js.map +1 -1
- package/dist/workflows/WaitForEventManager.js.map +1 -1
- package/dist/workflows/compat/backends/cloudflare-workflows.js.map +1 -1
- package/dist/workflows/compat/inngest/index.js.map +1 -1
- package/dist/workflows/compat/qstash/index.js.map +1 -1
- package/dist/workflows/compat/temporal/client.js.map +1 -1
- package/dist/workflows/compat/temporal/index.js.map +1 -1
- package/dist/workflows/compat/trigger/index.js.map +1 -1
- package/dist/workflows/compat/utils/index.js.map +1 -1
- package/dist/workflows/context/correlation.js +2 -2
- package/dist/workflows/context/correlation.js.map +1 -1
- package/dist/workflows/context/experiment.js +1 -1
- package/dist/workflows/context/experiment.js.map +1 -1
- package/dist/workflows/context/flag.js +1 -1
- package/dist/workflows/context/flag.js.map +1 -1
- package/dist/workflows/context/measure.js +1 -1
- package/dist/workflows/context/measure.js.map +1 -1
- package/dist/workflows/context/rate-limit.js.map +1 -1
- package/dist/workflows/data/entity-events/entity-events.js.map +1 -1
- package/dist/workflows/data/experiment/index.js.map +1 -1
- package/dist/workflows/data/goal/context.js +1 -1
- package/dist/workflows/data/goal/context.js.map +1 -1
- package/dist/workflows/data/measure/index.js +1 -1
- package/dist/workflows/data/measure/index.js.map +1 -1
- package/dist/workflows/data/stream/index.js +10 -76
- package/dist/workflows/data/stream/index.js.map +1 -1
- package/dist/workflows/data/track/context.js.map +1 -1
- package/dist/workflows/data/view/context.js.map +1 -1
- package/dist/workflows/domain.js.map +1 -1
- package/dist/workflows/flags.js +1 -1
- package/dist/workflows/flags.js.map +1 -1
- package/dist/workflows/hash.js.map +1 -1
- package/dist/workflows/on.js +1 -1
- package/dist/workflows/on.js.map +1 -1
- package/dist/workflows/schedule-builder.js.map +1 -1
- package/dist/workflows/visibility/index.js +0 -2
- package/dist/workflows/visibility/index.js.map +1 -1
- package/dist/workflows/visibility/query-parser.js.map +1 -1
- package/package.json +18 -3
- package/dist/api/analytics/router.js +0 -601
- package/dist/api/analytics/router.js.map +0 -1
- package/dist/api/index.js +0 -158
- package/dist/api/index.js.map +0 -1
- package/dist/api/middleware/error-handling.js +0 -176
- package/dist/api/middleware/error-handling.js.map +0 -1
- package/dist/api/middleware/request-id.js +0 -21
- package/dist/api/middleware/request-id.js.map +0 -1
- package/dist/api/pages.js +0 -1180
- package/dist/api/pages.js.map +0 -1
- package/dist/api/routes/api.js +0 -612
- package/dist/api/routes/api.js.map +0 -1
- package/dist/api/routes/browsers.js +0 -471
- package/dist/api/routes/browsers.js.map +0 -1
- package/dist/api/routes/do.js +0 -188
- package/dist/api/routes/do.js.map +0 -1
- package/dist/api/routes/mcp.js +0 -459
- package/dist/api/routes/mcp.js.map +0 -1
- package/dist/api/routes/obs.js +0 -445
- package/dist/api/routes/obs.js.map +0 -1
- package/dist/api/routes/openapi.js +0 -794
- package/dist/api/routes/openapi.js.map +0 -1
- package/dist/api/routes/rpc.js +0 -1103
- package/dist/api/routes/rpc.js.map +0 -1
- package/dist/api/routes/sandboxes.js +0 -389
- package/dist/api/routes/sandboxes.js.map +0 -1
- package/dist/api/test-do.js +0 -38
- package/dist/api/test-do.js.map +0 -1
- package/dist/api/types.js +0 -11
- package/dist/api/types.js.map +0 -1
- package/dist/cli/bin.js +0 -2
- package/dist/cli/main.js +0 -52342
- package/dist/do/bash.js +0 -35
- package/dist/do/bash.js.map +0 -1
- package/dist/do/fs.js +0 -25
- package/dist/do/fs.js.map +0 -1
- package/dist/do/full.js +0 -61
- package/dist/do/full.js.map +0 -1
- package/dist/do/git.js +0 -28
- package/dist/do/git.js.map +0 -1
- package/dist/do/index.js +0 -52
- package/dist/do/index.js.map +0 -1
- package/dist/lib/agent/tools/bash.js +0 -336
- package/dist/lib/agent/tools/bash.js.map +0 -1
- package/dist/lib/agent/tools/edit.js +0 -157
- package/dist/lib/agent/tools/edit.js.map +0 -1
- package/dist/lib/agent/tools/glob.js +0 -137
- package/dist/lib/agent/tools/glob.js.map +0 -1
- package/dist/lib/agent/tools/grep.js +0 -315
- package/dist/lib/agent/tools/grep.js.map +0 -1
- package/dist/lib/agent/tools/index.js +0 -71
- package/dist/lib/agent/tools/index.js.map +0 -1
- package/dist/lib/agent/tools/read.js +0 -212
- package/dist/lib/agent/tools/read.js.map +0 -1
- package/dist/lib/agent/tools/types.js +0 -197
- package/dist/lib/agent/tools/types.js.map +0 -1
- package/dist/lib/agent/tools/write.js +0 -159
- package/dist/lib/agent/tools/write.js.map +0 -1
- package/dist/lib/mixins/index.js +0 -29
- package/dist/lib/mixins/index.js.map +0 -1
- package/dist/primitives/bashx/src/ast/analyze.js +0 -1472
- package/dist/primitives/bashx/src/ast/analyze.js.map +0 -1
- package/dist/primitives/bashx/src/ast/parser.js +0 -1488
- package/dist/primitives/bashx/src/ast/parser.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/crypto.js +0 -1954
- package/dist/primitives/bashx/src/do/commands/crypto.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/data-processing.js +0 -1812
- package/dist/primitives/bashx/src/do/commands/data-processing.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/extended-utils.js +0 -804
- package/dist/primitives/bashx/src/do/commands/extended-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/math-control.js +0 -1122
- package/dist/primitives/bashx/src/do/commands/math-control.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/posix-utils.js +0 -1015
- package/dist/primitives/bashx/src/do/commands/posix-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/system-utils.js +0 -687
- package/dist/primitives/bashx/src/do/commands/system-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/test-command.js +0 -523
- package/dist/primitives/bashx/src/do/commands/test-command.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/text-processing.js +0 -1550
- package/dist/primitives/bashx/src/do/commands/text-processing.js.map +0 -1
- package/dist/primitives/bashx/src/do/container-executor.js +0 -429
- package/dist/primitives/bashx/src/do/container-executor.js.map +0 -1
- package/dist/primitives/bashx/src/do/index.js +0 -668
- package/dist/primitives/bashx/src/do/index.js.map +0 -1
- package/dist/primitives/bashx/src/do/tiered-executor.js +0 -2647
- package/dist/primitives/bashx/src/do/tiered-executor.js.map +0 -1
- package/dist/primitives/bashx/src/do/worker.js +0 -352
- package/dist/primitives/bashx/src/do/worker.js.map +0 -1
- package/dist/primitives/bashx/src/types.js +0 -10
- package/dist/primitives/bashx/src/types.js.map +0 -1
- package/dist/primitives/fsx/core/backend.js +0 -480
- package/dist/primitives/fsx/core/backend.js.map +0 -1
- package/dist/primitives/fsx/core/constants.js +0 -140
- package/dist/primitives/fsx/core/constants.js.map +0 -1
- package/dist/primitives/fsx/core/fsx.js +0 -1184
- package/dist/primitives/fsx/core/fsx.js.map +0 -1
- package/dist/primitives/fsx/core/glob/glob.js +0 -438
- package/dist/primitives/fsx/core/glob/glob.js.map +0 -1
- package/dist/primitives/fsx/core/glob/index.js +0 -8
- package/dist/primitives/fsx/core/glob/index.js.map +0 -1
- package/dist/primitives/fsx/core/glob/match.js +0 -392
- package/dist/primitives/fsx/core/glob/match.js.map +0 -1
- package/dist/primitives/fsx/core/types.js +0 -307
- package/dist/primitives/fsx/core/types.js.map +0 -1
- package/dist/sdk/capnweb-compat.js +0 -42
- package/dist/sdk/capnweb-compat.js.map +0 -1
- package/dist/sdk/client.js +0 -20
- package/dist/sdk/client.js.map +0 -1
- package/dist/sdk/index.js +0 -17
- package/dist/sdk/index.js.map +0 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Configuration Management
|
|
3
|
+
*
|
|
4
|
+
* Manages configuration stored in ~/.dotdo/config
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { readFile, writeFile, mkdir, access } from 'fs/promises'
|
|
8
|
+
import { homedir } from 'os'
|
|
9
|
+
import { join } from 'path'
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Constants
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
const CONFIG_DIR_NAME = '.dotdo'
|
|
16
|
+
const CONFIG_FILE_NAME = 'config'
|
|
17
|
+
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Types
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
export interface Config {
|
|
23
|
+
/** Base API URL for rpc.do gateway */
|
|
24
|
+
api_url: string
|
|
25
|
+
/** Output JSON instead of human-readable format */
|
|
26
|
+
json_output: boolean
|
|
27
|
+
/** Default LLM model */
|
|
28
|
+
default_model?: string
|
|
29
|
+
/** Default sender for calls/texts */
|
|
30
|
+
default_from?: string
|
|
31
|
+
/** Default email sender */
|
|
32
|
+
default_email_from?: string
|
|
33
|
+
/** Default currency for charges */
|
|
34
|
+
default_currency?: string
|
|
35
|
+
/** Custom headers to include in all requests */
|
|
36
|
+
custom_headers?: Record<string, string>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Available config keys for validation */
|
|
40
|
+
export const configKeys = [
|
|
41
|
+
'api_url',
|
|
42
|
+
'json_output',
|
|
43
|
+
'default_model',
|
|
44
|
+
'default_from',
|
|
45
|
+
'default_email_from',
|
|
46
|
+
'default_currency',
|
|
47
|
+
'custom_headers',
|
|
48
|
+
] as const
|
|
49
|
+
|
|
50
|
+
export type ConfigKey = (typeof configKeys)[number]
|
|
51
|
+
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// Default Configuration
|
|
54
|
+
// ============================================================================
|
|
55
|
+
|
|
56
|
+
export const defaultConfig: Config = {
|
|
57
|
+
api_url: 'https://rpc.do',
|
|
58
|
+
json_output: false,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Paths
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get the config directory path
|
|
67
|
+
*/
|
|
68
|
+
function getConfigDir(): string {
|
|
69
|
+
return join(homedir(), CONFIG_DIR_NAME)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get the config file path
|
|
74
|
+
*/
|
|
75
|
+
export function getConfigPath(): string {
|
|
76
|
+
return join(getConfigDir(), CONFIG_FILE_NAME)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Config Operations
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Read stored configuration, merging with defaults
|
|
85
|
+
*/
|
|
86
|
+
export async function getConfig(): Promise<Config> {
|
|
87
|
+
const configPath = getConfigPath()
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const content = await readFile(configPath, 'utf-8')
|
|
91
|
+
const stored = JSON.parse(content)
|
|
92
|
+
|
|
93
|
+
// Merge stored config with defaults
|
|
94
|
+
return {
|
|
95
|
+
...defaultConfig,
|
|
96
|
+
...stored,
|
|
97
|
+
}
|
|
98
|
+
} catch (error: unknown) {
|
|
99
|
+
// File doesn't exist or is malformed - return defaults
|
|
100
|
+
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
|
101
|
+
return { ...defaultConfig }
|
|
102
|
+
}
|
|
103
|
+
// JSON parse error - return defaults
|
|
104
|
+
return { ...defaultConfig }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Update configuration values
|
|
110
|
+
*/
|
|
111
|
+
export async function setConfig(updates: Partial<Config>): Promise<void> {
|
|
112
|
+
const configDir = getConfigDir()
|
|
113
|
+
const configPath = getConfigPath()
|
|
114
|
+
|
|
115
|
+
// Ensure config directory exists
|
|
116
|
+
try {
|
|
117
|
+
await access(configDir)
|
|
118
|
+
} catch {
|
|
119
|
+
await mkdir(configDir, { recursive: true, mode: 0o700 })
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Read existing config
|
|
123
|
+
let existing: Partial<Config> = {}
|
|
124
|
+
try {
|
|
125
|
+
const content = await readFile(configPath, 'utf-8')
|
|
126
|
+
existing = JSON.parse(content)
|
|
127
|
+
} catch {
|
|
128
|
+
// No existing config
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Merge and write
|
|
132
|
+
const merged = {
|
|
133
|
+
...existing,
|
|
134
|
+
...updates,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
await writeFile(configPath, JSON.stringify(merged, null, 2), { mode: 0o600 })
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Remove a configuration key
|
|
142
|
+
*/
|
|
143
|
+
export async function unsetConfig(key: ConfigKey): Promise<void> {
|
|
144
|
+
const config = await getConfig()
|
|
145
|
+
// Use a type-safe delete
|
|
146
|
+
const configAny = config as unknown as Record<string, unknown>
|
|
147
|
+
delete configAny[key]
|
|
148
|
+
await setConfig(config)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Validate a config key exists
|
|
153
|
+
*/
|
|
154
|
+
export function isValidConfigKey(key: string): key is ConfigKey {
|
|
155
|
+
return configKeys.includes(key as ConfigKey)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Parse and validate a config value by key
|
|
160
|
+
*/
|
|
161
|
+
export function parseConfigValue(key: ConfigKey, value: string): unknown {
|
|
162
|
+
switch (key) {
|
|
163
|
+
case 'json_output':
|
|
164
|
+
if (value === 'true') return true
|
|
165
|
+
if (value === 'false') return false
|
|
166
|
+
throw new Error(`Invalid value for ${key}: expected 'true' or 'false'`)
|
|
167
|
+
|
|
168
|
+
case 'api_url':
|
|
169
|
+
case 'default_model':
|
|
170
|
+
case 'default_from':
|
|
171
|
+
case 'default_email_from':
|
|
172
|
+
case 'default_currency':
|
|
173
|
+
return value
|
|
174
|
+
|
|
175
|
+
case 'custom_headers':
|
|
176
|
+
try {
|
|
177
|
+
return JSON.parse(value)
|
|
178
|
+
} catch {
|
|
179
|
+
throw new Error(`Invalid value for ${key}: expected valid JSON`)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
default:
|
|
183
|
+
return value
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Output Formatting
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for formatting CLI output:
|
|
5
|
+
* - JSON output for scripting
|
|
6
|
+
* - Table output for lists
|
|
7
|
+
* - Streaming output for LLM responses
|
|
8
|
+
* - Spinner for long-running operations
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Types
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
export interface OutputOptions {
|
|
16
|
+
/** Pretty print JSON */
|
|
17
|
+
pretty?: boolean
|
|
18
|
+
/** Columns to display in table */
|
|
19
|
+
columns?: string[]
|
|
20
|
+
/** Maximum width for truncation */
|
|
21
|
+
maxWidth?: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface Spinner {
|
|
25
|
+
/** Start the spinner animation */
|
|
26
|
+
start(): void
|
|
27
|
+
/** Stop the spinner */
|
|
28
|
+
stop(): void
|
|
29
|
+
/** Stop with success message */
|
|
30
|
+
succeed(message?: string): void
|
|
31
|
+
/** Stop with failure message */
|
|
32
|
+
fail(message?: string): void
|
|
33
|
+
/** Update spinner text */
|
|
34
|
+
text(message: string): void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// JSON Formatting
|
|
39
|
+
// ============================================================================
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Format data as JSON string
|
|
43
|
+
*/
|
|
44
|
+
export function formatJson(data: unknown, options: OutputOptions = {}): string {
|
|
45
|
+
if (options.pretty) {
|
|
46
|
+
return JSON.stringify(data, null, 2)
|
|
47
|
+
}
|
|
48
|
+
return JSON.stringify(data)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Table Formatting
|
|
53
|
+
// ============================================================================
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Format array of objects as ASCII table
|
|
57
|
+
*/
|
|
58
|
+
export function formatTable(
|
|
59
|
+
data: Record<string, unknown>[],
|
|
60
|
+
options: OutputOptions = {}
|
|
61
|
+
): string {
|
|
62
|
+
if (data.length === 0) {
|
|
63
|
+
return ''
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Determine columns
|
|
67
|
+
const columns = options.columns ?? Object.keys(data[0])
|
|
68
|
+
const maxWidth = options.maxWidth ?? 50
|
|
69
|
+
|
|
70
|
+
// Calculate column widths
|
|
71
|
+
const widths: Record<string, number> = {}
|
|
72
|
+
for (const col of columns) {
|
|
73
|
+
widths[col] = col.length
|
|
74
|
+
for (const row of data) {
|
|
75
|
+
const value = String(row[col] ?? '')
|
|
76
|
+
widths[col] = Math.max(widths[col], Math.min(value.length, maxWidth))
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Format header
|
|
81
|
+
const header = columns.map((col) => col.padEnd(widths[col])).join(' ')
|
|
82
|
+
const separator = columns.map((col) => '-'.repeat(widths[col])).join(' ')
|
|
83
|
+
|
|
84
|
+
// Format rows
|
|
85
|
+
const rows = data.map((row) => {
|
|
86
|
+
return columns
|
|
87
|
+
.map((col) => {
|
|
88
|
+
const value = String(row[col] ?? '')
|
|
89
|
+
const truncated = value.length > maxWidth ? value.slice(0, maxWidth - 3) + '...' : value
|
|
90
|
+
return truncated.padEnd(widths[col])
|
|
91
|
+
})
|
|
92
|
+
.join(' ')
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
return [header, separator, ...rows].join('\n')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// Streaming Output
|
|
100
|
+
// ============================================================================
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Async iterator for streaming response
|
|
104
|
+
*/
|
|
105
|
+
export async function* formatStream(
|
|
106
|
+
stream: ReadableStream<Uint8Array>
|
|
107
|
+
): AsyncGenerator<string, void, unknown> {
|
|
108
|
+
const reader = stream.getReader()
|
|
109
|
+
const decoder = new TextDecoder()
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
while (true) {
|
|
113
|
+
const { done, value } = await reader.read()
|
|
114
|
+
if (done) break
|
|
115
|
+
yield decoder.decode(value, { stream: true })
|
|
116
|
+
}
|
|
117
|
+
} finally {
|
|
118
|
+
// releaseLock may not exist in all environments (e.g., mocks)
|
|
119
|
+
if (typeof reader.releaseLock === 'function') {
|
|
120
|
+
reader.releaseLock()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Parse SSE stream and extract content
|
|
127
|
+
*/
|
|
128
|
+
export async function* parseSSEStream(
|
|
129
|
+
stream: ReadableStream<Uint8Array>
|
|
130
|
+
): AsyncGenerator<string, void, unknown> {
|
|
131
|
+
let buffer = ''
|
|
132
|
+
|
|
133
|
+
for await (const chunk of formatStream(stream)) {
|
|
134
|
+
buffer += chunk
|
|
135
|
+
|
|
136
|
+
// Process complete lines
|
|
137
|
+
const lines = buffer.split('\n')
|
|
138
|
+
buffer = lines.pop() ?? '' // Keep incomplete line in buffer
|
|
139
|
+
|
|
140
|
+
for (const line of lines) {
|
|
141
|
+
if (line.startsWith('data: ')) {
|
|
142
|
+
const data = line.slice(6)
|
|
143
|
+
if (data === '[DONE]') continue
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const parsed = JSON.parse(data)
|
|
147
|
+
if (parsed.delta) {
|
|
148
|
+
yield parsed.delta
|
|
149
|
+
} else if (parsed.content) {
|
|
150
|
+
yield parsed.content
|
|
151
|
+
} else if (parsed.choices?.[0]?.delta?.content) {
|
|
152
|
+
yield parsed.choices[0].delta.content
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
// Not JSON, might be raw content
|
|
156
|
+
yield data
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Process any remaining buffer
|
|
163
|
+
if (buffer.startsWith('data: ')) {
|
|
164
|
+
const data = buffer.slice(6)
|
|
165
|
+
if (data !== '[DONE]') {
|
|
166
|
+
try {
|
|
167
|
+
const parsed = JSON.parse(data)
|
|
168
|
+
if (parsed.delta) {
|
|
169
|
+
yield parsed.delta
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
yield data
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// Spinner
|
|
180
|
+
// ============================================================================
|
|
181
|
+
|
|
182
|
+
const SPINNER_FRAMES = ['|', '/', '-', '\\']
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Create a CLI spinner for long-running operations
|
|
186
|
+
*/
|
|
187
|
+
export function createSpinner(message: string): Spinner {
|
|
188
|
+
let intervalId: ReturnType<typeof setInterval> | null = null
|
|
189
|
+
let frameIndex = 0
|
|
190
|
+
let currentMessage = message
|
|
191
|
+
|
|
192
|
+
const render = () => {
|
|
193
|
+
const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length]
|
|
194
|
+
process.stdout.write(`\r${frame} ${currentMessage}`)
|
|
195
|
+
frameIndex++
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const clear = () => {
|
|
199
|
+
process.stdout.write('\r' + ' '.repeat(currentMessage.length + 3) + '\r')
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
start() {
|
|
204
|
+
if (intervalId) return
|
|
205
|
+
render()
|
|
206
|
+
intervalId = setInterval(render, 100)
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
stop() {
|
|
210
|
+
if (intervalId) {
|
|
211
|
+
clearInterval(intervalId)
|
|
212
|
+
intervalId = null
|
|
213
|
+
}
|
|
214
|
+
clear()
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
succeed(msg?: string) {
|
|
218
|
+
this.stop()
|
|
219
|
+
console.log(`\u2713 ${msg ?? currentMessage}`)
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
fail(msg?: string) {
|
|
223
|
+
this.stop()
|
|
224
|
+
console.log(`\u2717 ${msg ?? currentMessage}`)
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
text(msg: string) {
|
|
228
|
+
currentMessage = msg
|
|
229
|
+
},
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ============================================================================
|
|
234
|
+
// Color Output (if terminal supports it)
|
|
235
|
+
// ============================================================================
|
|
236
|
+
|
|
237
|
+
const supportsColor = process.stdout.isTTY && process.env.TERM !== 'dumb'
|
|
238
|
+
|
|
239
|
+
export const colors = {
|
|
240
|
+
red: (text: string) => (supportsColor ? `\x1b[31m${text}\x1b[0m` : text),
|
|
241
|
+
green: (text: string) => (supportsColor ? `\x1b[32m${text}\x1b[0m` : text),
|
|
242
|
+
yellow: (text: string) => (supportsColor ? `\x1b[33m${text}\x1b[0m` : text),
|
|
243
|
+
blue: (text: string) => (supportsColor ? `\x1b[34m${text}\x1b[0m` : text),
|
|
244
|
+
dim: (text: string) => (supportsColor ? `\x1b[2m${text}\x1b[0m` : text),
|
|
245
|
+
bold: (text: string) => (supportsColor ? `\x1b[1m${text}\x1b[0m` : text),
|
|
246
|
+
}
|
package/cli/src/rpc.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI RPC Client
|
|
3
|
+
*
|
|
4
|
+
* Makes authenticated requests to *.do services via rpc.do gateway.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getConfig } from './config'
|
|
8
|
+
import { getAuthHeaders, AuthError } from './auth'
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Types
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
export interface RPCError {
|
|
15
|
+
error: string
|
|
16
|
+
message?: string
|
|
17
|
+
code?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface RPCRequestOptions {
|
|
21
|
+
/** HTTP method */
|
|
22
|
+
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
|
|
23
|
+
/** Request body (will be JSON stringified) */
|
|
24
|
+
body?: unknown
|
|
25
|
+
/** Additional headers */
|
|
26
|
+
headers?: Record<string, string>
|
|
27
|
+
/** Stream the response */
|
|
28
|
+
stream?: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class RPCNetworkError extends Error {
|
|
32
|
+
constructor(message: string) {
|
|
33
|
+
super(`Network error: ${message}`)
|
|
34
|
+
this.name = 'RPCNetworkError'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class RPCAPIError extends Error {
|
|
39
|
+
status: number
|
|
40
|
+
code?: string
|
|
41
|
+
|
|
42
|
+
constructor(message: string, status: number, code?: string) {
|
|
43
|
+
super(message)
|
|
44
|
+
this.name = 'RPCAPIError'
|
|
45
|
+
this.status = status
|
|
46
|
+
this.code = code
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class RPCRateLimitError extends RPCAPIError {
|
|
51
|
+
retryAfter?: number
|
|
52
|
+
|
|
53
|
+
constructor(message: string, retryAfter?: number) {
|
|
54
|
+
super(message, 429, 'rate_limit_exceeded')
|
|
55
|
+
this.name = 'RPCRateLimitError'
|
|
56
|
+
this.retryAfter = retryAfter
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ============================================================================
|
|
61
|
+
// RPC Client
|
|
62
|
+
// ============================================================================
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Make an authenticated request to a *.do service
|
|
66
|
+
*/
|
|
67
|
+
export async function rpcRequest<T = unknown>(
|
|
68
|
+
service: string,
|
|
69
|
+
path: string,
|
|
70
|
+
options: RPCRequestOptions = {}
|
|
71
|
+
): Promise<T> {
|
|
72
|
+
const config = await getConfig()
|
|
73
|
+
const authHeaders = await getAuthHeaders()
|
|
74
|
+
|
|
75
|
+
const { method = 'GET', body, headers = {}, stream = false } = options
|
|
76
|
+
|
|
77
|
+
const url = `${config.api_url}/${service}${path}`
|
|
78
|
+
|
|
79
|
+
const requestHeaders: Record<string, string> = {
|
|
80
|
+
...authHeaders,
|
|
81
|
+
...headers,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Only set Content-Type if not already provided and body is defined
|
|
85
|
+
if (body !== undefined && !requestHeaders['Content-Type']) {
|
|
86
|
+
requestHeaders['Content-Type'] = 'application/json'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let response: Response
|
|
90
|
+
try {
|
|
91
|
+
response = await fetch(url, {
|
|
92
|
+
method,
|
|
93
|
+
headers: requestHeaders,
|
|
94
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
95
|
+
})
|
|
96
|
+
} catch (error) {
|
|
97
|
+
throw new RPCNetworkError((error as Error).message)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Handle rate limiting
|
|
101
|
+
if (response.status === 429) {
|
|
102
|
+
const retryAfter = response.headers.get('Retry-After')
|
|
103
|
+
throw new RPCRateLimitError(
|
|
104
|
+
'Rate limit exceeded. Please try again later.',
|
|
105
|
+
retryAfter ? parseInt(retryAfter, 10) : undefined
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Handle errors
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
let errorData: RPCError
|
|
112
|
+
try {
|
|
113
|
+
errorData = await response.json()
|
|
114
|
+
} catch {
|
|
115
|
+
errorData = { error: 'unknown_error', message: `Request failed with status ${response.status}` }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
throw new RPCAPIError(
|
|
119
|
+
errorData.message || errorData.error,
|
|
120
|
+
response.status,
|
|
121
|
+
errorData.code || errorData.error
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Stream response
|
|
126
|
+
if (stream && response.body) {
|
|
127
|
+
return response.body as unknown as T
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// JSON response
|
|
131
|
+
return response.json()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Make a request to calls.do
|
|
136
|
+
*/
|
|
137
|
+
export async function callsRequest<T = unknown>(
|
|
138
|
+
path: string,
|
|
139
|
+
options?: RPCRequestOptions
|
|
140
|
+
): Promise<T> {
|
|
141
|
+
return rpcRequest<T>('calls.do', path, options)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Make a request to texts.do
|
|
146
|
+
*/
|
|
147
|
+
export async function textsRequest<T = unknown>(
|
|
148
|
+
path: string,
|
|
149
|
+
options?: RPCRequestOptions
|
|
150
|
+
): Promise<T> {
|
|
151
|
+
return rpcRequest<T>('texts.do', path, options)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Make a request to emails.do
|
|
156
|
+
*/
|
|
157
|
+
export async function emailsRequest<T = unknown>(
|
|
158
|
+
path: string,
|
|
159
|
+
options?: RPCRequestOptions
|
|
160
|
+
): Promise<T> {
|
|
161
|
+
return rpcRequest<T>('emails.do', path, options)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Make a request to payments.do
|
|
166
|
+
*/
|
|
167
|
+
export async function paymentsRequest<T = unknown>(
|
|
168
|
+
path: string,
|
|
169
|
+
options?: RPCRequestOptions
|
|
170
|
+
): Promise<T> {
|
|
171
|
+
return rpcRequest<T>('payments.do', path, options)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Make a request to queue.do
|
|
176
|
+
*/
|
|
177
|
+
export async function queueRequest<T = unknown>(
|
|
178
|
+
path: string,
|
|
179
|
+
options?: RPCRequestOptions
|
|
180
|
+
): Promise<T> {
|
|
181
|
+
return rpcRequest<T>('queue.do', path, options)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Make a request to llm.do
|
|
186
|
+
*/
|
|
187
|
+
export async function llmRequest<T = unknown>(
|
|
188
|
+
path: string,
|
|
189
|
+
options?: RPCRequestOptions
|
|
190
|
+
): Promise<T> {
|
|
191
|
+
return rpcRequest<T>('llm.do', path, options)
|
|
192
|
+
}
|