@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,342 @@
|
|
|
1
|
+
# @kb-labs/shared-cli-ui
|
|
2
|
+
|
|
3
|
+
> **Shared CLI UI utilities for KB Labs projects - colors, formatting, progress indicators.** Provides command suggestions, validation, multi-CLI support, formatting utilities, and consistent UX components for CLI applications.
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
[](https://pnpm.io/)
|
|
8
|
+
|
|
9
|
+
## 🎯 Vision & Purpose
|
|
10
|
+
|
|
11
|
+
**@kb-labs/shared-cli-ui** provides shared CLI UI utilities for KB Labs ecosystem. It includes command suggestions, validation, multi-CLI support, formatting utilities, colors, progress indicators, and consistent UX components for all CLI applications.
|
|
12
|
+
|
|
13
|
+
### What Problem Does This Solve?
|
|
14
|
+
|
|
15
|
+
- **CLI UX Consistency**: CLI tools need consistent UI - cli-ui provides shared components
|
|
16
|
+
- **Command Discovery**: Need to discover and suggest commands - cli-ui provides discovery utilities
|
|
17
|
+
- **Formatting**: Need consistent output formatting - cli-ui provides formatting utilities
|
|
18
|
+
- **Multi-CLI Support**: Need to manage multiple CLI packages - cli-ui provides multi-CLI manager
|
|
19
|
+
|
|
20
|
+
### Why Does This Package Exist?
|
|
21
|
+
|
|
22
|
+
- **Unified CLI UX**: All KB Labs CLI tools use the same UI components
|
|
23
|
+
- **Code Reuse**: Avoid duplicating CLI UI code
|
|
24
|
+
- **Consistency**: Ensure consistent user experience across CLI tools
|
|
25
|
+
- **Developer Experience**: Easy-to-use utilities for CLI development
|
|
26
|
+
|
|
27
|
+
### What Makes This Package Unique?
|
|
28
|
+
|
|
29
|
+
- **Comprehensive Utilities**: Wide range of CLI UI utilities
|
|
30
|
+
- **Multi-CLI Support**: Manage suggestions across multiple CLI packages
|
|
31
|
+
- **Command Discovery**: Automatic command discovery from manifests
|
|
32
|
+
- **Formatting**: Rich formatting utilities (tables, boxes, colors)
|
|
33
|
+
|
|
34
|
+
## 🚀 Quick Start
|
|
35
|
+
|
|
36
|
+
### Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm add @kb-labs/shared-cli-ui
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Basic Usage
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { box, table, keyValue } from '@kb-labs/shared-cli-ui';
|
|
46
|
+
|
|
47
|
+
const output = box('Title', ['Line 1', 'Line 2']);
|
|
48
|
+
const tableOutput = table([['A', 'B'], ['1', '2']], ['Col1', 'Col2']);
|
|
49
|
+
const kvOutput = keyValue({ key: 'value' });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## ✨ Features
|
|
53
|
+
|
|
54
|
+
- **Command Suggestions**: Generate contextual suggestions for CLI commands
|
|
55
|
+
- **Command Validation**: Check if commands are available before suggesting them
|
|
56
|
+
- **Multi-CLI Support**: Manage suggestions across multiple CLI packages
|
|
57
|
+
- **Manifest Parsing**: Extract command information from CLI manifests
|
|
58
|
+
- **Consistent UX**: Shared UI components and styling
|
|
59
|
+
|
|
60
|
+
## Command Suggestions
|
|
61
|
+
|
|
62
|
+
### Basic Usage
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import {
|
|
66
|
+
createCommandRegistry,
|
|
67
|
+
generateDevlinkSuggestions
|
|
68
|
+
} from '@kb-labs/shared-cli-ui';
|
|
69
|
+
|
|
70
|
+
// Create a registry of available commands
|
|
71
|
+
const registry = createCommandRegistry([
|
|
72
|
+
'devlink:apply',
|
|
73
|
+
'devlink:clean',
|
|
74
|
+
'devlink:plan'
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
// Generate suggestions based on warnings
|
|
78
|
+
const suggestions = generateDevlinkSuggestions(
|
|
79
|
+
new Set(['LOCK_MISMATCH']),
|
|
80
|
+
{ undo: { available: true } },
|
|
81
|
+
registry
|
|
82
|
+
);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Multi-CLI Integration
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { MultiCLISuggestions } from '@kb-labs/shared-cli-ui';
|
|
89
|
+
|
|
90
|
+
// Create a multi-CLI manager
|
|
91
|
+
const manager = new MultiCLISuggestions();
|
|
92
|
+
|
|
93
|
+
// Register your CLI package
|
|
94
|
+
manager.registerPackage({
|
|
95
|
+
name: 'my-cli',
|
|
96
|
+
group: 'my-cli',
|
|
97
|
+
commands: myCommands,
|
|
98
|
+
priority: 80
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Generate suggestions from all registered packages
|
|
102
|
+
const suggestions = manager.generateAllSuggestions({
|
|
103
|
+
warningCodes: new Set(['MY_WARNING']),
|
|
104
|
+
undo: { available: true }
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Integration Guide
|
|
109
|
+
|
|
110
|
+
### 1. Create CLI Suggestions Module
|
|
111
|
+
|
|
112
|
+
Create a `cli-suggestions.ts` file in your CLI package:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import {
|
|
116
|
+
MultiCLISuggestions,
|
|
117
|
+
type CommandSuggestion
|
|
118
|
+
} from '@kb-labs/shared-cli-ui';
|
|
119
|
+
import { commands } from './cli.manifest.js';
|
|
120
|
+
|
|
121
|
+
export function generateMyCLISuggestions(
|
|
122
|
+
warningCodes: Set<string>,
|
|
123
|
+
context: any
|
|
124
|
+
): CommandSuggestion[] {
|
|
125
|
+
const suggestions: CommandSuggestion[] = [];
|
|
126
|
+
|
|
127
|
+
if (warningCodes.has('MY_WARNING')) {
|
|
128
|
+
suggestions.push({
|
|
129
|
+
id: 'MY_COMMAND',
|
|
130
|
+
command: 'kb my-cli command',
|
|
131
|
+
args: [],
|
|
132
|
+
description: 'Execute my command',
|
|
133
|
+
impact: 'safe',
|
|
134
|
+
when: 'MY_WARNING',
|
|
135
|
+
available: true
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return suggestions;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function createMyCLISuggestions(): MultiCLISuggestions {
|
|
143
|
+
const manager = new MultiCLISuggestions();
|
|
144
|
+
|
|
145
|
+
manager.registerPackage({
|
|
146
|
+
name: 'my-cli',
|
|
147
|
+
group: 'my-cli',
|
|
148
|
+
commands,
|
|
149
|
+
priority: 80
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return manager;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 2. Register with Main CLI
|
|
157
|
+
|
|
158
|
+
In your main CLI (e.g., devlink), register the package:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { MultiCLISuggestions } from '@kb-labs/shared-cli-ui';
|
|
162
|
+
import { createMyCLISuggestions } from '@kb-labs/my-cli/cli-suggestions';
|
|
163
|
+
|
|
164
|
+
const multiCLI = new MultiCLISuggestions();
|
|
165
|
+
|
|
166
|
+
// Register all CLI packages
|
|
167
|
+
multiCLI.registerPackage(devlinkPackage);
|
|
168
|
+
multiCLI.registerPackage(myCLIPackage);
|
|
169
|
+
|
|
170
|
+
// Generate suggestions
|
|
171
|
+
const suggestions = multiCLI.generateAllSuggestions(context);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 3. Command Priority
|
|
175
|
+
|
|
176
|
+
Set priority for your CLI package:
|
|
177
|
+
- **100**: Core tools (devlink)
|
|
178
|
+
- **80**: Important tools (mind)
|
|
179
|
+
- **70**: Utility tools (tox)
|
|
180
|
+
- **50**: Optional tools (ai-review)
|
|
181
|
+
|
|
182
|
+
## API Reference
|
|
183
|
+
|
|
184
|
+
### CommandSuggestion
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
interface CommandSuggestion {
|
|
188
|
+
id: string;
|
|
189
|
+
command: string;
|
|
190
|
+
args: string[];
|
|
191
|
+
description: string;
|
|
192
|
+
impact: 'safe' | 'disruptive';
|
|
193
|
+
when: string;
|
|
194
|
+
available?: boolean;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### MultiCLISuggestions
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
class MultiCLISuggestions {
|
|
202
|
+
registerPackage(pkg: CLIPackage): void;
|
|
203
|
+
generateAllSuggestions(context: MultiCLIContext): CommandSuggestion[];
|
|
204
|
+
generateGroupSuggestions(group: string, context: MultiCLIContext): CommandSuggestion[];
|
|
205
|
+
getAvailableCommands(group: string): string[];
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Command Registry
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
function createCommandRegistry(commands: string[]): CommandRegistry;
|
|
213
|
+
function isCommandAvailable(command: string, registry: CommandRegistry): boolean;
|
|
214
|
+
function validateSuggestions(suggestions: CommandSuggestion[], registry: CommandRegistry): CommandSuggestion[];
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Artifacts Display
|
|
218
|
+
|
|
219
|
+
The artifacts display system provides consistent, beautiful display of generated files and artifacts across all CLI commands.
|
|
220
|
+
|
|
221
|
+
### Features
|
|
222
|
+
|
|
223
|
+
- **Consistent Formatting**: Unified display format across all CLI packages
|
|
224
|
+
- **Multiple Display Modes**: Compact, detailed, and grouped views
|
|
225
|
+
- **Smart Sorting**: By time (newest first) by default, with type and custom options
|
|
226
|
+
- **Size & Time Info**: Human-readable file sizes and relative timestamps
|
|
227
|
+
- **Path Normalization**: Shows relative paths for better readability
|
|
228
|
+
- **Federal Sorting**: All CLI packages automatically get time-based sorting
|
|
229
|
+
|
|
230
|
+
### Usage
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
import {
|
|
234
|
+
displayArtifacts,
|
|
235
|
+
displayArtifactsCompact,
|
|
236
|
+
displaySingleArtifact,
|
|
237
|
+
type ArtifactInfo
|
|
238
|
+
} from '@kb-labs/shared-cli-ui';
|
|
239
|
+
|
|
240
|
+
// Define artifacts
|
|
241
|
+
const artifacts: ArtifactInfo[] = [
|
|
242
|
+
{
|
|
243
|
+
name: 'Plan',
|
|
244
|
+
path: '/path/to/.kb/devlink/last-plan.json',
|
|
245
|
+
size: 1024,
|
|
246
|
+
modified: new Date(),
|
|
247
|
+
description: 'Last generated plan'
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: 'Lock',
|
|
251
|
+
path: '/path/to/.kb/devlink/lock.json',
|
|
252
|
+
size: 2048,
|
|
253
|
+
modified: new Date(Date.now() - 3600000),
|
|
254
|
+
description: 'Dependency lock file'
|
|
255
|
+
}
|
|
256
|
+
];
|
|
257
|
+
|
|
258
|
+
// Display in compact format (for status-like displays)
|
|
259
|
+
const compactDisplay = displayArtifactsCompact(artifacts, {
|
|
260
|
+
maxItems: 5,
|
|
261
|
+
showSize: true
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Display with full details
|
|
265
|
+
const fullDisplay = displayArtifacts(artifacts, {
|
|
266
|
+
showSize: true,
|
|
267
|
+
showTime: true,
|
|
268
|
+
showDescription: true,
|
|
269
|
+
maxItems: 10,
|
|
270
|
+
title: 'Generated Files',
|
|
271
|
+
groupBy: 'type'
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Display single artifact
|
|
275
|
+
const singleDisplay = displaySingleArtifact(artifacts[0], 'Latest Artifact');
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Display Options
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
interface ArtifactDisplayOptions {
|
|
282
|
+
showSize?: boolean; // Show file sizes (default: true)
|
|
283
|
+
showTime?: boolean; // Show modification times (default: true)
|
|
284
|
+
showDescription?: boolean; // Show descriptions (default: false)
|
|
285
|
+
maxItems?: number; // Maximum items to show (default: 10)
|
|
286
|
+
title?: string; // Section title (default: 'Generated Artifacts')
|
|
287
|
+
groupBy?: 'none' | 'type' | 'time'; // Grouping strategy (default: 'none')
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Integration in CLI Commands
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
import { displayArtifactsCompact } from '@kb-labs/shared-cli-ui';
|
|
295
|
+
import { discoverArtifacts } from './my-artifact-discovery';
|
|
296
|
+
|
|
297
|
+
export const run: CommandModule['run'] = async (ctx, _argv, flags) => {
|
|
298
|
+
// ... your command logic ...
|
|
299
|
+
|
|
300
|
+
// Show artifacts after operation
|
|
301
|
+
const artifacts = await discoverArtifacts(process.cwd());
|
|
302
|
+
const artifactsInfo = displayArtifactsCompact(artifacts, { maxItems: 5 });
|
|
303
|
+
|
|
304
|
+
const output = box('My Command', [
|
|
305
|
+
...summary,
|
|
306
|
+
...artifactsInfo
|
|
307
|
+
]);
|
|
308
|
+
|
|
309
|
+
ctx.presenter.write(output);
|
|
310
|
+
};
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## 📦 API Reference
|
|
314
|
+
|
|
315
|
+
### Main Exports
|
|
316
|
+
|
|
317
|
+
#### Formatting Functions
|
|
318
|
+
|
|
319
|
+
- `box(title, content)`: Create boxed section
|
|
320
|
+
- `table(rows, headers?)`: Format table
|
|
321
|
+
- `keyValue(pairs, options?)`: Format key-value pairs
|
|
322
|
+
- `indent(lines, level?)`: Add indentation
|
|
323
|
+
- `section(header, content)`: Create section
|
|
324
|
+
|
|
325
|
+
#### Command Utilities
|
|
326
|
+
|
|
327
|
+
- `createCommandRegistry(commands)`: Create command registry
|
|
328
|
+
- `MultiCLISuggestions`: Multi-CLI manager class
|
|
329
|
+
- `displayArtifacts(artifacts, options?)`: Display artifacts
|
|
330
|
+
- `displayArtifactsCompact(artifacts, options?)`: Compact artifact display
|
|
331
|
+
|
|
332
|
+
### Types & Interfaces
|
|
333
|
+
|
|
334
|
+
See detailed API documentation in code comments.
|
|
335
|
+
|
|
336
|
+
## 🤝 Contributing
|
|
337
|
+
|
|
338
|
+
See [CONTRIBUTING.md](../../CONTRIBUTING.md) for development guidelines.
|
|
339
|
+
|
|
340
|
+
## 📄 License
|
|
341
|
+
|
|
342
|
+
MIT © KB Labs
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Package Architecture Description: @kb-labs/shared-cli-ui
|
|
2
|
+
|
|
3
|
+
**Version**: 0.1.0
|
|
4
|
+
**Last Updated**: 2025-11-16
|
|
5
|
+
|
|
6
|
+
## Executive Summary
|
|
7
|
+
|
|
8
|
+
**@kb-labs/shared-cli-ui** provides shared CLI UI utilities for KB Labs ecosystem. It includes command suggestions, validation, multi-CLI support, formatting utilities, colors, progress indicators, and consistent UX components for all CLI applications.
|
|
9
|
+
|
|
10
|
+
## 1. Package Overview
|
|
11
|
+
|
|
12
|
+
### 1.1 Purpose & Scope
|
|
13
|
+
|
|
14
|
+
**Primary Purpose**: Provide shared CLI UI utilities for consistent user experience.
|
|
15
|
+
|
|
16
|
+
**Scope Boundaries**:
|
|
17
|
+
- **In Scope**: Formatting, command discovery, suggestions, artifacts display
|
|
18
|
+
- **Out of Scope**: Command execution, file system operations
|
|
19
|
+
|
|
20
|
+
**Domain**: Shared Utilities / CLI UI
|
|
21
|
+
|
|
22
|
+
### 1.2 Key Responsibilities
|
|
23
|
+
|
|
24
|
+
1. **Formatting**: Format CLI output (tables, boxes, colors)
|
|
25
|
+
2. **Command Discovery**: Discover commands from manifests
|
|
26
|
+
3. **Command Suggestions**: Generate context-aware suggestions
|
|
27
|
+
4. **Artifacts Display**: Display generated artifacts
|
|
28
|
+
|
|
29
|
+
## 2. High-Level Architecture
|
|
30
|
+
|
|
31
|
+
### 2.1 Architecture Diagram
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
CLI UI Utilities
|
|
35
|
+
│
|
|
36
|
+
├──► Formatting (tables, boxes, colors)
|
|
37
|
+
├──► Command Discovery (manifest parsing)
|
|
38
|
+
├──► Command Suggestions (auto-suggestions)
|
|
39
|
+
├──► Multi-CLI Support (multi-package manager)
|
|
40
|
+
├──► Artifacts Display (artifact rendering)
|
|
41
|
+
└──► Debug Utilities (debug formatting)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2.2 Architectural Style
|
|
45
|
+
|
|
46
|
+
- **Style**: Utility Library with Manager Pattern
|
|
47
|
+
- **Rationale**: Pure utilities with stateful managers for multi-CLI
|
|
48
|
+
|
|
49
|
+
## 3. Component Architecture
|
|
50
|
+
|
|
51
|
+
### 3.1 Component: Formatting Utilities
|
|
52
|
+
|
|
53
|
+
- **Purpose**: Format CLI output
|
|
54
|
+
- **Responsibilities**: Tables, boxes, colors, indentation
|
|
55
|
+
- **Dependencies**: None (pure functions)
|
|
56
|
+
|
|
57
|
+
### 3.2 Component: Command Discovery
|
|
58
|
+
|
|
59
|
+
- **Purpose**: Discover commands from manifests
|
|
60
|
+
- **Responsibilities**: Parse manifests, extract commands
|
|
61
|
+
- **Dependencies**: None
|
|
62
|
+
|
|
63
|
+
### 3.3 Component: Multi-CLI Manager
|
|
64
|
+
|
|
65
|
+
- **Purpose**: Manage multiple CLI packages
|
|
66
|
+
- **Responsibilities**: Register packages, generate suggestions
|
|
67
|
+
- **Dependencies**: Command discovery
|
|
68
|
+
|
|
69
|
+
## 4. Data Flow
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
createCommandRegistry(commands)
|
|
73
|
+
│
|
|
74
|
+
├──► Build command registry
|
|
75
|
+
└──► return registry
|
|
76
|
+
|
|
77
|
+
generateSuggestions(context, registry)
|
|
78
|
+
│
|
|
79
|
+
├──► Analyze context
|
|
80
|
+
├──► Match commands
|
|
81
|
+
└──► return suggestions
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 5. Design Patterns
|
|
85
|
+
|
|
86
|
+
- **Utility Pattern**: Pure utility functions
|
|
87
|
+
- **Manager Pattern**: Multi-CLI manager
|
|
88
|
+
- **Factory Pattern**: Command runner creation
|
|
89
|
+
|
|
90
|
+
## 6. Performance Architecture
|
|
91
|
+
|
|
92
|
+
- **Time Complexity**: O(n) for most operations
|
|
93
|
+
- **Space Complexity**: O(n) for formatting
|
|
94
|
+
- **Bottlenecks**: Large table formatting
|
|
95
|
+
|
|
96
|
+
## 7. Security Architecture
|
|
97
|
+
|
|
98
|
+
- **Input Validation**: All inputs validated
|
|
99
|
+
- **No Side Effects**: Pure functions (mostly)
|
|
100
|
+
- **Path Validation**: Path operations validated
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
**Last Updated**: 2025-11-16
|
|
105
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard ESLint configuration template
|
|
3
|
+
*
|
|
4
|
+
* This is the canonical template for all @kb-labs packages.
|
|
5
|
+
* DO NOT modify this file locally - it is synced from @kb-labs/devkit
|
|
6
|
+
*
|
|
7
|
+
* Customization guidelines:
|
|
8
|
+
* - DevKit preset already includes all standard ignores
|
|
9
|
+
* - Only add project-specific ignores if absolutely necessary
|
|
10
|
+
* - Document why custom ignores are needed
|
|
11
|
+
*
|
|
12
|
+
* @see https://github.com/kb-labs/devkit#eslint-configuration
|
|
13
|
+
*/
|
|
14
|
+
import nodePreset from '@kb-labs/devkit/eslint/node.js';
|
|
15
|
+
|
|
16
|
+
export default [
|
|
17
|
+
...nodePreset,
|
|
18
|
+
|
|
19
|
+
// OPTIONAL: Add project-specific ignores only if needed
|
|
20
|
+
// DevKit preset already ignores: dist/, coverage/, node_modules/, *.d.ts, scripts/, etc.
|
|
21
|
+
// {
|
|
22
|
+
// ignores: [
|
|
23
|
+
// // Add ONLY project-specific patterns here
|
|
24
|
+
// // Example: '**/*.generated.ts',
|
|
25
|
+
// ]
|
|
26
|
+
// }
|
|
27
|
+
];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kb-labs/shared-cli-ui",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Shared CLI UI utilities for KB Labs projects - colors, formatting, progress indicators",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./debug": {
|
|
14
|
+
"import": "./dist/debug.js",
|
|
15
|
+
"types": "./dist/debug.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./table": {
|
|
18
|
+
"import": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"typesVersions": {
|
|
23
|
+
"*": {
|
|
24
|
+
"*": [
|
|
25
|
+
"src/*"
|
|
26
|
+
],
|
|
27
|
+
"debug": [
|
|
28
|
+
"src/debug"
|
|
29
|
+
],
|
|
30
|
+
"debug/*": [
|
|
31
|
+
"src/debug/*"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"scripts": {
|
|
42
|
+
"clean": "rimraf dist",
|
|
43
|
+
"build": "tsup --config tsup.config.ts",
|
|
44
|
+
"dev": "tsup --config tsup.config.ts --watch",
|
|
45
|
+
"lint": "eslint src --ext .ts,.tsx,.js,.jsx",
|
|
46
|
+
"lint:fix": "eslint . --fix",
|
|
47
|
+
"type-check": "tsc --noEmit",
|
|
48
|
+
"test": "vitest run --passWithNoTests",
|
|
49
|
+
"test:watch": "vitest"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"glob": "^11.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@kb-labs/devkit": "link:../../../../infra/kb-labs-devkit",
|
|
56
|
+
"eslint": "^9",
|
|
57
|
+
"rimraf": "^6.0.1",
|
|
58
|
+
"tsup": "^8.5.0",
|
|
59
|
+
"typescript": "^5.6.3",
|
|
60
|
+
"vitest": "^3.2.4",
|
|
61
|
+
"@types/node": "^24.3.3"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=20.0.0",
|
|
65
|
+
"pnpm": ">=9.0.0"
|
|
66
|
+
},
|
|
67
|
+
"packageManager": "pnpm@9.11.0",
|
|
68
|
+
"module": "./dist/index.js",
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const TEST_NOW = new Date('2025-01-01T00:06:00Z');
|
|
5
|
+
|
|
6
|
+
describe('artifacts display formatting', () => {
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
vi.resetModules();
|
|
9
|
+
vi.useFakeTimers();
|
|
10
|
+
vi.setSystemTime(TEST_NOW);
|
|
11
|
+
process.env.NO_COLOR = '1';
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
vi.useRealTimers();
|
|
16
|
+
delete process.env.NO_COLOR;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('renders detailed artifact list with metadata', async () => {
|
|
20
|
+
const { displayArtifacts } = await import('../artifacts-display.js');
|
|
21
|
+
const cwd = process.cwd();
|
|
22
|
+
|
|
23
|
+
const apiArtifact = {
|
|
24
|
+
name: 'API Index',
|
|
25
|
+
path: path.join(cwd, 'api-index.json'),
|
|
26
|
+
size: 512,
|
|
27
|
+
modified: new Date('2025-01-01T00:05:00Z'),
|
|
28
|
+
description: 'API index',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const indexArtifact = {
|
|
32
|
+
name: 'Index',
|
|
33
|
+
path: path.join(cwd, 'index.json'),
|
|
34
|
+
size: 1024,
|
|
35
|
+
modified: new Date('2025-01-01T00:04:00Z'),
|
|
36
|
+
description: 'Primary index',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const artifacts = [indexArtifact, apiArtifact];
|
|
40
|
+
const lines = displayArtifacts(artifacts, {
|
|
41
|
+
title: 'Artifacts',
|
|
42
|
+
showDescription: true,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const expected = [
|
|
46
|
+
'Artifacts',
|
|
47
|
+
`${apiArtifact.name}: ${path.relative(cwd, apiArtifact.path)}`,
|
|
48
|
+
' Size: 512 B',
|
|
49
|
+
' Updated: 1 minute ago',
|
|
50
|
+
` Note: ${apiArtifact.description}`,
|
|
51
|
+
'',
|
|
52
|
+
`${indexArtifact.name}: ${path.relative(cwd, indexArtifact.path)}`,
|
|
53
|
+
' Size: 1.0 KB',
|
|
54
|
+
' Updated: 2 minutes ago',
|
|
55
|
+
` Note: ${indexArtifact.description}`,
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
expect(lines).toEqual(expected);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('renders compact artifact summary', async () => {
|
|
62
|
+
const { displayArtifactsCompact } = await import('../artifacts-display.js');
|
|
63
|
+
const cwd = process.cwd();
|
|
64
|
+
|
|
65
|
+
const artifact = {
|
|
66
|
+
name: 'Index',
|
|
67
|
+
path: path.join(cwd, 'index.json'),
|
|
68
|
+
size: 1024,
|
|
69
|
+
modified: new Date('2025-01-01T00:05:00Z'),
|
|
70
|
+
description: '',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const lines = displayArtifactsCompact([artifact], {
|
|
74
|
+
title: 'Artifacts',
|
|
75
|
+
showTime: true,
|
|
76
|
+
showSize: true,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const expected = [
|
|
80
|
+
'Artifacts',
|
|
81
|
+
`${artifact.name}: ${path.relative(cwd, artifact.path)}`,
|
|
82
|
+
' Size: 1.0 KB',
|
|
83
|
+
' Updated: 1 minute ago',
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
expect(lines).toEqual(expected);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
+
import { formatTimestamp, formatRelativeTime } from '../format';
|
|
3
|
+
|
|
4
|
+
describe('format helpers', () => {
|
|
5
|
+
const baseDate = new Date('2025-01-01T00:05:30Z');
|
|
6
|
+
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
vi.useRealTimers();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('formats timestamp in ISO mode with offset', () => {
|
|
12
|
+
expect(formatTimestamp(baseDate, { mode: 'iso', timeZone: 'UTC' })).toBe('2025-01-01T00:05:30.000Z (+00:00)');
|
|
13
|
+
expect(formatTimestamp(baseDate, { mode: 'iso', timeZone: 'UTC', includeMilliseconds: false })).toBe(
|
|
14
|
+
'2025-01-01T00:05:30Z (+00:00)',
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('formats timestamp in local mode for a specific timezone', () => {
|
|
19
|
+
expect(
|
|
20
|
+
formatTimestamp(baseDate, {
|
|
21
|
+
mode: 'local',
|
|
22
|
+
timeZone: 'UTC',
|
|
23
|
+
includeSeconds: true,
|
|
24
|
+
}),
|
|
25
|
+
).toBe('2025-01-01 00:05:30 (+00:00)');
|
|
26
|
+
|
|
27
|
+
expect(
|
|
28
|
+
formatTimestamp(baseDate, {
|
|
29
|
+
mode: 'local',
|
|
30
|
+
timeZone: 'America/Los_Angeles',
|
|
31
|
+
includeSeconds: true,
|
|
32
|
+
}),
|
|
33
|
+
).toBe('2024-12-31 16:05:30 (-08:00)');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('returns human-friendly relative time', () => {
|
|
37
|
+
const now = new Date('2025-01-01T00:06:30Z');
|
|
38
|
+
vi.useFakeTimers();
|
|
39
|
+
vi.setSystemTime(now);
|
|
40
|
+
|
|
41
|
+
expect(formatRelativeTime(baseDate)).toBe('1 minute ago');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|