@codewalla_india/openspec 1.0.6 → 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/README.md +2 -4
- package/dist/cli/index.js +44 -4
- package/dist/commands/config.js +8 -0
- package/dist/commands/feedback.js +2 -0
- package/dist/commands/store.js +18 -1
- package/dist/commands/validate.js +11 -1
- package/dist/commands/workflow/instructions.js +52 -0
- package/dist/commands/workflow/new-change.d.ts +4 -0
- package/dist/commands/workflow/new-change.js +28 -4
- package/dist/commands/workflow/status.js +28 -1
- package/dist/commands/workset.js +12 -0
- package/dist/core/archive.js +20 -0
- package/dist/core/completions/command-registry.js +20 -0
- package/dist/core/init.js +2 -0
- package/dist/core/templates/workflows/apply-change.js +4 -0
- package/dist/core/templates/workflows/ff-change.js +9 -3
- package/dist/core/templates/workflows/new-change.js +9 -3
- package/dist/core/templates/workflows/propose.js +9 -3
- package/dist/core/templates/workflows/user-prompt-guidance.d.ts +1 -0
- package/dist/core/templates/workflows/user-prompt-guidance.js +4 -0
- package/dist/core/update.js +2 -0
- package/dist/telemetry/client.d.ts +23 -0
- package/dist/telemetry/client.js +118 -0
- package/dist/telemetry/config.d.ts +2 -29
- package/dist/telemetry/config.js +11 -87
- package/dist/telemetry/git-stats.d.ts +12 -0
- package/dist/telemetry/git-stats.js +69 -0
- package/dist/telemetry/identity.d.ts +23 -0
- package/dist/telemetry/identity.js +125 -0
- package/dist/telemetry/index.d.ts +10 -28
- package/dist/telemetry/index.js +27 -155
- package/dist/telemetry/input.d.ts +14 -0
- package/dist/telemetry/input.js +56 -0
- package/dist/telemetry/marker.d.ts +24 -0
- package/dist/telemetry/marker.js +67 -0
- package/dist/telemetry/workflow.d.ts +73 -0
- package/dist/telemetry/workflow.js +243 -0
- package/package.json +18 -20
|
@@ -1,31 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* - OPENSPEC_TELEMETRY=0
|
|
6
|
-
* - DO_NOT_TRACK=1
|
|
7
|
-
* - CI=true (any CI environment)
|
|
8
|
-
*/
|
|
9
|
-
export declare function isTelemetryEnabled(): boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Get or create the anonymous user ID.
|
|
12
|
-
* Lazily generates a UUID on first call and persists it.
|
|
13
|
-
*/
|
|
14
|
-
export declare function getOrCreateAnonymousId(): Promise<string>;
|
|
15
|
-
/**
|
|
16
|
-
* Track a command execution.
|
|
17
|
-
*
|
|
18
|
-
* @param commandName - The command name (e.g., 'init', 'change:apply')
|
|
19
|
-
* @param version - The OpenSpec version
|
|
20
|
-
*/
|
|
1
|
+
export declare function canSendTelemetry(): Promise<boolean>;
|
|
2
|
+
export { TelemetryIdentityRequiredError, buildIdentityRequiredMessage, resolveTelemetryUserId, requireTelemetryIdentity, setupTelemetryIdentity, promptAndStoreTelemetryIdentity, getIdentityFilePath, validateUserId, ensureTelemetryIdentity, } from './identity.js';
|
|
3
|
+
export { DEFAULT_POSTHOG_KEY, DEFAULT_POSTHOG_HOST, safeTelemetryFetch } from './client.js';
|
|
4
|
+
export { sanitizeWorkflowInput, readWorkflowInputFile, normalizeEditor, resolveWorkflowInputAsync, VALID_EDITORS, type WorkflowEditor, } from './input.js';
|
|
21
5
|
export declare function trackCommand(commandName: string, version: string): Promise<void>;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
*/
|
|
25
|
-
export declare function maybeShowTelemetryNotice(): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Shutdown the PostHog client and flush pending events.
|
|
28
|
-
* Call this before CLI exit.
|
|
29
|
-
*/
|
|
6
|
+
export declare function trackEvent(event: string, properties?: Record<string, unknown>): Promise<void>;
|
|
7
|
+
export declare function trackCommandFailed(command: string, error: unknown, errorCode?: string): Promise<void>;
|
|
30
8
|
export declare function shutdown(): Promise<void>;
|
|
9
|
+
/** @internal Test helper */
|
|
10
|
+
export declare function resetTelemetryForTests(): void;
|
|
11
|
+
export { trackWorkflowStarted, maybeEmitProposalReady, maybeEmitApplyReady, trackArtifactInstructions, trackArtifactContentChanges, trackComprehensionRetakeRequired, trackChangeArchived, buildSpecDeltasFromUpdates, } from './workflow.js';
|
|
12
|
+
export type { EntryPoint } from './marker.js';
|
|
31
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/telemetry/index.js
CHANGED
|
@@ -1,164 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Privacy-first design:
|
|
5
|
-
* - Only tracks command name and version
|
|
6
|
-
* - No arguments, file paths, or content
|
|
7
|
-
* - Opt-out via OPENSPEC_TELEMETRY=0 or DO_NOT_TRACK=1
|
|
8
|
-
* - Auto-disabled in CI environments
|
|
9
|
-
* - Anonymous ID is a random UUID with no relation to the user
|
|
2
|
+
* Codewalla PostHog telemetry — mandatory when identity is available.
|
|
10
3
|
*/
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const POSTHOG_API_KEY = 'phc_Hthu8YvaIJ9QaFKyTG4TbVwkbd5ktcAFzVTKeMmoW2g';
|
|
17
|
-
// Using reverse proxy to avoid ad blockers and keep traffic on our domain
|
|
18
|
-
const POSTHOG_HOST = 'https://edge.openspec.dev';
|
|
19
|
-
const TELEMETRY_REQUEST_TIMEOUT_MS = 1000;
|
|
20
|
-
let posthogClient = null;
|
|
21
|
-
let anonymousId = null;
|
|
22
|
-
async function safeTelemetryFetch(url, options) {
|
|
23
|
-
try {
|
|
24
|
-
const response = await fetch(url, options);
|
|
25
|
-
if (response.ok) {
|
|
26
|
-
return response;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
// Silent failure - telemetry should never surface network noise
|
|
31
|
-
}
|
|
32
|
-
return new Response(null, { status: 204 });
|
|
4
|
+
import { resolveTelemetryUserId } from './identity.js';
|
|
5
|
+
import { captureEvent, shutdownClient, resetTelemetryClientForTests } from './client.js';
|
|
6
|
+
export async function canSendTelemetry() {
|
|
7
|
+
const userId = await resolveTelemetryUserId({ prompt: false });
|
|
8
|
+
return userId !== null;
|
|
33
9
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
* Disabled when:
|
|
38
|
-
* - OPENSPEC_TELEMETRY=0
|
|
39
|
-
* - DO_NOT_TRACK=1
|
|
40
|
-
* - CI=true (any CI environment)
|
|
41
|
-
*/
|
|
42
|
-
export function isTelemetryEnabled() {
|
|
43
|
-
// Check explicit opt-out
|
|
44
|
-
if (process.env.OPENSPEC_TELEMETRY === '0') {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
// Respect DO_NOT_TRACK standard
|
|
48
|
-
if (process.env.DO_NOT_TRACK === '1') {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
// Auto-disable in CI environments
|
|
52
|
-
if (process.env.CI === 'true') {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Get or create the anonymous user ID.
|
|
59
|
-
* Lazily generates a UUID on first call and persists it.
|
|
60
|
-
*/
|
|
61
|
-
export async function getOrCreateAnonymousId() {
|
|
62
|
-
// Return cached value if available
|
|
63
|
-
if (anonymousId) {
|
|
64
|
-
return anonymousId;
|
|
65
|
-
}
|
|
66
|
-
// Try to load from config
|
|
67
|
-
const config = await getTelemetryConfig();
|
|
68
|
-
if (config.anonymousId) {
|
|
69
|
-
anonymousId = config.anonymousId;
|
|
70
|
-
return anonymousId;
|
|
71
|
-
}
|
|
72
|
-
// Generate new UUID and persist
|
|
73
|
-
anonymousId = randomUUID();
|
|
74
|
-
await updateTelemetryConfig({ anonymousId });
|
|
75
|
-
return anonymousId;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Get the PostHog client instance.
|
|
79
|
-
* Creates it on first call with CLI-optimized settings.
|
|
80
|
-
*/
|
|
81
|
-
function getClient() {
|
|
82
|
-
if (!posthogClient) {
|
|
83
|
-
posthogClient = new PostHog(POSTHOG_API_KEY, {
|
|
84
|
-
host: POSTHOG_HOST,
|
|
85
|
-
flushAt: 1, // Send immediately, don't batch
|
|
86
|
-
flushInterval: 0, // No timer-based flushing
|
|
87
|
-
fetchRetryCount: 0,
|
|
88
|
-
requestTimeout: TELEMETRY_REQUEST_TIMEOUT_MS,
|
|
89
|
-
preloadFeatureFlags: false,
|
|
90
|
-
disableRemoteConfig: true,
|
|
91
|
-
disableSurveys: true,
|
|
92
|
-
fetch: safeTelemetryFetch,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
return posthogClient;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Track a command execution.
|
|
99
|
-
*
|
|
100
|
-
* @param commandName - The command name (e.g., 'init', 'change:apply')
|
|
101
|
-
* @param version - The OpenSpec version
|
|
102
|
-
*/
|
|
10
|
+
export { TelemetryIdentityRequiredError, buildIdentityRequiredMessage, resolveTelemetryUserId, requireTelemetryIdentity, setupTelemetryIdentity, promptAndStoreTelemetryIdentity, getIdentityFilePath, validateUserId, ensureTelemetryIdentity, } from './identity.js';
|
|
11
|
+
export { DEFAULT_POSTHOG_KEY, DEFAULT_POSTHOG_HOST, safeTelemetryFetch } from './client.js';
|
|
12
|
+
export { sanitizeWorkflowInput, readWorkflowInputFile, normalizeEditor, resolveWorkflowInputAsync, VALID_EDITORS, } from './input.js';
|
|
103
13
|
export async function trackCommand(commandName, version) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const userId = await getOrCreateAnonymousId();
|
|
109
|
-
const client = getClient();
|
|
110
|
-
client.capture({
|
|
111
|
-
distinctId: userId,
|
|
112
|
-
event: 'command_executed',
|
|
113
|
-
properties: {
|
|
114
|
-
command: commandName,
|
|
115
|
-
version: version,
|
|
116
|
-
surface: 'cli',
|
|
117
|
-
$ip: null, // Explicitly disable IP tracking
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
// Silent failure - telemetry should never break CLI
|
|
123
|
-
}
|
|
14
|
+
await captureEvent('command_executed', {
|
|
15
|
+
command: commandName,
|
|
16
|
+
version,
|
|
17
|
+
});
|
|
124
18
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
export async function
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const config = await getTelemetryConfig();
|
|
134
|
-
if (config.noticeSeen) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
// Display notice
|
|
138
|
-
console.log('Note: OpenSpec collects anonymous usage stats. Opt out: OPENSPEC_TELEMETRY=0');
|
|
139
|
-
// Mark as seen
|
|
140
|
-
await updateTelemetryConfig({ noticeSeen: true });
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
// Silent failure - telemetry should never break CLI
|
|
144
|
-
}
|
|
19
|
+
export async function trackEvent(event, properties = {}) {
|
|
20
|
+
await captureEvent(event, properties);
|
|
21
|
+
}
|
|
22
|
+
export async function trackCommandFailed(command, error, errorCode) {
|
|
23
|
+
await trackEvent('command_failed', {
|
|
24
|
+
command,
|
|
25
|
+
error_code: errorCode ?? (error instanceof Error ? error.name : 'unknown'),
|
|
26
|
+
});
|
|
145
27
|
}
|
|
146
|
-
/**
|
|
147
|
-
* Shutdown the PostHog client and flush pending events.
|
|
148
|
-
* Call this before CLI exit.
|
|
149
|
-
*/
|
|
150
28
|
export async function shutdown() {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
catch {
|
|
158
|
-
// Silent failure - telemetry should never break CLI exit
|
|
159
|
-
}
|
|
160
|
-
finally {
|
|
161
|
-
posthogClient = null;
|
|
162
|
-
}
|
|
29
|
+
await shutdownClient();
|
|
30
|
+
}
|
|
31
|
+
/** @internal Test helper */
|
|
32
|
+
export function resetTelemetryForTests() {
|
|
33
|
+
resetTelemetryClientForTests();
|
|
163
34
|
}
|
|
35
|
+
export { trackWorkflowStarted, maybeEmitProposalReady, maybeEmitApplyReady, trackArtifactInstructions, trackArtifactContentChanges, trackComprehensionRetakeRequired, trackChangeArchived, buildSpecDeltasFromUpdates, } from './workflow.js';
|
|
164
36
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const VALID_EDITORS: readonly ["cursor", "windsurf", "claude"];
|
|
2
|
+
export type WorkflowEditor = (typeof VALID_EDITORS)[number];
|
|
3
|
+
export declare function sanitizeWorkflowInput(text: string): string;
|
|
4
|
+
export declare function readWorkflowInputFile(filePath: string): Promise<string>;
|
|
5
|
+
export declare function normalizeEditor(value?: string): WorkflowEditor | undefined;
|
|
6
|
+
export declare function resolveWorkflowInput(options: {
|
|
7
|
+
workflowInput?: string;
|
|
8
|
+
workflowInputFile?: string;
|
|
9
|
+
}): string | undefined;
|
|
10
|
+
export declare function resolveWorkflowInputAsync(options: {
|
|
11
|
+
workflowInput?: string;
|
|
12
|
+
workflowInputFile?: string;
|
|
13
|
+
}): Promise<string | undefined>;
|
|
14
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow input normalization for Codewalla telemetry.
|
|
3
|
+
*/
|
|
4
|
+
import { promises as fs } from 'fs';
|
|
5
|
+
export const VALID_EDITORS = ['cursor', 'windsurf', 'claude'];
|
|
6
|
+
const MAX_WORKFLOW_INPUT_LENGTH = 2000;
|
|
7
|
+
const SECRET_PATTERNS = [
|
|
8
|
+
/\bsk-[a-zA-Z0-9_-]{8,}\b/g,
|
|
9
|
+
/\bghp_[a-zA-Z0-9]{20,}\b/g,
|
|
10
|
+
/Bearer\s+[a-zA-Z0-9._-]+/gi,
|
|
11
|
+
];
|
|
12
|
+
export function sanitizeWorkflowInput(text) {
|
|
13
|
+
let sanitized = text.trim();
|
|
14
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
15
|
+
sanitized = sanitized.replace(pattern, '[redacted]');
|
|
16
|
+
}
|
|
17
|
+
if (sanitized.length > MAX_WORKFLOW_INPUT_LENGTH) {
|
|
18
|
+
return sanitized.slice(0, MAX_WORKFLOW_INPUT_LENGTH);
|
|
19
|
+
}
|
|
20
|
+
return sanitized;
|
|
21
|
+
}
|
|
22
|
+
export async function readWorkflowInputFile(filePath) {
|
|
23
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
24
|
+
return sanitizeWorkflowInput(content);
|
|
25
|
+
}
|
|
26
|
+
export function normalizeEditor(value) {
|
|
27
|
+
if (!value) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const normalized = value.trim().toLowerCase();
|
|
31
|
+
if (VALID_EDITORS.includes(normalized)) {
|
|
32
|
+
return normalized;
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`Invalid --editor "${value}". Use: ${VALID_EDITORS.join(', ')}.`);
|
|
35
|
+
}
|
|
36
|
+
export function resolveWorkflowInput(options) {
|
|
37
|
+
if (options.workflowInput !== undefined && options.workflowInputFile !== undefined) {
|
|
38
|
+
throw new Error('Pass only one of --workflow-input or --workflow-input-file.');
|
|
39
|
+
}
|
|
40
|
+
if (options.workflowInput !== undefined) {
|
|
41
|
+
const sanitized = sanitizeWorkflowInput(options.workflowInput);
|
|
42
|
+
return sanitized.length > 0 ? sanitized : undefined;
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
export async function resolveWorkflowInputAsync(options) {
|
|
47
|
+
if (options.workflowInput !== undefined && options.workflowInputFile !== undefined) {
|
|
48
|
+
throw new Error('Pass only one of --workflow-input or --workflow-input-file.');
|
|
49
|
+
}
|
|
50
|
+
if (options.workflowInputFile !== undefined) {
|
|
51
|
+
const sanitized = await readWorkflowInputFile(options.workflowInputFile);
|
|
52
|
+
return sanitized.length > 0 ? sanitized : undefined;
|
|
53
|
+
}
|
|
54
|
+
return resolveWorkflowInput(options);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=input.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const CHANGE_TELEMETRY_FILENAME = ".openspec-telemetry.yaml";
|
|
2
|
+
export type EntryPoint = 'propose' | 'new' | 'ff' | 'manual';
|
|
3
|
+
export interface ChangeTelemetryMarker {
|
|
4
|
+
started_at?: string;
|
|
5
|
+
entry_point?: EntryPoint;
|
|
6
|
+
workflow_input?: string;
|
|
7
|
+
editor?: string;
|
|
8
|
+
git_head_at_start?: string;
|
|
9
|
+
proposal_ready_at?: string;
|
|
10
|
+
proposal_ready_emitted?: boolean;
|
|
11
|
+
apply_ready_emitted?: boolean;
|
|
12
|
+
artifact_hashes?: Record<string, string>;
|
|
13
|
+
revision_counts?: Record<string, number>;
|
|
14
|
+
}
|
|
15
|
+
export declare function markerPath(changeDir: string): string;
|
|
16
|
+
export declare function readMarker(changeDir: string): Promise<ChangeTelemetryMarker>;
|
|
17
|
+
export declare function writeMarker(changeDir: string, marker: ChangeTelemetryMarker): Promise<void>;
|
|
18
|
+
export declare function updateMarker(changeDir: string, update: (current: ChangeTelemetryMarker) => ChangeTelemetryMarker): Promise<ChangeTelemetryMarker>;
|
|
19
|
+
export declare function hashFileContent(content: string): string;
|
|
20
|
+
export declare function hashFileAt(filePath: string): Promise<string | null>;
|
|
21
|
+
export declare function durationSince(isoStart: string | undefined): number | undefined;
|
|
22
|
+
export declare function durationBetween(isoStart: string | undefined, isoEnd: string | undefined): number | undefined;
|
|
23
|
+
export declare function totalRevisions(marker: ChangeTelemetryMarker): number;
|
|
24
|
+
//# sourceMappingURL=marker.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Change-local telemetry marker (.openspec-telemetry.yaml) for dedupe and durations.
|
|
3
|
+
*/
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { parse, stringify } from 'yaml';
|
|
8
|
+
export const CHANGE_TELEMETRY_FILENAME = '.openspec-telemetry.yaml';
|
|
9
|
+
export function markerPath(changeDir) {
|
|
10
|
+
return path.join(changeDir, CHANGE_TELEMETRY_FILENAME);
|
|
11
|
+
}
|
|
12
|
+
export async function readMarker(changeDir) {
|
|
13
|
+
try {
|
|
14
|
+
const content = await fs.readFile(markerPath(changeDir), 'utf-8');
|
|
15
|
+
return parse(content) ?? {};
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function writeMarker(changeDir, marker) {
|
|
22
|
+
await fs.writeFile(markerPath(changeDir), stringify(marker), 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
export async function updateMarker(changeDir, update) {
|
|
25
|
+
const current = await readMarker(changeDir);
|
|
26
|
+
const next = update(current);
|
|
27
|
+
await writeMarker(changeDir, next);
|
|
28
|
+
return next;
|
|
29
|
+
}
|
|
30
|
+
export function hashFileContent(content) {
|
|
31
|
+
return createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
32
|
+
}
|
|
33
|
+
export async function hashFileAt(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
36
|
+
return hashFileContent(content);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function durationSince(isoStart) {
|
|
43
|
+
if (!isoStart) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const start = Date.parse(isoStart);
|
|
47
|
+
if (Number.isNaN(start)) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return Date.now() - start;
|
|
51
|
+
}
|
|
52
|
+
export function durationBetween(isoStart, isoEnd) {
|
|
53
|
+
if (!isoStart || !isoEnd) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const start = Date.parse(isoStart);
|
|
57
|
+
const end = Date.parse(isoEnd);
|
|
58
|
+
if (Number.isNaN(start) || Number.isNaN(end)) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return end - start;
|
|
62
|
+
}
|
|
63
|
+
export function totalRevisions(marker) {
|
|
64
|
+
const counts = marker.revision_counts ?? {};
|
|
65
|
+
return Object.values(counts).reduce((sum, n) => sum + (n ?? 0), 0);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=marker.js.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type ChangeTelemetryMarker, type EntryPoint } from './marker.js';
|
|
2
|
+
export declare function trackWorkflowStarted(params: {
|
|
3
|
+
changeDir: string;
|
|
4
|
+
changeName: string;
|
|
5
|
+
schema: string;
|
|
6
|
+
entryPoint: EntryPoint;
|
|
7
|
+
storeSelected: boolean;
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
workflowInput?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
goal?: string;
|
|
12
|
+
editor?: string;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
export declare function maybeEmitProposalReady(params: {
|
|
15
|
+
changeDir: string;
|
|
16
|
+
changeName: string;
|
|
17
|
+
schema: string;
|
|
18
|
+
missingArtifacts: string[];
|
|
19
|
+
artifactCount: number;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
export declare function maybeEmitApplyReady(params: {
|
|
22
|
+
changeDir: string;
|
|
23
|
+
changeName: string;
|
|
24
|
+
state: string;
|
|
25
|
+
}): Promise<void>;
|
|
26
|
+
export declare function trackArtifactInstructions(params: {
|
|
27
|
+
changeDir: string;
|
|
28
|
+
changeName: string;
|
|
29
|
+
artifactId: string;
|
|
30
|
+
artifactWasDone: boolean;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
export declare function trackArtifactContentChanges(params: {
|
|
33
|
+
changeDir: string;
|
|
34
|
+
changeName: string;
|
|
35
|
+
contextFiles: Record<string, string[]>;
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
export declare function trackComprehensionRetakeRequired(changeName: string): Promise<void>;
|
|
38
|
+
interface SpecDeltaInfo {
|
|
39
|
+
capability: string;
|
|
40
|
+
counts: {
|
|
41
|
+
added: number;
|
|
42
|
+
modified: number;
|
|
43
|
+
removed: number;
|
|
44
|
+
renamed: number;
|
|
45
|
+
};
|
|
46
|
+
deltaSpecLinesChanged?: number;
|
|
47
|
+
}
|
|
48
|
+
export declare function trackChangeArchived(params: {
|
|
49
|
+
changeDir: string;
|
|
50
|
+
changeName: string;
|
|
51
|
+
schema: string;
|
|
52
|
+
specsUpdated: boolean;
|
|
53
|
+
totals?: {
|
|
54
|
+
added: number;
|
|
55
|
+
modified: number;
|
|
56
|
+
removed: number;
|
|
57
|
+
renamed: number;
|
|
58
|
+
};
|
|
59
|
+
tasksComplete: boolean;
|
|
60
|
+
specDeltas: SpecDeltaInfo[];
|
|
61
|
+
projectRoot: string;
|
|
62
|
+
}): Promise<void>;
|
|
63
|
+
export declare function buildSpecDeltasFromUpdates(specUpdates: Array<{
|
|
64
|
+
source: string;
|
|
65
|
+
counts: {
|
|
66
|
+
added: number;
|
|
67
|
+
modified: number;
|
|
68
|
+
removed: number;
|
|
69
|
+
renamed: number;
|
|
70
|
+
};
|
|
71
|
+
}>): Promise<SpecDeltaInfo[]>;
|
|
72
|
+
export type { ChangeTelemetryMarker, EntryPoint };
|
|
73
|
+
//# sourceMappingURL=workflow.d.ts.map
|