@kb-labs/shared 1.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/.cursorrules +32 -0
- package/.github/workflows/ci.yml +13 -0
- package/.github/workflows/deploy.yml +28 -0
- package/.github/workflows/docker-build.yml +25 -0
- package/.github/workflows/drift-check.yml +10 -0
- package/.github/workflows/profiles-validate.yml +16 -0
- package/.github/workflows/release.yml +8 -0
- package/.kb/devkit/agents/devkit-maintainer/context.globs +15 -0
- package/.kb/devkit/agents/devkit-maintainer/permissions.yml +17 -0
- package/.kb/devkit/agents/devkit-maintainer/prompt.md +28 -0
- package/.kb/devkit/agents/devkit-maintainer/runbook.md +31 -0
- package/.kb/devkit/agents/docs-crafter/prompt.md +24 -0
- package/.kb/devkit/agents/docs-crafter/runbook.md +18 -0
- package/.kb/devkit/agents/release-manager/context.globs +7 -0
- package/.kb/devkit/agents/release-manager/prompt.md +27 -0
- package/.kb/devkit/agents/release-manager/runbook.md +17 -0
- package/.kb/devkit/agents/test-generator/context.globs +7 -0
- package/.kb/devkit/agents/test-generator/prompt.md +27 -0
- package/.kb/devkit/agents/test-generator/runbook.md +18 -0
- package/.vscode/settings.json +23 -0
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTING.md +117 -0
- package/LICENSE +21 -0
- package/README.md +306 -0
- package/docs/DECLARATIVE-FLAGS-AND-ENV.md +622 -0
- package/docs/DOCUMENTATION.md +70 -0
- package/docs/adr/0000-template.md +52 -0
- package/docs/adr/0001-architecture-and-repository-layout.md +31 -0
- package/docs/adr/0002-plugins-and-extensibility.md +44 -0
- package/docs/adr/0003-package-and-module-boundaries.md +35 -0
- package/docs/adr/0004-versioning-and-release-policy.md +36 -0
- package/docs/adr/0005-reactive-loader-pattern.md +179 -0
- package/docs/adr/0006-declarative-flags-and-env-systems.md +376 -0
- package/eslint.config.js +27 -0
- package/kb-labs.config.json +5 -0
- package/package.json +88 -0
- package/package.json.bin +25 -0
- package/package.json.lib +30 -0
- package/packages/shared-cli-ui/CHANGELOG.md +20 -0
- package/packages/shared-cli-ui/README.md +342 -0
- package/packages/shared-cli-ui/docs/ARCHITECTURE.md +105 -0
- package/packages/shared-cli-ui/eslint.config.js +27 -0
- package/packages/shared-cli-ui/package.json +72 -0
- package/packages/shared-cli-ui/src/__tests__/artifacts-display.spec.ts +89 -0
- package/packages/shared-cli-ui/src/__tests__/format.spec.ts +44 -0
- package/packages/shared-cli-ui/src/__tests__/loader-json-mode.test.ts +119 -0
- package/packages/shared-cli-ui/src/artifacts-display.ts +266 -0
- package/packages/shared-cli-ui/src/cli-auto-discovery.ts +120 -0
- package/packages/shared-cli-ui/src/colors.ts +142 -0
- package/packages/shared-cli-ui/src/command-discovery.ts +72 -0
- package/packages/shared-cli-ui/src/command-output.ts +153 -0
- package/packages/shared-cli-ui/src/command-result.ts +267 -0
- package/packages/shared-cli-ui/src/command-runner.ts +310 -0
- package/packages/shared-cli-ui/src/command-suggestions.ts +204 -0
- package/packages/shared-cli-ui/src/debug/components/output.ts +141 -0
- package/packages/shared-cli-ui/src/debug/components/trace.ts +101 -0
- package/packages/shared-cli-ui/src/debug/components/tree.ts +88 -0
- package/packages/shared-cli-ui/src/debug/formatters/ai.ts +17 -0
- package/packages/shared-cli-ui/src/debug/formatters/human.ts +98 -0
- package/packages/shared-cli-ui/src/debug/formatters/timeline.ts +94 -0
- package/packages/shared-cli-ui/src/debug/index.ts +56 -0
- package/packages/shared-cli-ui/src/debug/types.ts +57 -0
- package/packages/shared-cli-ui/src/debug/utilities.ts +203 -0
- package/packages/shared-cli-ui/src/dynamic-command-discovery.ts +131 -0
- package/packages/shared-cli-ui/src/format.ts +412 -0
- package/packages/shared-cli-ui/src/index.ts +34 -0
- package/packages/shared-cli-ui/src/loader.ts +196 -0
- package/packages/shared-cli-ui/src/manifest-parser.ts +151 -0
- package/packages/shared-cli-ui/src/modern-format.ts +271 -0
- package/packages/shared-cli-ui/src/multi-cli-suggestions.ts +159 -0
- package/packages/shared-cli-ui/src/table.ts +134 -0
- package/packages/shared-cli-ui/src/timing-tracker.ts +68 -0
- package/packages/shared-cli-ui/src/utils/context.ts +12 -0
- package/packages/shared-cli-ui/src/utils/env.ts +164 -0
- package/packages/shared-cli-ui/src/utils/flags.ts +269 -0
- package/packages/shared-cli-ui/src/utils/path.ts +8 -0
- package/packages/shared-cli-ui/tsconfig.build.json +15 -0
- package/packages/shared-cli-ui/tsconfig.json +9 -0
- package/packages/shared-cli-ui/tsup.config.ts +11 -0
- package/packages/shared-cli-ui/vitest.config.ts +15 -0
- package/packages/shared-command-kit/CHANGELOG.md +20 -0
- package/packages/shared-command-kit/LICENSE +22 -0
- package/packages/shared-command-kit/README.md +1030 -0
- package/packages/shared-command-kit/docs/HIGH-LEVEL-API.md +89 -0
- package/packages/shared-command-kit/docs/LOW-LEVEL-API.md +105 -0
- package/packages/shared-command-kit/docs/MIGRATION-GUIDE.md +135 -0
- package/packages/shared-command-kit/eslint.config.js +27 -0
- package/packages/shared-command-kit/eslint.config.ts +14 -0
- package/packages/shared-command-kit/package.json +76 -0
- package/packages/shared-command-kit/prettierrc.json +5 -0
- package/packages/shared-command-kit/src/__tests__/define-command.spec.ts +294 -0
- package/packages/shared-command-kit/src/__tests__/define-route.test.ts +285 -0
- package/packages/shared-command-kit/src/__tests__/define-system-command.spec.ts +508 -0
- package/packages/shared-command-kit/src/__tests__/define-webhook.test.ts +156 -0
- package/packages/shared-command-kit/src/__tests__/define-websocket.test.ts +316 -0
- package/packages/shared-command-kit/src/__tests__/errors.spec.ts +45 -0
- package/packages/shared-command-kit/src/__tests__/flags.spec.ts +353 -0
- package/packages/shared-command-kit/src/__tests__/platform-api.test.ts +135 -0
- package/packages/shared-command-kit/src/__tests__/plugin-context-v3.snapshot.spec.ts +240 -0
- package/packages/shared-command-kit/src/__tests__/ws-types.test.ts +359 -0
- package/packages/shared-command-kit/src/analytics/index.ts +6 -0
- package/packages/shared-command-kit/src/analytics/with-analytics.ts +195 -0
- package/packages/shared-command-kit/src/define-action.ts +100 -0
- package/packages/shared-command-kit/src/define-command.ts +113 -0
- package/packages/shared-command-kit/src/define-route.ts +113 -0
- package/packages/shared-command-kit/src/define-system-command.ts +362 -0
- package/packages/shared-command-kit/src/define-webhook.ts +115 -0
- package/packages/shared-command-kit/src/define-websocket.ts +308 -0
- package/packages/shared-command-kit/src/errors/factory.ts +282 -0
- package/packages/shared-command-kit/src/errors/format-validation.ts +144 -0
- package/packages/shared-command-kit/src/errors/format.ts +92 -0
- package/packages/shared-command-kit/src/errors/index.ts +9 -0
- package/packages/shared-command-kit/src/errors/types.ts +32 -0
- package/packages/shared-command-kit/src/flags/define.ts +92 -0
- package/packages/shared-command-kit/src/flags/index.ts +9 -0
- package/packages/shared-command-kit/src/flags/types.ts +153 -0
- package/packages/shared-command-kit/src/flags/validate.ts +358 -0
- package/packages/shared-command-kit/src/helpers/context.ts +8 -0
- package/packages/shared-command-kit/src/helpers/flags.ts +84 -0
- package/packages/shared-command-kit/src/helpers/index.ts +42 -0
- package/packages/shared-command-kit/src/helpers/patterns.ts +464 -0
- package/packages/shared-command-kit/src/helpers/platform.ts +335 -0
- package/packages/shared-command-kit/src/helpers/use-analytics.ts +95 -0
- package/packages/shared-command-kit/src/helpers/use-cache.ts +97 -0
- package/packages/shared-command-kit/src/helpers/use-config.ts +99 -0
- package/packages/shared-command-kit/src/helpers/use-embeddings.ts +49 -0
- package/packages/shared-command-kit/src/helpers/use-llm.ts +316 -0
- package/packages/shared-command-kit/src/helpers/use-logger.ts +77 -0
- package/packages/shared-command-kit/src/helpers/use-platform.ts +111 -0
- package/packages/shared-command-kit/src/helpers/use-resource-broker.ts +106 -0
- package/packages/shared-command-kit/src/helpers/use-storage.ts +71 -0
- package/packages/shared-command-kit/src/helpers/use-vector-store.ts +49 -0
- package/packages/shared-command-kit/src/helpers/validation.ts +398 -0
- package/packages/shared-command-kit/src/index.ts +410 -0
- package/packages/shared-command-kit/src/jobs.ts +132 -0
- package/packages/shared-command-kit/src/lifecycle/define-handlers.ts +366 -0
- package/packages/shared-command-kit/src/lifecycle/index.ts +6 -0
- package/packages/shared-command-kit/src/manifest.ts +127 -0
- package/packages/shared-command-kit/src/rest/define-handler.ts +187 -0
- package/packages/shared-command-kit/src/rest/index.ts +11 -0
- package/packages/shared-command-kit/src/studio/index.ts +12 -0
- package/packages/shared-command-kit/src/validation/index.ts +6 -0
- package/packages/shared-command-kit/src/validation/schema-builders.ts +409 -0
- package/packages/shared-command-kit/src/ws-types.ts +106 -0
- package/packages/shared-command-kit/tsconfig.build.json +15 -0
- package/packages/shared-command-kit/tsconfig.json +9 -0
- package/packages/shared-command-kit/tsup.config.ts +30 -0
- package/packages/shared-command-kit/vitest.config.ts +4 -0
- package/packages/shared-http/package.json +67 -0
- package/packages/shared-http/src/__tests__/log-correlation.test.ts +81 -0
- package/packages/shared-http/src/__tests__/operation-metrics-tracker.test.ts +55 -0
- package/packages/shared-http/src/http-observability-collector.ts +363 -0
- package/packages/shared-http/src/index.ts +36 -0
- package/packages/shared-http/src/log-correlation.ts +89 -0
- package/packages/shared-http/src/operation-metrics-tracker.ts +107 -0
- package/packages/shared-http/src/register-openapi.ts +108 -0
- package/packages/shared-http/src/resolve-schema-ref.ts +75 -0
- package/packages/shared-http/src/schemas.ts +29 -0
- package/packages/shared-http/src/service-observability.ts +63 -0
- package/packages/shared-http/tsconfig.build.json +15 -0
- package/packages/shared-http/tsconfig.json +9 -0
- package/packages/shared-http/tsup.config.ts +23 -0
- package/packages/shared-http/vitest.config.ts +13 -0
- package/packages/shared-perm-presets/CHANGELOG.md +20 -0
- package/packages/shared-perm-presets/README.md +78 -0
- package/packages/shared-perm-presets/eslint.config.js +27 -0
- package/packages/shared-perm-presets/package.json +45 -0
- package/packages/shared-perm-presets/src/__tests__/combine.test.ts +403 -0
- package/packages/shared-perm-presets/src/__tests__/presets.test.ts +205 -0
- package/packages/shared-perm-presets/src/combine.ts +278 -0
- package/packages/shared-perm-presets/src/index.ts +18 -0
- package/packages/shared-perm-presets/src/presets/ci-environment.ts +34 -0
- package/packages/shared-perm-presets/src/presets/full-env.ts +16 -0
- package/packages/shared-perm-presets/src/presets/git-workflow.ts +40 -0
- package/packages/shared-perm-presets/src/presets/index.ts +8 -0
- package/packages/shared-perm-presets/src/presets/kb-platform.ts +30 -0
- package/packages/shared-perm-presets/src/presets/llm-access.ts +29 -0
- package/packages/shared-perm-presets/src/presets/minimal.ts +21 -0
- package/packages/shared-perm-presets/src/presets/npm-publish.ts +48 -0
- package/packages/shared-perm-presets/src/presets/vector-store.ts +40 -0
- package/packages/shared-perm-presets/src/types.ts +192 -0
- package/packages/shared-perm-presets/tsconfig.build.json +15 -0
- package/packages/shared-perm-presets/tsconfig.json +9 -0
- package/packages/shared-perm-presets/tsup.config.ts +8 -0
- package/packages/shared-perm-presets/vitest.config.ts +9 -0
- package/packages/shared-testing/CHANGELOG.md +20 -0
- package/packages/shared-testing/README.md +430 -0
- package/packages/shared-testing/package.json +51 -0
- package/packages/shared-testing/src/__tests__/create-test-context.test.ts +199 -0
- package/packages/shared-testing/src/__tests__/mock-cache.test.ts +174 -0
- package/packages/shared-testing/src/__tests__/mock-llm.test.ts +212 -0
- package/packages/shared-testing/src/__tests__/setup-platform.test.ts +90 -0
- package/packages/shared-testing/src/__tests__/test-command.test.ts +557 -0
- package/packages/shared-testing/src/create-test-context.ts +550 -0
- package/packages/shared-testing/src/index.ts +77 -0
- package/packages/shared-testing/src/mock-cache.ts +179 -0
- package/packages/shared-testing/src/mock-llm.ts +319 -0
- package/packages/shared-testing/src/mock-logger.ts +97 -0
- package/packages/shared-testing/src/mock-storage.ts +108 -0
- package/packages/shared-testing/src/setup-platform.ts +101 -0
- package/packages/shared-testing/src/test-command.ts +288 -0
- package/packages/shared-testing/tsconfig.build.json +15 -0
- package/packages/shared-testing/tsconfig.json +9 -0
- package/packages/shared-testing/tsup.config.ts +20 -0
- package/packages/shared-testing/vitest.config.ts +3 -0
- package/packages/shared-tool-kit/CHANGELOG.md +20 -0
- package/packages/shared-tool-kit/package.json +47 -0
- package/packages/shared-tool-kit/src/__tests__/factory.test.ts +103 -0
- package/packages/shared-tool-kit/src/__tests__/mock-tool.test.ts +95 -0
- package/packages/shared-tool-kit/src/factory.ts +126 -0
- package/packages/shared-tool-kit/src/index.ts +32 -0
- package/packages/shared-tool-kit/src/testing/index.ts +84 -0
- package/packages/shared-tool-kit/tsconfig.build.json +15 -0
- package/packages/shared-tool-kit/tsconfig.json +9 -0
- package/packages/shared-tool-kit/tsup.config.ts +21 -0
- package/pnpm-workspace.yaml +11070 -0
- package/prettierrc.json +1 -0
- package/scripts/devkit-sync.mjs +37 -0
- package/scripts/hooks/post-push +9 -0
- package/scripts/hooks/pre-commit +9 -0
- package/scripts/hooks/pre-push +9 -0
- package/tsconfig.base.json +9 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +9 -0
- package/tsconfig.paths.json +50 -0
- package/tsconfig.tools.json +18 -0
- package/tsup.config.bin.ts +34 -0
- package/tsup.config.cli.ts +41 -0
- package/tsup.config.dual.ts +46 -0
- package/tsup.config.ts +36 -0
- package/tsup.external.json +104 -0
- package/vitest.config.ts +48 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/shared-command-kit
|
|
3
|
+
* Command Kit - High-level API and utilities for building CLI commands
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { PluginContextV3 } from '@kb-labs/plugin-contracts';
|
|
7
|
+
import type { FlagSchemaDefinition, InferFlags } from './flags/index';
|
|
8
|
+
|
|
9
|
+
// Re-exports
|
|
10
|
+
export * from './flags/index';
|
|
11
|
+
export * from './analytics/index';
|
|
12
|
+
export * from './errors/index';
|
|
13
|
+
export * from './helpers/index';
|
|
14
|
+
export * from './define-system-command';
|
|
15
|
+
// Removed: output-helpers (success, error, warning, info, result helpers) - no longer used
|
|
16
|
+
export * from './manifest';
|
|
17
|
+
// TODO: V3 migration - permissions helpers need to be rewritten for V3 PermissionSpec structure
|
|
18
|
+
// export * from './permissions';
|
|
19
|
+
export * from './validation/index';
|
|
20
|
+
export * from './rest/index';
|
|
21
|
+
export * from './lifecycle/index';
|
|
22
|
+
// TODO: Remove studio - it's a stub that throws error, not implemented
|
|
23
|
+
// export * from './studio/index';
|
|
24
|
+
export * from './jobs';
|
|
25
|
+
export type { CommandOutput } from '@kb-labs/shared-cli-ui';
|
|
26
|
+
|
|
27
|
+
// Plugin handler definitions (CLI, REST, Webhooks, WebSockets, Workflows)
|
|
28
|
+
export * from './define-command';
|
|
29
|
+
export * from './define-route';
|
|
30
|
+
export * from './define-webhook';
|
|
31
|
+
export * from './define-websocket';
|
|
32
|
+
export * from './define-action';
|
|
33
|
+
export * from './ws-types';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Command execution status
|
|
37
|
+
*/
|
|
38
|
+
// Note: 'warning' and 'info' are legacy statuses from cli-ui, they may be used for display purposes
|
|
39
|
+
// but semantically a command is either successful or not
|
|
40
|
+
export type CommandStatus = 'success' | 'failed' | 'error' | 'cancelled' | 'skipped' | 'warning' | 'info';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Helper types for command results (optional - use when convenient)
|
|
44
|
+
*
|
|
45
|
+
* These types make it easier to define command results without repeating `CommandResult &`.
|
|
46
|
+
* They are completely optional - you can still use `CommandResult & { ... }` directly.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* // Using helper types (optional)
|
|
51
|
+
* type MyResult = SuccessResult<{ items: Item[]; total: number }>;
|
|
52
|
+
*
|
|
53
|
+
* // Direct usage (also works)
|
|
54
|
+
* type MyResult = CommandResult & { ok: true; items: Item[]; total: number };
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export type SuccessResult<T extends Record<string, unknown> = Record<string, never>> = CommandResult & { ok: true } & T;
|
|
58
|
+
export type ErrorResult<T extends Record<string, unknown> = Record<string, never>> = CommandResult & { ok: false; error: string } & T;
|
|
59
|
+
export type ResultWith<T extends Record<string, unknown>> = CommandResult & T;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Base command result contract - all command results must extend this
|
|
63
|
+
*
|
|
64
|
+
* This defines the minimal contract that every command must fulfill.
|
|
65
|
+
* Every command MUST explicitly declare its result type via generic TResult parameter.
|
|
66
|
+
*
|
|
67
|
+
* Required fields:
|
|
68
|
+
* - `ok: boolean` - execution success status
|
|
69
|
+
*
|
|
70
|
+
* Recommended fields:
|
|
71
|
+
* - `error?: string` - error message when ok === false
|
|
72
|
+
* - `status?: CommandStatus` - execution status (auto-inferred if not provided)
|
|
73
|
+
*
|
|
74
|
+
* Additional fields should be added via generic TResult type parameter.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* // Minimal result (not recommended - use explicit type)
|
|
79
|
+
* type MyResult = CommandResult; // { ok: boolean; error?: string; status?: CommandStatus }
|
|
80
|
+
*
|
|
81
|
+
* // Extended result with custom fields (RECOMMENDED)
|
|
82
|
+
* type WorkflowRunResult = CommandResult & {
|
|
83
|
+
* run: WorkflowRun;
|
|
84
|
+
* timingMs: number;
|
|
85
|
+
* };
|
|
86
|
+
*
|
|
87
|
+
* type ListResult = CommandResult & {
|
|
88
|
+
* items: Item[];
|
|
89
|
+
* total: number;
|
|
90
|
+
* };
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export type CommandResult = {
|
|
94
|
+
/** Whether the command executed successfully - REQUIRED */
|
|
95
|
+
ok: boolean;
|
|
96
|
+
/** Error message if ok === false - RECOMMENDED for error cases */
|
|
97
|
+
error?: string;
|
|
98
|
+
/** Execution status - automatically inferred from ok if not provided */
|
|
99
|
+
status?: CommandStatus;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Command handler function signature
|
|
104
|
+
*
|
|
105
|
+
* TConfig is the product configuration type (auto-loaded from kb.config.json)
|
|
106
|
+
* TEnv is the environment variables type (validated at runtime)
|
|
107
|
+
* TResult must extend CommandResult ({ ok: boolean }) and represents the contract
|
|
108
|
+
* for what the command returns. This ensures type safety and enables future contract
|
|
109
|
+
* validation.
|
|
110
|
+
*
|
|
111
|
+
* TArgv is optional - by default it's `string[]`, but you can provide a tuple type
|
|
112
|
+
* for strict argument typing if needed.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* // Default: argv is string[]
|
|
117
|
+
* handler: (ctx, argv, flags) => { ... }
|
|
118
|
+
*
|
|
119
|
+
* // With typed config
|
|
120
|
+
* handler: (ctx, argv, flags) => {
|
|
121
|
+
* ctx.config?.llmProvider // TypeScript knows the config type
|
|
122
|
+
* }
|
|
123
|
+
*
|
|
124
|
+
* // With typed env
|
|
125
|
+
* handler: (ctx, argv, flags) => {
|
|
126
|
+
* ctx.env.OPENAI_API_KEY // TypeScript knows it's a string
|
|
127
|
+
* }
|
|
128
|
+
*
|
|
129
|
+
* // Strict typing: argv is tuple ['workflow-id', ...string[]]
|
|
130
|
+
* handler: (ctx, argv: ['workflow-id', ...string[]], flags) => {
|
|
131
|
+
* const workflowId = argv[0]; // TypeScript knows it's 'workflow-id'
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export type CommandHandler<
|
|
136
|
+
_TConfig = any,
|
|
137
|
+
TFlags extends Record<string, unknown> = Record<string, unknown>,
|
|
138
|
+
TResult extends CommandResult = CommandResult,
|
|
139
|
+
TArgv extends readonly string[] = string[],
|
|
140
|
+
_TEnv = Record<string, string | undefined>
|
|
141
|
+
> = (
|
|
142
|
+
ctx: PluginContextV3,
|
|
143
|
+
argv: TArgv,
|
|
144
|
+
flags: TFlags
|
|
145
|
+
) => Promise<number | TResult> | number | TResult;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Command formatter function
|
|
149
|
+
*
|
|
150
|
+
* All type parameters are optional with defaults - same as CommandHandler.
|
|
151
|
+
* Use explicit types when you want type safety, skip them for simplicity.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // Default: argv is string[]
|
|
156
|
+
* formatter: (result, ctx, flags) => { ... }
|
|
157
|
+
*
|
|
158
|
+
* // With typed config
|
|
159
|
+
* formatter: (result, ctx, flags) => {
|
|
160
|
+
* ctx.config?.llmProvider // TypeScript knows the config type
|
|
161
|
+
* }
|
|
162
|
+
*
|
|
163
|
+
* // With typed env
|
|
164
|
+
* formatter: (result, ctx, flags) => {
|
|
165
|
+
* ctx.env.OPENAI_API_KEY // TypeScript knows it's a string
|
|
166
|
+
* }
|
|
167
|
+
*
|
|
168
|
+
* // Strict typing: argv is tuple ['workflow-id', ...string[]]
|
|
169
|
+
* formatter: (result, ctx, flags, argv: ['workflow-id', ...string[]]) => {
|
|
170
|
+
* const workflowId = argv[0]; // TypeScript knows it's 'workflow-id'
|
|
171
|
+
* }
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export type CommandFormatter<
|
|
175
|
+
_TConfig = any,
|
|
176
|
+
TFlags extends Record<string, unknown> = Record<string, unknown>,
|
|
177
|
+
TResult extends CommandResult = CommandResult,
|
|
178
|
+
TArgv extends readonly string[] = string[],
|
|
179
|
+
_TEnv = Record<string, string | undefined>
|
|
180
|
+
> = (
|
|
181
|
+
result: TResult,
|
|
182
|
+
ctx: PluginContextV3,
|
|
183
|
+
flags: TFlags,
|
|
184
|
+
argv?: TArgv
|
|
185
|
+
) => void;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Command configuration
|
|
189
|
+
*
|
|
190
|
+
* All type parameters are optional with sensible defaults:
|
|
191
|
+
* - TConfig defaults to any (product config type)
|
|
192
|
+
* - TFlags defaults to FlagSchemaDefinition (flags are Record<string, unknown>)
|
|
193
|
+
* - TResult defaults to CommandResult (basic { ok: boolean })
|
|
194
|
+
* - TArgv defaults to string[] (arguments are string[])
|
|
195
|
+
* - TEnv defaults to Record<string, string | undefined> (process.env)
|
|
196
|
+
*
|
|
197
|
+
* Use explicit types when you want better type safety, but everything works without them.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* // Default: argv is string[]
|
|
202
|
+
* const cmd = defineCommand({
|
|
203
|
+
* handler: (ctx, argv, flags) => { ... }
|
|
204
|
+
* });
|
|
205
|
+
*
|
|
206
|
+
* // Simple usage with flags and result only (RECOMMENDED)
|
|
207
|
+
* const cmd = defineCommand<MyFlags, MyResult>({
|
|
208
|
+
* handler: (ctx, argv, flags) => {
|
|
209
|
+
* // flags are typed as InferFlags<MyFlags>
|
|
210
|
+
* return { ok: true, ...result };
|
|
211
|
+
* }
|
|
212
|
+
* });
|
|
213
|
+
*
|
|
214
|
+
* // With typed config (third parameter)
|
|
215
|
+
* type MindConfig = { llmProvider: string; maxTokens: number };
|
|
216
|
+
* const cmd = defineCommand<Flags, Result, MindConfig>({
|
|
217
|
+
* handler: (ctx, argv, flags) => {
|
|
218
|
+
* ctx.config?.llmProvider // TypeScript knows it's a string
|
|
219
|
+
* }
|
|
220
|
+
* });
|
|
221
|
+
*
|
|
222
|
+
* // With typed env (fifth parameter)
|
|
223
|
+
* type Env = { OPENAI_API_KEY: string; DEBUG?: string };
|
|
224
|
+
* const cmd = defineCommand<Flags, Result, Config, Argv, Env>({
|
|
225
|
+
* handler: (ctx, argv, flags) => {
|
|
226
|
+
* ctx.env.OPENAI_API_KEY // string (validated!)
|
|
227
|
+
* }
|
|
228
|
+
* });
|
|
229
|
+
*
|
|
230
|
+
* // Strict typing: argv is tuple ['workflow-id', ...string[]]
|
|
231
|
+
* const cmd = defineCommand<Flags, Result, Config, ['workflow-id', ...string[]]>({
|
|
232
|
+
* handler: (ctx, argv, flags) => {
|
|
233
|
+
* const workflowId = argv[0]; // TypeScript knows it's 'workflow-id'
|
|
234
|
+
* }
|
|
235
|
+
* });
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
export interface CommandConfig<
|
|
239
|
+
TFlags extends FlagSchemaDefinition = FlagSchemaDefinition,
|
|
240
|
+
TResult extends CommandResult = CommandResult,
|
|
241
|
+
TConfig = any,
|
|
242
|
+
TArgv extends readonly string[] = string[],
|
|
243
|
+
TEnv = Record<string, string | undefined>
|
|
244
|
+
> {
|
|
245
|
+
/** Command name (for logging) */
|
|
246
|
+
name?: string;
|
|
247
|
+
/** Flag schema definition */
|
|
248
|
+
flags: TFlags;
|
|
249
|
+
/**
|
|
250
|
+
* Analytics configuration (legacy field, kept for backward compatibility)
|
|
251
|
+
* Use ctx.platform.analytics.track() or withAnalytics() helper instead
|
|
252
|
+
*/
|
|
253
|
+
analytics?: {
|
|
254
|
+
command?: string;
|
|
255
|
+
startEvent?: string;
|
|
256
|
+
finishEvent?: string;
|
|
257
|
+
actor?: string;
|
|
258
|
+
context?: Record<string, unknown>;
|
|
259
|
+
includeFlags?: boolean;
|
|
260
|
+
};
|
|
261
|
+
/**
|
|
262
|
+
* Optional environment variable schema for validation.
|
|
263
|
+
* If provided, required env vars will be validated at runtime.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```typescript
|
|
267
|
+
* env: {
|
|
268
|
+
* OPENAI_API_KEY: { required: true },
|
|
269
|
+
* DEBUG: { required: false },
|
|
270
|
+
* }
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
env?: Record<string, { required?: boolean }>;
|
|
274
|
+
/** Command handler - must return TResult */
|
|
275
|
+
handler: CommandHandler<TConfig, InferFlags<TFlags>, TResult, TArgv, TEnv>;
|
|
276
|
+
/** Optional formatter for output - receives TResult */
|
|
277
|
+
formatter?: CommandFormatter<TConfig, InferFlags<TFlags>, TResult, TArgv, TEnv>;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Define a command with automatic validation, logging, analytics, and error handling
|
|
282
|
+
*
|
|
283
|
+
* Returns a function with signature `(ctx, argv, flags) => Promise<number>`
|
|
284
|
+
* that can be used as a command handler in manifest.v2.ts
|
|
285
|
+
*
|
|
286
|
+
* All type parameters are optional - use them when you want type safety, skip them for simplicity.
|
|
287
|
+
*
|
|
288
|
+
* @template TFlags - Flag schema definition type (FIRST - most commonly used)
|
|
289
|
+
* @template TResult - Command result type (must extend CommandResult)
|
|
290
|
+
* @template TConfig - Product configuration type (auto-loaded from kb.config.json)
|
|
291
|
+
* @template TArgv - Argument tuple type (defaults to string[])
|
|
292
|
+
* @template TEnv - Environment variables type (defaults to process.env)
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* // Simple command with flags and result (RECOMMENDED)
|
|
297
|
+
* export const releaseRunHandler = defineCommand<
|
|
298
|
+
* { scope: { type: 'string'; required: true } }, // flags
|
|
299
|
+
* CommandResult & { published: number } // result
|
|
300
|
+
* >({
|
|
301
|
+
* name: 'release:run',
|
|
302
|
+
* flags: {
|
|
303
|
+
* scope: { type: 'string', required: true },
|
|
304
|
+
* 'dry-run': { type: 'boolean', default: false },
|
|
305
|
+
* },
|
|
306
|
+
* analytics: {
|
|
307
|
+
* startEvent: 'RELEASE_RUN_STARTED',
|
|
308
|
+
* finishEvent: 'RELEASE_RUN_FINISHED',
|
|
309
|
+
* },
|
|
310
|
+
* async handler(ctx, argv, flags) {
|
|
311
|
+
* ctx.platform?.logger?.info('Release started', { scope: flags.scope });
|
|
312
|
+
* ctx.tracker.checkpoint('planning');
|
|
313
|
+
* // ... business logic
|
|
314
|
+
* return { ok: true, published: 5 };
|
|
315
|
+
* },
|
|
316
|
+
* });
|
|
317
|
+
*
|
|
318
|
+
* // Command with typed config (third parameter)
|
|
319
|
+
* type MindConfig = { llmProvider: string; maxTokens: number };
|
|
320
|
+
* type RagQueryFlags = {
|
|
321
|
+
* text: { type: 'string'; required: true };
|
|
322
|
+
* mode: { type: 'string' };
|
|
323
|
+
* };
|
|
324
|
+
* type RagQueryResult = CommandResult & { answer: string; confidence: number };
|
|
325
|
+
*
|
|
326
|
+
* export const ragQueryHandler = defineCommand<
|
|
327
|
+
* RagQueryFlags,
|
|
328
|
+
* RagQueryResult,
|
|
329
|
+
* MindConfig
|
|
330
|
+
* >({
|
|
331
|
+
* flags: {
|
|
332
|
+
* text: { type: 'string', required: true },
|
|
333
|
+
* mode: { type: 'string', default: 'instant' },
|
|
334
|
+
* },
|
|
335
|
+
* async handler(ctx, argv, flags) {
|
|
336
|
+
* // ctx.config is typed as MindConfig | undefined
|
|
337
|
+
* const provider = ctx.config?.llmProvider ?? 'openai';
|
|
338
|
+
* const maxTokens = ctx.config?.maxTokens ?? 4000;
|
|
339
|
+
*
|
|
340
|
+
* // flags.text is typed as string (required)
|
|
341
|
+
* // flags.mode is typed as string | undefined
|
|
342
|
+
*
|
|
343
|
+
* const answer = await query(flags.text, { provider, maxTokens });
|
|
344
|
+
* return { ok: true, answer, confidence: 0.85 };
|
|
345
|
+
* },
|
|
346
|
+
* });
|
|
347
|
+
*
|
|
348
|
+
* // Command with typed env variables (fifth parameter)
|
|
349
|
+
* type Env = {
|
|
350
|
+
* OPENAI_API_KEY: string;
|
|
351
|
+
* DEBUG?: string;
|
|
352
|
+
* };
|
|
353
|
+
*
|
|
354
|
+
* export const envAwareHandler = defineCommand<Flags, Result, Config, Argv, Env>({
|
|
355
|
+
* env: {
|
|
356
|
+
* OPENAI_API_KEY: { required: true },
|
|
357
|
+
* DEBUG: { required: false },
|
|
358
|
+
* },
|
|
359
|
+
* flags: { ... },
|
|
360
|
+
* async handler(ctx, argv, flags) {
|
|
361
|
+
* // ctx.env.OPENAI_API_KEY is typed as string (validated!)
|
|
362
|
+
* const apiKey = ctx.env.OPENAI_API_KEY;
|
|
363
|
+
* // ctx.env.DEBUG is typed as string | undefined
|
|
364
|
+
* const debug = ctx.env.DEBUG;
|
|
365
|
+
* return { ok: true };
|
|
366
|
+
* },
|
|
367
|
+
* });
|
|
368
|
+
*
|
|
369
|
+
* // Command with UI output (new convenience methods)
|
|
370
|
+
* export const processDataHandler = defineCommand<
|
|
371
|
+
* { json: { type: 'boolean' } },
|
|
372
|
+
* CommandResult & { processed: number; items: string[] }
|
|
373
|
+
* >({
|
|
374
|
+
* name: 'process:data',
|
|
375
|
+
* flags: {
|
|
376
|
+
* json: { type: 'boolean', default: false },
|
|
377
|
+
* },
|
|
378
|
+
* async handler(ctx, argv, flags) {
|
|
379
|
+
* // Show progress (CLI only, no-op in REST/Workflow)
|
|
380
|
+
* ctx.ui?.startProgress('loading', 'Fetching data...');
|
|
381
|
+
* const data = await fetchData();
|
|
382
|
+
* ctx.ui?.completeProgress('loading', 'Data loaded!');
|
|
383
|
+
*
|
|
384
|
+
* // Process data
|
|
385
|
+
* const result = processItems(data);
|
|
386
|
+
*
|
|
387
|
+
* // UI output (CLI only)
|
|
388
|
+
* if (!flags.json) {
|
|
389
|
+
* if (ctx.ui?.success) {
|
|
390
|
+
* ctx.ui.success('Processing Complete', [
|
|
391
|
+
* { header: 'Summary', items: [`Processed: ${result.processed}`, `Total: ${result.items.length}`] },
|
|
392
|
+
* { items: result.items.map(i => `✓ ${i}`) },
|
|
393
|
+
* ]);
|
|
394
|
+
* }
|
|
395
|
+
* } else {
|
|
396
|
+
* ctx.ui?.json(result);
|
|
397
|
+
* }
|
|
398
|
+
*
|
|
399
|
+
* // Return value (for invoke/REST/workflow)
|
|
400
|
+
* return { ok: true, ...result };
|
|
401
|
+
* },
|
|
402
|
+
* });
|
|
403
|
+
*
|
|
404
|
+
* // Note: Use ctx.ui.showError() for error display (error() is from PresenterFacade)
|
|
405
|
+
* // Available methods: success(), showError(), warning(), info()
|
|
406
|
+
* // Progress helpers: startProgress(), updateProgress(), completeProgress(), failProgress()
|
|
407
|
+
* // Low-level UI: table(), keyValue(), list(), box(), sideBox()
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job definition helpers
|
|
3
|
+
* @module @kb-labs/shared-command-kit/jobs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { JobDecl, PermissionSpec, PluginContextV3 } from '@kb-labs/plugin-contracts';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Job input passed to handler at runtime
|
|
10
|
+
*/
|
|
11
|
+
export interface JobInput {
|
|
12
|
+
/** Job identifier */
|
|
13
|
+
jobId: string;
|
|
14
|
+
/** When the job was scheduled to execute */
|
|
15
|
+
executedAt: Date;
|
|
16
|
+
/** How many times this job has run */
|
|
17
|
+
runCount: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Job handler function signature
|
|
22
|
+
*
|
|
23
|
+
* @template TInput - Custom input type (extends JobInput)
|
|
24
|
+
* @template TOutput - Handler return type
|
|
25
|
+
*/
|
|
26
|
+
export type JobHandler<
|
|
27
|
+
TInput extends JobInput = JobInput,
|
|
28
|
+
TOutput = { ok: boolean; [key: string]: unknown }
|
|
29
|
+
> = (input: TInput, ctx: PluginContextV3) => Promise<TOutput>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Job definition configuration
|
|
33
|
+
*
|
|
34
|
+
* Combines JobDecl manifest fields with the actual handler function
|
|
35
|
+
* for type-safe job creation.
|
|
36
|
+
*/
|
|
37
|
+
export interface JobDefinition<
|
|
38
|
+
TInput extends JobInput = JobInput,
|
|
39
|
+
TOutput = { ok: boolean; [key: string]: unknown }
|
|
40
|
+
> {
|
|
41
|
+
/** Unique job identifier within plugin (e.g., 'auto-index') */
|
|
42
|
+
id: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Cron schedule expression
|
|
46
|
+
* Supports shortcuts (@hourly, @daily, @weekly, @monthly, @yearly) and standard cron format
|
|
47
|
+
*/
|
|
48
|
+
schedule: string;
|
|
49
|
+
|
|
50
|
+
/** Human-readable description */
|
|
51
|
+
describe?: string;
|
|
52
|
+
|
|
53
|
+
/** Whether job is enabled (default: true) */
|
|
54
|
+
enabled?: boolean;
|
|
55
|
+
|
|
56
|
+
/** Job priority (1-10, default: 5, higher = more important) */
|
|
57
|
+
priority?: number;
|
|
58
|
+
|
|
59
|
+
/** Execution timeout in milliseconds (default: 60000 = 1min) */
|
|
60
|
+
timeout?: number;
|
|
61
|
+
|
|
62
|
+
/** Number of retry attempts on failure (default: 2) */
|
|
63
|
+
retries?: number;
|
|
64
|
+
|
|
65
|
+
/** Tags for filtering and organization */
|
|
66
|
+
tags?: string[];
|
|
67
|
+
|
|
68
|
+
/** Permissions for job execution (filesystem, network, quotas) */
|
|
69
|
+
permissions?: PermissionSpec;
|
|
70
|
+
|
|
71
|
+
/** Job handler function */
|
|
72
|
+
handler: JobHandler<TInput, TOutput>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Defined job object with manifest conversion
|
|
77
|
+
*/
|
|
78
|
+
export interface DefinedJob<
|
|
79
|
+
TInput extends JobInput = JobInput,
|
|
80
|
+
TOutput = { ok: boolean; [key: string]: unknown }
|
|
81
|
+
> {
|
|
82
|
+
/** Job configuration */
|
|
83
|
+
readonly config: Omit<JobDefinition<TInput, TOutput>, 'handler'> & { handler: string };
|
|
84
|
+
|
|
85
|
+
/** Job handler function */
|
|
86
|
+
readonly handler: JobHandler<TInput, TOutput>;
|
|
87
|
+
|
|
88
|
+
/** Convert to manifest JobDecl */
|
|
89
|
+
toManifest(handlerPath: string): JobDecl;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Define a type-safe job with handler
|
|
94
|
+
*
|
|
95
|
+
* This helper provides compile-time type safety for job definitions
|
|
96
|
+
* and allows sharing the same handler function between manifest and runtime.
|
|
97
|
+
*
|
|
98
|
+
* The handler function can be exported from a separate file and the manifest
|
|
99
|
+
* references it via the handler path.
|
|
100
|
+
*
|
|
101
|
+
* See plugin-template/src/jobs/hello.ts for a complete example.
|
|
102
|
+
*
|
|
103
|
+
* @param definition - Job configuration with handler
|
|
104
|
+
* @returns DefinedJob object with handler and manifest conversion
|
|
105
|
+
*/
|
|
106
|
+
export function defineJob<
|
|
107
|
+
TInput extends JobInput = JobInput,
|
|
108
|
+
TOutput = { ok: boolean; [key: string]: unknown }
|
|
109
|
+
>(
|
|
110
|
+
definition: JobDefinition<TInput, TOutput>
|
|
111
|
+
): DefinedJob<TInput, TOutput> {
|
|
112
|
+
const { handler, ...config } = definition;
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
config: { ...config, handler: '' }, // handler path will be set in toManifest()
|
|
116
|
+
handler,
|
|
117
|
+
toManifest(handlerPath: string): JobDecl {
|
|
118
|
+
// JobDecl now extends CronDecl, which has job.type instead of handler
|
|
119
|
+
return {
|
|
120
|
+
id: config.id,
|
|
121
|
+
schedule: config.schedule,
|
|
122
|
+
job: {
|
|
123
|
+
type: config.id, // Use job id as type
|
|
124
|
+
payload: {}, // Empty payload by default
|
|
125
|
+
},
|
|
126
|
+
describe: config.describe,
|
|
127
|
+
enabled: config.enabled,
|
|
128
|
+
permissions: definition.permissions,
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|