@sduck/sduck-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1149 -0
- package/dist/cli.js.map +1 -0
- package/package.json +59 -0
- package/sduck-assets/agent-rules/antigravity.md +4 -0
- package/sduck-assets/agent-rules/claude-code.md +4 -0
- package/sduck-assets/agent-rules/codex.md +4 -0
- package/sduck-assets/agent-rules/core.md +11 -0
- package/sduck-assets/agent-rules/cursor.mdc +11 -0
- package/sduck-assets/agent-rules/gemini-cli.md +4 -0
- package/sduck-assets/agent-rules/opencode.md +4 -0
- package/sduck-assets/eval/plan.yml +31 -0
- package/sduck-assets/eval/spec.yml +31 -0
- package/sduck-assets/eval/task.yml +31 -0
- package/sduck-assets/types/build.md +194 -0
- package/sduck-assets/types/chore.md +164 -0
- package/sduck-assets/types/feature.md +187 -0
- package/sduck-assets/types/fix.md +174 -0
- package/sduck-assets/types/refactor.md +174 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/init.ts","../src/core/agent-rules.ts","../src/core/fs.ts","../src/core/init.ts","../src/core/assets.ts","../src/commands/plan-approve.ts","../src/core/plan-approve.ts","../src/core/workspace.ts","../src/utils/utc-date.ts","../src/commands/spec-approve.ts","../src/core/spec-approve.ts","../src/core/start.ts","../src/commands/start.ts","../src/core/command-metadata.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\n\nimport { runInitCommand } from './commands/init.js';\nimport { runPlanApproveCommand } from './commands/plan-approve.js';\nimport { runSpecApproveCommand } from './commands/spec-approve.js';\nimport { runStartCommand } from './commands/start.js';\nimport {\n CLI_DESCRIPTION,\n CLI_NAME,\n PLACEHOLDER_MESSAGE,\n normalizeCommandName,\n} from './core/command-metadata.js';\n\nconst program = new Command();\n\nprogram.name(CLI_NAME).description(CLI_DESCRIPTION).version('0.1.0');\n\nprogram\n .command('init')\n .description('Initialize the current repository for the SDD workflow')\n .option('--force', 'Regenerate the bundled assets in sduck-assets')\n .option(\n '--agents <agents>',\n 'Comma-separated agents (claude-code,codex,opencode,gemini-cli,cursor,antigravity)',\n )\n .action(async (options: { agents?: string; force?: boolean }) => {\n const initOptions =\n options.agents === undefined\n ? { force: options.force ?? false }\n : { agents: options.agents, force: options.force ?? false };\n const result = await runInitCommand(initOptions, process.cwd());\n\n if (result.stdout !== '') {\n console.log(result.stdout);\n }\n\n if (result.stderr !== '') {\n console.error(result.stderr);\n }\n\n if (result.exitCode !== 0) {\n process.exitCode = result.exitCode;\n }\n });\n\nprogram\n .command('preview <name>')\n .description('Print the normalized command name for bootstrap verification')\n .action((name: string) => {\n console.log(normalizeCommandName(name));\n });\n\nprogram\n .command('start <type> <slug>')\n .description('Create a new task workspace from a type template')\n .action(async (type: string, slug: string) => {\n const result = await runStartCommand(type, slug, process.cwd());\n\n if (result.stdout !== '') {\n console.log(result.stdout);\n }\n\n if (result.stderr !== '') {\n console.error(result.stderr);\n }\n\n if (result.exitCode !== 0) {\n process.exitCode = result.exitCode;\n }\n });\n\nprogram\n .command('spec')\n .description('Manage spec workflow state')\n .command('approve [target]')\n .description('Approve a task spec and move it to plan writing')\n .action(async (target?: string) => {\n const input = target === undefined ? {} : { target };\n const result = await runSpecApproveCommand(input, process.cwd());\n\n if (result.stdout !== '') {\n console.log(result.stdout);\n }\n\n if (result.stderr !== '') {\n console.error(result.stderr);\n }\n\n if (result.exitCode !== 0) {\n process.exitCode = result.exitCode;\n }\n });\n\nprogram\n .command('plan')\n .description('Manage plan workflow state')\n .command('approve [target]')\n .description('Approve a task plan and move it to implementation')\n .action(async (target?: string) => {\n const input = target === undefined ? {} : { target };\n const result = await runPlanApproveCommand(input, process.cwd());\n\n if (result.stdout !== '') {\n console.log(result.stdout);\n }\n\n if (result.stderr !== '') {\n console.error(result.stderr);\n }\n\n if (result.exitCode !== 0) {\n process.exitCode = result.exitCode;\n }\n });\n\nprogram\n .command('roadmap')\n .description('Show the current bootstrap status')\n .action(() => {\n console.log(PLACEHOLDER_MESSAGE);\n });\n\nawait program.parseAsync(process.argv);\n","import { checkbox } from '@inquirer/prompts';\n\nimport { SUPPORTED_AGENTS, parseAgentsOption, type SupportedAgentId } from '../core/agent-rules.js';\nimport {\n type InitCommandOptions,\n type InitExecutionResult,\n type InitSummaryRow,\n initProject,\n} from '../core/init.js';\n\nexport interface CommandResult {\n exitCode: number;\n stderr: string;\n stdout: string;\n}\n\nexport interface InitCliOptions {\n agents?: string;\n force: boolean;\n}\n\nfunction padCell(value: string, width: number): string {\n return value.padEnd(width, ' ');\n}\n\nfunction buildSummaryTable(rows: InitSummaryRow[]): string {\n const statusWidth = Math.max('Status'.length, ...rows.map((row) => row.status.length));\n const pathWidth = Math.max('Path'.length, ...rows.map((row) => row.path.length));\n\n const border = `+-${'-'.repeat(statusWidth)}-+-${'-'.repeat(pathWidth)}-+`;\n const header = `| ${padCell('Status', statusWidth)} | ${padCell('Path', pathWidth)} |`;\n const body = rows.map(\n (row) => `| ${padCell(row.status, statusWidth)} | ${padCell(row.path, pathWidth)} |`,\n );\n\n return [border, header, border, ...body, border].join('\\n');\n}\n\nfunction formatResult(result: InitExecutionResult): string {\n const lines = [\n result.didChange ? 'sduck init completed.' : 'sduck init completed with no file changes.',\n ];\n\n if (result.agents.length > 0) {\n lines.push(`Selected agents: ${result.agents.join(', ')}`);\n }\n\n lines.push('', buildSummaryTable(result.summary.rows));\n\n if (result.summary.warnings.length > 0) {\n lines.push('', 'Warnings:');\n lines.push(...result.summary.warnings.map((warning) => `- ${warning}`));\n }\n\n return lines.join('\\n');\n}\n\nasync function resolveSelectedAgents(options: InitCliOptions): Promise<SupportedAgentId[]> {\n const parsedAgents = parseAgentsOption(options.agents);\n\n if (parsedAgents.length > 0 || !process.stdin.isTTY || !process.stdout.isTTY) {\n return parsedAgents;\n }\n\n return await checkbox<SupportedAgentId>({\n message: 'Select AI agents to generate repository rule files for',\n choices: SUPPORTED_AGENTS.map((agent) => ({\n name: agent.label,\n value: agent.id,\n })),\n });\n}\n\nexport async function runInitCommand(\n options: InitCliOptions,\n projectRoot: string,\n): Promise<CommandResult> {\n try {\n const resolvedOptions: InitCommandOptions = {\n force: options.force,\n agents: await resolveSelectedAgents(options),\n };\n const result = await initProject(resolvedOptions, projectRoot);\n\n return {\n exitCode: 0,\n stderr: '',\n stdout: formatResult(result),\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown init failure.';\n\n return {\n exitCode: 1,\n stderr: message,\n stdout: '',\n };\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { getFsEntryKind, type FsEntryKind } from './fs.js';\n\nexport type SupportedAgentId =\n | 'claude-code'\n | 'codex'\n | 'opencode'\n | 'gemini-cli'\n | 'cursor'\n | 'antigravity';\n\nexport type AgentRuleTargetKind = 'root-file' | 'managed-file';\n\nexport interface AgentRuleTarget {\n agentId: SupportedAgentId;\n outputPath: string;\n kind: AgentRuleTargetKind;\n}\n\nexport type AgentRuleMergeMode = 'create' | 'prepend' | 'keep' | 'replace-block' | 'overwrite';\n\nexport interface PlannedAgentRuleAction {\n agentId: SupportedAgentId;\n outputPath: string;\n kind: AgentRuleTargetKind;\n mergeMode: AgentRuleMergeMode;\n currentKind: FsEntryKind;\n}\n\nexport const SDD_RULES_BEGIN = '<!-- sduck:begin -->';\nexport const SDD_RULES_END = '<!-- sduck:end -->';\n\nexport const SUPPORTED_AGENTS: readonly { id: SupportedAgentId; label: string }[] = [\n { id: 'claude-code', label: 'Claude Code' },\n { id: 'codex', label: 'Codex' },\n { id: 'opencode', label: 'OpenCode' },\n { id: 'gemini-cli', label: 'Gemini CLI' },\n { id: 'cursor', label: 'Cursor' },\n { id: 'antigravity', label: 'Antigravity' },\n];\n\nconst AGENT_RULE_TARGETS: readonly AgentRuleTarget[] = [\n { agentId: 'claude-code', outputPath: 'CLAUDE.md', kind: 'root-file' },\n { agentId: 'codex', outputPath: 'AGENTS.md', kind: 'root-file' },\n { agentId: 'opencode', outputPath: 'AGENTS.md', kind: 'root-file' },\n { agentId: 'gemini-cli', outputPath: 'GEMINI.md', kind: 'root-file' },\n {\n agentId: 'cursor',\n outputPath: join('.cursor', 'rules', 'sduck-core.mdc'),\n kind: 'managed-file',\n },\n {\n agentId: 'antigravity',\n outputPath: join('.agents', 'rules', 'sduck-core.md'),\n kind: 'managed-file',\n },\n];\n\nconst AGENT_TEMPLATE_FILES: Record<SupportedAgentId, string> = {\n 'claude-code': 'claude-code.md',\n codex: 'codex.md',\n opencode: 'opencode.md',\n 'gemini-cli': 'gemini-cli.md',\n cursor: 'cursor.mdc',\n antigravity: 'antigravity.md',\n};\n\nfunction unique<T>(values: readonly T[]): T[] {\n return [...new Set(values)];\n}\n\nexport function parseAgentsOption(rawAgents: string | undefined): SupportedAgentId[] {\n if (rawAgents === undefined || rawAgents.trim() === '') {\n return [];\n }\n\n const requestedAgents = unique(\n rawAgents\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value !== ''),\n );\n\n const validAgents = new Set(SUPPORTED_AGENTS.map((agent) => agent.id));\n const invalidAgent = requestedAgents.find((agent) => !validAgents.has(agent as SupportedAgentId));\n\n if (invalidAgent !== undefined) {\n throw new Error(`Unsupported agent: ${invalidAgent}`);\n }\n\n return requestedAgents as SupportedAgentId[];\n}\n\nexport function listAgentRuleTargets(selectedAgents: SupportedAgentId[]): AgentRuleTarget[] {\n const selectedAgentSet = new Set(selectedAgents);\n\n return AGENT_RULE_TARGETS.filter((target) => selectedAgentSet.has(target.agentId)).filter(\n (target, index, allTargets) =>\n index === allTargets.findIndex((candidate) => candidate.outputPath === target.outputPath),\n );\n}\n\nexport function hasManagedBlock(content: string): boolean {\n return content.includes(SDD_RULES_BEGIN) && content.includes(SDD_RULES_END);\n}\n\nexport function prependManagedBlock(existingContent: string, blockContent: string): string {\n const normalizedExistingContent = existingContent.trimStart();\n\n if (normalizedExistingContent === '') {\n return `${blockContent}\\n`;\n }\n\n return `${blockContent}\\n\\n${normalizedExistingContent}`;\n}\n\nexport function replaceManagedBlock(existingContent: string, blockContent: string): string {\n const blockPattern = new RegExp(`${SDD_RULES_BEGIN}[\\\\s\\\\S]*?${SDD_RULES_END}`);\n\n if (!blockPattern.test(existingContent)) {\n return prependManagedBlock(existingContent, blockContent);\n }\n\n return existingContent.replace(blockPattern, blockContent);\n}\n\nfunction renderManagedBlock(lines: string[]): string {\n return [SDD_RULES_BEGIN, ...lines, SDD_RULES_END].join('\\n');\n}\n\nasync function getAgentRulesAssetRoot(): Promise<string> {\n const currentDirectoryPath = dirname(fileURLToPath(import.meta.url));\n const candidatePaths = [\n join(currentDirectoryPath, '..', '..', 'sduck-assets', 'agent-rules'),\n join(currentDirectoryPath, '..', 'sduck-assets', 'agent-rules'),\n ];\n\n for (const candidatePath of candidatePaths) {\n if ((await getFsEntryKind(candidatePath)) === 'directory') {\n return candidatePath;\n }\n }\n\n throw new Error('Unable to locate bundled sduck agent rule assets.');\n}\n\nasync function readAssetFile(assetRoot: string, fileName: string): Promise<string> {\n return await readFile(join(assetRoot, fileName), 'utf8');\n}\n\nfunction buildRootFileLines(\n agentIds: SupportedAgentId[],\n agentSpecificContent: string[],\n): string[] {\n const labels = SUPPORTED_AGENTS.filter((agent) => agentIds.includes(agent.id)).map(\n (agent) => agent.label,\n );\n\n return [\n '# sduck managed rules',\n '',\n `Selected agents: ${labels.join(', ')}`,\n '',\n ...agentSpecificContent,\n ];\n}\n\nexport async function renderAgentRuleContent(\n target: AgentRuleTarget,\n selectedAgents: SupportedAgentId[],\n): Promise<string> {\n const assetRoot = await getAgentRulesAssetRoot();\n const coreContent = await readAssetFile(assetRoot, 'core.md');\n\n if (target.kind === 'managed-file') {\n const templateFileName = AGENT_TEMPLATE_FILES[target.agentId];\n const specificContent = await readAssetFile(assetRoot, templateFileName);\n\n return `${specificContent.trim()}\\n\\n${coreContent.trim()}\\n`;\n }\n\n const relatedAgents = AGENT_RULE_TARGETS.filter(\n (candidate) =>\n candidate.outputPath === target.outputPath && selectedAgents.includes(candidate.agentId),\n ).map((candidate) => candidate.agentId);\n\n const specificSections: string[] = [];\n\n for (const agentId of relatedAgents) {\n const templateFileName = AGENT_TEMPLATE_FILES[agentId];\n specificSections.push((await readAssetFile(assetRoot, templateFileName)).trim());\n }\n\n const lines = buildRootFileLines(relatedAgents, [...specificSections, coreContent.trim()]);\n\n return `${renderManagedBlock(lines)}\\n`;\n}\n\nexport function planAgentRuleActions(\n mode: 'safe' | 'force',\n targets: readonly AgentRuleTarget[],\n existingEntries: Map<string, FsEntryKind>,\n existingContents: Map<string, string>,\n): PlannedAgentRuleAction[] {\n return targets.map((target) => {\n const currentKind = existingEntries.get(target.outputPath) ?? 'missing';\n\n if (currentKind === 'missing') {\n return { ...target, mergeMode: 'create', currentKind };\n }\n\n if (currentKind !== 'file') {\n return { ...target, mergeMode: 'overwrite', currentKind };\n }\n\n if (target.kind === 'managed-file') {\n return { ...target, mergeMode: mode === 'force' ? 'overwrite' : 'keep', currentKind };\n }\n\n const content = existingContents.get(target.outputPath) ?? '';\n\n if (mode === 'safe') {\n return { ...target, mergeMode: hasManagedBlock(content) ? 'keep' : 'prepend', currentKind };\n }\n\n return {\n ...target,\n mergeMode: hasManagedBlock(content) ? 'replace-block' : 'prepend',\n currentKind,\n };\n });\n}\n","import { constants } from 'node:fs';\nimport { access, copyFile, mkdir, stat } from 'node:fs/promises';\n\nexport type FsEntryKind = 'missing' | 'file' | 'directory';\n\nexport async function getFsEntryKind(targetPath: string): Promise<FsEntryKind> {\n try {\n const stats = await stat(targetPath);\n\n if (stats.isDirectory()) {\n return 'directory';\n }\n\n if (stats.isFile()) {\n return 'file';\n }\n\n return 'file';\n } catch {\n return 'missing';\n }\n}\n\nexport async function ensureDirectory(targetPath: string): Promise<void> {\n await mkdir(targetPath, { recursive: true });\n}\n\nexport async function ensureReadableFile(targetPath: string): Promise<void> {\n await access(targetPath, constants.R_OK);\n}\n\nexport async function copyFileIntoPlace(sourcePath: string, targetPath: string): Promise<void> {\n await copyFile(sourcePath, targetPath);\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport {\n type AgentRuleTarget,\n listAgentRuleTargets,\n planAgentRuleActions,\n prependManagedBlock,\n renderAgentRuleContent,\n replaceManagedBlock,\n type PlannedAgentRuleAction,\n type SupportedAgentId,\n} from './agent-rules.js';\nimport { EVAL_ASSET_RELATIVE_PATHS, getBundledAssetsRoot } from './assets.js';\nimport {\n copyFileIntoPlace,\n ensureDirectory,\n ensureReadableFile,\n getFsEntryKind,\n type FsEntryKind,\n} from './fs.js';\n\nimport type { InitCommandOptions, InitMode, ResolvedInitOptions } from './init-types.js';\n\nexport type { FsEntryKind } from './fs.js';\nexport type { InitCommandOptions, InitMode, ResolvedInitOptions } from './init-types.js';\n\nexport type AssetTemplateKey =\n | 'eval-spec'\n | 'eval-plan'\n | 'type-build'\n | 'type-feature'\n | 'type-fix'\n | 'type-refactor'\n | 'type-chore';\n\nexport interface AssetTemplateDefinition {\n key: AssetTemplateKey;\n relativePath: string;\n}\n\nexport type AssetTemplateMap = Record<AssetTemplateKey, AssetTemplateDefinition>;\n\nexport type AssetActionKind = 'create' | 'keep' | 'overwrite' | 'error';\n\nexport type AssetCollisionKind =\n | 'none'\n | 'file-directory-mismatch'\n | 'directory-file-mismatch'\n | 'unknown';\n\nexport interface PlannedAssetAction {\n key: AssetTemplateKey;\n targetPath: string;\n currentKind: FsEntryKind;\n action: AssetActionKind;\n collision: AssetCollisionKind;\n}\n\nexport type InitWarningCode =\n | 'kept-existing-asset'\n | 'kept-existing-rule'\n | 'type-conflict'\n | 'force-recommended';\n\nexport type InitErrorCode =\n | 'asset-root-conflict'\n | 'workspace-root-conflict'\n | 'asset-write-failed'\n | 'unknown-fs-error';\n\nexport interface InitSummaryRow {\n path: string;\n status: 'created' | 'prepended' | 'kept' | 'overwritten';\n}\n\nexport interface InitExecutionSummary {\n created: string[];\n prepended: string[];\n kept: string[];\n overwritten: string[];\n warnings: string[];\n errors: string[];\n rows: InitSummaryRow[];\n}\n\nexport interface InitExecutionResult {\n mode: InitMode;\n agents: string[];\n summary: InitExecutionSummary;\n didChange: boolean;\n}\n\nconst ASSET_TEMPLATE_DEFINITIONS = [\n {\n key: 'eval-spec',\n relativePath: join('sduck-assets', EVAL_ASSET_RELATIVE_PATHS.spec),\n },\n {\n key: 'eval-plan',\n relativePath: join('sduck-assets', EVAL_ASSET_RELATIVE_PATHS.plan),\n },\n {\n key: 'type-build',\n relativePath: join('sduck-assets', 'types', 'build.md'),\n },\n {\n key: 'type-feature',\n relativePath: join('sduck-assets', 'types', 'feature.md'),\n },\n { key: 'type-fix', relativePath: join('sduck-assets', 'types', 'fix.md') },\n {\n key: 'type-refactor',\n relativePath: join('sduck-assets', 'types', 'refactor.md'),\n },\n {\n key: 'type-chore',\n relativePath: join('sduck-assets', 'types', 'chore.md'),\n },\n] as const satisfies readonly AssetTemplateDefinition[];\n\nexport const ASSET_TEMPLATE_MAP = Object.fromEntries(\n ASSET_TEMPLATE_DEFINITIONS.map((definition) => [definition.key, definition]),\n) as AssetTemplateMap;\n\nexport function planInitActions(\n mode: InitMode,\n existingEntries: Map<string, FsEntryKind>,\n): PlannedAssetAction[] {\n return ASSET_TEMPLATE_DEFINITIONS.map((definition) => {\n const currentKind = existingEntries.get(definition.relativePath) ?? 'missing';\n\n if (currentKind === 'missing') {\n return {\n key: definition.key,\n targetPath: definition.relativePath,\n currentKind,\n action: 'create',\n collision: 'none',\n } satisfies PlannedAssetAction;\n }\n\n if (currentKind === 'file') {\n return {\n key: definition.key,\n targetPath: definition.relativePath,\n currentKind,\n action: mode === 'force' ? 'overwrite' : 'keep',\n collision: 'none',\n } satisfies PlannedAssetAction;\n }\n\n return {\n key: definition.key,\n targetPath: definition.relativePath,\n currentKind,\n action: 'error',\n collision: 'directory-file-mismatch',\n } satisfies PlannedAssetAction;\n });\n}\n\nexport function summarizeInitActions(actions: PlannedAssetAction[]): InitExecutionSummary {\n const summary: InitExecutionSummary = {\n created: [],\n prepended: [],\n kept: [],\n overwritten: [],\n warnings: [],\n errors: [],\n rows: [],\n };\n\n for (const action of actions) {\n if (action.action === 'create') {\n summary.created.push(action.targetPath);\n summary.rows.push({ path: action.targetPath, status: 'created' });\n continue;\n }\n\n if (action.action === 'keep') {\n summary.kept.push(action.targetPath);\n summary.rows.push({ path: action.targetPath, status: 'kept' });\n summary.warnings.push(`Kept existing asset: ${action.targetPath}`);\n continue;\n }\n\n if (action.action === 'overwrite') {\n summary.overwritten.push(action.targetPath);\n summary.rows.push({ path: action.targetPath, status: 'overwritten' });\n continue;\n }\n\n summary.errors.push(`Path conflict for ${action.targetPath}: ${action.collision}`);\n }\n\n if (summary.kept.length > 0) {\n summary.warnings.push('Run `sduck init --force` if you want to regenerate bundled assets.');\n }\n\n return summary;\n}\n\nfunction getInitMode(options: InitCommandOptions): InitMode {\n return options.force ? 'force' : 'safe';\n}\n\nfunction resolveInitOptions(options: InitCommandOptions): ResolvedInitOptions {\n return {\n mode: getInitMode(options),\n agents: [...new Set(options.agents)],\n };\n}\n\nasync function collectExistingEntries(projectRoot: string): Promise<Map<string, FsEntryKind>> {\n const existingEntries = new Map<string, FsEntryKind>();\n\n for (const definition of ASSET_TEMPLATE_DEFINITIONS) {\n existingEntries.set(\n definition.relativePath,\n await getFsEntryKind(join(projectRoot, definition.relativePath)),\n );\n }\n\n return existingEntries;\n}\n\nasync function collectExistingFileContents(\n projectRoot: string,\n targets: readonly AgentRuleTarget[],\n): Promise<Map<string, string>> {\n const contents = new Map<string, string>();\n\n for (const target of targets) {\n const targetPath = join(projectRoot, target.outputPath);\n\n if ((await getFsEntryKind(targetPath)) === 'file') {\n contents.set(target.outputPath, await readFile(targetPath, 'utf8'));\n }\n }\n\n return contents;\n}\n\nasync function ensureRootDirectory(\n targetPath: string,\n errorCode: InitErrorCode,\n): Promise<'created' | 'kept' | 'overwritten'> {\n const kind = await getFsEntryKind(targetPath);\n\n if (kind === 'missing') {\n await ensureDirectory(targetPath);\n return 'created';\n }\n\n if (kind === 'directory') {\n return 'kept';\n }\n\n throw new Error(`${errorCode}: expected a directory at ${targetPath}.`);\n}\n\nexport async function initProject(\n options: InitCommandOptions,\n projectRoot: string,\n): Promise<InitExecutionResult> {\n const resolvedOptions = resolveInitOptions(options);\n const { mode } = resolvedOptions;\n const assetSourceRoot = await getBundledAssetsRoot();\n const assetsRoot = join(projectRoot, 'sduck-assets');\n const workspaceRoot = join(projectRoot, 'sduck-workspace');\n\n const summary: InitExecutionSummary = {\n created: [],\n prepended: [],\n kept: [],\n overwritten: [],\n warnings: [],\n errors: [],\n rows: [],\n };\n\n const assetsRootStatus = await ensureRootDirectory(assetsRoot, 'asset-root-conflict');\n summary[assetsRootStatus].push('sduck-assets/');\n summary.rows.push({ path: 'sduck-assets/', status: assetsRootStatus });\n\n const workspaceRootStatus = await ensureRootDirectory(workspaceRoot, 'workspace-root-conflict');\n summary[workspaceRootStatus].push('sduck-workspace/');\n summary.rows.push({ path: 'sduck-workspace/', status: workspaceRootStatus });\n\n const actions = planInitActions(mode, await collectExistingEntries(projectRoot));\n const actionSummary = summarizeInitActions(actions);\n\n summary.created.push(...actionSummary.created);\n summary.kept.push(...actionSummary.kept);\n summary.overwritten.push(...actionSummary.overwritten);\n summary.warnings.push(...actionSummary.warnings);\n summary.errors.push(...actionSummary.errors);\n summary.rows.push(...actionSummary.rows);\n\n const conflict = actions.find((action) => action.action === 'error');\n\n if (conflict !== undefined) {\n throw new Error(\n `type-conflict: expected a file but found a directory at ${conflict.targetPath}. ` +\n 'Resolve it manually or move the conflicting path before retrying.',\n );\n }\n\n for (const action of actions) {\n if (action.action === 'keep') {\n continue;\n }\n\n const definition = ASSET_TEMPLATE_MAP[action.key];\n const sourcePath = join(\n assetSourceRoot,\n definition.relativePath.replace(/^sduck-assets[\\\\/]/, ''),\n );\n const targetPath = join(projectRoot, definition.relativePath);\n\n await ensureReadableFile(sourcePath);\n await mkdir(dirname(targetPath), { recursive: true });\n await copyFileIntoPlace(sourcePath, targetPath);\n }\n\n const agentTargets = listAgentRuleTargets(resolvedOptions.agents);\n const agentEntryKinds = new Map<string, FsEntryKind>();\n\n for (const target of agentTargets) {\n agentEntryKinds.set(\n target.outputPath,\n await getFsEntryKind(join(projectRoot, target.outputPath)),\n );\n }\n\n const existingContents = await collectExistingFileContents(projectRoot, agentTargets);\n const agentActions = planAgentRuleActions(mode, agentTargets, agentEntryKinds, existingContents);\n\n await applyAgentRuleActions(\n projectRoot,\n agentActions,\n existingContents,\n summary,\n resolvedOptions.agents,\n );\n\n return {\n mode,\n agents: resolvedOptions.agents,\n summary,\n didChange:\n summary.created.length > 0 || summary.prepended.length > 0 || summary.overwritten.length > 0,\n };\n}\n\nasync function applyAgentRuleActions(\n projectRoot: string,\n actions: readonly PlannedAgentRuleAction[],\n existingContents: Map<string, string>,\n summary: InitExecutionSummary,\n selectedAgents: SupportedAgentId[],\n): Promise<void> {\n for (const action of actions) {\n const targetPath = join(projectRoot, action.outputPath);\n const content = await renderAgentRuleContent(action, selectedAgents);\n\n if (action.mergeMode === 'create') {\n await mkdir(dirname(targetPath), { recursive: true });\n await writeFile(targetPath, content, 'utf8');\n summary.created.push(action.outputPath);\n summary.rows.push({ path: action.outputPath, status: 'created' });\n continue;\n }\n\n if (action.mergeMode === 'keep') {\n summary.kept.push(action.outputPath);\n summary.rows.push({ path: action.outputPath, status: 'kept' });\n summary.warnings.push(`Kept existing rule file: ${action.outputPath}`);\n continue;\n }\n\n await mkdir(dirname(targetPath), { recursive: true });\n\n if (action.mergeMode === 'prepend') {\n const currentContent = existingContents.get(action.outputPath) ?? '';\n await writeFile(targetPath, prependManagedBlock(currentContent, content.trimEnd()), 'utf8');\n summary.prepended.push(action.outputPath);\n summary.rows.push({ path: action.outputPath, status: 'prepended' });\n continue;\n }\n\n if (action.mergeMode === 'replace-block') {\n const currentContent = existingContents.get(action.outputPath) ?? '';\n await writeFile(targetPath, replaceManagedBlock(currentContent, content.trimEnd()), 'utf8');\n summary.overwritten.push(action.outputPath);\n summary.rows.push({ path: action.outputPath, status: 'overwritten' });\n continue;\n }\n\n await writeFile(targetPath, content, 'utf8');\n summary.overwritten.push(action.outputPath);\n summary.rows.push({ path: action.outputPath, status: 'overwritten' });\n }\n\n if (summary.kept.some((path) => path.endsWith('.md') || path.endsWith('.mdc'))) {\n summary.warnings.push(\n 'Run `sduck init --force` to refresh managed rule content for selected agents.',\n );\n }\n}\n","import { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { getFsEntryKind } from './fs.js';\n\nexport type SupportedTaskType = 'build' | 'feature' | 'fix' | 'refactor' | 'chore';\n\nexport const SUPPORTED_TASK_TYPES: readonly SupportedTaskType[] = [\n 'build',\n 'feature',\n 'fix',\n 'refactor',\n 'chore',\n];\n\nexport const EVAL_ASSET_RELATIVE_PATHS = {\n plan: join('eval', 'plan.yml'),\n spec: join('eval', 'spec.yml'),\n} as const;\n\nexport const SPEC_TEMPLATE_RELATIVE_PATHS: Record<SupportedTaskType, string> = {\n build: join('types', 'build.md'),\n feature: join('types', 'feature.md'),\n fix: join('types', 'fix.md'),\n refactor: join('types', 'refactor.md'),\n chore: join('types', 'chore.md'),\n};\n\nexport const INIT_ASSET_RELATIVE_PATHS = [\n EVAL_ASSET_RELATIVE_PATHS.spec,\n EVAL_ASSET_RELATIVE_PATHS.plan,\n ...Object.values(SPEC_TEMPLATE_RELATIVE_PATHS),\n] as const;\n\nexport async function getBundledAssetsRoot(): Promise<string> {\n const currentDirectoryPath = dirname(fileURLToPath(import.meta.url));\n const candidatePaths = [\n join(currentDirectoryPath, '..', '..', 'sduck-assets'),\n join(currentDirectoryPath, '..', 'sduck-assets'),\n ];\n\n for (const candidatePath of candidatePaths) {\n if ((await getFsEntryKind(candidatePath)) === 'directory') {\n return candidatePath;\n }\n }\n\n throw new Error('Unable to locate bundled sduck-assets directory.');\n}\n\nexport function isSupportedTaskType(value: string): value is SupportedTaskType {\n return SUPPORTED_TASK_TYPES.includes(value as SupportedTaskType);\n}\n\nexport function resolveSpecTemplateRelativePath(type: SupportedTaskType): string {\n return SPEC_TEMPLATE_RELATIVE_PATHS[type];\n}\n","import { checkbox } from '@inquirer/prompts';\n\nimport {\n approvePlans,\n createPlanApprovedAt,\n loadPlanApprovalCandidates,\n type PlanApproveCommandInput,\n type PlanApproveResult,\n type PlanApproveTarget,\n} from '../core/plan-approve.js';\n\nexport interface PlanApproveCommandResult {\n exitCode: number;\n stderr: string;\n stdout: string;\n}\n\nfunction padCell(value: string, width: number): string {\n return value.padEnd(width, ' ');\n}\n\nfunction buildResultTable(result: PlanApproveResult): string {\n const rows = [\n ...result.succeeded.map((row) => ({\n note: row.note,\n result: 'success',\n steps: String(row.steps),\n task: row.taskId,\n })),\n ...result.failed.map((row) => ({\n note: row.note,\n result: 'failed',\n steps: '-',\n task: row.taskId,\n })),\n ];\n\n const resultWidth = Math.max('Result'.length, ...rows.map((row) => row.result.length));\n const taskWidth = Math.max('Task'.length, ...rows.map((row) => row.task.length));\n const stepsWidth = Math.max('Steps'.length, ...rows.map((row) => row.steps.length));\n const noteWidth = Math.max('Note'.length, ...rows.map((row) => row.note.length));\n\n const border = `+-${'-'.repeat(resultWidth)}-+-${'-'.repeat(taskWidth)}-+-${'-'.repeat(stepsWidth)}-+-${'-'.repeat(noteWidth)}-+`;\n const header = `| ${padCell('Result', resultWidth)} | ${padCell('Task', taskWidth)} | ${padCell('Steps', stepsWidth)} | ${padCell('Note', noteWidth)} |`;\n const body = rows.map(\n (row) =>\n `| ${padCell(row.result, resultWidth)} | ${padCell(row.task, taskWidth)} | ${padCell(row.steps, stepsWidth)} | ${padCell(row.note, noteWidth)} |`,\n );\n\n return [border, header, border, ...body, border].join('\\n');\n}\n\nfunction formatTaskLabel(task: PlanApproveTarget): string {\n return `${task.id} (${task.status})`;\n}\n\nfunction formatSuccess(result: PlanApproveResult): string {\n const lines = [buildResultTable(result)];\n\n if (result.succeeded.length > 0) {\n lines.push('', '상태: IN_PROGRESS → 작업을 시작합니다.');\n }\n\n return lines.join('\\n');\n}\n\nasync function selectTargets(tasks: readonly PlanApproveTarget[]): Promise<PlanApproveTarget[]> {\n if (tasks.length <= 1 || !process.stdin.isTTY || !process.stdout.isTTY) {\n return [...tasks];\n }\n\n const selectedIds = await checkbox<string>({\n message: 'Select tasks to approve plan for',\n choices: tasks.map((task) => ({ checked: true, name: formatTaskLabel(task), value: task.id })),\n });\n\n return tasks.filter((task) => selectedIds.includes(task.id));\n}\n\nexport async function runPlanApproveCommand(\n input: PlanApproveCommandInput,\n projectRoot: string,\n): Promise<PlanApproveCommandResult> {\n try {\n const candidates = await loadPlanApprovalCandidates(projectRoot, input);\n\n if (candidates.length === 0) {\n throw new Error('No matching tasks awaiting plan approval.');\n }\n\n if (\n input.target !== undefined &&\n candidates.length > 1 &&\n (!process.stdin.isTTY || !process.stdout.isTTY)\n ) {\n throw new Error(\n 'Multiple matching tasks found; rerun interactively to choose approval targets.',\n );\n }\n\n const selectedTasks = await selectTargets(candidates);\n\n if (selectedTasks.length === 0) {\n throw new Error('No tasks selected for plan approval.');\n }\n\n const result = await approvePlans(projectRoot, selectedTasks, createPlanApprovedAt());\n\n if (result.succeeded.length === 0) {\n return {\n exitCode: 1,\n stderr: buildResultTable(result),\n stdout: '',\n };\n }\n\n return {\n exitCode: result.failed.length > 0 ? 1 : 0,\n stderr: result.failed.length > 0 ? '' : '',\n stdout: formatSuccess(result),\n };\n } catch (error) {\n return {\n exitCode: 1,\n stderr: error instanceof Error ? error.message : 'Unknown plan approval failure.',\n stdout: '',\n };\n }\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getFsEntryKind } from './fs.js';\nimport { listWorkspaceTasks, type WorkspaceTaskSummary } from './workspace.js';\nimport { formatUtcTimestamp } from '../utils/utc-date.js';\n\nexport interface PlanApproveCommandInput {\n target?: string;\n}\n\nexport interface PlanApproveTarget {\n createdAt?: string;\n id: string;\n path: string;\n slug?: string;\n status: string;\n}\n\nexport interface PlanApproveSuccessRow {\n note: string;\n steps: number;\n taskId: string;\n}\n\nexport interface PlanApproveFailureRow {\n note: string;\n taskId: string;\n}\n\nexport interface PlanApproveResult {\n approvedAt: string;\n failed: PlanApproveFailureRow[];\n nextStatus: 'IN_PROGRESS';\n succeeded: PlanApproveSuccessRow[];\n}\n\nexport function filterPlanApprovalCandidates(\n tasks: readonly WorkspaceTaskSummary[],\n): PlanApproveTarget[] {\n return tasks.filter((task) => task.status === 'SPEC_APPROVED');\n}\n\nexport function resolvePlanApprovalCandidates(\n tasks: readonly WorkspaceTaskSummary[],\n target: string | undefined,\n): PlanApproveTarget[] {\n const candidates = filterPlanApprovalCandidates(tasks);\n\n if (target === undefined || target.trim() === '') {\n return candidates;\n }\n\n const trimmedTarget = target.trim();\n\n return candidates.filter(\n (task) =>\n task.id === trimmedTarget || task.slug === trimmedTarget || task.id.endsWith(trimmedTarget),\n );\n}\n\nexport function countPlanSteps(planContent: string): number {\n const matches = planContent.match(/^## Step \\d+\\. .+$/gm);\n return matches?.length ?? 0;\n}\n\nexport function validatePlanHasSteps(planContent: string): void {\n if (countPlanSteps(planContent) === 0) {\n throw new Error('Plan does not contain any valid `## Step N. 제목` headers.');\n }\n}\n\nfunction updatePlanApprovalBlock(\n metaContent: string,\n approvedAt: string,\n totalSteps: number,\n): string {\n const withStatus = metaContent.replace(/^status:\\s+.+$/m, 'status: IN_PROGRESS');\n const withPlan = withStatus.replace(\n /plan:\\n {2}approved:\\s+false\\n {2}approved_at:\\s+null/m,\n `plan:\\n approved: true\\n approved_at: ${approvedAt}`,\n );\n\n return withPlan.replace(\n /steps:\\n {2}total:\\s+null\\n {2}completed:\\s+\\[\\]/m,\n `steps:\\n total: ${String(totalSteps)}\\n completed: []`,\n );\n}\n\nexport async function approvePlans(\n projectRoot: string,\n tasks: readonly PlanApproveTarget[],\n approvedAt: string,\n): Promise<PlanApproveResult> {\n const succeeded: PlanApproveSuccessRow[] = [];\n const failed: PlanApproveFailureRow[] = [];\n\n for (const task of tasks) {\n if (task.status !== 'SPEC_APPROVED') {\n failed.push({\n note: `task is not awaiting plan approval (${task.status})`,\n taskId: task.id,\n });\n continue;\n }\n\n const metaPath = join(projectRoot, task.path, 'meta.yml');\n const planPath = join(projectRoot, task.path, 'plan.md');\n\n if ((await getFsEntryKind(metaPath)) !== 'file') {\n failed.push({ note: 'missing meta.yml', taskId: task.id });\n continue;\n }\n\n if ((await getFsEntryKind(planPath)) !== 'file') {\n failed.push({ note: 'missing plan.md', taskId: task.id });\n continue;\n }\n\n const planContent = await readFile(planPath, 'utf8');\n const totalSteps = countPlanSteps(planContent);\n\n if (totalSteps === 0) {\n failed.push({ note: 'missing valid Step headers', taskId: task.id });\n continue;\n }\n\n const updatedMeta = updatePlanApprovalBlock(\n await readFile(metaPath, 'utf8'),\n approvedAt,\n totalSteps,\n );\n await writeFile(metaPath, updatedMeta, 'utf8');\n\n succeeded.push({ note: 'moved to IN_PROGRESS', steps: totalSteps, taskId: task.id });\n }\n\n return {\n approvedAt,\n failed,\n nextStatus: 'IN_PROGRESS',\n succeeded,\n };\n}\n\nexport async function loadPlanApprovalCandidates(\n projectRoot: string,\n input: PlanApproveCommandInput,\n): Promise<PlanApproveTarget[]> {\n const tasks = await listWorkspaceTasks(projectRoot);\n return resolvePlanApprovalCandidates(tasks, input.target);\n}\n\nexport function createPlanApprovedAt(date = new Date()): string {\n return formatUtcTimestamp(date);\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getFsEntryKind } from './fs.js';\n\nexport interface ActiveTaskSummary {\n id: string;\n path: string;\n status: string;\n}\n\nexport interface WorkspaceTaskSummary {\n createdAt?: string;\n id: string;\n path: string;\n slug?: string;\n status: string;\n}\n\nconst ACTIVE_STATUSES = new Set(['IN_PROGRESS', 'PENDING_SPEC_APPROVAL', 'PENDING_PLAN_APPROVAL']);\n\ninterface ParsedMeta {\n createdAt?: string;\n id?: string;\n slug?: string;\n status?: string;\n}\n\nfunction parseMetaText(content: string): ParsedMeta {\n const createdAtMatch = /^created_at:\\s+(.+)$/m.exec(content);\n const idMatch = /^id:\\s+(.+)$/m.exec(content);\n const slugMatch = /^slug:\\s+(.+)$/m.exec(content);\n const statusMatch = /^status:\\s+(.+)$/m.exec(content);\n const parsedMeta: ParsedMeta = {};\n\n if (createdAtMatch?.[1] !== undefined) {\n parsedMeta.createdAt = createdAtMatch[1].trim();\n }\n\n if (idMatch?.[1] !== undefined) {\n parsedMeta.id = idMatch[1].trim();\n }\n\n if (slugMatch?.[1] !== undefined) {\n parsedMeta.slug = slugMatch[1].trim();\n }\n\n if (statusMatch?.[1] !== undefined) {\n parsedMeta.status = statusMatch[1].trim();\n }\n\n return parsedMeta;\n}\n\nexport function sortTasksByRecency(tasks: readonly WorkspaceTaskSummary[]): WorkspaceTaskSummary[] {\n return [...tasks].sort((left, right) => {\n const leftValue = left.createdAt ?? '';\n const rightValue = right.createdAt ?? '';\n\n return rightValue.localeCompare(leftValue);\n });\n}\n\nexport async function listWorkspaceTasks(projectRoot: string): Promise<WorkspaceTaskSummary[]> {\n const workspaceRoot = join(projectRoot, 'sduck-workspace');\n\n if ((await getFsEntryKind(workspaceRoot)) !== 'directory') {\n return [];\n }\n\n const { readdir } = await import('node:fs/promises');\n const entries = await readdir(workspaceRoot, { withFileTypes: true });\n const tasks: WorkspaceTaskSummary[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) {\n continue;\n }\n\n const relativePath = join('sduck-workspace', entry.name);\n const metaPath = join(projectRoot, relativePath, 'meta.yml');\n\n if ((await getFsEntryKind(metaPath)) !== 'file') {\n continue;\n }\n\n const parsedMeta = parseMetaText(await readFile(metaPath, 'utf8'));\n\n if (parsedMeta.id !== undefined && parsedMeta.status !== undefined) {\n const task: WorkspaceTaskSummary = {\n id: parsedMeta.id,\n path: relativePath,\n status: parsedMeta.status,\n };\n\n if (parsedMeta.createdAt !== undefined) {\n task.createdAt = parsedMeta.createdAt;\n }\n\n if (parsedMeta.slug !== undefined) {\n task.slug = parsedMeta.slug;\n }\n\n tasks.push(task);\n }\n }\n\n return sortTasksByRecency(tasks);\n}\n\nexport async function findActiveTask(projectRoot: string): Promise<ActiveTaskSummary | null> {\n const tasks = await listWorkspaceTasks(projectRoot);\n\n for (const task of tasks) {\n if (ACTIVE_STATUSES.has(task.status)) {\n return {\n id: task.id,\n path: task.path,\n status: task.status,\n };\n }\n }\n\n return null;\n}\n","function pad2(value: number): string {\n return String(value).padStart(2, '0');\n}\n\nexport function formatUtcDate(date: Date): string {\n const year = String(date.getUTCFullYear());\n const month = pad2(date.getUTCMonth() + 1);\n const day = pad2(date.getUTCDate());\n\n return `${year}-${month}-${day}`;\n}\n\nexport function formatUtcTimestamp(date: Date): string {\n const year = String(date.getUTCFullYear());\n const month = pad2(date.getUTCMonth() + 1);\n const day = pad2(date.getUTCDate());\n const hour = pad2(date.getUTCHours());\n const minute = pad2(date.getUTCMinutes());\n const second = pad2(date.getUTCSeconds());\n\n return `${year}-${month}-${day}T${hour}:${minute}:${second}Z`;\n}\n","import { checkbox } from '@inquirer/prompts';\n\nimport {\n approveSpecs,\n createSpecApprovedAt,\n loadSpecApprovalCandidates,\n type SpecApproveCommandInput,\n type SpecApproveResult,\n type SpecApproveTarget,\n} from '../core/spec-approve.js';\n\nexport interface SpecApproveCommandResult {\n exitCode: number;\n stderr: string;\n stdout: string;\n}\n\nfunction formatTaskLabel(task: SpecApproveTarget): string {\n return `${task.id} (${task.status})`;\n}\n\nfunction formatSuccess(result: SpecApproveResult, tasks: readonly SpecApproveTarget[]): string {\n const lines = ['스펙 승인됨'];\n\n for (const task of tasks) {\n lines.push(`- ${task.path} -> ${result.nextStatus}`);\n }\n\n lines.push('상태: SPEC_APPROVED → 플랜 작성을 시작합니다.');\n\n return lines.join('\\n');\n}\n\nasync function selectTargets(tasks: readonly SpecApproveTarget[]): Promise<SpecApproveTarget[]> {\n if (tasks.length <= 1 || !process.stdin.isTTY || !process.stdout.isTTY) {\n return [...tasks];\n }\n\n const selectedIds = await checkbox<string>({\n message: 'Select tasks to approve',\n choices: tasks.map((task) => ({\n checked: true,\n name: formatTaskLabel(task),\n value: task.id,\n })),\n });\n\n return tasks.filter((task) => selectedIds.includes(task.id));\n}\n\nexport async function runSpecApproveCommand(\n input: SpecApproveCommandInput,\n projectRoot: string,\n): Promise<SpecApproveCommandResult> {\n try {\n const candidates = await loadSpecApprovalCandidates(projectRoot, input);\n\n if (candidates.length === 0) {\n throw new Error('No matching tasks awaiting spec approval.');\n }\n\n if (\n input.target !== undefined &&\n candidates.length > 1 &&\n (!process.stdin.isTTY || !process.stdout.isTTY)\n ) {\n throw new Error(\n 'Multiple matching tasks found; rerun interactively to choose approval targets.',\n );\n }\n\n const selectedTasks = await selectTargets(candidates);\n\n if (selectedTasks.length === 0) {\n throw new Error('No tasks selected for spec approval.');\n }\n\n const result = await approveSpecs(projectRoot, selectedTasks, createSpecApprovedAt());\n\n return {\n exitCode: 0,\n stderr: '',\n stdout: formatSuccess(result, selectedTasks),\n };\n } catch (error) {\n return {\n exitCode: 1,\n stderr: error instanceof Error ? error.message : 'Unknown spec approval failure.',\n stdout: '',\n };\n }\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getFsEntryKind } from './fs.js';\nimport { listWorkspaceTasks, type WorkspaceTaskSummary } from './workspace.js';\nimport { formatUtcTimestamp } from '../utils/utc-date.js';\n\nexport interface SpecApproveCommandInput {\n target?: string;\n}\n\nexport interface SpecApproveTarget {\n createdAt?: string;\n id: string;\n path: string;\n slug?: string;\n status: string;\n}\n\nexport interface SpecApproveResult {\n approvedAt: string;\n approvedTaskIds: string[];\n nextStatus: 'SPEC_APPROVED';\n}\n\nexport function filterApprovalCandidates(\n tasks: readonly WorkspaceTaskSummary[],\n): SpecApproveTarget[] {\n return tasks.filter((task) => task.status === 'PENDING_SPEC_APPROVAL');\n}\n\nexport function resolveTargetCandidates(\n tasks: readonly WorkspaceTaskSummary[],\n target: string | undefined,\n): SpecApproveTarget[] {\n const candidates = filterApprovalCandidates(tasks);\n\n if (target === undefined || target.trim() === '') {\n return candidates;\n }\n\n const trimmedTarget = target.trim();\n\n return candidates.filter(\n (task) =>\n task.id === trimmedTarget || task.slug === trimmedTarget || task.id.endsWith(trimmedTarget),\n );\n}\n\nexport function validateSpecApprovalTargets(tasks: readonly SpecApproveTarget[]): void {\n if (tasks.length === 0) {\n throw new Error('No approvable spec tasks found.');\n }\n\n const invalidTask = tasks.find((task) => task.status !== 'PENDING_SPEC_APPROVAL');\n\n if (invalidTask !== undefined) {\n throw new Error(\n `Task ${invalidTask.id} is not awaiting spec approval (${invalidTask.status}).`,\n );\n }\n}\n\nfunction updateSpecApprovalBlock(metaContent: string, approvedAt: string): string {\n const withStatus = metaContent.replace(/^status:\\s+.+$/m, 'status: SPEC_APPROVED');\n\n return withStatus.replace(\n /spec:\\n {2}approved:\\s+false\\n {2}approved_at:\\s+null/m,\n `spec:\\n approved: true\\n approved_at: ${approvedAt}`,\n );\n}\n\nexport async function approveSpecs(\n projectRoot: string,\n tasks: readonly SpecApproveTarget[],\n approvedAt: string,\n): Promise<SpecApproveResult> {\n validateSpecApprovalTargets(tasks);\n\n for (const task of tasks) {\n const metaPath = join(projectRoot, task.path, 'meta.yml');\n\n if ((await getFsEntryKind(metaPath)) !== 'file') {\n throw new Error(`Missing meta.yml for task ${task.id}.`);\n }\n\n const updatedContent = updateSpecApprovalBlock(await readFile(metaPath, 'utf8'), approvedAt);\n await writeFile(metaPath, updatedContent, 'utf8');\n }\n\n return {\n approvedAt,\n approvedTaskIds: tasks.map((task) => task.id),\n nextStatus: 'SPEC_APPROVED',\n };\n}\n\nexport async function loadSpecApprovalCandidates(\n projectRoot: string,\n input: SpecApproveCommandInput,\n): Promise<SpecApproveTarget[]> {\n const tasks = await listWorkspaceTasks(projectRoot);\n return resolveTargetCandidates(tasks, input.target);\n}\n\nexport function createSpecApprovedAt(date = new Date()): string {\n return formatUtcTimestamp(date);\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport {\n getBundledAssetsRoot,\n isSupportedTaskType,\n resolveSpecTemplateRelativePath,\n type SupportedTaskType,\n} from './assets.js';\nimport { getFsEntryKind } from './fs.js';\nimport { findActiveTask, type ActiveTaskSummary } from './workspace.js';\nimport { formatUtcDate, formatUtcTimestamp } from '../utils/utc-date.js';\n\nexport interface StartCommandInput {\n type: SupportedTaskType;\n slug: string;\n}\n\nexport interface StartExecutionResult {\n workspaceId: string;\n workspacePath: string;\n status: 'PENDING_SPEC_APPROVAL';\n}\n\nexport function normalizeSlug(input: string): string {\n return input\n .trim()\n .toLowerCase()\n .replace(/[_\\s]+/g, '-')\n .replace(/[^a-z0-9-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport function validateSlug(slug: string): void {\n if (slug === '') {\n throw new Error('Invalid slug: slug cannot be empty after normalization.');\n }\n\n if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) {\n throw new Error('Invalid slug: use lowercase kebab-case only.');\n }\n}\n\nexport function createWorkspaceId(date: Date, type: SupportedTaskType, slug: string): string {\n const year = String(date.getUTCFullYear());\n const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n const day = String(date.getUTCDate()).padStart(2, '0');\n const hour = String(date.getUTCHours()).padStart(2, '0');\n const minute = String(date.getUTCMinutes()).padStart(2, '0');\n\n return `${year}${month}${day}-${hour}${minute}-${type}-${slug}`;\n}\n\nexport function renderInitialMeta(input: {\n createdAt: string;\n id: string;\n slug: string;\n type: SupportedTaskType;\n}): string {\n return [\n `id: ${input.id}`,\n `type: ${input.type}`,\n `slug: ${input.slug}`,\n `created_at: ${input.createdAt}`,\n '',\n 'status: PENDING_SPEC_APPROVAL',\n '',\n 'spec:',\n ' approved: false',\n ' approved_at: null',\n '',\n 'plan:',\n ' approved: false',\n ' approved_at: null',\n '',\n 'steps:',\n ' total: null',\n ' completed: []',\n '',\n 'completed_at: null',\n '',\n ].join('\\n');\n}\n\nexport async function resolveSpecTemplatePath(type: SupportedTaskType): Promise<string> {\n const assetsRoot = await getBundledAssetsRoot();\n return join(assetsRoot, resolveSpecTemplateRelativePath(type));\n}\n\nfunction applyTemplateDefaults(\n template: string,\n type: SupportedTaskType,\n slug: string,\n currentDate: Date,\n): string {\n const displayName = slug.replace(/-/g, ' ');\n\n return template\n .replace(/\\{기능명\\}/g, displayName)\n .replace(/\\{버그 요약 한 줄\\}/g, displayName)\n .replace(/YYYY-MM-DD/g, formatUtcDate(currentDate))\n .replace(/> \\*\\*작성자:\\*\\*\\s*$/m, '> **작성자:** taehee')\n .replace(/> \\*\\*연관 티켓:\\*\\*\\s*$/m, '> **연관 티켓:** -')\n .replace(/^# \\[(feature|fix|refactor|chore|build)\\] .*/m, `# [${type}] ${displayName}`);\n}\n\nexport async function startTask(\n rawType: string,\n rawSlug: string,\n projectRoot: string,\n currentDate = new Date(),\n): Promise<StartExecutionResult> {\n if (!isSupportedTaskType(rawType)) {\n throw new Error(`Unsupported type: ${rawType}`);\n }\n\n const slug = normalizeSlug(rawSlug);\n validateSlug(slug);\n\n const activeTask = await findActiveTask(projectRoot);\n\n if (activeTask !== null) {\n throw new Error(\n `Active task exists: ${activeTask.id} (${activeTask.status}) at ${activeTask.path}. Finish or approve it before starting a new task.`,\n );\n }\n\n const workspaceId = createWorkspaceId(currentDate, rawType, slug);\n const workspacePath = join('sduck-workspace', workspaceId);\n const absoluteWorkspacePath = join(projectRoot, workspacePath);\n\n if ((await getFsEntryKind(absoluteWorkspacePath)) !== 'missing') {\n throw new Error(`Workspace already exists: ${workspacePath}`);\n }\n\n const workspaceRoot = join(projectRoot, 'sduck-workspace');\n await mkdir(workspaceRoot, { recursive: true });\n await mkdir(absoluteWorkspacePath, { recursive: false });\n\n const templatePath = await resolveSpecTemplatePath(rawType);\n if ((await getFsEntryKind(templatePath)) !== 'file') {\n throw new Error(`Missing spec template for type '${rawType}' at ${templatePath}`);\n }\n\n const specTemplate = await readFile(templatePath, 'utf8');\n const specContent = applyTemplateDefaults(specTemplate, rawType, slug, currentDate);\n const metaContent = renderInitialMeta({\n createdAt: formatUtcTimestamp(currentDate),\n id: workspaceId,\n slug,\n type: rawType,\n });\n\n await writeFile(join(absoluteWorkspacePath, 'meta.yml'), metaContent, 'utf8');\n await writeFile(join(absoluteWorkspacePath, 'spec.md'), specContent, 'utf8');\n await writeFile(join(absoluteWorkspacePath, 'plan.md'), '', 'utf8');\n\n return {\n workspaceId,\n workspacePath,\n status: 'PENDING_SPEC_APPROVAL',\n };\n}\n\nexport type { ActiveTaskSummary };\n","import { startTask } from '../core/start.js';\n\nexport interface StartCommandResult {\n exitCode: number;\n stderr: string;\n stdout: string;\n}\n\nexport async function runStartCommand(\n type: string,\n slug: string,\n projectRoot: string,\n): Promise<StartCommandResult> {\n try {\n const result = await startTask(type, slug, projectRoot);\n\n return {\n exitCode: 0,\n stderr: '',\n stdout: [\n '작업 디렉토리 생성됨',\n `경로: ${result.workspacePath}/`,\n `상태: ${result.status}`,\n ].join('\\n'),\n };\n } catch (error) {\n return {\n exitCode: 1,\n stderr: error instanceof Error ? error.message : 'Unknown start failure.',\n stdout: '',\n };\n }\n}\n","export const CLI_NAME = 'sduck';\n\nexport const CLI_DESCRIPTION = 'Spec-Driven Development workflow bootstrap CLI';\n\nexport const PLACEHOLDER_MESSAGE =\n 'Core workflow commands are planned but not implemented in this bootstrap yet.';\n\nexport function normalizeCommandName(input: string): string {\n return input.trim().toLowerCase().replace(/\\s+/g, '-');\n}\n"],"mappings":"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","names":["mkdir","readFile","dirname","join","dirname","join","fileURLToPath","join","dirname","fileURLToPath","join","readFile","mkdir","dirname","checkbox","readFile","writeFile","join","readFile","join","join","readFile","join","readFile","writeFile","padCell","checkbox","checkbox","readFile","writeFile","join","join","readFile","writeFile","formatTaskLabel","formatSuccess","selectTargets","checkbox","mkdir","readFile","writeFile","join","join","mkdir","readFile","writeFile"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sduck/sduck-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Spec-Driven Development CLI bootstrap",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"sduck": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"sduck-assets"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"dev": "tsx src/cli.ts",
|
|
18
|
+
"build": "tsup src/cli.ts --config tsup.config.ts",
|
|
19
|
+
"lint": "eslint . --max-warnings=0",
|
|
20
|
+
"format": "prettier --write .",
|
|
21
|
+
"format:check": "prettier --check .",
|
|
22
|
+
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
23
|
+
"test:unit": "vitest run tests/unit",
|
|
24
|
+
"test:e2e": "vitest run tests/e2e",
|
|
25
|
+
"test": "npm run test:unit && npm run test:e2e",
|
|
26
|
+
"prepare": "husky"
|
|
27
|
+
},
|
|
28
|
+
"lint-staged": {
|
|
29
|
+
"*.{js,mjs,cjs,ts,mts,cts}": [
|
|
30
|
+
"eslint --fix",
|
|
31
|
+
"prettier --write"
|
|
32
|
+
],
|
|
33
|
+
"*.{json,md,yml,yaml}": [
|
|
34
|
+
"prettier --write"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@inquirer/prompts": "^7.8.6",
|
|
39
|
+
"commander": "^14.0.1",
|
|
40
|
+
"js-yaml": "^4.1.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@eslint/js": "^9.23.0",
|
|
44
|
+
"@types/node": "^22.13.14",
|
|
45
|
+
"eslint": "^9.23.0",
|
|
46
|
+
"eslint-config-prettier": "^10.1.1",
|
|
47
|
+
"eslint-plugin-import": "^2.31.0",
|
|
48
|
+
"eslint-import-resolver-typescript": "^4.3.5",
|
|
49
|
+
"eslint-plugin-n": "^17.16.2",
|
|
50
|
+
"husky": "^9.1.7",
|
|
51
|
+
"lint-staged": "^15.5.0",
|
|
52
|
+
"prettier": "^3.5.3",
|
|
53
|
+
"tsup": "^8.4.0",
|
|
54
|
+
"tsx": "^4.19.3",
|
|
55
|
+
"typescript": "^5.8.2",
|
|
56
|
+
"typescript-eslint": "^8.28.0",
|
|
57
|
+
"vitest": "^3.0.8"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# SDD Workflow Rules
|
|
2
|
+
|
|
3
|
+
- Start each session by checking `sduck-workspace/` and any active task `meta.yml`.
|
|
4
|
+
- Do not write implementation code before spec approval.
|
|
5
|
+
- Do not start implementation before plan approval.
|
|
6
|
+
- Follow the workflow order: `spec -> approval -> plan -> approval -> implementation`.
|
|
7
|
+
- Respect `meta.yml` state transitions and update step completion immediately.
|
|
8
|
+
- Read and apply user memo text appended with `<-` in `spec.md` and `plan.md`.
|
|
9
|
+
- Use `sduck-assets/eval/spec.yml`, `sduck-assets/eval/plan.yml`, and `sduck-assets/eval/task.yml` when evaluating spec, plan, and completed task quality.
|
|
10
|
+
- After implementation is complete, run task evaluation, show the results, and only then move to `task done` or final completion processing.
|
|
11
|
+
- Do not mark a task `DONE` until all completion criteria are satisfied.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
|
|
3
|
+
plan_evaluation:
|
|
4
|
+
scale:
|
|
5
|
+
min: 1
|
|
6
|
+
max: 5
|
|
7
|
+
|
|
8
|
+
criteria:
|
|
9
|
+
- key: semantic_clarity
|
|
10
|
+
label: semantic clarity
|
|
11
|
+
question: 의미가 분명한가
|
|
12
|
+
|
|
13
|
+
- key: abstraction
|
|
14
|
+
label: abstraction
|
|
15
|
+
question: 추상화 수준이 적절한가
|
|
16
|
+
|
|
17
|
+
- key: typing
|
|
18
|
+
label: typing
|
|
19
|
+
question: 타입 안정성을 충분히 고려했는가
|
|
20
|
+
|
|
21
|
+
- key: security
|
|
22
|
+
label: security
|
|
23
|
+
question: 보안상 문제 가능성을 줄였는가
|
|
24
|
+
|
|
25
|
+
- key: maintainability
|
|
26
|
+
label: maintainability
|
|
27
|
+
question: 유지보수하기 쉬운 구조인가
|
|
28
|
+
|
|
29
|
+
- key: testability
|
|
30
|
+
label: testability
|
|
31
|
+
question: 테스트하기 쉬운가
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
|
|
3
|
+
spec_evaluation:
|
|
4
|
+
scale:
|
|
5
|
+
min: 1
|
|
6
|
+
max: 5
|
|
7
|
+
|
|
8
|
+
criteria:
|
|
9
|
+
- key: problem_clarity
|
|
10
|
+
label: problem clarity
|
|
11
|
+
question: 문제와 목표가 분명한가
|
|
12
|
+
|
|
13
|
+
- key: scope_definition
|
|
14
|
+
label: scope definition
|
|
15
|
+
question: 범위와 제외 범위가 명확한가
|
|
16
|
+
|
|
17
|
+
- key: completion_criteria
|
|
18
|
+
label: completion criteria
|
|
19
|
+
question: 완료 조건이 검증 가능하게 정의되었는가
|
|
20
|
+
|
|
21
|
+
- key: feasibility
|
|
22
|
+
label: feasibility
|
|
23
|
+
question: 현재 시스템 기준으로 실행 가능한가
|
|
24
|
+
|
|
25
|
+
- key: risk_coverage
|
|
26
|
+
label: risk coverage
|
|
27
|
+
question: 엣지 케이스와 영향 범위를 충분히 고려했는가
|
|
28
|
+
|
|
29
|
+
- key: testability
|
|
30
|
+
label: testability
|
|
31
|
+
question: 테스트 및 검증 방법이 드러나는가
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
|
|
3
|
+
task_evaluation:
|
|
4
|
+
scale:
|
|
5
|
+
min: 1
|
|
6
|
+
max: 5
|
|
7
|
+
|
|
8
|
+
criteria:
|
|
9
|
+
- key: spec_alignment
|
|
10
|
+
label: spec alignment
|
|
11
|
+
question: 구현 결과가 승인된 spec과 일치하는가
|
|
12
|
+
|
|
13
|
+
- key: plan_alignment
|
|
14
|
+
label: plan alignment
|
|
15
|
+
question: 구현 결과가 승인된 plan의 단계와 의도를 충실히 반영하는가
|
|
16
|
+
|
|
17
|
+
- key: implementation_quality
|
|
18
|
+
label: implementation quality
|
|
19
|
+
question: 구현 품질과 구조가 충분히 명확하고 견고한가
|
|
20
|
+
|
|
21
|
+
- key: test_completeness
|
|
22
|
+
label: test completeness
|
|
23
|
+
question: 테스트가 핵심 동작과 회귀 위험을 충분히 검증하는가
|
|
24
|
+
|
|
25
|
+
- key: documentation_quality
|
|
26
|
+
label: documentation quality
|
|
27
|
+
question: 필요한 문서와 사용 흐름이 구현과 일치하게 정리되었는가
|
|
28
|
+
|
|
29
|
+
- key: maintainability
|
|
30
|
+
label: maintainability
|
|
31
|
+
question: 이후 수정과 확장이 쉬운 상태로 정리되었는가
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# [build] {프로젝트명} — 프로젝트 초기 설정
|
|
2
|
+
|
|
3
|
+
> **작업 타입:** `build` (Project Init/Build)
|
|
4
|
+
> **작성자:**
|
|
5
|
+
> **작성일:** YYYY-MM-DD
|
|
6
|
+
> **연관 티켓:**
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. 프로젝트 개요
|
|
11
|
+
|
|
12
|
+
### 목적 및 배경
|
|
13
|
+
|
|
14
|
+
<!-- 이 프로젝트가 왜 존재하는지, 어떤 문제를 해결하는지 서술 -->
|
|
15
|
+
|
|
16
|
+
### 핵심 목표
|
|
17
|
+
|
|
18
|
+
<!-- 이 빌드 작업을 통해 달성하고자 하는 구체적인 결과물을 나열 -->
|
|
19
|
+
|
|
20
|
+
- [ ]
|
|
21
|
+
- [ ]
|
|
22
|
+
- [ ]
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 2. 기술 스택
|
|
27
|
+
|
|
28
|
+
| 구분 | 선택 | 버전 | 선택 이유 |
|
|
29
|
+
| ------------------- | ---- | ---- | --------- |
|
|
30
|
+
| 언어 | | | |
|
|
31
|
+
| 런타임 | | | |
|
|
32
|
+
| 프레임워크 | | | |
|
|
33
|
+
| DB | | | |
|
|
34
|
+
| ORM / Query Builder | | | |
|
|
35
|
+
| 상태 관리 | | | |
|
|
36
|
+
| 테스트 프레임워크 | | | |
|
|
37
|
+
| CI/CD | | | |
|
|
38
|
+
| 컨테이너 | | | |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 3. 아키텍처
|
|
43
|
+
|
|
44
|
+
### 전체 구조
|
|
45
|
+
|
|
46
|
+
<!-- 디렉토리 구조 및 레이어 분리 방식 기술 (예: Clean Architecture, MVC 등) -->
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
{project-root}/
|
|
50
|
+
├── src/
|
|
51
|
+
│ ├── ...
|
|
52
|
+
├── tests/
|
|
53
|
+
│ ├── ...
|
|
54
|
+
└── ...
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 계층 및 의존성 규칙
|
|
58
|
+
|
|
59
|
+
<!-- 각 계층(Layer)의 역할과 의존 방향을 명시 -->
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 4. 코드 컨벤션
|
|
64
|
+
|
|
65
|
+
### 네이밍 규칙
|
|
66
|
+
|
|
67
|
+
| 대상 | 규칙 | 예시 |
|
|
68
|
+
| ----------------- | ---- | ---- |
|
|
69
|
+
| 파일명 | | |
|
|
70
|
+
| 클래스 / 컴포넌트 | | |
|
|
71
|
+
| 함수 / 메서드 | | |
|
|
72
|
+
| 변수 | | |
|
|
73
|
+
| 상수 | | |
|
|
74
|
+
| 타입 / 인터페이스 | | |
|
|
75
|
+
|
|
76
|
+
### 포맷팅
|
|
77
|
+
|
|
78
|
+
<!-- 들여쓰기, 줄 길이, 세미콜론 등 -->
|
|
79
|
+
|
|
80
|
+
- 들여쓰기:
|
|
81
|
+
- 최대 줄 길이:
|
|
82
|
+
- 기타:
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 5. 린팅 및 타입 검사
|
|
87
|
+
|
|
88
|
+
| 도구 | 설정 파일 | 주요 규칙 |
|
|
89
|
+
| ------------ | --------- | --------- |
|
|
90
|
+
| Linter | | |
|
|
91
|
+
| Formatter | | |
|
|
92
|
+
| Type Checker | | |
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
<!-- 핵심 설정 값 또는 extends/plugins 목록 -->
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 6. 테스트 전략
|
|
101
|
+
|
|
102
|
+
### 목표 커버리지
|
|
103
|
+
|
|
104
|
+
- 전체: **80%** 이상 (기본값)
|
|
105
|
+
- 비즈니스 로직 (Unit): **%** 이상
|
|
106
|
+
- API / 통합 (Integration): **%** 이상
|
|
107
|
+
|
|
108
|
+
### 테스트 레벨별 전략
|
|
109
|
+
|
|
110
|
+
| 레벨 | 도구 | 대상 범위 | 비고 |
|
|
111
|
+
| ----------- | ---- | --------- | ---- |
|
|
112
|
+
| Unit | | | |
|
|
113
|
+
| Integration | | | |
|
|
114
|
+
| E2E | | | |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 7. 환경 구성
|
|
119
|
+
|
|
120
|
+
### 환경 목록
|
|
121
|
+
|
|
122
|
+
| 환경 | 목적 | 배포 방식 |
|
|
123
|
+
| ------------ | ----------- | --------- |
|
|
124
|
+
| `local` | 개발자 로컬 | 수동 |
|
|
125
|
+
| `dev` | 통합 개발 | CI 자동 |
|
|
126
|
+
| `staging` | QA / 검증 | 수동 승인 |
|
|
127
|
+
| `production` | 운영 | 수동 승인 |
|
|
128
|
+
|
|
129
|
+
### 환경 변수
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
# 필수 환경 변수 목록 (값 제외, 키만 명시)
|
|
133
|
+
APP_ENV=
|
|
134
|
+
DATABASE_URL=
|
|
135
|
+
SECRET_KEY=
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 8. Git 전략
|
|
141
|
+
|
|
142
|
+
### 브랜치 모델
|
|
143
|
+
|
|
144
|
+
<!-- 예: Git Flow / GitHub Flow / Trunk-based 중 선택 및 이유 -->
|
|
145
|
+
|
|
146
|
+
### 커밋 메시지 컨벤션
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
<type>(<scope>): <subject>
|
|
150
|
+
|
|
151
|
+
예) feat(auth): add JWT refresh token logic
|
|
152
|
+
fix(api): resolve null pointer on user fetch
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### PR / MR 규칙
|
|
156
|
+
|
|
157
|
+
- 최소 리뷰어 수:
|
|
158
|
+
- 머지 방식: (Squash / Rebase / Merge Commit)
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 9. CI/CD 파이프라인
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
Push → Lint & Type Check → Unit Test → Build → (Integration Test) → Deploy
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
- **Lint / Type Check:** 실패 시 파이프라인 즉시 중단
|
|
169
|
+
- **테스트 커버리지 임계값:** 미달 시 배포 차단
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 10. 제약 조건 및 비기능 요구사항
|
|
174
|
+
|
|
175
|
+
| 항목 | 요구사항 | 측정 기준 |
|
|
176
|
+
| ----------------------- | -------- | --------- |
|
|
177
|
+
| 성능 | | |
|
|
178
|
+
| 보안 | | |
|
|
179
|
+
| 접근성 | | |
|
|
180
|
+
| 브라우저 / OS 지원 범위 | | |
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 11. 미결 사항 (Open Questions)
|
|
185
|
+
|
|
186
|
+
<!-- 아직 결정되지 않았거나 추가 논의가 필요한 항목 -->
|
|
187
|
+
|
|
188
|
+
- [ ]
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 12. 참고 자료
|
|
193
|
+
|
|
194
|
+
-
|