@nshiab/setup-data-project 4.0.0 → 4.0.2
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/README.md +19 -11
- package/dist/main.mjs +11 -10
- package/dist/main.mjs.map +1 -1
- package/dist/sda.mjs +124 -7
- package/dist/sda.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,15 +53,22 @@ The project includes `sda/main.ts`, helpers, tests, data and output folders,
|
|
|
53
53
|
`.env`, `.gitignore`, and managed sections in README.md and AGENTS.md.
|
|
54
54
|
Existing source files, environment values, scripts, tooling configuration,
|
|
55
55
|
and unmanaged documentation are preserved.
|
|
56
|
+
Remove the generated section or its markers from README.md or AGENTS.md to stop updates to that file.
|
|
56
57
|
|
|
57
58
|
Generated projects run TypeScript directly with Node or Bun. Vite+ provides
|
|
58
|
-
formatting, linting, type checking, and Vitest tests. Use
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
formatting, linting, type checking, and Vitest tests. Use these commands
|
|
60
|
+
(replace `npm run` with `bun run` for Bun projects):
|
|
61
|
+
|
|
62
|
+
- `npm run sda`: run `fix`, then execute `sda/main.ts` once if checks pass.
|
|
63
|
+
- `npm run sda:watch`: do the same on changes to `sda/` and `.env`, excluding `sda/output/`.
|
|
64
|
+
- `npm run sda:status`: check whether an SDA run or watcher is active.
|
|
65
|
+
- `npm run all-tests`: check formatting, lint, types, and tests; succeeds when no tests exist.
|
|
66
|
+
- `npm run fix`: format files, apply automatic lint fixes, and check types.
|
|
67
|
+
- `npm run docs`: refresh documentation for the installed library versions.
|
|
68
|
+
- `npm run clean`: delete cached results and temporary files in `.sda-cache/`, `.journalism-cache/`, and `.tmp/`.
|
|
69
|
+
|
|
62
70
|
The watcher comes from the installed setup-data-project package; no runner script is added to your project.
|
|
63
71
|
SDA blocks simultaneous runs. Recovery after a forced termination is best effort.
|
|
64
|
-
The generated `all-tests` command also succeeds when no tests exist.
|
|
65
72
|
New development tools are installed at their latest versions; existing dependencies
|
|
66
73
|
are preserved.
|
|
67
74
|
|
|
@@ -81,10 +88,11 @@ and `.vscode/settings.json` files are left unchanged.
|
|
|
81
88
|
Documentation is downloaded automatically for the exact installed library
|
|
82
89
|
versions. Each library's release archive preserves its README, license,
|
|
83
90
|
`llms.txt` index, granular API pages, and media under `docs/<library>/`.
|
|
84
|
-
Observable Plot
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
Observable Plot uses a cached reference for the installed version, falling back
|
|
92
|
+
to that version's upstream Git tag. Selected documentation for static charts and
|
|
93
|
+
maps is split into feature, mark, and transform pages, indexed at
|
|
94
|
+
`docs/observable-plot/llms.txt`. Website controls are removed; examples that depend
|
|
95
|
+
on upstream setup or interactive templates are labeled.
|
|
88
96
|
The generated `docs/` folder is ignored by Git.
|
|
89
97
|
|
|
90
98
|
After cloning or changing dependencies, run `npm run docs` or `bun run docs`.
|
|
@@ -102,8 +110,8 @@ exit unsuccessfully. Generated docs scripts pin the setup CLI version that
|
|
|
102
110
|
created them. Use `--help` for usage.
|
|
103
111
|
|
|
104
112
|
For development, use `npm ci` and `npm run all-tests`.
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
Releases use `npm run patch`, `npm run minor`, or `npm run major` from main;
|
|
114
|
+
GitHub Actions publishes to npm.
|
|
107
115
|
|
|
108
116
|
To cache documentation for the latest Observable Plot version, run:
|
|
109
117
|
|
package/dist/main.mjs
CHANGED
|
@@ -152,8 +152,8 @@ function ensureGitignore() {
|
|
|
152
152
|
//#endregion
|
|
153
153
|
//#region src/helpers/ensureManagedSection.ts
|
|
154
154
|
function ensureManagedSection(options) {
|
|
155
|
-
const startMarker = `<!--
|
|
156
|
-
const endMarker = `<!--
|
|
155
|
+
const startMarker = `<!-- setup-data-project:${options.name}:start / Safe to remove if you don't want this section. -->`;
|
|
156
|
+
const endMarker = `<!-- setup-data-project:${options.name}:end / End of generated section. -->`;
|
|
157
157
|
const trimmedContent = options.content.trim();
|
|
158
158
|
const section = trimmedContent === "" ? `${startMarker}\n${endMarker}` : `${startMarker}\n\n${trimmedContent}\n\n${endMarker}`;
|
|
159
159
|
if (!existsSync(options.path)) {
|
|
@@ -163,10 +163,7 @@ function ensureManagedSection(options) {
|
|
|
163
163
|
const currentContent = readFileSync(options.path, "utf-8");
|
|
164
164
|
const start = currentContent.indexOf(startMarker);
|
|
165
165
|
const end = currentContent.indexOf(endMarker);
|
|
166
|
-
if (start === -1 || end === -1 || end < start)
|
|
167
|
-
log.warn(`${options.path} was not updated because its setup-data-project markers were not found. Add ${startMarker} and ${endMarker}, then rerun the script.`);
|
|
168
|
-
return "missing-markers";
|
|
169
|
-
}
|
|
166
|
+
if (start === -1 || end === -1 || end < start) return "missing-markers";
|
|
170
167
|
const nextContent = currentContent.slice(0, start) + section + currentContent.slice(end + endMarker.length);
|
|
171
168
|
if (nextContent === currentContent) return "unchanged";
|
|
172
169
|
writeFileSync(options.path, ensureFinalNewline(nextContent));
|
|
@@ -189,14 +186,15 @@ function ensureReadme(runtime, installedPackages = []) {
|
|
|
189
186
|
|
|
190
187
|
- \`${run} sda\`: run \`${run} fix\`, then run the analysis once if checks pass.
|
|
191
188
|
- \`${run} sda:watch\`: do the same on changes to sda/ and .env, excluding sda/output/.
|
|
189
|
+
- \`${run} sda:status\`: check whether an SDA run or watcher is active.
|
|
192
190
|
- \`${run} all-tests\`: check types, lint, formatting, and tests; succeeds when no tests exist.
|
|
193
|
-
- \`${run} fix\`: apply
|
|
191
|
+
- \`${run} fix\`: format files, apply automatic lint fixes, and check types.
|
|
194
192
|
- \`${run} docs\`: refresh documentation for the installed library versions.
|
|
195
193
|
- \`${run} clean\`: delete cached results and temporary files in .sda-cache/, .journalism-cache/, and .tmp/.
|
|
196
194
|
|
|
197
195
|
SDA blocks simultaneous runs. Recovery after a forced termination is best effort.
|
|
198
196
|
|
|
199
|
-
|
|
197
|
+
Run one test file with \`${vp} test sda/tests/example.test.ts\`. For test-driven development, watch for changes with \`${vp} test sda/tests/example.test.ts --watch\`. Replace the path with your test file.
|
|
200
198
|
|
|
201
199
|
In VS Code, install the recommended Vite+ extension pack for Oxc formatting and linting and the Vitest test runner. Generated .vscode/settings.json enables formatting and lint fixes on save, plus visual line wrapping. Existing VS Code configuration files are preserved.
|
|
202
200
|
|
|
@@ -229,7 +227,7 @@ async function installPackages(packages, options = {}) {
|
|
|
229
227
|
//#endregion
|
|
230
228
|
//#region package.json
|
|
231
229
|
var name = "@nshiab/setup-data-project";
|
|
232
|
-
var version = "4.0.
|
|
230
|
+
var version = "4.0.2";
|
|
233
231
|
//#endregion
|
|
234
232
|
//#region src/helpers/ensureTooling.ts
|
|
235
233
|
const tools = ["vite-plus", "@types/node"];
|
|
@@ -305,6 +303,7 @@ function getProjectTasks(runtime = getRuntime()) {
|
|
|
305
303
|
return {
|
|
306
304
|
sda: `${runner} sda/main.ts`,
|
|
307
305
|
"sda:watch": `${runner} --watch sda/main.ts sda .env --ignore sda/output`,
|
|
306
|
+
"sda:status": `${runner} --status`,
|
|
308
307
|
"all-tests": `${vp} check && ${vp} test --passWithNoTests`,
|
|
309
308
|
clean: "rm -rf .sda-cache .journalism-cache .tmp",
|
|
310
309
|
fix: `${vp} check --fix`,
|
|
@@ -359,7 +358,9 @@ Use sda/main.ts as the entry point and sda/helpers/ for reusable helpers. Put te
|
|
|
359
358
|
|
|
360
359
|
Run \`${run} sda\` to fix and check code, then execute the analysis once. Use \`${run} sda:watch\` to watch for changes. Before handing off code changes, run \`${run} all-tests\` and resolve failures.
|
|
361
360
|
|
|
362
|
-
Before
|
|
361
|
+
Before starting work, run \`${run} sda:status\` and follow its instructions.
|
|
362
|
+
|
|
363
|
+
For a focused test run, use \`${runtime === "bun" ? "bun run --bun vp" : "npx vp"} test sda/tests/example.test.ts\`, replacing the path with your test file. Add \`--watch\` for test-driven development.
|
|
363
364
|
|
|
364
365
|
The clean script removes cached results and temporary files. Run it only when those cached results can be discarded.
|
|
365
366
|
|
package/dist/main.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.mjs","names":["process","metadata.name","metadata.version","metadata.version","process"],"sources":["../src/helpers/getRuntime.ts","../src/helpers/packageRegistry.ts","../src/helpers/packageOptions.ts","../src/helpers/gitignoreEntries.ts","../src/helpers/ensureGitignore.ts","../src/helpers/ensureManagedSection.ts","../src/helpers/ensureReadme.ts","../src/helpers/installPackages.ts","../package.json","../src/helpers/ensureTooling.ts","../src/helpers/ensureVscode.ts","../src/helpers/getProjectTasks.ts","../src/helpers/createFolderStructure.ts","../src/helpers/ensureEnvFile.ts","../src/helpers/ensureAgents.ts","../src/helpers/projectManifest.ts","../src/helpers/fetchPackageDocs.ts","../src/helpers/cleanPlotMarkdown.ts","../src/helpers/combinePlotDocs.ts","../src/helpers/plotDocPages.ts","../src/helpers/splitPlotDocs.ts","../src/helpers/fetchPlotDocs.ts","../src/helpers/syncPackageDocs.ts","../src/helpers/getInstalledPackageVersions.ts","../src/helpers/parseArguments.ts","../src/main.ts"],"sourcesContent":["import process from \"node:process\";\nexport type Runtime = \"node\" | \"bun\";\nexport function getRuntime(versions: { bun?: string; node?: string } = process.versions): Runtime {\n return versions.bun ? \"bun\" : \"node\";\n}\n","export interface PackageConfig {\n value: string;\n label: string;\n type: \"sda\" | \"journalism\" | \"other\";\n hint?: string;\n}\n\nexport const SUPPORTED_PACKAGES: PackageConfig[] = [\n {\n value: \"@nshiab/simple-data-analysis\",\n label: \"simple-data-analysis\",\n type: \"sda\",\n hint: \"All the core functionality, plus methods for dataviz, AI, Google sheets, etc.\",\n },\n {\n value: \"@nshiab/simple-data-analysis-core\",\n label: \"simple-data-analysis-core\",\n type: \"sda\",\n hint: \"No fluff. Great for constrained environments, like a cheap server.\",\n },\n {\n value: \"@nshiab/journalism-ai\",\n label: \"journalism-ai\",\n type: \"journalism\",\n hint: \"Easily use AI local models with Ollama or remote models with Gemini/Vertex.\",\n },\n {\n value: \"@nshiab/journalism-google\",\n label: \"journalism-google\",\n type: \"journalism\",\n hint: \"Push and retrieve data from Google Sheets, Google Bucket, and more.\",\n },\n {\n value: \"@nshiab/journalism-web-scraping\",\n label: \"journalism-web-scraping\",\n type: \"journalism\",\n hint: \"Retrieve data from Statistics Canada tables, HTML table, download files...\",\n },\n {\n value: \"@nshiab/journalism-finance\",\n label: \"journalism-finance\",\n type: \"journalism\",\n hint: \"Retrieve financial data, calculate Canadian mortgage payments and taxes...\",\n },\n {\n value: \"@nshiab/journalism-format\",\n label: \"journalism-format\",\n type: \"journalism\",\n hint: \"Easily format dates, numbers, currencies...\",\n },\n {\n value: \"@nshiab/journalism-climate\",\n label: \"journalism-climate\",\n type: \"journalism\",\n hint: \"Retrieve data from Environment Canada APIs and more.\",\n },\n {\n value: \"@nshiab/journalism-dataviz\",\n label: \"journalism-dataviz\",\n type: \"journalism\",\n hint: \"Render charts/maps with Observable Plot or directly in the terminal.\",\n },\n {\n value: \"@nshiab/journalism-geo\",\n label: \"journalism-geo\",\n type: \"journalism\",\n hint: \"Calculate distances, transform 2D coordinates to 3D, wrangle GeoTIFF files...\",\n },\n {\n value: \"@nshiab/journalism-statistics\",\n label: \"journalism-statistics\",\n type: \"journalism\",\n hint: \"Functions for statistical tests, clustering, random path generation...\",\n },\n {\n value: \"@nshiab/journalism-web\",\n label: \"journalism-web\",\n type: \"journalism\",\n hint: \"Web related functions, including downloading data as CSV, extracting ZIP files to URLs...\",\n },\n {\n value: \"@nshiab/journalism-extras\",\n label: \"journalism-extras\",\n type: \"journalism\",\n hint: \"Functions to zip/unzip, sleep, reencode files, create nested directories...\",\n },\n];\n\n// Plot is installed alongside charting libraries, but is not a setup menu option.\nexport const DOCUMENTED_PACKAGES: PackageConfig[] = [\n ...SUPPORTED_PACKAGES,\n { value: \"@nshiab/journalism\", label: \"journalism\", type: \"journalism\" },\n { value: \"@observablehq/plot\", label: \"Observable Plot\", type: \"other\" },\n];\n\nexport function getInstalledPackageConfigs(installedPackages: string[]): PackageConfig[] {\n const installedSet = new Set(installedPackages);\n return DOCUMENTED_PACKAGES.filter((pkg) => installedSet.has(pkg.value));\n}\n","import { SUPPORTED_PACKAGES } from \"./packageRegistry.ts\";\n\nexport const PACKAGE_OPTIONS = SUPPORTED_PACKAGES.map((pkg) => ({\n value: pkg.value,\n label: pkg.label,\n hint: pkg.hint,\n}));\n","export const GITIGNORE_ENTRIES = [\n \"node_modules\",\n \"docs/\",\n \".tmp\",\n \".sda-cache\",\n \"sda/.sda.pid\",\n \"sda/.sda-lock/\",\n \".journalism-cache\",\n \"sda/data\",\n \"sda/output\",\n \".env\",\n \".DS_Store\",\n];\n","import { lstatSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { GITIGNORE_ENTRIES } from \"./gitignoreEntries.ts\";\n\nexport const GITIGNORE_SENTINEL = \"# Added by setup-data-project. Do not remove this line.\";\n\nexport function ensureGitignore() {\n const path = \".gitignore\";\n const stats = lstatSync(path, { throwIfNoEntry: false });\n\n if (stats?.isSymbolicLink()) {\n return;\n }\n\n const content = stats === undefined ? \"\" : readFileSync(path, \"utf-8\");\n const hasSentinel = content.split(\"\\n\").some((line) => line.trim() === GITIGNORE_SENTINEL);\n\n if (hasSentinel) {\n const entries = new Set(content.split(\"\\n\").map((line) => line.trim()));\n const missing = GITIGNORE_ENTRIES.filter((entry) => !entries.has(entry));\n if (missing.length)\n writeFileSync(\n path,\n content + (content.endsWith(\"\\n\") ? \"\" : \"\\n\") + missing.join(\"\\n\") + \"\\n\",\n );\n return;\n }\n\n const separator = content === \"\" ? \"\" : content.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n const block = `${GITIGNORE_SENTINEL}\\n${GITIGNORE_ENTRIES.join(\"\\n\")}\\n`;\n writeFileSync(path, content + separator + block);\n}\n","import { log } from \"@clack/prompts\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\n\ninterface ManagedSectionOptions {\n path: string;\n name: string;\n content: string;\n createContent: (section: string) => string;\n}\n\nexport function ensureManagedSection(\n options: ManagedSectionOptions,\n): \"created\" | \"updated\" | \"unchanged\" | \"missing-markers\" {\n const startMarker = `<!-- Do not remove / setup-data-project:${options.name}:start -->`;\n const endMarker = `<!-- Do not remove / setup-data-project:${options.name}:end -->`;\n const trimmedContent = options.content.trim();\n const section =\n trimmedContent === \"\"\n ? `${startMarker}\\n${endMarker}`\n : `${startMarker}\\n\\n${trimmedContent}\\n\\n${endMarker}`;\n\n if (!existsSync(options.path)) {\n writeFileSync(options.path, ensureFinalNewline(options.createContent(section)));\n return \"created\";\n }\n\n const currentContent = readFileSync(options.path, \"utf-8\");\n const start = currentContent.indexOf(startMarker);\n const end = currentContent.indexOf(endMarker);\n\n if (start === -1 || end === -1 || end < start) {\n log.warn(\n `${options.path} was not updated because its setup-data-project markers ` +\n `were not found. Add ${startMarker} and ${endMarker}, then rerun the ` +\n \"script.\",\n );\n return \"missing-markers\";\n }\n\n const nextContent =\n currentContent.slice(0, start) + section + currentContent.slice(end + endMarker.length);\n\n if (nextContent === currentContent) {\n return \"unchanged\";\n }\n\n writeFileSync(options.path, ensureFinalNewline(nextContent));\n return \"updated\";\n}\n\nfunction ensureFinalNewline(content: string): string {\n return content.endsWith(\"\\n\") ? content : content + \"\\n\";\n}\n","import { ensureManagedSection } from \"./ensureManagedSection.ts\";\nimport { getInstalledPackageConfigs } from \"./packageRegistry.ts\";\nimport type { Runtime } from \"./getRuntime.ts\";\nexport function ensureReadme(runtime: Runtime, installedPackages: string[] = []) {\n const run = runtime === \"bun\" ? \"bun run\" : \"npm run\";\n const vp = runtime === \"bun\" ? \"bun run --bun vp\" : \"npx vp\";\n const libraries = getInstalledPackageConfigs(installedPackages)\n .map((pkg) => `\\`${pkg.value}\\``)\n .join(\", \");\n ensureManagedSection({\n path: \"README.md\",\n name: \"libraries\",\n createContent: (section) =>\n `# Data project\\n\\nCreated with [setup-data-project](https://github.com/nshiab/setup-data-project).\\n\\n${section}`,\n content: `${libraries ? `Installed libraries: ${libraries}.\\n\\n` : \"\"}Use sda/main.ts to process source data from sda/data/ and write results to sda/output/. Both data folders are ignored by Git. Put reusable helpers in sda/helpers/ and tests in sda/tests/. Import test utilities from \\`vite-plus/test\\`.\n\n- \\`${run} sda\\`: run \\`${run} fix\\`, then run the analysis once if checks pass.\n- \\`${run} sda:watch\\`: do the same on changes to sda/ and .env, excluding sda/output/.\n- \\`${run} all-tests\\`: check types, lint, formatting, and tests; succeeds when no tests exist.\n- \\`${run} fix\\`: apply formatting and automatic fixes.\n- \\`${run} docs\\`: refresh documentation for the installed library versions.\n- \\`${run} clean\\`: delete cached results and temporary files in .sda-cache/, .journalism-cache/, and .tmp/.\n\nSDA blocks simultaneous runs. Recovery after a forced termination is best effort.\n\nFor test-driven development, run one test file and watch for changes with \\`${vp} test sda/tests/example.test.ts --watch\\`. Replace the path with your test file.\n\nIn VS Code, install the recommended Vite+ extension pack for Oxc formatting and linting and the Vitest test runner. Generated .vscode/settings.json enables formatting and lint fixes on save, plus visual line wrapping. Existing VS Code configuration files are preserved.\n\nThe generated docs/ folder is ignored by Git. Refresh it after cloning or updating dependencies. See AGENTS.md for documentation pointers.`,\n });\n}\n","import { execFile } from \"node:child_process\";\nimport { getRuntime } from \"./getRuntime.ts\";\nexport function runPackageManager(args: string[]): Promise<void> {\n const command = getRuntime() === \"bun\" ? \"bun\" : process.platform === \"win32\" ? \"npm.cmd\" : \"npm\";\n return new Promise((resolve, reject) => {\n execFile(\n command,\n args,\n { maxBuffer: 10 * 1024 * 1024, shell: process.platform === \"win32\" },\n (error, stdout, stderr) => {\n if (error)\n reject(\n new Error(`${command} ${args.join(\" \")} failed.\\n${stderr || stdout}`, {\n cause: error,\n }),\n );\n else resolve();\n },\n );\n });\n}\nexport async function installPackages(\n packages: string[],\n options: { development?: boolean } = {},\n): Promise<void> {\n if (packages.length === 0) return;\n const bun = getRuntime() === \"bun\";\n await runPackageManager([\n bun ? \"add\" : \"install\",\n ...(options.development ? (bun ? [\"--dev\"] : [\"--save-dev\"]) : []),\n ...packages,\n ]);\n}\n","","import { existsSync, writeFileSync } from \"node:fs\";\nimport { ProjectManifest } from \"./projectManifest.ts\";\nimport { getRuntime } from \"./getRuntime.ts\";\nimport { installPackages } from \"./installPackages.ts\";\nimport metadata from \"../../package.json\" with { type: \"json\" };\nconst tools = [\"vite-plus\", \"@types/node\"];\nexport async function ensureTooling(manifest: ProjectManifest): Promise<void> {\n const runtime = getRuntime();\n const runtimeTools = runtime === \"bun\" ? [...tools, \"@types/bun\"] : tools;\n const installed = manifest.getInstalledPackages();\n await installPackages(\n [\n ...runtimeTools.filter((pkg) => !installed.includes(pkg)).map((pkg) => `${pkg}@latest`),\n ...(installed.includes(metadata.name) ? [] : [`${metadata.name}@${metadata.version}`]),\n ],\n { development: true },\n );\n if (\n ![\n \"vite.config.ts\",\n \"vite.config.js\",\n \"vite.config.mts\",\n \"vite.config.mjs\",\n \"vite.config.cts\",\n \"vite.config.cjs\",\n ].some((file) => existsSync(file))\n ) {\n writeFileSync(\n \"vite.config.ts\",\n `import { defineConfig, loadEnv } from \"vite-plus\";\n\nexport default defineConfig({\n test: { env: loadEnv(\"test\", process.cwd(), \"\") },\n lint: { options: { typeAware: true, typeCheck: true } },\n fmt: { ignorePatterns: [\"docs/**\", \"sda/data/**\", \"sda/output/**\"] },\n});\n`,\n );\n }\n if (!existsSync(\"tsconfig.json\"))\n writeFileSync(\n \"tsconfig.json\",\n `{\n \"compilerOptions\": {\n \"target\": \"ES2023\",\n \"module\": \"NodeNext\",\n \"strict\": true,\n \"noEmit\": true,\n \"allowImportingTsExtensions\": true,\n \"erasableSyntaxOnly\": ${runtime === \"node\"},\n \"types\": ${runtime === \"bun\" ? '[\"node\", \"bun\"]' : '[\"node\"]'},\n \"skipLibCheck\": true\n },\n \"include\": [\"sda/**/*.ts\", \"vite.config.*\"]\n}\n`,\n );\n}\n","import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\n\nexport function ensureVscode(): void {\n mkdirSync(\".vscode\", { recursive: true });\n const formatter = \"oxc.oxc-vscode\";\n const files = {\n \"extensions.json\": `{\n \"recommendations\": [\"VoidZero.vite-plus-extension-pack\"]\n}\n`,\n \"settings.json\": `${JSON.stringify(\n {\n \"editor.defaultFormatter\": formatter,\n \"[javascript]\": { \"editor.defaultFormatter\": formatter },\n \"[javascriptreact]\": { \"editor.defaultFormatter\": formatter },\n \"[typescript]\": { \"editor.defaultFormatter\": formatter },\n \"[typescriptreact]\": { \"editor.defaultFormatter\": formatter },\n \"oxc.disableNestedConfig\": true,\n \"oxc.fmt.disableNestedConfig\": true,\n \"editor.formatOnSave\": true,\n \"editor.formatOnSaveMode\": \"file\",\n \"editor.codeActionsOnSave\": { \"source.fixAll.oxc\": \"explicit\" },\n \"editor.wordWrap\": \"on\",\n },\n null,\n 2,\n )}\\n`,\n };\n for (const [name, config] of Object.entries(files)) {\n const path = `.vscode/${name}`;\n if (!existsSync(path)) writeFileSync(path, config);\n }\n}\n","import { getRuntime, type Runtime } from \"./getRuntime.ts\";\nimport metadata from \"../../package.json\" with { type: \"json\" };\nexport function getProjectTasks(runtime: Runtime = getRuntime()) {\n const vp = runtime === \"bun\" ? \"bun run --bun vp\" : \"vp\";\n const runner = runtime === \"bun\" ? \"bun run --bun --no-env-file sda-run\" : \"sda-run\";\n return {\n sda: `${runner} sda/main.ts`,\n \"sda:watch\": `${runner} --watch sda/main.ts sda .env --ignore sda/output`,\n \"all-tests\": `${vp} check && ${vp} test --passWithNoTests`,\n clean: \"rm -rf .sda-cache .journalism-cache .tmp\",\n fix: `${vp} check --fix`,\n docs: `${runtime === \"bun\" ? \"bunx --bun\" : \"npx\"} @nshiab/setup-data-project@${metadata.version} --docs`,\n };\n}\n","import { existsSync, lstatSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport function createFolderStructure(selectedPackages: string[]) {\n const sdaFolder = \"sda\";\n const folders = [\"data\", \"helpers\", \"output\", \"tests\"];\n\n if (!existsSync(sdaFolder)) {\n mkdirSync(sdaFolder, { recursive: true });\n }\n\n for (const folder of folders) {\n const path = join(sdaFolder, folder);\n if (!existsSync(path)) {\n mkdirSync(path, { recursive: true });\n }\n }\n\n const mainTsPath = join(sdaFolder, \"main.ts\");\n\n let mainTsContent = 'console.log(\"Hello simple-data-analysis!\");\\n';\n\n if (\n selectedPackages.includes(\"@nshiab/simple-data-analysis\") ||\n selectedPackages.includes(\"@nshiab/simple-data-analysis-core\")\n ) {\n const pkg = selectedPackages.includes(\"@nshiab/simple-data-analysis\")\n ? \"@nshiab/simple-data-analysis\"\n : \"@nshiab/simple-data-analysis-core\";\n mainTsContent = `import { SimpleDB } from \"${pkg}\";\n\nconst sdb = new SimpleDB();\nconst table = sdb.newTable();\n\nawait table.loadArray([{ message: \"Hello simple-data-analysis!\" }]).log();\n\nawait sdb.close();\n`;\n }\n\n if (lstatSync(mainTsPath, { throwIfNoEntry: false }) === undefined) {\n writeFileSync(mainTsPath, mainTsContent);\n }\n\n return sdaFolder;\n}\n","import { lstatSync, writeFileSync } from \"node:fs\";\n\nexport function ensureEnvFile() {\n if (lstatSync(\".env\", { throwIfNoEntry: false }) === undefined) {\n writeFileSync(\".env\", \"\");\n }\n}\n","import type { PackageDocs } from \"./fetchPackageDocs.ts\";\nimport { ensureManagedSection } from \"./ensureManagedSection.ts\";\nimport { getInstalledPackageConfigs } from \"./packageRegistry.ts\";\nimport type { Runtime } from \"./getRuntime.ts\";\nexport function ensureAgents(\n docsMapping: Record<string, PackageDocs>,\n runtime: Runtime,\n installedPackages: string[] = Object.keys(docsMapping),\n) {\n const run = runtime === \"bun\" ? \"bun run\" : \"npm run\";\n const links = getInstalledPackageConfigs(installedPackages).map((pkg) => {\n if (pkg.value === \"@observablehq/plot\")\n return `- Observable Plot charts and maps: start at \\`docs/observable-plot/llms.txt\\`, then read the relevant pages for use with writeChart and writeMap.`;\n return `- \\`${pkg.value}\\`: start at \\`docs/${pkg.value.slice(\"@nshiab/\".length)}/llms.txt\\`, then read the relevant API pages and examples.`;\n });\n ensureManagedSection({\n path: \"AGENTS.md\",\n name: \"agents\",\n createContent: (section) => section,\n content: `Read package.json for the installed libraries and scripts. Prefer the installed data libraries when they cover the task.\n\nUse sda/main.ts as the entry point and sda/helpers/ for reusable helpers. Put tests in sda/tests/, source data in sda/data/, and results in sda/output/. Import test utilities from \\`vite-plus/test\\`.\n\nRun \\`${run} sda\\` to fix and check code, then execute the analysis once. Use \\`${run} sda:watch\\` to watch for changes. Before handing off code changes, run \\`${run} all-tests\\` and resolve failures.\n\nBefore editing, check sda/.sda.pid. Verify that its PID belongs to this project's sda-run process from @nshiab/setup-data-project (dist/sda.mjs) using the process command and working directory. For a single run, wait for it to finish. For a watcher (--watch), stop it with SIGTERM and wait for it to exit; tell the user you stopped it and they can restart with \\`${run} sda:watch\\` afterward. Stale locks recover automatically on the next run. Leave active runs alone for read-only work.\n\nThe clean script removes cached results and temporary files. Run it only when those cached results can be discarded.\n\nLibrary documentation in docs/ is generated and ignored by Git. Run \\`${run} docs\\` when documentation is missing or after dependency changes; resolve refresh failures before using possibly stale references. Edit project source files rather than downloaded documentation.\n\n${links.join(\"\\n\")}`,\n });\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { isObject } from \"./jsonObject.ts\";\nexport class ProjectManifest {\n #config: Record<string, unknown>;\n private constructor(config: Record<string, unknown>) {\n this.#config = config;\n }\n static open(): ProjectManifest {\n if (!existsSync(\"package.json\"))\n return new ProjectManifest({ name: \"data-project\", private: true, type: \"module\" });\n const config: unknown = JSON.parse(readFileSync(\"package.json\", \"utf8\"));\n if (!isObject(config)) throw new Error(\"package.json must contain a JSON object.\");\n return new ProjectManifest(config);\n }\n reload(): void {\n this.#config = ProjectManifest.open().#config;\n }\n getInstalledPackages(): string[] {\n return Object.keys(this.getInstalledPackageSpecifiers());\n }\n getInstalledPackageSpecifiers(): Record<string, string> {\n const packages: Record<string, string> = {};\n for (const key of [\"dependencies\", \"devDependencies\"]) {\n const dependencies = this.#config[key];\n if (isObject(dependencies))\n for (const [name, version] of Object.entries(dependencies)) {\n if (typeof version === \"string\") packages[name] = version;\n }\n }\n return packages;\n }\n updateTasks(tasks: Record<string, string>): void {\n if (this.#config.type === \"commonjs\") {\n throw new Error(\n 'Setup requires an ESM project. Set \"type\": \"module\" in package.json, or use --docs to refresh documentation only.',\n );\n }\n if (this.#config.type === undefined) this.#config.type = \"module\";\n const existing = this.#config.scripts;\n this.#config.scripts = { ...tasks, ...(isObject(existing) ? existing : {}) };\n writeFileSync(\"package.json\", JSON.stringify(this.#config, null, 2) + \"\\n\");\n }\n}\n","import { log } from \"@clack/prompts\";\nimport {\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join, posix } from \"node:path\";\nimport { x } from \"tar\";\nimport { DOCUMENTED_PACKAGES } from \"./packageRegistry.ts\";\nexport interface PackageDocs {\n readme?: string;\n index?: string;\n llm?: string;\n plot?: { version: string; pages: string[] };\n}\nexport async function fetchPackageDocs(pkg: string, version: string): Promise<PackageDocs> {\n const config = DOCUMENTED_PACKAGES.find(\n (item) => item.value === pkg && item.value.startsWith(\"@nshiab/\"),\n );\n if (!config || !/^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/.test(version))\n throw new Error(`Unsupported package or version: ${pkg}@${version}`);\n const repo = pkg.slice(\"@nshiab/\".length);\n mkdirSync(\"docs\", { recursive: true });\n const staging = mkdtempSync(join(\"docs\", \".download-\"));\n const contents = join(staging, \"contents\");\n const target = join(\"docs\", repo);\n const backup = join(staging, \"previous\");\n try {\n const url = `https://github.com/nshiab/${repo}/releases/download/v${version}/documentation.tar.gz`;\n const response = await fetch(url);\n if (!response.ok) throw new Error(`HTTP ${response.status} from ${url}`);\n const archive = join(staging, \"documentation.tar.gz\");\n writeFileSync(archive, Buffer.from(await response.arrayBuffer()));\n mkdirSync(contents);\n let unsafeEntry: string | undefined;\n await x({\n file: archive,\n cwd: contents,\n strict: true,\n preservePaths: false,\n filter(path, entry) {\n const normalized = posix.normalize(path);\n if (\n path.includes(\"\\\\\") ||\n path.startsWith(\"/\") ||\n normalized === \"..\" ||\n normalized.startsWith(\"../\") ||\n !(\"type\" in entry) ||\n ![\"File\", \"Directory\"].includes(entry.type)\n ) {\n unsafeEntry = path;\n return false;\n }\n return true;\n },\n });\n if (unsafeEntry !== undefined) throw new Error(`Unsafe archive entry: ${unsafeEntry}`);\n for (const path of [\"README.md\", \"LICENSE\", \"llms.txt\", \"docs\"]) {\n if (!existsSync(join(contents, path)))\n throw new Error(`Documentation archive is missing ${path}.`);\n }\n const readme = readFileSync(join(contents, \"README.md\"), \"utf8\");\n const index = readFileSync(join(contents, \"llms.txt\"), \"utf8\");\n if (existsSync(target)) renameSync(target, backup);\n try {\n renameSync(contents, target);\n } catch (error) {\n if (existsSync(backup)) renameSync(backup, target);\n throw error;\n }\n return { readme, index };\n } catch (error) {\n log.warn(\n `Could not refresh ${pkg}@${version}: ${String(error)} Existing documentation was preserved and may be stale. Run the docs script again after resolving the error.`,\n );\n return {};\n } finally {\n rmSync(staging, { recursive: true, force: true });\n }\n}\n","// Plot's source is VitePress Markdown. Keep examples as reference material,\n// but remove the website UI and turn its custom containers into ordinary text.\nexport function cleanPlotMarkdown(content: string): string {\n const preserved: string[] = [];\n const keep = (value: string) => {\n preserved.push(value);\n return `\\uE000PLOT${preserved.length - 1}\\uE000`;\n };\n const lines = content.split(\"\\n\");\n const prose: string[] = [];\n for (let index = 0; index < lines.length; index++) {\n if (/^\\s*<!--/.test(lines[index])) {\n const start = index;\n while (!lines[index].includes(\"-->\") && index + 1 < lines.length) index++;\n prose.push(lines.slice(start, index + 1).join(\"\\n\"));\n continue;\n }\n const opening = lines[index].match(/^ {0,3}(`{3,}|~{3,})(.*)$/);\n if (!opening) {\n prose.push(lines[index]);\n continue;\n }\n const start = index;\n while (++index < lines.length) {\n const closing = lines[index].match(/^ {0,3}(`{3,}|~{3,})\\s*$/);\n if (closing?.[1][0] === opening[1][0] && closing[1].length >= opening[1].length) break;\n }\n if (index >= lines.length) throw new Error(\"Unclosed Plot code fence.\");\n const block = lines.slice(start, index + 1);\n if (opening[2].trim() === \"js-vue\") {\n block[0] = `${opening[1]}text`;\n prose.push(\n keep(\n \"Interactive example template (values in `{{…}}` come from the upstream website):\\n\\n\" +\n block.join(\"\\n\"),\n ),\n );\n } else {\n prose.push(keep(block.join(\"\\n\")));\n }\n }\n let result = prose\n .join(\"\\n\")\n .replace(/<script\\b[^>]*>([\\s\\S]*?)<\\/script>/g, (_match: string, code: string) => {\n const fence = \"`\".repeat(\n Math.max(3, ...[...code.matchAll(/`+/g)].map((match) => match[0].length + 1)),\n );\n return keep(\n `**Upstream example setup.** This code may use Vue and sample data from the linked source page.\\n\\n${fence}js\\n${code.trim()}\\n${fence}`,\n );\n })\n .replace(/^[ \\t]*<!--(?!\\s*setup-data-project:)[\\s\\S]*?-->/gm, \"\")\n .replace(\n /<\\/?[A-Za-z](?:\"[^\"]*\"|'[^']*'|[^'\"><])*>|(`+)[^`\\n]*?\\1/g,\n (part: string, fence: string | undefined) => (fence ? keep(part) : part),\n )\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/g, \"\")\n .replace(/<p\\b[^>]*>([\\s\\S]*?)<\\/p>/g, (_match: string, body: string) =>\n /<(?:input|select|label)\\b/.test(body) ? \"\" : body,\n )\n .replace(/<PlotRender\\b[\\s\\S]*?\\/>/g, (component) => {\n const options = component.match(/:options=([\"'])([\\s\\S]*?)\\1/)?.[2];\n const method = component.match(/\\bmethod=[\"'](\\w+)[\"']/)?.[1] ?? \"plot\";\n if (!options) throw new Error(\"Unrecognized PlotRender example.\");\n return keep(`\\`\\`\\`js\\nPlot.${method}(${options});\\n\\`\\`\\``);\n })\n .replace(/<VersionBadge\\b[\\s\\S]*?\\/>/g, (badge) => {\n const version = badge.match(/\\bversion=[\"']([^\"']+)[\"']/)?.[1];\n return version ? `(since v${version})` : \"\";\n })\n .replace(/<\\/?span\\b(?:\"[^\"]*\"|'[^']*'|[^'\">])*>/g, \"\")\n .replace(/<svg\\b[\\s\\S]*?<\\/svg>/g, \"arrow\");\n result = result\n .replace(/^[ \\t]*:::plot\\b([^\\n]*)/gm, (_match: string, options: string) => {\n const url = options.match(/https?:\\/\\/\\S+/)?.[0];\n return url ? `[Interactive example](${url})\\n` : \"\";\n })\n .replace(\n /^([ \\t]*):::(tip|info|warning)\\b[ \\t]*/gm,\n (_match: string, indent: string, kind: string) =>\n `${indent}**${kind[0].toUpperCase() + kind.slice(1)}:** `,\n )\n .replace(/^[ \\t]*:::[ \\t]*$/gm, \"\")\n .replace(/[ \\t]+:::[ \\t]*$/gm, \"\")\n .replace(\n /\\{\\{([\\s\\S]*?)\\}\\}/g,\n (_match: string, expression: string) => `\\`${expression.trim().replace(/\\s+/g, \" \")}\\``,\n )\n .replace(/[ \\t]+$/gm, \"\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n return (\n result.replace(\n /\\uE000PLOT(\\d+)\\uE000/g,\n (_match: string, index: string) => preserved[Number(index)],\n ) + \"\\n\"\n );\n}\n","import { cleanPlotMarkdown } from \"./cleanPlotMarkdown.ts\";\nimport { posix } from \"node:path\";\n\n// The Plot source uses ATX headings, explicit VitePress IDs, and Markdown fences.\n// Keep code verbatim; rewrite only prose links and anchors while joining pages.\nexport function combinePlotDocs(version: string, documents: Map<string, string>): string {\n const pages = [...documents.keys()].sort();\n const source = `https://github.com/observablehq/plot/tree/v${version}/docs`;\n const anchors = new Map<string, Map<string, string>>();\n const sections = new Map<string, { line: number; title: string; id: string }[]>();\n const pageId = (page: string) => `plot-${page.replace(/\\.md$/, \"\").replaceAll(\"/\", \"--\")}`;\n\n for (const page of pages) {\n const ids = new Map<string, string>();\n const headings: { line: number; title: string; id: string }[] = [];\n const counts = new Map<string, number>();\n proseLines(documents.get(page) ?? \"\", (line, number) => {\n for (const match of line.matchAll(/\\bid=[\"']([^\"']+)[\"']/g)) {\n ids.set(match[1], `${pageId(page)}--${match[1]}`);\n }\n const heading = line.match(/^ {0,3}#{1,6}\\s+(.+?)\\s*#*\\s*$/);\n if (!heading) return line;\n const explicit = heading[1].match(/\\{#([^}]+)\\}/)?.[1];\n const title = heading[1].replace(/\\s*\\{#[^}]+\\}/g, \"\");\n const slug =\n explicit ??\n title\n .replace(/<[^>]*>/g, \"\")\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}_\\s-]/gu, \"\")\n .trim()\n .replace(/\\s+/g, \"-\");\n const count = counts.get(slug) ?? 0;\n counts.set(slug, count + 1);\n const localId = `${slug}${count ? `-${count}` : \"\"}`;\n const id = `${pageId(page)}--${localId}`;\n ids.set(localId, id);\n headings.push({ line: number, title, id });\n return line;\n });\n anchors.set(page, ids);\n sections.set(page, headings);\n }\n\n function link(target: string, page: string): string {\n if (/^(?:[a-z][a-z\\d+.-]*:|\\/\\/)/i.test(target)) return target;\n const [pathAndQuery, fragment] = target.split(\"#\", 2);\n const path = pathAndQuery.split(\"?\", 1)[0];\n const resolved =\n path === \"\"\n ? page\n : posix.normalize(\n path.startsWith(\"/\") ? path.slice(1) : posix.join(posix.dirname(page), path),\n );\n const markdown = [resolved, `${resolved}.md`, `${resolved}/index.md`].find((candidate) =>\n documents.has(candidate),\n );\n if (markdown) {\n const id = fragment\n ? anchors.get(markdown)?.get(decodeURIComponent(fragment))\n : pageId(markdown);\n if (id) return `#${id}`;\n // Preserve an upstream target when a fragment is not a known heading/ID.\n return `${source}/${markdown}${fragment ? `#${fragment}` : \"\"}`;\n }\n if (resolved.endsWith(\".md\")) {\n return `${source}/${resolved}${fragment ? `#${fragment}` : \"\"}`;\n }\n const base =\n \"https://raw.githubusercontent.com/observablehq/plot/\" + `refs/tags/v${version}/docs/`;\n return path.startsWith(\"/\")\n ? new URL(`public${target}`, base).href\n : new URL(target, `${base}${page}`).href;\n }\n\n const contents = pages\n .flatMap((page) => [\n `- [${page}](#${pageId(page)})`,\n ...(sections.get(page) ?? []).map(\n ({ title, id }) => ` - [${title.replace(/[[\\]]/g, \"\")}](#${id})`,\n ),\n ])\n .join(\"\\n\");\n const combined = pages\n .map((page) => {\n const headings = new Map(\n (sections.get(page) ?? []).map((heading) => [heading.line, heading]),\n );\n const body = proseLines(documents.get(page) ?? \"\", (line, number) => {\n const heading = headings.get(number);\n // Inline code also remains verbatim. Plot's prose links have simple destinations.\n line = line\n .split(/(`+[^`]*`+)/g)\n .map((part, index) => {\n if (index % 2) return part;\n return part\n .replace(\n /(\\]\\()([^\\s)]+)([^)]*\\))/g,\n (_match: string, before: string, target: string, after: string) =>\n `${before}${link(target, page)}${after}`,\n )\n .replace(\n /^( {0,3}\\[[^\\]]+\\]:\\s*)(\\S+)/,\n (_match: string, before: string, target: string) =>\n `${before}${link(target, page)}`,\n )\n .replace(\n /(?<!:)\\b(href|src)=([\"'])([^\"']+)\\2/g,\n (_match: string, attr: string, quote: string, target: string) =>\n `${attr}=${quote}${link(target, page)}${quote}`,\n )\n .replace(\n /\\bid=([\"'])([^\"']+)\\1/g,\n (_match: string, quote: string, id: string) =>\n `id=${quote}${anchors.get(page)?.get(id) ?? id}${quote}`,\n );\n })\n .join(\"\");\n return heading\n ? `<a id=\"${heading.id}\"></a>\\n\\n${line.replace(/\\s*\\{#[^}]+\\}/g, \"\")}`\n : line;\n });\n return `<a id=\"${pageId(page)}\"></a>\\n\\n# ${page}\\n\\nSource: ${source}/${page}\\n\\n${body}`;\n })\n .join(\"\\n\\n---\\n\\n\");\n return cleanPlotMarkdown(\n `# Observable Plot ${version}\\n\\nPackage: \\`@observablehq/plot@${version}\\`. Source: [v${version}](${source}).\\n\\nThis reference combines selected upstream documentation for static charts and maps. Introductory and site pages, interaction helpers, and the Auto and Tip marks are omitted. Website controls are omitted; upstream setup and interactive templates are labeled as reference code. Use the table of contents to find API signatures and examples; links to omitted pages lead to the tagged upstream documentation.\\n\\n## Table of contents\\n\\n${contents}\\n\\n---\\n\\n${combined}\\n\\n<!-- setup-data-project:observable-plot:${version}:complete -->\\n`,\n );\n}\n\nexport function proseLines(\n content: string,\n transform: (line: string, number: number) => string,\n): string {\n let fence: { character: string; length: number } | undefined;\n let script = false;\n return content\n .split(\"\\n\")\n .map((line, number) => {\n const marker = line.match(/^ {0,3}(`{3,}|~{3,})/);\n if (fence) {\n if (\n marker?.[1][0] === fence.character &&\n marker[1].length >= fence.length &&\n /^ {0,3}(?:`+|~+)\\s*$/.test(line)\n )\n fence = undefined;\n return line;\n }\n if (marker) {\n fence = { character: marker[1][0], length: marker[1].length };\n return line;\n }\n if (/^\\s*<script\\b/.test(line)) script = true;\n if (script) {\n if (/<\\/script>/.test(line)) script = false;\n return line;\n }\n return transform(line, number);\n })\n .join(\"\\n\");\n}\n","// Static chart creation references. Keep this explicit so new upstream pages do\n// not silently expand the installed agent reference.\nexport const PLOT_DOC_PAGES: string[] = [\n \"features/plots.md\",\n \"features/marks.md\",\n \"features/scales.md\",\n \"features/projections.md\",\n \"features/legends.md\",\n \"features/facets.md\",\n \"features/formats.md\",\n \"features/curves.md\",\n \"transforms/bin.md\",\n \"transforms/group.md\",\n \"transforms/stack.md\",\n \"transforms/normalize.md\",\n \"transforms/centroid.md\",\n \"transforms/sort.md\",\n \"marks/area.md\",\n \"marks/arrow.md\",\n \"marks/axis.md\",\n \"marks/bar.md\",\n \"marks/bollinger.md\",\n \"marks/box.md\",\n \"marks/cell.md\",\n \"marks/contour.md\",\n \"marks/delaunay.md\",\n \"marks/density.md\",\n \"marks/difference.md\",\n \"marks/dot.md\",\n \"marks/frame.md\",\n \"marks/geo.md\",\n \"marks/grid.md\",\n \"marks/hexgrid.md\",\n \"marks/image.md\",\n \"marks/line.md\",\n \"marks/linear-regression.md\",\n \"marks/link.md\",\n \"marks/raster.md\",\n \"marks/rect.md\",\n \"marks/rule.md\",\n \"marks/text.md\",\n \"marks/tick.md\",\n \"marks/tree.md\",\n \"marks/vector.md\",\n \"marks/waffle.md\",\n].sort();\n","import { cleanPlotMarkdown } from \"./cleanPlotMarkdown.ts\";\nimport { posix } from \"node:path\";\nimport { proseLines } from \"./combinePlotDocs.ts\";\nimport { PLOT_DOC_PAGES } from \"./plotDocPages.ts\";\n\n// Split the cached format without changing code examples or heading anchors.\nexport function splitPlotDocs(reference: string, version: string): Map<string, string> {\n const sections = [\n ...reference.matchAll(\n /<a id=\"(plot-[^\"]+)\"><\\/a>\\n\\n# ([^\\n]+\\.md)\\n\\nSource:\\s+([^\\s]+)\\n\\n/g,\n ),\n ];\n const files = new Map<string, string>();\n const anchors = new Map<string, string>();\n const source = `https://github.com/observablehq/plot/tree/v${version}/docs`;\n const completion = `<!-- setup-data-project:observable-plot:${version}:complete -->`;\n if (!reference.trimEnd().endsWith(completion)) throw new Error(\"Incomplete Plot reference.\");\n const end = reference.lastIndexOf(completion);\n const licenseStart = reference.lastIndexOf(\"\\n## Upstream license\\n\", end);\n for (let index = 0; index < sections.length; index++) {\n const section = sections[index];\n const page = section[2];\n if (!PLOT_DOC_PAGES.includes(page) || files.has(page) || section[3] !== `${source}/${page}`)\n throw new Error(`Invalid Plot page: ${page}`);\n const body = reference\n .slice(section.index, sections[index + 1]?.index ?? (licenseStart >= 0 ? licenseStart : end))\n .trimEnd()\n .replace(/\\n\\n---$/, \"\");\n files.set(page, body);\n proseLines(body, (line) => {\n for (const match of line.matchAll(/\\bid=[\"']([^\"']+)[\"']/g)) anchors.set(match[1], page);\n return line;\n });\n }\n if (files.size !== PLOT_DOC_PAGES.length) throw new Error(\"Incomplete Plot pages.\");\n\n for (const [page, body] of files) {\n const link = (id: string) => {\n const destination = anchors.get(id);\n return destination && destination !== page\n ? `${posix.relative(posix.dirname(page), destination)}#${id}`\n : `#${id}`;\n };\n files.set(\n page,\n cleanPlotMarkdown(\n proseLines(body, (line) =>\n line\n .split(/(`+[^`]*`+)/g)\n .map((part, index) =>\n index % 2\n ? part\n : part\n .replace(\n /(\\]\\()#([^\\s)]+)([^)]*\\))/g,\n (_match: string, before: string, id: string, after: string) =>\n `${before}${link(id)}${after}`,\n )\n .replace(\n /^( {0,3}\\[[^\\]]+\\]:\\s*)#(\\S+)/,\n (_match: string, before: string, id: string) => `${before}${link(id)}`,\n )\n .replace(\n /(?<!:)\\b(href|src)=([\"'])#([^\"']+)\\2/g,\n (_match: string, attr: string, quote: string, id: string) =>\n `${attr}=${quote}${link(id)}${quote}`,\n ),\n )\n .join(\"\"),\n ),\n ),\n );\n }\n const license =\n licenseStart >= 0\n ? reference.slice(licenseStart + \"\\n## Upstream license\\n\".length, end).trim()\n : undefined;\n if (license) files.set(\"LICENSE\", license + \"\\n\");\n const index =\n `# Observable Plot ${version}\\n\\n> Selected documentation for static charts and maps. Start here, then read the relevant pages.\\n\\n[Versioned upstream documentation](${source})${license ? \" · [License](./LICENSE)\" : \"\"}\\n\\n` +\n [\"features\", \"marks\", \"transforms\"]\n .map(\n (group) =>\n `## ${group[0].toUpperCase() + group.slice(1)}\\n\\n` +\n PLOT_DOC_PAGES.filter((page) => page.startsWith(`${group}/`))\n .map((page) => `- [${page}](./${page})`)\n .join(\"\\n\"),\n )\n .join(\"\\n\\n\") +\n \"\\n\";\n files.set(\"llms.txt\", index);\n return files;\n}\n","import { log } from \"@clack/prompts\";\nimport { existsSync, mkdirSync, mkdtempSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { splitPlotDocs } from \"./splitPlotDocs.ts\";\nimport { combinePlotDocs } from \"./combinePlotDocs.ts\";\nimport { PLOT_DOC_PAGES } from \"./plotDocPages.ts\";\nimport type { PackageDocs } from \"./fetchPackageDocs.ts\";\n\n// Replace local documentation only after every page is ready.\nexport async function fetchPlotDocs(\n version: string,\n options: { preferStored?: boolean } = {},\n): Promise<PackageDocs> {\n const tag = `v${version}`;\n const directory = join(\"docs\", \"observable-plot\");\n try {\n let llm: string | undefined;\n if (options.preferStored !== false) {\n try {\n const response = await fetch(\n \"https://raw.githubusercontent.com/nshiab/setup-data-project/\" +\n `refs/heads/main/docs-cache/observable-plot/${version}/llm.md`,\n );\n if (response.ok) {\n const cached = await response.text();\n if (isStoredReference(cached, version)) llm = cached;\n }\n } catch {\n // A cache is an optimization. An unavailable cache never blocks the tag.\n }\n }\n if (llm === undefined) llm = await generatePlotReference(version);\n const files = splitPlotDocs(llm, version);\n mkdirSync(\"docs\", { recursive: true });\n const staging = mkdtempSync(join(\"docs\", \".plot-\"));\n const contents = join(staging, \"contents\");\n const backup = join(staging, \"previous\");\n try {\n for (const [page, content] of files) {\n const path = join(contents, page);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, content);\n }\n if (existsSync(directory)) renameSync(directory, backup);\n try {\n renameSync(contents, directory);\n } catch (error) {\n if (existsSync(backup)) renameSync(backup, directory);\n throw error;\n }\n } finally {\n rmSync(staging, { recursive: true, force: true });\n }\n return { llm, index: files.get(\"llms.txt\"), plot: { version, pages: [...PLOT_DOC_PAGES] } };\n } catch (error) {\n log.warn(\n `Could not fetch complete Observable Plot documentation for ${tag}. ` +\n \"Existing files were preserved, but may not match the installed \" +\n \"version. Resolve the refresh failure before using this reference. \" +\n String(error),\n );\n return {};\n }\n}\n\nexport async function generatePlotReference(version: string): Promise<string> {\n if (!/^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$/.test(version))\n throw new Error(\"An exact Plot version is required.\");\n const tag = `v${version}`;\n const pages = PLOT_DOC_PAGES;\n const documents = new Map<string, string>();\n const failed: string[] = [];\n // Fetch in small batches to avoid overwhelming GitHub on the first run.\n for (let offset = 0; offset < pages.length; offset += 8) {\n await Promise.all(\n pages.slice(offset, offset + 8).map(async (page) => {\n try {\n const url =\n \"https://raw.githubusercontent.com/observablehq/plot/\" +\n `refs/tags/${tag}/docs/${page}`;\n const response = await fetch(url);\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n const content = await response.text();\n documents.set(page, content);\n } catch {\n failed.push(page);\n }\n }),\n );\n }\n\n if (failed.length > 0) {\n throw new Error(`Could not fetch ${failed.length} Markdown pages`);\n }\n const response = await fetch(\n `https://raw.githubusercontent.com/observablehq/plot/refs/tags/${tag}/LICENSE`,\n );\n if (!response.ok) throw new Error(`Could not fetch Plot's license: HTTP ${response.status}`);\n const license = await response.text();\n const completion = `<!-- setup-data-project:observable-plot:${version}:complete -->`;\n return combinePlotDocs(version, documents).replace(\n completion,\n `## Upstream license\\n\\n${license.trim()}\\n\\n${completion}`,\n );\n}\n\nfunction isStoredReference(content: string, version: string): boolean {\n const source = `https://github.com/observablehq/plot/tree/v${version}/docs`;\n const metadata = content.split(/\\n\\s*\\n/)[1]?.replace(/\\s+/g, \" \");\n if (\n !content.startsWith(`# Observable Plot ${version}\\n\\n`) ||\n metadata !== `Package: \\`@observablehq/plot@${version}\\`. Source: [v${version}](${source}).` ||\n !content.trimEnd().endsWith(`<!-- setup-data-project:observable-plot:${version}:complete -->`)\n )\n return false;\n\n // Match actual page sections, not TOC entries. Require every selected page\n // exactly once and some upstream heading/content after its source record.\n const sections = [\n ...content.matchAll(/<a id=\"(plot-[^\"]+)\"><\\/a>\\n\\n# ([^\\n]+\\.md)\\n\\nSource:\\s+([^\\s]+)\\n\\n/g),\n ];\n if (sections.length !== PLOT_DOC_PAGES.length) return false;\n const found = new Set<string>();\n for (let index = 0; index < sections.length; index++) {\n const section = sections[index];\n const page = section[2];\n const id = `plot-${page.replace(/\\.md$/, \"\").replaceAll(\"/\", \"--\")}`;\n if (\n !PLOT_DOC_PAGES.includes(page) ||\n found.has(page) ||\n section[1] !== id ||\n section[3] !== `${source}/${page}`\n )\n return false;\n const body = content.slice(section.index + section[0].length, sections[index + 1]?.index);\n if (!/^#{1,6}\\s+\\S/m.test(body)) return false;\n found.add(page);\n }\n return true;\n}\n","import { log } from \"@clack/prompts\";\nimport { fetchPackageDocs, type PackageDocs } from \"./fetchPackageDocs.ts\";\nimport { fetchPlotDocs } from \"./fetchPlotDocs.ts\";\nimport { getInstalledPackageConfigs } from \"./packageRegistry.ts\";\nexport async function syncPackageDocs(\n installedPackages: string[],\n installedVersions: Record<string, string>,\n): Promise<Record<string, PackageDocs>> {\n const mapping: Record<string, PackageDocs> = {};\n for (const pkg of getInstalledPackageConfigs(installedPackages)) {\n const version = installedVersions[pkg.value];\n if (!version) {\n log.warn(\n `Could not determine the installed version of ${pkg.value}. Install the project dependencies, then run the docs script again. Existing documentation may be stale.`,\n );\n continue;\n }\n const docs =\n pkg.value === \"@observablehq/plot\"\n ? await fetchPlotDocs(version)\n : await fetchPackageDocs(pkg.value, version);\n if (docs.index !== undefined || docs.plot) mapping[pkg.value] = docs;\n }\n return mapping;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isObject } from \"./jsonObject.ts\";\nexport function getInstalledPackageVersions(\n packageSpecifiers: Record<string, string>,\n): Record<string, string> {\n const versions: Record<string, string> = {};\n for (const pkg of Object.keys(packageSpecifiers)) {\n const path = join(\"node_modules\", pkg, \"package.json\");\n if (!existsSync(path)) continue;\n const config: unknown = JSON.parse(readFileSync(path, \"utf8\"));\n if (\n isObject(config) &&\n typeof config.version === \"string\" &&\n /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/.test(config.version)\n )\n versions[pkg] = config.version;\n }\n return versions;\n}\n","import { SUPPORTED_PACKAGES } from \"./packageRegistry.ts\";\n\nexport interface CliOptions {\n help: boolean;\n docs: boolean;\n packages: string[];\n}\n\nconst packageFlags = new Map(\n SUPPORTED_PACKAGES.map((pkg) => [\n `--${pkg.label.replace(/^simple-data-analysis/, \"sda\").replace(/^journalism-/, \"\")}`,\n pkg.value,\n ]),\n);\n\nexport const CLI_HELP = `Usage: setup-data-project [library flags | --docs] [--help]\n\n${Array.from(packageFlags, ([flag, pkg]) => ` ${flag.padEnd(16)} Select ${pkg}.`).join(\"\\n\")}\n --docs Refresh documentation only for installed libraries.\n -h, --help Show this help and exit.\n\nWithout a package flag, choose packages interactively.\nCombine package flags to select libraries without prompting.\nPackage flags keep existing versions and still set up project files and docs.`;\n\nexport function parseArguments(args: string[]): CliOptions {\n const options: CliOptions = { help: false, docs: false, packages: [] };\n\n for (const arg of args) {\n const pkg = packageFlags.get(arg);\n if (arg === \"--help\" || arg === \"-h\") {\n options.help = true;\n } else if (arg === \"--docs\") {\n options.docs = true;\n } else if (pkg) {\n if (!options.packages.includes(pkg)) options.packages.push(pkg);\n } else {\n throw new Error(`Unknown argument: ${arg}. Use --help for usage.`);\n }\n }\n\n if (options.docs && options.packages.length > 0)\n throw new Error(\"--docs cannot be combined with package flags.\");\n return options;\n}\n","#!/usr/bin/env node\nimport { cancel, intro, isCancel, multiselect, outro, select, spinner } from \"@clack/prompts\";\nimport process from \"node:process\";\nimport { execFileSync } from \"node:child_process\";\n\nimport { getRuntime } from \"./helpers/getRuntime.ts\";\nimport { PACKAGE_OPTIONS } from \"./helpers/packageOptions.ts\";\nimport { ensureGitignore } from \"./helpers/ensureGitignore.ts\";\nimport { ensureReadme } from \"./helpers/ensureReadme.ts\";\nimport { ensureTooling } from \"./helpers/ensureTooling.ts\";\nimport { ensureVscode } from \"./helpers/ensureVscode.ts\";\nimport { runPackageManager, installPackages } from \"./helpers/installPackages.ts\";\nimport { getProjectTasks } from \"./helpers/getProjectTasks.ts\";\nimport { createFolderStructure } from \"./helpers/createFolderStructure.ts\";\nimport { ensureEnvFile } from \"./helpers/ensureEnvFile.ts\";\nimport { ensureAgents } from \"./helpers/ensureAgents.ts\";\nimport { getInstalledPackageConfigs } from \"./helpers/packageRegistry.ts\";\nimport { ProjectManifest } from \"./helpers/projectManifest.ts\";\nimport { syncPackageDocs } from \"./helpers/syncPackageDocs.ts\";\nimport { getInstalledPackageVersions } from \"./helpers/getInstalledPackageVersions.ts\";\nimport { CLI_HELP, parseArguments } from \"./helpers/parseArguments.ts\";\n\nasync function main() {\n const cliOptions = parseArguments(process.argv.slice(2));\n if (cliOptions.help) {\n console.log(CLI_HELP);\n return;\n }\n\n const runtime = getRuntime();\n const projectManifest = ProjectManifest.open();\n if (cliOptions.docs) {\n await refreshDocs(projectManifest);\n return;\n }\n console.log();\n intro(`Hi! 👋 (Running on ${runtime})`);\n\n const installedPackages = projectManifest.getInstalledPackages();\n const options = PACKAGE_OPTIONS.map((opt) => ({\n ...opt,\n label: installedPackages.includes(opt.value)\n ? `${opt.label} \\x1b[2m(installed)\\x1b[22m`\n : opt.label,\n }));\n\n const selectedPackages =\n cliOptions.packages.length > 0\n ? cliOptions.packages\n : await multiselect({\n message:\n \"Which libraries would you like to install?\\n\\x1b[2m(space to select, arrows to navigate, enter to confirm)\\x1b[22m\\n\",\n options,\n required: false,\n });\n\n if (isCancel(selectedPackages)) {\n cancel(\"Installation cancelled.\");\n process.exit(0);\n }\n\n const alreadyInstalled = selectedPackages.filter((pkg) => installedPackages.includes(pkg));\n\n const packagesToInstall: string[] = [];\n\n for (const pkg of selectedPackages) {\n if (alreadyInstalled.includes(pkg)) {\n if (cliOptions.packages.length > 0) continue;\n\n const action = await select({\n message: `${pkg} is already installed. What would you like to do?`,\n options: [\n { value: \"skip\", label: \"Keep existing version\" },\n { value: \"update\", label: \"Update to latest\" },\n ],\n });\n\n if (isCancel(action)) {\n cancel(\"Installation cancelled.\");\n process.exit(0);\n }\n\n if (action === \"update\") {\n packagesToInstall.push(pkg);\n }\n } else {\n packagesToInstall.push(pkg);\n }\n }\n\n projectManifest.updateTasks(getProjectTasks(runtime));\n\n const sInstall = spinner();\n sInstall.start(\"Installing packages...\");\n\n try {\n await installPackages(packagesToInstall);\n projectManifest.reload();\n const declared = projectManifest.getInstalledPackageSpecifiers();\n if (\n projectManifest\n .getInstalledPackages()\n .some((pkg) =>\n [\"@nshiab/simple-data-analysis\", \"@nshiab/journalism-dataviz\"].includes(pkg),\n ) &&\n !declared[\"@observablehq/plot\"]\n ) {\n await installPackages([\"@observablehq/plot\"]);\n projectManifest.reload();\n }\n await ensureTooling(projectManifest);\n // Reinstall declared dependencies when a project was cloned without node_modules.\n projectManifest.reload();\n const versions = getInstalledPackageVersions(projectManifest.getInstalledPackageSpecifiers());\n if (projectManifest.getInstalledPackages().some((pkg) => !versions[pkg]))\n await runPackageManager([\"install\"]);\n } catch (error) {\n sInstall.stop(\"Package installation failed.\");\n throw error;\n }\n sInstall.stop(\"Packages installed.\");\n\n projectManifest.reload();\n const finalInstalledPackages = getInstalledPackageConfigs(\n projectManifest.getInstalledPackages(),\n ).map((pkg) => pkg.value);\n const docsMapping = await refreshDocs(projectManifest);\n\n const sConfig = spinner();\n sConfig.start(\"Preparing project files and configuration...\");\n try {\n projectManifest.updateTasks(getProjectTasks());\n execFileSync(process.execPath, [\"node_modules/vite-plus/bin/vp\", \"fmt\", \"package.json\"], {\n stdio: \"pipe\",\n });\n\n createFolderStructure(finalInstalledPackages);\n ensureGitignore();\n ensureEnvFile();\n ensureVscode();\n ensureReadme(runtime, finalInstalledPackages);\n ensureAgents(docsMapping, runtime, finalInstalledPackages);\n } catch (error) {\n sConfig.stop(\"Project configuration failed.\");\n throw error;\n }\n sConfig.stop(\"Project files and configuration ready.\");\n\n outro(\n process.exitCode\n ? \"Project setup complete; documentation needs attention.\"\n : \"You are all set! 🙌\",\n );\n}\n\nasync function refreshDocs(manifest: ProjectManifest) {\n const packages = getInstalledPackageConfigs(manifest.getInstalledPackages()).map(\n (pkg) => pkg.value,\n );\n const sDocs = spinner();\n sDocs.start(\"Downloading documentation...\");\n try {\n const mapping = await syncPackageDocs(\n packages,\n getInstalledPackageVersions(manifest.getInstalledPackageSpecifiers()),\n );\n if (Object.keys(mapping).length !== packages.length) {\n sDocs.stop(\"Documentation incomplete. See the warnings above.\");\n process.exitCode = 1;\n } else {\n sDocs.stop(\n packages.length > 0 ? \"Documentation downloaded.\" : \"No library documentation to download.\",\n );\n }\n return mapping;\n } catch (error) {\n sDocs.stop(\"Documentation download failed.\");\n throw error;\n }\n}\n\nmain().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`❌ Error: ${message}`);\n process.exitCode = 1;\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"main.mjs","names":["process","metadata.name","metadata.version","metadata.version","process"],"sources":["../src/helpers/getRuntime.ts","../src/helpers/packageRegistry.ts","../src/helpers/packageOptions.ts","../src/helpers/gitignoreEntries.ts","../src/helpers/ensureGitignore.ts","../src/helpers/ensureManagedSection.ts","../src/helpers/ensureReadme.ts","../src/helpers/installPackages.ts","../package.json","../src/helpers/ensureTooling.ts","../src/helpers/ensureVscode.ts","../src/helpers/getProjectTasks.ts","../src/helpers/createFolderStructure.ts","../src/helpers/ensureEnvFile.ts","../src/helpers/ensureAgents.ts","../src/helpers/projectManifest.ts","../src/helpers/fetchPackageDocs.ts","../src/helpers/cleanPlotMarkdown.ts","../src/helpers/combinePlotDocs.ts","../src/helpers/plotDocPages.ts","../src/helpers/splitPlotDocs.ts","../src/helpers/fetchPlotDocs.ts","../src/helpers/syncPackageDocs.ts","../src/helpers/getInstalledPackageVersions.ts","../src/helpers/parseArguments.ts","../src/main.ts"],"sourcesContent":["import process from \"node:process\";\nexport type Runtime = \"node\" | \"bun\";\nexport function getRuntime(versions: { bun?: string; node?: string } = process.versions): Runtime {\n return versions.bun ? \"bun\" : \"node\";\n}\n","export interface PackageConfig {\n value: string;\n label: string;\n type: \"sda\" | \"journalism\" | \"other\";\n hint?: string;\n}\n\nexport const SUPPORTED_PACKAGES: PackageConfig[] = [\n {\n value: \"@nshiab/simple-data-analysis\",\n label: \"simple-data-analysis\",\n type: \"sda\",\n hint: \"All the core functionality, plus methods for dataviz, AI, Google sheets, etc.\",\n },\n {\n value: \"@nshiab/simple-data-analysis-core\",\n label: \"simple-data-analysis-core\",\n type: \"sda\",\n hint: \"No fluff. Great for constrained environments, like a cheap server.\",\n },\n {\n value: \"@nshiab/journalism-ai\",\n label: \"journalism-ai\",\n type: \"journalism\",\n hint: \"Easily use AI local models with Ollama or remote models with Gemini/Vertex.\",\n },\n {\n value: \"@nshiab/journalism-google\",\n label: \"journalism-google\",\n type: \"journalism\",\n hint: \"Push and retrieve data from Google Sheets, Google Bucket, and more.\",\n },\n {\n value: \"@nshiab/journalism-web-scraping\",\n label: \"journalism-web-scraping\",\n type: \"journalism\",\n hint: \"Retrieve data from Statistics Canada tables, HTML table, download files...\",\n },\n {\n value: \"@nshiab/journalism-finance\",\n label: \"journalism-finance\",\n type: \"journalism\",\n hint: \"Retrieve financial data, calculate Canadian mortgage payments and taxes...\",\n },\n {\n value: \"@nshiab/journalism-format\",\n label: \"journalism-format\",\n type: \"journalism\",\n hint: \"Easily format dates, numbers, currencies...\",\n },\n {\n value: \"@nshiab/journalism-climate\",\n label: \"journalism-climate\",\n type: \"journalism\",\n hint: \"Retrieve data from Environment Canada APIs and more.\",\n },\n {\n value: \"@nshiab/journalism-dataviz\",\n label: \"journalism-dataviz\",\n type: \"journalism\",\n hint: \"Render charts/maps with Observable Plot or directly in the terminal.\",\n },\n {\n value: \"@nshiab/journalism-geo\",\n label: \"journalism-geo\",\n type: \"journalism\",\n hint: \"Calculate distances, transform 2D coordinates to 3D, wrangle GeoTIFF files...\",\n },\n {\n value: \"@nshiab/journalism-statistics\",\n label: \"journalism-statistics\",\n type: \"journalism\",\n hint: \"Functions for statistical tests, clustering, random path generation...\",\n },\n {\n value: \"@nshiab/journalism-web\",\n label: \"journalism-web\",\n type: \"journalism\",\n hint: \"Web related functions, including downloading data as CSV, extracting ZIP files to URLs...\",\n },\n {\n value: \"@nshiab/journalism-extras\",\n label: \"journalism-extras\",\n type: \"journalism\",\n hint: \"Functions to zip/unzip, sleep, reencode files, create nested directories...\",\n },\n];\n\n// Plot is installed alongside charting libraries, but is not a setup menu option.\nexport const DOCUMENTED_PACKAGES: PackageConfig[] = [\n ...SUPPORTED_PACKAGES,\n { value: \"@nshiab/journalism\", label: \"journalism\", type: \"journalism\" },\n { value: \"@observablehq/plot\", label: \"Observable Plot\", type: \"other\" },\n];\n\nexport function getInstalledPackageConfigs(installedPackages: string[]): PackageConfig[] {\n const installedSet = new Set(installedPackages);\n return DOCUMENTED_PACKAGES.filter((pkg) => installedSet.has(pkg.value));\n}\n","import { SUPPORTED_PACKAGES } from \"./packageRegistry.ts\";\n\nexport const PACKAGE_OPTIONS = SUPPORTED_PACKAGES.map((pkg) => ({\n value: pkg.value,\n label: pkg.label,\n hint: pkg.hint,\n}));\n","export const GITIGNORE_ENTRIES = [\n \"node_modules\",\n \"docs/\",\n \".tmp\",\n \".sda-cache\",\n \"sda/.sda.pid\",\n \"sda/.sda-lock/\",\n \".journalism-cache\",\n \"sda/data\",\n \"sda/output\",\n \".env\",\n \".DS_Store\",\n];\n","import { lstatSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { GITIGNORE_ENTRIES } from \"./gitignoreEntries.ts\";\n\nexport const GITIGNORE_SENTINEL = \"# Added by setup-data-project. Do not remove this line.\";\n\nexport function ensureGitignore() {\n const path = \".gitignore\";\n const stats = lstatSync(path, { throwIfNoEntry: false });\n\n if (stats?.isSymbolicLink()) {\n return;\n }\n\n const content = stats === undefined ? \"\" : readFileSync(path, \"utf-8\");\n const hasSentinel = content.split(\"\\n\").some((line) => line.trim() === GITIGNORE_SENTINEL);\n\n if (hasSentinel) {\n const entries = new Set(content.split(\"\\n\").map((line) => line.trim()));\n const missing = GITIGNORE_ENTRIES.filter((entry) => !entries.has(entry));\n if (missing.length)\n writeFileSync(\n path,\n content + (content.endsWith(\"\\n\") ? \"\" : \"\\n\") + missing.join(\"\\n\") + \"\\n\",\n );\n return;\n }\n\n const separator = content === \"\" ? \"\" : content.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n const block = `${GITIGNORE_SENTINEL}\\n${GITIGNORE_ENTRIES.join(\"\\n\")}\\n`;\n writeFileSync(path, content + separator + block);\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\n\ninterface ManagedSectionOptions {\n path: string;\n name: string;\n content: string;\n createContent: (section: string) => string;\n}\n\nexport function ensureManagedSection(\n options: ManagedSectionOptions,\n): \"created\" | \"updated\" | \"unchanged\" | \"missing-markers\" {\n const startMarker = `<!-- setup-data-project:${options.name}:start / Safe to remove if you don't want this section. -->`;\n const endMarker = `<!-- setup-data-project:${options.name}:end / End of generated section. -->`;\n const trimmedContent = options.content.trim();\n const section =\n trimmedContent === \"\"\n ? `${startMarker}\\n${endMarker}`\n : `${startMarker}\\n\\n${trimmedContent}\\n\\n${endMarker}`;\n\n if (!existsSync(options.path)) {\n writeFileSync(options.path, ensureFinalNewline(options.createContent(section)));\n return \"created\";\n }\n\n const currentContent = readFileSync(options.path, \"utf-8\");\n const start = currentContent.indexOf(startMarker);\n const end = currentContent.indexOf(endMarker);\n\n if (start === -1 || end === -1 || end < start) {\n return \"missing-markers\";\n }\n\n const nextContent =\n currentContent.slice(0, start) + section + currentContent.slice(end + endMarker.length);\n\n if (nextContent === currentContent) {\n return \"unchanged\";\n }\n\n writeFileSync(options.path, ensureFinalNewline(nextContent));\n return \"updated\";\n}\n\nfunction ensureFinalNewline(content: string): string {\n return content.endsWith(\"\\n\") ? content : content + \"\\n\";\n}\n","import { ensureManagedSection } from \"./ensureManagedSection.ts\";\nimport { getInstalledPackageConfigs } from \"./packageRegistry.ts\";\nimport type { Runtime } from \"./getRuntime.ts\";\nexport function ensureReadme(runtime: Runtime, installedPackages: string[] = []) {\n const run = runtime === \"bun\" ? \"bun run\" : \"npm run\";\n const vp = runtime === \"bun\" ? \"bun run --bun vp\" : \"npx vp\";\n const libraries = getInstalledPackageConfigs(installedPackages)\n .map((pkg) => `\\`${pkg.value}\\``)\n .join(\", \");\n ensureManagedSection({\n path: \"README.md\",\n name: \"libraries\",\n createContent: (section) =>\n `# Data project\\n\\nCreated with [setup-data-project](https://github.com/nshiab/setup-data-project).\\n\\n${section}`,\n content: `${libraries ? `Installed libraries: ${libraries}.\\n\\n` : \"\"}Use sda/main.ts to process source data from sda/data/ and write results to sda/output/. Both data folders are ignored by Git. Put reusable helpers in sda/helpers/ and tests in sda/tests/. Import test utilities from \\`vite-plus/test\\`.\n\n- \\`${run} sda\\`: run \\`${run} fix\\`, then run the analysis once if checks pass.\n- \\`${run} sda:watch\\`: do the same on changes to sda/ and .env, excluding sda/output/.\n- \\`${run} sda:status\\`: check whether an SDA run or watcher is active.\n- \\`${run} all-tests\\`: check types, lint, formatting, and tests; succeeds when no tests exist.\n- \\`${run} fix\\`: format files, apply automatic lint fixes, and check types.\n- \\`${run} docs\\`: refresh documentation for the installed library versions.\n- \\`${run} clean\\`: delete cached results and temporary files in .sda-cache/, .journalism-cache/, and .tmp/.\n\nSDA blocks simultaneous runs. Recovery after a forced termination is best effort.\n\nRun one test file with \\`${vp} test sda/tests/example.test.ts\\`. For test-driven development, watch for changes with \\`${vp} test sda/tests/example.test.ts --watch\\`. Replace the path with your test file.\n\nIn VS Code, install the recommended Vite+ extension pack for Oxc formatting and linting and the Vitest test runner. Generated .vscode/settings.json enables formatting and lint fixes on save, plus visual line wrapping. Existing VS Code configuration files are preserved.\n\nThe generated docs/ folder is ignored by Git. Refresh it after cloning or updating dependencies. See AGENTS.md for documentation pointers.`,\n });\n}\n","import { execFile } from \"node:child_process\";\nimport { getRuntime } from \"./getRuntime.ts\";\nexport function runPackageManager(args: string[]): Promise<void> {\n const command = getRuntime() === \"bun\" ? \"bun\" : process.platform === \"win32\" ? \"npm.cmd\" : \"npm\";\n return new Promise((resolve, reject) => {\n execFile(\n command,\n args,\n { maxBuffer: 10 * 1024 * 1024, shell: process.platform === \"win32\" },\n (error, stdout, stderr) => {\n if (error)\n reject(\n new Error(`${command} ${args.join(\" \")} failed.\\n${stderr || stdout}`, {\n cause: error,\n }),\n );\n else resolve();\n },\n );\n });\n}\nexport async function installPackages(\n packages: string[],\n options: { development?: boolean } = {},\n): Promise<void> {\n if (packages.length === 0) return;\n const bun = getRuntime() === \"bun\";\n await runPackageManager([\n bun ? \"add\" : \"install\",\n ...(options.development ? (bun ? [\"--dev\"] : [\"--save-dev\"]) : []),\n ...packages,\n ]);\n}\n","","import { existsSync, writeFileSync } from \"node:fs\";\nimport { ProjectManifest } from \"./projectManifest.ts\";\nimport { getRuntime } from \"./getRuntime.ts\";\nimport { installPackages } from \"./installPackages.ts\";\nimport metadata from \"../../package.json\" with { type: \"json\" };\nconst tools = [\"vite-plus\", \"@types/node\"];\nexport async function ensureTooling(manifest: ProjectManifest): Promise<void> {\n const runtime = getRuntime();\n const runtimeTools = runtime === \"bun\" ? [...tools, \"@types/bun\"] : tools;\n const installed = manifest.getInstalledPackages();\n await installPackages(\n [\n ...runtimeTools.filter((pkg) => !installed.includes(pkg)).map((pkg) => `${pkg}@latest`),\n ...(installed.includes(metadata.name) ? [] : [`${metadata.name}@${metadata.version}`]),\n ],\n { development: true },\n );\n if (\n ![\n \"vite.config.ts\",\n \"vite.config.js\",\n \"vite.config.mts\",\n \"vite.config.mjs\",\n \"vite.config.cts\",\n \"vite.config.cjs\",\n ].some((file) => existsSync(file))\n ) {\n writeFileSync(\n \"vite.config.ts\",\n `import { defineConfig, loadEnv } from \"vite-plus\";\n\nexport default defineConfig({\n test: { env: loadEnv(\"test\", process.cwd(), \"\") },\n lint: { options: { typeAware: true, typeCheck: true } },\n fmt: { ignorePatterns: [\"docs/**\", \"sda/data/**\", \"sda/output/**\"] },\n});\n`,\n );\n }\n if (!existsSync(\"tsconfig.json\"))\n writeFileSync(\n \"tsconfig.json\",\n `{\n \"compilerOptions\": {\n \"target\": \"ES2023\",\n \"module\": \"NodeNext\",\n \"strict\": true,\n \"noEmit\": true,\n \"allowImportingTsExtensions\": true,\n \"erasableSyntaxOnly\": ${runtime === \"node\"},\n \"types\": ${runtime === \"bun\" ? '[\"node\", \"bun\"]' : '[\"node\"]'},\n \"skipLibCheck\": true\n },\n \"include\": [\"sda/**/*.ts\", \"vite.config.*\"]\n}\n`,\n );\n}\n","import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\n\nexport function ensureVscode(): void {\n mkdirSync(\".vscode\", { recursive: true });\n const formatter = \"oxc.oxc-vscode\";\n const files = {\n \"extensions.json\": `{\n \"recommendations\": [\"VoidZero.vite-plus-extension-pack\"]\n}\n`,\n \"settings.json\": `${JSON.stringify(\n {\n \"editor.defaultFormatter\": formatter,\n \"[javascript]\": { \"editor.defaultFormatter\": formatter },\n \"[javascriptreact]\": { \"editor.defaultFormatter\": formatter },\n \"[typescript]\": { \"editor.defaultFormatter\": formatter },\n \"[typescriptreact]\": { \"editor.defaultFormatter\": formatter },\n \"oxc.disableNestedConfig\": true,\n \"oxc.fmt.disableNestedConfig\": true,\n \"editor.formatOnSave\": true,\n \"editor.formatOnSaveMode\": \"file\",\n \"editor.codeActionsOnSave\": { \"source.fixAll.oxc\": \"explicit\" },\n \"editor.wordWrap\": \"on\",\n },\n null,\n 2,\n )}\\n`,\n };\n for (const [name, config] of Object.entries(files)) {\n const path = `.vscode/${name}`;\n if (!existsSync(path)) writeFileSync(path, config);\n }\n}\n","import { getRuntime, type Runtime } from \"./getRuntime.ts\";\nimport metadata from \"../../package.json\" with { type: \"json\" };\nexport function getProjectTasks(runtime: Runtime = getRuntime()) {\n const vp = runtime === \"bun\" ? \"bun run --bun vp\" : \"vp\";\n const runner = runtime === \"bun\" ? \"bun run --bun --no-env-file sda-run\" : \"sda-run\";\n return {\n sda: `${runner} sda/main.ts`,\n \"sda:watch\": `${runner} --watch sda/main.ts sda .env --ignore sda/output`,\n \"sda:status\": `${runner} --status`,\n \"all-tests\": `${vp} check && ${vp} test --passWithNoTests`,\n clean: \"rm -rf .sda-cache .journalism-cache .tmp\",\n fix: `${vp} check --fix`,\n docs: `${runtime === \"bun\" ? \"bunx --bun\" : \"npx\"} @nshiab/setup-data-project@${metadata.version} --docs`,\n };\n}\n","import { existsSync, lstatSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport function createFolderStructure(selectedPackages: string[]) {\n const sdaFolder = \"sda\";\n const folders = [\"data\", \"helpers\", \"output\", \"tests\"];\n\n if (!existsSync(sdaFolder)) {\n mkdirSync(sdaFolder, { recursive: true });\n }\n\n for (const folder of folders) {\n const path = join(sdaFolder, folder);\n if (!existsSync(path)) {\n mkdirSync(path, { recursive: true });\n }\n }\n\n const mainTsPath = join(sdaFolder, \"main.ts\");\n\n let mainTsContent = 'console.log(\"Hello simple-data-analysis!\");\\n';\n\n if (\n selectedPackages.includes(\"@nshiab/simple-data-analysis\") ||\n selectedPackages.includes(\"@nshiab/simple-data-analysis-core\")\n ) {\n const pkg = selectedPackages.includes(\"@nshiab/simple-data-analysis\")\n ? \"@nshiab/simple-data-analysis\"\n : \"@nshiab/simple-data-analysis-core\";\n mainTsContent = `import { SimpleDB } from \"${pkg}\";\n\nconst sdb = new SimpleDB();\nconst table = sdb.newTable();\n\nawait table.loadArray([{ message: \"Hello simple-data-analysis!\" }]).log();\n\nawait sdb.close();\n`;\n }\n\n if (lstatSync(mainTsPath, { throwIfNoEntry: false }) === undefined) {\n writeFileSync(mainTsPath, mainTsContent);\n }\n\n return sdaFolder;\n}\n","import { lstatSync, writeFileSync } from \"node:fs\";\n\nexport function ensureEnvFile() {\n if (lstatSync(\".env\", { throwIfNoEntry: false }) === undefined) {\n writeFileSync(\".env\", \"\");\n }\n}\n","import type { PackageDocs } from \"./fetchPackageDocs.ts\";\nimport { ensureManagedSection } from \"./ensureManagedSection.ts\";\nimport { getInstalledPackageConfigs } from \"./packageRegistry.ts\";\nimport type { Runtime } from \"./getRuntime.ts\";\nexport function ensureAgents(\n docsMapping: Record<string, PackageDocs>,\n runtime: Runtime,\n installedPackages: string[] = Object.keys(docsMapping),\n) {\n const run = runtime === \"bun\" ? \"bun run\" : \"npm run\";\n const vp = runtime === \"bun\" ? \"bun run --bun vp\" : \"npx vp\";\n const links = getInstalledPackageConfigs(installedPackages).map((pkg) => {\n if (pkg.value === \"@observablehq/plot\")\n return `- Observable Plot charts and maps: start at \\`docs/observable-plot/llms.txt\\`, then read the relevant pages for use with writeChart and writeMap.`;\n return `- \\`${pkg.value}\\`: start at \\`docs/${pkg.value.slice(\"@nshiab/\".length)}/llms.txt\\`, then read the relevant API pages and examples.`;\n });\n ensureManagedSection({\n path: \"AGENTS.md\",\n name: \"agents\",\n createContent: (section) => section,\n content: `Read package.json for the installed libraries and scripts. Prefer the installed data libraries when they cover the task.\n\nUse sda/main.ts as the entry point and sda/helpers/ for reusable helpers. Put tests in sda/tests/, source data in sda/data/, and results in sda/output/. Import test utilities from \\`vite-plus/test\\`.\n\nRun \\`${run} sda\\` to fix and check code, then execute the analysis once. Use \\`${run} sda:watch\\` to watch for changes. Before handing off code changes, run \\`${run} all-tests\\` and resolve failures.\n\nBefore starting work, run \\`${run} sda:status\\` and follow its instructions.\n\nFor a focused test run, use \\`${vp} test sda/tests/example.test.ts\\`, replacing the path with your test file. Add \\`--watch\\` for test-driven development.\n\nThe clean script removes cached results and temporary files. Run it only when those cached results can be discarded.\n\nLibrary documentation in docs/ is generated and ignored by Git. Run \\`${run} docs\\` when documentation is missing or after dependency changes; resolve refresh failures before using possibly stale references. Edit project source files rather than downloaded documentation.\n\n${links.join(\"\\n\")}`,\n });\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { isObject } from \"./jsonObject.ts\";\nexport class ProjectManifest {\n #config: Record<string, unknown>;\n private constructor(config: Record<string, unknown>) {\n this.#config = config;\n }\n static open(): ProjectManifest {\n if (!existsSync(\"package.json\"))\n return new ProjectManifest({ name: \"data-project\", private: true, type: \"module\" });\n const config: unknown = JSON.parse(readFileSync(\"package.json\", \"utf8\"));\n if (!isObject(config)) throw new Error(\"package.json must contain a JSON object.\");\n return new ProjectManifest(config);\n }\n reload(): void {\n this.#config = ProjectManifest.open().#config;\n }\n getInstalledPackages(): string[] {\n return Object.keys(this.getInstalledPackageSpecifiers());\n }\n getInstalledPackageSpecifiers(): Record<string, string> {\n const packages: Record<string, string> = {};\n for (const key of [\"dependencies\", \"devDependencies\"]) {\n const dependencies = this.#config[key];\n if (isObject(dependencies))\n for (const [name, version] of Object.entries(dependencies)) {\n if (typeof version === \"string\") packages[name] = version;\n }\n }\n return packages;\n }\n updateTasks(tasks: Record<string, string>): void {\n if (this.#config.type === \"commonjs\") {\n throw new Error(\n 'Setup requires an ESM project. Set \"type\": \"module\" in package.json, or use --docs to refresh documentation only.',\n );\n }\n if (this.#config.type === undefined) this.#config.type = \"module\";\n const existing = this.#config.scripts;\n this.#config.scripts = { ...tasks, ...(isObject(existing) ? existing : {}) };\n writeFileSync(\"package.json\", JSON.stringify(this.#config, null, 2) + \"\\n\");\n }\n}\n","import { log } from \"@clack/prompts\";\nimport {\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join, posix } from \"node:path\";\nimport { x } from \"tar\";\nimport { DOCUMENTED_PACKAGES } from \"./packageRegistry.ts\";\nexport interface PackageDocs {\n readme?: string;\n index?: string;\n llm?: string;\n plot?: { version: string; pages: string[] };\n}\nexport async function fetchPackageDocs(pkg: string, version: string): Promise<PackageDocs> {\n const config = DOCUMENTED_PACKAGES.find(\n (item) => item.value === pkg && item.value.startsWith(\"@nshiab/\"),\n );\n if (!config || !/^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/.test(version))\n throw new Error(`Unsupported package or version: ${pkg}@${version}`);\n const repo = pkg.slice(\"@nshiab/\".length);\n mkdirSync(\"docs\", { recursive: true });\n const staging = mkdtempSync(join(\"docs\", \".download-\"));\n const contents = join(staging, \"contents\");\n const target = join(\"docs\", repo);\n const backup = join(staging, \"previous\");\n try {\n const url = `https://github.com/nshiab/${repo}/releases/download/v${version}/documentation.tar.gz`;\n const response = await fetch(url);\n if (!response.ok) throw new Error(`HTTP ${response.status} from ${url}`);\n const archive = join(staging, \"documentation.tar.gz\");\n writeFileSync(archive, Buffer.from(await response.arrayBuffer()));\n mkdirSync(contents);\n let unsafeEntry: string | undefined;\n await x({\n file: archive,\n cwd: contents,\n strict: true,\n preservePaths: false,\n filter(path, entry) {\n const normalized = posix.normalize(path);\n if (\n path.includes(\"\\\\\") ||\n path.startsWith(\"/\") ||\n normalized === \"..\" ||\n normalized.startsWith(\"../\") ||\n !(\"type\" in entry) ||\n ![\"File\", \"Directory\"].includes(entry.type)\n ) {\n unsafeEntry = path;\n return false;\n }\n return true;\n },\n });\n if (unsafeEntry !== undefined) throw new Error(`Unsafe archive entry: ${unsafeEntry}`);\n for (const path of [\"README.md\", \"LICENSE\", \"llms.txt\", \"docs\"]) {\n if (!existsSync(join(contents, path)))\n throw new Error(`Documentation archive is missing ${path}.`);\n }\n const readme = readFileSync(join(contents, \"README.md\"), \"utf8\");\n const index = readFileSync(join(contents, \"llms.txt\"), \"utf8\");\n if (existsSync(target)) renameSync(target, backup);\n try {\n renameSync(contents, target);\n } catch (error) {\n if (existsSync(backup)) renameSync(backup, target);\n throw error;\n }\n return { readme, index };\n } catch (error) {\n log.warn(\n `Could not refresh ${pkg}@${version}: ${String(error)} Existing documentation was preserved and may be stale. Run the docs script again after resolving the error.`,\n );\n return {};\n } finally {\n rmSync(staging, { recursive: true, force: true });\n }\n}\n","// Plot's source is VitePress Markdown. Keep examples as reference material,\n// but remove the website UI and turn its custom containers into ordinary text.\nexport function cleanPlotMarkdown(content: string): string {\n const preserved: string[] = [];\n const keep = (value: string) => {\n preserved.push(value);\n return `\\uE000PLOT${preserved.length - 1}\\uE000`;\n };\n const lines = content.split(\"\\n\");\n const prose: string[] = [];\n for (let index = 0; index < lines.length; index++) {\n if (/^\\s*<!--/.test(lines[index])) {\n const start = index;\n while (!lines[index].includes(\"-->\") && index + 1 < lines.length) index++;\n prose.push(lines.slice(start, index + 1).join(\"\\n\"));\n continue;\n }\n const opening = lines[index].match(/^ {0,3}(`{3,}|~{3,})(.*)$/);\n if (!opening) {\n prose.push(lines[index]);\n continue;\n }\n const start = index;\n while (++index < lines.length) {\n const closing = lines[index].match(/^ {0,3}(`{3,}|~{3,})\\s*$/);\n if (closing?.[1][0] === opening[1][0] && closing[1].length >= opening[1].length) break;\n }\n if (index >= lines.length) throw new Error(\"Unclosed Plot code fence.\");\n const block = lines.slice(start, index + 1);\n if (opening[2].trim() === \"js-vue\") {\n block[0] = `${opening[1]}text`;\n prose.push(\n keep(\n \"Interactive example template (values in `{{…}}` come from the upstream website):\\n\\n\" +\n block.join(\"\\n\"),\n ),\n );\n } else {\n prose.push(keep(block.join(\"\\n\")));\n }\n }\n let result = prose\n .join(\"\\n\")\n .replace(/<script\\b[^>]*>([\\s\\S]*?)<\\/script>/g, (_match: string, code: string) => {\n const fence = \"`\".repeat(\n Math.max(3, ...[...code.matchAll(/`+/g)].map((match) => match[0].length + 1)),\n );\n return keep(\n `**Upstream example setup.** This code may use Vue and sample data from the linked source page.\\n\\n${fence}js\\n${code.trim()}\\n${fence}`,\n );\n })\n .replace(/^[ \\t]*<!--(?!\\s*setup-data-project:)[\\s\\S]*?-->/gm, \"\")\n .replace(\n /<\\/?[A-Za-z](?:\"[^\"]*\"|'[^']*'|[^'\"><])*>|(`+)[^`\\n]*?\\1/g,\n (part: string, fence: string | undefined) => (fence ? keep(part) : part),\n )\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/g, \"\")\n .replace(/<p\\b[^>]*>([\\s\\S]*?)<\\/p>/g, (_match: string, body: string) =>\n /<(?:input|select|label)\\b/.test(body) ? \"\" : body,\n )\n .replace(/<PlotRender\\b[\\s\\S]*?\\/>/g, (component) => {\n const options = component.match(/:options=([\"'])([\\s\\S]*?)\\1/)?.[2];\n const method = component.match(/\\bmethod=[\"'](\\w+)[\"']/)?.[1] ?? \"plot\";\n if (!options) throw new Error(\"Unrecognized PlotRender example.\");\n return keep(`\\`\\`\\`js\\nPlot.${method}(${options});\\n\\`\\`\\``);\n })\n .replace(/<VersionBadge\\b[\\s\\S]*?\\/>/g, (badge) => {\n const version = badge.match(/\\bversion=[\"']([^\"']+)[\"']/)?.[1];\n return version ? `(since v${version})` : \"\";\n })\n .replace(/<\\/?span\\b(?:\"[^\"]*\"|'[^']*'|[^'\">])*>/g, \"\")\n .replace(/<svg\\b[\\s\\S]*?<\\/svg>/g, \"arrow\");\n result = result\n .replace(/^[ \\t]*:::plot\\b([^\\n]*)/gm, (_match: string, options: string) => {\n const url = options.match(/https?:\\/\\/\\S+/)?.[0];\n return url ? `[Interactive example](${url})\\n` : \"\";\n })\n .replace(\n /^([ \\t]*):::(tip|info|warning)\\b[ \\t]*/gm,\n (_match: string, indent: string, kind: string) =>\n `${indent}**${kind[0].toUpperCase() + kind.slice(1)}:** `,\n )\n .replace(/^[ \\t]*:::[ \\t]*$/gm, \"\")\n .replace(/[ \\t]+:::[ \\t]*$/gm, \"\")\n .replace(\n /\\{\\{([\\s\\S]*?)\\}\\}/g,\n (_match: string, expression: string) => `\\`${expression.trim().replace(/\\s+/g, \" \")}\\``,\n )\n .replace(/[ \\t]+$/gm, \"\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n return (\n result.replace(\n /\\uE000PLOT(\\d+)\\uE000/g,\n (_match: string, index: string) => preserved[Number(index)],\n ) + \"\\n\"\n );\n}\n","import { cleanPlotMarkdown } from \"./cleanPlotMarkdown.ts\";\nimport { posix } from \"node:path\";\n\n// The Plot source uses ATX headings, explicit VitePress IDs, and Markdown fences.\n// Keep code verbatim; rewrite only prose links and anchors while joining pages.\nexport function combinePlotDocs(version: string, documents: Map<string, string>): string {\n const pages = [...documents.keys()].sort();\n const source = `https://github.com/observablehq/plot/tree/v${version}/docs`;\n const anchors = new Map<string, Map<string, string>>();\n const sections = new Map<string, { line: number; title: string; id: string }[]>();\n const pageId = (page: string) => `plot-${page.replace(/\\.md$/, \"\").replaceAll(\"/\", \"--\")}`;\n\n for (const page of pages) {\n const ids = new Map<string, string>();\n const headings: { line: number; title: string; id: string }[] = [];\n const counts = new Map<string, number>();\n proseLines(documents.get(page) ?? \"\", (line, number) => {\n for (const match of line.matchAll(/\\bid=[\"']([^\"']+)[\"']/g)) {\n ids.set(match[1], `${pageId(page)}--${match[1]}`);\n }\n const heading = line.match(/^ {0,3}#{1,6}\\s+(.+?)\\s*#*\\s*$/);\n if (!heading) return line;\n const explicit = heading[1].match(/\\{#([^}]+)\\}/)?.[1];\n const title = heading[1].replace(/\\s*\\{#[^}]+\\}/g, \"\");\n const slug =\n explicit ??\n title\n .replace(/<[^>]*>/g, \"\")\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}_\\s-]/gu, \"\")\n .trim()\n .replace(/\\s+/g, \"-\");\n const count = counts.get(slug) ?? 0;\n counts.set(slug, count + 1);\n const localId = `${slug}${count ? `-${count}` : \"\"}`;\n const id = `${pageId(page)}--${localId}`;\n ids.set(localId, id);\n headings.push({ line: number, title, id });\n return line;\n });\n anchors.set(page, ids);\n sections.set(page, headings);\n }\n\n function link(target: string, page: string): string {\n if (/^(?:[a-z][a-z\\d+.-]*:|\\/\\/)/i.test(target)) return target;\n const [pathAndQuery, fragment] = target.split(\"#\", 2);\n const path = pathAndQuery.split(\"?\", 1)[0];\n const resolved =\n path === \"\"\n ? page\n : posix.normalize(\n path.startsWith(\"/\") ? path.slice(1) : posix.join(posix.dirname(page), path),\n );\n const markdown = [resolved, `${resolved}.md`, `${resolved}/index.md`].find((candidate) =>\n documents.has(candidate),\n );\n if (markdown) {\n const id = fragment\n ? anchors.get(markdown)?.get(decodeURIComponent(fragment))\n : pageId(markdown);\n if (id) return `#${id}`;\n // Preserve an upstream target when a fragment is not a known heading/ID.\n return `${source}/${markdown}${fragment ? `#${fragment}` : \"\"}`;\n }\n if (resolved.endsWith(\".md\")) {\n return `${source}/${resolved}${fragment ? `#${fragment}` : \"\"}`;\n }\n const base =\n \"https://raw.githubusercontent.com/observablehq/plot/\" + `refs/tags/v${version}/docs/`;\n return path.startsWith(\"/\")\n ? new URL(`public${target}`, base).href\n : new URL(target, `${base}${page}`).href;\n }\n\n const contents = pages\n .flatMap((page) => [\n `- [${page}](#${pageId(page)})`,\n ...(sections.get(page) ?? []).map(\n ({ title, id }) => ` - [${title.replace(/[[\\]]/g, \"\")}](#${id})`,\n ),\n ])\n .join(\"\\n\");\n const combined = pages\n .map((page) => {\n const headings = new Map(\n (sections.get(page) ?? []).map((heading) => [heading.line, heading]),\n );\n const body = proseLines(documents.get(page) ?? \"\", (line, number) => {\n const heading = headings.get(number);\n // Inline code also remains verbatim. Plot's prose links have simple destinations.\n line = line\n .split(/(`+[^`]*`+)/g)\n .map((part, index) => {\n if (index % 2) return part;\n return part\n .replace(\n /(\\]\\()([^\\s)]+)([^)]*\\))/g,\n (_match: string, before: string, target: string, after: string) =>\n `${before}${link(target, page)}${after}`,\n )\n .replace(\n /^( {0,3}\\[[^\\]]+\\]:\\s*)(\\S+)/,\n (_match: string, before: string, target: string) =>\n `${before}${link(target, page)}`,\n )\n .replace(\n /(?<!:)\\b(href|src)=([\"'])([^\"']+)\\2/g,\n (_match: string, attr: string, quote: string, target: string) =>\n `${attr}=${quote}${link(target, page)}${quote}`,\n )\n .replace(\n /\\bid=([\"'])([^\"']+)\\1/g,\n (_match: string, quote: string, id: string) =>\n `id=${quote}${anchors.get(page)?.get(id) ?? id}${quote}`,\n );\n })\n .join(\"\");\n return heading\n ? `<a id=\"${heading.id}\"></a>\\n\\n${line.replace(/\\s*\\{#[^}]+\\}/g, \"\")}`\n : line;\n });\n return `<a id=\"${pageId(page)}\"></a>\\n\\n# ${page}\\n\\nSource: ${source}/${page}\\n\\n${body}`;\n })\n .join(\"\\n\\n---\\n\\n\");\n return cleanPlotMarkdown(\n `# Observable Plot ${version}\\n\\nPackage: \\`@observablehq/plot@${version}\\`. Source: [v${version}](${source}).\\n\\nThis reference combines selected upstream documentation for static charts and maps. Introductory and site pages, interaction helpers, and the Auto and Tip marks are omitted. Website controls are omitted; upstream setup and interactive templates are labeled as reference code. Use the table of contents to find API signatures and examples; links to omitted pages lead to the tagged upstream documentation.\\n\\n## Table of contents\\n\\n${contents}\\n\\n---\\n\\n${combined}\\n\\n<!-- setup-data-project:observable-plot:${version}:complete -->\\n`,\n );\n}\n\nexport function proseLines(\n content: string,\n transform: (line: string, number: number) => string,\n): string {\n let fence: { character: string; length: number } | undefined;\n let script = false;\n return content\n .split(\"\\n\")\n .map((line, number) => {\n const marker = line.match(/^ {0,3}(`{3,}|~{3,})/);\n if (fence) {\n if (\n marker?.[1][0] === fence.character &&\n marker[1].length >= fence.length &&\n /^ {0,3}(?:`+|~+)\\s*$/.test(line)\n )\n fence = undefined;\n return line;\n }\n if (marker) {\n fence = { character: marker[1][0], length: marker[1].length };\n return line;\n }\n if (/^\\s*<script\\b/.test(line)) script = true;\n if (script) {\n if (/<\\/script>/.test(line)) script = false;\n return line;\n }\n return transform(line, number);\n })\n .join(\"\\n\");\n}\n","// Static chart creation references. Keep this explicit so new upstream pages do\n// not silently expand the installed agent reference.\nexport const PLOT_DOC_PAGES: string[] = [\n \"features/plots.md\",\n \"features/marks.md\",\n \"features/scales.md\",\n \"features/projections.md\",\n \"features/legends.md\",\n \"features/facets.md\",\n \"features/formats.md\",\n \"features/curves.md\",\n \"transforms/bin.md\",\n \"transforms/group.md\",\n \"transforms/stack.md\",\n \"transforms/normalize.md\",\n \"transforms/centroid.md\",\n \"transforms/sort.md\",\n \"marks/area.md\",\n \"marks/arrow.md\",\n \"marks/axis.md\",\n \"marks/bar.md\",\n \"marks/bollinger.md\",\n \"marks/box.md\",\n \"marks/cell.md\",\n \"marks/contour.md\",\n \"marks/delaunay.md\",\n \"marks/density.md\",\n \"marks/difference.md\",\n \"marks/dot.md\",\n \"marks/frame.md\",\n \"marks/geo.md\",\n \"marks/grid.md\",\n \"marks/hexgrid.md\",\n \"marks/image.md\",\n \"marks/line.md\",\n \"marks/linear-regression.md\",\n \"marks/link.md\",\n \"marks/raster.md\",\n \"marks/rect.md\",\n \"marks/rule.md\",\n \"marks/text.md\",\n \"marks/tick.md\",\n \"marks/tree.md\",\n \"marks/vector.md\",\n \"marks/waffle.md\",\n].sort();\n","import { cleanPlotMarkdown } from \"./cleanPlotMarkdown.ts\";\nimport { posix } from \"node:path\";\nimport { proseLines } from \"./combinePlotDocs.ts\";\nimport { PLOT_DOC_PAGES } from \"./plotDocPages.ts\";\n\n// Split the cached format without changing code examples or heading anchors.\nexport function splitPlotDocs(reference: string, version: string): Map<string, string> {\n const sections = [\n ...reference.matchAll(\n /<a id=\"(plot-[^\"]+)\"><\\/a>\\n\\n# ([^\\n]+\\.md)\\n\\nSource:\\s+([^\\s]+)\\n\\n/g,\n ),\n ];\n const files = new Map<string, string>();\n const anchors = new Map<string, string>();\n const source = `https://github.com/observablehq/plot/tree/v${version}/docs`;\n const completion = `<!-- setup-data-project:observable-plot:${version}:complete -->`;\n if (!reference.trimEnd().endsWith(completion)) throw new Error(\"Incomplete Plot reference.\");\n const end = reference.lastIndexOf(completion);\n const licenseStart = reference.lastIndexOf(\"\\n## Upstream license\\n\", end);\n for (let index = 0; index < sections.length; index++) {\n const section = sections[index];\n const page = section[2];\n if (!PLOT_DOC_PAGES.includes(page) || files.has(page) || section[3] !== `${source}/${page}`)\n throw new Error(`Invalid Plot page: ${page}`);\n const body = reference\n .slice(section.index, sections[index + 1]?.index ?? (licenseStart >= 0 ? licenseStart : end))\n .trimEnd()\n .replace(/\\n\\n---$/, \"\");\n files.set(page, body);\n proseLines(body, (line) => {\n for (const match of line.matchAll(/\\bid=[\"']([^\"']+)[\"']/g)) anchors.set(match[1], page);\n return line;\n });\n }\n if (files.size !== PLOT_DOC_PAGES.length) throw new Error(\"Incomplete Plot pages.\");\n\n for (const [page, body] of files) {\n const link = (id: string) => {\n const destination = anchors.get(id);\n return destination && destination !== page\n ? `${posix.relative(posix.dirname(page), destination)}#${id}`\n : `#${id}`;\n };\n files.set(\n page,\n cleanPlotMarkdown(\n proseLines(body, (line) =>\n line\n .split(/(`+[^`]*`+)/g)\n .map((part, index) =>\n index % 2\n ? part\n : part\n .replace(\n /(\\]\\()#([^\\s)]+)([^)]*\\))/g,\n (_match: string, before: string, id: string, after: string) =>\n `${before}${link(id)}${after}`,\n )\n .replace(\n /^( {0,3}\\[[^\\]]+\\]:\\s*)#(\\S+)/,\n (_match: string, before: string, id: string) => `${before}${link(id)}`,\n )\n .replace(\n /(?<!:)\\b(href|src)=([\"'])#([^\"']+)\\2/g,\n (_match: string, attr: string, quote: string, id: string) =>\n `${attr}=${quote}${link(id)}${quote}`,\n ),\n )\n .join(\"\"),\n ),\n ),\n );\n }\n const license =\n licenseStart >= 0\n ? reference.slice(licenseStart + \"\\n## Upstream license\\n\".length, end).trim()\n : undefined;\n if (license) files.set(\"LICENSE\", license + \"\\n\");\n const index =\n `# Observable Plot ${version}\\n\\n> Selected documentation for static charts and maps. Start here, then read the relevant pages.\\n\\n[Versioned upstream documentation](${source})${license ? \" · [License](./LICENSE)\" : \"\"}\\n\\n` +\n [\"features\", \"marks\", \"transforms\"]\n .map(\n (group) =>\n `## ${group[0].toUpperCase() + group.slice(1)}\\n\\n` +\n PLOT_DOC_PAGES.filter((page) => page.startsWith(`${group}/`))\n .map((page) => `- [${page}](./${page})`)\n .join(\"\\n\"),\n )\n .join(\"\\n\\n\") +\n \"\\n\";\n files.set(\"llms.txt\", index);\n return files;\n}\n","import { log } from \"@clack/prompts\";\nimport { existsSync, mkdirSync, mkdtempSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { splitPlotDocs } from \"./splitPlotDocs.ts\";\nimport { combinePlotDocs } from \"./combinePlotDocs.ts\";\nimport { PLOT_DOC_PAGES } from \"./plotDocPages.ts\";\nimport type { PackageDocs } from \"./fetchPackageDocs.ts\";\n\n// Replace local documentation only after every page is ready.\nexport async function fetchPlotDocs(\n version: string,\n options: { preferStored?: boolean } = {},\n): Promise<PackageDocs> {\n const tag = `v${version}`;\n const directory = join(\"docs\", \"observable-plot\");\n try {\n let llm: string | undefined;\n if (options.preferStored !== false) {\n try {\n const response = await fetch(\n \"https://raw.githubusercontent.com/nshiab/setup-data-project/\" +\n `refs/heads/main/docs-cache/observable-plot/${version}/llm.md`,\n );\n if (response.ok) {\n const cached = await response.text();\n if (isStoredReference(cached, version)) llm = cached;\n }\n } catch {\n // A cache is an optimization. An unavailable cache never blocks the tag.\n }\n }\n if (llm === undefined) llm = await generatePlotReference(version);\n const files = splitPlotDocs(llm, version);\n mkdirSync(\"docs\", { recursive: true });\n const staging = mkdtempSync(join(\"docs\", \".plot-\"));\n const contents = join(staging, \"contents\");\n const backup = join(staging, \"previous\");\n try {\n for (const [page, content] of files) {\n const path = join(contents, page);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, content);\n }\n if (existsSync(directory)) renameSync(directory, backup);\n try {\n renameSync(contents, directory);\n } catch (error) {\n if (existsSync(backup)) renameSync(backup, directory);\n throw error;\n }\n } finally {\n rmSync(staging, { recursive: true, force: true });\n }\n return { llm, index: files.get(\"llms.txt\"), plot: { version, pages: [...PLOT_DOC_PAGES] } };\n } catch (error) {\n log.warn(\n `Could not fetch complete Observable Plot documentation for ${tag}. ` +\n \"Existing files were preserved, but may not match the installed \" +\n \"version. Resolve the refresh failure before using this reference. \" +\n String(error),\n );\n return {};\n }\n}\n\nexport async function generatePlotReference(version: string): Promise<string> {\n if (!/^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$/.test(version))\n throw new Error(\"An exact Plot version is required.\");\n const tag = `v${version}`;\n const pages = PLOT_DOC_PAGES;\n const documents = new Map<string, string>();\n const failed: string[] = [];\n // Fetch in small batches to avoid overwhelming GitHub on the first run.\n for (let offset = 0; offset < pages.length; offset += 8) {\n await Promise.all(\n pages.slice(offset, offset + 8).map(async (page) => {\n try {\n const url =\n \"https://raw.githubusercontent.com/observablehq/plot/\" +\n `refs/tags/${tag}/docs/${page}`;\n const response = await fetch(url);\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n const content = await response.text();\n documents.set(page, content);\n } catch {\n failed.push(page);\n }\n }),\n );\n }\n\n if (failed.length > 0) {\n throw new Error(`Could not fetch ${failed.length} Markdown pages`);\n }\n const response = await fetch(\n `https://raw.githubusercontent.com/observablehq/plot/refs/tags/${tag}/LICENSE`,\n );\n if (!response.ok) throw new Error(`Could not fetch Plot's license: HTTP ${response.status}`);\n const license = await response.text();\n const completion = `<!-- setup-data-project:observable-plot:${version}:complete -->`;\n return combinePlotDocs(version, documents).replace(\n completion,\n `## Upstream license\\n\\n${license.trim()}\\n\\n${completion}`,\n );\n}\n\nfunction isStoredReference(content: string, version: string): boolean {\n const source = `https://github.com/observablehq/plot/tree/v${version}/docs`;\n const metadata = content.split(/\\n\\s*\\n/)[1]?.replace(/\\s+/g, \" \");\n if (\n !content.startsWith(`# Observable Plot ${version}\\n\\n`) ||\n metadata !== `Package: \\`@observablehq/plot@${version}\\`. Source: [v${version}](${source}).` ||\n !content.trimEnd().endsWith(`<!-- setup-data-project:observable-plot:${version}:complete -->`)\n )\n return false;\n\n // Match actual page sections, not TOC entries. Require every selected page\n // exactly once and some upstream heading/content after its source record.\n const sections = [\n ...content.matchAll(/<a id=\"(plot-[^\"]+)\"><\\/a>\\n\\n# ([^\\n]+\\.md)\\n\\nSource:\\s+([^\\s]+)\\n\\n/g),\n ];\n if (sections.length !== PLOT_DOC_PAGES.length) return false;\n const found = new Set<string>();\n for (let index = 0; index < sections.length; index++) {\n const section = sections[index];\n const page = section[2];\n const id = `plot-${page.replace(/\\.md$/, \"\").replaceAll(\"/\", \"--\")}`;\n if (\n !PLOT_DOC_PAGES.includes(page) ||\n found.has(page) ||\n section[1] !== id ||\n section[3] !== `${source}/${page}`\n )\n return false;\n const body = content.slice(section.index + section[0].length, sections[index + 1]?.index);\n if (!/^#{1,6}\\s+\\S/m.test(body)) return false;\n found.add(page);\n }\n return true;\n}\n","import { log } from \"@clack/prompts\";\nimport { fetchPackageDocs, type PackageDocs } from \"./fetchPackageDocs.ts\";\nimport { fetchPlotDocs } from \"./fetchPlotDocs.ts\";\nimport { getInstalledPackageConfigs } from \"./packageRegistry.ts\";\nexport async function syncPackageDocs(\n installedPackages: string[],\n installedVersions: Record<string, string>,\n): Promise<Record<string, PackageDocs>> {\n const mapping: Record<string, PackageDocs> = {};\n for (const pkg of getInstalledPackageConfigs(installedPackages)) {\n const version = installedVersions[pkg.value];\n if (!version) {\n log.warn(\n `Could not determine the installed version of ${pkg.value}. Install the project dependencies, then run the docs script again. Existing documentation may be stale.`,\n );\n continue;\n }\n const docs =\n pkg.value === \"@observablehq/plot\"\n ? await fetchPlotDocs(version)\n : await fetchPackageDocs(pkg.value, version);\n if (docs.index !== undefined || docs.plot) mapping[pkg.value] = docs;\n }\n return mapping;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isObject } from \"./jsonObject.ts\";\nexport function getInstalledPackageVersions(\n packageSpecifiers: Record<string, string>,\n): Record<string, string> {\n const versions: Record<string, string> = {};\n for (const pkg of Object.keys(packageSpecifiers)) {\n const path = join(\"node_modules\", pkg, \"package.json\");\n if (!existsSync(path)) continue;\n const config: unknown = JSON.parse(readFileSync(path, \"utf8\"));\n if (\n isObject(config) &&\n typeof config.version === \"string\" &&\n /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/.test(config.version)\n )\n versions[pkg] = config.version;\n }\n return versions;\n}\n","import { SUPPORTED_PACKAGES } from \"./packageRegistry.ts\";\n\nexport interface CliOptions {\n help: boolean;\n docs: boolean;\n packages: string[];\n}\n\nconst packageFlags = new Map(\n SUPPORTED_PACKAGES.map((pkg) => [\n `--${pkg.label.replace(/^simple-data-analysis/, \"sda\").replace(/^journalism-/, \"\")}`,\n pkg.value,\n ]),\n);\n\nexport const CLI_HELP = `Usage: setup-data-project [library flags | --docs] [--help]\n\n${Array.from(packageFlags, ([flag, pkg]) => ` ${flag.padEnd(16)} Select ${pkg}.`).join(\"\\n\")}\n --docs Refresh documentation only for installed libraries.\n -h, --help Show this help and exit.\n\nWithout a package flag, choose packages interactively.\nCombine package flags to select libraries without prompting.\nPackage flags keep existing versions and still set up project files and docs.`;\n\nexport function parseArguments(args: string[]): CliOptions {\n const options: CliOptions = { help: false, docs: false, packages: [] };\n\n for (const arg of args) {\n const pkg = packageFlags.get(arg);\n if (arg === \"--help\" || arg === \"-h\") {\n options.help = true;\n } else if (arg === \"--docs\") {\n options.docs = true;\n } else if (pkg) {\n if (!options.packages.includes(pkg)) options.packages.push(pkg);\n } else {\n throw new Error(`Unknown argument: ${arg}. Use --help for usage.`);\n }\n }\n\n if (options.docs && options.packages.length > 0)\n throw new Error(\"--docs cannot be combined with package flags.\");\n return options;\n}\n","#!/usr/bin/env node\nimport { cancel, intro, isCancel, multiselect, outro, select, spinner } from \"@clack/prompts\";\nimport process from \"node:process\";\nimport { execFileSync } from \"node:child_process\";\n\nimport { getRuntime } from \"./helpers/getRuntime.ts\";\nimport { PACKAGE_OPTIONS } from \"./helpers/packageOptions.ts\";\nimport { ensureGitignore } from \"./helpers/ensureGitignore.ts\";\nimport { ensureReadme } from \"./helpers/ensureReadme.ts\";\nimport { ensureTooling } from \"./helpers/ensureTooling.ts\";\nimport { ensureVscode } from \"./helpers/ensureVscode.ts\";\nimport { runPackageManager, installPackages } from \"./helpers/installPackages.ts\";\nimport { getProjectTasks } from \"./helpers/getProjectTasks.ts\";\nimport { createFolderStructure } from \"./helpers/createFolderStructure.ts\";\nimport { ensureEnvFile } from \"./helpers/ensureEnvFile.ts\";\nimport { ensureAgents } from \"./helpers/ensureAgents.ts\";\nimport { getInstalledPackageConfigs } from \"./helpers/packageRegistry.ts\";\nimport { ProjectManifest } from \"./helpers/projectManifest.ts\";\nimport { syncPackageDocs } from \"./helpers/syncPackageDocs.ts\";\nimport { getInstalledPackageVersions } from \"./helpers/getInstalledPackageVersions.ts\";\nimport { CLI_HELP, parseArguments } from \"./helpers/parseArguments.ts\";\n\nasync function main() {\n const cliOptions = parseArguments(process.argv.slice(2));\n if (cliOptions.help) {\n console.log(CLI_HELP);\n return;\n }\n\n const runtime = getRuntime();\n const projectManifest = ProjectManifest.open();\n if (cliOptions.docs) {\n await refreshDocs(projectManifest);\n return;\n }\n console.log();\n intro(`Hi! 👋 (Running on ${runtime})`);\n\n const installedPackages = projectManifest.getInstalledPackages();\n const options = PACKAGE_OPTIONS.map((opt) => ({\n ...opt,\n label: installedPackages.includes(opt.value)\n ? `${opt.label} \\x1b[2m(installed)\\x1b[22m`\n : opt.label,\n }));\n\n const selectedPackages =\n cliOptions.packages.length > 0\n ? cliOptions.packages\n : await multiselect({\n message:\n \"Which libraries would you like to install?\\n\\x1b[2m(space to select, arrows to navigate, enter to confirm)\\x1b[22m\\n\",\n options,\n required: false,\n });\n\n if (isCancel(selectedPackages)) {\n cancel(\"Installation cancelled.\");\n process.exit(0);\n }\n\n const alreadyInstalled = selectedPackages.filter((pkg) => installedPackages.includes(pkg));\n\n const packagesToInstall: string[] = [];\n\n for (const pkg of selectedPackages) {\n if (alreadyInstalled.includes(pkg)) {\n if (cliOptions.packages.length > 0) continue;\n\n const action = await select({\n message: `${pkg} is already installed. What would you like to do?`,\n options: [\n { value: \"skip\", label: \"Keep existing version\" },\n { value: \"update\", label: \"Update to latest\" },\n ],\n });\n\n if (isCancel(action)) {\n cancel(\"Installation cancelled.\");\n process.exit(0);\n }\n\n if (action === \"update\") {\n packagesToInstall.push(pkg);\n }\n } else {\n packagesToInstall.push(pkg);\n }\n }\n\n projectManifest.updateTasks(getProjectTasks(runtime));\n\n const sInstall = spinner();\n sInstall.start(\"Installing packages...\");\n\n try {\n await installPackages(packagesToInstall);\n projectManifest.reload();\n const declared = projectManifest.getInstalledPackageSpecifiers();\n if (\n projectManifest\n .getInstalledPackages()\n .some((pkg) =>\n [\"@nshiab/simple-data-analysis\", \"@nshiab/journalism-dataviz\"].includes(pkg),\n ) &&\n !declared[\"@observablehq/plot\"]\n ) {\n await installPackages([\"@observablehq/plot\"]);\n projectManifest.reload();\n }\n await ensureTooling(projectManifest);\n // Reinstall declared dependencies when a project was cloned without node_modules.\n projectManifest.reload();\n const versions = getInstalledPackageVersions(projectManifest.getInstalledPackageSpecifiers());\n if (projectManifest.getInstalledPackages().some((pkg) => !versions[pkg]))\n await runPackageManager([\"install\"]);\n } catch (error) {\n sInstall.stop(\"Package installation failed.\");\n throw error;\n }\n sInstall.stop(\"Packages installed.\");\n\n projectManifest.reload();\n const finalInstalledPackages = getInstalledPackageConfigs(\n projectManifest.getInstalledPackages(),\n ).map((pkg) => pkg.value);\n const docsMapping = await refreshDocs(projectManifest);\n\n const sConfig = spinner();\n sConfig.start(\"Preparing project files and configuration...\");\n try {\n projectManifest.updateTasks(getProjectTasks());\n execFileSync(process.execPath, [\"node_modules/vite-plus/bin/vp\", \"fmt\", \"package.json\"], {\n stdio: \"pipe\",\n });\n\n createFolderStructure(finalInstalledPackages);\n ensureGitignore();\n ensureEnvFile();\n ensureVscode();\n ensureReadme(runtime, finalInstalledPackages);\n ensureAgents(docsMapping, runtime, finalInstalledPackages);\n } catch (error) {\n sConfig.stop(\"Project configuration failed.\");\n throw error;\n }\n sConfig.stop(\"Project files and configuration ready.\");\n\n outro(\n process.exitCode\n ? \"Project setup complete; documentation needs attention.\"\n : \"You are all set! 🙌\",\n );\n}\n\nasync function refreshDocs(manifest: ProjectManifest) {\n const packages = getInstalledPackageConfigs(manifest.getInstalledPackages()).map(\n (pkg) => pkg.value,\n );\n const sDocs = spinner();\n sDocs.start(\"Downloading documentation...\");\n try {\n const mapping = await syncPackageDocs(\n packages,\n getInstalledPackageVersions(manifest.getInstalledPackageSpecifiers()),\n );\n if (Object.keys(mapping).length !== packages.length) {\n sDocs.stop(\"Documentation incomplete. See the warnings above.\");\n process.exitCode = 1;\n } else {\n sDocs.stop(\n packages.length > 0 ? \"Documentation downloaded.\" : \"No library documentation to download.\",\n );\n }\n return mapping;\n } catch (error) {\n sDocs.stop(\"Documentation download failed.\");\n throw error;\n }\n}\n\nmain().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`❌ Error: ${message}`);\n process.exitCode = 1;\n});\n"],"mappings":"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"}
|
package/dist/sda.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as isObject } from "./jsonObject-B1ldqsgL.mjs";
|
|
3
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
4
|
-
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, watch, writeFileSync } from "node:fs";
|
|
3
|
+
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
4
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, watch, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, join, resolve, sep } from "node:path";
|
|
6
6
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
7
7
|
import { parseArgs } from "node:util";
|
|
@@ -9,7 +9,7 @@ import { randomUUID } from "node:crypto";
|
|
|
9
9
|
//#region src/helpers/sdaLock.ts
|
|
10
10
|
const SDA_PID_FILE = "sda/.sda.pid";
|
|
11
11
|
const SDA_LOCK_DIRECTORY = "sda/.sda-lock";
|
|
12
|
-
function errorCode$
|
|
12
|
+
function errorCode$2(error) {
|
|
13
13
|
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
14
14
|
}
|
|
15
15
|
async function acquireSdaLock(command) {
|
|
@@ -41,7 +41,7 @@ async function acquireSdaLock(command) {
|
|
|
41
41
|
try {
|
|
42
42
|
process.kill(pid, 0);
|
|
43
43
|
} catch (error) {
|
|
44
|
-
if (errorCode$
|
|
44
|
+
if (errorCode$2(error) !== "ESRCH") throw error;
|
|
45
45
|
rmSync(path, {
|
|
46
46
|
recursive: true,
|
|
47
47
|
force: true
|
|
@@ -52,7 +52,7 @@ async function acquireSdaLock(command) {
|
|
|
52
52
|
try {
|
|
53
53
|
record = JSON.parse(readFileSync(join(path, "owner.json"), "utf8"));
|
|
54
54
|
} catch (error) {
|
|
55
|
-
if (errorCode$
|
|
55
|
+
if (errorCode$2(error) !== "ENOENT") throw error;
|
|
56
56
|
return existsSync(path) ? {
|
|
57
57
|
id: candidate,
|
|
58
58
|
pid,
|
|
@@ -75,7 +75,8 @@ async function acquireSdaLock(command) {
|
|
|
75
75
|
}
|
|
76
76
|
writeFileSync(join(ownDirectory, "owner.tmp"), JSON.stringify({
|
|
77
77
|
ticket,
|
|
78
|
-
command
|
|
78
|
+
command,
|
|
79
|
+
projectRoot: realpathSync(process.cwd())
|
|
79
80
|
}));
|
|
80
81
|
renameSync(join(ownDirectory, "owner.tmp"), join(ownDirectory, "owner.json"));
|
|
81
82
|
const deadline = performance.now() + 5e3;
|
|
@@ -98,10 +99,124 @@ async function acquireSdaLock(command) {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
//#endregion
|
|
102
|
+
//#region src/helpers/sdaStatus.ts
|
|
103
|
+
function errorCode$1(error) {
|
|
104
|
+
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
105
|
+
}
|
|
106
|
+
function printSdaStatus() {
|
|
107
|
+
const run = `${process.versions.bun ? "bun" : "npm"} run`;
|
|
108
|
+
const retry = `${run} sda:status`;
|
|
109
|
+
try {
|
|
110
|
+
const pids = /* @__PURE__ */ new Set();
|
|
111
|
+
const claims = /* @__PURE__ */ new Map();
|
|
112
|
+
try {
|
|
113
|
+
for (const name of readdirSync(SDA_LOCK_DIRECTORY)) {
|
|
114
|
+
const match = /^(\d+)-[\da-f-]{36}$/.exec(name);
|
|
115
|
+
if (match) {
|
|
116
|
+
const pid = Number(match[1]);
|
|
117
|
+
pids.add(pid);
|
|
118
|
+
claims.set(pid, [...claims.get(pid) ?? [], name]);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (errorCode$1(error) !== "ENOENT") throw error;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const value = readFileSync(SDA_PID_FILE, "utf8").trim();
|
|
126
|
+
if (!/^\d+$/.test(value)) throw new Error("The SDA PID file is invalid.");
|
|
127
|
+
pids.add(Number(value));
|
|
128
|
+
} catch (error) {
|
|
129
|
+
if (errorCode$1(error) !== "ENOENT") throw error;
|
|
130
|
+
}
|
|
131
|
+
const messages = [];
|
|
132
|
+
for (const pid of pids) {
|
|
133
|
+
if (!Number.isInteger(pid) || pid <= 0 || pid > 2147483647) throw new Error("The recorded SDA PID is invalid.");
|
|
134
|
+
try {
|
|
135
|
+
process.kill(pid, 0);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (errorCode$1(error) === "ESRCH") continue;
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
let command;
|
|
141
|
+
if (process.platform === "win32") {
|
|
142
|
+
const owners = claims.get(pid) ?? [];
|
|
143
|
+
if (owners.length !== 1) throw new Error(`PID ${pid} has no unambiguous SDA owner record.`);
|
|
144
|
+
const owner = JSON.parse(readFileSync(join(SDA_LOCK_DIRECTORY, owners[0], "owner.json"), "utf8"));
|
|
145
|
+
if (!isObject(owner) || typeof owner.projectRoot !== "string" || realpathSync(owner.projectRoot) !== realpathSync(process.cwd())) throw new Error(`PID ${pid} could not be verified as this project's SDA process.`);
|
|
146
|
+
const result = JSON.parse(execFileSync("powershell.exe", [
|
|
147
|
+
"-NoLogo",
|
|
148
|
+
"-NoProfile",
|
|
149
|
+
"-NonInteractive",
|
|
150
|
+
"-Command",
|
|
151
|
+
`[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new(\$false); (Get-CimInstance Win32_Process -Filter 'ProcessId = ${pid}' -ErrorAction Stop).CommandLine | ConvertTo-Json -Compress`
|
|
152
|
+
], {
|
|
153
|
+
encoding: "utf8",
|
|
154
|
+
timeout: 5e3,
|
|
155
|
+
maxBuffer: 65536,
|
|
156
|
+
windowsHide: true,
|
|
157
|
+
stdio: [
|
|
158
|
+
"ignore",
|
|
159
|
+
"pipe",
|
|
160
|
+
"pipe"
|
|
161
|
+
]
|
|
162
|
+
}));
|
|
163
|
+
if (typeof result !== "string" || !result.trim()) throw new Error(`PID ${pid} has no readable command line.`);
|
|
164
|
+
command = result;
|
|
165
|
+
} else if (process.platform === "darwin" || process.platform === "linux") {
|
|
166
|
+
command = execFileSync("ps", [
|
|
167
|
+
"-p",
|
|
168
|
+
String(pid),
|
|
169
|
+
"-o",
|
|
170
|
+
"command="
|
|
171
|
+
], {
|
|
172
|
+
encoding: "utf8",
|
|
173
|
+
timeout: 5e3,
|
|
174
|
+
stdio: [
|
|
175
|
+
"ignore",
|
|
176
|
+
"pipe",
|
|
177
|
+
"pipe"
|
|
178
|
+
]
|
|
179
|
+
}).trim();
|
|
180
|
+
const cwd = process.platform === "linux" ? realpathSync(`/proc/${pid}/cwd`) : execFileSync("lsof", [
|
|
181
|
+
"-a",
|
|
182
|
+
"-p",
|
|
183
|
+
String(pid),
|
|
184
|
+
"-d",
|
|
185
|
+
"cwd",
|
|
186
|
+
"-Fn"
|
|
187
|
+
], {
|
|
188
|
+
encoding: "utf8",
|
|
189
|
+
timeout: 5e3,
|
|
190
|
+
stdio: [
|
|
191
|
+
"ignore",
|
|
192
|
+
"pipe",
|
|
193
|
+
"pipe"
|
|
194
|
+
]
|
|
195
|
+
}).split("\n").find((line) => line.startsWith("n"))?.slice(1);
|
|
196
|
+
if (!cwd || realpathSync(cwd) !== realpathSync(process.cwd())) throw new Error(`PID ${pid} could not be verified as this project's SDA process.`);
|
|
197
|
+
} else throw new Error("Active SDA processes cannot be verified on this platform.");
|
|
198
|
+
const executable = process.argv[1];
|
|
199
|
+
if (!executable || !command.includes(executable) && !command.includes(realpathSync(executable)) && !/(?:[\\/]@nshiab[\\/]setup-data-project[\\/]dist[\\/]sda\.mjs|[\\/]node_modules[\\/]\.bin[\\/]sda-run)(?:["\s]|$)/.test(command)) throw new Error(`PID ${pid} could not be verified as this project's SDA process.`);
|
|
200
|
+
messages.push(/(?:^|["\s])--watch(?:["\s]|$)/.test(command) ? `SDA watcher is running (${run} sda:watch, PID ${pid}). It automatically fixes files and reruns the analysis. If you are an agent, ask the user to stop it with Ctrl+C, then recheck with ${retry} before doing any work.` : `SDA analysis is running (${run} sda, PID ${pid}). Wait for it to finish. Recheck with ${retry} in 30 seconds before doing any work.`);
|
|
201
|
+
}
|
|
202
|
+
for (const message of messages) console.log(message);
|
|
203
|
+
if (messages.length) return 1;
|
|
204
|
+
console.log("No active SDA process found. You can proceed.");
|
|
205
|
+
return 0;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.error(`Unable to verify SDA status: ${error instanceof Error ? error.message : String(error)} If you are an agent, ask the user to confirm that neither ${run} sda nor ${run} sda:watch is running and that you may proceed, then wait for their confirmation before doing any work.`);
|
|
208
|
+
return 2;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//#endregion
|
|
101
212
|
//#region src/sda.ts
|
|
102
213
|
const { positionals: [entry, ...paths], values } = parseArgs({
|
|
103
214
|
allowPositionals: true,
|
|
104
215
|
options: {
|
|
216
|
+
status: {
|
|
217
|
+
type: "boolean",
|
|
218
|
+
default: false
|
|
219
|
+
},
|
|
105
220
|
watch: {
|
|
106
221
|
type: "boolean",
|
|
107
222
|
default: false
|
|
@@ -113,8 +228,9 @@ const { positionals: [entry, ...paths], values } = parseArgs({
|
|
|
113
228
|
}
|
|
114
229
|
}
|
|
115
230
|
});
|
|
231
|
+
if (values.status) process.exit(printSdaStatus());
|
|
116
232
|
if (!entry) {
|
|
117
|
-
console.error("Usage: sda-run [--watch] <entry-file> [watch-paths...] [--ignore path]");
|
|
233
|
+
console.error("Usage: sda-run --status | [--watch] <entry-file> [watch-paths...] [--ignore path]");
|
|
118
234
|
process.exit(1);
|
|
119
235
|
}
|
|
120
236
|
const watching = values.watch;
|
|
@@ -140,6 +256,7 @@ let contents = /* @__PURE__ */ new Map();
|
|
|
140
256
|
const watchers = /* @__PURE__ */ new Map();
|
|
141
257
|
function launch(args, command = process.execPath) {
|
|
142
258
|
const child = spawn(command, args, {
|
|
259
|
+
argv0: windows && bun && command === process.execPath ? "bun" : void 0,
|
|
143
260
|
stdio: "inherit",
|
|
144
261
|
detached: !windows,
|
|
145
262
|
shell: windows && command === "npm.cmd"
|
package/dist/sda.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sda.mjs","names":["errorCode","delay","delay"],"sources":["../src/helpers/sdaLock.ts","../src/sda.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { isObject } from \"./jsonObject.ts\";\n\nexport const SDA_PID_FILE = \"sda/.sda.pid\";\nexport const SDA_LOCK_DIRECTORY = \"sda/.sda-lock\";\n\ntype Claim = { id: string; pid: number; ticket: number; command?: string };\n\nfunction errorCode(error: unknown) {\n return error instanceof Error && \"code\" in error ? error.code : undefined;\n}\n\n// Bakery ordering: publish a unique claim before choosing a ticket, then wait for\n// concurrent ticket choices. Never replace/delete a shared lock during recovery.\n// https://www.microsoft.com/en-us/research/publication/new-solution-dijkstras-concurrent-programming-problem/\nexport async function acquireSdaLock(command: string): Promise<() => void> {\n const directory = resolve(SDA_LOCK_DIRECTORY);\n const pidFile = resolve(SDA_PID_FILE);\n const id = `${process.pid}-${randomUUID()}`;\n const ownDirectory = join(directory, id);\n mkdirSync(directory, { recursive: true });\n mkdirSync(ownDirectory);\n let ownsPid = false;\n const release = () => {\n if (ownsPid) {\n // Remove the informational PID before releasing ownership to the next run.\n rmSync(pidFile, { force: true });\n ownsPid = false;\n }\n rmSync(ownDirectory, { recursive: true, force: true });\n process.removeListener(\"exit\", release);\n };\n process.once(\"exit\", release);\n\n function readClaim(candidate: string): Claim | undefined {\n const match = /^(\\d+)-[\\da-f-]{36}$/.exec(candidate);\n if (!match) return;\n const pid = Number(match[1]);\n if (!Number.isInteger(pid) || pid <= 0 || pid > 2147483647) return;\n const path = join(directory, candidate);\n try {\n process.kill(pid, 0);\n } catch (error) {\n if (errorCode(error) !== \"ESRCH\") throw error;\n // Claim names are never reused, so another starter cannot acquire this path.\n rmSync(path, { recursive: true, force: true });\n return;\n }\n let record: unknown;\n try {\n record = JSON.parse(readFileSync(join(path, \"owner.json\"), \"utf8\"));\n } catch (error) {\n if (errorCode(error) !== \"ENOENT\") throw error;\n // A directory without a published ticket is still choosing, or has exited.\n return existsSync(path) ? { id: candidate, pid, ticket: 0 } : undefined;\n }\n if (\n !isObject(record) ||\n typeof record.ticket !== \"number\" ||\n !Number.isSafeInteger(record.ticket) ||\n record.ticket < 1 ||\n typeof record.command !== \"string\"\n )\n throw new Error(`Cannot read the SDA lock owned by process ${pid}.`);\n return { id: candidate, pid, ticket: record.ticket, command: record.command };\n }\n\n try {\n let ticket = 1;\n for (const candidate of readdirSync(directory)) {\n const claim = readClaim(candidate);\n if (claim) ticket = Math.max(ticket, claim.ticket + 1);\n }\n writeFileSync(join(ownDirectory, \"owner.tmp\"), JSON.stringify({ ticket, command }));\n renameSync(join(ownDirectory, \"owner.tmp\"), join(ownDirectory, \"owner.json\"));\n const deadline = performance.now() + 5000;\n for (const candidate of readdirSync(directory)) {\n if (candidate === id) continue;\n let claim = readClaim(candidate);\n while (claim?.ticket === 0) {\n if (performance.now() >= deadline)\n throw new Error(\n `Another SDA command is still starting (PID ${claim.pid}). Wait for it to finish starting, then try again.`,\n );\n await delay(10);\n claim = readClaim(candidate);\n }\n if (claim && (claim.ticket < ticket || (claim.ticket === ticket && claim.id < id)))\n throw new Error(\n `${claim.command} is already running${claim.command?.endsWith(\"sda:watch\") ? \" and watching this project's files\" : \" an analysis for this project\"} (PID ${claim.pid}). Wait for it to finish or stop it with Ctrl+C in its terminal, then try again.`,\n );\n }\n // Only the winner touches the shared PID file, including stale-file recovery.\n writeFileSync(pidFile, String(process.pid) + \"\\n\");\n ownsPid = true;\n return release;\n } catch (error) {\n release();\n throw error;\n }\n}\n","#!/usr/bin/env node\nimport { existsSync, lstatSync, type FSWatcher, readdirSync, watch } from \"node:fs\";\nimport { spawn, spawnSync, type ChildProcess } from \"node:child_process\";\nimport { dirname, join, resolve, sep } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { parseArgs } from \"node:util\";\nimport { acquireSdaLock, SDA_PID_FILE, SDA_LOCK_DIRECTORY } from \"./helpers/sdaLock.ts\";\n\nconst {\n positionals: [entry, ...paths],\n values,\n} = parseArgs({\n allowPositionals: true,\n options: {\n watch: { type: \"boolean\", default: false },\n ignore: { type: \"string\", multiple: true, default: [] },\n },\n});\nif (!entry) {\n console.error(\"Usage: sda-run [--watch] <entry-file> [watch-paths...] [--ignore path]\");\n process.exit(1);\n}\nconst watching = values.watch;\nconst selected = [entry, ...paths].map((path) => resolve(path));\nconst ignored = [SDA_PID_FILE, SDA_LOCK_DIRECTORY, ...values.ignore].map((path) => resolve(path));\nconst within = (path: string, root: string) => path === root || path.startsWith(root + sep);\nconst excluded = (path: string) => ignored.some((root) => within(path, root));\nconst bun = Boolean(process.versions.bun);\nconst runCommand = (bun ? \"bun run \" : \"npm run \") + (watching ? \"sda:watch\" : \"sda\");\nconst windows = process.platform === \"win32\";\ntype Job = { child: ChildProcess; done: Promise<number | null> };\nlet releaseLock: (() => void) | undefined;\nlet fixer: Job | undefined;\nlet analysis: Job | undefined;\nlet timer: ReturnType<typeof setTimeout> | undefined;\nlet checking = false;\nlet closing = false;\nlet needsCheck = true;\nlet contents = new Map<string, string | null>();\nconst watchers = new Map<string, { watcher: FSWatcher; recursive: boolean }>();\n\nfunction launch(args: string[], command = process.execPath) {\n const child = spawn(command, args, {\n stdio: \"inherit\",\n detached: !windows,\n shell: windows && command === \"npm.cmd\",\n });\n const done = new Promise<number | null>((resolve) => {\n child.once(\"error\", (error) => {\n console.error(errorMessage(error));\n resolve(1);\n });\n child.once(\"close\", resolve);\n });\n return { child, done };\n}\n\nfunction snapshot() {\n const files = new Map<string, string | null>();\n function collect(path: string) {\n if (excluded(path) || files.has(path)) return;\n try {\n const stat = lstatSync(path, { bigint: true });\n if (stat.isDirectory()) {\n files.set(path, \"directory\");\n for (const name of readdirSync(path)) collect(join(path, name));\n } else {\n // Compare metadata without reading potentially large datasets or following symlinks.\n files.set(path, [stat.dev, stat.ino, stat.size, stat.mtimeNs, stat.ctimeNs].join(\":\"));\n }\n } catch (error) {\n if (errorCode(error) !== \"ENOENT\" && errorCode(error) !== \"ENOTDIR\") throw error;\n files.set(path, null);\n }\n }\n for (const path of selected) collect(path);\n return files;\n}\n\nfunction equal(left: Map<string, string | null>, right: Map<string, string | null>) {\n return left.size === right.size && [...left].every(([path, value]) => right.get(path) === value);\n}\n\nfunction refreshWatchers() {\n const directories = new Map<string, boolean>();\n const add = (directory: string, recursive: boolean) => {\n directories.set(directory, recursive || directories.get(directory) || false);\n };\n for (const path of selected) {\n if (excluded(path)) continue;\n if (lstatSync(path, { throwIfNoEntry: false })?.isDirectory()) add(path, true);\n // Watch the parent too, so deleted files and folders can be restored.\n let parent = dirname(path);\n while (!existsSync(parent)) parent = dirname(parent);\n add(parent, parent !== dirname(path));\n }\n for (const [directory, state] of watchers) {\n if (directories.get(directory) !== state.recursive) {\n state.watcher.close();\n watchers.delete(directory);\n }\n }\n for (const [directory, recursive] of directories) {\n if (watchers.has(directory)) continue;\n const watcher = watch(directory, { recursive }, (_event, name) => {\n if (checking || closing) return;\n const changed = name && resolve(directory, name.toString());\n if (\n !changed ||\n (!excluded(changed) &&\n selected.some((path) => within(changed, path) || within(path, changed)))\n )\n schedule();\n });\n watcher.on(\"error\", fail);\n watchers.set(directory, { watcher, recursive });\n }\n}\n\nasync function stop(job: Job | undefined) {\n if (!job?.child.pid) return;\n const pid = job.child.pid;\n if (windows) {\n if (job.child.exitCode === null && job.child.signalCode === null) {\n spawnSync(\"taskkill\", [\"/pid\", String(job.child.pid), \"/T\", \"/F\"], { stdio: \"ignore\" });\n }\n await job.done;\n return;\n }\n const signal = (name: NodeJS.Signals | 0) => {\n try {\n process.kill(-pid, name);\n return true;\n } catch (error) {\n if (errorCode(error) !== \"ESRCH\") throw error;\n return false;\n }\n };\n signal(\"SIGTERM\");\n // The direct child can exit first; retain the grace period for its entire process group.\n const deadline = performance.now() + 1000;\n while (signal(0)) {\n if (performance.now() >= deadline) {\n signal(\"SIGKILL\");\n break;\n }\n await delay(25);\n }\n await job.done;\n}\n\nasync function check() {\n if (closing || checking) return;\n if (!needsCheck && equal(contents, snapshot())) return;\n checking = true;\n needsCheck = false;\n await stop(analysis);\n analysis = undefined;\n if (closing) return;\n refreshWatchers();\n contents = snapshot();\n process.stdout.write(\"\\u001b[2J\\u001b[3J\\u001b[H\");\n console.log(\"Fixing and checking...\");\n fixer = launch([\"run\", \"fix\"], bun ? process.execPath : windows ? \"npm.cmd\" : \"npm\");\n const fixed = await fixer.done;\n if (closing) return;\n const current = snapshot();\n // Recheck edits made during fixes; ignore delayed events for unchanged file states.\n needsCheck = !equal(contents, current);\n contents = current;\n refreshWatchers();\n fixer = undefined;\n checking = false;\n if (needsCheck) {\n schedule();\n } else if (fixed === 0) {\n console.log(\"Running analysis...\");\n analysis = launch(bun ? [\"run\", entry] : [\"--env-file=.env\", entry]);\n } else {\n console.log(\"Fix failed. Watching for changes...\");\n }\n}\n\nfunction schedule() {\n clearTimeout(timer);\n timer = setTimeout(() => check().catch(fail), 0);\n}\n\nasync function shutdown(code: number) {\n if (closing) return;\n closing = true;\n clearTimeout(timer);\n for (const { watcher } of watchers.values()) watcher.close();\n await Promise.all([stop(fixer), stop(analysis)]);\n releaseLock?.();\n process.exit(code);\n}\n\nfunction errorCode(error: unknown) {\n return error instanceof Error && \"code\" in error ? error.code : undefined;\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction fail(error: unknown) {\n console.error(errorMessage(error));\n void shutdown(1);\n}\n\nprocess.on(\"SIGINT\", () => void shutdown(0));\nprocess.on(\"SIGTERM\", () => void shutdown(0));\n\nasync function runOnce() {\n console.log(\"Fixing and checking...\");\n fixer = launch([\"run\", \"fix\"], bun ? process.execPath : windows ? \"npm.cmd\" : \"npm\");\n const fixed = await fixer.done;\n if (closing) return;\n if (fixed !== 0) {\n await shutdown(fixed ?? 1);\n return;\n }\n await stop(fixer);\n fixer = undefined;\n if (closing) return;\n console.log(\"Running analysis...\");\n analysis = launch(bun ? [\"run\", entry] : [\"--env-file=.env\", entry]);\n const result = await analysis.done;\n await shutdown(result ?? 1);\n}\n\ntry {\n releaseLock = await acquireSdaLock(runCommand);\n if (closing) releaseLock();\n else if (watching) {\n refreshWatchers();\n void check().catch(fail);\n } else {\n void runOnce().catch(fail);\n }\n} catch (error) {\n fail(new Error(\"Cannot start \" + runCommand + \": \" + errorMessage(error)));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sda.mjs","names":["errorCode","delay","errorCode","delay"],"sources":["../src/helpers/sdaLock.ts","../src/helpers/sdaStatus.ts","../src/sda.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n realpathSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { isObject } from \"./jsonObject.ts\";\n\nexport const SDA_PID_FILE = \"sda/.sda.pid\";\nexport const SDA_LOCK_DIRECTORY = \"sda/.sda-lock\";\n\ntype Claim = { id: string; pid: number; ticket: number; command?: string };\n\nfunction errorCode(error: unknown) {\n return error instanceof Error && \"code\" in error ? error.code : undefined;\n}\n\n// Bakery ordering: publish a unique claim before choosing a ticket, then wait for\n// concurrent ticket choices. Never replace/delete a shared lock during recovery.\n// https://www.microsoft.com/en-us/research/publication/new-solution-dijkstras-concurrent-programming-problem/\nexport async function acquireSdaLock(command: string): Promise<() => void> {\n const directory = resolve(SDA_LOCK_DIRECTORY);\n const pidFile = resolve(SDA_PID_FILE);\n const id = `${process.pid}-${randomUUID()}`;\n const ownDirectory = join(directory, id);\n mkdirSync(directory, { recursive: true });\n mkdirSync(ownDirectory);\n let ownsPid = false;\n const release = () => {\n if (ownsPid) {\n // Remove the informational PID before releasing ownership to the next run.\n rmSync(pidFile, { force: true });\n ownsPid = false;\n }\n rmSync(ownDirectory, { recursive: true, force: true });\n process.removeListener(\"exit\", release);\n };\n process.once(\"exit\", release);\n\n function readClaim(candidate: string): Claim | undefined {\n const match = /^(\\d+)-[\\da-f-]{36}$/.exec(candidate);\n if (!match) return;\n const pid = Number(match[1]);\n if (!Number.isInteger(pid) || pid <= 0 || pid > 2147483647) return;\n const path = join(directory, candidate);\n try {\n process.kill(pid, 0);\n } catch (error) {\n if (errorCode(error) !== \"ESRCH\") throw error;\n // Claim names are never reused, so another starter cannot acquire this path.\n rmSync(path, { recursive: true, force: true });\n return;\n }\n let record: unknown;\n try {\n record = JSON.parse(readFileSync(join(path, \"owner.json\"), \"utf8\"));\n } catch (error) {\n if (errorCode(error) !== \"ENOENT\") throw error;\n // A directory without a published ticket is still choosing, or has exited.\n return existsSync(path) ? { id: candidate, pid, ticket: 0 } : undefined;\n }\n if (\n !isObject(record) ||\n typeof record.ticket !== \"number\" ||\n !Number.isSafeInteger(record.ticket) ||\n record.ticket < 1 ||\n typeof record.command !== \"string\"\n )\n throw new Error(`Cannot read the SDA lock owned by process ${pid}.`);\n return { id: candidate, pid, ticket: record.ticket, command: record.command };\n }\n\n try {\n let ticket = 1;\n for (const candidate of readdirSync(directory)) {\n const claim = readClaim(candidate);\n if (claim) ticket = Math.max(ticket, claim.ticket + 1);\n }\n writeFileSync(\n join(ownDirectory, \"owner.tmp\"),\n JSON.stringify({ ticket, command, projectRoot: realpathSync(process.cwd()) }),\n );\n renameSync(join(ownDirectory, \"owner.tmp\"), join(ownDirectory, \"owner.json\"));\n const deadline = performance.now() + 5000;\n for (const candidate of readdirSync(directory)) {\n if (candidate === id) continue;\n let claim = readClaim(candidate);\n while (claim?.ticket === 0) {\n if (performance.now() >= deadline)\n throw new Error(\n `Another SDA command is still starting (PID ${claim.pid}). Wait for it to finish starting, then try again.`,\n );\n await delay(10);\n claim = readClaim(candidate);\n }\n if (claim && (claim.ticket < ticket || (claim.ticket === ticket && claim.id < id)))\n throw new Error(\n `${claim.command} is already running${claim.command?.endsWith(\"sda:watch\") ? \" and watching this project's files\" : \" an analysis for this project\"} (PID ${claim.pid}). Wait for it to finish or stop it with Ctrl+C in its terminal, then try again.`,\n );\n }\n // Only the winner touches the shared PID file, including stale-file recovery.\n writeFileSync(pidFile, String(process.pid) + \"\\n\");\n ownsPid = true;\n return release;\n } catch (error) {\n release();\n throw error;\n }\n}\n","import { execFileSync } from \"node:child_process\";\nimport { readFileSync, readdirSync, realpathSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isObject } from \"./jsonObject.ts\";\nimport { SDA_LOCK_DIRECTORY, SDA_PID_FILE } from \"./sdaLock.ts\";\n\nfunction errorCode(error: unknown) {\n return error instanceof Error && \"code\" in error ? error.code : undefined;\n}\n\n// Status is read-only: a missing or dead owner is ignored, never removed.\nexport function printSdaStatus(): number {\n const run = `${process.versions.bun ? \"bun\" : \"npm\"} run`;\n const retry = `${run} sda:status`;\n try {\n const pids = new Set<number>();\n const claims = new Map<number, string[]>();\n try {\n for (const name of readdirSync(SDA_LOCK_DIRECTORY)) {\n const match = /^(\\d+)-[\\da-f-]{36}$/.exec(name);\n if (match) {\n const pid = Number(match[1]);\n pids.add(pid);\n claims.set(pid, [...(claims.get(pid) ?? []), name]);\n }\n }\n } catch (error) {\n if (errorCode(error) !== \"ENOENT\") throw error;\n }\n try {\n const value = readFileSync(SDA_PID_FILE, \"utf8\").trim();\n if (!/^\\d+$/.test(value)) throw new Error(\"The SDA PID file is invalid.\");\n pids.add(Number(value));\n } catch (error) {\n if (errorCode(error) !== \"ENOENT\") throw error;\n }\n const messages: string[] = [];\n for (const pid of pids) {\n if (!Number.isInteger(pid) || pid <= 0 || pid > 2147483647)\n throw new Error(\"The recorded SDA PID is invalid.\");\n try {\n process.kill(pid, 0);\n } catch (error) {\n if (errorCode(error) === \"ESRCH\") continue;\n throw error;\n }\n let command: string;\n if (process.platform === \"win32\") {\n const owners = claims.get(pid) ?? [];\n if (owners.length !== 1) throw new Error(`PID ${pid} has no unambiguous SDA owner record.`);\n const owner: unknown = JSON.parse(\n readFileSync(join(SDA_LOCK_DIRECTORY, owners[0], \"owner.json\"), \"utf8\"),\n );\n // WMI has no readable cwd. This is the claim's recorded project association,\n // not proof of the live process's cwd or protection against PID reuse.\n if (\n !isObject(owner) ||\n typeof owner.projectRoot !== \"string\" ||\n realpathSync(owner.projectRoot) !== realpathSync(process.cwd())\n )\n throw new Error(`PID ${pid} could not be verified as this project's SDA process.`);\n const result: unknown = JSON.parse(\n execFileSync(\n \"powershell.exe\",\n [\n \"-NoLogo\",\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-Command\",\n \"[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false); \" +\n `(Get-CimInstance Win32_Process -Filter 'ProcessId = ${pid}' -ErrorAction Stop).CommandLine | ConvertTo-Json -Compress`,\n ],\n {\n encoding: \"utf8\",\n timeout: 5000,\n maxBuffer: 64 * 1024,\n windowsHide: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n },\n ),\n );\n if (typeof result !== \"string\" || !result.trim())\n throw new Error(`PID ${pid} has no readable command line.`);\n command = result;\n } else if (process.platform === \"darwin\" || process.platform === \"linux\") {\n command = execFileSync(\"ps\", [\"-p\", String(pid), \"-o\", \"command=\"], {\n encoding: \"utf8\",\n timeout: 5000,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n }).trim();\n const cwd =\n process.platform === \"linux\"\n ? realpathSync(`/proc/${pid}/cwd`)\n : execFileSync(\"lsof\", [\"-a\", \"-p\", String(pid), \"-d\", \"cwd\", \"-Fn\"], {\n encoding: \"utf8\",\n timeout: 5000,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n })\n .split(\"\\n\")\n .find((line) => line.startsWith(\"n\"))\n ?.slice(1);\n if (!cwd || realpathSync(cwd) !== realpathSync(process.cwd()))\n throw new Error(`PID ${pid} could not be verified as this project's SDA process.`);\n } else {\n throw new Error(\"Active SDA processes cannot be verified on this platform.\");\n }\n const executable = process.argv[1];\n if (\n !executable ||\n (!command.includes(executable) &&\n !command.includes(realpathSync(executable)) &&\n !/(?:[\\\\/]@nshiab[\\\\/]setup-data-project[\\\\/]dist[\\\\/]sda\\.mjs|[\\\\/]node_modules[\\\\/]\\.bin[\\\\/]sda-run)(?:[\"\\s]|$)/.test(\n command,\n ))\n )\n throw new Error(`PID ${pid} could not be verified as this project's SDA process.`);\n messages.push(\n /(?:^|[\"\\s])--watch(?:[\"\\s]|$)/.test(command)\n ? `SDA watcher is running (${run} sda:watch, PID ${pid}). It automatically fixes files and reruns the analysis. If you are an agent, ask the user to stop it with Ctrl+C, then recheck with ${retry} before doing any work.`\n : `SDA analysis is running (${run} sda, PID ${pid}). Wait for it to finish. Recheck with ${retry} in 30 seconds before doing any work.`,\n );\n }\n for (const message of messages) console.log(message);\n if (messages.length) return 1;\n console.log(\"No active SDA process found. You can proceed.\");\n return 0;\n } catch (error) {\n console.error(\n `Unable to verify SDA status: ${error instanceof Error ? error.message : String(error)} If you are an agent, ask the user to confirm that neither ${run} sda nor ${run} sda:watch is running and that you may proceed, then wait for their confirmation before doing any work.`,\n );\n return 2;\n }\n}\n","#!/usr/bin/env node\nimport { existsSync, lstatSync, type FSWatcher, readdirSync, watch } from \"node:fs\";\nimport { spawn, spawnSync, type ChildProcess } from \"node:child_process\";\nimport { dirname, join, resolve, sep } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { parseArgs } from \"node:util\";\nimport { acquireSdaLock, SDA_PID_FILE, SDA_LOCK_DIRECTORY } from \"./helpers/sdaLock.ts\";\nimport { printSdaStatus } from \"./helpers/sdaStatus.ts\";\n\nconst {\n positionals: [entry, ...paths],\n values,\n} = parseArgs({\n allowPositionals: true,\n options: {\n status: { type: \"boolean\", default: false },\n watch: { type: \"boolean\", default: false },\n ignore: { type: \"string\", multiple: true, default: [] },\n },\n});\nif (values.status) process.exit(printSdaStatus());\nif (!entry) {\n console.error(\n \"Usage: sda-run --status | [--watch] <entry-file> [watch-paths...] [--ignore path]\",\n );\n process.exit(1);\n}\nconst watching = values.watch;\nconst selected = [entry, ...paths].map((path) => resolve(path));\nconst ignored = [SDA_PID_FILE, SDA_LOCK_DIRECTORY, ...values.ignore].map((path) => resolve(path));\nconst within = (path: string, root: string) => path === root || path.startsWith(root + sep);\nconst excluded = (path: string) => ignored.some((root) => within(path, root));\nconst bun = Boolean(process.versions.bun);\nconst runCommand = (bun ? \"bun run \" : \"npm run \") + (watching ? \"sda:watch\" : \"sda\");\nconst windows = process.platform === \"win32\";\ntype Job = { child: ChildProcess; done: Promise<number | null> };\nlet releaseLock: (() => void) | undefined;\nlet fixer: Job | undefined;\nlet analysis: Job | undefined;\nlet timer: ReturnType<typeof setTimeout> | undefined;\nlet checking = false;\nlet closing = false;\nlet needsCheck = true;\nlet contents = new Map<string, string | null>();\nconst watchers = new Map<string, { watcher: FSWatcher; recursive: boolean }>();\n\nfunction launch(args: string[], command = process.execPath) {\n const child = spawn(command, args, {\n // Bun's Windows --bun shim is named node.exe; keep Bun CLI argument parsing.\n argv0: windows && bun && command === process.execPath ? \"bun\" : undefined,\n stdio: \"inherit\",\n detached: !windows,\n shell: windows && command === \"npm.cmd\",\n });\n const done = new Promise<number | null>((resolve) => {\n child.once(\"error\", (error) => {\n console.error(errorMessage(error));\n resolve(1);\n });\n child.once(\"close\", resolve);\n });\n return { child, done };\n}\n\nfunction snapshot() {\n const files = new Map<string, string | null>();\n function collect(path: string) {\n if (excluded(path) || files.has(path)) return;\n try {\n const stat = lstatSync(path, { bigint: true });\n if (stat.isDirectory()) {\n files.set(path, \"directory\");\n for (const name of readdirSync(path)) collect(join(path, name));\n } else {\n // Compare metadata without reading potentially large datasets or following symlinks.\n files.set(path, [stat.dev, stat.ino, stat.size, stat.mtimeNs, stat.ctimeNs].join(\":\"));\n }\n } catch (error) {\n if (errorCode(error) !== \"ENOENT\" && errorCode(error) !== \"ENOTDIR\") throw error;\n files.set(path, null);\n }\n }\n for (const path of selected) collect(path);\n return files;\n}\n\nfunction equal(left: Map<string, string | null>, right: Map<string, string | null>) {\n return left.size === right.size && [...left].every(([path, value]) => right.get(path) === value);\n}\n\nfunction refreshWatchers() {\n const directories = new Map<string, boolean>();\n const add = (directory: string, recursive: boolean) => {\n directories.set(directory, recursive || directories.get(directory) || false);\n };\n for (const path of selected) {\n if (excluded(path)) continue;\n if (lstatSync(path, { throwIfNoEntry: false })?.isDirectory()) add(path, true);\n // Watch the parent too, so deleted files and folders can be restored.\n let parent = dirname(path);\n while (!existsSync(parent)) parent = dirname(parent);\n add(parent, parent !== dirname(path));\n }\n for (const [directory, state] of watchers) {\n if (directories.get(directory) !== state.recursive) {\n state.watcher.close();\n watchers.delete(directory);\n }\n }\n for (const [directory, recursive] of directories) {\n if (watchers.has(directory)) continue;\n const watcher = watch(directory, { recursive }, (_event, name) => {\n if (checking || closing) return;\n const changed = name && resolve(directory, name.toString());\n if (\n !changed ||\n (!excluded(changed) &&\n selected.some((path) => within(changed, path) || within(path, changed)))\n )\n schedule();\n });\n watcher.on(\"error\", fail);\n watchers.set(directory, { watcher, recursive });\n }\n}\n\nasync function stop(job: Job | undefined) {\n if (!job?.child.pid) return;\n const pid = job.child.pid;\n if (windows) {\n if (job.child.exitCode === null && job.child.signalCode === null) {\n spawnSync(\"taskkill\", [\"/pid\", String(job.child.pid), \"/T\", \"/F\"], { stdio: \"ignore\" });\n }\n await job.done;\n return;\n }\n const signal = (name: NodeJS.Signals | 0) => {\n try {\n process.kill(-pid, name);\n return true;\n } catch (error) {\n if (errorCode(error) !== \"ESRCH\") throw error;\n return false;\n }\n };\n signal(\"SIGTERM\");\n // The direct child can exit first; retain the grace period for its entire process group.\n const deadline = performance.now() + 1000;\n while (signal(0)) {\n if (performance.now() >= deadline) {\n signal(\"SIGKILL\");\n break;\n }\n await delay(25);\n }\n await job.done;\n}\n\nasync function check() {\n if (closing || checking) return;\n if (!needsCheck && equal(contents, snapshot())) return;\n checking = true;\n needsCheck = false;\n await stop(analysis);\n analysis = undefined;\n if (closing) return;\n refreshWatchers();\n contents = snapshot();\n process.stdout.write(\"\\u001b[2J\\u001b[3J\\u001b[H\");\n console.log(\"Fixing and checking...\");\n fixer = launch([\"run\", \"fix\"], bun ? process.execPath : windows ? \"npm.cmd\" : \"npm\");\n const fixed = await fixer.done;\n if (closing) return;\n const current = snapshot();\n // Recheck edits made during fixes; ignore delayed events for unchanged file states.\n needsCheck = !equal(contents, current);\n contents = current;\n refreshWatchers();\n fixer = undefined;\n checking = false;\n if (needsCheck) {\n schedule();\n } else if (fixed === 0) {\n console.log(\"Running analysis...\");\n analysis = launch(bun ? [\"run\", entry] : [\"--env-file=.env\", entry]);\n } else {\n console.log(\"Fix failed. Watching for changes...\");\n }\n}\n\nfunction schedule() {\n clearTimeout(timer);\n timer = setTimeout(() => check().catch(fail), 0);\n}\n\nasync function shutdown(code: number) {\n if (closing) return;\n closing = true;\n clearTimeout(timer);\n for (const { watcher } of watchers.values()) watcher.close();\n await Promise.all([stop(fixer), stop(analysis)]);\n releaseLock?.();\n process.exit(code);\n}\n\nfunction errorCode(error: unknown) {\n return error instanceof Error && \"code\" in error ? error.code : undefined;\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction fail(error: unknown) {\n console.error(errorMessage(error));\n void shutdown(1);\n}\n\nprocess.on(\"SIGINT\", () => void shutdown(0));\nprocess.on(\"SIGTERM\", () => void shutdown(0));\n\nasync function runOnce() {\n console.log(\"Fixing and checking...\");\n fixer = launch([\"run\", \"fix\"], bun ? process.execPath : windows ? \"npm.cmd\" : \"npm\");\n const fixed = await fixer.done;\n if (closing) return;\n if (fixed !== 0) {\n await shutdown(fixed ?? 1);\n return;\n }\n await stop(fixer);\n fixer = undefined;\n if (closing) return;\n console.log(\"Running analysis...\");\n analysis = launch(bun ? [\"run\", entry] : [\"--env-file=.env\", entry]);\n const result = await analysis.done;\n await shutdown(result ?? 1);\n}\n\ntry {\n releaseLock = await acquireSdaLock(runCommand);\n if (closing) releaseLock();\n else if (watching) {\n refreshWatchers();\n void check().catch(fail);\n } else {\n void runOnce().catch(fail);\n }\n} catch (error) {\n fail(new Error(\"Cannot start \" + runCommand + \": \" + errorMessage(error)));\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nshiab/setup-data-project",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "Quickly kick off a project using simple-data-analysis-core, simple-data-analysis, and journalism libraries.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "https://github.com/nshiab/setup-data-project",
|