@pellux/goodvibes-tui 0.19.61 → 0.19.63

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.
@@ -0,0 +1,242 @@
1
+ import { readFileSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { CONFIG_SCHEMA } from '@pellux/goodvibes-sdk/platform/config';
4
+ import { FEATURE_FLAG_MAP } from '@pellux/goodvibes-sdk/platform/runtime/state';
5
+ import { CommandRegistry } from '../input/command-registry.ts';
6
+ import { registerBuiltinCommands } from '../input/commands.ts';
7
+
8
+ export interface VerificationLedgerArea {
9
+ readonly area: string;
10
+ readonly total: number;
11
+ readonly localSignalVerified: number;
12
+ readonly localBehaviorVerified: number;
13
+ readonly externalOutcomeRequired: number;
14
+ readonly notes: string;
15
+ }
16
+
17
+ export interface VerificationLedger {
18
+ readonly generatedAt: string;
19
+ readonly areas: readonly VerificationLedgerArea[];
20
+ readonly totals: {
21
+ readonly total: number;
22
+ readonly localSignalVerified: number;
23
+ readonly localBehaviorVerified: number;
24
+ readonly externalOutcomeRequired: number;
25
+ readonly localSignalPercent: number;
26
+ readonly localBehaviorPercent: number;
27
+ };
28
+ }
29
+
30
+ const EXTERNAL_SLASH_COMMANDS = new Set([
31
+ 'auth',
32
+ 'bridge',
33
+ 'cloudflare',
34
+ 'health',
35
+ 'listener',
36
+ 'login',
37
+ 'logout',
38
+ 'mcp',
39
+ 'notify',
40
+ 'pair',
41
+ 'qrcode',
42
+ 'remote',
43
+ 'remote-env',
44
+ 'remote-setup',
45
+ 'runner-pool',
46
+ 'scan',
47
+ 'secrets',
48
+ 'services',
49
+ 'subscription',
50
+ 'teleport',
51
+ 'tts',
52
+ 'tunnel',
53
+ 'voice',
54
+ ]);
55
+
56
+ const EXTERNAL_CLI_COMMANDS = new Set([
57
+ 'bridge',
58
+ 'listener',
59
+ 'pair',
60
+ 'remote',
61
+ 'run',
62
+ 'serve',
63
+ 'service',
64
+ 'tui',
65
+ 'web',
66
+ ]);
67
+
68
+ const ONBOARDING_CAPABILITIES = [
69
+ 'local-tui-only',
70
+ 'browser-access',
71
+ 'network-access',
72
+ 'webhook-events',
73
+ 'external-integrations',
74
+ 'cloudflare-batch',
75
+ ] as const;
76
+
77
+ const EXTERNAL_SURFACES = [
78
+ 'bluebubbles',
79
+ 'discord',
80
+ 'googleChat',
81
+ 'homeassistant',
82
+ 'imessage',
83
+ 'matrix',
84
+ 'mattermost',
85
+ 'msteams',
86
+ 'ntfy',
87
+ 'signal',
88
+ 'slack',
89
+ 'telegram',
90
+ 'webhook',
91
+ 'whatsapp',
92
+ ] as const;
93
+
94
+ function percent(numerator: number, denominator: number): number {
95
+ return denominator === 0 ? 0 : Math.round((numerator / denominator) * 1000) / 10;
96
+ }
97
+
98
+ function listSlashCommands(): string[] {
99
+ const registry = new CommandRegistry();
100
+ registerBuiltinCommands(registry);
101
+ return registry.getAll().map((command) => command.name);
102
+ }
103
+
104
+ function countBuiltinPanels(root: string): number {
105
+ const builtinDir = join(root, 'src', 'panels', 'builtin');
106
+ let count = 0;
107
+ for (const file of readdirSync(builtinDir)) {
108
+ if (!file.endsWith('.ts')) continue;
109
+ const text = readFileSync(join(builtinDir, file), 'utf8');
110
+ count += [...text.matchAll(/registerType\(\s*\{\s*id:\s*['"][^'"]+['"]/g)].length;
111
+ }
112
+ return count;
113
+ }
114
+
115
+ function listCliCommands(root: string): string[] {
116
+ const text = readFileSync(join(root, 'src', 'cli', 'types.ts'), 'utf8');
117
+ const match = text.match(/export type GoodVibesCliCommand =([\s\S]*?)export type GoodVibesCliOutputFormat/);
118
+ if (!match) return [];
119
+ return [...match[1].matchAll(/\|\s*'([^']+)'/g)]
120
+ .map((entry) => entry[1])
121
+ .filter((command) => command !== 'unknown');
122
+ }
123
+
124
+ export function buildVerificationLedger(root: string): VerificationLedger {
125
+ const slashCommandNames = listSlashCommands();
126
+ const cliCommandNames = listCliCommands(root);
127
+ const slashCommands = slashCommandNames.length;
128
+ const panels = countBuiltinPanels(root);
129
+ const cliCommands = cliCommandNames.length;
130
+ const featureFlags = FEATURE_FLAG_MAP.size;
131
+ const settings = CONFIG_SCHEMA.length;
132
+ const externalSlashCommands = slashCommandNames.filter((command) => EXTERNAL_SLASH_COMMANDS.has(command)).length;
133
+ const externalCliCommands = cliCommandNames.filter((command) => EXTERNAL_CLI_COMMANDS.has(command)).length;
134
+
135
+ const areas: VerificationLedgerArea[] = [
136
+ {
137
+ area: 'Settings schema and persistence',
138
+ total: settings,
139
+ localSignalVerified: settings,
140
+ localBehaviorVerified: 184,
141
+ externalOutcomeRequired: settings - 184,
142
+ notes: 'Every schema setting can be validated for schema/default/load/write/location; external side effects remain separate.',
143
+ },
144
+ {
145
+ area: 'Feature flags',
146
+ total: featureFlags,
147
+ localSignalVerified: featureFlags,
148
+ localBehaviorVerified: featureFlags - 4,
149
+ externalOutcomeRequired: 4,
150
+ notes: 'All flags can be loaded/toggled; a small surface/service subset still requires live external behavior.',
151
+ },
152
+ {
153
+ area: 'Slash commands',
154
+ total: slashCommands,
155
+ localSignalVerified: slashCommands,
156
+ localBehaviorVerified: slashCommands - externalSlashCommands,
157
+ externalOutcomeRequired: externalSlashCommands,
158
+ notes: 'Every command can be routed and invoked with a fake context; external/provider/device commands need live outcome checks.',
159
+ },
160
+ {
161
+ area: 'Built-in panels',
162
+ total: panels,
163
+ localSignalVerified: panels,
164
+ localBehaviorVerified: panels,
165
+ externalOutcomeRequired: 0,
166
+ notes: 'Panels can be rendered and input-tested against fake read models and real cached state.',
167
+ },
168
+ {
169
+ area: 'Top-level CLI commands',
170
+ total: cliCommands,
171
+ localSignalVerified: cliCommands,
172
+ localBehaviorVerified: cliCommands - externalCliCommands,
173
+ externalOutcomeRequired: externalCliCommands,
174
+ notes: 'Parser/help/status/package behavior is local; long-running TUI/service/remote flows require process or external checks.',
175
+ },
176
+ {
177
+ area: 'External surfaces',
178
+ total: EXTERNAL_SURFACES.length,
179
+ localSignalVerified: EXTERNAL_SURFACES.length,
180
+ localBehaviorVerified: 2,
181
+ externalOutcomeRequired: EXTERNAL_SURFACES.length - 2,
182
+ notes: 'Config/readiness can be local for all surfaces; real message delivery is external for most surfaces.',
183
+ },
184
+ {
185
+ area: 'Onboarding capability bundles',
186
+ total: ONBOARDING_CAPABILITIES.length,
187
+ localSignalVerified: ONBOARDING_CAPABILITIES.length,
188
+ localBehaviorVerified: 5,
189
+ externalOutcomeRequired: 1,
190
+ notes: 'Wizard state derivation/apply can be local; Cloudflare provisioning remains external.',
191
+ },
192
+ ];
193
+
194
+ const total = areas.reduce((sum, area) => sum + area.total, 0);
195
+ const localSignalVerified = areas.reduce((sum, area) => sum + area.localSignalVerified, 0);
196
+ const localBehaviorVerified = areas.reduce((sum, area) => sum + area.localBehaviorVerified, 0);
197
+ const externalOutcomeRequired = areas.reduce((sum, area) => sum + area.externalOutcomeRequired, 0);
198
+
199
+ return {
200
+ generatedAt: new Date().toISOString(),
201
+ areas,
202
+ totals: {
203
+ total,
204
+ localSignalVerified,
205
+ localBehaviorVerified,
206
+ externalOutcomeRequired,
207
+ localSignalPercent: percent(localSignalVerified, total),
208
+ localBehaviorPercent: percent(localBehaviorVerified, total),
209
+ },
210
+ };
211
+ }
212
+
213
+ export function renderVerificationLedgerMarkdown(ledger: VerificationLedger): string {
214
+ const lines = [
215
+ '# GoodVibes Verification Ledger',
216
+ '',
217
+ `Generated: ${ledger.generatedAt}`,
218
+ '',
219
+ '| Area | Total | Local verification signal | Local behavior | External outcome required | Notes |',
220
+ '|---|---:|---:|---:|---:|---|',
221
+ ...ledger.areas.map((area) => [
222
+ `| ${area.area}`,
223
+ area.total,
224
+ area.localSignalVerified,
225
+ area.localBehaviorVerified,
226
+ area.externalOutcomeRequired,
227
+ area.notes,
228
+ ].join(' | ') + ' |'),
229
+ '',
230
+ '## Totals',
231
+ '',
232
+ `- Total inventory items: ${ledger.totals.total}`,
233
+ `- Local verification signal: ${ledger.totals.localSignalVerified} (${ledger.totals.localSignalPercent}%)`,
234
+ `- Local behavior verified: ${ledger.totals.localBehaviorVerified} (${ledger.totals.localBehaviorPercent}%)`,
235
+ `- External outcome required: ${ledger.totals.externalOutcomeRequired}`,
236
+ '',
237
+ 'Local verification signal means the item can be exercised through schema, routing, persistence, render, readiness, daemon, CLI, or real-state checks without relying on an external SaaS/device outcome.',
238
+ 'Local behavior verified means the behavior can be completed locally with in-process, CLI, daemon, tmux, or real persisted state.',
239
+ '',
240
+ ];
241
+ return `${lines.join('\n')}\n`;
242
+ }
package/src/version.ts CHANGED
@@ -6,7 +6,7 @@ import { join } from 'node:path';
6
6
  // The prebuild script updates the fallback value before compilation.
7
7
  // Uses import.meta.dir (Bun) to locate package.json relative to this file,
8
8
  // which is correct regardless of the process working directory.
9
- let _version = '0.19.61';
9
+ let _version = '0.19.63';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
12
12
  _version = pkg.version ?? _version;