Compare commits

...

17 Commits

Author SHA1 Message Date
Dicky Moore e137aeebcc
Merge 6eb7225f0a into 61d89c82ef 2026-03-11 11:09:10 +13:00
Alex Verkhovsky 61d89c82ef
docs: refine quick dev new preview explainer (#1889)
* docs: explain quick dev new preview workflow

* docs: refine quick dev new preview explainer
2026-03-10 16:48:48 -05:00
Alex Verkhovsky 30a98633cd
revert: restore QA checklist wording (#1888) 2026-03-10 05:54:07 -06:00
Alex Verkhovsky b7315c6e32 chore(publish): remove trusted publishing diagnostics 2026-03-10 05:23:33 -06:00
Alex Verkhovsky 6a0046917a fix(publish): pin npm for trusted publishing 2026-03-10 04:09:10 -06:00
Alex Verkhovsky c8f5b60598 fix(publish): remove empty token env and improve auth diagnostics 2026-03-10 03:57:58 -06:00
Dicky Moore 6eb7225f0a
Merge branch 'main' into feature/native-skills-lean-shard-doc-prototype 2026-03-09 21:39:07 +00:00
Dicky Moore c51a3f9e2a
Merge branch 'main' into feature/native-skills-lean-shard-doc-prototype 2026-03-09 08:52:27 +00:00
Dicky Moore e9a1bdba56
Merge branch 'main' into feature/native-skills-lean-shard-doc-prototype 2026-03-09 07:50:44 +00:00
Dicky Moore 7f9b3c814e
Merge branch 'main' into feature/native-skills-lean-shard-doc-prototype 2026-03-08 22:10:19 +00:00
Dicky Moore f053d3067e
Merge branch 'main' into feature/native-skills-lean-shard-doc-prototype 2026-03-08 18:18:23 +00:00
Dicky Moore 1eee9cd36c refactor(lean): simplify shard-doc prototype copy path 2026-03-08 17:50:12 +00:00
Dicky Moore 08a9d1d3e3 chore(lean): drop skill-manifest refactors from PoC scope 2026-03-08 17:48:01 +00:00
Dicky Moore 6714253197 chore(lean): defer skill-manifest resolver cleanup to follow-up 2026-03-08 17:38:50 +00:00
Dicky Moore c56af3296e fix(installer): tighten lean shard-doc review follow-ups 2026-03-08 17:17:58 +00:00
Dicky Moore 1f7879f6c1 Merge upstream/main into feature/native-skills-lean-shard-doc-prototype 2026-03-08 16:57:49 +00:00
Dicky Moore 3755e72f61 feat(installer): add lean shard-doc skill prototype install PoC 2026-03-08 16:44:10 +00:00
10 changed files with 283 additions and 109 deletions

View File

@ -52,74 +52,10 @@ jobs:
node-version-file: ".nvmrc" node-version-file: ".nvmrc"
cache: "npm" cache: "npm"
- name: Debug npm auth config surface - name: Ensure trusted publishing toolchain
run: | run: |
USERCONFIG=$(npm config get userconfig) # npm trusted publishing requires Node >= 22.14.0 and npm >= 11.5.1.
echo "npm userconfig: $USERCONFIG" npm install --global npm@11.6.2
if [ -f "$USERCONFIG" ]; then
if rg -n "_authToken|always-auth|registry.npmjs.org" "$USERCONFIG" >/dev/null 2>&1; then
echo "npm userconfig contains registry auth-related entries"
rg -n "_authToken|always-auth|registry.npmjs.org" "$USERCONFIG" | sed -E 's/(_authToken=).*/\1***MASKED***/'
else
echo "npm userconfig has no registry auth-related entries"
fi
else
echo "npm userconfig file not found"
fi
- name: Debug trusted publishing identity
run: |
echo "GitHub workflow context:"
echo " repository: ${{ github.repository }}"
echo " repository_owner: ${{ github.repository_owner }}"
echo " ref: ${{ github.ref }}"
echo " event_name: ${{ github.event_name }}"
echo " workflow: ${{ github.workflow }}"
echo " workflow_ref: ${{ github.workflow_ref }}"
echo " actor: ${{ github.actor }}"
echo " selected_channel: ${{ inputs.channel || 'n/a' }}"
echo " selected_bump: ${{ inputs.bump || 'n/a' }}"
echo " node_auth_token_present: $([ -n \"$NODE_AUTH_TOKEN\" ] && echo yes || echo no)"
WORKFLOW_FILE=$(node -e "
const ref = process.argv[1] || '';
const match = ref.match(/\.github\/workflows\/([^@]+)@/);
process.stdout.write(match ? match[1] : '');
" "${{ github.workflow_ref }}")
echo " workflow_filename_for_npm: ${WORKFLOW_FILE:-unknown}"
echo "OIDC claims (sanitized):"
RESPONSE=$(curl -fsS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=npm:registry.npmjs.org")
ID_TOKEN=$(node -e "
const fs = require('fs');
const data = JSON.parse(fs.readFileSync(0, 'utf8'));
process.stdout.write(data.value || '');
" <<<"$RESPONSE")
node -e "
const token = process.argv[1];
if (!token) {
console.log(JSON.stringify({ error: 'missing_id_token' }, null, 2));
process.exit(0);
}
const payloadPart = token.split('.')[1] || '';
const padded = payloadPart.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat((4 - (payloadPart.length % 4)) % 4);
const claims = JSON.parse(Buffer.from(padded, 'base64').toString('utf8'));
const out = {
iss: claims.iss,
sub: claims.sub,
aud: claims.aud,
repository: claims.repository,
repository_owner: claims.repository_owner,
workflow: claims.workflow,
workflow_ref: claims.workflow_ref,
job_workflow_ref: claims.job_workflow_ref,
ref: claims.ref,
environment: claims.environment || null,
runner_environment: claims.runner_environment || null,
};
console.log(JSON.stringify(out, null, 2));
" "$ID_TOKEN"
- name: Configure git user - name: Configure git user
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest' if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
@ -160,50 +96,13 @@ jobs:
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest' if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
run: 'npm version ${{ inputs.bump }} -m "chore(release): v%s [skip ci]"' run: 'npm version ${{ inputs.bump }} -m "chore(release): v%s [skip ci]"'
- name: Debug publish target and registry state
run: |
echo "Local package target:"
node -e "
const pkg = require('./package.json');
console.log(JSON.stringify({ name: pkg.name, version: pkg.version }, null, 2));
"
echo "Registry package view (bmad-method):"
npm view bmad-method name version dist-tags --json || true
- name: Publish prerelease to npm - name: Publish prerelease to npm
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.channel == 'next') if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.channel == 'next')
run: npm publish --tag next --provenance run: npm publish --tag next --provenance
env:
NPM_CONFIG_USERCONFIG: /dev/null
NODE_AUTH_TOKEN: ""
- name: Publish stable release to npm - name: Publish stable release to npm
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest' if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
run: npm publish --tag latest --provenance run: npm publish --tag latest --provenance
env:
NPM_CONFIG_USERCONFIG: /dev/null
NODE_AUTH_TOKEN: ""
- name: Print npm debug logs
if: always()
run: |
LOG_DIR="$HOME/.npm/_logs"
echo "npm log directory: $LOG_DIR"
ls -la "$LOG_DIR" || true
found=0
for file in "$LOG_DIR"/*-debug-0.log; do
[ -e "$file" ] || continue
found=1
echo "::group::npm-debug $(basename "$file")"
cat "$file"
echo "::endgroup::"
done
if [ "$found" -eq 0 ]; then
echo "No npm *-debug-0.log files found."
fi
- name: Push version commit and tag - name: Push version commit and tag
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest' if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'

View File

@ -0,0 +1,73 @@
---
title: "Quick Dev New Preview"
description: Reduce human-in-the-loop friction without giving up the checkpoints that protect output quality
sidebar:
order: 2
---
`bmad-quick-dev-new-preview` is an experimental attempt to radically improve Quick Flow: intent in, code changes out, with lower ceremony and fewer human-in-the-loop turns without sacrificing quality.
It lets the model run longer between checkpoints, then brings the human back only when the task cannot safely continue without human judgment or when it is time to review the end result.
![Quick Dev New Preview workflow diagram](/diagrams/quick-dev-diagram.png)
## Why This Exists
Human-in-the-loop turns are necessary and expensive.
Current LLMs still fail in predictable ways: they misread intent, fill gaps with confident guesses, drift into unrelated work, and generate noisy review output. At the same time, constant human intervention limits development velocity. Human attention is the bottleneck.
This experimental version of Quick Flow is an attempt to rebalance that tradeoff. It trusts the model to run unsupervised for longer stretches, but only after the workflow has created a strong enough boundary to make that safe.
## The Core Design
### 1. Compress intent first
The workflow starts by having the human and the model compress the request into one coherent goal. The input can begin as a rough expression of intent, but before the workflow runs autonomously it has to become small enough, clear enough, and contradiction-free enough to execute.
Intent can come in many forms: a couple of phrases, a bug tracker link, output from plan mode, text copied from a chat session, or even a story number from BMAD's own `epics.md`. In that last case, the workflow will not understand BMAD story-tracking semantics, but it can still take the story itself and run with it.
This workflow does not eliminate human control. It relocates it to a small number of high-value moments:
- **Intent clarification** - turning a messy request into one coherent goal without hidden contradictions
- **Spec approval** - confirming that the frozen understanding is the right thing to build
- **Review of the final product** - the primary checkpoint, where the human decides whether the result is acceptable at the end
### 2. Route to the smallest safe path
Once the goal is clear, the workflow decides whether this is a true one-shot change or whether it needs the fuller path. Small, zero-blast-radius changes can go straight to implementation. Everything else goes through planning so the model has a stronger boundary before it runs longer on its own.
### 3. Run longer with less supervision
After that routing decision, the model can carry more of the work on its own. On the fuller path, the approved spec becomes the boundary the model executes against with less supervision, which is the whole point of the experiment.
### 4. Diagnose failure at the right layer
If the implementation is wrong because the intent was wrong, patching the code is the wrong fix. If the code is wrong because the spec was weak, patching the diff is also the wrong fix. The workflow is designed to diagnose where the failure entered the system, go back to that layer, and regenerate from there.
Review findings are used to decide whether the problem came from intent, spec generation, or local implementation. Only truly local problems get patched locally.
### 5. Bring the human back only when needed
The intent interview is human-in-the-loop, but it is not the same kind of interruption as a recurring checkpoint. The workflow tries to keep those recurring checkpoints to a minimum. After the initial shaping of intent, the human mainly comes back when the workflow cannot safely continue without judgment and at the end, when it is time to review the result.
- **Intent-gap resolution** - stepping back in when review proves the workflow could not safely infer what was meant
Everything else is a candidate for longer autonomous execution. That tradeoff is deliberate. Older patterns spend more human attention on continuous supervision. Quick Dev New Preview spends more trust on the model, but saves human attention for the moments where human reasoning has the highest leverage.
## Why the Review System Matters
The review phase is not just there to find bugs. It is there to route correction without destroying momentum.
This workflow works best on a platform that can spawn subagents, or at least invoke another LLM through the command line and wait for a result. If your platform does not support that natively, you can add a skill to do it. Context-free subagents are a cornerstone of the review design.
Agentic reviews often go wrong in two ways:
- They generate too many findings, forcing the human to sift through noise.
- They derail the current change by surfacing unrelated issues and turning every run into an ad hoc cleanup project.
Quick Dev New Preview addresses both by treating review as triage.
Some findings belong to the current change. Some do not. If a finding is incidental rather than causally tied to the current work, the workflow can defer it instead of forcing the human to handle it immediately. That keeps the run focused and prevents random tangents from consuming the budget of attention.
That triage will sometimes be imperfect. That is acceptable. It is usually better to misjudge some findings than to flood the human with thousands of low-value review comments. The system is optimizing for signal quality, not exhaustive recall.

View File

@ -7,6 +7,10 @@ sidebar:
Skip the ceremony. Quick Flow takes you from idea to working code in two skills - no Product Brief, no PRD, no Architecture doc. Skip the ceremony. Quick Flow takes you from idea to working code in two skills - no Product Brief, no PRD, no Architecture doc.
:::tip[Want a Unified Variant?]
If you want one workflow to clarify, plan, implement, review, and present in a single run, see [Quick Dev New Preview](./quick-dev-new-preview.md).
:::
## When to Use It ## When to Use It
- Bug fixes and patches - Bug fixes and patches

View File

@ -30,4 +30,4 @@ Run the tests using your project's test command.
--- ---
**Need more comprehensive test coverage?** Install [Test Architect (TEA)](https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/) for advanced workflows. **Need more comprehensive testing?** Install [Test Architect (TEA)](https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/) for advanced workflows.

View File

@ -0,0 +1,12 @@
---
name: bmad-shard-doc-skill-prototype
description: Prototype native skill wrapper for shard-doc during transition.
---
# bmad-shard-doc-skill-prototype
Prototype marker: source-authored-skill
Read and execute from: {project-root}/_bmad/core/tasks/shard-doc.xml
Follow all shard-doc task instructions exactly as written.

View File

@ -0,0 +1,3 @@
canonicalId: bmad-shard-doc-skill-prototype
type: task
description: "Prototype native skill wrapper for shard-doc during installer transition"

View File

@ -17,6 +17,7 @@ const fs = require('fs-extra');
const { YamlXmlBuilder } = require('../tools/cli/lib/yaml-xml-builder'); const { YamlXmlBuilder } = require('../tools/cli/lib/yaml-xml-builder');
const { ManifestGenerator } = require('../tools/cli/installers/lib/core/manifest-generator'); const { ManifestGenerator } = require('../tools/cli/installers/lib/core/manifest-generator');
const { IdeManager } = require('../tools/cli/installers/lib/ide/manager'); const { IdeManager } = require('../tools/cli/installers/lib/ide/manager');
const { ConfigDrivenIdeSetup } = require('../tools/cli/installers/lib/ide/_config-driven');
const { clearCache, loadPlatformCodes } = require('../tools/cli/installers/lib/ide/platform-codes'); const { clearCache, loadPlatformCodes } = require('../tools/cli/installers/lib/ide/platform-codes');
// ANSI colors // ANSI colors
@ -81,6 +82,70 @@ async function createTestBmadFixture() {
return fixtureDir; return fixtureDir;
} }
async function createShardDocPrototypeFixture() {
const fixtureDir = await createTestBmadFixture();
await fs.ensureDir(path.join(fixtureDir, 'core', 'tasks'));
await fs.writeFile(
path.join(fixtureDir, 'core', 'tasks', 'shard-doc.xml'),
'<task id="_bmad/core/tasks/shard-doc" name="Shard Document" description="Test shard-doc task"><objective>Test objective</objective></task>\n',
);
await fs.writeFile(
path.join(fixtureDir, 'core', 'tasks', 'bmad-skill-manifest.yaml'),
[
'shard-doc.xml:',
' canonicalId: bmad-shard-doc',
' type: task',
' description: "Splits large markdown documents into smaller, organized files based on sections"',
'',
].join('\n'),
);
await fs.ensureDir(path.join(fixtureDir, 'core', 'tasks', 'bmad-shard-doc-skill-prototype'));
await fs.writeFile(
path.join(fixtureDir, 'core', 'tasks', 'bmad-shard-doc-skill-prototype', 'SKILL.md'),
[
'---',
'name: bmad-shard-doc-skill-prototype',
'description: Source-authored prototype skill',
'---',
'',
'# bmad-shard-doc-skill-prototype',
'',
'Prototype marker: source-authored-skill',
'',
'Read and execute from: {project-root}/_bmad/core/tasks/shard-doc.xml',
'',
'Follow all shard-doc task instructions exactly as written.',
'',
].join('\n'),
);
await fs.writeFile(
path.join(fixtureDir, 'core', 'tasks', 'bmad-shard-doc-skill-prototype', 'bmad-skill-manifest.yaml'),
[
'canonicalId: bmad-shard-doc-skill-prototype',
'type: task',
'description: "Prototype native skill wrapper for shard-doc during installer transition"',
'',
].join('\n'),
);
await fs.writeFile(
path.join(fixtureDir, '_config', 'task-manifest.csv'),
[
'name,displayName,description,module,path,standalone,canonicalId',
'shard-doc,Shard Document,Test shard-doc task,core,_bmad/core/tasks/shard-doc.xml,true,bmad-shard-doc',
'',
].join('\n'),
);
// Ensure tool manifest exists to avoid parser edge-cases in some environments.
await fs.writeFile(path.join(fixtureDir, '_config', 'tool-manifest.csv'), '');
return fixtureDir;
}
/** /**
* Test Suite * Test Suite
*/ */
@ -827,6 +892,99 @@ async function runTests() {
console.log(''); console.log('');
// ============================================================ // ============================================================
// Test 11: Shard-doc Prototype Duplication (Skill/Non-Skill Scope)
// ============================================================
console.log(`${colors.yellow}Test Suite 11: Shard-doc Prototype Duplication${colors.reset}\n`);
let tempSkillProjectDir;
let tempNonSkillProjectDir;
let installedBmadDir;
try {
clearCache();
const platformCodes = await loadPlatformCodes();
const skillFormatEntry = Object.entries(platformCodes.platforms || {}).find(([_, platform]) => {
const installer = platform?.installer;
if (!installer || installer.skill_format !== true || typeof installer.target_dir !== 'string') return false;
if (Array.isArray(installer.artifact_types) && !installer.artifact_types.includes('tasks')) return false;
return true;
});
assert(Boolean(skillFormatEntry), 'Found a skill_format platform that installs task artifacts');
if (!skillFormatEntry) throw new Error('No suitable skill_format platform found for shard-doc prototype test');
const [skillFormatPlatformCode, skillFormatPlatform] = skillFormatEntry;
const skillInstaller = skillFormatPlatform.installer;
tempSkillProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-skill-prototype-test-'));
tempNonSkillProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-nonskill-prototype-test-'));
installedBmadDir = await createShardDocPrototypeFixture();
const ideManager = new IdeManager();
await ideManager.ensureInitialized();
const skillResult = await ideManager.setup(skillFormatPlatformCode, tempSkillProjectDir, installedBmadDir, {
silent: true,
selectedModules: ['bmm'],
});
assert(skillResult.success === true, `${skillFormatPlatformCode} setup succeeds for shard-doc prototype fixture`);
const canonicalSkillPath = path.join(tempSkillProjectDir, skillInstaller.target_dir, 'bmad-shard-doc', 'SKILL.md');
const prototypeSkillPath = path.join(tempSkillProjectDir, skillInstaller.target_dir, 'bmad-shard-doc-skill-prototype', 'SKILL.md');
assert(await fs.pathExists(canonicalSkillPath), `${skillFormatPlatformCode} install writes canonical shard-doc skill`);
assert(await fs.pathExists(prototypeSkillPath), `${skillFormatPlatformCode} install writes duplicated shard-doc prototype skill`);
const canonicalSkillContent = await fs.readFile(canonicalSkillPath, 'utf8');
const prototypeSkillContent = await fs.readFile(prototypeSkillPath, 'utf8');
assert(canonicalSkillContent.includes('name: bmad-shard-doc'), 'Canonical shard-doc skill keeps canonical frontmatter name');
assert(
canonicalSkillContent.includes('Read the entire task file at: {project-root}/_bmad/core/tasks/shard-doc.xml'),
'Canonical shard-doc skill points to shard-doc.xml',
);
assert(
prototypeSkillContent.includes('name: bmad-shard-doc-skill-prototype'),
'Prototype shard-doc skill uses prototype frontmatter name',
);
assert(
prototypeSkillContent.includes('Prototype marker: source-authored-skill'),
'Prototype shard-doc skill is copied from source SKILL.md',
);
assert(
prototypeSkillContent.includes('Read and execute from: {project-root}/_bmad/core/tasks/shard-doc.xml'),
'Prototype shard-doc skill preserves source-authored shard-doc.xml reference',
);
const nonSkillInstaller = {
...skillInstaller,
target_dir: '.legacy/prototype-commands',
skill_format: false,
artifact_types: ['tasks'],
};
const nonSkillHandler = new ConfigDrivenIdeSetup('prototype-nonskill-test', {
name: 'Prototype Non-Skill Test',
preferred: false,
installer: nonSkillInstaller,
});
const nonSkillResult = await nonSkillHandler.setup(tempNonSkillProjectDir, installedBmadDir, {
silent: true,
selectedModules: ['bmm'],
});
assert(nonSkillResult.success === true, 'Synthetic non-skill-format setup succeeds for shard-doc prototype fixture');
const nonSkillTargetDir = path.join(tempNonSkillProjectDir, nonSkillInstaller.target_dir);
const nonSkillEntries = await fs.readdir(nonSkillTargetDir);
const hasCanonical = nonSkillEntries.some((entry) => /^bmad-shard-doc(\.|$)/.test(entry));
const hasPrototype = nonSkillEntries.some((entry) => /^bmad-shard-doc-skill-prototype(\.|$)/.test(entry));
assert(hasCanonical, 'Non-skill-format install writes canonical shard-doc artifact');
assert(!hasPrototype, 'Non-skill-format install does not write duplicated shard-doc prototype artifact');
} catch (error) {
assert(false, 'Shard-doc prototype duplication test succeeds', error.message);
} finally {
await Promise.allSettled([tempSkillProjectDir, tempNonSkillProjectDir, installedBmadDir].filter(Boolean).map((dir) => fs.remove(dir)));
}
// Test 17: GitHub Copilot Native Skills Install // Test 17: GitHub Copilot Native Skills Install
// ============================================================ // ============================================================
console.log(`${colors.yellow}Test Suite 17: GitHub Copilot Native Skills${colors.reset}\n`); console.log(`${colors.yellow}Test Suite 17: GitHub Copilot Native Skills${colors.reset}\n`);

View File

@ -161,6 +161,7 @@ function generateLlmsTxt(outputDir) {
'## Core Concepts', '## Core Concepts',
'', '',
`- **[Quick Flow](${siteUrl}/explanation/quick-flow/)** - Fast development workflow`, `- **[Quick Flow](${siteUrl}/explanation/quick-flow/)** - Fast development workflow`,
`- **[Quick Dev New Preview](${siteUrl}/explanation/quick-dev-new-preview/)** - Unified quick workflow with planning, implementation, and review in one run`,
`- **[Party Mode](${siteUrl}/explanation/party-mode/)** - Multi-agent collaboration`, `- **[Party Mode](${siteUrl}/explanation/party-mode/)** - Multi-agent collaboration`,
`- **[Workflow Map](${siteUrl}/reference/workflow-map/)** - Visual overview of phases and workflows`, `- **[Workflow Map](${siteUrl}/reference/workflow-map/)** - Visual overview of phases and workflows`,
'', '',

View File

@ -150,7 +150,7 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
if (!artifact_types || artifact_types.includes('tasks') || artifact_types.includes('tools')) { if (!artifact_types || artifact_types.includes('tasks') || artifact_types.includes('tools')) {
const taskToolGen = new TaskToolCommandGenerator(this.bmadFolderName); const taskToolGen = new TaskToolCommandGenerator(this.bmadFolderName);
const { artifacts } = await taskToolGen.collectTaskToolArtifacts(bmadDir); const { artifacts } = await taskToolGen.collectTaskToolArtifacts(bmadDir);
const taskToolResult = await this.writeTaskToolArtifacts(targetPath, artifacts, template_type, config); const taskToolResult = await this.writeTaskToolArtifacts(targetPath, artifacts, template_type, config, bmadDir);
results.tasks = taskToolResult.tasks || 0; results.tasks = taskToolResult.tasks || 0;
results.tools = taskToolResult.tools || 0; results.tools = taskToolResult.tools || 0;
} }
@ -258,7 +258,7 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
* @param {Object} config - Installation configuration * @param {Object} config - Installation configuration
* @returns {Promise<Object>} Counts of tasks and tools written * @returns {Promise<Object>} Counts of tasks and tools written
*/ */
async writeTaskToolArtifacts(targetPath, artifacts, templateType, config = {}) { async writeTaskToolArtifacts(targetPath, artifacts, templateType, config = {}, bmadDir = null) {
let taskCount = 0; let taskCount = 0;
let toolCount = 0; let toolCount = 0;
@ -286,7 +286,7 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
const filename = this.generateFilename(artifact, artifact.type, extension); const filename = this.generateFilename(artifact, artifact.type, extension);
if (config.skill_format) { if (config.skill_format) {
await this.writeSkillFile(targetPath, artifact, content); await this.writeSkillFile(targetPath, artifact, content, bmadDir);
} else { } else {
const filePath = path.join(targetPath, filename); const filePath = path.join(targetPath, filename);
await this.writeFile(filePath, content); await this.writeFile(filePath, content);
@ -481,7 +481,7 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
* @param {Object} artifact - Artifact data * @param {Object} artifact - Artifact data
* @param {string} content - Rendered template content * @param {string} content - Rendered template content
*/ */
async writeSkillFile(targetPath, artifact, content) { async writeSkillFile(targetPath, artifact, content, bmadDir = null) {
const { resolveSkillName } = require('./shared/path-utils'); const { resolveSkillName } = require('./shared/path-utils');
// Get the skill name (prefers canonicalId, falls back to path-derived) and remove .md // Get the skill name (prefers canonicalId, falls back to path-derived) and remove .md
@ -500,6 +500,30 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
const skillContent = this.transformToSkillFormat(content, skillName); const skillContent = this.transformToSkillFormat(content, skillName);
await this.writeFile(path.join(skillDir, 'SKILL.md'), skillContent); await this.writeFile(path.join(skillDir, 'SKILL.md'), skillContent);
await this.writeShardDocPrototypeSkill(targetPath, bmadDir, skillName);
}
/**
* Copy shard-doc prototype skill during transition when installing skill-format targets.
* Keeps scope literal for the first PoC without introducing generalized prototype linkage.
* @param {string} targetPath - Base skills directory
* @param {string|null} bmadDir - Installed bmad directory
* @param {string} skillName - Canonical skill name being written
*/
async writeShardDocPrototypeSkill(targetPath, bmadDir, skillName) {
if (!bmadDir || skillName !== 'bmad-shard-doc') return;
const prototypeId = 'bmad-shard-doc-skill-prototype';
const sourceSkillPath = path.join(bmadDir, 'core', 'tasks', prototypeId, 'SKILL.md');
if (!(await fs.pathExists(sourceSkillPath))) return;
const sourceSkillContent = await fs.readFile(sourceSkillPath, 'utf8');
if (!sourceSkillContent) return;
const prototypeDir = path.join(targetPath, prototypeId);
await this.ensureDir(prototypeDir);
await this.writeFile(path.join(prototypeDir, 'SKILL.md'), sourceSkillContent);
} }
/** /**

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB