()
| 135 | fs.existsSync(path.join(dir, 'skills')) && |
| 136 | fs.existsSync(path.join(dir, 'package.json')) && |
| 137 | JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8')).name === 'citadel'; |
| 138 | } |
| 139 | |
| 140 | function main() { |
| 141 | const options = parseArgs(process.argv); |
| 142 | const { projectRoot, exportOnly, legacyApply } = options; |
| 143 | |
| 144 | if (isCitadelRepo(projectRoot)) { |
| 145 | console.error('Error: unharness cannot run against the Citadel plugin repo itself.'); |
| 146 | console.error('Run this from your project directory, or pass the project path as an argument:'); |
| 147 | console.error(' node /path/to/Citadel/scripts/unharness.js /your/project'); |
| 148 | process.exit(1); |
| 149 | } |
| 150 | |
| 151 | const planning = path.join(projectRoot, '.planning'); |
| 152 | const citadelDir = path.join(projectRoot, '.citadel'); |
| 153 | const activeReceipt = path.join(citadelDir, 'adoption', 'active.json'); |
| 154 | |
| 155 | if (!exportOnly && !legacyApply) { |
| 156 | console.error(''); |
| 157 | console.error('Citadel Unharness is now plan-first.'); |
| 158 | if (fs.existsSync(activeReceipt)) { |
| 159 | console.error('This project has a governed adoption receipt.'); |
| 160 | console.error(`Run: node "${path.join(__dirname, 'adopt.js')}" leave plan --target "${projectRoot}"`); |
| 161 | console.error('Review and save that plan, then run leave apply with its confirmation token.'); |
| 162 | } else { |
| 163 | console.error('No governed adoption receipt was found, so exact ownership is unknown.'); |
| 164 | console.error(`Run: node "${path.join(__dirname, 'adopt.js')}" import plan "${path.resolve(__dirname, '..')}" --target "${projectRoot}"`); |
| 165 | console.error('After importing and reviewing ownership, use adopt leave plan|apply.'); |
| 166 | console.error('The one-major emergency fallback is --legacy-apply; it cannot prove exact removal.'); |
| 167 | } |
| 168 | process.exitCode = 2; |
| 169 | return; |
| 170 | } |
| 171 | const pluginRootFile = path.join(citadelDir, 'plugin-root.txt'); |
| 172 | const citadelRoot = fs.existsSync(pluginRootFile) |
| 173 | ? fs.readFileSync(pluginRootFile, 'utf8').trim() |
| 174 | : path.resolve(__dirname, '..'); |
| 175 | |
| 176 | const exportedAt = new Date().toISOString(); |
| 177 | const archiveDir = path.join(projectRoot, 'docs', 'citadel'); |
| 178 | |
| 179 | // --- SCAN --- |
| 180 | const campaigns = readMarkdownFiles(path.join(planning, 'campaigns', 'completed')); |
| 181 | const postmortems = readMarkdownFiles(path.join(planning, 'postmortems')); |
| 182 | const research = readMarkdownFiles(path.join(planning, 'research')); |
| 183 | const intake = readMarkdownFiles(path.join(planning, 'intake'), ['_TEMPLATE']); |
| 184 | const discoveries = readMarkdownFiles(path.join(planning, 'discoveries')); |
| 185 | |
| 186 | const hasContent = campaigns.length + postmortems.length + research.length + |
| 187 | intake.length + discoveries.length > 0; |
| 188 | |
| 189 | const projectMd = path.join(citadelDir, 'project.md'); |
| 190 | const harnessJson = path.join(projectRoot, '.claude', 'harness.json'); |
| 191 | |
| 192 | console.log(''); |
| 193 | console.log('Citadel Unharness'); |
| 194 | console.log('================='); |
no test coverage detected