diff --git a/.github/prompts/opsx-apply.prompt.md b/.github/prompts/opsx-apply.prompt.md index e23ec64d14..cb53869ecc 100644 --- a/.github/prompts/opsx-apply.prompt.md +++ b/.github/prompts/opsx-apply.prompt.md @@ -23,6 +23,7 @@ Implement tasks from an OpenSpec change. ``` Parse the JSON to understand: - `schemaName`: The workflow being used (e.g., "spec-driven") + - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) 3. **Get apply instructions** @@ -42,6 +43,8 @@ Implement tasks from an OpenSpec change. - If `state: "all_done"`: congratulate, suggest archive - Otherwise: proceed to implementation + **Workspace guard:** If status JSON reports `actionContext.mode: "workspace-planning"` and `allowedEditRoots` is empty, explain that full workspace apply is not supported in this slice. Treat linked repos and folders as read-only context, ask the user to select an affected area through an explicit implementation workflow, and STOP before editing files. + 4. **Read context files** Read every file path listed under `contextFiles` from the apply instructions output. diff --git a/.github/prompts/opsx-archive.prompt.md b/.github/prompts/opsx-archive.prompt.md index 1163776da4..b30dcd0e7c 100644 --- a/.github/prompts/opsx-archive.prompt.md +++ b/.github/prompts/opsx-archive.prompt.md @@ -23,8 +23,11 @@ Archive a completed change in the experimental workflow. Parse the JSON to understand: - `schemaName`: The workflow being used + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context - `artifacts`: List of artifacts with their status (`done` or other) + If status reports `actionContext.mode: "workspace-planning"`, explain that workspace archive is not supported in this slice and STOP. Do not move workspace changes into repo-local archives or edit linked repos. + **If any artifacts are not `done`:** - Display warning listing incomplete artifacts - Prompt user for confirmation to continue @@ -45,7 +48,7 @@ Archive a completed change in the experimental workflow. 4. **Assess delta spec sync state** - Check for delta specs at `openspec/changes//specs/`. If none exist, proceed without sync prompt. + Use `artifactPaths.specs.existingOutputPaths` from status JSON to check for delta specs. If none exist, proceed without sync prompt. **If delta specs exist:** - Compare each delta spec with its corresponding main spec at `openspec/specs//spec.md` @@ -60,19 +63,19 @@ Archive a completed change in the experimental workflow. 5. **Perform the archive** - Create the archive directory if it doesn't exist: + Create an `archive` directory under `planningHome.changesDir` if it doesn't exist: ```bash - mkdir -p openspec/changes/archive + mkdir -p "/archive" ``` Generate target name using current date: `YYYY-MM-DD-` **Check if target already exists:** - If yes: Fail with error, suggest renaming existing archive or using different date - - If no: Move the change directory to archive + - If no: Move `changeRoot` to the archive directory ```bash - mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD- + mv "" "/archive/YYYY-MM-DD-" ``` 6. **Display summary** @@ -91,7 +94,7 @@ Archive a completed change in the experimental workflow. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** ✓ Synced to main specs All artifacts complete. All tasks complete. @@ -104,7 +107,7 @@ All artifacts complete. All tasks complete. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** No delta specs All artifacts complete. All tasks complete. @@ -117,7 +120,7 @@ All artifacts complete. All tasks complete. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** Sync skipped (user chose to skip) **Warnings:** @@ -134,7 +137,7 @@ Review the archive if this was not intentional. ## Archive Failed **Change:** -**Target:** openspec/changes/archive/YYYY-MM-DD-/ +**Target:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ Target archive directory already exists. diff --git a/.github/prompts/opsx-explore.prompt.md b/.github/prompts/opsx-explore.prompt.md index 3b674ebb57..32ec8d2e28 100644 --- a/.github/prompts/opsx-explore.prompt.md +++ b/.github/prompts/opsx-explore.prompt.md @@ -104,11 +104,10 @@ Think freely. When insights crystallize, you might offer: If the user mentions a change or you detect one is relevant: -1. **Read existing artifacts for context** - - `openspec/changes//proposal.md` - - `openspec/changes//design.md` - - `openspec/changes//tasks.md` - - etc. +1. **Resolve and read existing artifacts for context** + - Run `openspec status --change "" --json`. + - Use `changeRoot`, `artifactPaths`, and `actionContext` from the status JSON. + - Read existing files from `artifactPaths..existingOutputPaths`. 2. **Reference them naturally in conversation** - "Your design mentions using Redis, but we just realized SQLite fits better..." diff --git a/.github/prompts/opsx-propose.prompt.md b/.github/prompts/opsx-propose.prompt.md index cf30b2a550..30bd6fd5bb 100644 --- a/.github/prompts/opsx-propose.prompt.md +++ b/.github/prompts/opsx-propose.prompt.md @@ -30,7 +30,7 @@ When ready to implement, run /opsx:apply ```bash openspec new change "" ``` - This creates a scaffolded change at `openspec/changes//` with `.openspec.yaml`. + This creates a scaffolded change in the planning home resolved by the CLI with `.openspec.yaml`. 3. **Get the artifact build order** ```bash @@ -39,6 +39,7 @@ When ready to implement, run /opsx:apply Parse the JSON to get: - `applyRequires`: array of artifact IDs needed before implementation (e.g., `["tasks"]`) - `artifacts`: list of all artifacts with their status and dependencies + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context. Use these instead of assuming repo-local paths. 4. **Create artifacts in sequence until apply-ready** @@ -56,10 +57,10 @@ When ready to implement, run /opsx:apply - `rules`: Artifact-specific rules (constraints for you - do NOT include in output) - `template`: The structure to use for your output file - `instruction`: Schema-specific guidance for this artifact type - - `outputPath`: Where to write the artifact + - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read for context - Read any completed dependency files for context - - Create the artifact file using `template` as the structure + - Create the artifact file using `template` as the structure and write it to `resolvedOutputPath` - Apply `context` and `rules` as constraints - but do NOT copy them into the file - Show brief progress: "Created " diff --git a/.github/skills/openspec-apply-change/SKILL.md b/.github/skills/openspec-apply-change/SKILL.md index 70fbdb8569..db4d8ce2a8 100644 --- a/.github/skills/openspec-apply-change/SKILL.md +++ b/.github/skills/openspec-apply-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Implement tasks from an OpenSpec change. @@ -30,6 +30,7 @@ Implement tasks from an OpenSpec change. ``` Parse the JSON to understand: - `schemaName`: The workflow being used (e.g., "spec-driven") + - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) 3. **Get apply instructions** @@ -49,6 +50,8 @@ Implement tasks from an OpenSpec change. - If `state: "all_done"`: congratulate, suggest archive - Otherwise: proceed to implementation + **Workspace guard:** If status JSON reports `actionContext.mode: "workspace-planning"` and `allowedEditRoots` is empty, explain that full workspace apply is not supported in this slice. Treat linked repos and folders as read-only context, ask the user to select an affected area through an explicit implementation workflow, and STOP before editing files. + 4. **Read context files** Read every file path listed under `contextFiles` from the apply instructions output. diff --git a/.github/skills/openspec-archive-change/SKILL.md b/.github/skills/openspec-archive-change/SKILL.md index 12e2f70e9c..97c3e5e3a4 100644 --- a/.github/skills/openspec-archive-change/SKILL.md +++ b/.github/skills/openspec-archive-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Archive a completed change in the experimental workflow. @@ -30,8 +30,11 @@ Archive a completed change in the experimental workflow. Parse the JSON to understand: - `schemaName`: The workflow being used + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context - `artifacts`: List of artifacts with their status (`done` or other) + If status reports `actionContext.mode: "workspace-planning"`, explain that workspace archive is not supported in this slice and STOP. Do not move workspace changes into repo-local archives or edit linked repos. + **If any artifacts are not `done`:** - Display warning listing incomplete artifacts - Use **AskUserQuestion tool** to confirm user wants to proceed @@ -52,7 +55,7 @@ Archive a completed change in the experimental workflow. 4. **Assess delta spec sync state** - Check for delta specs at `openspec/changes//specs/`. If none exist, proceed without sync prompt. + Use `artifactPaths.specs.existingOutputPaths` from status JSON to check for delta specs. If none exist, proceed without sync prompt. **If delta specs exist:** - Compare each delta spec with its corresponding main spec at `openspec/specs//spec.md` @@ -67,19 +70,19 @@ Archive a completed change in the experimental workflow. 5. **Perform the archive** - Create the archive directory if it doesn't exist: + Create an `archive` directory under `planningHome.changesDir` if it doesn't exist: ```bash - mkdir -p openspec/changes/archive + mkdir -p "/archive" ``` Generate target name using current date: `YYYY-MM-DD-` **Check if target already exists:** - If yes: Fail with error, suggest renaming existing archive or using different date - - If no: Move the change directory to archive + - If no: Move `changeRoot` to the archive directory ```bash - mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD- + mv "" "/archive/YYYY-MM-DD-" ``` 6. **Display summary** @@ -98,7 +101,7 @@ Archive a completed change in the experimental workflow. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** ✓ Synced to main specs (or "No delta specs" or "Sync skipped") All artifacts complete. All tasks complete. diff --git a/.github/skills/openspec-explore/SKILL.md b/.github/skills/openspec-explore/SKILL.md index 6858d3f693..1e97aaa81f 100644 --- a/.github/skills/openspec-explore/SKILL.md +++ b/.github/skills/openspec-explore/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. @@ -102,11 +102,10 @@ Think freely. When insights crystallize, you might offer: If the user mentions a change or you detect one is relevant: -1. **Read existing artifacts for context** - - `openspec/changes//proposal.md` - - `openspec/changes//design.md` - - `openspec/changes//tasks.md` - - etc. +1. **Resolve and read existing artifacts for context** + - Run `openspec status --change "" --json`. + - Use `changeRoot`, `artifactPaths`, and `actionContext` from the status JSON. + - Read existing files from `artifactPaths..existingOutputPaths`. 2. **Reference them naturally in conversation** - "Your design mentions using Redis, but we just realized SQLite fits better..." diff --git a/.github/skills/openspec-propose/SKILL.md b/.github/skills/openspec-propose/SKILL.md index 4b7e204184..9fc85139aa 100644 --- a/.github/skills/openspec-propose/SKILL.md +++ b/.github/skills/openspec-propose/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Propose a new change - create the change and generate all artifacts in one step. @@ -37,7 +37,7 @@ When ready to implement, run /opsx:apply ```bash openspec new change "" ``` - This creates a scaffolded change at `openspec/changes//` with `.openspec.yaml`. + This creates a scaffolded change in the planning home resolved by the CLI with `.openspec.yaml`. 3. **Get the artifact build order** ```bash @@ -46,6 +46,7 @@ When ready to implement, run /opsx:apply Parse the JSON to get: - `applyRequires`: array of artifact IDs needed before implementation (e.g., `["tasks"]`) - `artifacts`: list of all artifacts with their status and dependencies + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context. Use these instead of assuming repo-local paths. 4. **Create artifacts in sequence until apply-ready** @@ -63,10 +64,10 @@ When ready to implement, run /opsx:apply - `rules`: Artifact-specific rules (constraints for you - do NOT include in output) - `template`: The structure to use for your output file - `instruction`: Schema-specific guidance for this artifact type - - `outputPath`: Where to write the artifact + - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read for context - Read any completed dependency files for context - - Create the artifact file using `template` as the structure + - Create the artifact file using `template` as the structure and write it to `resolvedOutputPath` - Apply `context` and `rules` as constraints - but do NOT copy them into the file - Show brief progress: "Created " diff --git a/.kilocode/skills/openspec-apply-change/SKILL.md b/.kilocode/skills/openspec-apply-change/SKILL.md index 70fbdb8569..db4d8ce2a8 100644 --- a/.kilocode/skills/openspec-apply-change/SKILL.md +++ b/.kilocode/skills/openspec-apply-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Implement tasks from an OpenSpec change. @@ -30,6 +30,7 @@ Implement tasks from an OpenSpec change. ``` Parse the JSON to understand: - `schemaName`: The workflow being used (e.g., "spec-driven") + - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) 3. **Get apply instructions** @@ -49,6 +50,8 @@ Implement tasks from an OpenSpec change. - If `state: "all_done"`: congratulate, suggest archive - Otherwise: proceed to implementation + **Workspace guard:** If status JSON reports `actionContext.mode: "workspace-planning"` and `allowedEditRoots` is empty, explain that full workspace apply is not supported in this slice. Treat linked repos and folders as read-only context, ask the user to select an affected area through an explicit implementation workflow, and STOP before editing files. + 4. **Read context files** Read every file path listed under `contextFiles` from the apply instructions output. diff --git a/.kilocode/skills/openspec-archive-change/SKILL.md b/.kilocode/skills/openspec-archive-change/SKILL.md index 12e2f70e9c..97c3e5e3a4 100644 --- a/.kilocode/skills/openspec-archive-change/SKILL.md +++ b/.kilocode/skills/openspec-archive-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Archive a completed change in the experimental workflow. @@ -30,8 +30,11 @@ Archive a completed change in the experimental workflow. Parse the JSON to understand: - `schemaName`: The workflow being used + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context - `artifacts`: List of artifacts with their status (`done` or other) + If status reports `actionContext.mode: "workspace-planning"`, explain that workspace archive is not supported in this slice and STOP. Do not move workspace changes into repo-local archives or edit linked repos. + **If any artifacts are not `done`:** - Display warning listing incomplete artifacts - Use **AskUserQuestion tool** to confirm user wants to proceed @@ -52,7 +55,7 @@ Archive a completed change in the experimental workflow. 4. **Assess delta spec sync state** - Check for delta specs at `openspec/changes//specs/`. If none exist, proceed without sync prompt. + Use `artifactPaths.specs.existingOutputPaths` from status JSON to check for delta specs. If none exist, proceed without sync prompt. **If delta specs exist:** - Compare each delta spec with its corresponding main spec at `openspec/specs//spec.md` @@ -67,19 +70,19 @@ Archive a completed change in the experimental workflow. 5. **Perform the archive** - Create the archive directory if it doesn't exist: + Create an `archive` directory under `planningHome.changesDir` if it doesn't exist: ```bash - mkdir -p openspec/changes/archive + mkdir -p "/archive" ``` Generate target name using current date: `YYYY-MM-DD-` **Check if target already exists:** - If yes: Fail with error, suggest renaming existing archive or using different date - - If no: Move the change directory to archive + - If no: Move `changeRoot` to the archive directory ```bash - mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD- + mv "" "/archive/YYYY-MM-DD-" ``` 6. **Display summary** @@ -98,7 +101,7 @@ Archive a completed change in the experimental workflow. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** ✓ Synced to main specs (or "No delta specs" or "Sync skipped") All artifacts complete. All tasks complete. diff --git a/.kilocode/skills/openspec-explore/SKILL.md b/.kilocode/skills/openspec-explore/SKILL.md index 6858d3f693..1e97aaa81f 100644 --- a/.kilocode/skills/openspec-explore/SKILL.md +++ b/.kilocode/skills/openspec-explore/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. @@ -102,11 +102,10 @@ Think freely. When insights crystallize, you might offer: If the user mentions a change or you detect one is relevant: -1. **Read existing artifacts for context** - - `openspec/changes//proposal.md` - - `openspec/changes//design.md` - - `openspec/changes//tasks.md` - - etc. +1. **Resolve and read existing artifacts for context** + - Run `openspec status --change "" --json`. + - Use `changeRoot`, `artifactPaths`, and `actionContext` from the status JSON. + - Read existing files from `artifactPaths..existingOutputPaths`. 2. **Reference them naturally in conversation** - "Your design mentions using Redis, but we just realized SQLite fits better..." diff --git a/.kilocode/skills/openspec-propose/SKILL.md b/.kilocode/skills/openspec-propose/SKILL.md index 4b7e204184..9fc85139aa 100644 --- a/.kilocode/skills/openspec-propose/SKILL.md +++ b/.kilocode/skills/openspec-propose/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Propose a new change - create the change and generate all artifacts in one step. @@ -37,7 +37,7 @@ When ready to implement, run /opsx:apply ```bash openspec new change "" ``` - This creates a scaffolded change at `openspec/changes//` with `.openspec.yaml`. + This creates a scaffolded change in the planning home resolved by the CLI with `.openspec.yaml`. 3. **Get the artifact build order** ```bash @@ -46,6 +46,7 @@ When ready to implement, run /opsx:apply Parse the JSON to get: - `applyRequires`: array of artifact IDs needed before implementation (e.g., `["tasks"]`) - `artifacts`: list of all artifacts with their status and dependencies + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context. Use these instead of assuming repo-local paths. 4. **Create artifacts in sequence until apply-ready** @@ -63,10 +64,10 @@ When ready to implement, run /opsx:apply - `rules`: Artifact-specific rules (constraints for you - do NOT include in output) - `template`: The structure to use for your output file - `instruction`: Schema-specific guidance for this artifact type - - `outputPath`: Where to write the artifact + - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read for context - Read any completed dependency files for context - - Create the artifact file using `template` as the structure + - Create the artifact file using `template` as the structure and write it to `resolvedOutputPath` - Apply `context` and `rules` as constraints - but do NOT copy them into the file - Show brief progress: "Created " diff --git a/.kilocode/workflows/opsx-apply.md b/.kilocode/workflows/opsx-apply.md index a10693a5e2..422724e59a 100644 --- a/.kilocode/workflows/opsx-apply.md +++ b/.kilocode/workflows/opsx-apply.md @@ -19,6 +19,7 @@ Implement tasks from an OpenSpec change. ``` Parse the JSON to understand: - `schemaName`: The workflow being used (e.g., "spec-driven") + - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) 3. **Get apply instructions** @@ -38,6 +39,8 @@ Implement tasks from an OpenSpec change. - If `state: "all_done"`: congratulate, suggest archive - Otherwise: proceed to implementation + **Workspace guard:** If status JSON reports `actionContext.mode: "workspace-planning"` and `allowedEditRoots` is empty, explain that full workspace apply is not supported in this slice. Treat linked repos and folders as read-only context, ask the user to select an affected area through an explicit implementation workflow, and STOP before editing files. + 4. **Read context files** Read every file path listed under `contextFiles` from the apply instructions output. diff --git a/.kilocode/workflows/opsx-archive.md b/.kilocode/workflows/opsx-archive.md index 46def164ca..d7a8850196 100644 --- a/.kilocode/workflows/opsx-archive.md +++ b/.kilocode/workflows/opsx-archive.md @@ -19,8 +19,11 @@ Archive a completed change in the experimental workflow. Parse the JSON to understand: - `schemaName`: The workflow being used + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context - `artifacts`: List of artifacts with their status (`done` or other) + If status reports `actionContext.mode: "workspace-planning"`, explain that workspace archive is not supported in this slice and STOP. Do not move workspace changes into repo-local archives or edit linked repos. + **If any artifacts are not `done`:** - Display warning listing incomplete artifacts - Prompt user for confirmation to continue @@ -41,7 +44,7 @@ Archive a completed change in the experimental workflow. 4. **Assess delta spec sync state** - Check for delta specs at `openspec/changes//specs/`. If none exist, proceed without sync prompt. + Use `artifactPaths.specs.existingOutputPaths` from status JSON to check for delta specs. If none exist, proceed without sync prompt. **If delta specs exist:** - Compare each delta spec with its corresponding main spec at `openspec/specs//spec.md` @@ -56,19 +59,19 @@ Archive a completed change in the experimental workflow. 5. **Perform the archive** - Create the archive directory if it doesn't exist: + Create an `archive` directory under `planningHome.changesDir` if it doesn't exist: ```bash - mkdir -p openspec/changes/archive + mkdir -p "/archive" ``` Generate target name using current date: `YYYY-MM-DD-` **Check if target already exists:** - If yes: Fail with error, suggest renaming existing archive or using different date - - If no: Move the change directory to archive + - If no: Move `changeRoot` to the archive directory ```bash - mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD- + mv "" "/archive/YYYY-MM-DD-" ``` 6. **Display summary** @@ -87,7 +90,7 @@ Archive a completed change in the experimental workflow. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** ✓ Synced to main specs All artifacts complete. All tasks complete. @@ -100,7 +103,7 @@ All artifacts complete. All tasks complete. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** No delta specs All artifacts complete. All tasks complete. @@ -113,7 +116,7 @@ All artifacts complete. All tasks complete. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** Sync skipped (user chose to skip) **Warnings:** @@ -130,7 +133,7 @@ Review the archive if this was not intentional. ## Archive Failed **Change:** -**Target:** openspec/changes/archive/YYYY-MM-DD-/ +**Target:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ Target archive directory already exists. diff --git a/.kilocode/workflows/opsx-explore.md b/.kilocode/workflows/opsx-explore.md index f4debae1a3..6c31efab47 100644 --- a/.kilocode/workflows/opsx-explore.md +++ b/.kilocode/workflows/opsx-explore.md @@ -100,11 +100,10 @@ Think freely. When insights crystallize, you might offer: If the user mentions a change or you detect one is relevant: -1. **Read existing artifacts for context** - - `openspec/changes//proposal.md` - - `openspec/changes//design.md` - - `openspec/changes//tasks.md` - - etc. +1. **Resolve and read existing artifacts for context** + - Run `openspec status --change "" --json`. + - Use `changeRoot`, `artifactPaths`, and `actionContext` from the status JSON. + - Read existing files from `artifactPaths..existingOutputPaths`. 2. **Reference them naturally in conversation** - "Your design mentions using Redis, but we just realized SQLite fits better..." diff --git a/.kilocode/workflows/opsx-propose.md b/.kilocode/workflows/opsx-propose.md index 5085afc97c..e9733e35a6 100644 --- a/.kilocode/workflows/opsx-propose.md +++ b/.kilocode/workflows/opsx-propose.md @@ -26,7 +26,7 @@ When ready to implement, run /opsx:apply ```bash openspec new change "" ``` - This creates a scaffolded change at `openspec/changes//` with `.openspec.yaml`. + This creates a scaffolded change in the planning home resolved by the CLI with `.openspec.yaml`. 3. **Get the artifact build order** ```bash @@ -35,6 +35,7 @@ When ready to implement, run /opsx:apply Parse the JSON to get: - `applyRequires`: array of artifact IDs needed before implementation (e.g., `["tasks"]`) - `artifacts`: list of all artifacts with their status and dependencies + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context. Use these instead of assuming repo-local paths. 4. **Create artifacts in sequence until apply-ready** @@ -52,10 +53,10 @@ When ready to implement, run /opsx:apply - `rules`: Artifact-specific rules (constraints for you - do NOT include in output) - `template`: The structure to use for your output file - `instruction`: Schema-specific guidance for this artifact type - - `outputPath`: Where to write the artifact + - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read for context - Read any completed dependency files for context - - Create the artifact file using `template` as the structure + - Create the artifact file using `template` as the structure and write it to `resolvedOutputPath` - Apply `context` and `rules` as constraints - but do NOT copy them into the file - Show brief progress: "Created " diff --git a/.roo/commands/opsx-apply.md b/.roo/commands/opsx-apply.md index 37a78e612d..30a8841cdc 100644 --- a/.roo/commands/opsx-apply.md +++ b/.roo/commands/opsx-apply.md @@ -23,6 +23,7 @@ Implement tasks from an OpenSpec change. ``` Parse the JSON to understand: - `schemaName`: The workflow being used (e.g., "spec-driven") + - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) 3. **Get apply instructions** @@ -42,6 +43,8 @@ Implement tasks from an OpenSpec change. - If `state: "all_done"`: congratulate, suggest archive - Otherwise: proceed to implementation + **Workspace guard:** If status JSON reports `actionContext.mode: "workspace-planning"` and `allowedEditRoots` is empty, explain that full workspace apply is not supported in this slice. Treat linked repos and folders as read-only context, ask the user to select an affected area through an explicit implementation workflow, and STOP before editing files. + 4. **Read context files** Read every file path listed under `contextFiles` from the apply instructions output. diff --git a/.roo/commands/opsx-archive.md b/.roo/commands/opsx-archive.md index c38d6f6ef9..b0b43a341b 100644 --- a/.roo/commands/opsx-archive.md +++ b/.roo/commands/opsx-archive.md @@ -23,8 +23,11 @@ Archive a completed change in the experimental workflow. Parse the JSON to understand: - `schemaName`: The workflow being used + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context - `artifacts`: List of artifacts with their status (`done` or other) + If status reports `actionContext.mode: "workspace-planning"`, explain that workspace archive is not supported in this slice and STOP. Do not move workspace changes into repo-local archives or edit linked repos. + **If any artifacts are not `done`:** - Display warning listing incomplete artifacts - Prompt user for confirmation to continue @@ -45,7 +48,7 @@ Archive a completed change in the experimental workflow. 4. **Assess delta spec sync state** - Check for delta specs at `openspec/changes//specs/`. If none exist, proceed without sync prompt. + Use `artifactPaths.specs.existingOutputPaths` from status JSON to check for delta specs. If none exist, proceed without sync prompt. **If delta specs exist:** - Compare each delta spec with its corresponding main spec at `openspec/specs//spec.md` @@ -60,19 +63,19 @@ Archive a completed change in the experimental workflow. 5. **Perform the archive** - Create the archive directory if it doesn't exist: + Create an `archive` directory under `planningHome.changesDir` if it doesn't exist: ```bash - mkdir -p openspec/changes/archive + mkdir -p "/archive" ``` Generate target name using current date: `YYYY-MM-DD-` **Check if target already exists:** - If yes: Fail with error, suggest renaming existing archive or using different date - - If no: Move the change directory to archive + - If no: Move `changeRoot` to the archive directory ```bash - mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD- + mv "" "/archive/YYYY-MM-DD-" ``` 6. **Display summary** @@ -91,7 +94,7 @@ Archive a completed change in the experimental workflow. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** ✓ Synced to main specs All artifacts complete. All tasks complete. @@ -104,7 +107,7 @@ All artifacts complete. All tasks complete. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** No delta specs All artifacts complete. All tasks complete. @@ -117,7 +120,7 @@ All artifacts complete. All tasks complete. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** Sync skipped (user chose to skip) **Warnings:** @@ -134,7 +137,7 @@ Review the archive if this was not intentional. ## Archive Failed **Change:** -**Target:** openspec/changes/archive/YYYY-MM-DD-/ +**Target:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ Target archive directory already exists. diff --git a/.roo/commands/opsx-explore.md b/.roo/commands/opsx-explore.md index 0c5f0347ce..84ba87a04e 100644 --- a/.roo/commands/opsx-explore.md +++ b/.roo/commands/opsx-explore.md @@ -104,11 +104,10 @@ Think freely. When insights crystallize, you might offer: If the user mentions a change or you detect one is relevant: -1. **Read existing artifacts for context** - - `openspec/changes//proposal.md` - - `openspec/changes//design.md` - - `openspec/changes//tasks.md` - - etc. +1. **Resolve and read existing artifacts for context** + - Run `openspec status --change "" --json`. + - Use `changeRoot`, `artifactPaths`, and `actionContext` from the status JSON. + - Read existing files from `artifactPaths..existingOutputPaths`. 2. **Reference them naturally in conversation** - "Your design mentions using Redis, but we just realized SQLite fits better..." diff --git a/.roo/commands/opsx-propose.md b/.roo/commands/opsx-propose.md index 6669d0d32d..a8a501e9de 100644 --- a/.roo/commands/opsx-propose.md +++ b/.roo/commands/opsx-propose.md @@ -30,7 +30,7 @@ When ready to implement, run /opsx:apply ```bash openspec new change "" ``` - This creates a scaffolded change at `openspec/changes//` with `.openspec.yaml`. + This creates a scaffolded change in the planning home resolved by the CLI with `.openspec.yaml`. 3. **Get the artifact build order** ```bash @@ -39,6 +39,7 @@ When ready to implement, run /opsx:apply Parse the JSON to get: - `applyRequires`: array of artifact IDs needed before implementation (e.g., `["tasks"]`) - `artifacts`: list of all artifacts with their status and dependencies + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context. Use these instead of assuming repo-local paths. 4. **Create artifacts in sequence until apply-ready** @@ -56,10 +57,10 @@ When ready to implement, run /opsx:apply - `rules`: Artifact-specific rules (constraints for you - do NOT include in output) - `template`: The structure to use for your output file - `instruction`: Schema-specific guidance for this artifact type - - `outputPath`: Where to write the artifact + - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read for context - Read any completed dependency files for context - - Create the artifact file using `template` as the structure + - Create the artifact file using `template` as the structure and write it to `resolvedOutputPath` - Apply `context` and `rules` as constraints - but do NOT copy them into the file - Show brief progress: "Created " diff --git a/.roo/skills/openspec-apply-change/SKILL.md b/.roo/skills/openspec-apply-change/SKILL.md index 70fbdb8569..db4d8ce2a8 100644 --- a/.roo/skills/openspec-apply-change/SKILL.md +++ b/.roo/skills/openspec-apply-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Implement tasks from an OpenSpec change. @@ -30,6 +30,7 @@ Implement tasks from an OpenSpec change. ``` Parse the JSON to understand: - `schemaName`: The workflow being used (e.g., "spec-driven") + - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) 3. **Get apply instructions** @@ -49,6 +50,8 @@ Implement tasks from an OpenSpec change. - If `state: "all_done"`: congratulate, suggest archive - Otherwise: proceed to implementation + **Workspace guard:** If status JSON reports `actionContext.mode: "workspace-planning"` and `allowedEditRoots` is empty, explain that full workspace apply is not supported in this slice. Treat linked repos and folders as read-only context, ask the user to select an affected area through an explicit implementation workflow, and STOP before editing files. + 4. **Read context files** Read every file path listed under `contextFiles` from the apply instructions output. diff --git a/.roo/skills/openspec-archive-change/SKILL.md b/.roo/skills/openspec-archive-change/SKILL.md index 12e2f70e9c..97c3e5e3a4 100644 --- a/.roo/skills/openspec-archive-change/SKILL.md +++ b/.roo/skills/openspec-archive-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Archive a completed change in the experimental workflow. @@ -30,8 +30,11 @@ Archive a completed change in the experimental workflow. Parse the JSON to understand: - `schemaName`: The workflow being used + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context - `artifacts`: List of artifacts with their status (`done` or other) + If status reports `actionContext.mode: "workspace-planning"`, explain that workspace archive is not supported in this slice and STOP. Do not move workspace changes into repo-local archives or edit linked repos. + **If any artifacts are not `done`:** - Display warning listing incomplete artifacts - Use **AskUserQuestion tool** to confirm user wants to proceed @@ -52,7 +55,7 @@ Archive a completed change in the experimental workflow. 4. **Assess delta spec sync state** - Check for delta specs at `openspec/changes//specs/`. If none exist, proceed without sync prompt. + Use `artifactPaths.specs.existingOutputPaths` from status JSON to check for delta specs. If none exist, proceed without sync prompt. **If delta specs exist:** - Compare each delta spec with its corresponding main spec at `openspec/specs//spec.md` @@ -67,19 +70,19 @@ Archive a completed change in the experimental workflow. 5. **Perform the archive** - Create the archive directory if it doesn't exist: + Create an `archive` directory under `planningHome.changesDir` if it doesn't exist: ```bash - mkdir -p openspec/changes/archive + mkdir -p "/archive" ``` Generate target name using current date: `YYYY-MM-DD-` **Check if target already exists:** - If yes: Fail with error, suggest renaming existing archive or using different date - - If no: Move the change directory to archive + - If no: Move `changeRoot` to the archive directory ```bash - mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD- + mv "" "/archive/YYYY-MM-DD-" ``` 6. **Display summary** @@ -98,7 +101,7 @@ Archive a completed change in the experimental workflow. **Change:** **Schema:** -**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ +**Archived to:** the archive path derived from `planningHome.changesDir`/YYYY-MM-DD-/ **Specs:** ✓ Synced to main specs (or "No delta specs" or "Sync skipped") All artifacts complete. All tasks complete. diff --git a/.roo/skills/openspec-explore/SKILL.md b/.roo/skills/openspec-explore/SKILL.md index 6858d3f693..1e97aaa81f 100644 --- a/.roo/skills/openspec-explore/SKILL.md +++ b/.roo/skills/openspec-explore/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. @@ -102,11 +102,10 @@ Think freely. When insights crystallize, you might offer: If the user mentions a change or you detect one is relevant: -1. **Read existing artifacts for context** - - `openspec/changes//proposal.md` - - `openspec/changes//design.md` - - `openspec/changes//tasks.md` - - etc. +1. **Resolve and read existing artifacts for context** + - Run `openspec status --change "" --json`. + - Use `changeRoot`, `artifactPaths`, and `actionContext` from the status JSON. + - Read existing files from `artifactPaths..existingOutputPaths`. 2. **Reference them naturally in conversation** - "Your design mentions using Redis, but we just realized SQLite fits better..." diff --git a/.roo/skills/openspec-propose/SKILL.md b/.roo/skills/openspec-propose/SKILL.md index 4b7e204184..9fc85139aa 100644 --- a/.roo/skills/openspec-propose/SKILL.md +++ b/.roo/skills/openspec-propose/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.3.1" + generatedBy: "1.4.1" --- Propose a new change - create the change and generate all artifacts in one step. @@ -37,7 +37,7 @@ When ready to implement, run /opsx:apply ```bash openspec new change "" ``` - This creates a scaffolded change at `openspec/changes//` with `.openspec.yaml`. + This creates a scaffolded change in the planning home resolved by the CLI with `.openspec.yaml`. 3. **Get the artifact build order** ```bash @@ -46,6 +46,7 @@ When ready to implement, run /opsx:apply Parse the JSON to get: - `applyRequires`: array of artifact IDs needed before implementation (e.g., `["tasks"]`) - `artifacts`: list of all artifacts with their status and dependencies + - `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context. Use these instead of assuming repo-local paths. 4. **Create artifacts in sequence until apply-ready** @@ -63,10 +64,10 @@ When ready to implement, run /opsx:apply - `rules`: Artifact-specific rules (constraints for you - do NOT include in output) - `template`: The structure to use for your output file - `instruction`: Schema-specific guidance for this artifact type - - `outputPath`: Where to write the artifact + - `resolvedOutputPath`: Resolved path or pattern to write the artifact - `dependencies`: Completed artifacts to read for context - Read any completed dependency files for context - - Create the artifact file using `template` as the structure + - Create the artifact file using `template` as the structure and write it to `resolvedOutputPath` - Apply `context` and `rules` as constraints - but do NOT copy them into the file - Show brief progress: "Created " diff --git a/frontend/app/modals/modalregistry.tsx b/frontend/app/modals/modalregistry.tsx index 88d19e732c..da0bb7b22e 100644 --- a/frontend/app/modals/modalregistry.tsx +++ b/frontend/app/modals/modalregistry.tsx @@ -1,6 +1,7 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { CommandConfigModal } from "@/app/view/term/CommandConfigModal"; import { MessageModal } from "@/app/modals/messagemodal"; import { NewInstallOnboardingModal } from "@/app/onboarding/onboarding"; import { UpgradeOnboardingModal } from "@/app/onboarding/onboarding-upgrade"; @@ -15,6 +16,7 @@ const modalRegistry: { [key: string]: React.ComponentType } = { [UpgradeOnboardingModal.displayName || "UpgradeOnboardingModal"]: UpgradeOnboardingModal, [UpgradeOnboardingPatch.displayName || "UpgradeOnboardingPatch"]: UpgradeOnboardingPatch, [UserInputModal.displayName || "UserInputModal"]: UserInputModal, + [CommandConfigModal.displayName || "CommandConfigModal"]: CommandConfigModal, [AboutModal.displayName || "AboutModal"]: AboutModal, [MessageModal.displayName || "MessageModal"]: MessageModal, [PublishAppModal.displayName || "PublishAppModal"]: PublishAppModal, diff --git a/frontend/app/view/term/CommandConfigModal.scss b/frontend/app/view/term/CommandConfigModal.scss new file mode 100644 index 0000000000..70808bbcc9 --- /dev/null +++ b/frontend/app/view/term/CommandConfigModal.scss @@ -0,0 +1,2 @@ +// Configure Command Modal styles +// Uses Tailwind classes for most styling; this file for any overrides if needed diff --git a/frontend/app/view/term/CommandConfigModal.tsx b/frontend/app/view/term/CommandConfigModal.tsx new file mode 100644 index 0000000000..39327ff959 --- /dev/null +++ b/frontend/app/view/term/CommandConfigModal.tsx @@ -0,0 +1,170 @@ +import { Modal } from "@/app/modals/modal"; +import { modalsModel } from "@/app/store/modalmodel"; +import { RpcApi } from "@/app/store/wshclientapi"; +import { TabRpcClient } from "@/app/store/wshrpcutil"; +import { WOS, atoms, globalStore } from "@/store/global"; +import * as keyutil from "@/util/keyutil"; +import { fireAndForget } from "@/util/util"; +import { useCallback, useMemo, useState } from "react"; + +import "./CommandConfigModal.scss"; + +interface CommandConfigModalProps { + blockId: string; +} + +function parseEnvText(text: string): { valid: boolean; map: Record; error?: string } { + const lines = text.split("\n"); + const map: Record = {}; + for (let i = 0; i < lines.length; i++) { + const line = lines[i].trim(); + if (line === "" || line.startsWith("#")) { + continue; + } + const eqIdx = line.indexOf("="); + if (eqIdx <= 0) { + return { valid: false, map, error: `Invalid format on line ${i + 1}: use KEY=VALUE` }; + } + const key = line.substring(0, eqIdx).trim(); + const value = line.substring(eqIdx + 1).trim(); + map[key] = value; + } + return { valid: true, map }; +} + +function envMapToText(envMap: Record | undefined | null): string { + if (!envMap) return ""; + return Object.entries(envMap) + .map(([k, v]) => `${k}=${v}`) + .join("\n"); +} + +const CommandConfigModal = (props: CommandConfigModalProps) => { + const { blockId } = props; + const blockAtom = useMemo(() => WOS.getWaveObjectAtom(WOS.makeORef("block", blockId)), [blockId]); + const blockData = globalStore.get(blockAtom); + + const [command, setCommand] = useState(blockData?.meta?.["cmd"] ?? ""); + const [runOnStart, setRunOnStart] = useState(blockData?.meta?.["cmd:runonstart"] ?? true); + const [clearOnStart, setClearOnStart] = useState(blockData?.meta?.["cmd:clearonstart"] ?? false); + const [envText, setEnvText] = useState(envMapToText(blockData?.meta?.["cmd:env"])); + const [saveDisabled, setSaveDisabled] = useState(false); + const [validationError, setValidationError] = useState(null); + + const handleSaveAndRestart = useCallback(() => { + const parsed = parseEnvText(envText); + if (!parsed.valid) { + setValidationError(parsed.error ?? "Invalid environment variables"); + return; + } + setValidationError(null); + setSaveDisabled(true); + const meta: Record = { + "cmd": command || null, + "cmd:runonstart": !!runOnStart, + "cmd:clearonstart": !!clearOnStart, + "cmd:env": parsed.map, + "controller": "shell", + }; + fireAndForget(async () => { + try { + await RpcApi.SetMetaCommand(TabRpcClient, { + oref: WOS.makeORef("block", blockId), + meta, + }); + await RpcApi.ControllerDestroyCommand(TabRpcClient, blockId); + await RpcApi.ControllerResyncCommand(TabRpcClient, { + tabid: globalStore.get(atoms.staticTabId), + blockid: blockId, + forcerestart: true, + }); + } catch (e) { + console.error("Save & Restart failed:", e); + } + modalsModel.popModal(); + }); + }, [blockId, command, runOnStart, clearOnStart, envText]); + + const handleCancel = useCallback(() => { + modalsModel.popModal(); + }, []); + + const handleKeyDown = useCallback( + (waveEvent: WaveKeyboardEvent): boolean => { + if (keyutil.checkKeyPressed(waveEvent, "Escape")) { + handleCancel(); + return true; + } + return false; + }, + [handleCancel] + ); + + return ( + +
Startup Command
+
+
+ +