@codewalla_india/openspec 1.0.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 +225 -0
- package/bin/openspec.js +5 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +548 -0
- package/dist/commands/change.d.ts +39 -0
- package/dist/commands/change.js +279 -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 +26 -0
- package/dist/commands/validate.js +330 -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 +45 -0
- package/dist/commands/workflow/instructions.js +500 -0
- package/dist/commands/workflow/new-change.d.ts +20 -0
- package/dist/commands/workflow/new-change.js +106 -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 +84 -0
- package/dist/commands/workflow/shared.js +133 -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 +471 -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 +37 -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 +32 -0
- package/dist/core/command-generation/adapters/index.js +32 -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/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/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 +98 -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 +778 -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/comprehension/config.d.ts +20 -0
- package/dist/core/comprehension/config.js +23 -0
- package/dist/core/comprehension/fingerprint.d.ts +5 -0
- package/dist/core/comprehension/fingerprint.js +25 -0
- package/dist/core/comprehension/index.d.ts +49 -0
- package/dist/core/comprehension/index.js +78 -0
- package/dist/core/comprehension/pass-record.d.ts +29 -0
- package/dist/core/comprehension/pass-record.js +64 -0
- package/dist/core/comprehension/stats.d.ts +18 -0
- package/dist/core/comprehension/stats.js +41 -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 +39 -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 +613 -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 +185 -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 +192 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +197 -0
- package/dist/core/parsers/markdown-parser.d.ts +26 -0
- package/dist/core/parsers/markdown-parser.js +227 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.js +201 -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 +200 -0
- package/dist/core/profiles.d.ts +26 -0
- package/dist/core/profiles.js +40 -0
- package/dist/core/project-config.d.ts +120 -0
- package/dist/core/project-config.js +406 -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 +13 -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/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 +96 -0
- package/dist/core/shared/tool-detection.d.ts +71 -0
- package/dist/core/shared/tool-detection.js +158 -0
- package/dist/core/specs-apply.d.ts +78 -0
- package/dist/core/specs-apply.js +394 -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 +783 -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 +19 -0
- package/dist/core/templates/skill-templates.js +18 -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 +337 -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/comprehension-guidance.d.ts +9 -0
- package/dist/core/templates/workflows/comprehension-guidance.js +58 -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/mcp-guidance.d.ts +13 -0
- package/dist/core/templates/workflows/mcp-guidance.js +116 -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 +228 -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/verify-change.d.ts +10 -0
- package/dist/core/templates/workflows/verify-change.js +346 -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 +44 -0
- package/dist/core/validation/validator.js +435 -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 +71 -0
- package/dist/utils/change-utils.js +138 -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 +8 -0
- package/dist/utils/task-progress.js +36 -0
- package/package.json +84 -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,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Referenced-store index assembly (slice 3.1).
|
|
3
|
+
*
|
|
4
|
+
* A root's `openspec/config.yaml` may declare `references:` — store ids
|
|
5
|
+
* whose specs the root's work draws on. Instructions output carries an
|
|
6
|
+
* INDEX of those stores' specs (id, one-line summary, fetch recipe via
|
|
7
|
+
* `--store`), built live from the registered checkouts at assembly time.
|
|
8
|
+
* Content is never inlined; root resolution is never affected; problems
|
|
9
|
+
* degrade to `warning` diagnostics instead of failing generation.
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'node:fs/promises';
|
|
12
|
+
import * as os from 'node:os';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import { makeStoreDiagnostic } from './store/errors.js';
|
|
15
|
+
import { isValidStoreId, listStoreRegistryEntries, readStoreRegistryState, } from './store/foundation.js';
|
|
16
|
+
import { getStoreRootForBackend } from './store/registry.js';
|
|
17
|
+
import { inspectRegisteredStore } from './root-selection.js';
|
|
18
|
+
import { getSpecIds } from '../utils/item-discovery.js';
|
|
19
|
+
import { FileSystemUtils } from '../utils/file-system.js';
|
|
20
|
+
import { MAX_CONTEXT_SIZE } from './project-config.js';
|
|
21
|
+
/**
|
|
22
|
+
* Shares the project-context cap: the rendered index is prompt material.
|
|
23
|
+
* Measured in UTF-8 bytes against the XML rendering (the larger of the
|
|
24
|
+
* two), entries and diagnostics included; only the truncation warning
|
|
25
|
+
* itself is exempt (no oscillation).
|
|
26
|
+
*/
|
|
27
|
+
const MAX_RENDERED_INDEX_SIZE = MAX_CONTEXT_SIZE;
|
|
28
|
+
function warning(code, message, fix) {
|
|
29
|
+
return makeStoreDiagnostic('warning', code, message, { target: 'references', fix });
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A remote is rendered into the pasteable clone command only when it is
|
|
33
|
+
* shell-inert: no whitespace, quotes, or metacharacters, and not
|
|
34
|
+
* flag-like (a config-supplied `--upload-pack=...` must never reach a
|
|
35
|
+
* command agents execute verbatim). Anything else falls back to the
|
|
36
|
+
* teammate-checkout wording.
|
|
37
|
+
*/
|
|
38
|
+
function isShellSafeRemote(remote) {
|
|
39
|
+
return /^[A-Za-z0-9@:/._~+-]+$/.test(remote) && !remote.startsWith('-');
|
|
40
|
+
}
|
|
41
|
+
function registerFix(id, remote) {
|
|
42
|
+
if (remote && isShellSafeRemote(remote)) {
|
|
43
|
+
// Verbatim-pasteable: absolute home path because tilde never
|
|
44
|
+
// expands outside a shell and agent JSON consumers execute argv.
|
|
45
|
+
// The checkout is quoted (homedirs may contain spaces); the remote
|
|
46
|
+
// is unquoted but gated by isShellSafeRemote above.
|
|
47
|
+
const checkout = path.join(os.homedir(), 'openspec', id);
|
|
48
|
+
// The fix renders on the machine that will paste it: POSIX shells
|
|
49
|
+
// get single quotes; cmd/PowerShell treat single quotes as literal
|
|
50
|
+
// characters, so win32 gets double quotes (valid everywhere).
|
|
51
|
+
const quoted = process.platform === 'win32' ? `"${checkout}"` : `'${checkout}'`;
|
|
52
|
+
return `git clone -- ${remote} ${quoted} && openspec store register ${quoted} --id ${id}`;
|
|
53
|
+
}
|
|
54
|
+
return `Get a checkout from a teammate and run: openspec store register <path> --id ${id}`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Tolerant first-Purpose-line extraction. parseSpec() throws on specs
|
|
58
|
+
* without Purpose/Requirements sections; the index must never fail on an
|
|
59
|
+
* imperfect upstream spec, so this scans for the heading directly —
|
|
60
|
+
* fence-aware, so `## Purpose` inside a code block never matches, and
|
|
61
|
+
* tolerant of CommonMark closing hashes (`## Purpose ##`).
|
|
62
|
+
*/
|
|
63
|
+
export function extractFirstPurposeLine(markdown) {
|
|
64
|
+
const lines = markdown.split(/\r?\n/);
|
|
65
|
+
let inPurpose = false;
|
|
66
|
+
let fenceMarker = null;
|
|
67
|
+
for (const line of lines) {
|
|
68
|
+
// CommonMark: a fence closes only with its own marker kind.
|
|
69
|
+
const fence = line.match(/^\s*(```|~~~)/);
|
|
70
|
+
if (fence) {
|
|
71
|
+
if (fenceMarker === null) {
|
|
72
|
+
fenceMarker = fence[1];
|
|
73
|
+
}
|
|
74
|
+
else if (fence[1] === fenceMarker) {
|
|
75
|
+
fenceMarker = null;
|
|
76
|
+
}
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (fenceMarker !== null) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const heading = line.match(/^(#{1,6})\s+(.*)$/);
|
|
83
|
+
if (heading) {
|
|
84
|
+
if (inPurpose) {
|
|
85
|
+
return '';
|
|
86
|
+
}
|
|
87
|
+
const title = heading[2].replace(/\s+#+\s*$/, '').trim();
|
|
88
|
+
inPurpose = title.toLowerCase() === 'purpose';
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (inPurpose && line.trim().length > 0) {
|
|
92
|
+
return line.trim();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return '';
|
|
96
|
+
}
|
|
97
|
+
async function collectSpecEntries(referencedRoot) {
|
|
98
|
+
const specIds = await getSpecIds(referencedRoot);
|
|
99
|
+
return Promise.all(specIds.map(async (specId) => {
|
|
100
|
+
let summary = '';
|
|
101
|
+
try {
|
|
102
|
+
const content = await fs.readFile(path.join(referencedRoot, 'openspec', 'specs', specId, 'spec.md'), 'utf-8');
|
|
103
|
+
summary = sanitizeInline(extractFirstPurposeLine(content));
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Unreadable spec file: index the id with an empty summary.
|
|
107
|
+
}
|
|
108
|
+
return { id: specId, summary };
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
export function fetchRecipe(storeId) {
|
|
112
|
+
return `openspec show <spec-id> --type spec --store ${storeId}`;
|
|
113
|
+
}
|
|
114
|
+
function specLine(spec) {
|
|
115
|
+
// Ids are raw directory names from cloned content; summaries are
|
|
116
|
+
// sanitized at index time (collectSpecEntries).
|
|
117
|
+
const id = sanitizeInline(spec.id, 100);
|
|
118
|
+
return spec.summary ? ` - ${id}: ${spec.summary}` : ` - ${id}`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Pure renderer for the artifact-instructions XML block. Also the byte
|
|
122
|
+
* budget's measuring stick (it is the larger rendering).
|
|
123
|
+
*/
|
|
124
|
+
export function renderReferencedStoresBlock(entries) {
|
|
125
|
+
const lines = [
|
|
126
|
+
'<referenced_stores>',
|
|
127
|
+
'<!-- Read-only upstream context. Fetch what you need; cite what you use. -->',
|
|
128
|
+
];
|
|
129
|
+
for (const entry of entries) {
|
|
130
|
+
lines.push(...renderEntryLines(entry));
|
|
131
|
+
}
|
|
132
|
+
lines.push('</referenced_stores>');
|
|
133
|
+
return lines.join('\n');
|
|
134
|
+
}
|
|
135
|
+
/** Pure renderer for the apply-instructions markdown section. */
|
|
136
|
+
export function renderReferencedStoresSection(entries) {
|
|
137
|
+
const lines = [
|
|
138
|
+
'### Referenced Stores',
|
|
139
|
+
'',
|
|
140
|
+
'Read-only upstream context. Fetch what you need; cite what you use.',
|
|
141
|
+
'',
|
|
142
|
+
];
|
|
143
|
+
for (const entry of entries) {
|
|
144
|
+
lines.push(...renderEntryLines(entry));
|
|
145
|
+
}
|
|
146
|
+
return lines.join('\n');
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Strings rendered into agent guidance can come from cloned content
|
|
150
|
+
* (spec directory names, Purpose lines, config-declared remotes). One
|
|
151
|
+
* line in, one line out: control characters and newlines must never
|
|
152
|
+
* let hostile content forge instruction lines (slice 6.1 hardening).
|
|
153
|
+
*/
|
|
154
|
+
export function sanitizeInline(value, maxLength = 300) {
|
|
155
|
+
// eslint-disable-next-line no-control-regex
|
|
156
|
+
const flattened = value.replace(/[\u0000-\u001f\u007f]+/g, ' ').trim();
|
|
157
|
+
return flattened.length > maxLength ? `${flattened.slice(0, maxLength)}…` : flattened;
|
|
158
|
+
}
|
|
159
|
+
function renderEntryLines(entry) {
|
|
160
|
+
const lines = [];
|
|
161
|
+
if (entry.root !== undefined) {
|
|
162
|
+
lines.push(`Store ${entry.store_id} (${entry.root}):`);
|
|
163
|
+
for (const spec of entry.specs ?? []) {
|
|
164
|
+
lines.push(specLine(spec));
|
|
165
|
+
}
|
|
166
|
+
if (entry.fetch) {
|
|
167
|
+
lines.push(` Fetch: ${entry.fetch}`);
|
|
168
|
+
}
|
|
169
|
+
// Diagnostics on a resolved entry (e.g. truncation) render message
|
|
170
|
+
// AND fix — an orphan fix line would hide that the list is partial.
|
|
171
|
+
for (const diagnostic of entry.status) {
|
|
172
|
+
lines.push(` Note: ${diagnostic.message}`);
|
|
173
|
+
if (diagnostic.fix) {
|
|
174
|
+
lines.push(` Fix: ${diagnostic.fix}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
for (const diagnostic of entry.status) {
|
|
180
|
+
lines.push(`Store ${entry.store_id}: ${diagnostic.message}`);
|
|
181
|
+
if (diagnostic.fix) {
|
|
182
|
+
lines.push(` Fix: ${diagnostic.fix}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return lines;
|
|
187
|
+
}
|
|
188
|
+
function renderedByteSize(entries) {
|
|
189
|
+
return Buffer.byteLength(renderReferencedStoresBlock(entries), 'utf-8');
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Builds the referenced-store index. One registry read per call; one
|
|
193
|
+
* level deep (a referenced store's own references are never followed);
|
|
194
|
+
* self-references omitted; every failure degrades to a warning entry.
|
|
195
|
+
*/
|
|
196
|
+
export async function assembleReferenceIndex(input) {
|
|
197
|
+
const declarations = input.references;
|
|
198
|
+
if (declarations.length === 0) {
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
// null means the registry itself was unreadable (corrupt file).
|
|
202
|
+
let registryEntries;
|
|
203
|
+
if (input.registryEntries !== undefined) {
|
|
204
|
+
registryEntries = input.registryEntries;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
try {
|
|
208
|
+
const registry = await readStoreRegistryState(input.globalDataDir ? { globalDataDir: input.globalDataDir } : {});
|
|
209
|
+
registryEntries = registry ? listStoreRegistryEntries(registry) : [];
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
registryEntries = null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const includeSpecs = input.includeSpecs !== false;
|
|
216
|
+
const resolvedRootPath = FileSystemUtils.canonicalizeExistingPath(input.resolvedRoot.path);
|
|
217
|
+
const entries = [];
|
|
218
|
+
for (const { id, remote } of declarations) {
|
|
219
|
+
// Registry-independent checks come first: an invalid id is an
|
|
220
|
+
// invalid id (and a self-reference is omittable) even when the
|
|
221
|
+
// registry is corrupt. The declared remote is only consulted after
|
|
222
|
+
// the id passes grammar.
|
|
223
|
+
if (!isValidStoreId(id)) {
|
|
224
|
+
entries.push({
|
|
225
|
+
store_id: id,
|
|
226
|
+
status: [
|
|
227
|
+
warning('reference_invalid_id', `Reference '${id}' is not a valid store id.`, 'Use kebab-case store ids in the references list.'),
|
|
228
|
+
],
|
|
229
|
+
});
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (input.resolvedRoot.storeId === id) {
|
|
233
|
+
continue; // Self-reference: meaningless, silently omitted.
|
|
234
|
+
}
|
|
235
|
+
if (registryEntries === null) {
|
|
236
|
+
entries.push({
|
|
237
|
+
store_id: id,
|
|
238
|
+
status: [
|
|
239
|
+
warning('reference_registry_unreadable', `Referenced store '${id}' cannot be checked: the store registry is unreadable.`, 'Run: openspec store doctor'),
|
|
240
|
+
],
|
|
241
|
+
});
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const registryEntry = registryEntries.find((candidate) => candidate.id === id);
|
|
245
|
+
if (!registryEntry) {
|
|
246
|
+
entries.push({
|
|
247
|
+
store_id: id,
|
|
248
|
+
status: [
|
|
249
|
+
warning('reference_unresolved', `Referenced store '${id}' is not registered on this machine.`, registerFix(id, remote)),
|
|
250
|
+
],
|
|
251
|
+
});
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
let inspection;
|
|
255
|
+
try {
|
|
256
|
+
const storeRoot = getStoreRootForBackend(registryEntry.backend);
|
|
257
|
+
inspection = await inspectRegisteredStore(id, storeRoot);
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
inspection = { kind: 'inspection_error', error };
|
|
261
|
+
}
|
|
262
|
+
if (inspection.kind !== 'ok') {
|
|
263
|
+
entries.push({
|
|
264
|
+
store_id: id,
|
|
265
|
+
status: [
|
|
266
|
+
warning('reference_root_unhealthy', `Referenced store '${id}' is registered but not usable (${inspection.kind.replace(/_/g, ' ')}).`, `Run: openspec store doctor ${id}`),
|
|
267
|
+
],
|
|
268
|
+
});
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (inspection.canonicalRoot === resolvedRootPath) {
|
|
272
|
+
continue; // Self-reference by path: silently omitted.
|
|
273
|
+
}
|
|
274
|
+
if (!includeSpecs) {
|
|
275
|
+
// Health mode: resolution facts only — no content, no budget.
|
|
276
|
+
entries.push({ store_id: id, root: inspection.canonicalRoot, status: [] });
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const specs = await collectSpecEntries(inspection.canonicalRoot);
|
|
280
|
+
const entry = {
|
|
281
|
+
store_id: id,
|
|
282
|
+
root: inspection.canonicalRoot,
|
|
283
|
+
specs,
|
|
284
|
+
fetch: fetchRecipe(id),
|
|
285
|
+
status: [],
|
|
286
|
+
};
|
|
287
|
+
// Budget the real rendering: keep the longest spec-list prefix whose
|
|
288
|
+
// full rendered index stays under the cap. The truncation warning
|
|
289
|
+
// itself is exempt (added after the size decision — no oscillation).
|
|
290
|
+
entries.push(entry);
|
|
291
|
+
if (renderedByteSize(entries) > MAX_RENDERED_INDEX_SIZE) {
|
|
292
|
+
let low = 0;
|
|
293
|
+
let high = specs.length;
|
|
294
|
+
while (low < high) {
|
|
295
|
+
const mid = Math.ceil((low + high) / 2);
|
|
296
|
+
entry.specs = specs.slice(0, mid);
|
|
297
|
+
if (renderedByteSize(entries) > MAX_RENDERED_INDEX_SIZE) {
|
|
298
|
+
high = mid - 1;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
low = mid;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
entry.specs = specs.slice(0, low);
|
|
305
|
+
entry.status.push(warning('reference_index_truncated', `Referenced store '${id}' index truncated at the 50KB budget (${low} of ${specs.length} specs listed).`, `List the rest directly: openspec list --specs --store ${id}`));
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return entries;
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=references.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relationship health composition (slice 3.6).
|
|
3
|
+
*
|
|
4
|
+
* One read-only answer to "are the roots this work relates to available
|
|
5
|
+
* on this machine?" — pure composition over inputs the doctor command
|
|
6
|
+
* gathers. The lock's four categories stay separated: root health,
|
|
7
|
+
* store metadata health, and reference health. Nothing here (or
|
|
8
|
+
* downstream) clones, syncs, or repairs.
|
|
9
|
+
*/
|
|
10
|
+
import { type StoreDiagnostic } from './store/errors.js';
|
|
11
|
+
import { type ReferenceIndexEntry } from './references.js';
|
|
12
|
+
import { type ResolvedOpenSpecRoot } from './root-selection.js';
|
|
13
|
+
export interface RelationshipHealth {
|
|
14
|
+
root: {
|
|
15
|
+
path: string;
|
|
16
|
+
source: ResolvedOpenSpecRoot['source'];
|
|
17
|
+
store_id?: string;
|
|
18
|
+
healthy: boolean;
|
|
19
|
+
status: StoreDiagnostic[];
|
|
20
|
+
};
|
|
21
|
+
store: {
|
|
22
|
+
id: string;
|
|
23
|
+
metadata: {
|
|
24
|
+
present: boolean;
|
|
25
|
+
valid: boolean;
|
|
26
|
+
remote?: string;
|
|
27
|
+
};
|
|
28
|
+
origin_url?: string;
|
|
29
|
+
status: StoreDiagnostic[];
|
|
30
|
+
} | null;
|
|
31
|
+
references: ReferenceIndexEntry[];
|
|
32
|
+
status: StoreDiagnostic[];
|
|
33
|
+
}
|
|
34
|
+
export interface InspectRelationshipsInput {
|
|
35
|
+
root: ResolvedOpenSpecRoot;
|
|
36
|
+
rootHealthy: boolean;
|
|
37
|
+
rootStatus?: StoreDiagnostic[];
|
|
38
|
+
/** Store facts for store-backed roots (explicit or declared). */
|
|
39
|
+
storeFacts?: {
|
|
40
|
+
id: string;
|
|
41
|
+
metadataPresent: boolean;
|
|
42
|
+
metadataValid: boolean;
|
|
43
|
+
canonicalRemote?: string;
|
|
44
|
+
originUrl?: string;
|
|
45
|
+
};
|
|
46
|
+
referenceEntries: ReferenceIndexEntry[];
|
|
47
|
+
registryUnreadable: boolean;
|
|
48
|
+
/** A real root whose config also declares a store: pointer (3.2). */
|
|
49
|
+
bothShapesPointer?: {
|
|
50
|
+
value: string;
|
|
51
|
+
filePath: string;
|
|
52
|
+
};
|
|
53
|
+
/** A real root whose store: pointer value is malformed (3.2). */
|
|
54
|
+
malformedPointer?: {
|
|
55
|
+
filePath: string;
|
|
56
|
+
reason: 'unparseable' | 'non_string';
|
|
57
|
+
};
|
|
58
|
+
/** Reference declarations in a pointer directory's own config are inert. */
|
|
59
|
+
inertPointerDeclarations?: {
|
|
60
|
+
filePath: string;
|
|
61
|
+
fields: string[];
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export declare function inspectRelationships(input: InspectRelationshipsInput): RelationshipHealth;
|
|
65
|
+
//# sourceMappingURL=relationship-health.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relationship health composition (slice 3.6).
|
|
3
|
+
*
|
|
4
|
+
* One read-only answer to "are the roots this work relates to available
|
|
5
|
+
* on this machine?" — pure composition over inputs the doctor command
|
|
6
|
+
* gathers. The lock's four categories stay separated: root health,
|
|
7
|
+
* store metadata health, and reference health. Nothing here (or
|
|
8
|
+
* downstream) clones, syncs, or repairs.
|
|
9
|
+
*/
|
|
10
|
+
import { makeStoreDiagnostic } from './store/errors.js';
|
|
11
|
+
import { sanitizeInline } from './references.js';
|
|
12
|
+
import { storePointerProblem } from './project-config.js';
|
|
13
|
+
import { toRootOutput } from './root-selection.js';
|
|
14
|
+
function warning(code, message, fix) {
|
|
15
|
+
return makeStoreDiagnostic('warning', code, message, { target: 'relationships', fix });
|
|
16
|
+
}
|
|
17
|
+
export function inspectRelationships(input) {
|
|
18
|
+
const status = [];
|
|
19
|
+
if (input.registryUnreadable) {
|
|
20
|
+
status.push(warning('relationship_registry_unreadable', 'The store registry is unreadable; reference health cannot be checked.', 'Run: openspec store doctor'));
|
|
21
|
+
}
|
|
22
|
+
if (input.bothShapesPointer) {
|
|
23
|
+
status.push(warning('root_pointer_ignored', `${input.bothShapesPointer.filePath} declares store '${input.bothShapesPointer.value}', but this directory is a real OpenSpec root; the declaration is ignored.`, `Remove the store: line from ${input.bothShapesPointer.filePath}, or move the planning files into the store.`));
|
|
24
|
+
}
|
|
25
|
+
if (input.malformedPointer) {
|
|
26
|
+
status.push(warning('root_pointer_invalid', `${input.malformedPointer.filePath} declares a store: pointer that cannot be used (${storePointerProblem(input.malformedPointer.reason)}).`, `Fix or remove the store: line in ${input.malformedPointer.filePath}.`));
|
|
27
|
+
}
|
|
28
|
+
if (input.inertPointerDeclarations && input.inertPointerDeclarations.fields.length > 0) {
|
|
29
|
+
status.push(warning('pointer_declarations_inert', `${input.inertPointerDeclarations.filePath} declares ${input.inertPointerDeclarations.fields.join(' and ')}, but commands read the resolved store's config — these declarations are inert.`, `Move the ${input.inertPointerDeclarations.fields.join('/')} declarations into the store's openspec/config.yaml.`));
|
|
30
|
+
}
|
|
31
|
+
// Store section: metadata facts + the divergence info note.
|
|
32
|
+
let store = null;
|
|
33
|
+
if (input.storeFacts) {
|
|
34
|
+
const storeStatus = [];
|
|
35
|
+
if (input.storeFacts.canonicalRemote &&
|
|
36
|
+
input.storeFacts.originUrl &&
|
|
37
|
+
input.storeFacts.canonicalRemote !== input.storeFacts.originUrl) {
|
|
38
|
+
storeStatus.push(makeStoreDiagnostic('info', 'store_remote_divergence', `The store.yaml remote (${sanitizeInline(input.storeFacts.canonicalRemote, 200)}) differs from the checkout's origin (${sanitizeInline(input.storeFacts.originUrl, 200)}).`, { target: 'store.metadata' }));
|
|
39
|
+
}
|
|
40
|
+
store = {
|
|
41
|
+
id: input.storeFacts.id,
|
|
42
|
+
metadata: {
|
|
43
|
+
present: input.storeFacts.metadataPresent,
|
|
44
|
+
valid: input.storeFacts.metadataValid,
|
|
45
|
+
...(input.storeFacts.canonicalRemote
|
|
46
|
+
? { remote: input.storeFacts.canonicalRemote }
|
|
47
|
+
: {}),
|
|
48
|
+
},
|
|
49
|
+
...(input.storeFacts.originUrl ? { origin_url: input.storeFacts.originUrl } : {}),
|
|
50
|
+
status: storeStatus,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
root: {
|
|
55
|
+
...toRootOutput(input.root),
|
|
56
|
+
healthy: input.rootHealthy,
|
|
57
|
+
status: input.rootStatus ?? [],
|
|
58
|
+
},
|
|
59
|
+
store,
|
|
60
|
+
references: input.referenceEntries,
|
|
61
|
+
status,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=relationship-health.js.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared OpenSpec root resolution for normal commands.
|
|
3
|
+
*
|
|
4
|
+
* Normal commands (`new change`, `status`, `instructions`, `list`, `show`,
|
|
5
|
+
* `validate`, `archive`) resolve one OpenSpec root through this module:
|
|
6
|
+
*
|
|
7
|
+
* - `--store <id>` selects a registered store's root.
|
|
8
|
+
* - Without `--store`, the nearest ancestor containing `openspec/` wins.
|
|
9
|
+
* Leftover workspace view state is never considered a root here.
|
|
10
|
+
* - With no nearest root, registered stores produce a selection hint error;
|
|
11
|
+
* otherwise commands may treat the current directory as an implicit root.
|
|
12
|
+
*
|
|
13
|
+
* Diagnostic codes reuse the store taxonomy where an error passes
|
|
14
|
+
* through unchanged (`invalid_store_id`, metadata parse failures);
|
|
15
|
+
* resolver-specific failures use the normal-command codes below
|
|
16
|
+
* (`unknown_store`, `no_registered_stores`, `store_identity_mismatch`,
|
|
17
|
+
* `unhealthy_store_root`, `store_path_not_supported`,
|
|
18
|
+
* `invalid_store_pointer`, `no_root_with_registered_stores`,
|
|
19
|
+
* `no_openspec_root`).
|
|
20
|
+
*/
|
|
21
|
+
import { type PlanningHome } from './planning-home.js';
|
|
22
|
+
export type OpenSpecRootSource = 'store' | 'declared' | 'nearest' | 'implicit';
|
|
23
|
+
export interface StoreSelectorOptions {
|
|
24
|
+
store?: string;
|
|
25
|
+
storePath?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ResolveOpenSpecRootOptions extends StoreSelectorOptions {
|
|
28
|
+
startPath?: string;
|
|
29
|
+
allowImplicitRoot?: boolean;
|
|
30
|
+
globalDataDir?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ResolvedOpenSpecRoot {
|
|
33
|
+
path: string;
|
|
34
|
+
changesDir: string;
|
|
35
|
+
specsDir: string;
|
|
36
|
+
archiveDir: string;
|
|
37
|
+
defaultSchema: 'spec-driven';
|
|
38
|
+
source: OpenSpecRootSource;
|
|
39
|
+
storeId?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface RootSelectionDiagnostic {
|
|
42
|
+
severity: 'error';
|
|
43
|
+
code: string;
|
|
44
|
+
message: string;
|
|
45
|
+
target?: string;
|
|
46
|
+
fix?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare class RootSelectionError extends Error {
|
|
49
|
+
readonly diagnostic: RootSelectionDiagnostic;
|
|
50
|
+
constructor(message: string, code: string, options?: {
|
|
51
|
+
target?: string;
|
|
52
|
+
fix?: string;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
export declare function isRootSelectionError(error: unknown): error is RootSelectionError;
|
|
56
|
+
/**
|
|
57
|
+
* The metadata-identity and root-health stages of registered-store
|
|
58
|
+
* resolution, as a non-throwing result. `resolveStoreRoot` maps each
|
|
59
|
+
* failure kind to its established error; the reference index assembler
|
|
60
|
+
* maps them to warnings. One shared inspection path — never fork it.
|
|
61
|
+
*/
|
|
62
|
+
export type RegisteredStoreInspection = {
|
|
63
|
+
kind: 'ok';
|
|
64
|
+
canonicalRoot: string;
|
|
65
|
+
} | {
|
|
66
|
+
kind: 'metadata_error';
|
|
67
|
+
error: unknown;
|
|
68
|
+
} | {
|
|
69
|
+
kind: 'metadata_missing';
|
|
70
|
+
metadataPath: string;
|
|
71
|
+
} | {
|
|
72
|
+
kind: 'metadata_id_mismatch';
|
|
73
|
+
actualId: string;
|
|
74
|
+
} | {
|
|
75
|
+
kind: 'unhealthy_root';
|
|
76
|
+
problems: string;
|
|
77
|
+
};
|
|
78
|
+
export declare function inspectRegisteredStore(id: string, storeRoot: string): Promise<RegisteredStoreInspection>;
|
|
79
|
+
export declare function resolveOpenSpecRoot(options?: ResolveOpenSpecRootOptions): Promise<ResolvedOpenSpecRoot>;
|
|
80
|
+
export interface RootOutput {
|
|
81
|
+
path: string;
|
|
82
|
+
source: OpenSpecRootSource;
|
|
83
|
+
store_id?: string;
|
|
84
|
+
}
|
|
85
|
+
export declare function toRootOutput(root: ResolvedOpenSpecRoot): RootOutput;
|
|
86
|
+
/**
|
|
87
|
+
* A store-selected root — explicit `--store` or the declared fallback.
|
|
88
|
+
* Cross-root behavior (absolute paths, --store hints, suppressed
|
|
89
|
+
* noun-form suggestions) keys on this, never on `source` directly.
|
|
90
|
+
*/
|
|
91
|
+
export declare function isStoreSelectedRoot(root: ResolvedOpenSpecRoot): root is ResolvedOpenSpecRoot & {
|
|
92
|
+
storeId: string;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Human-mode verification signal for a selected store. Written to stderr so
|
|
96
|
+
* raw-Markdown and agent-consumed stdout payloads stay clean.
|
|
97
|
+
*/
|
|
98
|
+
export declare function emitStoreRootBanner(root: ResolvedOpenSpecRoot): void;
|
|
99
|
+
/**
|
|
100
|
+
* Keeps follow-up command hints inside the selected store: a hint a user can
|
|
101
|
+
* paste verbatim must carry `--store <id>` when a store was selected.
|
|
102
|
+
*/
|
|
103
|
+
export declare function withStoreFlag(root: ResolvedOpenSpecRoot, command: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* Compatibility bridge for workflow code that still expects a PlanningHome.
|
|
106
|
+
* The planning home is always repo-shaped.
|
|
107
|
+
*/
|
|
108
|
+
export declare function toPlanningHome(root: ResolvedOpenSpecRoot): PlanningHome;
|
|
109
|
+
/**
|
|
110
|
+
* CLI adapter shared by the supported commands. In JSON mode a resolution
|
|
111
|
+
* failure is reported as a machine-readable payload on stdout (no human prose
|
|
112
|
+
* or blank lines) with a non-zero exit code; the caller must return when this
|
|
113
|
+
* resolves to null. In human mode the error propagates to the command's
|
|
114
|
+
* standard error handling so message text and exit behavior stay consistent.
|
|
115
|
+
*/
|
|
116
|
+
export declare function resolveRootForCommand(selector: StoreSelectorOptions, output?: {
|
|
117
|
+
json?: boolean;
|
|
118
|
+
failurePayload?: Record<string, unknown>;
|
|
119
|
+
/** Diagnostic commands inspect what exists; they never scaffold. */
|
|
120
|
+
allowImplicitRoot?: boolean;
|
|
121
|
+
}): Promise<ResolvedOpenSpecRoot | null>;
|
|
122
|
+
//# sourceMappingURL=root-selection.d.ts.map
|