@niujiajie/freespec 0.0.0-stage → 1.15.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/LICENSE +22 -0
- package/README.md +58 -2
- package/bin/freespec.js +5 -0
- package/dist/cli/index.d.ts +25 -0
- package/dist/cli/index.js +359 -0
- package/dist/commands/shared-output.d.ts +18 -0
- package/dist/commands/shared-output.js +61 -0
- package/dist/commands/workflow/default-schema.d.ts +2 -0
- package/dist/commands/workflow/default-schema.js +4 -0
- package/dist/commands/workflow/index.d.ts +13 -0
- package/dist/commands/workflow/index.js +10 -0
- package/dist/commands/workflow/instructions.d.ts +39 -0
- package/dist/commands/workflow/instructions.js +565 -0
- package/dist/commands/workflow/new-change.d.ts +19 -0
- package/dist/commands/workflow/new-change.js +135 -0
- package/dist/commands/workflow/shared.d.ts +94 -0
- package/dist/commands/workflow/shared.js +169 -0
- package/dist/commands/workflow/status.d.ts +18 -0
- package/dist/commands/workflow/status.js +201 -0
- package/dist/core/artifact-graph/graph.d.ts +72 -0
- package/dist/core/artifact-graph/graph.js +165 -0
- package/dist/core/artifact-graph/index.d.ts +9 -0
- package/dist/core/artifact-graph/index.js +14 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +208 -0
- package/dist/core/artifact-graph/instruction-loader.js +268 -0
- package/dist/core/artifact-graph/outputs.d.ts +19 -0
- package/dist/core/artifact-graph/outputs.js +351 -0
- package/dist/core/artifact-graph/resolver.d.ts +89 -0
- package/dist/core/artifact-graph/resolver.js +342 -0
- package/dist/core/artifact-graph/schema.d.ts +27 -0
- package/dist/core/artifact-graph/schema.js +160 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.js +31 -0
- package/dist/core/artifact-graph/types.d.ts +40 -0
- package/dist/core/artifact-graph/types.js +59 -0
- package/dist/core/available-tools.d.ts +18 -0
- package/dist/core/available-tools.js +49 -0
- package/dist/core/change-layout.d.ts +17 -0
- package/dist/core/change-layout.js +30 -0
- package/dist/core/change-metadata/index.d.ts +2 -0
- package/dist/core/change-metadata/index.js +2 -0
- package/dist/core/change-metadata/schema.d.ts +23 -0
- package/dist/core/change-metadata/schema.js +46 -0
- package/dist/core/change-status-policy.d.ts +49 -0
- package/dist/core/change-status-policy.js +50 -0
- package/dist/core/command-generation/adapters/amazon-q.d.ts +17 -0
- package/dist/core/command-generation/adapters/amazon-q.js +32 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +27 -0
- package/dist/core/command-generation/adapters/atomcode.d.ts +24 -0
- package/dist/core/command-generation/adapters/atomcode.js +46 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +28 -0
- package/dist/core/command-generation/adapters/bob.d.ts +18 -0
- package/dist/core/command-generation/adapters/bob.js +33 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +32 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codeassistant.d.ts +15 -0
- package/dist/core/command-generation/adapters/codeassistant.js +29 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +29 -0
- package/dist/core/command-generation/adapters/codestudio.d.ts +13 -0
- package/dist/core/command-generation/adapters/codestudio.js +27 -0
- package/dist/core/command-generation/adapters/command-code.d.ts +19 -0
- package/dist/core/command-generation/adapters/command-code.js +34 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +33 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +28 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +31 -0
- 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/easycode.d.ts +17 -0
- package/dist/core/command-generation/adapters/easycode.js +28 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +28 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +27 -0
- package/dist/core/command-generation/adapters/gigacode.d.ts +17 -0
- package/dist/core/command-generation/adapters/gigacode.js +31 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +27 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +30 -0
- package/dist/core/command-generation/adapters/index.d.ts +40 -0
- package/dist/core/command-generation/adapters/index.js +40 -0
- package/dist/core/command-generation/adapters/junie.d.ts +13 -0
- package/dist/core/command-generation/adapters/junie.js +27 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
- package/dist/core/command-generation/adapters/kiro.js +27 -0
- package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
- package/dist/core/command-generation/adapters/lingma.js +30 -0
- 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.d.ts +14 -0
- package/dist/core/command-generation/adapters/opencode.js +38 -0
- package/dist/core/command-generation/adapters/pi.d.ts +18 -0
- package/dist/core/command-generation/adapters/pi.js +39 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +17 -0
- package/dist/core/command-generation/adapters/qwen.js +31 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- 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 +29 -0
- package/dist/core/command-generation/generator.js +43 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- 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.d.ts +36 -0
- package/dist/core/command-generation/registry.js +114 -0
- package/dist/core/command-generation/toml.d.ts +19 -0
- package/dist/core/command-generation/toml.js +39 -0
- package/dist/core/command-generation/types.d.ts +63 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/command-generation/yaml.d.ts +36 -0
- package/dist/core/command-generation/yaml.js +48 -0
- package/dist/core/command-surface.d.ts +15 -0
- package/dist/core/command-surface.js +33 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +56 -0
- package/dist/core/config-schema.d.ts +98 -0
- package/dist/core/config-schema.js +308 -0
- package/dist/core/config.d.ts +50 -0
- package/dist/core/config.js +122 -0
- package/dist/core/file-state.d.ts +36 -0
- package/dist/core/file-state.js +144 -0
- package/dist/core/file-view.d.ts +13 -0
- package/dist/core/file-view.js +14 -0
- package/dist/core/global-config.d.ts +101 -0
- package/dist/core/global-config.js +182 -0
- package/dist/core/id.d.ts +17 -0
- package/dist/core/id.js +30 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +7 -0
- package/dist/core/init.d.ts +57 -0
- package/dist/core/init.js +836 -0
- package/dist/core/list.d.ts +11 -0
- package/dist/core/list.js +197 -0
- package/dist/core/migration.d.ts +121 -0
- package/dist/core/migration.js +540 -0
- package/dist/core/onboarding-commands.d.ts +30 -0
- package/dist/core/onboarding-commands.js +38 -0
- package/dist/core/openspec-root.d.ts +47 -0
- package/dist/core/openspec-root.js +196 -0
- package/dist/core/planning-home.d.ts +16 -0
- package/dist/core/planning-home.js +67 -0
- package/dist/core/profile-sync-drift.d.ts +31 -0
- package/dist/core/profile-sync-drift.js +201 -0
- package/dist/core/profiles.d.ts +19 -0
- package/dist/core/profiles.js +33 -0
- package/dist/core/project-config.d.ts +132 -0
- package/dist/core/project-config.js +519 -0
- package/dist/core/references.d.ts +10 -0
- package/dist/core/references.js +46 -0
- package/dist/core/root-selection.d.ts +59 -0
- package/dist/core/root-selection.js +132 -0
- package/dist/core/shared/allowed-tools.d.ts +12 -0
- package/dist/core/shared/allowed-tools.js +12 -0
- package/dist/core/shared/ide-restart.d.ts +26 -0
- package/dist/core/shared/ide-restart.js +42 -0
- package/dist/core/shared/index.d.ts +11 -0
- package/dist/core/shared/index.js +11 -0
- package/dist/core/shared/skill-content-equivalence.d.ts +7 -0
- package/dist/core/shared/skill-content-equivalence.js +45 -0
- package/dist/core/shared/skill-files.d.ts +7 -0
- package/dist/core/shared/skill-files.js +43 -0
- package/dist/core/shared/skill-generation.d.ts +49 -0
- package/dist/core/shared/skill-generation.js +125 -0
- 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 +99 -0
- package/dist/core/shared/tool-detection.js +318 -0
- package/dist/core/shared-skill-target.d.ts +51 -0
- package/dist/core/shared-skill-target.js +239 -0
- package/dist/core/store/errors.d.ts +20 -0
- package/dist/core/store/errors.js +22 -0
- package/dist/core/store/index.d.ts +2 -0
- package/dist/core/store/index.js +2 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/optional-workflow.d.ts +69 -0
- package/dist/core/templates/optional-workflow.js +140 -0
- package/dist/core/templates/types.d.ts +19 -0
- package/dist/core/templates/types.js +5 -0
- package/dist/core/templates/workflows/personal.d.ts +22 -0
- package/dist/core/templates/workflows/personal.js +225 -0
- package/dist/core/update-plan.d.ts +127 -0
- package/dist/core/update-plan.js +390 -0
- package/dist/core/update.d.ts +154 -0
- package/dist/core/update.js +723 -0
- package/dist/core/version-check.d.ts +188 -0
- package/dist/core/version-check.js +906 -0
- package/dist/core/zod-issues.d.ts +4 -0
- package/dist/core/zod-issues.js +10 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +35 -0
- package/dist/prompts/searchable-multi-select.js +188 -0
- package/dist/telemetry/config.d.ts +37 -0
- package/dist/telemetry/config.js +148 -0
- package/dist/telemetry/index.d.ts +39 -0
- package/dist/telemetry/index.js +217 -0
- package/dist/telemetry/opt-out.d.ts +17 -0
- package/dist/telemetry/opt-out.js +27 -0
- package/dist/ui/ascii-patterns.d.ts +16 -0
- package/dist/ui/ascii-patterns.js +133 -0
- package/dist/ui/welcome-screen.d.ts +18 -0
- package/dist/ui/welcome-screen.js +199 -0
- package/dist/utils/change-metadata.d.ts +116 -0
- package/dist/utils/change-metadata.js +324 -0
- package/dist/utils/change-utils.d.ts +79 -0
- package/dist/utils/change-utils.js +121 -0
- package/dist/utils/ci.d.ts +12 -0
- package/dist/utils/ci.js +16 -0
- package/dist/utils/command-references.d.ts +104 -0
- package/dist/utils/command-references.js +190 -0
- package/dist/utils/date.d.ts +8 -0
- package/dist/utils/date.js +13 -0
- package/dist/utils/executable-path.d.ts +5 -0
- package/dist/utils/executable-path.js +44 -0
- package/dist/utils/file-system.d.ts +58 -0
- package/dist/utils/file-system.js +432 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/interactive.d.ts +85 -0
- package/dist/utils/interactive.js +174 -0
- package/dist/utils/item-discovery.d.ts +15 -0
- package/dist/utils/item-discovery.js +33 -0
- package/dist/utils/line-endings.d.ts +34 -0
- package/dist/utils/line-endings.js +46 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/nested-change.d.ts +35 -0
- package/dist/utils/nested-change.js +185 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +94 -0
- package/dist/utils/task-progress.d.ts +67 -0
- package/dist/utils/task-progress.js +184 -0
- package/package.json +74 -4
- package/schemas//351/273/230/350/256/244/schema.yaml +68 -0
- package/schemas//351/273/230/350/256/244/templates//344/273/273/345/212/241/346/270/205/345/215/225.md +25 -0
- package/schemas//351/273/230/350/256/244/templates//346/265/213/350/257/225/347/224/250/344/276/213.md +34 -0
- package/schemas//351/273/230/350/256/244/templates//350/256/276/350/256/241/346/226/207/346/241/243.md +172 -0
- package/schemas//351/273/230/350/256/244/templates//351/234/200/346/261/202/346/226/207/346/241/243.md +19 -0
- package/skill-files//344/273/273/345/212/241/references//346/212/244/346/240/217.md +43 -0
- package/skill-files//344/273/273/345/212/241/references//347/262/222/345/272/246.md +23 -0
- package/skill-files//344/273/273/345/212/241/references//347/272/246/346/235/237.md +8 -0
- package/skill-files//344/273/273/345/212/241/scripts/check-tasks.mjs +83 -0
- package/skill-files//345/206/231Java/references/Java/350/247/204/350/214/203.md +25 -0
- package/skill-files//345/206/231Java/references//345/215/261/351/231/251/345/206/231/346/263/225.md +27 -0
- package/skill-files//345/206/231Java/references//345/256/214/346/210/220/345/257/271/347/205/247.md +15 -0
- package/skill-files//345/206/231Java/references//346/212/244/346/240/217.md +35 -0
- package/skill-files//345/206/231Java/references//347/272/246/346/235/237.md +8 -0
- package/skill-files//345/206/231Java/references//350/270/251/345/235/221.md +17 -0
- package/skill-files//345/256/241Java/references//346/212/244/346/240/217.md +19 -0
- package/skill-files//345/256/241Java/references//347/244/272/344/276/213.md +23 -0
- package/skill-files//345/256/241Java/references//347/272/246/346/235/237.md +7 -0
- package/skill-files//345/256/241Java/references//350/247/204/345/210/231.md +23 -0
- package/skill-files//345/256/241Java/references//351/242/206/345/237/237/346/243/200/351/241/271.md +58 -0
- package/skill-files//345/256/241/346/226/207/346/241/243/references//346/212/244/346/240/217.md +18 -0
- package/skill-files//345/256/241/346/226/207/346/241/243/references//347/272/246/346/235/237.md +8 -0
- package/skill-files//345/256/241/346/226/207/346/241/243/references//347/273/264/345/272/246.md +17 -0
- package/skill-files//345/256/241/346/226/207/346/241/243/references//350/270/251/345/235/221.md +11 -0
- package/skill-files//346/226/260/345/273/272/references//344/272/244/346/216/245.md +11 -0
- package/skill-files//346/226/260/345/273/272/references//346/212/244/346/240/217.md +14 -0
- package/skill-files//346/226/260/345/273/272/references//347/272/246/346/235/237.md +7 -0
- package/skill-files//346/267/261/346/200/235/config/prompts.yaml +114 -0
- package/skill-files//346/267/261/346/200/235/references//344/270/211/346/226/271/346/240/270/345/257/271.md +72 -0
- package/skill-files//346/267/261/346/200/235/references//344/276/213/345/255/220.md +39 -0
- package/skill-files//346/267/261/346/200/235/references//346/200/216/344/271/210/346/203/263.md +61 -0
- package/skill-files//346/267/261/346/200/235/references//346/212/244/346/240/217.md +26 -0
- package/skill-files//346/267/261/346/200/235/references//347/202/271/351/200/211/346/217/220/351/227/256.md +66 -0
- package/skill-files//346/267/261/346/200/235/references//347/231/273/350/256/260.md +45 -0
- package/skill-files//346/267/261/346/200/235/references//347/272/246/346/235/237.md +9 -0
- package/skill-files//347/224/250/344/276/213/references//346/200/216/344/271/210/345/206/231.md +13 -0
- package/skill-files//347/224/250/344/276/213/references//346/212/244/346/240/217.md +42 -0
- package/skill-files//347/224/250/344/276/213/references//347/272/246/346/235/237.md +5 -0
- package/skill-files//347/224/250/344/276/213/scripts/check-cases.mjs +70 -0
- package/skill-files//350/256/276/350/256/241/references//345/207/206/345/244/207.md +25 -0
- package/skill-files//350/256/276/350/256/241/references//346/212/244/346/240/217.md +134 -0
- package/skill-files//350/256/276/350/256/241/references//346/226/207/351/243/216.md +17 -0
- package/skill-files//350/256/276/350/256/241/references//347/225/214/351/235/242.md +18 -0
- package/skill-files//350/256/276/350/256/241/references//347/261/273/345/236/213.md +19 -0
- package/skill-files//350/256/276/350/256/241/references//347/272/246/346/235/237.md +25 -0
- package/skill-files//350/256/276/350/256/241/scripts/_smoke.mjs +72 -0
- package/skill-files//350/256/276/350/256/241/scripts/check-design.mjs +331 -0
- package/skill-files//351/234/200/346/261/202/references//346/212/244/346/240/217.md +26 -0
- package/skill-files//351/234/200/346/261/202/references//346/226/207/351/243/216.md +23 -0
- package/skill-files//351/234/200/346/261/202/references//346/267/261/346/200/235/346/221/204/345/205/245.md +21 -0
- package/skill-files//351/234/200/346/261/202/references//347/272/246/346/235/237.md +8 -0
- package/skill-files//351/234/200/346/261/202/references//351/234/200/346/261/202/345/276/205/345/256/232.md +13 -0
- package/skill-files//351/234/200/346/261/202/scripts/check-requirements.mjs +60 -0
- package/skill-files//351/252/214/346/224/266/references//346/212/244/346/240/217.md +27 -0
- package/skill-files//351/252/214/346/224/266/references//346/240/270/345/257/271.md +17 -0
- package/skill-files//351/252/214/346/224/266/references//347/272/246/346/235/237.md +7 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** One rendering for zod issues across every state/config parser. */
|
|
2
|
+
export function formatZodIssues(error, fallbackLocation = 'root') {
|
|
3
|
+
return error.issues
|
|
4
|
+
.map((issue) => {
|
|
5
|
+
const location = issue.path.length > 0 ? issue.path.join('.') : fallbackLocation;
|
|
6
|
+
return `${location}: ${issue.message}`;
|
|
7
|
+
})
|
|
8
|
+
.join('; ');
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=zod-issues.js.map
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
interface Choice {
|
|
2
|
+
name: string;
|
|
3
|
+
value: string;
|
|
4
|
+
/**
|
|
5
|
+
* Extra terms the search box matches, for choices users look for by a word
|
|
6
|
+
* the name does not spell (see #653). Never rendered.
|
|
7
|
+
*/
|
|
8
|
+
searchAliases?: string[];
|
|
9
|
+
description?: string;
|
|
10
|
+
configured?: boolean;
|
|
11
|
+
detected?: boolean;
|
|
12
|
+
configuredLabel?: string;
|
|
13
|
+
preSelected?: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface Config {
|
|
16
|
+
message: string;
|
|
17
|
+
choices: Choice[];
|
|
18
|
+
pageSize?: number;
|
|
19
|
+
validate?: (selected: string[]) => boolean | string;
|
|
20
|
+
/** Shown when a search matches nothing, so the list is not a dead end. */
|
|
21
|
+
emptyHint?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A searchable multi-select prompt with visible search box,
|
|
25
|
+
* selected items display, and intuitive keyboard navigation.
|
|
26
|
+
*
|
|
27
|
+
* - Type to filter choices
|
|
28
|
+
* - ↑↓ to navigate
|
|
29
|
+
* - Space to toggle highlighted item selection
|
|
30
|
+
* - Backspace to remove last selected item (or delete search char)
|
|
31
|
+
* - Enter to confirm selections
|
|
32
|
+
*/
|
|
33
|
+
export declare function searchableMultiSelect(config: Config): Promise<string[]>;
|
|
34
|
+
export default searchableMultiSelect;
|
|
35
|
+
//# sourceMappingURL=searchable-multi-select.d.ts.map
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
/**
|
|
3
|
+
* True when every character is printable, so the text can go in the search box.
|
|
4
|
+
* `\u007f` is DEL, which sorts above the printable range.
|
|
5
|
+
*/
|
|
6
|
+
function isPrintable(text) {
|
|
7
|
+
return text.length > 0 && [...text].every((char) => char >= ' ' && char !== '\u007f');
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create the searchable multi-select prompt.
|
|
11
|
+
* Uses dynamic import to prevent pre-commit hook hangs (see #367).
|
|
12
|
+
*/
|
|
13
|
+
async function createSearchableMultiSelect() {
|
|
14
|
+
const { createPrompt, useState, useKeypress, useMemo, usePrefix, isEnterKey, isBackspaceKey, isUpKey, isDownKey, } = await import('@inquirer/core');
|
|
15
|
+
return createPrompt((config, done) => {
|
|
16
|
+
const { message, choices, pageSize = 15, validate, emptyHint } = config;
|
|
17
|
+
const [searchText, setSearchText] = useState('');
|
|
18
|
+
const [selectedValues, setSelectedValues] = useState(() => choices.filter(c => c.preSelected).map(c => c.value));
|
|
19
|
+
const [cursor, setCursor] = useState(0);
|
|
20
|
+
const [status, setStatus] = useState('idle');
|
|
21
|
+
const [error, setError] = useState(null);
|
|
22
|
+
const prefix = usePrefix({ status });
|
|
23
|
+
// Filter choices by search
|
|
24
|
+
const filteredChoices = useMemo(() => {
|
|
25
|
+
if (!searchText.trim())
|
|
26
|
+
return choices;
|
|
27
|
+
const term = searchText.trim().toLowerCase();
|
|
28
|
+
return choices.filter((c) => c.name.toLowerCase().includes(term) ||
|
|
29
|
+
c.value.toLowerCase().includes(term) ||
|
|
30
|
+
(c.searchAliases ?? []).some((alias) => alias.toLowerCase().includes(term)));
|
|
31
|
+
}, [searchText, choices]);
|
|
32
|
+
const selectedSet = useMemo(() => new Set(selectedValues), [selectedValues]);
|
|
33
|
+
const choiceMap = useMemo(() => new Map(choices.map((c) => [c.value, c])), [choices]);
|
|
34
|
+
useKeypress((key) => {
|
|
35
|
+
if (status === 'done')
|
|
36
|
+
return;
|
|
37
|
+
// Enter to confirm/submit
|
|
38
|
+
if (isEnterKey(key)) {
|
|
39
|
+
if (validate) {
|
|
40
|
+
const result = validate(selectedValues);
|
|
41
|
+
if (result !== true) {
|
|
42
|
+
setError(typeof result === 'string' ? result : 'Invalid');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
setStatus('done');
|
|
47
|
+
done(selectedValues);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Space to toggle selection
|
|
51
|
+
if (key.name === 'space') {
|
|
52
|
+
const choice = filteredChoices[cursor];
|
|
53
|
+
if (choice) {
|
|
54
|
+
if (selectedSet.has(choice.value)) {
|
|
55
|
+
setSelectedValues(selectedValues.filter(v => v !== choice.value));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
setSelectedValues([...selectedValues, choice.value]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Backspace to remove or delete search char
|
|
64
|
+
if (isBackspaceKey(key)) {
|
|
65
|
+
if (searchText === '' && selectedValues.length > 0) {
|
|
66
|
+
setSelectedValues(selectedValues.slice(0, -1));
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
setSearchText(searchText.slice(0, -1));
|
|
70
|
+
setCursor(0);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Navigation
|
|
75
|
+
if (isUpKey(key)) {
|
|
76
|
+
setCursor(Math.max(0, cursor - 1));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (isDownKey(key)) {
|
|
80
|
+
setCursor(Math.min(filteredChoices.length - 1, cursor + 1));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Character input - handle printable characters.
|
|
84
|
+
// readline reports punctuation (`.`, `-`, `/`) only in `sequence`, leaving
|
|
85
|
+
// `name` undefined, so keying off `name` alone silently dropped every
|
|
86
|
+
// non-alphanumeric character the user typed.
|
|
87
|
+
// `@inquirer/core` types only `name` and `ctrl`; readline emits more.
|
|
88
|
+
const event = key;
|
|
89
|
+
if (event.ctrl || event.meta)
|
|
90
|
+
return;
|
|
91
|
+
// Requiring every character to be printable drops escape sequences
|
|
92
|
+
// (arrows, function keys), tab, escape and delete. readline splits a
|
|
93
|
+
// paste into one key per character, so a pasted space still toggles.
|
|
94
|
+
const typed = typeof event.sequence === 'string' && isPrintable(event.sequence)
|
|
95
|
+
? event.sequence
|
|
96
|
+
: // Only the sequence may be multi-character: readline `name`s such as
|
|
97
|
+
// 'tab' and 'escape' are printable strings but not typed input.
|
|
98
|
+
typeof event.name === 'string' &&
|
|
99
|
+
event.name.length === 1 &&
|
|
100
|
+
isPrintable(event.name)
|
|
101
|
+
? event.name
|
|
102
|
+
: undefined;
|
|
103
|
+
if (typed) {
|
|
104
|
+
setSearchText(searchText + typed);
|
|
105
|
+
setCursor(0);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
// Render done state
|
|
109
|
+
if (status === 'done') {
|
|
110
|
+
const names = selectedValues
|
|
111
|
+
.map((v) => choiceMap.get(v)?.name ?? v)
|
|
112
|
+
.join(', ');
|
|
113
|
+
return `${prefix} ${chalk.bold(message)} ${chalk.cyan(names || '(none)')}`;
|
|
114
|
+
}
|
|
115
|
+
// Render active state
|
|
116
|
+
const lines = [];
|
|
117
|
+
lines.push(`${prefix} ${chalk.bold(message)}`);
|
|
118
|
+
// Selected chips
|
|
119
|
+
const chips = selectedValues.length > 0
|
|
120
|
+
? selectedValues
|
|
121
|
+
.map((v) => chalk.bgCyan.black(` ${choiceMap.get(v)?.name} `))
|
|
122
|
+
.join(' ')
|
|
123
|
+
: chalk.dim('(none selected)');
|
|
124
|
+
lines.push(` Selected: ${chips}`);
|
|
125
|
+
// Search box
|
|
126
|
+
lines.push(` Search: ${chalk.yellow('[')}${searchText || chalk.dim('type to filter')}${chalk.yellow(']')}`);
|
|
127
|
+
// Instructions
|
|
128
|
+
lines.push(` ${chalk.cyan('↑↓')} navigate • ${chalk.cyan('Space')} toggle • ${chalk.cyan('Backspace')} remove • ${chalk.cyan('Enter')} confirm`);
|
|
129
|
+
// List
|
|
130
|
+
if (filteredChoices.length === 0) {
|
|
131
|
+
lines.push(chalk.yellow(' No matches'));
|
|
132
|
+
if (emptyHint)
|
|
133
|
+
lines.push(chalk.dim(` ${emptyHint}`));
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Calculate pagination
|
|
137
|
+
const startIndex = Math.max(0, Math.min(cursor - Math.floor(pageSize / 2), filteredChoices.length - pageSize));
|
|
138
|
+
const endIndex = Math.min(startIndex + pageSize, filteredChoices.length);
|
|
139
|
+
const visibleChoices = filteredChoices.slice(startIndex, endIndex);
|
|
140
|
+
for (let i = 0; i < visibleChoices.length; i++) {
|
|
141
|
+
const item = visibleChoices[i];
|
|
142
|
+
const actualIndex = startIndex + i;
|
|
143
|
+
const isActive = actualIndex === cursor;
|
|
144
|
+
const selected = selectedSet.has(item.value);
|
|
145
|
+
const icon = selected ? chalk.green('[x]') : chalk.dim('[ ]');
|
|
146
|
+
const arrow = isActive ? chalk.cyan('›') : ' ';
|
|
147
|
+
const name = isActive ? chalk.cyan(item.name) : item.name;
|
|
148
|
+
const isRefresh = selected && item.configured;
|
|
149
|
+
const statusLabel = !selected
|
|
150
|
+
? item.configured
|
|
151
|
+
? ' (configured)'
|
|
152
|
+
: item.detected
|
|
153
|
+
? ' (detected)'
|
|
154
|
+
: ''
|
|
155
|
+
: '';
|
|
156
|
+
const suffix = selected
|
|
157
|
+
? chalk.dim(isRefresh ? ' (refresh)' : ' (selected)')
|
|
158
|
+
: chalk.dim(statusLabel);
|
|
159
|
+
lines.push(` ${arrow} ${icon} ${name}${suffix}`);
|
|
160
|
+
}
|
|
161
|
+
// Show pagination indicator if needed
|
|
162
|
+
if (filteredChoices.length > pageSize) {
|
|
163
|
+
const currentPage = Math.floor(cursor / pageSize) + 1;
|
|
164
|
+
const totalPages = Math.ceil(filteredChoices.length / pageSize);
|
|
165
|
+
lines.push(chalk.dim(` (${currentPage}/${totalPages})`));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (error)
|
|
169
|
+
lines.push(chalk.red(` ${error}`));
|
|
170
|
+
return lines.join('\n');
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* A searchable multi-select prompt with visible search box,
|
|
175
|
+
* selected items display, and intuitive keyboard navigation.
|
|
176
|
+
*
|
|
177
|
+
* - Type to filter choices
|
|
178
|
+
* - ↑↓ to navigate
|
|
179
|
+
* - Space to toggle highlighted item selection
|
|
180
|
+
* - Backspace to remove last selected item (or delete search char)
|
|
181
|
+
* - Enter to confirm selections
|
|
182
|
+
*/
|
|
183
|
+
export async function searchableMultiSelect(config) {
|
|
184
|
+
const prompt = await createSearchableMultiSelect();
|
|
185
|
+
return prompt(config);
|
|
186
|
+
}
|
|
187
|
+
export default searchableMultiSelect;
|
|
188
|
+
//# sourceMappingURL=searchable-multi-select.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type TelemetryConfig } from '../core/global-config.js';
|
|
2
|
+
export declare const CONFIG_DIR_NAME = "freespec";
|
|
3
|
+
export declare const CONFIG_FILE_NAME = "config.json";
|
|
4
|
+
/** Re-export shared telemetry section type (single source of truth in global-config). */
|
|
5
|
+
export type { TelemetryConfig };
|
|
6
|
+
export interface GlobalConfig {
|
|
7
|
+
telemetry?: TelemetryConfig;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get the path to the global config file.
|
|
12
|
+
* Follows XDG Base Directory Specification and platform conventions.
|
|
13
|
+
*
|
|
14
|
+
* - All platforms: $XDG_CONFIG_HOME/freespec/ if XDG_CONFIG_HOME is set
|
|
15
|
+
* - Unix/macOS fallback: ~/.config/freespec/
|
|
16
|
+
* - Windows fallback: %APPDATA%/freespec/
|
|
17
|
+
*/
|
|
18
|
+
export declare function getConfigPath(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Read the global config file.
|
|
21
|
+
* Returns an empty object if the file doesn't exist.
|
|
22
|
+
*/
|
|
23
|
+
export declare function readConfig(): Promise<GlobalConfig>;
|
|
24
|
+
/**
|
|
25
|
+
* Write to the global config file.
|
|
26
|
+
* Preserves existing fields and merges in new values.
|
|
27
|
+
*/
|
|
28
|
+
export declare function writeConfig(updates: Partial<GlobalConfig>): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Get the telemetry config section.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getTelemetryConfig(): Promise<TelemetryConfig>;
|
|
33
|
+
/**
|
|
34
|
+
* Update the telemetry config section.
|
|
35
|
+
*/
|
|
36
|
+
export declare function updateTelemetryConfig(updates: Partial<TelemetryConfig>): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global configuration for telemetry state.
|
|
3
|
+
* Stores anonymous ID and notice-seen flag in the platform-appropriate config directory.
|
|
4
|
+
*/
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
import { GLOBAL_CONFIG_DIR_NAME, GLOBAL_CONFIG_FILE_NAME, getGlobalConfigDir, isConfigRootObject, unreadableGlobalConfigMessage, } from '../core/global-config.js';
|
|
9
|
+
// Constants
|
|
10
|
+
export const CONFIG_DIR_NAME = GLOBAL_CONFIG_DIR_NAME;
|
|
11
|
+
export const CONFIG_FILE_NAME = GLOBAL_CONFIG_FILE_NAME;
|
|
12
|
+
function getConfigDir() {
|
|
13
|
+
return getGlobalConfigDir();
|
|
14
|
+
}
|
|
15
|
+
function getLegacyConfigPath() {
|
|
16
|
+
return path.join(os.homedir(), '.config', CONFIG_DIR_NAME, CONFIG_FILE_NAME);
|
|
17
|
+
}
|
|
18
|
+
async function readConfigFile(configPath) {
|
|
19
|
+
try {
|
|
20
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
21
|
+
const parsed = JSON.parse(content);
|
|
22
|
+
// Valid JSON that is not an object carries no settings to merge into, and
|
|
23
|
+
// spreading it would replace the file (a string even spreads to numeric
|
|
24
|
+
// character keys). Same predicate the rest of the CLI refuses to save over.
|
|
25
|
+
if (!isConfigRootObject(parsed)) {
|
|
26
|
+
return { status: 'invalid', config: {} };
|
|
27
|
+
}
|
|
28
|
+
return { status: 'ok', config: parsed };
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error.code === 'ENOENT') {
|
|
32
|
+
return { status: 'missing' };
|
|
33
|
+
}
|
|
34
|
+
// If parse fails or another read error occurs, ignore the file.
|
|
35
|
+
return { status: 'invalid', config: {} };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function writeConfigFile(configPath, config) {
|
|
39
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
40
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
41
|
+
}
|
|
42
|
+
function hasMissingTelemetryFields(config) {
|
|
43
|
+
const telemetry = config.telemetry;
|
|
44
|
+
return (!telemetry ||
|
|
45
|
+
telemetry.anonymousId === undefined ||
|
|
46
|
+
telemetry.noticeSeen === undefined);
|
|
47
|
+
}
|
|
48
|
+
function mergeLegacyTelemetry(config, legacyConfig) {
|
|
49
|
+
const legacyTelemetry = legacyConfig.telemetry;
|
|
50
|
+
if (!legacyTelemetry) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const currentTelemetry = config.telemetry ?? {};
|
|
54
|
+
const shouldMigrate = (currentTelemetry.anonymousId === undefined && legacyTelemetry.anonymousId !== undefined) ||
|
|
55
|
+
(currentTelemetry.noticeSeen === undefined && legacyTelemetry.noticeSeen !== undefined);
|
|
56
|
+
if (!shouldMigrate) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
...config,
|
|
61
|
+
telemetry: {
|
|
62
|
+
...legacyTelemetry,
|
|
63
|
+
...currentTelemetry,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function migrateLegacyTelemetryConfig(configPath, config, persist) {
|
|
68
|
+
const legacyConfigPath = getLegacyConfigPath();
|
|
69
|
+
if (path.resolve(configPath) === path.resolve(legacyConfigPath) || !hasMissingTelemetryFields(config)) {
|
|
70
|
+
return config;
|
|
71
|
+
}
|
|
72
|
+
const legacyRead = await readConfigFile(legacyConfigPath);
|
|
73
|
+
if (legacyRead.status !== 'ok') {
|
|
74
|
+
return config;
|
|
75
|
+
}
|
|
76
|
+
const migrated = mergeLegacyTelemetry(config, legacyRead.config);
|
|
77
|
+
if (!migrated) {
|
|
78
|
+
return config;
|
|
79
|
+
}
|
|
80
|
+
if (persist) {
|
|
81
|
+
try {
|
|
82
|
+
await writeConfigFile(configPath, migrated);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Preserve telemetry for this run even if the one-time migration cannot be persisted.
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return migrated;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get the path to the global config file.
|
|
92
|
+
* Follows XDG Base Directory Specification and platform conventions.
|
|
93
|
+
*
|
|
94
|
+
* - All platforms: $XDG_CONFIG_HOME/freespec/ if XDG_CONFIG_HOME is set
|
|
95
|
+
* - Unix/macOS fallback: ~/.config/freespec/
|
|
96
|
+
* - Windows fallback: %APPDATA%/freespec/
|
|
97
|
+
*/
|
|
98
|
+
export function getConfigPath() {
|
|
99
|
+
const configDir = getConfigDir();
|
|
100
|
+
return path.join(configDir, CONFIG_FILE_NAME);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Read the global config file.
|
|
104
|
+
* Returns an empty object if the file doesn't exist.
|
|
105
|
+
*/
|
|
106
|
+
export async function readConfig() {
|
|
107
|
+
const configPath = getConfigPath();
|
|
108
|
+
const read = await readConfigFile(configPath);
|
|
109
|
+
const config = read.status === 'ok' ? read.config : {};
|
|
110
|
+
return migrateLegacyTelemetryConfig(configPath, config, read.status !== 'invalid');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Write to the global config file.
|
|
114
|
+
* Preserves existing fields and merges in new values.
|
|
115
|
+
*/
|
|
116
|
+
export async function writeConfig(updates) {
|
|
117
|
+
const configPath = getConfigPath();
|
|
118
|
+
// Never write over a file that did not parse: the merge below would start
|
|
119
|
+
// from an empty object and replace every setting in it with these updates.
|
|
120
|
+
if ((await readConfigFile(configPath)).status === 'invalid') {
|
|
121
|
+
throw new Error(unreadableGlobalConfigMessage(configPath));
|
|
122
|
+
}
|
|
123
|
+
// Read existing config and merge
|
|
124
|
+
const existing = await readConfig();
|
|
125
|
+
const merged = { ...existing, ...updates };
|
|
126
|
+
// Deep merge for telemetry object
|
|
127
|
+
if (updates.telemetry && existing.telemetry) {
|
|
128
|
+
merged.telemetry = { ...existing.telemetry, ...updates.telemetry };
|
|
129
|
+
}
|
|
130
|
+
await writeConfigFile(configPath, merged);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get the telemetry config section.
|
|
134
|
+
*/
|
|
135
|
+
export async function getTelemetryConfig() {
|
|
136
|
+
const config = await readConfig();
|
|
137
|
+
return config.telemetry ?? {};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Update the telemetry config section.
|
|
141
|
+
*/
|
|
142
|
+
export async function updateTelemetryConfig(updates) {
|
|
143
|
+
const existing = await getTelemetryConfig();
|
|
144
|
+
await writeConfig({
|
|
145
|
+
telemetry: { ...existing, ...updates },
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if telemetry is enabled.
|
|
3
|
+
*
|
|
4
|
+
* Precedence (first match wins):
|
|
5
|
+
* 1. OPENSPEC_TELEMETRY set to anything but an on-value (1/true/yes/on) → disabled
|
|
6
|
+
* 2. DO_NOT_TRACK set to anything but an off-value (0/false/no/off) → disabled
|
|
7
|
+
* 3. CI set to a truthy/on value → disabled (same rule as version-check)
|
|
8
|
+
* 4. global config telemetry.enabled === false → disabled
|
|
9
|
+
* 5. global config file exists but cannot be parsed → disabled
|
|
10
|
+
* 6. otherwise enabled (unset config means on; opt-out model)
|
|
11
|
+
*
|
|
12
|
+
* Kept synchronous so call sites need not become async. Reads config via
|
|
13
|
+
* sync getGlobalConfig() rather than async getTelemetryConfig().
|
|
14
|
+
*/
|
|
15
|
+
export declare function isTelemetryEnabled(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Get or create the anonymous user ID.
|
|
18
|
+
* Lazily generates a UUID on first call and persists it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getOrCreateAnonymousId(): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Track a command execution.
|
|
23
|
+
*
|
|
24
|
+
* @param commandName - The command name (e.g., 'init', 'change:apply')
|
|
25
|
+
* @param version - The FreeSpec version
|
|
26
|
+
*/
|
|
27
|
+
export declare function trackCommand(commandName: string, version: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Show first-run telemetry notice if not already seen.
|
|
30
|
+
*/
|
|
31
|
+
export declare function maybeShowTelemetryNotice(options?: {
|
|
32
|
+
silent?: boolean;
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Flush pending telemetry events.
|
|
36
|
+
* Call this before CLI exit.
|
|
37
|
+
*/
|
|
38
|
+
export declare function shutdown(): Promise<void>;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|