@kbdavis07/openspec 1.5.0-nov.1
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 +239 -0
- package/bin/openspec.js +5 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +544 -0
- package/dist/commands/change.d.ts +38 -0
- package/dist/commands/change.js +245 -0
- package/dist/commands/completion.d.ts +72 -0
- package/dist/commands/completion.js +264 -0
- package/dist/commands/config.d.ts +36 -0
- package/dist/commands/config.js +552 -0
- package/dist/commands/context.d.ts +3 -0
- package/dist/commands/context.js +155 -0
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.js +163 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +183 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +869 -0
- package/dist/commands/shared-gather.d.ts +14 -0
- package/dist/commands/shared-gather.js +31 -0
- package/dist/commands/shared-output.d.ts +18 -0
- package/dist/commands/shared-output.js +61 -0
- package/dist/commands/show.d.ts +19 -0
- package/dist/commands/show.js +177 -0
- package/dist/commands/spec.d.ts +19 -0
- package/dist/commands/spec.js +236 -0
- package/dist/commands/store.d.ts +3 -0
- package/dist/commands/store.js +547 -0
- package/dist/commands/validate.d.ts +34 -0
- package/dist/commands/validate.js +342 -0
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/instructions.d.ts +39 -0
- package/dist/commands/workflow/instructions.js +393 -0
- package/dist/commands/workflow/new-change.d.ts +20 -0
- package/dist/commands/workflow/new-change.js +109 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/shared.d.ts +74 -0
- package/dist/commands/workflow/shared.js +170 -0
- package/dist/commands/workflow/status.d.ts +16 -0
- package/dist/commands/workflow/status.js +92 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +69 -0
- package/dist/commands/workset-input.d.ts +19 -0
- package/dist/commands/workset-input.js +112 -0
- package/dist/commands/workset-prompts.d.ts +12 -0
- package/dist/commands/workset-prompts.js +143 -0
- package/dist/commands/workset.d.ts +25 -0
- package/dist/commands/workset.js +446 -0
- package/dist/core/archive.d.ts +22 -0
- package/dist/core/archive.js +496 -0
- package/dist/core/artifact-graph/graph.d.ts +56 -0
- package/dist/core/artifact-graph/graph.js +141 -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 +188 -0
- package/dist/core/artifact-graph/instruction-loader.js +233 -0
- package/dist/core/artifact-graph/outputs.d.ts +14 -0
- package/dist/core/artifact-graph/outputs.js +39 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.js +257 -0
- package/dist/core/artifact-graph/schema.d.ts +13 -0
- package/dist/core/artifact-graph/schema.js +108 -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 +29 -0
- package/dist/core/available-tools.d.ts +17 -0
- package/dist/core/available-tools.js +43 -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 +19 -0
- package/dist/core/change-metadata/schema.js +30 -0
- package/dist/core/change-status-policy.d.ts +37 -0
- package/dist/core/change-status-policy.js +35 -0
- package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
- package/dist/core/command-generation/adapters/amazon-q.js +26 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +26 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +27 -0
- package/dist/core/command-generation/adapters/bob.d.ts +14 -0
- package/dist/core/command-generation/adapters/bob.js +32 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +39 -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/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +28 -0
- package/dist/core/command-generation/adapters/codex.d.ts +16 -0
- package/dist/core/command-generation/adapters/codex.js +39 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +28 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +27 -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/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +26 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +26 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +29 -0
- package/dist/core/command-generation/adapters/index.d.ts +34 -0
- package/dist/core/command-generation/adapters/index.js +34 -0
- package/dist/core/command-generation/adapters/junie.d.ts +13 -0
- package/dist/core/command-generation/adapters/junie.js +26 -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 +26 -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 +44 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +29 -0
- package/dist/core/command-generation/adapters/pi.d.ts +18 -0
- package/dist/core/command-generation/adapters/pi.js +42 -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 +13 -0
- package/dist/core/command-generation/adapters/qwen.js +26 -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 +48 -0
- package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
- package/dist/core/command-generation/adapters/windsurf.js +38 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.js +27 -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/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +102 -0
- package/dist/core/command-generation/types.d.ts +56 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/command-generation/yaml.d.ts +22 -0
- package/dist/core/command-generation/yaml.js +38 -0
- package/dist/core/completions/command-registry.d.ts +3 -0
- package/dist/core/completions/command-registry.js +759 -0
- package/dist/core/completions/completion-provider.d.ts +71 -0
- package/dist/core/completions/completion-provider.js +129 -0
- package/dist/core/completions/factory.d.ts +64 -0
- package/dist/core/completions/factory.js +75 -0
- package/dist/core/completions/generators/bash-generator.d.ts +35 -0
- package/dist/core/completions/generators/bash-generator.js +230 -0
- package/dist/core/completions/generators/fish-generator.d.ts +32 -0
- package/dist/core/completions/generators/fish-generator.js +160 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
- package/dist/core/completions/generators/powershell-generator.js +266 -0
- package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
- package/dist/core/completions/generators/zsh-generator.js +276 -0
- package/dist/core/completions/installers/bash-installer.d.ts +87 -0
- package/dist/core/completions/installers/bash-installer.js +321 -0
- package/dist/core/completions/installers/fish-installer.d.ts +43 -0
- package/dist/core/completions/installers/fish-installer.js +151 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
- package/dist/core/completions/installers/powershell-installer.js +415 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
- package/dist/core/completions/installers/zsh-installer.js +424 -0
- package/dist/core/completions/shared-flags.d.ts +13 -0
- package/dist/core/completions/shared-flags.js +33 -0
- package/dist/core/completions/templates/bash-templates.d.ts +6 -0
- package/dist/core/completions/templates/bash-templates.js +30 -0
- package/dist/core/completions/templates/fish-templates.d.ts +7 -0
- package/dist/core/completions/templates/fish-templates.js +45 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
- package/dist/core/completions/templates/powershell-templates.js +34 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
- package/dist/core/completions/templates/zsh-templates.js +45 -0
- package/dist/core/completions/types.d.ts +101 -0
- package/dist/core/completions/types.js +2 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +34 -0
- package/dist/core/config-schema.d.ts +87 -0
- package/dist/core/config-schema.js +239 -0
- package/dist/core/config.d.ts +18 -0
- package/dist/core/config.js +40 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/file-state.d.ts +36 -0
- package/dist/core/file-state.js +112 -0
- package/dist/core/global-config.d.ts +51 -0
- package/dist/core/global-config.js +124 -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 +37 -0
- package/dist/core/init.js +614 -0
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +514 -0
- package/dist/core/list.d.ts +11 -0
- package/dist/core/list.js +214 -0
- package/dist/core/migration.d.ts +23 -0
- package/dist/core/migration.js +108 -0
- package/dist/core/openers.d.ts +77 -0
- package/dist/core/openers.js +251 -0
- package/dist/core/openspec-root.d.ts +45 -0
- package/dist/core/openspec-root.js +195 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +198 -0
- package/dist/core/parsers/markdown-parser.d.ts +23 -0
- package/dist/core/parsers/markdown-parser.js +173 -0
- package/dist/core/parsers/requirement-blocks.d.ts +48 -0
- package/dist/core/parsers/requirement-blocks.js +235 -0
- package/dist/core/parsers/requirement-text.d.ts +55 -0
- package/dist/core/parsers/requirement-text.js +136 -0
- package/dist/core/parsers/spec-structure.d.ts +9 -0
- package/dist/core/parsers/spec-structure.js +88 -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 +38 -0
- package/dist/core/profile-sync-drift.js +201 -0
- package/dist/core/profiles.d.ts +26 -0
- package/dist/core/profiles.js +41 -0
- package/dist/core/project-config.d.ts +107 -0
- package/dist/core/project-config.js +373 -0
- package/dist/core/references.d.ts +63 -0
- package/dist/core/references.js +310 -0
- package/dist/core/relationship-health.d.ts +65 -0
- package/dist/core/relationship-health.js +64 -0
- package/dist/core/root-selection.d.ts +122 -0
- package/dist/core/root-selection.js +337 -0
- package/dist/core/schemas/base.schema.d.ts +13 -0
- package/dist/core/schemas/base.schema.js +18 -0
- package/dist/core/schemas/change.schema.d.ts +73 -0
- package/dist/core/schemas/change.schema.js +31 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/spec.schema.d.ts +18 -0
- package/dist/core/schemas/spec.schema.js +15 -0
- 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 +8 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/skill-generation.d.ts +49 -0
- package/dist/core/shared/skill-generation.js +100 -0
- package/dist/core/shared/tool-detection.d.ts +71 -0
- package/dist/core/shared/tool-detection.js +160 -0
- package/dist/core/specs-apply.d.ts +78 -0
- package/dist/core/specs-apply.js +428 -0
- package/dist/core/store/errors.d.ts +20 -0
- package/dist/core/store/errors.js +22 -0
- package/dist/core/store/foundation.d.ts +56 -0
- package/dist/core/store/foundation.js +251 -0
- package/dist/core/store/git.d.ts +23 -0
- package/dist/core/store/git.js +137 -0
- package/dist/core/store/index.d.ts +5 -0
- package/dist/core/store/index.js +5 -0
- package/dist/core/store/operations.d.ts +114 -0
- package/dist/core/store/operations.js +803 -0
- package/dist/core/store/registry.d.ts +58 -0
- package/dist/core/store/registry.js +275 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/index.d.ts +8 -0
- package/dist/core/templates/index.js +9 -0
- package/dist/core/templates/skill-templates.d.ts +20 -0
- package/dist/core/templates/skill-templates.js +19 -0
- package/dist/core/templates/types.d.ts +19 -0
- package/dist/core/templates/types.js +5 -0
- package/dist/core/templates/workflows/apply-change.d.ts +10 -0
- package/dist/core/templates/workflows/apply-change.js +315 -0
- package/dist/core/templates/workflows/archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/archive-change.js +278 -0
- package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/bulk-archive-change.js +493 -0
- package/dist/core/templates/workflows/continue-change.d.ts +10 -0
- package/dist/core/templates/workflows/continue-change.js +239 -0
- package/dist/core/templates/workflows/explore.d.ts +10 -0
- package/dist/core/templates/workflows/explore.js +464 -0
- package/dist/core/templates/workflows/feedback.d.ts +9 -0
- package/dist/core/templates/workflows/feedback.js +108 -0
- package/dist/core/templates/workflows/ff-change.d.ts +10 -0
- package/dist/core/templates/workflows/ff-change.js +205 -0
- package/dist/core/templates/workflows/new-change.d.ts +10 -0
- package/dist/core/templates/workflows/new-change.js +148 -0
- package/dist/core/templates/workflows/onboard.d.ts +10 -0
- package/dist/core/templates/workflows/onboard.js +566 -0
- package/dist/core/templates/workflows/propose.d.ts +10 -0
- package/dist/core/templates/workflows/propose.js +223 -0
- package/dist/core/templates/workflows/store-selection.d.ts +8 -0
- package/dist/core/templates/workflows/store-selection.js +8 -0
- package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
- package/dist/core/templates/workflows/sync-specs.js +291 -0
- package/dist/core/templates/workflows/update-change.d.ts +10 -0
- package/dist/core/templates/workflows/update-change.js +167 -0
- package/dist/core/templates/workflows/verify-change.d.ts +10 -0
- package/dist/core/templates/workflows/verify-change.js +339 -0
- package/dist/core/update.d.ts +82 -0
- package/dist/core/update.js +557 -0
- package/dist/core/validation/constants.d.ts +34 -0
- package/dist/core/validation/constants.js +40 -0
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.js +2 -0
- package/dist/core/validation/validator.d.ts +51 -0
- package/dist/core/validation/validator.js +498 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +168 -0
- package/dist/core/working-set.d.ts +47 -0
- package/dist/core/working-set.js +43 -0
- package/dist/core/worksets.d.ts +75 -0
- package/dist/core/worksets.js +245 -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 +28 -0
- package/dist/prompts/searchable-multi-select.js +159 -0
- package/dist/telemetry/config.d.ts +38 -0
- package/dist/telemetry/config.js +136 -0
- package/dist/telemetry/index.d.ts +31 -0
- package/dist/telemetry/index.js +164 -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 +10 -0
- package/dist/ui/welcome-screen.js +146 -0
- package/dist/utils/change-metadata.d.ts +55 -0
- package/dist/utils/change-metadata.js +141 -0
- package/dist/utils/change-utils.d.ts +85 -0
- package/dist/utils/change-utils.js +173 -0
- package/dist/utils/command-references.d.ts +18 -0
- package/dist/utils/command-references.js +20 -0
- package/dist/utils/file-system.d.ts +41 -0
- package/dist/utils/file-system.js +320 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/interactive.d.ts +18 -0
- package/dist/utils/interactive.js +21 -0
- package/dist/utils/item-discovery.d.ts +4 -0
- package/dist/utils/item-discovery.js +72 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +41 -0
- package/dist/utils/task-progress.d.ts +17 -0
- package/dist/utils/task-progress.js +100 -0
- package/package.json +85 -0
- package/schemas/spec-driven/schema.yaml +153 -0
- package/schemas/spec-driven/templates/design.md +19 -0
- package/schemas/spec-driven/templates/proposal.md +23 -0
- package/schemas/spec-driven/templates/spec.md +8 -0
- package/schemas/spec-driven/templates/tasks.md +9 -0
- package/scripts/postinstall.js +83 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as nodeFs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { FileSystemUtils } from '../utils/file-system.js';
|
|
4
|
+
import { StoreError } from './store/errors.js';
|
|
5
|
+
const fs = nodeFs.promises;
|
|
6
|
+
/** One template for lock diagnostics; callers supply the data. */
|
|
7
|
+
export function makeLockErrorFactory(data) {
|
|
8
|
+
return (kind, info) => {
|
|
9
|
+
if (kind === 'create-failed') {
|
|
10
|
+
// A permission or filesystem problem, not contention - say so.
|
|
11
|
+
return new StoreError(`Cannot create ${data.createSubject} ${info.lockPath} (${info.cause?.code ?? info.cause}).`, data.code, {
|
|
12
|
+
target: data.target,
|
|
13
|
+
fix: `Check permissions on ${path.dirname(info.lockPath)}.`,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return new StoreError(data.busyMessage, data.code, {
|
|
17
|
+
target: data.target,
|
|
18
|
+
fix: `Retry shortly; if this persists, delete the stale lock file ${info.lockPath}.`,
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const STALE_LOCK_THRESHOLD_MS = 30_000;
|
|
23
|
+
const LOCK_DEADLINE_MS = 5000;
|
|
24
|
+
const LOCK_POLL_MS = 25;
|
|
25
|
+
export function isNodeErrorCode(error, code) {
|
|
26
|
+
return (typeof error === 'object' &&
|
|
27
|
+
error !== null &&
|
|
28
|
+
'code' in error &&
|
|
29
|
+
error.code === code);
|
|
30
|
+
}
|
|
31
|
+
export async function pathIsFile(filePath) {
|
|
32
|
+
try {
|
|
33
|
+
return (await fs.stat(filePath)).isFile();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Deliberately not FileSystemUtils.directoryExists: that variant
|
|
40
|
+
// debug-logs non-ENOENT failures, which is noise inside prompt
|
|
41
|
+
// validators, and pathIsFile has no FileSystemUtils equivalent - the
|
|
42
|
+
// silent symmetric pair lives here.
|
|
43
|
+
export async function pathIsDirectory(dirPath) {
|
|
44
|
+
try {
|
|
45
|
+
return (await fs.stat(dirPath)).isDirectory();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function sleep(milliseconds) {
|
|
52
|
+
await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
53
|
+
}
|
|
54
|
+
export async function writeFileAtomically(filePath, content) {
|
|
55
|
+
const dirPath = path.dirname(filePath);
|
|
56
|
+
await FileSystemUtils.createDirectory(dirPath);
|
|
57
|
+
const tempPath = path.join(dirPath, `.${path.basename(filePath)}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`);
|
|
58
|
+
try {
|
|
59
|
+
await fs.writeFile(tempPath, content, 'utf-8');
|
|
60
|
+
await fs.rename(tempPath, filePath);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
await fs.rm(tempPath, { force: true }).catch(() => undefined);
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export async function acquireFileLock(options) {
|
|
68
|
+
const { lockPath, errorFor } = options;
|
|
69
|
+
const lockDir = path.dirname(lockPath);
|
|
70
|
+
await FileSystemUtils.createDirectory(lockDir);
|
|
71
|
+
if (!(await FileSystemUtils.canWriteFile(lockDir))) {
|
|
72
|
+
throw errorFor('create-failed', { lockPath, cause: 'EACCES' });
|
|
73
|
+
}
|
|
74
|
+
const deadline = Date.now() + LOCK_DEADLINE_MS;
|
|
75
|
+
while (true) {
|
|
76
|
+
try {
|
|
77
|
+
return await fs.open(lockPath, 'wx');
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (!isNodeErrorCode(error, 'EEXIST')) {
|
|
81
|
+
// A permission or filesystem problem, not contention - say so.
|
|
82
|
+
throw errorFor('create-failed', { lockPath, cause: error });
|
|
83
|
+
}
|
|
84
|
+
// A crashed process leaves the lock behind forever; state-file
|
|
85
|
+
// writes are sub-second, so an old lock is an orphan - steal it.
|
|
86
|
+
let staleStolen = false;
|
|
87
|
+
try {
|
|
88
|
+
const lockStat = await fs.stat(lockPath);
|
|
89
|
+
if (Date.now() - lockStat.mtimeMs > STALE_LOCK_THRESHOLD_MS) {
|
|
90
|
+
await fs.rm(lockPath, { force: true });
|
|
91
|
+
staleStolen = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// The holder released between open and stat - retry, but stay
|
|
96
|
+
// bounded: a persistently failing stat (EPERM, delete-pending)
|
|
97
|
+
// must hit the deadline instead of spinning forever.
|
|
98
|
+
}
|
|
99
|
+
if (!staleStolen) {
|
|
100
|
+
if (Date.now() >= deadline) {
|
|
101
|
+
throw errorFor('timeout', { lockPath });
|
|
102
|
+
}
|
|
103
|
+
await sleep(LOCK_POLL_MS);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export async function releaseFileLock(lock, lockPath) {
|
|
109
|
+
await lock.close().catch(() => undefined);
|
|
110
|
+
await fs.rm(lockPath, { force: true }).catch(() => undefined);
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=file-state.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export declare const GLOBAL_CONFIG_DIR_NAME = "openspec";
|
|
2
|
+
export declare const GLOBAL_CONFIG_FILE_NAME = "config.json";
|
|
3
|
+
export declare const GLOBAL_DATA_DIR_NAME = "openspec";
|
|
4
|
+
export type Profile = 'core' | 'custom';
|
|
5
|
+
export type Delivery = 'both' | 'skills' | 'commands';
|
|
6
|
+
export interface GlobalConfig {
|
|
7
|
+
featureFlags?: Record<string, boolean>;
|
|
8
|
+
profile?: Profile;
|
|
9
|
+
delivery?: Delivery;
|
|
10
|
+
workflows?: string[];
|
|
11
|
+
/** Workset opener rows (slice 7.1); hand-edited, validated on use. */
|
|
12
|
+
openers?: unknown;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Gets the global configuration directory path following XDG Base Directory Specification.
|
|
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
|
+
*/
|
|
21
|
+
export declare function getGlobalConfigDir(): string;
|
|
22
|
+
/**
|
|
23
|
+
* Gets the global data directory path following XDG Base Directory Specification.
|
|
24
|
+
* Used for user data like schema overrides.
|
|
25
|
+
*
|
|
26
|
+
* - All platforms: $XDG_DATA_HOME/openspec/ if XDG_DATA_HOME is set
|
|
27
|
+
* - Unix/macOS fallback: ~/.local/share/openspec/
|
|
28
|
+
* - Windows fallback: %LOCALAPPDATA%/openspec/
|
|
29
|
+
*/
|
|
30
|
+
export interface GlobalDataDirOptions {
|
|
31
|
+
env?: NodeJS.ProcessEnv;
|
|
32
|
+
platform?: NodeJS.Platform;
|
|
33
|
+
homedir?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function getGlobalDataDir(options?: GlobalDataDirOptions): string;
|
|
36
|
+
/**
|
|
37
|
+
* Gets the path to the global config file.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getGlobalConfigPath(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Loads the global configuration from disk.
|
|
42
|
+
* Returns default configuration if file doesn't exist or is invalid.
|
|
43
|
+
* Merges loaded config with defaults to ensure new fields are available.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getGlobalConfig(): GlobalConfig;
|
|
46
|
+
/**
|
|
47
|
+
* Saves the global configuration to disk.
|
|
48
|
+
* Creates the config directory if it doesn't exist.
|
|
49
|
+
*/
|
|
50
|
+
export declare function saveGlobalConfig(config: GlobalConfig): void;
|
|
51
|
+
//# sourceMappingURL=global-config.d.ts.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
// Constants
|
|
5
|
+
export const GLOBAL_CONFIG_DIR_NAME = 'openspec';
|
|
6
|
+
export const GLOBAL_CONFIG_FILE_NAME = 'config.json';
|
|
7
|
+
export const GLOBAL_DATA_DIR_NAME = 'openspec';
|
|
8
|
+
const DEFAULT_CONFIG = {
|
|
9
|
+
featureFlags: {},
|
|
10
|
+
profile: 'core',
|
|
11
|
+
delivery: 'both',
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Gets the global configuration directory path following XDG Base Directory Specification.
|
|
15
|
+
*
|
|
16
|
+
* - All platforms: $XDG_CONFIG_HOME/openspec/ if XDG_CONFIG_HOME is set
|
|
17
|
+
* - Unix/macOS fallback: ~/.config/openspec/
|
|
18
|
+
* - Windows fallback: %APPDATA%/openspec/
|
|
19
|
+
*/
|
|
20
|
+
export function getGlobalConfigDir() {
|
|
21
|
+
// XDG_CONFIG_HOME takes precedence on all platforms when explicitly set
|
|
22
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
23
|
+
if (xdgConfigHome) {
|
|
24
|
+
return path.join(xdgConfigHome, GLOBAL_CONFIG_DIR_NAME);
|
|
25
|
+
}
|
|
26
|
+
const platform = os.platform();
|
|
27
|
+
if (platform === 'win32') {
|
|
28
|
+
// Windows: use %APPDATA%
|
|
29
|
+
const appData = process.env.APPDATA;
|
|
30
|
+
if (appData) {
|
|
31
|
+
return path.join(appData, GLOBAL_CONFIG_DIR_NAME);
|
|
32
|
+
}
|
|
33
|
+
// Fallback for Windows if APPDATA is not set
|
|
34
|
+
return path.join(os.homedir(), 'AppData', 'Roaming', GLOBAL_CONFIG_DIR_NAME);
|
|
35
|
+
}
|
|
36
|
+
// Unix/macOS fallback: ~/.config
|
|
37
|
+
return path.join(os.homedir(), '.config', GLOBAL_CONFIG_DIR_NAME);
|
|
38
|
+
}
|
|
39
|
+
function joinGlobalDataPath(platform, ...segments) {
|
|
40
|
+
return platform === 'win32'
|
|
41
|
+
? path.win32.join(...segments)
|
|
42
|
+
: path.posix.join(...segments);
|
|
43
|
+
}
|
|
44
|
+
export function getGlobalDataDir(options = {}) {
|
|
45
|
+
const env = options.env ?? process.env;
|
|
46
|
+
const platform = options.platform ?? os.platform();
|
|
47
|
+
// XDG_DATA_HOME takes precedence on all platforms when explicitly set
|
|
48
|
+
const xdgDataHome = env.XDG_DATA_HOME;
|
|
49
|
+
if (xdgDataHome) {
|
|
50
|
+
return joinGlobalDataPath(platform, xdgDataHome, GLOBAL_DATA_DIR_NAME);
|
|
51
|
+
}
|
|
52
|
+
const homedir = options.homedir ?? os.homedir();
|
|
53
|
+
if (platform === 'win32') {
|
|
54
|
+
// Windows: use %LOCALAPPDATA%
|
|
55
|
+
const localAppData = env.LOCALAPPDATA;
|
|
56
|
+
if (localAppData) {
|
|
57
|
+
return joinGlobalDataPath(platform, localAppData, GLOBAL_DATA_DIR_NAME);
|
|
58
|
+
}
|
|
59
|
+
// Fallback for Windows if LOCALAPPDATA is not set
|
|
60
|
+
return joinGlobalDataPath(platform, homedir, 'AppData', 'Local', GLOBAL_DATA_DIR_NAME);
|
|
61
|
+
}
|
|
62
|
+
// Unix/macOS fallback: ~/.local/share
|
|
63
|
+
return joinGlobalDataPath(platform, homedir, '.local', 'share', GLOBAL_DATA_DIR_NAME);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Gets the path to the global config file.
|
|
67
|
+
*/
|
|
68
|
+
export function getGlobalConfigPath() {
|
|
69
|
+
return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE_NAME);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Loads the global configuration from disk.
|
|
73
|
+
* Returns default configuration if file doesn't exist or is invalid.
|
|
74
|
+
* Merges loaded config with defaults to ensure new fields are available.
|
|
75
|
+
*/
|
|
76
|
+
export function getGlobalConfig() {
|
|
77
|
+
const configPath = getGlobalConfigPath();
|
|
78
|
+
try {
|
|
79
|
+
if (!fs.existsSync(configPath)) {
|
|
80
|
+
return { ...DEFAULT_CONFIG };
|
|
81
|
+
}
|
|
82
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
83
|
+
const parsed = JSON.parse(content);
|
|
84
|
+
// Merge with defaults (loaded values take precedence)
|
|
85
|
+
const merged = {
|
|
86
|
+
...DEFAULT_CONFIG,
|
|
87
|
+
...parsed,
|
|
88
|
+
// Deep merge featureFlags
|
|
89
|
+
featureFlags: {
|
|
90
|
+
...DEFAULT_CONFIG.featureFlags,
|
|
91
|
+
...(parsed.featureFlags || {})
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
// Schema evolution: apply defaults for new fields if not present in loaded config
|
|
95
|
+
if (parsed.profile === undefined) {
|
|
96
|
+
merged.profile = DEFAULT_CONFIG.profile;
|
|
97
|
+
}
|
|
98
|
+
if (parsed.delivery === undefined) {
|
|
99
|
+
merged.delivery = DEFAULT_CONFIG.delivery;
|
|
100
|
+
}
|
|
101
|
+
return merged;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
// Log warning for parse errors, but not for missing files
|
|
105
|
+
if (error instanceof SyntaxError) {
|
|
106
|
+
console.error(`Warning: Invalid JSON in ${configPath}, using defaults`);
|
|
107
|
+
}
|
|
108
|
+
return { ...DEFAULT_CONFIG };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Saves the global configuration to disk.
|
|
113
|
+
* Creates the config directory if it doesn't exist.
|
|
114
|
+
*/
|
|
115
|
+
export function saveGlobalConfig(config) {
|
|
116
|
+
const configDir = getGlobalConfigDir();
|
|
117
|
+
const configPath = getGlobalConfigPath();
|
|
118
|
+
// Create directory if it doesn't exist
|
|
119
|
+
if (!fs.existsSync(configDir)) {
|
|
120
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=global-config.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one kebab id grammar. Store ids, change ids, and legacy initiative ids
|
|
3
|
+
* all share it.
|
|
4
|
+
*/
|
|
5
|
+
export declare const KEBAB_ID_REGEX: RegExp;
|
|
6
|
+
export declare function isKebabId(value: string): boolean;
|
|
7
|
+
/** Human rendering of the grammar, shared so the wording never forks. */
|
|
8
|
+
export declare const KEBAB_ID_DESCRIPTION = "must be kebab-case with lowercase letters, numbers, and single hyphen separators";
|
|
9
|
+
/** The fix-line twin of KEBAB_ID_DESCRIPTION, shared for the same reason. */
|
|
10
|
+
export declare const KEBAB_ID_FIX = "Use kebab-case with lowercase letters, numbers, and single hyphen separators.";
|
|
11
|
+
/**
|
|
12
|
+
* The folder-safe-name grammar (store ids layer the kebab grammar on
|
|
13
|
+
* top of it; workset member labels use it alone). Returns a problem
|
|
14
|
+
* description, or null when valid.
|
|
15
|
+
*/
|
|
16
|
+
export declare function folderStyleNameProblem(value: string, label: string): string | null;
|
|
17
|
+
//# sourceMappingURL=id.d.ts.map
|
package/dist/core/id.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one kebab id grammar. Store ids, change ids, and legacy initiative ids
|
|
3
|
+
* all share it.
|
|
4
|
+
*/
|
|
5
|
+
export const KEBAB_ID_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
6
|
+
export function isKebabId(value) {
|
|
7
|
+
return KEBAB_ID_REGEX.test(value);
|
|
8
|
+
}
|
|
9
|
+
/** Human rendering of the grammar, shared so the wording never forks. */
|
|
10
|
+
export const KEBAB_ID_DESCRIPTION = 'must be kebab-case with lowercase letters, numbers, and single hyphen separators';
|
|
11
|
+
/** The fix-line twin of KEBAB_ID_DESCRIPTION, shared for the same reason. */
|
|
12
|
+
export const KEBAB_ID_FIX = 'Use kebab-case with lowercase letters, numbers, and single hyphen separators.';
|
|
13
|
+
/**
|
|
14
|
+
* The folder-safe-name grammar (store ids layer the kebab grammar on
|
|
15
|
+
* top of it; workset member labels use it alone). Returns a problem
|
|
16
|
+
* description, or null when valid.
|
|
17
|
+
*/
|
|
18
|
+
export function folderStyleNameProblem(value, label) {
|
|
19
|
+
if (value.length === 0) {
|
|
20
|
+
return `${label} must not be empty`;
|
|
21
|
+
}
|
|
22
|
+
if (value === '.' || value === '..') {
|
|
23
|
+
return `${label} must not be '${value}'`;
|
|
24
|
+
}
|
|
25
|
+
if (/[\\/]/u.test(value)) {
|
|
26
|
+
return `${label} must not contain path separators`;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=id.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { GLOBAL_CONFIG_DIR_NAME, GLOBAL_CONFIG_FILE_NAME, GLOBAL_DATA_DIR_NAME, type GlobalDataDirOptions, type GlobalConfig, getGlobalConfigDir, getGlobalConfigPath, getGlobalConfig, saveGlobalConfig, getGlobalDataDir } from './global-config.js';
|
|
2
|
+
export * from './references.js';
|
|
3
|
+
export * from './store/index.js';
|
|
4
|
+
export * from './planning-home.js';
|
|
5
|
+
export * from './openspec-root.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Core OpenSpec logic will be implemented here
|
|
2
|
+
export { GLOBAL_CONFIG_DIR_NAME, GLOBAL_CONFIG_FILE_NAME, GLOBAL_DATA_DIR_NAME, getGlobalConfigDir, getGlobalConfigPath, getGlobalConfig, saveGlobalConfig, getGlobalDataDir } from './global-config.js';
|
|
3
|
+
export * from './references.js';
|
|
4
|
+
export * from './store/index.js';
|
|
5
|
+
export * from './planning-home.js';
|
|
6
|
+
export * from './openspec-root.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Init Command
|
|
3
|
+
*
|
|
4
|
+
* Sets up OpenSpec with Agent Skills and /opsx:* slash commands.
|
|
5
|
+
* This is the unified setup command that replaces both the old init and experimental commands.
|
|
6
|
+
*/
|
|
7
|
+
type InitCommandOptions = {
|
|
8
|
+
tools?: string;
|
|
9
|
+
force?: boolean;
|
|
10
|
+
interactive?: boolean;
|
|
11
|
+
profile?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare class InitCommand {
|
|
14
|
+
private readonly toolsArg?;
|
|
15
|
+
private readonly force;
|
|
16
|
+
private readonly interactiveOption?;
|
|
17
|
+
private readonly profileOverride?;
|
|
18
|
+
constructor(options?: InitCommandOptions);
|
|
19
|
+
execute(targetPath: string): Promise<void>;
|
|
20
|
+
private validate;
|
|
21
|
+
private canPromptInteractively;
|
|
22
|
+
private resolveProfileOverride;
|
|
23
|
+
private handleLegacyCleanup;
|
|
24
|
+
private performLegacyCleanup;
|
|
25
|
+
private getSelectedTools;
|
|
26
|
+
private resolveToolsArg;
|
|
27
|
+
private validateTools;
|
|
28
|
+
private createDirectoryStructure;
|
|
29
|
+
private generateSkillsAndCommands;
|
|
30
|
+
private createConfig;
|
|
31
|
+
private displaySuccessMessage;
|
|
32
|
+
private startSpinner;
|
|
33
|
+
private removeSkillDirs;
|
|
34
|
+
private removeCommandFiles;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=init.d.ts.map
|