@codewalla_india/openspec 1.3.1 → 1.3.3
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/LICENSE +22 -22
- package/README.md +214 -133
- package/bin/openspec.js +5 -5
- package/dist/cli/index.js +99 -62
- package/dist/commands/change.d.ts +0 -2
- package/dist/commands/change.js +107 -86
- package/dist/commands/config.js +14 -16
- package/dist/commands/doctor.js +9 -4
- package/dist/commands/feedback.js +79 -30
- package/dist/commands/modify.d.ts +26 -0
- package/dist/commands/modify.js +147 -0
- package/dist/commands/schema.js +170 -91
- package/dist/commands/show.js +5 -2
- package/dist/commands/spec.js +49 -29
- package/dist/commands/store.js +15 -21
- package/dist/commands/validate.d.ts +8 -0
- package/dist/commands/validate.js +43 -20
- package/dist/commands/workflow/index.d.ts +2 -2
- package/dist/commands/workflow/index.js +1 -1
- package/dist/commands/workflow/instructions.d.ts +6 -26
- package/dist/commands/workflow/instructions.js +183 -376
- package/dist/commands/workflow/new-change.d.ts +0 -4
- package/dist/commands/workflow/new-change.js +10 -28
- package/dist/commands/workflow/shared.d.ts +34 -19
- package/dist/commands/workflow/shared.js +34 -4
- package/dist/commands/workflow/status.js +10 -32
- package/dist/commands/workflow/templates.js +15 -5
- package/dist/commands/workset.d.ts +2 -2
- package/dist/commands/workset.js +19 -22
- package/dist/comprehension-quiz/fingerprint.d.ts +39 -0
- package/dist/comprehension-quiz/fingerprint.js +84 -0
- package/dist/comprehension-quiz/index.d.ts +42 -0
- package/dist/comprehension-quiz/index.js +47 -0
- package/dist/comprehension-quiz/pass-record.d.ts +44 -0
- package/dist/comprehension-quiz/pass-record.js +98 -0
- package/dist/comprehension-quiz/providers/anthropic.d.ts +35 -0
- package/dist/comprehension-quiz/providers/anthropic.js +69 -0
- package/dist/comprehension-quiz/providers/factory.d.ts +44 -0
- package/dist/comprehension-quiz/providers/factory.js +174 -0
- package/dist/comprehension-quiz/providers/interface.d.ts +98 -0
- package/dist/comprehension-quiz/providers/interface.js +150 -0
- package/dist/comprehension-quiz/providers/local.d.ts +35 -0
- package/dist/comprehension-quiz/providers/local.js +69 -0
- package/dist/comprehension-quiz/providers/ollama.d.ts +35 -0
- package/dist/comprehension-quiz/providers/ollama.js +69 -0
- package/dist/comprehension-quiz/providers/openai.d.ts +35 -0
- package/dist/comprehension-quiz/providers/openai.js +72 -0
- package/dist/comprehension-quiz/question-generator.d.ts +117 -0
- package/dist/comprehension-quiz/question-generator.js +203 -0
- package/dist/comprehension-quiz/quiz-executor.d.ts +75 -0
- package/dist/comprehension-quiz/quiz-executor.js +181 -0
- package/dist/comprehension-quiz/types.d.ts +137 -0
- package/dist/comprehension-quiz/types.js +11 -0
- package/dist/core/archive.d.ts +14 -1
- package/dist/core/archive.js +1350 -190
- package/dist/core/artifact-graph/graph.d.ts +28 -9
- package/dist/core/artifact-graph/graph.js +94 -43
- package/dist/core/artifact-graph/index.d.ts +1 -1
- package/dist/core/artifact-graph/index.js +1 -1
- package/dist/core/artifact-graph/instruction-loader.d.ts +30 -3
- package/dist/core/artifact-graph/instruction-loader.js +70 -12
- package/dist/core/artifact-graph/outputs.d.ts +1 -0
- package/dist/core/artifact-graph/outputs.js +67 -5
- package/dist/core/artifact-graph/resolver.d.ts +14 -0
- package/dist/core/artifact-graph/resolver.js +69 -15
- package/dist/core/artifact-graph/types.js +21 -3
- package/dist/core/available-tools.d.ts +2 -2
- package/dist/core/available-tools.js +14 -3
- package/dist/core/change-metadata/schema.d.ts +2 -0
- package/dist/core/change-metadata/schema.js +13 -0
- package/dist/core/change-status-policy.d.ts +10 -1
- package/dist/core/change-status-policy.js +30 -2
- package/dist/core/command-generation/adapters/amazon-q.d.ts +4 -0
- package/dist/core/command-generation/adapters/amazon-q.js +11 -5
- package/dist/core/command-generation/adapters/antigravity.js +6 -5
- package/dist/core/command-generation/adapters/auggie.js +7 -6
- package/dist/core/command-generation/adapters/bob.d.ts +5 -1
- package/dist/core/command-generation/adapters/bob.js +11 -10
- package/dist/core/command-generation/adapters/claude.d.ts +1 -1
- package/dist/core/command-generation/adapters/claude.js +12 -17
- package/dist/core/command-generation/adapters/cline.js +5 -5
- package/dist/core/command-generation/adapters/codebuddy.js +8 -7
- package/dist/core/command-generation/adapters/continue.js +8 -7
- package/dist/core/command-generation/adapters/costrict.js +7 -6
- package/dist/core/command-generation/adapters/crush.js +9 -9
- package/dist/core/command-generation/adapters/cursor.js +8 -8
- package/dist/core/command-generation/adapters/devin.d.ts +19 -0
- package/dist/core/command-generation/adapters/devin.js +36 -0
- package/dist/core/command-generation/adapters/factory.js +7 -6
- package/dist/core/command-generation/adapters/gemini.js +40 -5
- package/dist/core/command-generation/adapters/github-copilot.js +6 -5
- package/dist/core/command-generation/adapters/iflow.js +9 -8
- package/dist/core/command-generation/adapters/index.d.ts +4 -2
- package/dist/core/command-generation/adapters/index.js +4 -2
- package/dist/core/command-generation/adapters/junie.js +6 -5
- package/dist/core/command-generation/adapters/kilocode.js +1 -1
- package/dist/core/command-generation/adapters/kiro.js +6 -5
- package/dist/core/command-generation/adapters/lingma.js +9 -9
- package/dist/core/command-generation/adapters/oh-my-pi.d.ts +21 -0
- package/dist/core/command-generation/adapters/oh-my-pi.js +42 -0
- package/dist/core/command-generation/adapters/opencode.js +6 -8
- package/dist/core/command-generation/adapters/pi.d.ts +2 -2
- package/dist/core/command-generation/adapters/pi.js +7 -10
- package/dist/core/command-generation/adapters/qoder.js +9 -9
- package/dist/core/command-generation/adapters/qwen.d.ts +7 -3
- package/dist/core/command-generation/adapters/qwen.js +14 -9
- package/dist/core/command-generation/adapters/roocode.d.ts +4 -4
- package/dist/core/command-generation/adapters/roocode.js +9 -9
- package/dist/core/command-generation/adapters/trae.d.ts +13 -0
- package/dist/core/command-generation/adapters/trae.js +28 -0
- package/dist/core/command-generation/adapters/zcode.d.ts +16 -0
- package/dist/core/command-generation/adapters/zcode.js +33 -0
- package/dist/core/command-generation/generator.d.ts +8 -0
- package/dist/core/command-generation/generator.js +15 -1
- package/dist/core/command-generation/index.d.ts +1 -1
- package/dist/core/command-generation/index.js +1 -1
- package/dist/core/command-generation/invocation.d.ts +73 -0
- package/dist/core/command-generation/invocation.js +77 -0
- package/dist/core/command-generation/registry.js +8 -4
- package/dist/core/command-generation/types.d.ts +9 -2
- package/dist/core/command-generation/yaml.d.ts +20 -6
- package/dist/core/command-generation/yaml.js +31 -21
- package/dist/core/command-surface.d.ts +15 -0
- package/dist/core/command-surface.js +33 -0
- package/dist/core/completions/command-registry.js +16 -61
- package/dist/core/completions/generators/bash-generator.js +41 -41
- package/dist/core/completions/generators/fish-generator.js +7 -7
- package/dist/core/completions/generators/powershell-generator.js +44 -37
- package/dist/core/completions/generators/zsh-generator.js +33 -33
- package/dist/core/completions/installers/zsh-installer.d.ts +9 -0
- package/dist/core/completions/installers/zsh-installer.js +20 -4
- package/dist/core/completions/templates/bash-templates.js +24 -24
- package/dist/core/completions/templates/fish-templates.js +38 -38
- package/dist/core/completions/templates/powershell-templates.js +28 -28
- package/dist/core/completions/templates/zsh-templates.js +39 -39
- package/dist/core/config-prompts.d.ts +1 -1
- package/dist/core/config-prompts.js +14 -1
- package/dist/core/config-schema.d.ts +10 -1
- package/dist/core/config-schema.js +67 -1
- package/dist/core/config.d.ts +15 -0
- package/dist/core/config.js +46 -5
- package/dist/core/file-state.js +56 -24
- package/dist/core/github-copilot/cloud-agent.d.ts +95 -0
- package/dist/core/github-copilot/cloud-agent.js +497 -0
- package/dist/core/global-config.d.ts +16 -0
- package/dist/core/init.d.ts +58 -0
- package/dist/core/init.js +474 -73
- package/dist/core/legacy-cleanup.d.ts +59 -0
- package/dist/core/legacy-cleanup.js +253 -24
- package/dist/core/list.js +23 -16
- package/dist/core/migration.d.ts +73 -1
- package/dist/core/migration.js +360 -11
- package/dist/core/modify/conflict-detector.d.ts +26 -0
- package/dist/core/modify/conflict-detector.js +62 -0
- package/dist/core/modify/dependency-propagator.d.ts +38 -0
- package/dist/core/modify/dependency-propagator.js +103 -0
- package/dist/core/modify/history-tracker.d.ts +34 -0
- package/dist/core/modify/history-tracker.js +114 -0
- package/dist/core/modify/index.d.ts +7 -0
- package/dist/core/modify/index.js +7 -0
- package/dist/core/onboarding-commands.d.ts +30 -0
- package/dist/core/onboarding-commands.js +38 -0
- package/dist/core/openspec-root.js +18 -15
- package/dist/core/parsers/change-parser.d.ts +17 -2
- package/dist/core/parsers/change-parser.js +35 -21
- package/dist/core/parsers/code-fence.d.ts +15 -0
- package/dist/core/parsers/code-fence.js +49 -0
- package/dist/core/parsers/markdown-parser.d.ts +0 -3
- package/dist/core/parsers/markdown-parser.js +7 -60
- package/dist/core/parsers/requirement-blocks.d.ts +29 -0
- package/dist/core/parsers/requirement-blocks.js +150 -31
- package/dist/core/parsers/requirement-text.d.ts +48 -0
- package/dist/core/parsers/requirement-text.js +98 -0
- package/dist/core/parsers/spec-structure.d.ts +1 -1
- package/dist/core/parsers/spec-structure.js +20 -30
- package/dist/core/profile-sync-drift.d.ts +0 -8
- package/dist/core/profile-sync-drift.js +49 -50
- package/dist/core/profiles.d.ts +2 -2
- package/dist/core/profiles.js +2 -2
- package/dist/core/project-config.d.ts +27 -18
- package/dist/core/project-config.js +101 -34
- package/dist/core/references.js +42 -4
- package/dist/core/relationship-health.d.ts +8 -0
- package/dist/core/relationship-health.js +13 -0
- package/dist/core/root-selection.d.ts +9 -6
- package/dist/core/root-selection.js +42 -5
- package/dist/core/schemas/base.schema.js +7 -2
- package/dist/core/shared/allowed-tools.d.ts +12 -0
- package/dist/core/shared/allowed-tools.js +12 -0
- package/dist/core/shared/index.d.ts +1 -0
- package/dist/core/shared/index.js +1 -0
- package/dist/core/shared/skill-content-equivalence.d.ts +7 -0
- package/dist/core/shared/skill-content-equivalence.js +41 -0
- package/dist/core/shared/skill-generation.js +17 -13
- package/dist/core/shared/skill-paths.d.ts +13 -0
- package/dist/core/shared/skill-paths.js +23 -0
- package/dist/core/shared/tool-detection.d.ts +27 -7
- package/dist/core/shared/tool-detection.js +167 -37
- package/dist/core/shared-skill-target.d.ts +16 -0
- package/dist/core/shared-skill-target.js +156 -0
- package/dist/core/specs-apply.d.ts +80 -33
- package/dist/core/specs-apply.js +667 -145
- package/dist/core/store/git.d.ts +13 -0
- package/dist/core/store/git.js +24 -0
- package/dist/core/store/operations.js +20 -0
- package/dist/core/templates/skill-templates.d.ts +3 -2
- package/dist/core/templates/skill-templates.js +3 -2
- package/dist/core/templates/workflows/apply-change.d.ts +10 -0
- package/dist/core/templates/workflows/apply-change.js +186 -224
- package/dist/core/templates/workflows/archive-change.js +387 -260
- package/dist/core/templates/workflows/bulk-archive-change.js +655 -475
- package/dist/core/templates/workflows/continue-change.js +210 -219
- package/dist/core/templates/workflows/explore.js +479 -443
- package/dist/core/templates/workflows/feedback.js +97 -97
- package/dist/core/templates/workflows/ff-change.js +200 -191
- package/dist/core/templates/workflows/modify-change.d.ts +4 -1
- package/dist/core/templates/workflows/modify-change.js +193 -71
- package/dist/core/templates/workflows/new-change.js +127 -134
- package/dist/core/templates/workflows/onboard.js +548 -542
- package/dist/core/templates/workflows/propose.js +273 -217
- package/dist/core/templates/workflows/store-selection.d.ts +1 -1
- package/dist/core/templates/workflows/store-selection.js +1 -1
- package/dist/core/templates/workflows/sync-specs.js +500 -273
- package/dist/core/templates/workflows/update-change.d.ts +10 -0
- package/dist/core/templates/workflows/update-change.js +177 -0
- package/dist/core/templates/workflows/verify-change.js +324 -326
- package/dist/core/update.d.ts +40 -5
- package/dist/core/update.js +411 -96
- package/dist/core/validation/constants.d.ts +4 -1
- package/dist/core/validation/constants.js +4 -1
- package/dist/core/validation/plan-validator.d.ts +8 -0
- package/dist/core/validation/plan-validator.js +45 -0
- package/dist/core/validation/task-numbering.d.ts +16 -0
- package/dist/core/validation/task-numbering.js +57 -0
- package/dist/core/validation/validator.d.ts +27 -3
- package/dist/core/validation/validator.js +337 -48
- package/dist/core/version-check.d.ts +152 -0
- package/dist/core/version-check.js +731 -0
- package/dist/core/view.js +13 -18
- package/dist/prompts/searchable-multi-select.js +1 -1
- package/dist/telemetry/caller-detection.d.ts +27 -0
- package/dist/telemetry/caller-detection.js +85 -0
- package/dist/telemetry/caller-detection.test.d.ts +5 -0
- package/dist/telemetry/config.d.ts +48 -2
- package/dist/telemetry/config.js +113 -11
- package/dist/telemetry/config.test.d.ts +5 -0
- package/dist/telemetry/deduplication.d.ts +35 -0
- package/dist/telemetry/deduplication.js +82 -0
- package/dist/telemetry/deduplication.test.d.ts +5 -0
- package/dist/telemetry/identity.d.ts +62 -22
- package/dist/telemetry/identity.js +147 -102
- package/dist/telemetry/index.d.ts +126 -15
- package/dist/telemetry/index.js +569 -37
- package/dist/telemetry/sanitization.d.ts +40 -0
- package/dist/telemetry/sanitization.js +114 -0
- package/dist/telemetry/sanitization.test.d.ts +5 -0
- package/dist/telemetry/throttling.d.ts +20 -0
- package/dist/telemetry/throttling.js +70 -0
- package/dist/ui/welcome-screen.d.ts +9 -1
- package/dist/ui/welcome-screen.js +91 -38
- package/dist/utils/change-metadata.d.ts +43 -0
- package/dist/utils/change-metadata.js +123 -7
- package/dist/utils/change-utils.d.ts +10 -4
- package/dist/utils/change-utils.js +20 -13
- package/dist/utils/ci.d.ts +12 -0
- package/dist/utils/ci.js +16 -0
- package/dist/utils/command-references.d.ts +92 -6
- package/dist/utils/command-references.js +180 -7
- package/dist/utils/date.d.ts +8 -0
- package/dist/utils/date.js +13 -0
- package/dist/utils/file-system.d.ts +10 -0
- package/dist/utils/file-system.js +70 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/interactive.d.ts +23 -0
- package/dist/utils/interactive.js +32 -0
- package/dist/utils/item-discovery.d.ts +19 -0
- package/dist/utils/item-discovery.js +30 -48
- package/dist/utils/shell-detection.d.ts +1 -1
- package/dist/utils/shell-detection.js +64 -11
- package/dist/utils/spec-discovery.d.ts +40 -0
- package/dist/utils/spec-discovery.js +115 -0
- package/dist/utils/task-progress.d.ts +29 -1
- package/dist/utils/task-progress.js +109 -15
- package/package.json +96 -84
- package/schemas/spec-driven/schema.yaml +252 -184
- package/schemas/spec-driven/templates/design.md +19 -19
- package/schemas/spec-driven/templates/plan-template.md +91 -0
- package/schemas/spec-driven/templates/proposal.md +29 -24
- package/schemas/spec-driven/templates/spec.md +11 -8
- package/schemas/spec-driven/templates/tasks.md +9 -9
- package/scripts/postinstall.js +83 -83
- package/dist/core/command-generation/adapters/codex.d.ts +0 -16
- package/dist/core/command-generation/adapters/codex.js +0 -39
- package/dist/core/command-generation/adapters/windsurf.d.ts +0 -14
- package/dist/core/command-generation/adapters/windsurf.js +0 -38
- package/dist/core/comprehension/config.d.ts +0 -20
- package/dist/core/comprehension/config.js +0 -23
- package/dist/core/comprehension/fingerprint.d.ts +0 -14
- package/dist/core/comprehension/fingerprint.js +0 -33
- package/dist/core/comprehension/index.d.ts +0 -57
- package/dist/core/comprehension/index.js +0 -87
- package/dist/core/comprehension/pass-record.d.ts +0 -29
- package/dist/core/comprehension/pass-record.js +0 -64
- package/dist/core/comprehension/stats.d.ts +0 -35
- package/dist/core/comprehension/stats.js +0 -133
- package/dist/core/templates/workflows/comprehension-guidance.d.ts +0 -9
- package/dist/core/templates/workflows/comprehension-guidance.js +0 -73
- package/dist/core/templates/workflows/mcp-guidance.d.ts +0 -13
- package/dist/core/templates/workflows/mcp-guidance.js +0 -131
- package/dist/core/templates/workflows/user-prompt-guidance.d.ts +0 -16
- package/dist/core/templates/workflows/user-prompt-guidance.js +0 -48
- package/dist/telemetry/caller.d.ts +0 -5
- package/dist/telemetry/caller.js +0 -29
- package/dist/telemetry/client.d.ts +0 -27
- package/dist/telemetry/client.js +0 -127
- package/dist/telemetry/command-context.d.ts +0 -13
- package/dist/telemetry/command-context.js +0 -59
- package/dist/telemetry/comprehension.d.ts +0 -44
- package/dist/telemetry/comprehension.js +0 -105
- package/dist/telemetry/content.d.ts +0 -10
- package/dist/telemetry/content.js +0 -56
- package/dist/telemetry/git-stats.d.ts +0 -12
- package/dist/telemetry/git-stats.js +0 -69
- package/dist/telemetry/identify-cache.d.ts +0 -7
- package/dist/telemetry/identify-cache.js +0 -47
- package/dist/telemetry/input.d.ts +0 -17
- package/dist/telemetry/input.js +0 -68
- package/dist/telemetry/marker.d.ts +0 -37
- package/dist/telemetry/marker.js +0 -67
- package/dist/telemetry/workflow.d.ts +0 -85
- package/dist/telemetry/workflow.js +0 -318
- package/schemas/spec-driven/templates/plan.md +0 -19
package/dist/core/view.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as path from 'path';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { getTaskProgressForChange } from '../utils/task-progress.js';
|
|
5
5
|
import { MarkdownParser } from './parsers/markdown-parser.js';
|
|
6
|
+
import { discoverSpecFiles } from '../utils/spec-discovery.js';
|
|
6
7
|
export class ViewCommand {
|
|
7
8
|
async execute(targetPath = '.') {
|
|
8
9
|
const openspecDir = path.join(targetPath, 'openspec');
|
|
@@ -70,7 +71,7 @@ export class ViewCommand {
|
|
|
70
71
|
const entries = fs.readdirSync(changesDir, { withFileTypes: true });
|
|
71
72
|
for (const entry of entries) {
|
|
72
73
|
if (entry.isDirectory() && entry.name !== 'archive') {
|
|
73
|
-
const progress = await getTaskProgressForChange(changesDir, entry.name);
|
|
74
|
+
const progress = await getTaskProgressForChange(changesDir, entry.name, path.dirname(openspecDir));
|
|
74
75
|
if (progress.total === 0) {
|
|
75
76
|
// No tasks defined yet - still in planning/draft phase
|
|
76
77
|
draft.push({ name: entry.name });
|
|
@@ -106,23 +107,17 @@ export class ViewCommand {
|
|
|
106
107
|
return [];
|
|
107
108
|
}
|
|
108
109
|
const specs = [];
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
// If spec cannot be parsed, include with 0 count
|
|
123
|
-
specs.push({ name: entry.name, requirementCount: 0 });
|
|
124
|
-
}
|
|
125
|
-
}
|
|
110
|
+
for (const { id, specFile } of await discoverSpecFiles(specsDir)) {
|
|
111
|
+
try {
|
|
112
|
+
const content = fs.readFileSync(specFile, 'utf-8');
|
|
113
|
+
const parser = new MarkdownParser(content);
|
|
114
|
+
const spec = parser.parseSpec(id);
|
|
115
|
+
const requirementCount = spec.requirements.length;
|
|
116
|
+
specs.push({ name: id, requirementCount });
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
// If spec cannot be parsed, include with 0 count
|
|
120
|
+
specs.push({ name: id, requirementCount: 0 });
|
|
126
121
|
}
|
|
127
122
|
}
|
|
128
123
|
return specs;
|
|
@@ -113,7 +113,7 @@ async function createSearchableMultiSelect() {
|
|
|
113
113
|
const actualIndex = startIndex + i;
|
|
114
114
|
const isActive = actualIndex === cursor;
|
|
115
115
|
const selected = selectedSet.has(item.value);
|
|
116
|
-
const icon = selected ? chalk.green('
|
|
116
|
+
const icon = selected ? chalk.green('[x]') : chalk.dim('[ ]');
|
|
117
117
|
const arrow = isActive ? chalk.cyan('›') : ' ';
|
|
118
118
|
const name = isActive ? chalk.cyan(item.name) : item.name;
|
|
119
119
|
const isRefresh = selected && item.configured;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caller detection module for telemetry.
|
|
3
|
+
*
|
|
4
|
+
* Detects the caller type (human, automation, ci, devin, cursor-agent, windsurf)
|
|
5
|
+
* from environment fingerprints and includes this information in all telemetry events.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Detect the caller type from environment fingerprints.
|
|
9
|
+
*
|
|
10
|
+
* Priority order:
|
|
11
|
+
* 1. Manual override via OPENSPEC_CALLER environment variable
|
|
12
|
+
* 2. Agent-specific detection (Devin, Cursor, Windsurf)
|
|
13
|
+
* 3. CI environment detection
|
|
14
|
+
* 4. TTY detection (interactive terminal)
|
|
15
|
+
* 5. Default to human if TTY present, else automation
|
|
16
|
+
*
|
|
17
|
+
* @returns The detected caller type
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectCaller(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Validate a caller type against the allowed set.
|
|
22
|
+
*
|
|
23
|
+
* @param callerType - The caller type to validate
|
|
24
|
+
* @returns True if valid, false otherwise
|
|
25
|
+
*/
|
|
26
|
+
export declare function isValidCallerType(callerType: string): boolean;
|
|
27
|
+
//# sourceMappingURL=caller-detection.d.ts.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caller detection module for telemetry.
|
|
3
|
+
*
|
|
4
|
+
* Detects the caller type (human, automation, ci, devin, cursor-agent, windsurf)
|
|
5
|
+
* from environment fingerprints and includes this information in all telemetry events.
|
|
6
|
+
*/
|
|
7
|
+
import { isCiEnvironment } from '../utils/ci.js';
|
|
8
|
+
// Allowed caller types
|
|
9
|
+
const ALLOWED_CALLER_TYPES = new Set([
|
|
10
|
+
'human',
|
|
11
|
+
'automation',
|
|
12
|
+
'ci',
|
|
13
|
+
'devin',
|
|
14
|
+
'cursor-agent',
|
|
15
|
+
'windsurf',
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Detect the caller type from environment fingerprints.
|
|
19
|
+
*
|
|
20
|
+
* Priority order:
|
|
21
|
+
* 1. Manual override via OPENSPEC_CALLER environment variable
|
|
22
|
+
* 2. Agent-specific detection (Devin, Cursor, Windsurf)
|
|
23
|
+
* 3. CI environment detection
|
|
24
|
+
* 4. TTY detection (interactive terminal)
|
|
25
|
+
* 5. Default to human if TTY present, else automation
|
|
26
|
+
*
|
|
27
|
+
* @returns The detected caller type
|
|
28
|
+
*/
|
|
29
|
+
export function detectCaller() {
|
|
30
|
+
// 1. Manual override (highest priority)
|
|
31
|
+
const manualOverride = process.env.OPENSPEC_CALLER;
|
|
32
|
+
if (manualOverride) {
|
|
33
|
+
const normalized = manualOverride.trim().toLowerCase();
|
|
34
|
+
if (ALLOWED_CALLER_TYPES.has(normalized)) {
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
// Invalid override, fall through to auto-detection
|
|
38
|
+
}
|
|
39
|
+
// 2. Agent-specific detection (placeholders for research)
|
|
40
|
+
// TODO: Research actual environment variable fingerprints for Devin, Cursor, Windsurf
|
|
41
|
+
const agentType = detectAgent();
|
|
42
|
+
if (agentType) {
|
|
43
|
+
return agentType;
|
|
44
|
+
}
|
|
45
|
+
// 3. CI environment detection
|
|
46
|
+
if (isCiEnvironment()) {
|
|
47
|
+
return 'ci';
|
|
48
|
+
}
|
|
49
|
+
// 4. TTY detection
|
|
50
|
+
if (process.stdout.isTTY) {
|
|
51
|
+
return 'human';
|
|
52
|
+
}
|
|
53
|
+
// 5. Default to automation
|
|
54
|
+
return 'automation';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Detect AI coding agent from environment variables.
|
|
58
|
+
*
|
|
59
|
+
* @returns The agent type if detected, null otherwise
|
|
60
|
+
*/
|
|
61
|
+
function detectAgent() {
|
|
62
|
+
// TODO: Research and implement actual environment variable fingerprints
|
|
63
|
+
// for Devin, Cursor, and Windsurf agents
|
|
64
|
+
// Placeholder implementations (to be replaced with actual detection logic)
|
|
65
|
+
if (process.env.DEVIN_AGENT === 'true') {
|
|
66
|
+
return 'devin';
|
|
67
|
+
}
|
|
68
|
+
if (process.env.CURSOR_AGENT === 'true') {
|
|
69
|
+
return 'cursor-agent';
|
|
70
|
+
}
|
|
71
|
+
if (process.env.WINDSURF_AGENT === 'true') {
|
|
72
|
+
return 'windsurf';
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validate a caller type against the allowed set.
|
|
78
|
+
*
|
|
79
|
+
* @param callerType - The caller type to validate
|
|
80
|
+
* @returns True if valid, false otherwise
|
|
81
|
+
*/
|
|
82
|
+
export function isValidCallerType(callerType) {
|
|
83
|
+
return ALLOWED_CALLER_TYPES.has(callerType.trim().toLowerCase());
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=caller-detection.js.map
|
|
@@ -1,11 +1,57 @@
|
|
|
1
|
+
import { type TelemetryConfig } from '../core/global-config.js';
|
|
1
2
|
export declare const CONFIG_DIR_NAME = "openspec";
|
|
2
3
|
export declare const CONFIG_FILE_NAME = "config.json";
|
|
4
|
+
export declare const IDENTITY_FILE_NAME = "telemetry-identity.json";
|
|
5
|
+
export declare const DEFAULT_POSTHOG_API_KEY = "phc_s56WNC4SgBSQBqa5jgZ22MpCmxv5rUsAy4g6MikQaZtD";
|
|
6
|
+
export declare const DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
|
|
7
|
+
/** Re-export shared telemetry section type (single source of truth in global-config). */
|
|
8
|
+
export type { TelemetryConfig };
|
|
3
9
|
export interface GlobalConfig {
|
|
10
|
+
telemetry?: TelemetryConfig;
|
|
4
11
|
[key: string]: unknown;
|
|
5
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Get the path to the global config file.
|
|
15
|
+
* Follows XDG Base Directory Specification and platform conventions.
|
|
16
|
+
*
|
|
17
|
+
* - All platforms: $XDG_CONFIG_HOME/openspec/ if XDG_CONFIG_HOME is set
|
|
18
|
+
* - Unix/macOS fallback: ~/.config/openspec/
|
|
19
|
+
* - Windows fallback: %APPDATA%/openspec/
|
|
20
|
+
*/
|
|
6
21
|
export declare function getConfigPath(): string;
|
|
22
|
+
/**
|
|
23
|
+
* Get the path to the identity file.
|
|
24
|
+
* Follows platform-specific config directory conventions.
|
|
25
|
+
*
|
|
26
|
+
* - All platforms: $XDG_CONFIG_HOME/openspec/ if XDG_CONFIG_HOME is set
|
|
27
|
+
* - Unix/macOS fallback: ~/.config/openspec/
|
|
28
|
+
* - Windows fallback: %APPDATA%/openspec/
|
|
29
|
+
*/
|
|
30
|
+
export declare function getIdentityFilePath(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Read the global config file.
|
|
33
|
+
* Returns an empty object if the file doesn't exist.
|
|
34
|
+
*/
|
|
7
35
|
export declare function readConfig(): Promise<GlobalConfig>;
|
|
36
|
+
/**
|
|
37
|
+
* Write to the global config file.
|
|
38
|
+
* Preserves existing fields and merges in new values.
|
|
39
|
+
*/
|
|
8
40
|
export declare function writeConfig(updates: Partial<GlobalConfig>): Promise<void>;
|
|
9
|
-
|
|
10
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Get the telemetry config section.
|
|
43
|
+
*/
|
|
44
|
+
export declare function getTelemetryConfig(): Promise<TelemetryConfig>;
|
|
45
|
+
/**
|
|
46
|
+
* Get the PostHog API key from environment variable or default.
|
|
47
|
+
*/
|
|
48
|
+
export declare function getPostHogApiKey(): string;
|
|
49
|
+
/**
|
|
50
|
+
* Get the PostHog host from environment variable or default.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getPostHogHost(): string;
|
|
53
|
+
/**
|
|
54
|
+
* Update the telemetry config section.
|
|
55
|
+
*/
|
|
56
|
+
export declare function updateTelemetryConfig(updates: Partial<TelemetryConfig>): Promise<void>;
|
|
11
57
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/telemetry/config.js
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Global configuration for
|
|
3
|
-
* Stores
|
|
2
|
+
* Global configuration for telemetry state.
|
|
3
|
+
* Stores anonymous ID and notice-seen flag in the platform-appropriate config directory.
|
|
4
4
|
*/
|
|
5
5
|
import { promises as fs } from 'fs';
|
|
6
6
|
import path from 'path';
|
|
7
|
+
import os from 'os';
|
|
7
8
|
import { GLOBAL_CONFIG_DIR_NAME, GLOBAL_CONFIG_FILE_NAME, getGlobalConfigDir, } from '../core/global-config.js';
|
|
9
|
+
// Constants
|
|
8
10
|
export const CONFIG_DIR_NAME = GLOBAL_CONFIG_DIR_NAME;
|
|
9
11
|
export const CONFIG_FILE_NAME = GLOBAL_CONFIG_FILE_NAME;
|
|
12
|
+
export const IDENTITY_FILE_NAME = 'telemetry-identity.json';
|
|
13
|
+
// PostHog configuration defaults
|
|
14
|
+
export const DEFAULT_POSTHOG_API_KEY = 'phc_s56WNC4SgBSQBqa5jgZ22MpCmxv5rUsAy4g6MikQaZtD';
|
|
15
|
+
export const DEFAULT_POSTHOG_HOST = 'https://us.i.posthog.com';
|
|
10
16
|
function getConfigDir() {
|
|
11
17
|
return getGlobalConfigDir();
|
|
12
18
|
}
|
|
19
|
+
function getLegacyConfigPath() {
|
|
20
|
+
return path.join(os.homedir(), '.config', CONFIG_DIR_NAME, CONFIG_FILE_NAME);
|
|
21
|
+
}
|
|
13
22
|
async function readConfigFile(configPath) {
|
|
14
23
|
try {
|
|
15
24
|
const content = await fs.readFile(configPath, 'utf-8');
|
|
@@ -19,6 +28,7 @@ async function readConfigFile(configPath) {
|
|
|
19
28
|
if (error.code === 'ENOENT') {
|
|
20
29
|
return { status: 'missing' };
|
|
21
30
|
}
|
|
31
|
+
// If parse fails or another read error occurs, ignore the file.
|
|
22
32
|
return { status: 'invalid', config: {} };
|
|
23
33
|
}
|
|
24
34
|
}
|
|
@@ -26,31 +36,123 @@ async function writeConfigFile(configPath, config) {
|
|
|
26
36
|
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
27
37
|
await fs.writeFile(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
28
38
|
}
|
|
39
|
+
function hasMissingTelemetryFields(config) {
|
|
40
|
+
const telemetry = config.telemetry;
|
|
41
|
+
return (!telemetry ||
|
|
42
|
+
telemetry.noticeSeen === undefined);
|
|
43
|
+
}
|
|
44
|
+
function mergeLegacyTelemetry(config, legacyConfig) {
|
|
45
|
+
const legacyTelemetry = legacyConfig.telemetry;
|
|
46
|
+
if (!legacyTelemetry) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const currentTelemetry = config.telemetry ?? {};
|
|
50
|
+
const shouldMigrate = (currentTelemetry.noticeSeen === undefined && legacyTelemetry.noticeSeen !== undefined);
|
|
51
|
+
if (!shouldMigrate) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
...config,
|
|
56
|
+
telemetry: {
|
|
57
|
+
...legacyTelemetry,
|
|
58
|
+
...currentTelemetry,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async function migrateLegacyTelemetryConfig(configPath, config, persist) {
|
|
63
|
+
const legacyConfigPath = getLegacyConfigPath();
|
|
64
|
+
if (path.resolve(configPath) === path.resolve(legacyConfigPath) || !hasMissingTelemetryFields(config)) {
|
|
65
|
+
return config;
|
|
66
|
+
}
|
|
67
|
+
const legacyRead = await readConfigFile(legacyConfigPath);
|
|
68
|
+
if (legacyRead.status !== 'ok') {
|
|
69
|
+
return config;
|
|
70
|
+
}
|
|
71
|
+
const migrated = mergeLegacyTelemetry(config, legacyRead.config);
|
|
72
|
+
if (!migrated) {
|
|
73
|
+
return config;
|
|
74
|
+
}
|
|
75
|
+
if (persist) {
|
|
76
|
+
try {
|
|
77
|
+
await writeConfigFile(configPath, migrated);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Preserve telemetry for this run even if the one-time migration cannot be persisted.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return migrated;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get the path to the global config file.
|
|
87
|
+
* Follows XDG Base Directory Specification and platform conventions.
|
|
88
|
+
*
|
|
89
|
+
* - All platforms: $XDG_CONFIG_HOME/openspec/ if XDG_CONFIG_HOME is set
|
|
90
|
+
* - Unix/macOS fallback: ~/.config/openspec/
|
|
91
|
+
* - Windows fallback: %APPDATA%/openspec/
|
|
92
|
+
*/
|
|
29
93
|
export function getConfigPath() {
|
|
30
|
-
|
|
94
|
+
const configDir = getConfigDir();
|
|
95
|
+
return path.join(configDir, CONFIG_FILE_NAME);
|
|
31
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the path to the identity file.
|
|
99
|
+
* Follows platform-specific config directory conventions.
|
|
100
|
+
*
|
|
101
|
+
* - All platforms: $XDG_CONFIG_HOME/openspec/ if XDG_CONFIG_HOME is set
|
|
102
|
+
* - Unix/macOS fallback: ~/.config/openspec/
|
|
103
|
+
* - Windows fallback: %APPDATA%/openspec/
|
|
104
|
+
*/
|
|
105
|
+
export function getIdentityFilePath() {
|
|
106
|
+
const configDir = getConfigDir();
|
|
107
|
+
return path.join(configDir, IDENTITY_FILE_NAME);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Read the global config file.
|
|
111
|
+
* Returns an empty object if the file doesn't exist.
|
|
112
|
+
*/
|
|
32
113
|
export async function readConfig() {
|
|
33
114
|
const configPath = getConfigPath();
|
|
34
115
|
const read = await readConfigFile(configPath);
|
|
35
|
-
|
|
116
|
+
const config = read.status === 'ok' ? read.config : {};
|
|
117
|
+
return migrateLegacyTelemetryConfig(configPath, config, read.status !== 'invalid');
|
|
36
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Write to the global config file.
|
|
121
|
+
* Preserves existing fields and merges in new values.
|
|
122
|
+
*/
|
|
37
123
|
export async function writeConfig(updates) {
|
|
38
124
|
const configPath = getConfigPath();
|
|
125
|
+
// Read existing config and merge
|
|
39
126
|
const existing = await readConfig();
|
|
40
127
|
const merged = { ...existing, ...updates };
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
...updates.telemetry,
|
|
45
|
-
};
|
|
128
|
+
// Deep merge for telemetry object
|
|
129
|
+
if (updates.telemetry && existing.telemetry) {
|
|
130
|
+
merged.telemetry = { ...existing.telemetry, ...updates.telemetry };
|
|
46
131
|
}
|
|
47
132
|
await writeConfigFile(configPath, merged);
|
|
48
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Get the telemetry config section.
|
|
136
|
+
*/
|
|
49
137
|
export async function getTelemetryConfig() {
|
|
50
138
|
const config = await readConfig();
|
|
51
|
-
|
|
52
|
-
return telemetry && typeof telemetry === 'object' ? telemetry : {};
|
|
139
|
+
return config.telemetry ?? {};
|
|
53
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Get the PostHog API key from environment variable or default.
|
|
143
|
+
*/
|
|
144
|
+
export function getPostHogApiKey() {
|
|
145
|
+
return process.env.POSTHOG_API_KEY || DEFAULT_POSTHOG_API_KEY;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get the PostHog host from environment variable or default.
|
|
149
|
+
*/
|
|
150
|
+
export function getPostHogHost() {
|
|
151
|
+
return process.env.POSTHOG_HOST || DEFAULT_POSTHOG_HOST;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Update the telemetry config section.
|
|
155
|
+
*/
|
|
54
156
|
export async function updateTelemetryConfig(updates) {
|
|
55
157
|
const existing = await getTelemetryConfig();
|
|
56
158
|
await writeConfig({
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event deduplication module for telemetry.
|
|
3
|
+
*
|
|
4
|
+
* Prevents duplicate event emission through:
|
|
5
|
+
* - Time-based throttling for $identify calls (24h window)
|
|
6
|
+
* - State-based deduplication for gate events
|
|
7
|
+
* - Rapid duplicate prevention for general events
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Check if an $identify call should be throttled for a given user.
|
|
11
|
+
*
|
|
12
|
+
* @param userId - The anonymous user ID
|
|
13
|
+
* @returns True if the call should be throttled (not sent), false otherwise
|
|
14
|
+
*/
|
|
15
|
+
export declare function shouldThrottleIdentify(userId: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Check if a gate event should be deduplicated based on state comparison.
|
|
18
|
+
*
|
|
19
|
+
* @param eventKey - Unique key for the gate event (e.g., "comprehension_gate_checked:change-name")
|
|
20
|
+
* @param currentState - The current state of the gate
|
|
21
|
+
* @returns True if the event should be deduplicated (not sent), false otherwise
|
|
22
|
+
*/
|
|
23
|
+
export declare function shouldDeduplicateGateEvent(eventKey: string, currentState: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Check if a general event should be deduplicated due to rapid succession.
|
|
26
|
+
*
|
|
27
|
+
* @param eventKey - Unique key for the event (e.g., "command_executed:init")
|
|
28
|
+
* @returns True if the event should be deduplicated (not sent), false otherwise
|
|
29
|
+
*/
|
|
30
|
+
export declare function shouldDeduplicateRapidEvent(eventKey: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Clear deduplication state (useful for testing or session reset).
|
|
33
|
+
*/
|
|
34
|
+
export declare function clearDeduplicationState(): void;
|
|
35
|
+
//# sourceMappingURL=deduplication.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event deduplication module for telemetry.
|
|
3
|
+
*
|
|
4
|
+
* Prevents duplicate event emission through:
|
|
5
|
+
* - Time-based throttling for $identify calls (24h window)
|
|
6
|
+
* - State-based deduplication for gate events
|
|
7
|
+
* - Rapid duplicate prevention for general events
|
|
8
|
+
*/
|
|
9
|
+
// In-memory state for session-level deduplication
|
|
10
|
+
const identifyThrottleState = new Map();
|
|
11
|
+
const gateEventState = new Map();
|
|
12
|
+
const recentEvents = new Map();
|
|
13
|
+
const IDENTIFY_THROTTLE_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
14
|
+
const RAPID_DUPLICATE_WINDOW_MS = 1000; // 1 second
|
|
15
|
+
/**
|
|
16
|
+
* Check if an $identify call should be throttled for a given user.
|
|
17
|
+
*
|
|
18
|
+
* @param userId - The anonymous user ID
|
|
19
|
+
* @returns True if the call should be throttled (not sent), false otherwise
|
|
20
|
+
*/
|
|
21
|
+
export function shouldThrottleIdentify(userId) {
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
const lastIdentify = identifyThrottleState.get(userId);
|
|
24
|
+
if (lastIdentify === undefined) {
|
|
25
|
+
identifyThrottleState.set(userId, now);
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const timeSinceLastIdentify = now - lastIdentify;
|
|
29
|
+
if (timeSinceLastIdentify < IDENTIFY_THROTTLE_MS) {
|
|
30
|
+
return true; // Throttle
|
|
31
|
+
}
|
|
32
|
+
identifyThrottleState.set(userId, now);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if a gate event should be deduplicated based on state comparison.
|
|
37
|
+
*
|
|
38
|
+
* @param eventKey - Unique key for the gate event (e.g., "comprehension_gate_checked:change-name")
|
|
39
|
+
* @param currentState - The current state of the gate
|
|
40
|
+
* @returns True if the event should be deduplicated (not sent), false otherwise
|
|
41
|
+
*/
|
|
42
|
+
export function shouldDeduplicateGateEvent(eventKey, currentState) {
|
|
43
|
+
const previousState = gateEventState.get(eventKey);
|
|
44
|
+
if (previousState === undefined) {
|
|
45
|
+
gateEventState.set(eventKey, currentState);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (previousState === currentState) {
|
|
49
|
+
return true; // Deduplicate - state unchanged
|
|
50
|
+
}
|
|
51
|
+
gateEventState.set(eventKey, currentState);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if a general event should be deduplicated due to rapid succession.
|
|
56
|
+
*
|
|
57
|
+
* @param eventKey - Unique key for the event (e.g., "command_executed:init")
|
|
58
|
+
* @returns True if the event should be deduplicated (not sent), false otherwise
|
|
59
|
+
*/
|
|
60
|
+
export function shouldDeduplicateRapidEvent(eventKey) {
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
const lastEventTime = recentEvents.get(eventKey);
|
|
63
|
+
if (lastEventTime === undefined) {
|
|
64
|
+
recentEvents.set(eventKey, now);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const timeSinceLastEvent = now - lastEventTime;
|
|
68
|
+
if (timeSinceLastEvent < RAPID_DUPLICATE_WINDOW_MS) {
|
|
69
|
+
return true; // Deduplicate - too rapid
|
|
70
|
+
}
|
|
71
|
+
recentEvents.set(eventKey, now);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Clear deduplication state (useful for testing or session reset).
|
|
76
|
+
*/
|
|
77
|
+
export function clearDeduplicationState() {
|
|
78
|
+
identifyThrottleState.clear();
|
|
79
|
+
gateEventState.clear();
|
|
80
|
+
recentEvents.clear();
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=deduplication.js.map
|
|
@@ -1,23 +1,63 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export declare function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
export declare const IDENTITY_FILE_NAME = "telemetry-identity.json";
|
|
2
|
+
/**
|
|
3
|
+
* Get the path to the identity file.
|
|
4
|
+
* Follows platform-specific config directory conventions.
|
|
5
|
+
*
|
|
6
|
+
* - All platforms: $XDG_CONFIG_HOME/openspec/ if XDG_CONFIG_HOME is set
|
|
7
|
+
* - Unix/macOS fallback: ~/.config/openspec/
|
|
8
|
+
* - Windows fallback: %APPDATA%/openspec/
|
|
9
|
+
*/
|
|
10
|
+
export declare function getIdentityPath(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Read identity from file or environment variable.
|
|
13
|
+
* Environment variable takes precedence over file.
|
|
14
|
+
*
|
|
15
|
+
* @returns The identity string, or null if not configured
|
|
16
|
+
*/
|
|
17
|
+
export declare function readIdentity(): Promise<string | null>;
|
|
18
|
+
/**
|
|
19
|
+
* Write identity to file with restricted permissions.
|
|
20
|
+
*
|
|
21
|
+
* @param identity - The identity string to write
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeIdentity(identity: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Validate email format using RFC 5322 compliant pattern.
|
|
26
|
+
*
|
|
27
|
+
* @param email - The email string to validate
|
|
28
|
+
* @returns True if valid, false otherwise
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateEmail(email: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Validate username format.
|
|
33
|
+
* Username must be 3-32 characters, alphanumeric + underscores + hyphens.
|
|
34
|
+
*
|
|
35
|
+
* @param username - The username string to validate
|
|
36
|
+
* @returns True if valid, false otherwise
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateUsername(username: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Normalize identity input by trimming whitespace and converting to lowercase.
|
|
41
|
+
*
|
|
42
|
+
* @param identity - The identity string to normalize
|
|
43
|
+
* @returns The normalized identity string
|
|
44
|
+
*/
|
|
45
|
+
export declare function normalizeIdentity(identity: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Validate identity format (email or username).
|
|
48
|
+
*
|
|
49
|
+
* @param identity - The identity string to validate
|
|
50
|
+
* @returns Object with valid flag and error messages if invalid
|
|
51
|
+
*/
|
|
52
|
+
export declare function validateIdentity(identity: string): {
|
|
53
|
+
valid: boolean;
|
|
54
|
+
errors: string[];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Interactive prompt for identity collection.
|
|
58
|
+
* Uses inquirer for consistent prompting with other OpenSpec commands.
|
|
59
|
+
*
|
|
60
|
+
* @returns The user's identity input
|
|
61
|
+
*/
|
|
62
|
+
export declare function promptForIdentity(): Promise<string>;
|
|
23
63
|
//# sourceMappingURL=identity.d.ts.map
|