@haystackeditor/cli 0.24.0 → 0.25.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.
Files changed (49) hide show
  1. package/dist/assets/capture/capture.cb4204fcc997d8e8.js +2 -0
  2. package/dist/assets/capture/release.json +4 -0
  3. package/dist/assets/telemetry/runtime.cjs +829 -1254
  4. package/dist/capture/adapters/client-routes.js +383 -0
  5. package/dist/capture/adapters/django.js +127 -0
  6. package/dist/capture/adapters/files.js +77 -0
  7. package/dist/capture/adapters/index.js +64 -0
  8. package/dist/capture/adapters/jsx-edit.js +81 -0
  9. package/dist/capture/adapters/next.js +327 -0
  10. package/dist/capture/adapters/nuxt.js +192 -0
  11. package/dist/capture/adapters/rails.js +171 -0
  12. package/dist/capture/adapters/react-router.js +432 -0
  13. package/dist/capture/adapters/sveltekit.js +102 -0
  14. package/dist/capture/adapters/types.js +4 -0
  15. package/dist/capture/adapters/vite.js +121 -0
  16. package/dist/capture/app-config.js +106 -0
  17. package/dist/capture/consent.js +127 -0
  18. package/dist/capture/csp.js +331 -0
  19. package/dist/capture/html.js +74 -0
  20. package/dist/capture/js-ast.js +400 -0
  21. package/dist/capture/manifest.js +95 -0
  22. package/dist/capture/project.js +177 -0
  23. package/dist/capture/route-pattern.js +119 -0
  24. package/dist/capture/script-release.js +47 -0
  25. package/dist/capture/tag.js +74 -0
  26. package/dist/capture-step.js +53 -0
  27. package/dist/commands/capture-brief.js +92 -0
  28. package/dist/commands/capture-contract.js +46 -0
  29. package/dist/commands/capture-manifest.js +78 -0
  30. package/dist/commands/init-capture.js +409 -0
  31. package/dist/commands/init-telemetry.js +1011 -0
  32. package/dist/commands/init.js +75 -9
  33. package/dist/commands/server-telemetry-contract.d.ts +66 -0
  34. package/dist/commands/server-telemetry-contract.js +127 -0
  35. package/dist/commands/telemetry-token.js +238 -0
  36. package/dist/commands/telemetry.d.ts +161 -8
  37. package/dist/commands/telemetry.js +940 -158
  38. package/dist/commands/verify-onboarding.js +5 -1
  39. package/dist/commands/verify.js +54 -7
  40. package/dist/index.js +83 -6
  41. package/dist/schema.js +2 -2
  42. package/dist/telemetry/next-loader.cjs +66 -9
  43. package/dist/telemetry/next.d.ts +11 -3
  44. package/dist/telemetry/next.js +95 -15
  45. package/dist/telemetry/typed-source.d.ts +47 -0
  46. package/dist/telemetry/typed-source.js +379 -0
  47. package/package.json +4 -2
  48. package/schemas/init.v1.json +63 -4
  49. package/schemas/pre-verify.v1.json +60 -3
@@ -1,5 +1,7 @@
1
+ import { type SettingLiteral, type TelemetrySettingsEntryV1, type TelemetrySettingsProposal } from './server-telemetry-contract.js';
2
+ import { type TypeImportResolver } from '../telemetry/typed-source.js';
1
3
  export declare function preloadBabel(): Promise<void>;
2
- declare const MANIFEST_SCHEMA_VERSION = "haystack-node-telemetry-instrumentation-v3";
4
+ declare const MANIFEST_SCHEMA_VERSION = "haystack-node-telemetry-instrumentation-v4";
3
5
  export interface TelemetryInstrumentOptions {
4
6
  entry: string;
5
7
  sourceRoot?: string;
@@ -24,6 +26,31 @@ export interface InstrumentedFileSummary {
24
26
  returns: number;
25
27
  throws: number;
26
28
  };
29
+ /** Rule 9(b)/(c): the file's typed source was read (declared fields, literal domains); false: shape-only. */
30
+ typed: boolean;
31
+ }
32
+ /** Rule 9(c): what the build did with `.haystack/telemetry-settings.json`. */
33
+ export interface TelemetrySettingsReport {
34
+ /** The settings file read, repository-relative, or null when the repository has none. */
35
+ file: string | null;
36
+ /** Why the file (or an entry) was not used; the build still ships. */
37
+ problems: string[];
38
+ /** Sites that record literals: the approved literals their typed source still declares. */
39
+ applied: Array<{
40
+ source_path: string;
41
+ qualified_name: string;
42
+ label: string;
43
+ literals: SettingLiteral[];
44
+ }>;
45
+ /** Approved entries the instrumenter refused (identity- or secret-looking, or no longer a literal domain). */
46
+ refused: Array<{
47
+ source_path: string;
48
+ qualified_name: string;
49
+ label: string;
50
+ why: string;
51
+ }>;
52
+ /** Approved entries no instrumented site of this build matches. */
53
+ unmatched: TelemetrySettingsEntryV1[];
27
54
  }
28
55
  export interface TelemetryInstrumentationResult {
29
56
  schema_version: typeof MANIFEST_SCHEMA_VERSION;
@@ -34,6 +61,12 @@ export interface TelemetryInstrumentationResult {
34
61
  instrumented_files: InstrumentedFileSummary[];
35
62
  sites: InstrumentedSite[];
36
63
  skipped_unmapped_files: string[];
64
+ /** Rule 13(b): compiled files the instrumenter could not transform, shipped exactly as built. */
65
+ skipped_untransformed_files: Array<{
66
+ output_path: string;
67
+ reason: string;
68
+ }>;
69
+ settings: TelemetrySettingsReport;
37
70
  already_instrumented: boolean;
38
71
  }
39
72
  export interface InstrumentedSite {
@@ -45,7 +78,10 @@ export interface InstrumentedSite {
45
78
  owner_key: string;
46
79
  structural_key: string;
47
80
  label?: string;
81
+ /** Rule 9(b): source-declared field names (read on the value, or declared by its type), at most SERVER_FIELDS_PER_SITE. */
48
82
  allowed_fields: string[];
83
+ /** Rule 9(c): an approved settings site's literals (approved and still declared by the typed source). */
84
+ settings?: SettingLiteral[];
49
85
  /**
50
86
  * 1-based line and 0-based column of the probed node in `source_path`.
51
87
  * Present only when the instrumented text IS the source (the bundler
@@ -63,6 +99,22 @@ export interface FileProbeCounts {
63
99
  returns: number;
64
100
  throws: number;
65
101
  }
102
+ /** What the typed source declares at one site; `fields` in declaration order. */
103
+ interface SiteTypeFacts {
104
+ fields: string[];
105
+ domain: SettingLiteral[] | null;
106
+ typeNames: string[];
107
+ }
108
+ type TypedSiteFacts = Map<string, SiteTypeFacts | {
109
+ ambiguous: true;
110
+ }>;
111
+ /**
112
+ * Rule 9(b)/(c): per site of a TYPED source file (keyed by the site's function and label exactly as instrumentSource
113
+ * names them), the fields its type declares and its literal domain. Compiled output loses the types, so the compiled-
114
+ * output path reads the original TypeScript beside it and joins by this key; the bundler path reads the module it
115
+ * instruments. A key the file declares twice with different facts is ambiguous and keeps neither.
116
+ */
117
+ export declare function collectTypedSiteFacts(code: string, parserPlugins: string[], resolve: TypeImportResolver | null): TypedSiteFacts;
66
118
  /**
67
119
  * The runtime source bound to one control channel, plus the integrity token
68
120
  * generated probes present to it and the hash a bootstrap verifies before
@@ -75,19 +127,45 @@ export declare function authenticateTelemetryRuntime(controlChannel: string): {
75
127
  integrity: string;
76
128
  hash: string;
77
129
  };
130
+ /** The repository root settings and repository-relative paths are read against: git's top level, else `start`. */
131
+ export declare function repositoryRoot(start: string): string;
132
+ /** Rule 9(c): the repository's reviewed settings allowlist, the only file instrumentation treats as approval (a
133
+ * proposal never is). A missing file is no settings; an unreadable file or entry is a problem the build reports,
134
+ * never a reason to fail it. */
135
+ export declare function readTelemetrySettings(repoRoot: string): {
136
+ file: string | null;
137
+ entries: TelemetrySettingsEntryV1[];
138
+ problems: string[];
139
+ };
140
+ /** Relative imports one hop away, parsed once per build: `./types`, `./types.js` (NodeNext) and `./types/index`. */
141
+ export declare function typeImportResolver(repoRoot: string): (fromFile: string) => TypeImportResolver;
78
142
  export declare function instrumentNodeTelemetryBuild(distDirectory: string, options: TelemetryInstrumentOptions): TelemetryInstrumentationResult;
143
+ /** The build output could not be put back exactly as it was; the files named are left instrumented, without a
144
+ * manifest, so the runtime installs nothing and every probe passes values through. */
145
+ export declare class PartialRestoreError extends Error {
146
+ }
79
147
  export declare const BUNDLED_SOURCE_EXTENSIONS: string[];
148
+ /** What one bundled module did with the settings allowlist (merged by the post-compile step). */
149
+ export interface BundledSettingsRecord {
150
+ applied: TelemetrySettingsReport['applied'];
151
+ refused: TelemetrySettingsReport['refused'];
152
+ /** Approved entries this module's sites matched, as `sourcePath\0qualifiedName\0label`. */
153
+ matched: string[];
154
+ }
80
155
  export type BundledModuleResult = {
81
156
  kind: 'instrumented';
82
157
  code: string;
158
+ map: Record<string, unknown> | null;
83
159
  probes: FileProbeCounts;
84
160
  sites: InstrumentedSite[];
161
+ typed: boolean;
162
+ settings: BundledSettingsRecord;
85
163
  }
86
- /** Already instrumented, or a "use client" module (its server copy is only the SSR render of browser code). */
164
+ /** Already instrumented, a "use client" module, or an edge-runtime module. */
87
165
  | {
88
166
  kind: 'unchanged';
89
167
  }
90
- /** Babel cannot parse it (syntax the bundler's own compiler accepts but Babel does not). */
168
+ /** Babel cannot parse it (syntax the bundler's own compiler accepts but Babel does not), or the transform failed. */
91
169
  | {
92
170
  kind: 'unparsed';
93
171
  reason: string;
@@ -95,15 +173,19 @@ export type BundledModuleResult = {
95
173
  /**
96
174
  * Instrument one source module inside a bundler. `sourcePath` is the
97
175
  * repository-relative path every site records, so production counts join the
98
- * change's files and line ranges exactly. A module Babel cannot parse is
99
- * reported, not thrown: the bundler's compiler may accept syntax Babel does
100
- * not, and telemetry must never be the reason a build fails. Any other error
101
- * is ours and stays loud.
176
+ * change's files and line ranges exactly. Rule 13(b): nothing here fails a
177
+ * build: a module Babel cannot parse or this pass cannot transform is reported
178
+ * and ships as written, with its input map.
102
179
  */
103
180
  export declare function instrumentBundledModule(code: string, options: {
104
181
  sourcePath: string;
182
+ /** The module's absolute path (its source map's file, and where relative type imports resolve from). */
183
+ absolutePath: string;
184
+ /** The repository root: where `.haystack/telemetry-settings.json` is read. */
185
+ sourceRoot: string;
105
186
  controlChannel: string;
106
187
  runtimeIntegrity: string;
188
+ inputSourceMap: object | null;
107
189
  }): BundledModuleResult;
108
190
  export interface BundledTelemetryManifest {
109
191
  schema_version: typeof MANIFEST_SCHEMA_VERSION;
@@ -116,14 +198,48 @@ export interface BundledTelemetryManifest {
116
198
  instrumented_files: Array<{
117
199
  source_path: string;
118
200
  probes: FileProbeCounts;
201
+ typed: boolean;
119
202
  }>;
120
- /** Server modules shipped uninstrumented because Babel could not parse them, with the parser's reason. */
203
+ /** Server modules shipped uninstrumented because Babel could not parse or this pass could not transform them. */
121
204
  skipped_unparsed_files: Array<{
122
205
  source_path: string;
123
206
  reason: string;
124
207
  }>;
208
+ /** How site paths were named: from the git checkout (repository-relative, tracked files only), or, in a build without
209
+ * git, relative to the project with what that loses said. */
210
+ source_identity: BundledSourceIdentity;
211
+ settings: TelemetrySettingsReport;
125
212
  sites: InstrumentedSite[];
126
213
  }
214
+ export interface BundledSourceIdentity {
215
+ git: boolean;
216
+ lost: string | null;
217
+ }
218
+ /** Rule 13(b): what a build that could not be instrumented leaves behind: the reason, and a preload that does nothing,
219
+ * so a server started with NODE_OPTIONS=--require=<it> starts exactly as it would without telemetry. */
220
+ export interface BundledTelemetryNotInstalled {
221
+ schema_version: typeof MANIFEST_SCHEMA_VERSION;
222
+ bundler: string;
223
+ installed: false;
224
+ reason: string;
225
+ skipped_unparsed_files: Array<{
226
+ source_path: string;
227
+ reason: string;
228
+ }>;
229
+ sites: [];
230
+ }
231
+ export declare function writeInertTelemetryRuntime(options: {
232
+ outputDirectory: string;
233
+ bundler: string;
234
+ reason: string;
235
+ unparsed?: Array<{
236
+ sourcePath: string;
237
+ reason: string;
238
+ }>;
239
+ }): {
240
+ registerPath: string;
241
+ report: BundledTelemetryNotInstalled;
242
+ };
127
243
  /**
128
244
  * Write the runtime, its manifest and the preload that installs it into
129
245
  * `<outputDirectory>/.haystack-telemetry/`. The runtime reads the manifest
@@ -135,10 +251,13 @@ export declare function writeBundledTelemetryRuntime(options: {
135
251
  controlChannel: string;
136
252
  bundler: string;
137
253
  sourceRoot: string;
254
+ sourceIdentity: BundledSourceIdentity;
138
255
  modules: Array<{
139
256
  sourcePath: string;
140
257
  probes: FileProbeCounts;
141
258
  sites: InstrumentedSite[];
259
+ typed: boolean;
260
+ settings: BundledSettingsRecord;
142
261
  }>;
143
262
  unparsed: Array<{
144
263
  sourcePath: string;
@@ -148,7 +267,41 @@ export declare function writeBundledTelemetryRuntime(options: {
148
267
  registerPath: string;
149
268
  manifest: BundledTelemetryManifest;
150
269
  };
270
+ /** The settings and typed-source lines a build prints (rule 8e: init's status repeats them). */
271
+ export declare function settingsSummary(report: TelemetrySettingsReport, typedFiles: number, totalFiles: number): string[];
151
272
  export declare function telemetryInstrumentCommand(distDirectory: string, options: TelemetryInstrumentOptions & {
152
273
  includeSymbolsFile?: string;
153
274
  }): Promise<void>;
275
+ /**
276
+ * Rule 9(c): propose settings. Every parameter and binding of the repository's typed source whose type is a closed set
277
+ * of literals (a union, a boolean, an enum, an `as const` array or object) is a candidate, refused when its name or a
278
+ * literal looks like identity or a secret. The proposal (SETTINGS_PROPOSAL_PATH) is the approved entries, unchanged,
279
+ * plus the new candidates; it approves nothing: only `haystack telemetry settings --approve`, run by a person, makes it
280
+ * the allowlist instrumentation reads.
281
+ */
282
+ export declare function proposeTelemetrySettings(repoRoot: string): TelemetrySettingsProposal;
283
+ /** What promoting the proposal would change in the approved allowlist, entry by entry. */
284
+ export declare function settingsApprovalDiff(repoRoot: string): {
285
+ proposal: {
286
+ file: string | null;
287
+ entries: TelemetrySettingsEntryV1[];
288
+ problems: string[];
289
+ };
290
+ added: TelemetrySettingsEntryV1[];
291
+ removed: TelemetrySettingsEntryV1[];
292
+ changed: Array<{
293
+ from: TelemetrySettingsEntryV1;
294
+ to: TelemetrySettingsEntryV1;
295
+ }>;
296
+ refused: Array<{
297
+ entry: TelemetrySettingsEntryV1;
298
+ why: string;
299
+ }>;
300
+ };
301
+ export declare function telemetrySettingsCommand(options: {
302
+ propose?: boolean;
303
+ approve?: boolean;
304
+ json?: boolean;
305
+ dryRun?: boolean;
306
+ }): Promise<void>;
154
307
  export {};