Setting the file. One moment.
Rp Telemetry · Rp Telemetry · wix/skills · Skills Docs
ContentsBack to the top of the page scripts/rp-telemetry.js
scripts/ rp-telemetry.js
JavaScript · 141 lines · 5 KB
15 // node scripts/rp-telemetry.js wait start [--halt <subtype> --skill <s> [--what '<text>']]
16 // node scripts/rp-telemetry.js wait end
17 // node scripts/rp-telemetry.js finalize '<rollup-json>'
18 // node scripts/rp-telemetry.js rebuild [--attempt <n>] [--push]
19 // node scripts/rp-telemetry.js status
20 //
21 // Output: one JSON object on stdout. {"ok":true,...} on success; on rejection
22 // {"ok":false,"errors":[...],"hint":...} with exit code 1 — fix and retry.
23
24 const fs = require ( 'node:fs' );
25 const recorder = require ( '../lib/telemetry-recorder.js' );
26
27 const VALUE_FLAGS = new Set ([ '--project' , '--outcome' , '--halt' , '--skill' , '--what' , '--attempt' , '--stage' ]);
28 // Meter measurements are accepted as kebab-case flags so a shell script can report its own timing
29 // without composing JSON: --api-ms 1234 --api-calls 73.
30 const METER_FLAGS = new Map (
31 [ 'model_ms' , 'api_ms' , 'script_ms' , 'input_tokens' , 'output_tokens' , 'cache_read_tokens' , 'cache_write_tokens' , 'api_calls' , 'api_retries' ]
32 . map (( key ) => [ `--${ key . replace ( /_/ g , '-' ) }` , key]),
33 );
34
35 function parseArgs ( argv ) {
36 const positional = [];
37 const flags = {};
38 const meter = {};
39 for ( let i = 0 ; i < argv. length ; i += 1 ) {
40 const arg = argv[i];
41 if ( VALUE_FLAGS . has (arg)) {
42 flags[arg. slice ( 2 )] = argv[i + 1 ];
43 i += 1 ;
44 } else if ( METER_FLAGS . has (arg)) {
45 const raw = argv[i + 1 ];
46 const value = Number (raw);
47 if ( ! Number. isFinite (value)) fail ([ `${ arg } expects a number (got: ${ raw === undefined ? '(none)' : raw })` ]);
48 meter[ METER_FLAGS . get (arg)] = value;
49 i += 1 ;
50 } else if (arg === '--push' ) {
51 flags.push = true ;
52 } else if (arg. startsWith ( '--' )) {
53 fail ([ `unknown flag: ${ arg }` ]);
54 } else {
55 positional. push (arg);
56 }
57 }
58 return { positional, flags, meter };
59 }
60
61 function fail ( errors , hint ) {
62 process.stdout. write ( `${ JSON . stringify ({ ok: false , errors , ... (hint ? { hint } : {}) }) } \n ` );
63 process. exit ( 1 );
64 }
65
66 function parseJsonArg ( raw , label ) {
67 if (raw === undefined ) fail ([ `missing ${ label } JSON argument` ]);
68 try {
69 return JSON . parse (raw);
70 } catch (error) {
71 fail ([ `${ label } is not valid JSON: ${ error . message }` ]);
72 }
73 return undefined ;
74 }
75
76 async function main () {
77 const { positional , flags , meter } = parseArgs (process.argv. slice ( 2 ));
78 const [ command , ... rest ] = positional;
79 const projectDir = flags.project || process. cwd ();
80 if ( ! fs. existsSync (projectDir) || ! fs. statSync (projectDir). isDirectory ()) {
81 fail ([ `project directory not found: ${ projectDir }` ], 'pass --project <migration project dir>' );
82 }
83
84 let result;
85 switch (command) {
86 case 'start' :
87 result = await recorder. start (projectDir, rest[ 0 ] === undefined ? {} : parseJsonArg (rest[ 0 ], 'dims' ));
88 break ;
89 case 'dims' :
90 result = await recorder. dims (projectDir, parseJsonArg (rest[ 0 ], 'dims' ));
91 break ;
92 case 'record' :
93 result = await recorder. record (projectDir, parseJsonArg (rest[ 0 ], 'event' ));
94 break ;
95 case 'stage' :
96 result = recorder. stage (projectDir, rest[ 0 ], rest[ 1 ], { outcome: flags.outcome });
97 break ;
98 case 'meter' : {
99 // Flags and a JSON payload both work; flags win on conflict so a wrapper script can override
100 // a template payload without rebuilding the JSON.
101 const fromJson = rest[ 0 ] === undefined ? {} : parseJsonArg (rest[ 0 ], 'meter' );
102 const payload = { ... fromJson, ... meter };
103 if (flags.stage) payload.stage = flags.stage;
104 result = recorder. meter (projectDir, payload);
105 break ;
106 }
107 case 'wait' :
108 result = await recorder. wait (projectDir, rest[ 0 ], {
109 haltSubtype: flags.halt,
110 skill: flags.skill,
111 what: flags.what,
112 });
113 break ;
114 case 'finalize' :
115 result = await recorder. finalize (projectDir, parseJsonArg (rest[ 0 ], 'rollup' ));
116 break ;
117 case 'rebuild' :
118 result = await recorder. rebuild (projectDir, {
119 attempt: flags.attempt === undefined ? undefined : Number (flags.attempt),
120 push: flags.push === true ,
121 });
122 break ;
123 case 'status' :
124 result = recorder. status (projectDir);
125 break ;
126 default :
127 fail (
128 [ `unknown command: ${ command || '(none)'}` ],
129 'commands: start, dims, record, stage start|end, meter, wait start|end, finalize, rebuild, status' ,
130 );
131 return ;
132 }
133 process.stdout. write ( `${ JSON . stringify ({ ok: true , ... result }) } \n ` );
134 }
135
136 main (). catch (( error ) => {
137 if (error instanceof recorder . ValidationError ) {
138 fail (error.errors, error.hint || undefined );
139 }
140 fail ([error && error.message ? error.message : String (error)]);
141 });