@haystackeditor/cli 0.15.29 → 0.15.31

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 (32) hide show
  1. package/dist/assets/telemetry/browser-runtime.js +148 -2
  2. package/dist/commands/design-verify.d.ts +2 -0
  3. package/dist/commands/design-verify.js +27 -1
  4. package/dist/commands/precompute-delivery-contract.d.ts +68 -0
  5. package/dist/commands/precompute-delivery-contract.js +1 -0
  6. package/dist/commands/precompute-delivery-worker.d.ts +1 -0
  7. package/dist/commands/precompute-delivery-worker.js +68 -0
  8. package/dist/commands/precompute-delivery.d.ts +20 -0
  9. package/dist/commands/precompute-delivery.js +319 -0
  10. package/dist/commands/verify-explore.d.ts +14 -0
  11. package/dist/commands/verify-explore.js +180 -0
  12. package/dist/commands/verify-history.d.ts +14 -0
  13. package/dist/commands/verify-history.js +152 -0
  14. package/dist/commands/verify-hosted.d.ts +12 -2
  15. package/dist/commands/verify-hosted.js +305 -50
  16. package/dist/commands/verify-precompute.d.ts +12 -1
  17. package/dist/commands/verify-precompute.js +135 -27
  18. package/dist/commands/verify.d.ts +6 -0
  19. package/dist/commands/verify.js +22 -0
  20. package/dist/index.js +71 -5
  21. package/dist/types/verify-history.d.ts +38 -0
  22. package/dist/types/verify-history.js +1 -0
  23. package/dist/utils/design-verifier-api.d.ts +8 -0
  24. package/dist/utils/design-verifier-api.js +23 -0
  25. package/dist/utils/design-verifier-history.d.ts +46 -0
  26. package/dist/utils/design-verifier-history.js +79 -0
  27. package/dist/utils/design-verifier-result.d.ts +17 -0
  28. package/dist/utils/design-verifier-result.js +80 -1
  29. package/dist/utils/git.js +5 -1
  30. package/dist/utils/telemetry.js +8 -2
  31. package/package.json +1 -1
  32. package/schemas/cloud-verifier.v1.json +108 -45
@@ -0,0 +1,152 @@
1
+ import { resolveAuthContext } from '../utils/auth.js';
2
+ import { haystackJson, HaystackApiError } from '../utils/haystack-api.js';
3
+ const HEALTH = ['healthy', 'degraded', 'infrastructure-error', 'not-executed', 'unknown'];
4
+ const LIFECYCLES = ['complete', 'failed', 'cancelled', 'budget-stopped', 'account-action'];
5
+ const RUN_ID = /^cv_[0-9a-f]{48}$/;
6
+ const COMMIT = /^[0-9a-f]{40}$/;
7
+ const REPO_COMPONENT = /^(?!\.{1,2}$)[A-Za-z0-9_.-]{1,100}$/;
8
+ function record(value) {
9
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
10
+ }
11
+ function count(value) {
12
+ return Number.isSafeInteger(value) && value >= 0;
13
+ }
14
+ function timestamp(value) {
15
+ return typeof value === 'string' && Number.isFinite(Date.parse(value));
16
+ }
17
+ /** Reject contradictory or mismatched data before printing health or findings. */
18
+ export function parseVerifyHistoryReport(value, expected) {
19
+ const invalid = () => {
20
+ throw new Error('The hosted verifier returned invalid or mismatched history. No reliability summary was accepted.');
21
+ };
22
+ if (!record(value) || value.version !== 'dv-verify-history-v1'
23
+ || value.provider !== 'haystack' || value.scope !== 'user'
24
+ || !record(value.repository)
25
+ || typeof value.repository.owner !== 'string' || typeof value.repository.name !== 'string'
26
+ || value.repository.owner !== expected.owner
27
+ || value.repository.name !== expected.name
28
+ || typeof value.repository.repositoryId !== 'string'
29
+ || !/^github\.com:[1-9]\d*$/.test(value.repository.repositoryId)
30
+ || value.limit !== expected.limit || typeof value.hasMore !== 'boolean'
31
+ || !Array.isArray(value.runs) || value.runs.length > expected.limit
32
+ || (value.hasMore && value.runs.length !== expected.limit)
33
+ || !record(value.summary) || !record(value.summary.counts))
34
+ return invalid();
35
+ const counts = {
36
+ healthy: 0, degraded: 0, 'infrastructure-error': 0, 'not-executed': 0, unknown: 0,
37
+ };
38
+ const seen = new Set();
39
+ let usable = 0;
40
+ let previousCompletedAt = Infinity;
41
+ for (const run of value.runs) {
42
+ if (!record(run) || typeof run.runId !== 'string' || !RUN_ID.test(run.runId)
43
+ || seen.has(run.runId)
44
+ || typeof run.baseCommit !== 'string' || !COMMIT.test(run.baseCommit)
45
+ || typeof run.headCommit !== 'string' || !COMMIT.test(run.headCommit)
46
+ || !timestamp(run.createdAt) || !timestamp(run.completedAt)
47
+ || Date.parse(run.completedAt) < Date.parse(run.createdAt)
48
+ || Date.parse(run.completedAt) > previousCompletedAt
49
+ || (run.status !== 'complete' && run.status !== 'errored')
50
+ || (run.lifecycle !== null && !LIFECYCLES.includes(run.lifecycle))
51
+ || !HEALTH.includes(run.health)
52
+ || (run.regressionCount !== null && !count(run.regressionCount))
53
+ || (run.executedCaseCount !== null && !count(run.executedCaseCount))
54
+ || !Array.isArray(run.degradationCodes)
55
+ || run.degradationCodes.some(code => typeof code !== 'string' || code.length === 0)
56
+ || new Set(run.degradationCodes).size !== run.degradationCodes.length
57
+ || (run.supersededBy !== null && (typeof run.supersededBy !== 'string'
58
+ || !RUN_ID.test(run.supersededBy) || run.supersededBy === run.runId)))
59
+ return invalid();
60
+ if (run.health === 'unknown') {
61
+ if (run.status !== 'errored' || run.lifecycle !== null || run.regressionCount !== null
62
+ || run.executedCaseCount !== null || run.degradationCodes.length !== 0)
63
+ return invalid();
64
+ }
65
+ else if (run.lifecycle === null || run.regressionCount === null || run.executedCaseCount === null) {
66
+ return invalid();
67
+ }
68
+ else if ((run.lifecycle === 'complete') !== (run.status === 'complete')) {
69
+ return invalid();
70
+ }
71
+ if (run.health === 'healthy' && (run.lifecycle !== 'complete'
72
+ || run.executedCaseCount === 0 || run.degradationCodes.length !== 0))
73
+ return invalid();
74
+ if (run.health === 'not-executed' && (run.executedCaseCount !== 0 || run.regressionCount !== 0))
75
+ return invalid();
76
+ if (run.executedCaseCount === 0 && run.regressionCount !== null && run.regressionCount !== 0)
77
+ return invalid();
78
+ seen.add(run.runId);
79
+ previousCompletedAt = Date.parse(run.completedAt);
80
+ counts[run.health]++;
81
+ if ((run.health === 'healthy' || run.health === 'degraded')
82
+ && typeof run.executedCaseCount === 'number' && run.executedCaseCount > 0)
83
+ usable++;
84
+ }
85
+ const usableRate = value.runs.length === 0 ? null : usable / value.runs.length;
86
+ const summaryCounts = value.summary.counts;
87
+ if (value.summary.total !== value.runs.length || value.summary.usableRate !== usableRate
88
+ || HEALTH.some(health => summaryCounts[health] !== counts[health]))
89
+ return invalid();
90
+ return value;
91
+ }
92
+ function terminalSafe(value) {
93
+ return Array.from(value).filter(character => {
94
+ const point = character.codePointAt(0);
95
+ return point >= 32 && !(point >= 127 && point <= 159);
96
+ }).join('');
97
+ }
98
+ export function formatVerifyHistory(report) {
99
+ const { summary } = report;
100
+ const lines = [
101
+ `Your verification history for ${report.repository.owner}/${report.repository.name}`,
102
+ `Latest ${summary.total} finished runs for the selected account (limit ${report.limit}).`,
103
+ ];
104
+ if (summary.total === 0) {
105
+ lines.push('No finished hosted fleet runs found for this account and repository.');
106
+ return lines.join('\n');
107
+ }
108
+ const usable = report.runs.filter(run => (run.health === 'healthy' || run.health === 'degraded')
109
+ && run.executedCaseCount !== null && run.executedCaseCount > 0).length;
110
+ lines.push(`Usable evidence: ${Math.round(summary.usableRate * 100)}% of these runs (${usable}/${summary.total}).`, `Healthy: ${summary.counts.healthy}; partially degraded: ${summary.counts.degraded}; infrastructure error: ${summary.counts['infrastructure-error']}; not executed: ${summary.counts['not-executed']}; unknown: ${summary.counts.unknown}.`, 'Usable means healthy or partially degraded with at least one executed check.', 'This measures execution reliability. Bugs found are listed separately; they do not lower this rate.', '');
111
+ for (const run of report.runs) {
112
+ const health = run.health === 'degraded' ? 'partially degraded' : run.health;
113
+ const checks = run.executedCaseCount === null ? 'unknown checks executed' : `${run.executedCaseCount} checks executed`;
114
+ const regressions = run.regressionCount === null ? 'bugs found unknown'
115
+ : `${run.regressionCount} ${run.regressionCount === 1 ? 'bug' : 'bugs'} found`;
116
+ lines.push(`${terminalSafe(run.completedAt)} ${health} ${checks} ${regressions}`, ` ${run.runId} ${run.baseCommit.slice(0, 12)} -> ${run.headCommit.slice(0, 12)}`);
117
+ if (run.lifecycle && run.lifecycle !== 'complete')
118
+ lines.push(` Run outcome: ${run.lifecycle}`);
119
+ if (run.degradationCodes.length)
120
+ lines.push(` Limitations: ${run.degradationCodes.map(terminalSafe).join(', ')}`);
121
+ if (run.supersededBy)
122
+ lines.push(` Replaced by: ${run.supersededBy}`);
123
+ }
124
+ if (report.hasMore)
125
+ lines.push('', 'Older finished runs exist. Increase --limit to show up to 100.');
126
+ return lines.join('\n');
127
+ }
128
+ export async function verifyHistoryCommand(repository, options) {
129
+ const parts = repository.split('/');
130
+ if (parts.length !== 2 || !parts.every(part => REPO_COMPONENT.test(part))) {
131
+ throw new Error('Use an exact GitHub owner/repository name for verification history.');
132
+ }
133
+ const limitText = options.limit ?? '20';
134
+ if (!/^[1-9]\d*$/.test(limitText) || Number(limitText) > 100) {
135
+ throw new Error('--limit must be a whole number from 1 to 100.');
136
+ }
137
+ const [owner, name] = parts;
138
+ const limit = Number(limitText);
139
+ const auth = await resolveAuthContext({ preferredLogin: options.account, owner, repo: name });
140
+ let response;
141
+ try {
142
+ response = await haystackJson(`/api/agent/cloud-verifier/history/${encodeURIComponent(owner)}/${encodeURIComponent(name)}?limit=${limit}`, auth.token, { method: 'GET' });
143
+ }
144
+ catch (error) {
145
+ if (error instanceof HaystackApiError && error.status === 404) {
146
+ throw new Error('Verification history was not found for this repository and account. Check repository access and use --account <login> if needed.');
147
+ }
148
+ throw error;
149
+ }
150
+ const report = parseVerifyHistoryReport(response, { owner, name, limit });
151
+ process.stdout.write((options.json ? JSON.stringify(report, null, 2) : formatVerifyHistory(report)) + '\n');
152
+ }
@@ -1,12 +1,14 @@
1
+ declare const FLEET_PROJECTION_VERSION = "dv-cloud-verifier-fleet-runner-projection-v1";
1
2
  export interface HostedIntent {
2
3
  problem: string;
3
4
  goal: string;
4
5
  intended_outcomes: string[];
5
6
  }
6
7
  export interface HostedStartOptions {
8
+ provider?: 'haystack';
7
9
  base: string;
8
10
  head: string;
9
- intentFile: string;
11
+ intentFile?: string;
10
12
  idempotencyKey?: string;
11
13
  replayPlanFrom?: string;
12
14
  account?: string;
@@ -44,6 +46,11 @@ export interface HostedRunState {
44
46
  completedAt?: string;
45
47
  output?: Record<string, unknown>;
46
48
  result?: HostedRunnerResult;
49
+ provider?: 'haystack';
50
+ version?: typeof FLEET_PROJECTION_VERSION;
51
+ /** Opaque P0 documents, authoritatively validated by the hosted service. */
52
+ progress?: Record<string, unknown>;
53
+ fleetResult?: Record<string, unknown>;
47
54
  error?: string;
48
55
  }
49
56
  export interface HostedPollOptions {
@@ -62,7 +69,10 @@ export declare function parseHostedRepository(value: string): {
62
69
  fullName: string;
63
70
  };
64
71
  export declare function readHostedIntentFile(intentFile: string | undefined): HostedIntent;
65
- export declare function defaultHostedIdempotencyKey(repository: string, baseCommit: string, headCommit: string, replayPlanFrom?: string): string;
72
+ export declare function defaultHostedIdempotencyKey(repository: string, baseCommit: string, headCommit: string, replayPlanFrom?: string, fleetRequest?: {
73
+ provider: 'haystack';
74
+ intent?: HostedIntent;
75
+ }): string;
66
76
  export declare function hostedPollingOptions(interval: string | undefined, timeout: string | undefined, onStatus?: (state: HostedRunState) => void): HostedPollOptions;
67
77
  export declare function startHostedVerification(repositoryArg: string, options: HostedStartOptions, token: string): Promise<{
68
78
  state: HostedRunState;