@precisa-saude/cli 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +39 -0
- package/dist/bin.js.map +1 -1
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -1
- package/dist/templates/dotfiles/renovate.json +11 -1
- package/dist/templates/github/workflows/_checks.yml +18 -18
- package/dist/templates/github/workflows/_deploy-site.yml +9 -9
- package/dist/templates/github/workflows/_publish.yml +3 -3
- package/dist/templates/github/workflows/_release.yml +5 -5
- package/dist/templates/github/workflows/doctor.yml +4 -4
- package/dist/templates/github/workflows/publish-tag.yml +3 -3
- package/dist/templates/github/workflows/publish-watch.yml +139 -0
- package/dist/templates/github/workflows/review.yml +4 -4
- package/dist/templates/templates.manifest.yml +5 -0
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -558,6 +558,8 @@ precisa new ${repoName}`));
|
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
// src/commands/sync.ts
|
|
561
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
562
|
+
import { join } from "path";
|
|
561
563
|
import chalk4 from "chalk";
|
|
562
564
|
|
|
563
565
|
// src/lib/diff.ts
|
|
@@ -629,8 +631,45 @@ ${err.message}`));
|
|
|
629
631
|
`${summary.create} create, ${summary.update} update, ${summary.mergeJson} merge-json, ${summary.preserve} preserve, ${summary.skip} skip, ${summary.error} error`
|
|
630
632
|
)
|
|
631
633
|
);
|
|
634
|
+
printPostSyncReminders(cwd, outcomes);
|
|
632
635
|
if (summary.error > 0) process.exit(1);
|
|
633
636
|
}
|
|
637
|
+
function printPostSyncReminders(cwd, outcomes) {
|
|
638
|
+
const touched = outcomes.filter((o) => o.kind === "create" || o.kind === "update").map((o) => o.target);
|
|
639
|
+
const publishYml = join(cwd, ".github/workflows/_publish.yml");
|
|
640
|
+
const hasPublishWorkflow = existsSync5(publishYml);
|
|
641
|
+
const publishReferencesEnv = hasPublishWorkflow && readFileSync5(publishYml, "utf8").includes("environment:") && readFileSync5(publishYml, "utf8").includes("npm-publish");
|
|
642
|
+
const publishTouched = touched.some((t) => t.endsWith("_publish.yml"));
|
|
643
|
+
if (publishReferencesEnv && publishTouched) {
|
|
644
|
+
console.log("");
|
|
645
|
+
console.log(chalk4.bold.yellow("Post-sync \u2014 manual GitHub setup"));
|
|
646
|
+
console.log(
|
|
647
|
+
chalk4.dim(
|
|
648
|
+
" Settings \u2192 Environments \u2192 npm-publish must exist with at least one required reviewer."
|
|
649
|
+
)
|
|
650
|
+
);
|
|
651
|
+
console.log(
|
|
652
|
+
chalk4.dim(
|
|
653
|
+
" Without it the publish step runs unattended. The CLI cannot create environments remotely."
|
|
654
|
+
)
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
const watchTouched = touched.some((t) => t.endsWith("publish-watch.yml"));
|
|
658
|
+
if (watchTouched) {
|
|
659
|
+
console.log("");
|
|
660
|
+
console.log(chalk4.bold.yellow("Post-sync \u2014 publish-watch"));
|
|
661
|
+
console.log(
|
|
662
|
+
chalk4.dim(
|
|
663
|
+
" publish-watch.yml now runs every 15 min. Confirm npm package names in `packages/**` are"
|
|
664
|
+
)
|
|
665
|
+
);
|
|
666
|
+
console.log(
|
|
667
|
+
chalk4.dim(
|
|
668
|
+
" current and that semantic-release tag convention (`<name>@<ver>` or `v<ver>`) matches."
|
|
669
|
+
)
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
634
673
|
function summarize(outcomes) {
|
|
635
674
|
const s = { create: 0, error: 0, mergeJson: 0, preserve: 0, skip: 0, update: 0 };
|
|
636
675
|
for (const o of outcomes) {
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bin.ts","../src/commands/doctor.ts","../src/lib/templates.ts","../src/lib/paths.ts","../src/manifest.ts","../src/commands/new.ts","../src/lib/merge.ts","../src/commands/sync.ts","../src/lib/diff.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\n\nimport { runDoctor } from './commands/doctor.js';\nimport { runNew } from './commands/new.js';\nimport { runSync } from './commands/sync.js';\n\nconst program = new Command();\n\nprogram\n .name('precisa')\n .description('Bootstrap and sync Precisa Saúde repositories.')\n .version('0.0.0');\n\nprogram\n .command('new <repo-name>')\n .description('Scaffold a new repository from the shared templates.')\n .option('--profile <profile>', 'preset: oss-library | oss-site | private-app', 'oss-library')\n .option('--dry-run', 'print what would be written without touching disk', false)\n .option('--non-interactive', 'skip prompts; use --owner/--scopes/etc. flags instead', false)\n .option('--owner <org>', 'GitHub owner (org or user)', 'Precisa-Saude')\n .option(\n '--scopes <csv>',\n 'Comma-separated commit scopes (e.g. \"core,docs,ci,deps\")',\n 'docs,ci,deps',\n )\n .option('--security-email <email>', 'Security contact email', 'security@precisa-saude.com.br')\n .option(\n '--conduct-email <email>',\n 'Code-of-conduct contact email',\n 'conduct@precisa-saude.com.br',\n )\n .action(\n async (\n repoName: string,\n opts: {\n profile: string;\n dryRun: boolean;\n nonInteractive: boolean;\n owner: string;\n scopes: string;\n securityEmail: string;\n conductEmail: string;\n },\n ) => {\n await runNew(repoName, opts);\n },\n );\n\nprogram\n .command('sync')\n .description(\"Re-render templates against this repo's .precisa.json manifest.\")\n .option('--dry-run', 'print a diff without writing', false)\n .action(async (opts: { dryRun: boolean }) => {\n await runSync(opts);\n });\n\nprogram\n .command('doctor')\n .description('Audit this repo against the templates and report drift.')\n .action(async () => {\n await runDoctor();\n });\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n console.error(err);\n process.exit(1);\n});\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport chalk from 'chalk';\n\nimport {\n loadTemplateManifest,\n readTemplateSource,\n renderTokens,\n type TemplateEntry,\n} from '../lib/templates.js';\nimport { isRequired, loadManifest, tokenContext } from '../manifest.js';\n\ntype Severity = 'ok' | 'info' | 'warning' | 'error';\n\ninterface DriftReport {\n message: string;\n severity: Severity;\n target: string;\n}\n\nexport async function runDoctor(): Promise<void> {\n const cwd = process.cwd();\n console.log(chalk.bold.cyan('\\nprecisa doctor'));\n\n let manifest;\n try {\n manifest = loadManifest(cwd);\n } catch (err) {\n console.error(chalk.red(`\\n${(err as Error).message}`));\n process.exit(1);\n }\n\n const entries = loadTemplateManifest();\n const context = tokenContext(manifest);\n\n const reports: DriftReport[] = [];\n\n for (const entry of entries) {\n const required = isRequired(entry.required_when, manifest);\n const targetPath = resolve(cwd, entry.target);\n const exists = existsSync(targetPath);\n\n if (!required && !exists) continue;\n if (!required && exists) {\n reports.push({\n message: `Present but not required by the manifest profile (ok)`,\n severity: 'info',\n target: entry.target,\n });\n continue;\n }\n if (!exists) {\n reports.push({\n message: 'Missing',\n severity: 'error',\n target: entry.target,\n });\n continue;\n }\n\n // Exists + required — compare to rendered template\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n const current = readFileSync(targetPath, 'utf-8');\n reports.push(compareContent(entry, current, rendered));\n }\n\n console.log('');\n let errors = 0;\n let warnings = 0;\n let infos = 0;\n let oks = 0;\n\n for (const r of reports) {\n const icon = iconFor(r.severity);\n const line = `${icon} ${r.target}${r.message ? chalk.dim(` — ${r.message}`) : ''}`;\n console.log(line);\n if (r.severity === 'error') errors += 1;\n else if (r.severity === 'warning') warnings += 1;\n else if (r.severity === 'info') infos += 1;\n else oks += 1;\n }\n\n console.log('');\n console.log(chalk.dim(`${oks} ok, ${warnings} warning, ${errors} error, ${infos} info`));\n\n if (errors > 0) process.exit(1);\n}\n\nfunction compareContent(entry: TemplateEntry, current: string, rendered: string): DriftReport {\n if (current === rendered) {\n return { message: '', severity: 'ok', target: entry.target };\n }\n\n // Non-overwrite strategies don't re-render on sync — treat drift as\n // informational, not a warning. Makes the doctor output scannable:\n // warnings are the files sync WOULD change; infos are files where\n // drift is intentional (customized scaffold, preserved docs).\n if (entry.merge_strategy === 'preserve') {\n return {\n message: 'Differs from template (preserve strategy — suggestion only)',\n severity: 'info',\n target: entry.target,\n };\n }\n if (entry.merge_strategy === 'skip_if_exists') {\n return {\n message: 'Differs from template (scaffold-only; sync will not overwrite)',\n severity: 'info',\n target: entry.target,\n };\n }\n\n return {\n message: 'Differs from template (run `precisa sync` to update)',\n severity: 'warning',\n target: entry.target,\n };\n}\n\nfunction iconFor(severity: Severity): string {\n switch (severity) {\n case 'ok':\n return chalk.green('✓');\n case 'info':\n return chalk.blue('i');\n case 'warning':\n return chalk.yellow('!');\n case 'error':\n return chalk.red('✗');\n }\n}\n","import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { parse as parseYaml } from 'yaml';\n\nimport type { RequiredWhen } from '../manifest.js';\nimport { resolveTemplatesDir } from './paths.js';\n\nexport type MergeStrategy = 'overwrite' | 'merge_json' | 'preserve' | 'skip_if_exists';\n\nexport interface TemplateEntry {\n /** Whether to mark the rendered file executable (chmod +x). */\n executable?: boolean;\n /** How to merge when the target already exists. */\n merge_strategy: MergeStrategy;\n /** Gate for inclusion. */\n required_when: RequiredWhen;\n /** Path relative to templates/. */\n source: string;\n /** Path in the target repo (relative to the repo root). */\n target: string;\n}\n\ninterface TemplateManifestFile {\n templates: TemplateEntry[];\n}\n\n/**\n * Load the `templates.manifest.yml` from the bundled templates directory.\n * Throws if the file is missing or the shape is wrong.\n */\nexport function loadTemplateManifest(): TemplateEntry[] {\n const dir = resolveTemplatesDir();\n const manifestPath = resolve(dir, 'templates.manifest.yml');\n const raw = readFileSync(manifestPath, 'utf-8');\n const parsed = parseYaml(raw) as TemplateManifestFile | undefined;\n if (!parsed || !Array.isArray(parsed.templates)) {\n throw new Error(`${manifestPath}: expected { templates: [...] } at root`);\n }\n for (const [i, t] of parsed.templates.entries()) {\n if (!t.source || !t.target) {\n throw new Error(`${manifestPath}: entry ${i} is missing source or target`);\n }\n }\n return parsed.templates;\n}\n\nexport function readTemplateSource(entry: TemplateEntry): string {\n const dir = resolveTemplatesDir();\n const path = resolve(dir, entry.source);\n return readFileSync(path, 'utf-8');\n}\n\n/**\n * Substitute `{{TOKEN}}` placeholders with values from `context`. Unknown\n * tokens are left untouched (keeps the double braces visible so bad keys\n * are easy to spot in rendered output).\n *\n * Also processes conditional blocks:\n *\n * {{#if HAS_SITE}}\n * ...lines rendered only when HAS_SITE is truthy...\n * {{/if}}\n *\n * Markers can appear inside a host-language comment so the template stays\n * parseable by syntax-aware tools (prettier on YAML, for example):\n *\n * # {{#if HAS_SITE}}\n * ...\n * # {{/if}}\n *\n * A token is \"truthy\" when its string value is non-empty and not `\"false\"`.\n * Blocks may nest; they are expanded before token substitution so a block's\n * body can itself reference tokens.\n */\nexport function renderTokens(source: string, context: Record<string, string>): string {\n return renderTokenSubstitutions(renderConditionalBlocks(source, context), context);\n}\n\nfunction renderTokenSubstitutions(source: string, context: Record<string, string>): string {\n return source.replace(/\\{\\{([A-Z_]+)\\}\\}/g, (match, token: string) => {\n return Object.prototype.hasOwnProperty.call(context, token) ? context[token]! : match;\n });\n}\n\nfunction renderConditionalBlocks(source: string, context: Record<string, string>): string {\n // Match an entire line containing `{{#if TOKEN}}` (possibly wrapped in a\n // host-language comment like `# {{#if TOKEN}}` or `// {{#if TOKEN}}`),\n // up through the matching `{{/if}}` line. The whole marker line is\n // consumed so commented-out markers don't leak into rendered output.\n const pattern =\n /^[ \\t]*[^\\S\\n]*[^\\n]*\\{\\{#if ([A-Z_]+)\\}\\}[^\\n]*\\n([\\s\\S]*?)^[ \\t]*[^\\n]*\\{\\{\\/if\\}\\}[^\\n]*\\n?/gm;\n let prev: string;\n let out = source;\n // Re-run to handle nested blocks. Simple fixed-point loop keeps the\n // replacement rules uniform.\n do {\n prev = out;\n out = out.replace(pattern, (_match, token: string, body: string) => {\n const value = context[token];\n const truthy = value !== undefined && value !== '' && value !== 'false';\n return truthy ? body : '';\n });\n } while (out !== prev);\n return out;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Locate the bundled `templates/` directory.\n *\n * When published to npm, the templates live at `dist/templates/` inside\n * the CLI package (copied by `scripts/copy-templates.mjs` during build).\n *\n * When running from the monorepo (e.g. `pnpm --filter @precisa-saude/cli dev`),\n * the templates live at the repo root — fall back to walking up from the\n * package directory.\n */\nexport function resolveTemplatesDir(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n\n // Published case: cli package's dist/templates\n const bundled = resolve(here, 'templates');\n if (existsSync(bundled)) return bundled;\n\n // Dev case: walk up from packages/cli/{src|dist} to the monorepo root\n const repoRoot = resolve(here, '..', '..', '..', '..');\n const repoTemplates = resolve(repoRoot, 'templates');\n if (existsSync(repoTemplates)) return repoTemplates;\n\n // Sibling-in-package case (tsup output): packages/cli/dist -> ../../templates\n const packageParent = resolve(here, '..', '..', 'templates');\n if (existsSync(packageParent)) return packageParent;\n\n throw new Error(\n `Could not locate templates/ directory. Searched:\\n ${bundled}\\n ${repoTemplates}\\n ${packageParent}`,\n );\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\n/**\n * `.precisa.json` manifest — sits at the root of every consumer repo and\n * declares the repo's profile so `precisa sync` and `precisa doctor` know\n * which templates to render and which rules to enforce.\n */\nexport interface PrecisaManifest {\n /** Commitlint scope enum for this repo. */\n commitScopes: string[];\n\n /** Contact emails used in governance doc templates. */\n contactEmails: {\n security: string;\n conduct: string;\n };\n\n /** Does this repo have publishable packages/*? */\n hasPackages: boolean;\n\n /** Does this repo ship a website? Controls preview-deploy workflows. */\n hasSite: boolean;\n\n /** Repository name (typically matches the GitHub repo name). */\n name: string;\n\n /** Pinned runtime versions. Default: node=22, pnpm=9.15.9. */\n nodeVersion?: string;\n\n /** GitHub organization or user that owns the repo (e.g. `Precisa-Saude`). */\n owner: string;\n\n pnpmVersion?: string;\n\n /** Publishes any workspace package to npm? */\n publishesToNpm: boolean;\n\n /**\n * Workspace package directories (relative to repo root) that the\n * `publish` job in `ci.yml` should pass to `_publish.yml`. Only read\n * when `publishesToNpm: true`. Example: `[\"packages/core\", \"packages/cli\"]`.\n */\n publishPackages?: string[];\n\n /** Schema version of this manifest file. Bump when the schema changes. */\n schemaVersion: 1;\n\n /**\n * pnpm filter selector for the site package, passed to the deploy\n * workflow. Only read when `hasSite: true`. Example: `@my-repo/site`.\n */\n siteFilter?: string;\n\n /**\n * Cloudflare Pages project name for the deploy-site workflow. Only\n * read when `hasSite: true`.\n */\n siteProjectName?: string;\n\n /**\n * Path prefix (relative to repo root, trailing slash) treated as site\n * source for change detection in `_deploy-site.yml`. Defaults to\n * `site/` — override to `packages/site/` for monorepos where the site\n * lives under `packages/`.\n */\n siteSourcePath?: string;\n\n /** Public-OSS or private-internal. Controls which templates are rendered. */\n visibility: 'oss' | 'private';\n}\n\nexport const MANIFEST_FILENAME = '.precisa.json';\n\nexport const DEFAULT_MANIFEST_FIELDS = {\n hasPackages: true,\n hasSite: false,\n nodeVersion: '22',\n pnpmVersion: '9.15.9',\n publishesToNpm: true,\n schemaVersion: 1 as const,\n visibility: 'oss' as const,\n};\n\n/** Template gate values — `required_when` in templates.manifest.yml. */\nexport type RequiredWhen =\n | 'always'\n | 'never'\n | 'oss'\n | 'private'\n | 'has_site'\n | 'has_packages'\n | 'publishes_to_npm';\n\n/** Returns true when a template's `required_when` gate applies to this manifest. */\nexport function isRequired(when: RequiredWhen, manifest: PrecisaManifest): boolean {\n switch (when) {\n case 'always':\n return true;\n case 'never':\n return false;\n case 'oss':\n return manifest.visibility === 'oss';\n case 'private':\n return manifest.visibility === 'private';\n case 'has_site':\n return manifest.hasSite;\n case 'has_packages':\n return manifest.hasPackages;\n case 'publishes_to_npm':\n return manifest.publishesToNpm;\n default:\n return true;\n }\n}\n\n/**\n * Build the token substitution map from a manifest. Keys are `{{TOKEN}}`\n * (without braces); values are always strings.\n */\nexport function tokenContext(manifest: PrecisaManifest): Record<string, string> {\n return {\n COMMIT_SCOPES: manifest.commitScopes.join(','),\n // For human-readable docs (AGENTS.md, README) — backticked list.\n COMMIT_SCOPES_HUMAN: manifest.commitScopes.map((s) => `\\`${s}\\``).join(', '),\n // For `.commitlintrc.cjs` — scope array spelled as JS string literals,\n // ready to drop inside `[ ... ]`.\n COMMIT_SCOPES_JSON: manifest.commitScopes.map((s) => `'${s}'`).join(', '),\n CONDUCT_EMAIL: manifest.contactEmails.conduct,\n HAS_PACKAGES: String(manifest.hasPackages),\n HAS_SITE: String(manifest.hasSite),\n NODE_VERSION: manifest.nodeVersion ?? '22',\n OWNER_ORG: manifest.owner,\n PNPM_VERSION: manifest.pnpmVersion ?? '9.15.9',\n // YAML block-scalar body for the `packages: |` input of `_publish.yml`.\n // The template provides the first entry's indent; subsequent entries\n // get 8 spaces explicitly to match. Empty when no packages declared.\n PUBLISH_PACKAGES_YAML: (manifest.publishPackages ?? []).join('\\n '),\n PUBLISHES_TO_NPM: String(manifest.publishesToNpm),\n REPO_NAME: manifest.name,\n REPO_SLUG: `${manifest.owner}/${manifest.name}`,\n SECURITY_EMAIL: manifest.contactEmails.security,\n SITE_FILTER: manifest.siteFilter ?? '',\n SITE_PROJECT_NAME: manifest.siteProjectName ?? '',\n SITE_SOURCE_PATH: manifest.siteSourcePath ?? 'site/',\n VISIBILITY: manifest.visibility,\n };\n}\n\nexport interface ManifestValidationError {\n message: string;\n path: string;\n}\n\nexport function validateManifest(raw: unknown): ManifestValidationError[] {\n const errors: ManifestValidationError[] = [];\n const m = raw as Partial<PrecisaManifest> | undefined;\n if (!m || typeof m !== 'object') {\n return [{ message: 'manifest must be a JSON object', path: '$' }];\n }\n if (m.schemaVersion !== 1) {\n errors.push({ message: 'must be 1', path: 'schemaVersion' });\n }\n if (typeof m.name !== 'string' || !m.name) {\n errors.push({ message: 'must be a non-empty string', path: 'name' });\n }\n if (typeof m.owner !== 'string' || !m.owner) {\n errors.push({ message: 'must be a non-empty string', path: 'owner' });\n }\n if (m.visibility !== 'oss' && m.visibility !== 'private') {\n errors.push({ message: \"must be 'oss' or 'private'\", path: 'visibility' });\n }\n for (const key of ['hasSite', 'hasPackages', 'publishesToNpm'] as const) {\n if (typeof m[key] !== 'boolean') {\n errors.push({ message: 'must be a boolean', path: key });\n }\n }\n if (!Array.isArray(m.commitScopes)) {\n errors.push({ message: 'must be an array of strings', path: 'commitScopes' });\n }\n if (m.publishPackages !== undefined) {\n if (!Array.isArray(m.publishPackages)) {\n errors.push({ message: 'must be an array of strings', path: 'publishPackages' });\n } else if (m.publishPackages.some((p) => typeof p !== 'string' || !p)) {\n errors.push({ message: 'entries must be non-empty strings', path: 'publishPackages' });\n }\n }\n if (m.publishesToNpm) {\n if (!Array.isArray(m.publishPackages) || m.publishPackages.length === 0) {\n errors.push({\n message: 'must have at least one entry when publishesToNpm is true',\n path: 'publishPackages',\n });\n }\n }\n if (m.hasSite === true) {\n for (const key of ['siteProjectName', 'siteFilter'] as const) {\n if (typeof m[key] !== 'string' || !m[key]) {\n errors.push({ message: 'required and non-empty when hasSite is true', path: key });\n }\n }\n }\n if (m.siteProjectName !== undefined && typeof m.siteProjectName !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteProjectName' });\n }\n if (m.siteFilter !== undefined && typeof m.siteFilter !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteFilter' });\n }\n if (m.siteSourcePath !== undefined && typeof m.siteSourcePath !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteSourcePath' });\n }\n if (!m.contactEmails || typeof m.contactEmails !== 'object') {\n errors.push({ message: 'must be an object', path: 'contactEmails' });\n } else {\n for (const key of ['security', 'conduct'] as const) {\n if (typeof m.contactEmails[key] !== 'string' || !m.contactEmails[key]) {\n errors.push({\n message: 'must be a non-empty string',\n path: `contactEmails.${key}`,\n });\n }\n }\n }\n return errors;\n}\n\nexport function loadManifest(cwd: string): PrecisaManifest {\n const path = resolve(cwd, MANIFEST_FILENAME);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, 'utf-8'));\n } catch (err) {\n throw new Error(`Failed to read ${MANIFEST_FILENAME} at ${path}: ${(err as Error).message}`);\n }\n const errors = validateManifest(raw);\n if (errors.length > 0) {\n const detail = errors.map((e) => ` - ${e.path}: ${e.message}`).join('\\n');\n throw new Error(`Invalid ${MANIFEST_FILENAME}:\\n${detail}`);\n }\n return raw as PrecisaManifest;\n}\n\nexport function writeManifest(cwd: string, manifest: PrecisaManifest): void {\n const path = resolve(cwd, MANIFEST_FILENAME);\n writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\\n`);\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport prompts from 'prompts';\n\nimport { applyTemplate } from '../lib/merge.js';\nimport { loadTemplateManifest, readTemplateSource, renderTokens } from '../lib/templates.js';\nimport {\n DEFAULT_MANIFEST_FIELDS,\n isRequired,\n type PrecisaManifest,\n tokenContext,\n writeManifest,\n} from '../manifest.js';\n\nexport interface NewOptions {\n conductEmail?: string;\n dryRun: boolean;\n /** Skip interactive prompts; require --owner/--scopes/--*-email flags. */\n nonInteractive?: boolean;\n owner?: string;\n profile: string;\n /** Comma-separated list, e.g. \"core,docs,ci,deps\". */\n scopes?: string;\n securityEmail?: string;\n}\n\nconst PROFILES = {\n 'oss-library': {\n hasPackages: true,\n hasSite: false,\n publishesToNpm: true,\n visibility: 'oss',\n },\n 'oss-site': {\n hasPackages: false,\n hasSite: true,\n publishesToNpm: false,\n visibility: 'oss',\n },\n 'private-app': {\n hasPackages: true,\n hasSite: true,\n publishesToNpm: false,\n visibility: 'private',\n },\n} as const satisfies Record<\n string,\n Pick<PrecisaManifest, 'visibility' | 'hasSite' | 'hasPackages' | 'publishesToNpm'>\n>;\n\nexport async function runNew(repoName: string, opts: NewOptions): Promise<void> {\n const targetDir = resolve(process.cwd(), repoName);\n\n if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {\n console.error(chalk.red(`\\nError: ${targetDir} already exists and is not empty.`));\n process.exit(1);\n }\n\n const profile = PROFILES[opts.profile as keyof typeof PROFILES];\n if (!profile) {\n console.error(\n chalk.red(`\\nError: unknown profile '${opts.profile}'. Choose one of:`),\n Object.keys(PROFILES).join(', '),\n );\n process.exit(1);\n }\n\n console.log(chalk.bold.cyan(`\\nprecisa new ${repoName}`));\n console.log(chalk.dim(`profile: ${opts.profile}${opts.dryRun ? ' (dry-run)' : ''}`));\n console.log(chalk.dim(`target: ${targetDir}\\n`));\n\n const answers = opts.nonInteractive\n ? {\n commitScopes: (opts.scopes ?? 'docs,ci,deps')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n conductEmail: opts.conductEmail ?? 'conduct@precisa-saude.com.br',\n owner: opts.owner ?? 'Precisa-Saude',\n securityEmail: opts.securityEmail ?? 'security@precisa-saude.com.br',\n }\n : await prompts(\n [\n {\n initial: opts.owner ?? 'Precisa-Saude',\n message: 'GitHub owner (org or user):',\n name: 'owner',\n type: 'text',\n },\n {\n initial: opts.securityEmail ?? 'security@precisa-saude.com.br',\n message: 'Security contact email:',\n name: 'securityEmail',\n type: 'text',\n },\n {\n initial: opts.conductEmail ?? 'conduct@precisa-saude.com.br',\n message: 'Code-of-conduct contact email:',\n name: 'conductEmail',\n type: 'text',\n },\n {\n initial: opts.scopes ?? 'docs,ci,deps',\n message: 'Commit scopes (comma-separated):',\n name: 'commitScopes',\n separator: ',',\n type: 'list',\n },\n ],\n { onCancel: () => process.exit(1) },\n );\n\n const manifest: PrecisaManifest = {\n ...DEFAULT_MANIFEST_FIELDS,\n ...profile,\n commitScopes: answers.commitScopes,\n contactEmails: {\n conduct: answers.conductEmail,\n security: answers.securityEmail,\n },\n name: repoName,\n owner: answers.owner,\n };\n\n const spinner = ora('Rendering templates').start();\n try {\n if (!opts.dryRun) mkdirSync(targetDir, { recursive: true });\n\n const entries = loadTemplateManifest().filter((e) => isRequired(e.required_when, manifest));\n const context = tokenContext(manifest);\n\n let created = 0;\n let skipped = 0;\n\n for (const entry of entries) {\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n const outcome = applyTemplate({\n cwd: targetDir,\n dryRun: opts.dryRun,\n entry,\n rendered,\n });\n if (outcome.kind === 'create') created += 1;\n else if (outcome.kind === 'skip-exists') skipped += 1;\n else if (outcome.kind === 'error') {\n spinner.fail(`Failed on ${entry.target}`);\n console.error(chalk.red(outcome.message));\n process.exit(1);\n }\n }\n\n spinner.succeed(\n opts.dryRun\n ? `Would render ${created} file${created === 1 ? '' : 's'} (${skipped} skipped)`\n : `Rendered ${created} file${created === 1 ? '' : 's'} (${skipped} skipped)`,\n );\n\n if (opts.dryRun) return;\n\n writeManifest(targetDir, manifest);\n console.log(chalk.dim(` wrote .precisa.json`));\n\n const gitStep = ora('git init + pnpm install').start();\n try {\n execSync('git init --initial-branch=main', { cwd: targetDir, stdio: 'pipe' });\n execSync('pnpm install', { cwd: targetDir, stdio: 'pipe' });\n gitStep.succeed('git init + pnpm install complete');\n } catch (err) {\n gitStep.warn(\n `git/pnpm setup skipped: ${(err as Error).message}. Run manually in ${targetDir}.`,\n );\n }\n\n console.log(chalk.bold.green(`\\n✓ ${repoName} scaffolded at ${targetDir}`));\n console.log(chalk.dim('\\nNext:'));\n console.log(chalk.dim(` cd ${repoName}`));\n console.log(chalk.dim(` # start adding your code`));\n } catch (err) {\n spinner.fail((err as Error).message);\n process.exit(1);\n }\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\nimport type { MergeStrategy, TemplateEntry } from './templates.js';\n\nexport type ApplyOutcome =\n | { kind: 'create'; target: string; rendered: string }\n | { kind: 'update'; target: string; previous: string; rendered: string }\n | { kind: 'skip-identical'; target: string }\n | { kind: 'preserve'; target: string; current: string; rendered: string }\n | { kind: 'skip-exists'; target: string }\n | { kind: 'merge-json'; target: string; previous: string; rendered: string }\n | { kind: 'error'; target: string; message: string };\n\nexport interface ApplyOptions {\n /** Repo root to apply into. */\n cwd: string;\n /** When true, compute the outcome but do not write to disk. */\n dryRun: boolean;\n /** Template entry being applied. */\n entry: TemplateEntry;\n /** Rendered template content (post token substitution). */\n rendered: string;\n}\n\n/**\n * Apply a single template file to the target repo. Returns the outcome\n * so callers can print a per-file status row and, on dry-run, a diff.\n */\nexport function applyTemplate({ cwd, dryRun, entry, rendered }: ApplyOptions): ApplyOutcome {\n const targetPath = resolve(cwd, entry.target);\n const exists = existsSync(targetPath);\n\n if (!exists) {\n if (!dryRun) writeFile(targetPath, rendered, entry.executable === true);\n return { kind: 'create', rendered, target: entry.target };\n }\n\n const current = readFileSync(targetPath, 'utf-8');\n\n switch (entry.merge_strategy as MergeStrategy) {\n case 'overwrite': {\n if (current === rendered) {\n return { kind: 'skip-identical', target: entry.target };\n }\n if (!dryRun) writeFile(targetPath, rendered, entry.executable === true);\n return { kind: 'update', previous: current, rendered, target: entry.target };\n }\n case 'skip_if_exists': {\n return { kind: 'skip-exists', target: entry.target };\n }\n case 'preserve': {\n return { current, kind: 'preserve', rendered, target: entry.target };\n }\n case 'merge_json': {\n let merged: string;\n try {\n merged = mergeJson(current, rendered);\n } catch (err) {\n return {\n kind: 'error',\n message: `JSON merge failed: ${(err as Error).message}`,\n target: entry.target,\n };\n }\n if (current === merged) {\n return { kind: 'skip-identical', target: entry.target };\n }\n if (!dryRun) writeFile(targetPath, merged, entry.executable === true);\n return { kind: 'merge-json', previous: current, rendered: merged, target: entry.target };\n }\n default: {\n return {\n kind: 'error',\n message: `Unknown merge_strategy '${entry.merge_strategy}'`,\n target: entry.target,\n };\n }\n }\n}\n\nfunction writeFile(path: string, contents: string, executable: boolean): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, contents);\n if (executable) chmodSync(path, 0o755);\n}\n\n/**\n * Shallow 3-way-ish JSON merge — the current file wins on conflicts so\n * repo-local customizations aren't clobbered. Objects are merged\n * key-by-key; arrays and scalars are replaced entirely by the current\n * value when present (falls back to the template value).\n *\n * If parsing fails, throws so the caller can report the error.\n */\nexport function mergeJson(currentRaw: string, templateRaw: string): string {\n const current = JSON.parse(currentRaw) as unknown;\n const template = JSON.parse(templateRaw) as unknown;\n const merged = mergeValue(template, current);\n return `${JSON.stringify(merged, null, 2)}\\n`;\n}\n\nfunction mergeValue(template: unknown, current: unknown): unknown {\n if (current === undefined) return template;\n if (\n typeof template !== 'object' ||\n template === null ||\n Array.isArray(template) ||\n typeof current !== 'object' ||\n current === null ||\n Array.isArray(current)\n ) {\n // Scalars / arrays: current value wins (never clobber repo-local values).\n return current;\n }\n const out: Record<string, unknown> = {};\n const keys = new Set([\n ...Object.keys(template as Record<string, unknown>),\n ...Object.keys(current as Record<string, unknown>),\n ]);\n for (const k of keys) {\n out[k] = mergeValue(\n (template as Record<string, unknown>)[k],\n (current as Record<string, unknown>)[k],\n );\n }\n return out;\n}\n","import chalk from 'chalk';\n\nimport { colorDiff } from '../lib/diff.js';\nimport { type ApplyOutcome, applyTemplate } from '../lib/merge.js';\nimport { loadTemplateManifest, readTemplateSource, renderTokens } from '../lib/templates.js';\nimport { isRequired, loadManifest, tokenContext } from '../manifest.js';\n\nexport interface SyncOptions {\n dryRun: boolean;\n}\n\nexport async function runSync(opts: SyncOptions): Promise<void> {\n const cwd = process.cwd();\n console.log(chalk.bold.cyan(`\\nprecisa sync${opts.dryRun ? ' --dry-run' : ''}`));\n\n let manifest;\n try {\n manifest = loadManifest(cwd);\n } catch (err) {\n console.error(chalk.red(`\\n${(err as Error).message}`));\n console.error(\n chalk.dim('\\n Run `precisa new <repo>` in an empty directory to scaffold a new repo,'),\n );\n console.error(chalk.dim(' or create a `.precisa.json` manifest manually.'));\n process.exit(1);\n }\n\n const entries = loadTemplateManifest().filter((e) => isRequired(e.required_when, manifest));\n const context = tokenContext(manifest);\n\n const outcomes: ApplyOutcome[] = [];\n for (const entry of entries) {\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n outcomes.push(\n applyTemplate({\n cwd,\n dryRun: opts.dryRun,\n entry,\n rendered,\n }),\n );\n }\n\n console.log('');\n for (const o of outcomes) {\n printOutcome(o, opts.dryRun);\n }\n\n const summary = summarize(outcomes);\n console.log('');\n console.log(\n chalk.dim(\n `${summary.create} create, ${summary.update} update, ${summary.mergeJson} merge-json, ${summary.preserve} preserve, ${summary.skip} skip, ${summary.error} error`,\n ),\n );\n\n if (summary.error > 0) process.exit(1);\n}\n\ninterface Summary {\n create: number;\n error: number;\n mergeJson: number;\n preserve: number;\n skip: number;\n update: number;\n}\n\nfunction summarize(outcomes: ApplyOutcome[]): Summary {\n const s: Summary = { create: 0, error: 0, mergeJson: 0, preserve: 0, skip: 0, update: 0 };\n for (const o of outcomes) {\n switch (o.kind) {\n case 'create':\n s.create += 1;\n break;\n case 'update':\n s.update += 1;\n break;\n case 'merge-json':\n s.mergeJson += 1;\n break;\n case 'preserve':\n s.preserve += 1;\n break;\n case 'skip-identical':\n case 'skip-exists':\n s.skip += 1;\n break;\n case 'error':\n s.error += 1;\n break;\n }\n }\n return s;\n}\n\nfunction printOutcome(o: ApplyOutcome, dryRun: boolean): void {\n const prefix = dryRun ? '(dry-run) ' : '';\n switch (o.kind) {\n case 'create':\n console.log(`${chalk.green('+')} ${prefix}create ${o.target}`);\n return;\n case 'update':\n console.log(`${chalk.yellow('~')} ${prefix}update ${o.target}`);\n if (dryRun) console.log(indent(colorDiff(o.target, o.previous, o.rendered)));\n return;\n case 'merge-json':\n console.log(`${chalk.yellow('~')} ${prefix}merge ${o.target}`);\n if (dryRun) console.log(indent(colorDiff(o.target, o.previous, o.rendered)));\n return;\n case 'preserve':\n console.log(\n `${chalk.blue('i')} ${prefix}preserve ${o.target} (template differs; not written)`,\n );\n if (dryRun && o.current !== o.rendered) {\n console.log(indent(colorDiff(o.target, o.current, o.rendered)));\n }\n return;\n case 'skip-identical':\n console.log(`${chalk.dim('=')} ${prefix}unchanged ${o.target}`);\n return;\n case 'skip-exists':\n console.log(`${chalk.dim('s')} ${prefix}skip ${o.target} (already exists)`);\n return;\n case 'error':\n console.log(`${chalk.red('!')} ${prefix}error ${o.target}: ${o.message}`);\n return;\n }\n}\n\nfunction indent(text: string): string {\n return text\n .split('\\n')\n .map((l) => ` ${l}`)\n .join('\\n');\n}\n","import chalk from 'chalk';\nimport { createPatch } from 'diff';\n\n/**\n * Format a unified diff with ANSI colors for terminal display.\n * Skips the `@@ hunk @@` metadata lines for a cleaner look.\n */\nexport function colorDiff(filename: string, previous: string, next: string): string {\n const patch = createPatch(filename, previous, next, '', '');\n const lines = patch.split('\\n');\n const out: string[] = [];\n for (const line of lines) {\n if (line.startsWith('---') || line.startsWith('+++')) continue;\n if (line.startsWith('@@')) {\n out.push(chalk.cyan(line));\n continue;\n }\n if (line.startsWith('+')) {\n out.push(chalk.green(line));\n continue;\n }\n if (line.startsWith('-')) {\n out.push(chalk.red(line));\n continue;\n }\n out.push(line);\n }\n return out.join('\\n');\n}\n"],"mappings":"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","names":["existsSync","readFileSync","resolve","resolve","resolve","readFileSync","resolve","resolve","existsSync","readFileSync","existsSync","mkdirSync","resolve","chalk","existsSync","readFileSync","writeFileSync","dirname","resolve","resolve","existsSync","chalk","mkdirSync","chalk","chalk","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/bin.ts","../src/commands/doctor.ts","../src/lib/templates.ts","../src/lib/paths.ts","../src/manifest.ts","../src/commands/new.ts","../src/lib/merge.ts","../src/commands/sync.ts","../src/lib/diff.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\n\nimport { runDoctor } from './commands/doctor.js';\nimport { runNew } from './commands/new.js';\nimport { runSync } from './commands/sync.js';\n\nconst program = new Command();\n\nprogram\n .name('precisa')\n .description('Bootstrap and sync Precisa Saúde repositories.')\n .version('0.0.0');\n\nprogram\n .command('new <repo-name>')\n .description('Scaffold a new repository from the shared templates.')\n .option('--profile <profile>', 'preset: oss-library | oss-site | private-app', 'oss-library')\n .option('--dry-run', 'print what would be written without touching disk', false)\n .option('--non-interactive', 'skip prompts; use --owner/--scopes/etc. flags instead', false)\n .option('--owner <org>', 'GitHub owner (org or user)', 'Precisa-Saude')\n .option(\n '--scopes <csv>',\n 'Comma-separated commit scopes (e.g. \"core,docs,ci,deps\")',\n 'docs,ci,deps',\n )\n .option('--security-email <email>', 'Security contact email', 'security@precisa-saude.com.br')\n .option(\n '--conduct-email <email>',\n 'Code-of-conduct contact email',\n 'conduct@precisa-saude.com.br',\n )\n .action(\n async (\n repoName: string,\n opts: {\n profile: string;\n dryRun: boolean;\n nonInteractive: boolean;\n owner: string;\n scopes: string;\n securityEmail: string;\n conductEmail: string;\n },\n ) => {\n await runNew(repoName, opts);\n },\n );\n\nprogram\n .command('sync')\n .description(\"Re-render templates against this repo's .precisa.json manifest.\")\n .option('--dry-run', 'print a diff without writing', false)\n .action(async (opts: { dryRun: boolean }) => {\n await runSync(opts);\n });\n\nprogram\n .command('doctor')\n .description('Audit this repo against the templates and report drift.')\n .action(async () => {\n await runDoctor();\n });\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n console.error(err);\n process.exit(1);\n});\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport chalk from 'chalk';\n\nimport {\n loadTemplateManifest,\n readTemplateSource,\n renderTokens,\n type TemplateEntry,\n} from '../lib/templates.js';\nimport { isRequired, loadManifest, tokenContext } from '../manifest.js';\n\ntype Severity = 'ok' | 'info' | 'warning' | 'error';\n\ninterface DriftReport {\n message: string;\n severity: Severity;\n target: string;\n}\n\nexport async function runDoctor(): Promise<void> {\n const cwd = process.cwd();\n console.log(chalk.bold.cyan('\\nprecisa doctor'));\n\n let manifest;\n try {\n manifest = loadManifest(cwd);\n } catch (err) {\n console.error(chalk.red(`\\n${(err as Error).message}`));\n process.exit(1);\n }\n\n const entries = loadTemplateManifest();\n const context = tokenContext(manifest);\n\n const reports: DriftReport[] = [];\n\n for (const entry of entries) {\n const required = isRequired(entry.required_when, manifest);\n const targetPath = resolve(cwd, entry.target);\n const exists = existsSync(targetPath);\n\n if (!required && !exists) continue;\n if (!required && exists) {\n reports.push({\n message: `Present but not required by the manifest profile (ok)`,\n severity: 'info',\n target: entry.target,\n });\n continue;\n }\n if (!exists) {\n reports.push({\n message: 'Missing',\n severity: 'error',\n target: entry.target,\n });\n continue;\n }\n\n // Exists + required — compare to rendered template\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n const current = readFileSync(targetPath, 'utf-8');\n reports.push(compareContent(entry, current, rendered));\n }\n\n console.log('');\n let errors = 0;\n let warnings = 0;\n let infos = 0;\n let oks = 0;\n\n for (const r of reports) {\n const icon = iconFor(r.severity);\n const line = `${icon} ${r.target}${r.message ? chalk.dim(` — ${r.message}`) : ''}`;\n console.log(line);\n if (r.severity === 'error') errors += 1;\n else if (r.severity === 'warning') warnings += 1;\n else if (r.severity === 'info') infos += 1;\n else oks += 1;\n }\n\n console.log('');\n console.log(chalk.dim(`${oks} ok, ${warnings} warning, ${errors} error, ${infos} info`));\n\n if (errors > 0) process.exit(1);\n}\n\nfunction compareContent(entry: TemplateEntry, current: string, rendered: string): DriftReport {\n if (current === rendered) {\n return { message: '', severity: 'ok', target: entry.target };\n }\n\n // Non-overwrite strategies don't re-render on sync — treat drift as\n // informational, not a warning. Makes the doctor output scannable:\n // warnings are the files sync WOULD change; infos are files where\n // drift is intentional (customized scaffold, preserved docs).\n if (entry.merge_strategy === 'preserve') {\n return {\n message: 'Differs from template (preserve strategy — suggestion only)',\n severity: 'info',\n target: entry.target,\n };\n }\n if (entry.merge_strategy === 'skip_if_exists') {\n return {\n message: 'Differs from template (scaffold-only; sync will not overwrite)',\n severity: 'info',\n target: entry.target,\n };\n }\n\n return {\n message: 'Differs from template (run `precisa sync` to update)',\n severity: 'warning',\n target: entry.target,\n };\n}\n\nfunction iconFor(severity: Severity): string {\n switch (severity) {\n case 'ok':\n return chalk.green('✓');\n case 'info':\n return chalk.blue('i');\n case 'warning':\n return chalk.yellow('!');\n case 'error':\n return chalk.red('✗');\n }\n}\n","import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { parse as parseYaml } from 'yaml';\n\nimport type { RequiredWhen } from '../manifest.js';\nimport { resolveTemplatesDir } from './paths.js';\n\nexport type MergeStrategy = 'overwrite' | 'merge_json' | 'preserve' | 'skip_if_exists';\n\nexport interface TemplateEntry {\n /** Whether to mark the rendered file executable (chmod +x). */\n executable?: boolean;\n /** How to merge when the target already exists. */\n merge_strategy: MergeStrategy;\n /** Gate for inclusion. */\n required_when: RequiredWhen;\n /** Path relative to templates/. */\n source: string;\n /** Path in the target repo (relative to the repo root). */\n target: string;\n}\n\ninterface TemplateManifestFile {\n templates: TemplateEntry[];\n}\n\n/**\n * Load the `templates.manifest.yml` from the bundled templates directory.\n * Throws if the file is missing or the shape is wrong.\n */\nexport function loadTemplateManifest(): TemplateEntry[] {\n const dir = resolveTemplatesDir();\n const manifestPath = resolve(dir, 'templates.manifest.yml');\n const raw = readFileSync(manifestPath, 'utf-8');\n const parsed = parseYaml(raw) as TemplateManifestFile | undefined;\n if (!parsed || !Array.isArray(parsed.templates)) {\n throw new Error(`${manifestPath}: expected { templates: [...] } at root`);\n }\n for (const [i, t] of parsed.templates.entries()) {\n if (!t.source || !t.target) {\n throw new Error(`${manifestPath}: entry ${i} is missing source or target`);\n }\n }\n return parsed.templates;\n}\n\nexport function readTemplateSource(entry: TemplateEntry): string {\n const dir = resolveTemplatesDir();\n const path = resolve(dir, entry.source);\n return readFileSync(path, 'utf-8');\n}\n\n/**\n * Substitute `{{TOKEN}}` placeholders with values from `context`. Unknown\n * tokens are left untouched (keeps the double braces visible so bad keys\n * are easy to spot in rendered output).\n *\n * Also processes conditional blocks:\n *\n * {{#if HAS_SITE}}\n * ...lines rendered only when HAS_SITE is truthy...\n * {{/if}}\n *\n * Markers can appear inside a host-language comment so the template stays\n * parseable by syntax-aware tools (prettier on YAML, for example):\n *\n * # {{#if HAS_SITE}}\n * ...\n * # {{/if}}\n *\n * A token is \"truthy\" when its string value is non-empty and not `\"false\"`.\n * Blocks may nest; they are expanded before token substitution so a block's\n * body can itself reference tokens.\n */\nexport function renderTokens(source: string, context: Record<string, string>): string {\n return renderTokenSubstitutions(renderConditionalBlocks(source, context), context);\n}\n\nfunction renderTokenSubstitutions(source: string, context: Record<string, string>): string {\n return source.replace(/\\{\\{([A-Z_]+)\\}\\}/g, (match, token: string) => {\n return Object.prototype.hasOwnProperty.call(context, token) ? context[token]! : match;\n });\n}\n\nfunction renderConditionalBlocks(source: string, context: Record<string, string>): string {\n // Match an entire line containing `{{#if TOKEN}}` (possibly wrapped in a\n // host-language comment like `# {{#if TOKEN}}` or `// {{#if TOKEN}}`),\n // up through the matching `{{/if}}` line. The whole marker line is\n // consumed so commented-out markers don't leak into rendered output.\n const pattern =\n /^[ \\t]*[^\\S\\n]*[^\\n]*\\{\\{#if ([A-Z_]+)\\}\\}[^\\n]*\\n([\\s\\S]*?)^[ \\t]*[^\\n]*\\{\\{\\/if\\}\\}[^\\n]*\\n?/gm;\n let prev: string;\n let out = source;\n // Re-run to handle nested blocks. Simple fixed-point loop keeps the\n // replacement rules uniform.\n do {\n prev = out;\n out = out.replace(pattern, (_match, token: string, body: string) => {\n const value = context[token];\n const truthy = value !== undefined && value !== '' && value !== 'false';\n return truthy ? body : '';\n });\n } while (out !== prev);\n return out;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Locate the bundled `templates/` directory.\n *\n * When published to npm, the templates live at `dist/templates/` inside\n * the CLI package (copied by `scripts/copy-templates.mjs` during build).\n *\n * When running from the monorepo (e.g. `pnpm --filter @precisa-saude/cli dev`),\n * the templates live at the repo root — fall back to walking up from the\n * package directory.\n */\nexport function resolveTemplatesDir(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n\n // Published case: cli package's dist/templates\n const bundled = resolve(here, 'templates');\n if (existsSync(bundled)) return bundled;\n\n // Dev case: walk up from packages/cli/{src|dist} to the monorepo root\n const repoRoot = resolve(here, '..', '..', '..', '..');\n const repoTemplates = resolve(repoRoot, 'templates');\n if (existsSync(repoTemplates)) return repoTemplates;\n\n // Sibling-in-package case (tsup output): packages/cli/dist -> ../../templates\n const packageParent = resolve(here, '..', '..', 'templates');\n if (existsSync(packageParent)) return packageParent;\n\n throw new Error(\n `Could not locate templates/ directory. Searched:\\n ${bundled}\\n ${repoTemplates}\\n ${packageParent}`,\n );\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\n/**\n * `.precisa.json` manifest — sits at the root of every consumer repo and\n * declares the repo's profile so `precisa sync` and `precisa doctor` know\n * which templates to render and which rules to enforce.\n */\nexport interface PrecisaManifest {\n /** Commitlint scope enum for this repo. */\n commitScopes: string[];\n\n /** Contact emails used in governance doc templates. */\n contactEmails: {\n security: string;\n conduct: string;\n };\n\n /** Does this repo have publishable packages/*? */\n hasPackages: boolean;\n\n /** Does this repo ship a website? Controls preview-deploy workflows. */\n hasSite: boolean;\n\n /** Repository name (typically matches the GitHub repo name). */\n name: string;\n\n /** Pinned runtime versions. Default: node=22, pnpm=9.15.9. */\n nodeVersion?: string;\n\n /** GitHub organization or user that owns the repo (e.g. `Precisa-Saude`). */\n owner: string;\n\n pnpmVersion?: string;\n\n /** Publishes any workspace package to npm? */\n publishesToNpm: boolean;\n\n /**\n * Workspace package directories (relative to repo root) that the\n * `publish` job in `ci.yml` should pass to `_publish.yml`. Only read\n * when `publishesToNpm: true`. Example: `[\"packages/core\", \"packages/cli\"]`.\n */\n publishPackages?: string[];\n\n /** Schema version of this manifest file. Bump when the schema changes. */\n schemaVersion: 1;\n\n /**\n * pnpm filter selector for the site package, passed to the deploy\n * workflow. Only read when `hasSite: true`. Example: `@my-repo/site`.\n */\n siteFilter?: string;\n\n /**\n * Cloudflare Pages project name for the deploy-site workflow. Only\n * read when `hasSite: true`.\n */\n siteProjectName?: string;\n\n /**\n * Path prefix (relative to repo root, trailing slash) treated as site\n * source for change detection in `_deploy-site.yml`. Defaults to\n * `site/` — override to `packages/site/` for monorepos where the site\n * lives under `packages/`.\n */\n siteSourcePath?: string;\n\n /** Public-OSS or private-internal. Controls which templates are rendered. */\n visibility: 'oss' | 'private';\n}\n\nexport const MANIFEST_FILENAME = '.precisa.json';\n\nexport const DEFAULT_MANIFEST_FIELDS = {\n hasPackages: true,\n hasSite: false,\n nodeVersion: '22',\n pnpmVersion: '9.15.9',\n publishesToNpm: true,\n schemaVersion: 1 as const,\n visibility: 'oss' as const,\n};\n\n/** Template gate values — `required_when` in templates.manifest.yml. */\nexport type RequiredWhen =\n | 'always'\n | 'never'\n | 'oss'\n | 'private'\n | 'has_site'\n | 'has_packages'\n | 'publishes_to_npm';\n\n/** Returns true when a template's `required_when` gate applies to this manifest. */\nexport function isRequired(when: RequiredWhen, manifest: PrecisaManifest): boolean {\n switch (when) {\n case 'always':\n return true;\n case 'never':\n return false;\n case 'oss':\n return manifest.visibility === 'oss';\n case 'private':\n return manifest.visibility === 'private';\n case 'has_site':\n return manifest.hasSite;\n case 'has_packages':\n return manifest.hasPackages;\n case 'publishes_to_npm':\n return manifest.publishesToNpm;\n default:\n return true;\n }\n}\n\n/**\n * Build the token substitution map from a manifest. Keys are `{{TOKEN}}`\n * (without braces); values are always strings.\n */\nexport function tokenContext(manifest: PrecisaManifest): Record<string, string> {\n return {\n COMMIT_SCOPES: manifest.commitScopes.join(','),\n // For human-readable docs (AGENTS.md, README) — backticked list.\n COMMIT_SCOPES_HUMAN: manifest.commitScopes.map((s) => `\\`${s}\\``).join(', '),\n // For `.commitlintrc.cjs` — scope array spelled as JS string literals,\n // ready to drop inside `[ ... ]`.\n COMMIT_SCOPES_JSON: manifest.commitScopes.map((s) => `'${s}'`).join(', '),\n CONDUCT_EMAIL: manifest.contactEmails.conduct,\n HAS_PACKAGES: String(manifest.hasPackages),\n HAS_SITE: String(manifest.hasSite),\n NODE_VERSION: manifest.nodeVersion ?? '22',\n OWNER_ORG: manifest.owner,\n PNPM_VERSION: manifest.pnpmVersion ?? '9.15.9',\n // YAML block-scalar body for the `packages: |` input of `_publish.yml`.\n // The template provides the first entry's indent; subsequent entries\n // get 8 spaces explicitly to match. Empty when no packages declared.\n PUBLISH_PACKAGES_YAML: (manifest.publishPackages ?? []).join('\\n '),\n PUBLISHES_TO_NPM: String(manifest.publishesToNpm),\n REPO_NAME: manifest.name,\n REPO_SLUG: `${manifest.owner}/${manifest.name}`,\n SECURITY_EMAIL: manifest.contactEmails.security,\n SITE_FILTER: manifest.siteFilter ?? '',\n SITE_PROJECT_NAME: manifest.siteProjectName ?? '',\n SITE_SOURCE_PATH: manifest.siteSourcePath ?? 'site/',\n VISIBILITY: manifest.visibility,\n };\n}\n\nexport interface ManifestValidationError {\n message: string;\n path: string;\n}\n\nexport function validateManifest(raw: unknown): ManifestValidationError[] {\n const errors: ManifestValidationError[] = [];\n const m = raw as Partial<PrecisaManifest> | undefined;\n if (!m || typeof m !== 'object') {\n return [{ message: 'manifest must be a JSON object', path: '$' }];\n }\n if (m.schemaVersion !== 1) {\n errors.push({ message: 'must be 1', path: 'schemaVersion' });\n }\n if (typeof m.name !== 'string' || !m.name) {\n errors.push({ message: 'must be a non-empty string', path: 'name' });\n }\n if (typeof m.owner !== 'string' || !m.owner) {\n errors.push({ message: 'must be a non-empty string', path: 'owner' });\n }\n if (m.visibility !== 'oss' && m.visibility !== 'private') {\n errors.push({ message: \"must be 'oss' or 'private'\", path: 'visibility' });\n }\n for (const key of ['hasSite', 'hasPackages', 'publishesToNpm'] as const) {\n if (typeof m[key] !== 'boolean') {\n errors.push({ message: 'must be a boolean', path: key });\n }\n }\n if (!Array.isArray(m.commitScopes)) {\n errors.push({ message: 'must be an array of strings', path: 'commitScopes' });\n }\n if (m.publishPackages !== undefined) {\n if (!Array.isArray(m.publishPackages)) {\n errors.push({ message: 'must be an array of strings', path: 'publishPackages' });\n } else if (m.publishPackages.some((p) => typeof p !== 'string' || !p)) {\n errors.push({ message: 'entries must be non-empty strings', path: 'publishPackages' });\n }\n }\n if (m.publishesToNpm) {\n if (!Array.isArray(m.publishPackages) || m.publishPackages.length === 0) {\n errors.push({\n message: 'must have at least one entry when publishesToNpm is true',\n path: 'publishPackages',\n });\n }\n }\n if (m.hasSite === true) {\n for (const key of ['siteProjectName', 'siteFilter'] as const) {\n if (typeof m[key] !== 'string' || !m[key]) {\n errors.push({ message: 'required and non-empty when hasSite is true', path: key });\n }\n }\n }\n if (m.siteProjectName !== undefined && typeof m.siteProjectName !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteProjectName' });\n }\n if (m.siteFilter !== undefined && typeof m.siteFilter !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteFilter' });\n }\n if (m.siteSourcePath !== undefined && typeof m.siteSourcePath !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteSourcePath' });\n }\n if (!m.contactEmails || typeof m.contactEmails !== 'object') {\n errors.push({ message: 'must be an object', path: 'contactEmails' });\n } else {\n for (const key of ['security', 'conduct'] as const) {\n if (typeof m.contactEmails[key] !== 'string' || !m.contactEmails[key]) {\n errors.push({\n message: 'must be a non-empty string',\n path: `contactEmails.${key}`,\n });\n }\n }\n }\n return errors;\n}\n\nexport function loadManifest(cwd: string): PrecisaManifest {\n const path = resolve(cwd, MANIFEST_FILENAME);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, 'utf-8'));\n } catch (err) {\n throw new Error(`Failed to read ${MANIFEST_FILENAME} at ${path}: ${(err as Error).message}`);\n }\n const errors = validateManifest(raw);\n if (errors.length > 0) {\n const detail = errors.map((e) => ` - ${e.path}: ${e.message}`).join('\\n');\n throw new Error(`Invalid ${MANIFEST_FILENAME}:\\n${detail}`);\n }\n return raw as PrecisaManifest;\n}\n\nexport function writeManifest(cwd: string, manifest: PrecisaManifest): void {\n const path = resolve(cwd, MANIFEST_FILENAME);\n writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\\n`);\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport prompts from 'prompts';\n\nimport { applyTemplate } from '../lib/merge.js';\nimport { loadTemplateManifest, readTemplateSource, renderTokens } from '../lib/templates.js';\nimport {\n DEFAULT_MANIFEST_FIELDS,\n isRequired,\n type PrecisaManifest,\n tokenContext,\n writeManifest,\n} from '../manifest.js';\n\nexport interface NewOptions {\n conductEmail?: string;\n dryRun: boolean;\n /** Skip interactive prompts; require --owner/--scopes/--*-email flags. */\n nonInteractive?: boolean;\n owner?: string;\n profile: string;\n /** Comma-separated list, e.g. \"core,docs,ci,deps\". */\n scopes?: string;\n securityEmail?: string;\n}\n\nconst PROFILES = {\n 'oss-library': {\n hasPackages: true,\n hasSite: false,\n publishesToNpm: true,\n visibility: 'oss',\n },\n 'oss-site': {\n hasPackages: false,\n hasSite: true,\n publishesToNpm: false,\n visibility: 'oss',\n },\n 'private-app': {\n hasPackages: true,\n hasSite: true,\n publishesToNpm: false,\n visibility: 'private',\n },\n} as const satisfies Record<\n string,\n Pick<PrecisaManifest, 'visibility' | 'hasSite' | 'hasPackages' | 'publishesToNpm'>\n>;\n\nexport async function runNew(repoName: string, opts: NewOptions): Promise<void> {\n const targetDir = resolve(process.cwd(), repoName);\n\n if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {\n console.error(chalk.red(`\\nError: ${targetDir} already exists and is not empty.`));\n process.exit(1);\n }\n\n const profile = PROFILES[opts.profile as keyof typeof PROFILES];\n if (!profile) {\n console.error(\n chalk.red(`\\nError: unknown profile '${opts.profile}'. Choose one of:`),\n Object.keys(PROFILES).join(', '),\n );\n process.exit(1);\n }\n\n console.log(chalk.bold.cyan(`\\nprecisa new ${repoName}`));\n console.log(chalk.dim(`profile: ${opts.profile}${opts.dryRun ? ' (dry-run)' : ''}`));\n console.log(chalk.dim(`target: ${targetDir}\\n`));\n\n const answers = opts.nonInteractive\n ? {\n commitScopes: (opts.scopes ?? 'docs,ci,deps')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n conductEmail: opts.conductEmail ?? 'conduct@precisa-saude.com.br',\n owner: opts.owner ?? 'Precisa-Saude',\n securityEmail: opts.securityEmail ?? 'security@precisa-saude.com.br',\n }\n : await prompts(\n [\n {\n initial: opts.owner ?? 'Precisa-Saude',\n message: 'GitHub owner (org or user):',\n name: 'owner',\n type: 'text',\n },\n {\n initial: opts.securityEmail ?? 'security@precisa-saude.com.br',\n message: 'Security contact email:',\n name: 'securityEmail',\n type: 'text',\n },\n {\n initial: opts.conductEmail ?? 'conduct@precisa-saude.com.br',\n message: 'Code-of-conduct contact email:',\n name: 'conductEmail',\n type: 'text',\n },\n {\n initial: opts.scopes ?? 'docs,ci,deps',\n message: 'Commit scopes (comma-separated):',\n name: 'commitScopes',\n separator: ',',\n type: 'list',\n },\n ],\n { onCancel: () => process.exit(1) },\n );\n\n const manifest: PrecisaManifest = {\n ...DEFAULT_MANIFEST_FIELDS,\n ...profile,\n commitScopes: answers.commitScopes,\n contactEmails: {\n conduct: answers.conductEmail,\n security: answers.securityEmail,\n },\n name: repoName,\n owner: answers.owner,\n };\n\n const spinner = ora('Rendering templates').start();\n try {\n if (!opts.dryRun) mkdirSync(targetDir, { recursive: true });\n\n const entries = loadTemplateManifest().filter((e) => isRequired(e.required_when, manifest));\n const context = tokenContext(manifest);\n\n let created = 0;\n let skipped = 0;\n\n for (const entry of entries) {\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n const outcome = applyTemplate({\n cwd: targetDir,\n dryRun: opts.dryRun,\n entry,\n rendered,\n });\n if (outcome.kind === 'create') created += 1;\n else if (outcome.kind === 'skip-exists') skipped += 1;\n else if (outcome.kind === 'error') {\n spinner.fail(`Failed on ${entry.target}`);\n console.error(chalk.red(outcome.message));\n process.exit(1);\n }\n }\n\n spinner.succeed(\n opts.dryRun\n ? `Would render ${created} file${created === 1 ? '' : 's'} (${skipped} skipped)`\n : `Rendered ${created} file${created === 1 ? '' : 's'} (${skipped} skipped)`,\n );\n\n if (opts.dryRun) return;\n\n writeManifest(targetDir, manifest);\n console.log(chalk.dim(` wrote .precisa.json`));\n\n const gitStep = ora('git init + pnpm install').start();\n try {\n execSync('git init --initial-branch=main', { cwd: targetDir, stdio: 'pipe' });\n execSync('pnpm install', { cwd: targetDir, stdio: 'pipe' });\n gitStep.succeed('git init + pnpm install complete');\n } catch (err) {\n gitStep.warn(\n `git/pnpm setup skipped: ${(err as Error).message}. Run manually in ${targetDir}.`,\n );\n }\n\n console.log(chalk.bold.green(`\\n✓ ${repoName} scaffolded at ${targetDir}`));\n console.log(chalk.dim('\\nNext:'));\n console.log(chalk.dim(` cd ${repoName}`));\n console.log(chalk.dim(` # start adding your code`));\n } catch (err) {\n spinner.fail((err as Error).message);\n process.exit(1);\n }\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\nimport type { MergeStrategy, TemplateEntry } from './templates.js';\n\nexport type ApplyOutcome =\n | { kind: 'create'; target: string; rendered: string }\n | { kind: 'update'; target: string; previous: string; rendered: string }\n | { kind: 'skip-identical'; target: string }\n | { kind: 'preserve'; target: string; current: string; rendered: string }\n | { kind: 'skip-exists'; target: string }\n | { kind: 'merge-json'; target: string; previous: string; rendered: string }\n | { kind: 'error'; target: string; message: string };\n\nexport interface ApplyOptions {\n /** Repo root to apply into. */\n cwd: string;\n /** When true, compute the outcome but do not write to disk. */\n dryRun: boolean;\n /** Template entry being applied. */\n entry: TemplateEntry;\n /** Rendered template content (post token substitution). */\n rendered: string;\n}\n\n/**\n * Apply a single template file to the target repo. Returns the outcome\n * so callers can print a per-file status row and, on dry-run, a diff.\n */\nexport function applyTemplate({ cwd, dryRun, entry, rendered }: ApplyOptions): ApplyOutcome {\n const targetPath = resolve(cwd, entry.target);\n const exists = existsSync(targetPath);\n\n if (!exists) {\n if (!dryRun) writeFile(targetPath, rendered, entry.executable === true);\n return { kind: 'create', rendered, target: entry.target };\n }\n\n const current = readFileSync(targetPath, 'utf-8');\n\n switch (entry.merge_strategy as MergeStrategy) {\n case 'overwrite': {\n if (current === rendered) {\n return { kind: 'skip-identical', target: entry.target };\n }\n if (!dryRun) writeFile(targetPath, rendered, entry.executable === true);\n return { kind: 'update', previous: current, rendered, target: entry.target };\n }\n case 'skip_if_exists': {\n return { kind: 'skip-exists', target: entry.target };\n }\n case 'preserve': {\n return { current, kind: 'preserve', rendered, target: entry.target };\n }\n case 'merge_json': {\n let merged: string;\n try {\n merged = mergeJson(current, rendered);\n } catch (err) {\n return {\n kind: 'error',\n message: `JSON merge failed: ${(err as Error).message}`,\n target: entry.target,\n };\n }\n if (current === merged) {\n return { kind: 'skip-identical', target: entry.target };\n }\n if (!dryRun) writeFile(targetPath, merged, entry.executable === true);\n return { kind: 'merge-json', previous: current, rendered: merged, target: entry.target };\n }\n default: {\n return {\n kind: 'error',\n message: `Unknown merge_strategy '${entry.merge_strategy}'`,\n target: entry.target,\n };\n }\n }\n}\n\nfunction writeFile(path: string, contents: string, executable: boolean): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, contents);\n if (executable) chmodSync(path, 0o755);\n}\n\n/**\n * Shallow 3-way-ish JSON merge — the current file wins on conflicts so\n * repo-local customizations aren't clobbered. Objects are merged\n * key-by-key; arrays and scalars are replaced entirely by the current\n * value when present (falls back to the template value).\n *\n * If parsing fails, throws so the caller can report the error.\n */\nexport function mergeJson(currentRaw: string, templateRaw: string): string {\n const current = JSON.parse(currentRaw) as unknown;\n const template = JSON.parse(templateRaw) as unknown;\n const merged = mergeValue(template, current);\n return `${JSON.stringify(merged, null, 2)}\\n`;\n}\n\nfunction mergeValue(template: unknown, current: unknown): unknown {\n if (current === undefined) return template;\n if (\n typeof template !== 'object' ||\n template === null ||\n Array.isArray(template) ||\n typeof current !== 'object' ||\n current === null ||\n Array.isArray(current)\n ) {\n // Scalars / arrays: current value wins (never clobber repo-local values).\n return current;\n }\n const out: Record<string, unknown> = {};\n const keys = new Set([\n ...Object.keys(template as Record<string, unknown>),\n ...Object.keys(current as Record<string, unknown>),\n ]);\n for (const k of keys) {\n out[k] = mergeValue(\n (template as Record<string, unknown>)[k],\n (current as Record<string, unknown>)[k],\n );\n }\n return out;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport chalk from 'chalk';\n\nimport { colorDiff } from '../lib/diff.js';\nimport { type ApplyOutcome, applyTemplate } from '../lib/merge.js';\nimport { loadTemplateManifest, readTemplateSource, renderTokens } from '../lib/templates.js';\nimport { isRequired, loadManifest, tokenContext } from '../manifest.js';\n\nexport interface SyncOptions {\n dryRun: boolean;\n}\n\nexport async function runSync(opts: SyncOptions): Promise<void> {\n const cwd = process.cwd();\n console.log(chalk.bold.cyan(`\\nprecisa sync${opts.dryRun ? ' --dry-run' : ''}`));\n\n let manifest;\n try {\n manifest = loadManifest(cwd);\n } catch (err) {\n console.error(chalk.red(`\\n${(err as Error).message}`));\n console.error(\n chalk.dim('\\n Run `precisa new <repo>` in an empty directory to scaffold a new repo,'),\n );\n console.error(chalk.dim(' or create a `.precisa.json` manifest manually.'));\n process.exit(1);\n }\n\n const entries = loadTemplateManifest().filter((e) => isRequired(e.required_when, manifest));\n const context = tokenContext(manifest);\n\n const outcomes: ApplyOutcome[] = [];\n for (const entry of entries) {\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n outcomes.push(\n applyTemplate({\n cwd,\n dryRun: opts.dryRun,\n entry,\n rendered,\n }),\n );\n }\n\n console.log('');\n for (const o of outcomes) {\n printOutcome(o, opts.dryRun);\n }\n\n const summary = summarize(outcomes);\n console.log('');\n console.log(\n chalk.dim(\n `${summary.create} create, ${summary.update} update, ${summary.mergeJson} merge-json, ${summary.preserve} preserve, ${summary.skip} skip, ${summary.error} error`,\n ),\n );\n\n printPostSyncReminders(cwd, outcomes);\n\n if (summary.error > 0) process.exit(1);\n}\n\n// Best-effort reminders for steps that have to happen in the GitHub UI\n// (creating environments, setting up required reviewers) that this CLI\n// cannot do remotely. Triggered when a workflow that depends on the\n// reminder was actually written or already present in the repo.\nfunction printPostSyncReminders(cwd: string, outcomes: ApplyOutcome[]): void {\n const touched = outcomes\n .filter((o) => o.kind === 'create' || o.kind === 'update')\n .map((o) => o.target);\n\n const publishYml = join(cwd, '.github/workflows/_publish.yml');\n const hasPublishWorkflow = existsSync(publishYml);\n const publishReferencesEnv =\n hasPublishWorkflow &&\n readFileSync(publishYml, 'utf8').includes('environment:') &&\n readFileSync(publishYml, 'utf8').includes('npm-publish');\n\n const publishTouched = touched.some((t) => t.endsWith('_publish.yml'));\n if (publishReferencesEnv && publishTouched) {\n console.log('');\n console.log(chalk.bold.yellow('Post-sync — manual GitHub setup'));\n console.log(\n chalk.dim(\n ' Settings → Environments → npm-publish must exist with at least one required reviewer.',\n ),\n );\n console.log(\n chalk.dim(\n ' Without it the publish step runs unattended. The CLI cannot create environments remotely.',\n ),\n );\n }\n\n const watchTouched = touched.some((t) => t.endsWith('publish-watch.yml'));\n if (watchTouched) {\n console.log('');\n console.log(chalk.bold.yellow('Post-sync — publish-watch'));\n console.log(\n chalk.dim(\n ' publish-watch.yml now runs every 15 min. Confirm npm package names in `packages/**` are',\n ),\n );\n console.log(\n chalk.dim(\n ' current and that semantic-release tag convention (`<name>@<ver>` or `v<ver>`) matches.',\n ),\n );\n }\n}\n\ninterface Summary {\n create: number;\n error: number;\n mergeJson: number;\n preserve: number;\n skip: number;\n update: number;\n}\n\nfunction summarize(outcomes: ApplyOutcome[]): Summary {\n const s: Summary = { create: 0, error: 0, mergeJson: 0, preserve: 0, skip: 0, update: 0 };\n for (const o of outcomes) {\n switch (o.kind) {\n case 'create':\n s.create += 1;\n break;\n case 'update':\n s.update += 1;\n break;\n case 'merge-json':\n s.mergeJson += 1;\n break;\n case 'preserve':\n s.preserve += 1;\n break;\n case 'skip-identical':\n case 'skip-exists':\n s.skip += 1;\n break;\n case 'error':\n s.error += 1;\n break;\n }\n }\n return s;\n}\n\nfunction printOutcome(o: ApplyOutcome, dryRun: boolean): void {\n const prefix = dryRun ? '(dry-run) ' : '';\n switch (o.kind) {\n case 'create':\n console.log(`${chalk.green('+')} ${prefix}create ${o.target}`);\n return;\n case 'update':\n console.log(`${chalk.yellow('~')} ${prefix}update ${o.target}`);\n if (dryRun) console.log(indent(colorDiff(o.target, o.previous, o.rendered)));\n return;\n case 'merge-json':\n console.log(`${chalk.yellow('~')} ${prefix}merge ${o.target}`);\n if (dryRun) console.log(indent(colorDiff(o.target, o.previous, o.rendered)));\n return;\n case 'preserve':\n console.log(\n `${chalk.blue('i')} ${prefix}preserve ${o.target} (template differs; not written)`,\n );\n if (dryRun && o.current !== o.rendered) {\n console.log(indent(colorDiff(o.target, o.current, o.rendered)));\n }\n return;\n case 'skip-identical':\n console.log(`${chalk.dim('=')} ${prefix}unchanged ${o.target}`);\n return;\n case 'skip-exists':\n console.log(`${chalk.dim('s')} ${prefix}skip ${o.target} (already exists)`);\n return;\n case 'error':\n console.log(`${chalk.red('!')} ${prefix}error ${o.target}: ${o.message}`);\n return;\n }\n}\n\nfunction indent(text: string): string {\n return text\n .split('\\n')\n .map((l) => ` ${l}`)\n .join('\\n');\n}\n","import chalk from 'chalk';\nimport { createPatch } from 'diff';\n\n/**\n * Format a unified diff with ANSI colors for terminal display.\n * Skips the `@@ hunk @@` metadata lines for a cleaner look.\n */\nexport function colorDiff(filename: string, previous: string, next: string): string {\n const patch = createPatch(filename, previous, next, '', '');\n const lines = patch.split('\\n');\n const out: string[] = [];\n for (const line of lines) {\n if (line.startsWith('---') || line.startsWith('+++')) continue;\n if (line.startsWith('@@')) {\n out.push(chalk.cyan(line));\n continue;\n }\n if (line.startsWith('+')) {\n out.push(chalk.green(line));\n continue;\n }\n if (line.startsWith('-')) {\n out.push(chalk.red(line));\n continue;\n }\n out.push(line);\n }\n return out.join('\\n');\n}\n"],"mappings":"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","names":["existsSync","readFileSync","resolve","resolve","resolve","readFileSync","resolve","resolve","existsSync","readFileSync","existsSync","mkdirSync","resolve","chalk","existsSync","readFileSync","writeFileSync","dirname","resolve","resolve","existsSync","chalk","mkdirSync","existsSync","readFileSync","chalk","chalk","chalk","existsSync","readFileSync"]}
|
package/dist/index.js
CHANGED
|
@@ -553,6 +553,8 @@ precisa new ${repoName}`));
|
|
|
553
553
|
}
|
|
554
554
|
|
|
555
555
|
// src/commands/sync.ts
|
|
556
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
557
|
+
import { join } from "path";
|
|
556
558
|
import chalk4 from "chalk";
|
|
557
559
|
|
|
558
560
|
// src/lib/diff.ts
|
|
@@ -624,8 +626,45 @@ ${err.message}`));
|
|
|
624
626
|
`${summary.create} create, ${summary.update} update, ${summary.mergeJson} merge-json, ${summary.preserve} preserve, ${summary.skip} skip, ${summary.error} error`
|
|
625
627
|
)
|
|
626
628
|
);
|
|
629
|
+
printPostSyncReminders(cwd, outcomes);
|
|
627
630
|
if (summary.error > 0) process.exit(1);
|
|
628
631
|
}
|
|
632
|
+
function printPostSyncReminders(cwd, outcomes) {
|
|
633
|
+
const touched = outcomes.filter((o) => o.kind === "create" || o.kind === "update").map((o) => o.target);
|
|
634
|
+
const publishYml = join(cwd, ".github/workflows/_publish.yml");
|
|
635
|
+
const hasPublishWorkflow = existsSync5(publishYml);
|
|
636
|
+
const publishReferencesEnv = hasPublishWorkflow && readFileSync5(publishYml, "utf8").includes("environment:") && readFileSync5(publishYml, "utf8").includes("npm-publish");
|
|
637
|
+
const publishTouched = touched.some((t) => t.endsWith("_publish.yml"));
|
|
638
|
+
if (publishReferencesEnv && publishTouched) {
|
|
639
|
+
console.log("");
|
|
640
|
+
console.log(chalk4.bold.yellow("Post-sync \u2014 manual GitHub setup"));
|
|
641
|
+
console.log(
|
|
642
|
+
chalk4.dim(
|
|
643
|
+
" Settings \u2192 Environments \u2192 npm-publish must exist with at least one required reviewer."
|
|
644
|
+
)
|
|
645
|
+
);
|
|
646
|
+
console.log(
|
|
647
|
+
chalk4.dim(
|
|
648
|
+
" Without it the publish step runs unattended. The CLI cannot create environments remotely."
|
|
649
|
+
)
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
const watchTouched = touched.some((t) => t.endsWith("publish-watch.yml"));
|
|
653
|
+
if (watchTouched) {
|
|
654
|
+
console.log("");
|
|
655
|
+
console.log(chalk4.bold.yellow("Post-sync \u2014 publish-watch"));
|
|
656
|
+
console.log(
|
|
657
|
+
chalk4.dim(
|
|
658
|
+
" publish-watch.yml now runs every 15 min. Confirm npm package names in `packages/**` are"
|
|
659
|
+
)
|
|
660
|
+
);
|
|
661
|
+
console.log(
|
|
662
|
+
chalk4.dim(
|
|
663
|
+
" current and that semantic-release tag convention (`<name>@<ver>` or `v<ver>`) matches."
|
|
664
|
+
)
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
629
668
|
function summarize(outcomes) {
|
|
630
669
|
const s = { create: 0, error: 0, mergeJson: 0, preserve: 0, skip: 0, update: 0 };
|
|
631
670
|
for (const o of outcomes) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/doctor.ts","../src/lib/templates.ts","../src/lib/paths.ts","../src/manifest.ts","../src/commands/new.ts","../src/lib/merge.ts","../src/commands/sync.ts","../src/lib/diff.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport chalk from 'chalk';\n\nimport {\n loadTemplateManifest,\n readTemplateSource,\n renderTokens,\n type TemplateEntry,\n} from '../lib/templates.js';\nimport { isRequired, loadManifest, tokenContext } from '../manifest.js';\n\ntype Severity = 'ok' | 'info' | 'warning' | 'error';\n\ninterface DriftReport {\n message: string;\n severity: Severity;\n target: string;\n}\n\nexport async function runDoctor(): Promise<void> {\n const cwd = process.cwd();\n console.log(chalk.bold.cyan('\\nprecisa doctor'));\n\n let manifest;\n try {\n manifest = loadManifest(cwd);\n } catch (err) {\n console.error(chalk.red(`\\n${(err as Error).message}`));\n process.exit(1);\n }\n\n const entries = loadTemplateManifest();\n const context = tokenContext(manifest);\n\n const reports: DriftReport[] = [];\n\n for (const entry of entries) {\n const required = isRequired(entry.required_when, manifest);\n const targetPath = resolve(cwd, entry.target);\n const exists = existsSync(targetPath);\n\n if (!required && !exists) continue;\n if (!required && exists) {\n reports.push({\n message: `Present but not required by the manifest profile (ok)`,\n severity: 'info',\n target: entry.target,\n });\n continue;\n }\n if (!exists) {\n reports.push({\n message: 'Missing',\n severity: 'error',\n target: entry.target,\n });\n continue;\n }\n\n // Exists + required — compare to rendered template\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n const current = readFileSync(targetPath, 'utf-8');\n reports.push(compareContent(entry, current, rendered));\n }\n\n console.log('');\n let errors = 0;\n let warnings = 0;\n let infos = 0;\n let oks = 0;\n\n for (const r of reports) {\n const icon = iconFor(r.severity);\n const line = `${icon} ${r.target}${r.message ? chalk.dim(` — ${r.message}`) : ''}`;\n console.log(line);\n if (r.severity === 'error') errors += 1;\n else if (r.severity === 'warning') warnings += 1;\n else if (r.severity === 'info') infos += 1;\n else oks += 1;\n }\n\n console.log('');\n console.log(chalk.dim(`${oks} ok, ${warnings} warning, ${errors} error, ${infos} info`));\n\n if (errors > 0) process.exit(1);\n}\n\nfunction compareContent(entry: TemplateEntry, current: string, rendered: string): DriftReport {\n if (current === rendered) {\n return { message: '', severity: 'ok', target: entry.target };\n }\n\n // Non-overwrite strategies don't re-render on sync — treat drift as\n // informational, not a warning. Makes the doctor output scannable:\n // warnings are the files sync WOULD change; infos are files where\n // drift is intentional (customized scaffold, preserved docs).\n if (entry.merge_strategy === 'preserve') {\n return {\n message: 'Differs from template (preserve strategy — suggestion only)',\n severity: 'info',\n target: entry.target,\n };\n }\n if (entry.merge_strategy === 'skip_if_exists') {\n return {\n message: 'Differs from template (scaffold-only; sync will not overwrite)',\n severity: 'info',\n target: entry.target,\n };\n }\n\n return {\n message: 'Differs from template (run `precisa sync` to update)',\n severity: 'warning',\n target: entry.target,\n };\n}\n\nfunction iconFor(severity: Severity): string {\n switch (severity) {\n case 'ok':\n return chalk.green('✓');\n case 'info':\n return chalk.blue('i');\n case 'warning':\n return chalk.yellow('!');\n case 'error':\n return chalk.red('✗');\n }\n}\n","import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { parse as parseYaml } from 'yaml';\n\nimport type { RequiredWhen } from '../manifest.js';\nimport { resolveTemplatesDir } from './paths.js';\n\nexport type MergeStrategy = 'overwrite' | 'merge_json' | 'preserve' | 'skip_if_exists';\n\nexport interface TemplateEntry {\n /** Whether to mark the rendered file executable (chmod +x). */\n executable?: boolean;\n /** How to merge when the target already exists. */\n merge_strategy: MergeStrategy;\n /** Gate for inclusion. */\n required_when: RequiredWhen;\n /** Path relative to templates/. */\n source: string;\n /** Path in the target repo (relative to the repo root). */\n target: string;\n}\n\ninterface TemplateManifestFile {\n templates: TemplateEntry[];\n}\n\n/**\n * Load the `templates.manifest.yml` from the bundled templates directory.\n * Throws if the file is missing or the shape is wrong.\n */\nexport function loadTemplateManifest(): TemplateEntry[] {\n const dir = resolveTemplatesDir();\n const manifestPath = resolve(dir, 'templates.manifest.yml');\n const raw = readFileSync(manifestPath, 'utf-8');\n const parsed = parseYaml(raw) as TemplateManifestFile | undefined;\n if (!parsed || !Array.isArray(parsed.templates)) {\n throw new Error(`${manifestPath}: expected { templates: [...] } at root`);\n }\n for (const [i, t] of parsed.templates.entries()) {\n if (!t.source || !t.target) {\n throw new Error(`${manifestPath}: entry ${i} is missing source or target`);\n }\n }\n return parsed.templates;\n}\n\nexport function readTemplateSource(entry: TemplateEntry): string {\n const dir = resolveTemplatesDir();\n const path = resolve(dir, entry.source);\n return readFileSync(path, 'utf-8');\n}\n\n/**\n * Substitute `{{TOKEN}}` placeholders with values from `context`. Unknown\n * tokens are left untouched (keeps the double braces visible so bad keys\n * are easy to spot in rendered output).\n *\n * Also processes conditional blocks:\n *\n * {{#if HAS_SITE}}\n * ...lines rendered only when HAS_SITE is truthy...\n * {{/if}}\n *\n * Markers can appear inside a host-language comment so the template stays\n * parseable by syntax-aware tools (prettier on YAML, for example):\n *\n * # {{#if HAS_SITE}}\n * ...\n * # {{/if}}\n *\n * A token is \"truthy\" when its string value is non-empty and not `\"false\"`.\n * Blocks may nest; they are expanded before token substitution so a block's\n * body can itself reference tokens.\n */\nexport function renderTokens(source: string, context: Record<string, string>): string {\n return renderTokenSubstitutions(renderConditionalBlocks(source, context), context);\n}\n\nfunction renderTokenSubstitutions(source: string, context: Record<string, string>): string {\n return source.replace(/\\{\\{([A-Z_]+)\\}\\}/g, (match, token: string) => {\n return Object.prototype.hasOwnProperty.call(context, token) ? context[token]! : match;\n });\n}\n\nfunction renderConditionalBlocks(source: string, context: Record<string, string>): string {\n // Match an entire line containing `{{#if TOKEN}}` (possibly wrapped in a\n // host-language comment like `# {{#if TOKEN}}` or `// {{#if TOKEN}}`),\n // up through the matching `{{/if}}` line. The whole marker line is\n // consumed so commented-out markers don't leak into rendered output.\n const pattern =\n /^[ \\t]*[^\\S\\n]*[^\\n]*\\{\\{#if ([A-Z_]+)\\}\\}[^\\n]*\\n([\\s\\S]*?)^[ \\t]*[^\\n]*\\{\\{\\/if\\}\\}[^\\n]*\\n?/gm;\n let prev: string;\n let out = source;\n // Re-run to handle nested blocks. Simple fixed-point loop keeps the\n // replacement rules uniform.\n do {\n prev = out;\n out = out.replace(pattern, (_match, token: string, body: string) => {\n const value = context[token];\n const truthy = value !== undefined && value !== '' && value !== 'false';\n return truthy ? body : '';\n });\n } while (out !== prev);\n return out;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Locate the bundled `templates/` directory.\n *\n * When published to npm, the templates live at `dist/templates/` inside\n * the CLI package (copied by `scripts/copy-templates.mjs` during build).\n *\n * When running from the monorepo (e.g. `pnpm --filter @precisa-saude/cli dev`),\n * the templates live at the repo root — fall back to walking up from the\n * package directory.\n */\nexport function resolveTemplatesDir(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n\n // Published case: cli package's dist/templates\n const bundled = resolve(here, 'templates');\n if (existsSync(bundled)) return bundled;\n\n // Dev case: walk up from packages/cli/{src|dist} to the monorepo root\n const repoRoot = resolve(here, '..', '..', '..', '..');\n const repoTemplates = resolve(repoRoot, 'templates');\n if (existsSync(repoTemplates)) return repoTemplates;\n\n // Sibling-in-package case (tsup output): packages/cli/dist -> ../../templates\n const packageParent = resolve(here, '..', '..', 'templates');\n if (existsSync(packageParent)) return packageParent;\n\n throw new Error(\n `Could not locate templates/ directory. Searched:\\n ${bundled}\\n ${repoTemplates}\\n ${packageParent}`,\n );\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\n/**\n * `.precisa.json` manifest — sits at the root of every consumer repo and\n * declares the repo's profile so `precisa sync` and `precisa doctor` know\n * which templates to render and which rules to enforce.\n */\nexport interface PrecisaManifest {\n /** Commitlint scope enum for this repo. */\n commitScopes: string[];\n\n /** Contact emails used in governance doc templates. */\n contactEmails: {\n security: string;\n conduct: string;\n };\n\n /** Does this repo have publishable packages/*? */\n hasPackages: boolean;\n\n /** Does this repo ship a website? Controls preview-deploy workflows. */\n hasSite: boolean;\n\n /** Repository name (typically matches the GitHub repo name). */\n name: string;\n\n /** Pinned runtime versions. Default: node=22, pnpm=9.15.9. */\n nodeVersion?: string;\n\n /** GitHub organization or user that owns the repo (e.g. `Precisa-Saude`). */\n owner: string;\n\n pnpmVersion?: string;\n\n /** Publishes any workspace package to npm? */\n publishesToNpm: boolean;\n\n /**\n * Workspace package directories (relative to repo root) that the\n * `publish` job in `ci.yml` should pass to `_publish.yml`. Only read\n * when `publishesToNpm: true`. Example: `[\"packages/core\", \"packages/cli\"]`.\n */\n publishPackages?: string[];\n\n /** Schema version of this manifest file. Bump when the schema changes. */\n schemaVersion: 1;\n\n /**\n * pnpm filter selector for the site package, passed to the deploy\n * workflow. Only read when `hasSite: true`. Example: `@my-repo/site`.\n */\n siteFilter?: string;\n\n /**\n * Cloudflare Pages project name for the deploy-site workflow. Only\n * read when `hasSite: true`.\n */\n siteProjectName?: string;\n\n /**\n * Path prefix (relative to repo root, trailing slash) treated as site\n * source for change detection in `_deploy-site.yml`. Defaults to\n * `site/` — override to `packages/site/` for monorepos where the site\n * lives under `packages/`.\n */\n siteSourcePath?: string;\n\n /** Public-OSS or private-internal. Controls which templates are rendered. */\n visibility: 'oss' | 'private';\n}\n\nexport const MANIFEST_FILENAME = '.precisa.json';\n\nexport const DEFAULT_MANIFEST_FIELDS = {\n hasPackages: true,\n hasSite: false,\n nodeVersion: '22',\n pnpmVersion: '9.15.9',\n publishesToNpm: true,\n schemaVersion: 1 as const,\n visibility: 'oss' as const,\n};\n\n/** Template gate values — `required_when` in templates.manifest.yml. */\nexport type RequiredWhen =\n | 'always'\n | 'never'\n | 'oss'\n | 'private'\n | 'has_site'\n | 'has_packages'\n | 'publishes_to_npm';\n\n/** Returns true when a template's `required_when` gate applies to this manifest. */\nexport function isRequired(when: RequiredWhen, manifest: PrecisaManifest): boolean {\n switch (when) {\n case 'always':\n return true;\n case 'never':\n return false;\n case 'oss':\n return manifest.visibility === 'oss';\n case 'private':\n return manifest.visibility === 'private';\n case 'has_site':\n return manifest.hasSite;\n case 'has_packages':\n return manifest.hasPackages;\n case 'publishes_to_npm':\n return manifest.publishesToNpm;\n default:\n return true;\n }\n}\n\n/**\n * Build the token substitution map from a manifest. Keys are `{{TOKEN}}`\n * (without braces); values are always strings.\n */\nexport function tokenContext(manifest: PrecisaManifest): Record<string, string> {\n return {\n COMMIT_SCOPES: manifest.commitScopes.join(','),\n // For human-readable docs (AGENTS.md, README) — backticked list.\n COMMIT_SCOPES_HUMAN: manifest.commitScopes.map((s) => `\\`${s}\\``).join(', '),\n // For `.commitlintrc.cjs` — scope array spelled as JS string literals,\n // ready to drop inside `[ ... ]`.\n COMMIT_SCOPES_JSON: manifest.commitScopes.map((s) => `'${s}'`).join(', '),\n CONDUCT_EMAIL: manifest.contactEmails.conduct,\n HAS_PACKAGES: String(manifest.hasPackages),\n HAS_SITE: String(manifest.hasSite),\n NODE_VERSION: manifest.nodeVersion ?? '22',\n OWNER_ORG: manifest.owner,\n PNPM_VERSION: manifest.pnpmVersion ?? '9.15.9',\n // YAML block-scalar body for the `packages: |` input of `_publish.yml`.\n // The template provides the first entry's indent; subsequent entries\n // get 8 spaces explicitly to match. Empty when no packages declared.\n PUBLISH_PACKAGES_YAML: (manifest.publishPackages ?? []).join('\\n '),\n PUBLISHES_TO_NPM: String(manifest.publishesToNpm),\n REPO_NAME: manifest.name,\n REPO_SLUG: `${manifest.owner}/${manifest.name}`,\n SECURITY_EMAIL: manifest.contactEmails.security,\n SITE_FILTER: manifest.siteFilter ?? '',\n SITE_PROJECT_NAME: manifest.siteProjectName ?? '',\n SITE_SOURCE_PATH: manifest.siteSourcePath ?? 'site/',\n VISIBILITY: manifest.visibility,\n };\n}\n\nexport interface ManifestValidationError {\n message: string;\n path: string;\n}\n\nexport function validateManifest(raw: unknown): ManifestValidationError[] {\n const errors: ManifestValidationError[] = [];\n const m = raw as Partial<PrecisaManifest> | undefined;\n if (!m || typeof m !== 'object') {\n return [{ message: 'manifest must be a JSON object', path: '$' }];\n }\n if (m.schemaVersion !== 1) {\n errors.push({ message: 'must be 1', path: 'schemaVersion' });\n }\n if (typeof m.name !== 'string' || !m.name) {\n errors.push({ message: 'must be a non-empty string', path: 'name' });\n }\n if (typeof m.owner !== 'string' || !m.owner) {\n errors.push({ message: 'must be a non-empty string', path: 'owner' });\n }\n if (m.visibility !== 'oss' && m.visibility !== 'private') {\n errors.push({ message: \"must be 'oss' or 'private'\", path: 'visibility' });\n }\n for (const key of ['hasSite', 'hasPackages', 'publishesToNpm'] as const) {\n if (typeof m[key] !== 'boolean') {\n errors.push({ message: 'must be a boolean', path: key });\n }\n }\n if (!Array.isArray(m.commitScopes)) {\n errors.push({ message: 'must be an array of strings', path: 'commitScopes' });\n }\n if (m.publishPackages !== undefined) {\n if (!Array.isArray(m.publishPackages)) {\n errors.push({ message: 'must be an array of strings', path: 'publishPackages' });\n } else if (m.publishPackages.some((p) => typeof p !== 'string' || !p)) {\n errors.push({ message: 'entries must be non-empty strings', path: 'publishPackages' });\n }\n }\n if (m.publishesToNpm) {\n if (!Array.isArray(m.publishPackages) || m.publishPackages.length === 0) {\n errors.push({\n message: 'must have at least one entry when publishesToNpm is true',\n path: 'publishPackages',\n });\n }\n }\n if (m.hasSite === true) {\n for (const key of ['siteProjectName', 'siteFilter'] as const) {\n if (typeof m[key] !== 'string' || !m[key]) {\n errors.push({ message: 'required and non-empty when hasSite is true', path: key });\n }\n }\n }\n if (m.siteProjectName !== undefined && typeof m.siteProjectName !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteProjectName' });\n }\n if (m.siteFilter !== undefined && typeof m.siteFilter !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteFilter' });\n }\n if (m.siteSourcePath !== undefined && typeof m.siteSourcePath !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteSourcePath' });\n }\n if (!m.contactEmails || typeof m.contactEmails !== 'object') {\n errors.push({ message: 'must be an object', path: 'contactEmails' });\n } else {\n for (const key of ['security', 'conduct'] as const) {\n if (typeof m.contactEmails[key] !== 'string' || !m.contactEmails[key]) {\n errors.push({\n message: 'must be a non-empty string',\n path: `contactEmails.${key}`,\n });\n }\n }\n }\n return errors;\n}\n\nexport function loadManifest(cwd: string): PrecisaManifest {\n const path = resolve(cwd, MANIFEST_FILENAME);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, 'utf-8'));\n } catch (err) {\n throw new Error(`Failed to read ${MANIFEST_FILENAME} at ${path}: ${(err as Error).message}`);\n }\n const errors = validateManifest(raw);\n if (errors.length > 0) {\n const detail = errors.map((e) => ` - ${e.path}: ${e.message}`).join('\\n');\n throw new Error(`Invalid ${MANIFEST_FILENAME}:\\n${detail}`);\n }\n return raw as PrecisaManifest;\n}\n\nexport function writeManifest(cwd: string, manifest: PrecisaManifest): void {\n const path = resolve(cwd, MANIFEST_FILENAME);\n writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\\n`);\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport prompts from 'prompts';\n\nimport { applyTemplate } from '../lib/merge.js';\nimport { loadTemplateManifest, readTemplateSource, renderTokens } from '../lib/templates.js';\nimport {\n DEFAULT_MANIFEST_FIELDS,\n isRequired,\n type PrecisaManifest,\n tokenContext,\n writeManifest,\n} from '../manifest.js';\n\nexport interface NewOptions {\n conductEmail?: string;\n dryRun: boolean;\n /** Skip interactive prompts; require --owner/--scopes/--*-email flags. */\n nonInteractive?: boolean;\n owner?: string;\n profile: string;\n /** Comma-separated list, e.g. \"core,docs,ci,deps\". */\n scopes?: string;\n securityEmail?: string;\n}\n\nconst PROFILES = {\n 'oss-library': {\n hasPackages: true,\n hasSite: false,\n publishesToNpm: true,\n visibility: 'oss',\n },\n 'oss-site': {\n hasPackages: false,\n hasSite: true,\n publishesToNpm: false,\n visibility: 'oss',\n },\n 'private-app': {\n hasPackages: true,\n hasSite: true,\n publishesToNpm: false,\n visibility: 'private',\n },\n} as const satisfies Record<\n string,\n Pick<PrecisaManifest, 'visibility' | 'hasSite' | 'hasPackages' | 'publishesToNpm'>\n>;\n\nexport async function runNew(repoName: string, opts: NewOptions): Promise<void> {\n const targetDir = resolve(process.cwd(), repoName);\n\n if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {\n console.error(chalk.red(`\\nError: ${targetDir} already exists and is not empty.`));\n process.exit(1);\n }\n\n const profile = PROFILES[opts.profile as keyof typeof PROFILES];\n if (!profile) {\n console.error(\n chalk.red(`\\nError: unknown profile '${opts.profile}'. Choose one of:`),\n Object.keys(PROFILES).join(', '),\n );\n process.exit(1);\n }\n\n console.log(chalk.bold.cyan(`\\nprecisa new ${repoName}`));\n console.log(chalk.dim(`profile: ${opts.profile}${opts.dryRun ? ' (dry-run)' : ''}`));\n console.log(chalk.dim(`target: ${targetDir}\\n`));\n\n const answers = opts.nonInteractive\n ? {\n commitScopes: (opts.scopes ?? 'docs,ci,deps')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n conductEmail: opts.conductEmail ?? 'conduct@precisa-saude.com.br',\n owner: opts.owner ?? 'Precisa-Saude',\n securityEmail: opts.securityEmail ?? 'security@precisa-saude.com.br',\n }\n : await prompts(\n [\n {\n initial: opts.owner ?? 'Precisa-Saude',\n message: 'GitHub owner (org or user):',\n name: 'owner',\n type: 'text',\n },\n {\n initial: opts.securityEmail ?? 'security@precisa-saude.com.br',\n message: 'Security contact email:',\n name: 'securityEmail',\n type: 'text',\n },\n {\n initial: opts.conductEmail ?? 'conduct@precisa-saude.com.br',\n message: 'Code-of-conduct contact email:',\n name: 'conductEmail',\n type: 'text',\n },\n {\n initial: opts.scopes ?? 'docs,ci,deps',\n message: 'Commit scopes (comma-separated):',\n name: 'commitScopes',\n separator: ',',\n type: 'list',\n },\n ],\n { onCancel: () => process.exit(1) },\n );\n\n const manifest: PrecisaManifest = {\n ...DEFAULT_MANIFEST_FIELDS,\n ...profile,\n commitScopes: answers.commitScopes,\n contactEmails: {\n conduct: answers.conductEmail,\n security: answers.securityEmail,\n },\n name: repoName,\n owner: answers.owner,\n };\n\n const spinner = ora('Rendering templates').start();\n try {\n if (!opts.dryRun) mkdirSync(targetDir, { recursive: true });\n\n const entries = loadTemplateManifest().filter((e) => isRequired(e.required_when, manifest));\n const context = tokenContext(manifest);\n\n let created = 0;\n let skipped = 0;\n\n for (const entry of entries) {\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n const outcome = applyTemplate({\n cwd: targetDir,\n dryRun: opts.dryRun,\n entry,\n rendered,\n });\n if (outcome.kind === 'create') created += 1;\n else if (outcome.kind === 'skip-exists') skipped += 1;\n else if (outcome.kind === 'error') {\n spinner.fail(`Failed on ${entry.target}`);\n console.error(chalk.red(outcome.message));\n process.exit(1);\n }\n }\n\n spinner.succeed(\n opts.dryRun\n ? `Would render ${created} file${created === 1 ? '' : 's'} (${skipped} skipped)`\n : `Rendered ${created} file${created === 1 ? '' : 's'} (${skipped} skipped)`,\n );\n\n if (opts.dryRun) return;\n\n writeManifest(targetDir, manifest);\n console.log(chalk.dim(` wrote .precisa.json`));\n\n const gitStep = ora('git init + pnpm install').start();\n try {\n execSync('git init --initial-branch=main', { cwd: targetDir, stdio: 'pipe' });\n execSync('pnpm install', { cwd: targetDir, stdio: 'pipe' });\n gitStep.succeed('git init + pnpm install complete');\n } catch (err) {\n gitStep.warn(\n `git/pnpm setup skipped: ${(err as Error).message}. Run manually in ${targetDir}.`,\n );\n }\n\n console.log(chalk.bold.green(`\\n✓ ${repoName} scaffolded at ${targetDir}`));\n console.log(chalk.dim('\\nNext:'));\n console.log(chalk.dim(` cd ${repoName}`));\n console.log(chalk.dim(` # start adding your code`));\n } catch (err) {\n spinner.fail((err as Error).message);\n process.exit(1);\n }\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\nimport type { MergeStrategy, TemplateEntry } from './templates.js';\n\nexport type ApplyOutcome =\n | { kind: 'create'; target: string; rendered: string }\n | { kind: 'update'; target: string; previous: string; rendered: string }\n | { kind: 'skip-identical'; target: string }\n | { kind: 'preserve'; target: string; current: string; rendered: string }\n | { kind: 'skip-exists'; target: string }\n | { kind: 'merge-json'; target: string; previous: string; rendered: string }\n | { kind: 'error'; target: string; message: string };\n\nexport interface ApplyOptions {\n /** Repo root to apply into. */\n cwd: string;\n /** When true, compute the outcome but do not write to disk. */\n dryRun: boolean;\n /** Template entry being applied. */\n entry: TemplateEntry;\n /** Rendered template content (post token substitution). */\n rendered: string;\n}\n\n/**\n * Apply a single template file to the target repo. Returns the outcome\n * so callers can print a per-file status row and, on dry-run, a diff.\n */\nexport function applyTemplate({ cwd, dryRun, entry, rendered }: ApplyOptions): ApplyOutcome {\n const targetPath = resolve(cwd, entry.target);\n const exists = existsSync(targetPath);\n\n if (!exists) {\n if (!dryRun) writeFile(targetPath, rendered, entry.executable === true);\n return { kind: 'create', rendered, target: entry.target };\n }\n\n const current = readFileSync(targetPath, 'utf-8');\n\n switch (entry.merge_strategy as MergeStrategy) {\n case 'overwrite': {\n if (current === rendered) {\n return { kind: 'skip-identical', target: entry.target };\n }\n if (!dryRun) writeFile(targetPath, rendered, entry.executable === true);\n return { kind: 'update', previous: current, rendered, target: entry.target };\n }\n case 'skip_if_exists': {\n return { kind: 'skip-exists', target: entry.target };\n }\n case 'preserve': {\n return { current, kind: 'preserve', rendered, target: entry.target };\n }\n case 'merge_json': {\n let merged: string;\n try {\n merged = mergeJson(current, rendered);\n } catch (err) {\n return {\n kind: 'error',\n message: `JSON merge failed: ${(err as Error).message}`,\n target: entry.target,\n };\n }\n if (current === merged) {\n return { kind: 'skip-identical', target: entry.target };\n }\n if (!dryRun) writeFile(targetPath, merged, entry.executable === true);\n return { kind: 'merge-json', previous: current, rendered: merged, target: entry.target };\n }\n default: {\n return {\n kind: 'error',\n message: `Unknown merge_strategy '${entry.merge_strategy}'`,\n target: entry.target,\n };\n }\n }\n}\n\nfunction writeFile(path: string, contents: string, executable: boolean): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, contents);\n if (executable) chmodSync(path, 0o755);\n}\n\n/**\n * Shallow 3-way-ish JSON merge — the current file wins on conflicts so\n * repo-local customizations aren't clobbered. Objects are merged\n * key-by-key; arrays and scalars are replaced entirely by the current\n * value when present (falls back to the template value).\n *\n * If parsing fails, throws so the caller can report the error.\n */\nexport function mergeJson(currentRaw: string, templateRaw: string): string {\n const current = JSON.parse(currentRaw) as unknown;\n const template = JSON.parse(templateRaw) as unknown;\n const merged = mergeValue(template, current);\n return `${JSON.stringify(merged, null, 2)}\\n`;\n}\n\nfunction mergeValue(template: unknown, current: unknown): unknown {\n if (current === undefined) return template;\n if (\n typeof template !== 'object' ||\n template === null ||\n Array.isArray(template) ||\n typeof current !== 'object' ||\n current === null ||\n Array.isArray(current)\n ) {\n // Scalars / arrays: current value wins (never clobber repo-local values).\n return current;\n }\n const out: Record<string, unknown> = {};\n const keys = new Set([\n ...Object.keys(template as Record<string, unknown>),\n ...Object.keys(current as Record<string, unknown>),\n ]);\n for (const k of keys) {\n out[k] = mergeValue(\n (template as Record<string, unknown>)[k],\n (current as Record<string, unknown>)[k],\n );\n }\n return out;\n}\n","import chalk from 'chalk';\n\nimport { colorDiff } from '../lib/diff.js';\nimport { type ApplyOutcome, applyTemplate } from '../lib/merge.js';\nimport { loadTemplateManifest, readTemplateSource, renderTokens } from '../lib/templates.js';\nimport { isRequired, loadManifest, tokenContext } from '../manifest.js';\n\nexport interface SyncOptions {\n dryRun: boolean;\n}\n\nexport async function runSync(opts: SyncOptions): Promise<void> {\n const cwd = process.cwd();\n console.log(chalk.bold.cyan(`\\nprecisa sync${opts.dryRun ? ' --dry-run' : ''}`));\n\n let manifest;\n try {\n manifest = loadManifest(cwd);\n } catch (err) {\n console.error(chalk.red(`\\n${(err as Error).message}`));\n console.error(\n chalk.dim('\\n Run `precisa new <repo>` in an empty directory to scaffold a new repo,'),\n );\n console.error(chalk.dim(' or create a `.precisa.json` manifest manually.'));\n process.exit(1);\n }\n\n const entries = loadTemplateManifest().filter((e) => isRequired(e.required_when, manifest));\n const context = tokenContext(manifest);\n\n const outcomes: ApplyOutcome[] = [];\n for (const entry of entries) {\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n outcomes.push(\n applyTemplate({\n cwd,\n dryRun: opts.dryRun,\n entry,\n rendered,\n }),\n );\n }\n\n console.log('');\n for (const o of outcomes) {\n printOutcome(o, opts.dryRun);\n }\n\n const summary = summarize(outcomes);\n console.log('');\n console.log(\n chalk.dim(\n `${summary.create} create, ${summary.update} update, ${summary.mergeJson} merge-json, ${summary.preserve} preserve, ${summary.skip} skip, ${summary.error} error`,\n ),\n );\n\n if (summary.error > 0) process.exit(1);\n}\n\ninterface Summary {\n create: number;\n error: number;\n mergeJson: number;\n preserve: number;\n skip: number;\n update: number;\n}\n\nfunction summarize(outcomes: ApplyOutcome[]): Summary {\n const s: Summary = { create: 0, error: 0, mergeJson: 0, preserve: 0, skip: 0, update: 0 };\n for (const o of outcomes) {\n switch (o.kind) {\n case 'create':\n s.create += 1;\n break;\n case 'update':\n s.update += 1;\n break;\n case 'merge-json':\n s.mergeJson += 1;\n break;\n case 'preserve':\n s.preserve += 1;\n break;\n case 'skip-identical':\n case 'skip-exists':\n s.skip += 1;\n break;\n case 'error':\n s.error += 1;\n break;\n }\n }\n return s;\n}\n\nfunction printOutcome(o: ApplyOutcome, dryRun: boolean): void {\n const prefix = dryRun ? '(dry-run) ' : '';\n switch (o.kind) {\n case 'create':\n console.log(`${chalk.green('+')} ${prefix}create ${o.target}`);\n return;\n case 'update':\n console.log(`${chalk.yellow('~')} ${prefix}update ${o.target}`);\n if (dryRun) console.log(indent(colorDiff(o.target, o.previous, o.rendered)));\n return;\n case 'merge-json':\n console.log(`${chalk.yellow('~')} ${prefix}merge ${o.target}`);\n if (dryRun) console.log(indent(colorDiff(o.target, o.previous, o.rendered)));\n return;\n case 'preserve':\n console.log(\n `${chalk.blue('i')} ${prefix}preserve ${o.target} (template differs; not written)`,\n );\n if (dryRun && o.current !== o.rendered) {\n console.log(indent(colorDiff(o.target, o.current, o.rendered)));\n }\n return;\n case 'skip-identical':\n console.log(`${chalk.dim('=')} ${prefix}unchanged ${o.target}`);\n return;\n case 'skip-exists':\n console.log(`${chalk.dim('s')} ${prefix}skip ${o.target} (already exists)`);\n return;\n case 'error':\n console.log(`${chalk.red('!')} ${prefix}error ${o.target}: ${o.message}`);\n return;\n }\n}\n\nfunction indent(text: string): string {\n return text\n .split('\\n')\n .map((l) => ` ${l}`)\n .join('\\n');\n}\n","import chalk from 'chalk';\nimport { createPatch } from 'diff';\n\n/**\n * Format a unified diff with ANSI colors for terminal display.\n * Skips the `@@ hunk @@` metadata lines for a cleaner look.\n */\nexport function colorDiff(filename: string, previous: string, next: string): string {\n const patch = createPatch(filename, previous, next, '', '');\n const lines = patch.split('\\n');\n const out: string[] = [];\n for (const line of lines) {\n if (line.startsWith('---') || line.startsWith('+++')) continue;\n if (line.startsWith('@@')) {\n out.push(chalk.cyan(line));\n continue;\n }\n if (line.startsWith('+')) {\n out.push(chalk.green(line));\n continue;\n }\n if (line.startsWith('-')) {\n out.push(chalk.red(line));\n continue;\n }\n out.push(line);\n }\n return out.join('\\n');\n}\n"],"mappings":"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","names":["existsSync","readFileSync","resolve","resolve","resolve","readFileSync","resolve","resolve","existsSync","readFileSync","existsSync","mkdirSync","resolve","chalk","existsSync","readFileSync","writeFileSync","dirname","resolve","resolve","existsSync","chalk","mkdirSync","chalk","chalk","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/doctor.ts","../src/lib/templates.ts","../src/lib/paths.ts","../src/manifest.ts","../src/commands/new.ts","../src/lib/merge.ts","../src/commands/sync.ts","../src/lib/diff.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport chalk from 'chalk';\n\nimport {\n loadTemplateManifest,\n readTemplateSource,\n renderTokens,\n type TemplateEntry,\n} from '../lib/templates.js';\nimport { isRequired, loadManifest, tokenContext } from '../manifest.js';\n\ntype Severity = 'ok' | 'info' | 'warning' | 'error';\n\ninterface DriftReport {\n message: string;\n severity: Severity;\n target: string;\n}\n\nexport async function runDoctor(): Promise<void> {\n const cwd = process.cwd();\n console.log(chalk.bold.cyan('\\nprecisa doctor'));\n\n let manifest;\n try {\n manifest = loadManifest(cwd);\n } catch (err) {\n console.error(chalk.red(`\\n${(err as Error).message}`));\n process.exit(1);\n }\n\n const entries = loadTemplateManifest();\n const context = tokenContext(manifest);\n\n const reports: DriftReport[] = [];\n\n for (const entry of entries) {\n const required = isRequired(entry.required_when, manifest);\n const targetPath = resolve(cwd, entry.target);\n const exists = existsSync(targetPath);\n\n if (!required && !exists) continue;\n if (!required && exists) {\n reports.push({\n message: `Present but not required by the manifest profile (ok)`,\n severity: 'info',\n target: entry.target,\n });\n continue;\n }\n if (!exists) {\n reports.push({\n message: 'Missing',\n severity: 'error',\n target: entry.target,\n });\n continue;\n }\n\n // Exists + required — compare to rendered template\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n const current = readFileSync(targetPath, 'utf-8');\n reports.push(compareContent(entry, current, rendered));\n }\n\n console.log('');\n let errors = 0;\n let warnings = 0;\n let infos = 0;\n let oks = 0;\n\n for (const r of reports) {\n const icon = iconFor(r.severity);\n const line = `${icon} ${r.target}${r.message ? chalk.dim(` — ${r.message}`) : ''}`;\n console.log(line);\n if (r.severity === 'error') errors += 1;\n else if (r.severity === 'warning') warnings += 1;\n else if (r.severity === 'info') infos += 1;\n else oks += 1;\n }\n\n console.log('');\n console.log(chalk.dim(`${oks} ok, ${warnings} warning, ${errors} error, ${infos} info`));\n\n if (errors > 0) process.exit(1);\n}\n\nfunction compareContent(entry: TemplateEntry, current: string, rendered: string): DriftReport {\n if (current === rendered) {\n return { message: '', severity: 'ok', target: entry.target };\n }\n\n // Non-overwrite strategies don't re-render on sync — treat drift as\n // informational, not a warning. Makes the doctor output scannable:\n // warnings are the files sync WOULD change; infos are files where\n // drift is intentional (customized scaffold, preserved docs).\n if (entry.merge_strategy === 'preserve') {\n return {\n message: 'Differs from template (preserve strategy — suggestion only)',\n severity: 'info',\n target: entry.target,\n };\n }\n if (entry.merge_strategy === 'skip_if_exists') {\n return {\n message: 'Differs from template (scaffold-only; sync will not overwrite)',\n severity: 'info',\n target: entry.target,\n };\n }\n\n return {\n message: 'Differs from template (run `precisa sync` to update)',\n severity: 'warning',\n target: entry.target,\n };\n}\n\nfunction iconFor(severity: Severity): string {\n switch (severity) {\n case 'ok':\n return chalk.green('✓');\n case 'info':\n return chalk.blue('i');\n case 'warning':\n return chalk.yellow('!');\n case 'error':\n return chalk.red('✗');\n }\n}\n","import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { parse as parseYaml } from 'yaml';\n\nimport type { RequiredWhen } from '../manifest.js';\nimport { resolveTemplatesDir } from './paths.js';\n\nexport type MergeStrategy = 'overwrite' | 'merge_json' | 'preserve' | 'skip_if_exists';\n\nexport interface TemplateEntry {\n /** Whether to mark the rendered file executable (chmod +x). */\n executable?: boolean;\n /** How to merge when the target already exists. */\n merge_strategy: MergeStrategy;\n /** Gate for inclusion. */\n required_when: RequiredWhen;\n /** Path relative to templates/. */\n source: string;\n /** Path in the target repo (relative to the repo root). */\n target: string;\n}\n\ninterface TemplateManifestFile {\n templates: TemplateEntry[];\n}\n\n/**\n * Load the `templates.manifest.yml` from the bundled templates directory.\n * Throws if the file is missing or the shape is wrong.\n */\nexport function loadTemplateManifest(): TemplateEntry[] {\n const dir = resolveTemplatesDir();\n const manifestPath = resolve(dir, 'templates.manifest.yml');\n const raw = readFileSync(manifestPath, 'utf-8');\n const parsed = parseYaml(raw) as TemplateManifestFile | undefined;\n if (!parsed || !Array.isArray(parsed.templates)) {\n throw new Error(`${manifestPath}: expected { templates: [...] } at root`);\n }\n for (const [i, t] of parsed.templates.entries()) {\n if (!t.source || !t.target) {\n throw new Error(`${manifestPath}: entry ${i} is missing source or target`);\n }\n }\n return parsed.templates;\n}\n\nexport function readTemplateSource(entry: TemplateEntry): string {\n const dir = resolveTemplatesDir();\n const path = resolve(dir, entry.source);\n return readFileSync(path, 'utf-8');\n}\n\n/**\n * Substitute `{{TOKEN}}` placeholders with values from `context`. Unknown\n * tokens are left untouched (keeps the double braces visible so bad keys\n * are easy to spot in rendered output).\n *\n * Also processes conditional blocks:\n *\n * {{#if HAS_SITE}}\n * ...lines rendered only when HAS_SITE is truthy...\n * {{/if}}\n *\n * Markers can appear inside a host-language comment so the template stays\n * parseable by syntax-aware tools (prettier on YAML, for example):\n *\n * # {{#if HAS_SITE}}\n * ...\n * # {{/if}}\n *\n * A token is \"truthy\" when its string value is non-empty and not `\"false\"`.\n * Blocks may nest; they are expanded before token substitution so a block's\n * body can itself reference tokens.\n */\nexport function renderTokens(source: string, context: Record<string, string>): string {\n return renderTokenSubstitutions(renderConditionalBlocks(source, context), context);\n}\n\nfunction renderTokenSubstitutions(source: string, context: Record<string, string>): string {\n return source.replace(/\\{\\{([A-Z_]+)\\}\\}/g, (match, token: string) => {\n return Object.prototype.hasOwnProperty.call(context, token) ? context[token]! : match;\n });\n}\n\nfunction renderConditionalBlocks(source: string, context: Record<string, string>): string {\n // Match an entire line containing `{{#if TOKEN}}` (possibly wrapped in a\n // host-language comment like `# {{#if TOKEN}}` or `// {{#if TOKEN}}`),\n // up through the matching `{{/if}}` line. The whole marker line is\n // consumed so commented-out markers don't leak into rendered output.\n const pattern =\n /^[ \\t]*[^\\S\\n]*[^\\n]*\\{\\{#if ([A-Z_]+)\\}\\}[^\\n]*\\n([\\s\\S]*?)^[ \\t]*[^\\n]*\\{\\{\\/if\\}\\}[^\\n]*\\n?/gm;\n let prev: string;\n let out = source;\n // Re-run to handle nested blocks. Simple fixed-point loop keeps the\n // replacement rules uniform.\n do {\n prev = out;\n out = out.replace(pattern, (_match, token: string, body: string) => {\n const value = context[token];\n const truthy = value !== undefined && value !== '' && value !== 'false';\n return truthy ? body : '';\n });\n } while (out !== prev);\n return out;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Locate the bundled `templates/` directory.\n *\n * When published to npm, the templates live at `dist/templates/` inside\n * the CLI package (copied by `scripts/copy-templates.mjs` during build).\n *\n * When running from the monorepo (e.g. `pnpm --filter @precisa-saude/cli dev`),\n * the templates live at the repo root — fall back to walking up from the\n * package directory.\n */\nexport function resolveTemplatesDir(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n\n // Published case: cli package's dist/templates\n const bundled = resolve(here, 'templates');\n if (existsSync(bundled)) return bundled;\n\n // Dev case: walk up from packages/cli/{src|dist} to the monorepo root\n const repoRoot = resolve(here, '..', '..', '..', '..');\n const repoTemplates = resolve(repoRoot, 'templates');\n if (existsSync(repoTemplates)) return repoTemplates;\n\n // Sibling-in-package case (tsup output): packages/cli/dist -> ../../templates\n const packageParent = resolve(here, '..', '..', 'templates');\n if (existsSync(packageParent)) return packageParent;\n\n throw new Error(\n `Could not locate templates/ directory. Searched:\\n ${bundled}\\n ${repoTemplates}\\n ${packageParent}`,\n );\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\n/**\n * `.precisa.json` manifest — sits at the root of every consumer repo and\n * declares the repo's profile so `precisa sync` and `precisa doctor` know\n * which templates to render and which rules to enforce.\n */\nexport interface PrecisaManifest {\n /** Commitlint scope enum for this repo. */\n commitScopes: string[];\n\n /** Contact emails used in governance doc templates. */\n contactEmails: {\n security: string;\n conduct: string;\n };\n\n /** Does this repo have publishable packages/*? */\n hasPackages: boolean;\n\n /** Does this repo ship a website? Controls preview-deploy workflows. */\n hasSite: boolean;\n\n /** Repository name (typically matches the GitHub repo name). */\n name: string;\n\n /** Pinned runtime versions. Default: node=22, pnpm=9.15.9. */\n nodeVersion?: string;\n\n /** GitHub organization or user that owns the repo (e.g. `Precisa-Saude`). */\n owner: string;\n\n pnpmVersion?: string;\n\n /** Publishes any workspace package to npm? */\n publishesToNpm: boolean;\n\n /**\n * Workspace package directories (relative to repo root) that the\n * `publish` job in `ci.yml` should pass to `_publish.yml`. Only read\n * when `publishesToNpm: true`. Example: `[\"packages/core\", \"packages/cli\"]`.\n */\n publishPackages?: string[];\n\n /** Schema version of this manifest file. Bump when the schema changes. */\n schemaVersion: 1;\n\n /**\n * pnpm filter selector for the site package, passed to the deploy\n * workflow. Only read when `hasSite: true`. Example: `@my-repo/site`.\n */\n siteFilter?: string;\n\n /**\n * Cloudflare Pages project name for the deploy-site workflow. Only\n * read when `hasSite: true`.\n */\n siteProjectName?: string;\n\n /**\n * Path prefix (relative to repo root, trailing slash) treated as site\n * source for change detection in `_deploy-site.yml`. Defaults to\n * `site/` — override to `packages/site/` for monorepos where the site\n * lives under `packages/`.\n */\n siteSourcePath?: string;\n\n /** Public-OSS or private-internal. Controls which templates are rendered. */\n visibility: 'oss' | 'private';\n}\n\nexport const MANIFEST_FILENAME = '.precisa.json';\n\nexport const DEFAULT_MANIFEST_FIELDS = {\n hasPackages: true,\n hasSite: false,\n nodeVersion: '22',\n pnpmVersion: '9.15.9',\n publishesToNpm: true,\n schemaVersion: 1 as const,\n visibility: 'oss' as const,\n};\n\n/** Template gate values — `required_when` in templates.manifest.yml. */\nexport type RequiredWhen =\n | 'always'\n | 'never'\n | 'oss'\n | 'private'\n | 'has_site'\n | 'has_packages'\n | 'publishes_to_npm';\n\n/** Returns true when a template's `required_when` gate applies to this manifest. */\nexport function isRequired(when: RequiredWhen, manifest: PrecisaManifest): boolean {\n switch (when) {\n case 'always':\n return true;\n case 'never':\n return false;\n case 'oss':\n return manifest.visibility === 'oss';\n case 'private':\n return manifest.visibility === 'private';\n case 'has_site':\n return manifest.hasSite;\n case 'has_packages':\n return manifest.hasPackages;\n case 'publishes_to_npm':\n return manifest.publishesToNpm;\n default:\n return true;\n }\n}\n\n/**\n * Build the token substitution map from a manifest. Keys are `{{TOKEN}}`\n * (without braces); values are always strings.\n */\nexport function tokenContext(manifest: PrecisaManifest): Record<string, string> {\n return {\n COMMIT_SCOPES: manifest.commitScopes.join(','),\n // For human-readable docs (AGENTS.md, README) — backticked list.\n COMMIT_SCOPES_HUMAN: manifest.commitScopes.map((s) => `\\`${s}\\``).join(', '),\n // For `.commitlintrc.cjs` — scope array spelled as JS string literals,\n // ready to drop inside `[ ... ]`.\n COMMIT_SCOPES_JSON: manifest.commitScopes.map((s) => `'${s}'`).join(', '),\n CONDUCT_EMAIL: manifest.contactEmails.conduct,\n HAS_PACKAGES: String(manifest.hasPackages),\n HAS_SITE: String(manifest.hasSite),\n NODE_VERSION: manifest.nodeVersion ?? '22',\n OWNER_ORG: manifest.owner,\n PNPM_VERSION: manifest.pnpmVersion ?? '9.15.9',\n // YAML block-scalar body for the `packages: |` input of `_publish.yml`.\n // The template provides the first entry's indent; subsequent entries\n // get 8 spaces explicitly to match. Empty when no packages declared.\n PUBLISH_PACKAGES_YAML: (manifest.publishPackages ?? []).join('\\n '),\n PUBLISHES_TO_NPM: String(manifest.publishesToNpm),\n REPO_NAME: manifest.name,\n REPO_SLUG: `${manifest.owner}/${manifest.name}`,\n SECURITY_EMAIL: manifest.contactEmails.security,\n SITE_FILTER: manifest.siteFilter ?? '',\n SITE_PROJECT_NAME: manifest.siteProjectName ?? '',\n SITE_SOURCE_PATH: manifest.siteSourcePath ?? 'site/',\n VISIBILITY: manifest.visibility,\n };\n}\n\nexport interface ManifestValidationError {\n message: string;\n path: string;\n}\n\nexport function validateManifest(raw: unknown): ManifestValidationError[] {\n const errors: ManifestValidationError[] = [];\n const m = raw as Partial<PrecisaManifest> | undefined;\n if (!m || typeof m !== 'object') {\n return [{ message: 'manifest must be a JSON object', path: '$' }];\n }\n if (m.schemaVersion !== 1) {\n errors.push({ message: 'must be 1', path: 'schemaVersion' });\n }\n if (typeof m.name !== 'string' || !m.name) {\n errors.push({ message: 'must be a non-empty string', path: 'name' });\n }\n if (typeof m.owner !== 'string' || !m.owner) {\n errors.push({ message: 'must be a non-empty string', path: 'owner' });\n }\n if (m.visibility !== 'oss' && m.visibility !== 'private') {\n errors.push({ message: \"must be 'oss' or 'private'\", path: 'visibility' });\n }\n for (const key of ['hasSite', 'hasPackages', 'publishesToNpm'] as const) {\n if (typeof m[key] !== 'boolean') {\n errors.push({ message: 'must be a boolean', path: key });\n }\n }\n if (!Array.isArray(m.commitScopes)) {\n errors.push({ message: 'must be an array of strings', path: 'commitScopes' });\n }\n if (m.publishPackages !== undefined) {\n if (!Array.isArray(m.publishPackages)) {\n errors.push({ message: 'must be an array of strings', path: 'publishPackages' });\n } else if (m.publishPackages.some((p) => typeof p !== 'string' || !p)) {\n errors.push({ message: 'entries must be non-empty strings', path: 'publishPackages' });\n }\n }\n if (m.publishesToNpm) {\n if (!Array.isArray(m.publishPackages) || m.publishPackages.length === 0) {\n errors.push({\n message: 'must have at least one entry when publishesToNpm is true',\n path: 'publishPackages',\n });\n }\n }\n if (m.hasSite === true) {\n for (const key of ['siteProjectName', 'siteFilter'] as const) {\n if (typeof m[key] !== 'string' || !m[key]) {\n errors.push({ message: 'required and non-empty when hasSite is true', path: key });\n }\n }\n }\n if (m.siteProjectName !== undefined && typeof m.siteProjectName !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteProjectName' });\n }\n if (m.siteFilter !== undefined && typeof m.siteFilter !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteFilter' });\n }\n if (m.siteSourcePath !== undefined && typeof m.siteSourcePath !== 'string') {\n errors.push({ message: 'must be a string', path: 'siteSourcePath' });\n }\n if (!m.contactEmails || typeof m.contactEmails !== 'object') {\n errors.push({ message: 'must be an object', path: 'contactEmails' });\n } else {\n for (const key of ['security', 'conduct'] as const) {\n if (typeof m.contactEmails[key] !== 'string' || !m.contactEmails[key]) {\n errors.push({\n message: 'must be a non-empty string',\n path: `contactEmails.${key}`,\n });\n }\n }\n }\n return errors;\n}\n\nexport function loadManifest(cwd: string): PrecisaManifest {\n const path = resolve(cwd, MANIFEST_FILENAME);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, 'utf-8'));\n } catch (err) {\n throw new Error(`Failed to read ${MANIFEST_FILENAME} at ${path}: ${(err as Error).message}`);\n }\n const errors = validateManifest(raw);\n if (errors.length > 0) {\n const detail = errors.map((e) => ` - ${e.path}: ${e.message}`).join('\\n');\n throw new Error(`Invalid ${MANIFEST_FILENAME}:\\n${detail}`);\n }\n return raw as PrecisaManifest;\n}\n\nexport function writeManifest(cwd: string, manifest: PrecisaManifest): void {\n const path = resolve(cwd, MANIFEST_FILENAME);\n writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\\n`);\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport prompts from 'prompts';\n\nimport { applyTemplate } from '../lib/merge.js';\nimport { loadTemplateManifest, readTemplateSource, renderTokens } from '../lib/templates.js';\nimport {\n DEFAULT_MANIFEST_FIELDS,\n isRequired,\n type PrecisaManifest,\n tokenContext,\n writeManifest,\n} from '../manifest.js';\n\nexport interface NewOptions {\n conductEmail?: string;\n dryRun: boolean;\n /** Skip interactive prompts; require --owner/--scopes/--*-email flags. */\n nonInteractive?: boolean;\n owner?: string;\n profile: string;\n /** Comma-separated list, e.g. \"core,docs,ci,deps\". */\n scopes?: string;\n securityEmail?: string;\n}\n\nconst PROFILES = {\n 'oss-library': {\n hasPackages: true,\n hasSite: false,\n publishesToNpm: true,\n visibility: 'oss',\n },\n 'oss-site': {\n hasPackages: false,\n hasSite: true,\n publishesToNpm: false,\n visibility: 'oss',\n },\n 'private-app': {\n hasPackages: true,\n hasSite: true,\n publishesToNpm: false,\n visibility: 'private',\n },\n} as const satisfies Record<\n string,\n Pick<PrecisaManifest, 'visibility' | 'hasSite' | 'hasPackages' | 'publishesToNpm'>\n>;\n\nexport async function runNew(repoName: string, opts: NewOptions): Promise<void> {\n const targetDir = resolve(process.cwd(), repoName);\n\n if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {\n console.error(chalk.red(`\\nError: ${targetDir} already exists and is not empty.`));\n process.exit(1);\n }\n\n const profile = PROFILES[opts.profile as keyof typeof PROFILES];\n if (!profile) {\n console.error(\n chalk.red(`\\nError: unknown profile '${opts.profile}'. Choose one of:`),\n Object.keys(PROFILES).join(', '),\n );\n process.exit(1);\n }\n\n console.log(chalk.bold.cyan(`\\nprecisa new ${repoName}`));\n console.log(chalk.dim(`profile: ${opts.profile}${opts.dryRun ? ' (dry-run)' : ''}`));\n console.log(chalk.dim(`target: ${targetDir}\\n`));\n\n const answers = opts.nonInteractive\n ? {\n commitScopes: (opts.scopes ?? 'docs,ci,deps')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n conductEmail: opts.conductEmail ?? 'conduct@precisa-saude.com.br',\n owner: opts.owner ?? 'Precisa-Saude',\n securityEmail: opts.securityEmail ?? 'security@precisa-saude.com.br',\n }\n : await prompts(\n [\n {\n initial: opts.owner ?? 'Precisa-Saude',\n message: 'GitHub owner (org or user):',\n name: 'owner',\n type: 'text',\n },\n {\n initial: opts.securityEmail ?? 'security@precisa-saude.com.br',\n message: 'Security contact email:',\n name: 'securityEmail',\n type: 'text',\n },\n {\n initial: opts.conductEmail ?? 'conduct@precisa-saude.com.br',\n message: 'Code-of-conduct contact email:',\n name: 'conductEmail',\n type: 'text',\n },\n {\n initial: opts.scopes ?? 'docs,ci,deps',\n message: 'Commit scopes (comma-separated):',\n name: 'commitScopes',\n separator: ',',\n type: 'list',\n },\n ],\n { onCancel: () => process.exit(1) },\n );\n\n const manifest: PrecisaManifest = {\n ...DEFAULT_MANIFEST_FIELDS,\n ...profile,\n commitScopes: answers.commitScopes,\n contactEmails: {\n conduct: answers.conductEmail,\n security: answers.securityEmail,\n },\n name: repoName,\n owner: answers.owner,\n };\n\n const spinner = ora('Rendering templates').start();\n try {\n if (!opts.dryRun) mkdirSync(targetDir, { recursive: true });\n\n const entries = loadTemplateManifest().filter((e) => isRequired(e.required_when, manifest));\n const context = tokenContext(manifest);\n\n let created = 0;\n let skipped = 0;\n\n for (const entry of entries) {\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n const outcome = applyTemplate({\n cwd: targetDir,\n dryRun: opts.dryRun,\n entry,\n rendered,\n });\n if (outcome.kind === 'create') created += 1;\n else if (outcome.kind === 'skip-exists') skipped += 1;\n else if (outcome.kind === 'error') {\n spinner.fail(`Failed on ${entry.target}`);\n console.error(chalk.red(outcome.message));\n process.exit(1);\n }\n }\n\n spinner.succeed(\n opts.dryRun\n ? `Would render ${created} file${created === 1 ? '' : 's'} (${skipped} skipped)`\n : `Rendered ${created} file${created === 1 ? '' : 's'} (${skipped} skipped)`,\n );\n\n if (opts.dryRun) return;\n\n writeManifest(targetDir, manifest);\n console.log(chalk.dim(` wrote .precisa.json`));\n\n const gitStep = ora('git init + pnpm install').start();\n try {\n execSync('git init --initial-branch=main', { cwd: targetDir, stdio: 'pipe' });\n execSync('pnpm install', { cwd: targetDir, stdio: 'pipe' });\n gitStep.succeed('git init + pnpm install complete');\n } catch (err) {\n gitStep.warn(\n `git/pnpm setup skipped: ${(err as Error).message}. Run manually in ${targetDir}.`,\n );\n }\n\n console.log(chalk.bold.green(`\\n✓ ${repoName} scaffolded at ${targetDir}`));\n console.log(chalk.dim('\\nNext:'));\n console.log(chalk.dim(` cd ${repoName}`));\n console.log(chalk.dim(` # start adding your code`));\n } catch (err) {\n spinner.fail((err as Error).message);\n process.exit(1);\n }\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\nimport type { MergeStrategy, TemplateEntry } from './templates.js';\n\nexport type ApplyOutcome =\n | { kind: 'create'; target: string; rendered: string }\n | { kind: 'update'; target: string; previous: string; rendered: string }\n | { kind: 'skip-identical'; target: string }\n | { kind: 'preserve'; target: string; current: string; rendered: string }\n | { kind: 'skip-exists'; target: string }\n | { kind: 'merge-json'; target: string; previous: string; rendered: string }\n | { kind: 'error'; target: string; message: string };\n\nexport interface ApplyOptions {\n /** Repo root to apply into. */\n cwd: string;\n /** When true, compute the outcome but do not write to disk. */\n dryRun: boolean;\n /** Template entry being applied. */\n entry: TemplateEntry;\n /** Rendered template content (post token substitution). */\n rendered: string;\n}\n\n/**\n * Apply a single template file to the target repo. Returns the outcome\n * so callers can print a per-file status row and, on dry-run, a diff.\n */\nexport function applyTemplate({ cwd, dryRun, entry, rendered }: ApplyOptions): ApplyOutcome {\n const targetPath = resolve(cwd, entry.target);\n const exists = existsSync(targetPath);\n\n if (!exists) {\n if (!dryRun) writeFile(targetPath, rendered, entry.executable === true);\n return { kind: 'create', rendered, target: entry.target };\n }\n\n const current = readFileSync(targetPath, 'utf-8');\n\n switch (entry.merge_strategy as MergeStrategy) {\n case 'overwrite': {\n if (current === rendered) {\n return { kind: 'skip-identical', target: entry.target };\n }\n if (!dryRun) writeFile(targetPath, rendered, entry.executable === true);\n return { kind: 'update', previous: current, rendered, target: entry.target };\n }\n case 'skip_if_exists': {\n return { kind: 'skip-exists', target: entry.target };\n }\n case 'preserve': {\n return { current, kind: 'preserve', rendered, target: entry.target };\n }\n case 'merge_json': {\n let merged: string;\n try {\n merged = mergeJson(current, rendered);\n } catch (err) {\n return {\n kind: 'error',\n message: `JSON merge failed: ${(err as Error).message}`,\n target: entry.target,\n };\n }\n if (current === merged) {\n return { kind: 'skip-identical', target: entry.target };\n }\n if (!dryRun) writeFile(targetPath, merged, entry.executable === true);\n return { kind: 'merge-json', previous: current, rendered: merged, target: entry.target };\n }\n default: {\n return {\n kind: 'error',\n message: `Unknown merge_strategy '${entry.merge_strategy}'`,\n target: entry.target,\n };\n }\n }\n}\n\nfunction writeFile(path: string, contents: string, executable: boolean): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, contents);\n if (executable) chmodSync(path, 0o755);\n}\n\n/**\n * Shallow 3-way-ish JSON merge — the current file wins on conflicts so\n * repo-local customizations aren't clobbered. Objects are merged\n * key-by-key; arrays and scalars are replaced entirely by the current\n * value when present (falls back to the template value).\n *\n * If parsing fails, throws so the caller can report the error.\n */\nexport function mergeJson(currentRaw: string, templateRaw: string): string {\n const current = JSON.parse(currentRaw) as unknown;\n const template = JSON.parse(templateRaw) as unknown;\n const merged = mergeValue(template, current);\n return `${JSON.stringify(merged, null, 2)}\\n`;\n}\n\nfunction mergeValue(template: unknown, current: unknown): unknown {\n if (current === undefined) return template;\n if (\n typeof template !== 'object' ||\n template === null ||\n Array.isArray(template) ||\n typeof current !== 'object' ||\n current === null ||\n Array.isArray(current)\n ) {\n // Scalars / arrays: current value wins (never clobber repo-local values).\n return current;\n }\n const out: Record<string, unknown> = {};\n const keys = new Set([\n ...Object.keys(template as Record<string, unknown>),\n ...Object.keys(current as Record<string, unknown>),\n ]);\n for (const k of keys) {\n out[k] = mergeValue(\n (template as Record<string, unknown>)[k],\n (current as Record<string, unknown>)[k],\n );\n }\n return out;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport chalk from 'chalk';\n\nimport { colorDiff } from '../lib/diff.js';\nimport { type ApplyOutcome, applyTemplate } from '../lib/merge.js';\nimport { loadTemplateManifest, readTemplateSource, renderTokens } from '../lib/templates.js';\nimport { isRequired, loadManifest, tokenContext } from '../manifest.js';\n\nexport interface SyncOptions {\n dryRun: boolean;\n}\n\nexport async function runSync(opts: SyncOptions): Promise<void> {\n const cwd = process.cwd();\n console.log(chalk.bold.cyan(`\\nprecisa sync${opts.dryRun ? ' --dry-run' : ''}`));\n\n let manifest;\n try {\n manifest = loadManifest(cwd);\n } catch (err) {\n console.error(chalk.red(`\\n${(err as Error).message}`));\n console.error(\n chalk.dim('\\n Run `precisa new <repo>` in an empty directory to scaffold a new repo,'),\n );\n console.error(chalk.dim(' or create a `.precisa.json` manifest manually.'));\n process.exit(1);\n }\n\n const entries = loadTemplateManifest().filter((e) => isRequired(e.required_when, manifest));\n const context = tokenContext(manifest);\n\n const outcomes: ApplyOutcome[] = [];\n for (const entry of entries) {\n const source = readTemplateSource(entry);\n const rendered = renderTokens(source, context);\n outcomes.push(\n applyTemplate({\n cwd,\n dryRun: opts.dryRun,\n entry,\n rendered,\n }),\n );\n }\n\n console.log('');\n for (const o of outcomes) {\n printOutcome(o, opts.dryRun);\n }\n\n const summary = summarize(outcomes);\n console.log('');\n console.log(\n chalk.dim(\n `${summary.create} create, ${summary.update} update, ${summary.mergeJson} merge-json, ${summary.preserve} preserve, ${summary.skip} skip, ${summary.error} error`,\n ),\n );\n\n printPostSyncReminders(cwd, outcomes);\n\n if (summary.error > 0) process.exit(1);\n}\n\n// Best-effort reminders for steps that have to happen in the GitHub UI\n// (creating environments, setting up required reviewers) that this CLI\n// cannot do remotely. Triggered when a workflow that depends on the\n// reminder was actually written or already present in the repo.\nfunction printPostSyncReminders(cwd: string, outcomes: ApplyOutcome[]): void {\n const touched = outcomes\n .filter((o) => o.kind === 'create' || o.kind === 'update')\n .map((o) => o.target);\n\n const publishYml = join(cwd, '.github/workflows/_publish.yml');\n const hasPublishWorkflow = existsSync(publishYml);\n const publishReferencesEnv =\n hasPublishWorkflow &&\n readFileSync(publishYml, 'utf8').includes('environment:') &&\n readFileSync(publishYml, 'utf8').includes('npm-publish');\n\n const publishTouched = touched.some((t) => t.endsWith('_publish.yml'));\n if (publishReferencesEnv && publishTouched) {\n console.log('');\n console.log(chalk.bold.yellow('Post-sync — manual GitHub setup'));\n console.log(\n chalk.dim(\n ' Settings → Environments → npm-publish must exist with at least one required reviewer.',\n ),\n );\n console.log(\n chalk.dim(\n ' Without it the publish step runs unattended. The CLI cannot create environments remotely.',\n ),\n );\n }\n\n const watchTouched = touched.some((t) => t.endsWith('publish-watch.yml'));\n if (watchTouched) {\n console.log('');\n console.log(chalk.bold.yellow('Post-sync — publish-watch'));\n console.log(\n chalk.dim(\n ' publish-watch.yml now runs every 15 min. Confirm npm package names in `packages/**` are',\n ),\n );\n console.log(\n chalk.dim(\n ' current and that semantic-release tag convention (`<name>@<ver>` or `v<ver>`) matches.',\n ),\n );\n }\n}\n\ninterface Summary {\n create: number;\n error: number;\n mergeJson: number;\n preserve: number;\n skip: number;\n update: number;\n}\n\nfunction summarize(outcomes: ApplyOutcome[]): Summary {\n const s: Summary = { create: 0, error: 0, mergeJson: 0, preserve: 0, skip: 0, update: 0 };\n for (const o of outcomes) {\n switch (o.kind) {\n case 'create':\n s.create += 1;\n break;\n case 'update':\n s.update += 1;\n break;\n case 'merge-json':\n s.mergeJson += 1;\n break;\n case 'preserve':\n s.preserve += 1;\n break;\n case 'skip-identical':\n case 'skip-exists':\n s.skip += 1;\n break;\n case 'error':\n s.error += 1;\n break;\n }\n }\n return s;\n}\n\nfunction printOutcome(o: ApplyOutcome, dryRun: boolean): void {\n const prefix = dryRun ? '(dry-run) ' : '';\n switch (o.kind) {\n case 'create':\n console.log(`${chalk.green('+')} ${prefix}create ${o.target}`);\n return;\n case 'update':\n console.log(`${chalk.yellow('~')} ${prefix}update ${o.target}`);\n if (dryRun) console.log(indent(colorDiff(o.target, o.previous, o.rendered)));\n return;\n case 'merge-json':\n console.log(`${chalk.yellow('~')} ${prefix}merge ${o.target}`);\n if (dryRun) console.log(indent(colorDiff(o.target, o.previous, o.rendered)));\n return;\n case 'preserve':\n console.log(\n `${chalk.blue('i')} ${prefix}preserve ${o.target} (template differs; not written)`,\n );\n if (dryRun && o.current !== o.rendered) {\n console.log(indent(colorDiff(o.target, o.current, o.rendered)));\n }\n return;\n case 'skip-identical':\n console.log(`${chalk.dim('=')} ${prefix}unchanged ${o.target}`);\n return;\n case 'skip-exists':\n console.log(`${chalk.dim('s')} ${prefix}skip ${o.target} (already exists)`);\n return;\n case 'error':\n console.log(`${chalk.red('!')} ${prefix}error ${o.target}: ${o.message}`);\n return;\n }\n}\n\nfunction indent(text: string): string {\n return text\n .split('\\n')\n .map((l) => ` ${l}`)\n .join('\\n');\n}\n","import chalk from 'chalk';\nimport { createPatch } from 'diff';\n\n/**\n * Format a unified diff with ANSI colors for terminal display.\n * Skips the `@@ hunk @@` metadata lines for a cleaner look.\n */\nexport function colorDiff(filename: string, previous: string, next: string): string {\n const patch = createPatch(filename, previous, next, '', '');\n const lines = patch.split('\\n');\n const out: string[] = [];\n for (const line of lines) {\n if (line.startsWith('---') || line.startsWith('+++')) continue;\n if (line.startsWith('@@')) {\n out.push(chalk.cyan(line));\n continue;\n }\n if (line.startsWith('+')) {\n out.push(chalk.green(line));\n continue;\n }\n if (line.startsWith('-')) {\n out.push(chalk.red(line));\n continue;\n }\n out.push(line);\n }\n return out.join('\\n');\n}\n"],"mappings":"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","names":["existsSync","readFileSync","resolve","resolve","resolve","readFileSync","resolve","resolve","existsSync","readFileSync","existsSync","mkdirSync","resolve","chalk","existsSync","readFileSync","writeFileSync","dirname","resolve","resolve","existsSync","chalk","mkdirSync","existsSync","readFileSync","chalk","chalk","chalk","existsSync","readFileSync"]}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
-
"extends": [
|
|
3
|
+
"extends": [
|
|
4
|
+
"config:recommended",
|
|
5
|
+
":dependencyDashboard",
|
|
6
|
+
":semanticCommits",
|
|
7
|
+
"helpers:pinGitHubActionDigests"
|
|
8
|
+
],
|
|
4
9
|
"schedule": ["before 6am on saturday"],
|
|
5
10
|
"timezone": "America/Sao_Paulo",
|
|
6
11
|
"labels": ["dependencies"],
|
|
@@ -20,6 +25,11 @@
|
|
|
20
25
|
{
|
|
21
26
|
"matchPackagePatterns": ["^@precisa-saude/"],
|
|
22
27
|
"groupName": "precisa-saude packages"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"matchManagers": ["github-actions"],
|
|
31
|
+
"groupName": "github-actions",
|
|
32
|
+
"pinDigests": true
|
|
23
33
|
}
|
|
24
34
|
],
|
|
25
35
|
"vulnerabilityAlerts": {
|
|
@@ -18,9 +18,9 @@ jobs:
|
|
|
18
18
|
runs-on: ubuntu-latest
|
|
19
19
|
timeout-minutes: 5
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@v6
|
|
22
|
-
- uses: pnpm/action-setup@v5
|
|
23
|
-
- uses: actions/setup-node@v6
|
|
21
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
22
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
23
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
24
24
|
with:
|
|
25
25
|
node-version: 22
|
|
26
26
|
cache: 'pnpm'
|
|
@@ -35,9 +35,9 @@ jobs:
|
|
|
35
35
|
runs-on: ubuntu-latest
|
|
36
36
|
timeout-minutes: 10
|
|
37
37
|
steps:
|
|
38
|
-
- uses: actions/checkout@v6
|
|
39
|
-
- uses: pnpm/action-setup@v5
|
|
40
|
-
- uses: actions/setup-node@v6
|
|
38
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
39
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
40
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
41
41
|
with:
|
|
42
42
|
node-version: 22
|
|
43
43
|
cache: 'pnpm'
|
|
@@ -49,9 +49,9 @@ jobs:
|
|
|
49
49
|
runs-on: ubuntu-latest
|
|
50
50
|
timeout-minutes: 10
|
|
51
51
|
steps:
|
|
52
|
-
- uses: actions/checkout@v6
|
|
53
|
-
- uses: pnpm/action-setup@v5
|
|
54
|
-
- uses: actions/setup-node@v6
|
|
52
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
53
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
54
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
55
55
|
with:
|
|
56
56
|
node-version: 22
|
|
57
57
|
cache: 'pnpm'
|
|
@@ -63,9 +63,9 @@ jobs:
|
|
|
63
63
|
runs-on: ubuntu-latest
|
|
64
64
|
timeout-minutes: 5
|
|
65
65
|
steps:
|
|
66
|
-
- uses: actions/checkout@v6
|
|
67
|
-
- uses: pnpm/action-setup@v5
|
|
68
|
-
- uses: actions/setup-node@v6
|
|
66
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
67
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
68
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
69
69
|
with:
|
|
70
70
|
node-version: 22
|
|
71
71
|
cache: 'pnpm'
|
|
@@ -77,9 +77,9 @@ jobs:
|
|
|
77
77
|
runs-on: ubuntu-latest
|
|
78
78
|
timeout-minutes: 15
|
|
79
79
|
steps:
|
|
80
|
-
- uses: actions/checkout@v6
|
|
81
|
-
- uses: pnpm/action-setup@v5
|
|
82
|
-
- uses: actions/setup-node@v6
|
|
80
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
81
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
82
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
83
83
|
with:
|
|
84
84
|
node-version: 22
|
|
85
85
|
cache: 'pnpm'
|
|
@@ -91,9 +91,9 @@ jobs:
|
|
|
91
91
|
runs-on: ubuntu-latest
|
|
92
92
|
timeout-minutes: 15
|
|
93
93
|
steps:
|
|
94
|
-
- uses: actions/checkout@v6
|
|
95
|
-
- uses: pnpm/action-setup@v5
|
|
96
|
-
- uses: actions/setup-node@v6
|
|
94
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
95
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
96
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
97
97
|
with:
|
|
98
98
|
node-version: 22
|
|
99
99
|
cache: 'pnpm'
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
steps:
|
|
34
34
|
- name: Check for site changes
|
|
35
35
|
id: changes
|
|
36
|
-
uses: actions/github-script@v7
|
|
36
|
+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
|
37
37
|
with:
|
|
38
38
|
script: |
|
|
39
39
|
if (context.eventName === 'workflow_dispatch') {
|
|
@@ -65,11 +65,11 @@ jobs:
|
|
|
65
65
|
const siteChanged = filenames.some(f => f.startsWith(sourcePath));
|
|
66
66
|
core.setOutput('site_changed', siteChanged ? 'true' : 'false');
|
|
67
67
|
|
|
68
|
-
- uses: actions/checkout@v6
|
|
68
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
69
69
|
if: steps.changes.outputs.site_changed == 'true'
|
|
70
|
-
- uses: pnpm/action-setup@v5
|
|
70
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
71
71
|
if: steps.changes.outputs.site_changed == 'true'
|
|
72
|
-
- uses: actions/setup-node@v6
|
|
72
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
73
73
|
if: steps.changes.outputs.site_changed == 'true'
|
|
74
74
|
with:
|
|
75
75
|
node-version: 22
|
|
@@ -82,7 +82,7 @@ jobs:
|
|
|
82
82
|
- name: Build site
|
|
83
83
|
if: steps.changes.outputs.site_changed == 'true'
|
|
84
84
|
run: pnpm turbo run build --filter=${{ inputs.site_filter }}...
|
|
85
|
-
- uses: actions/upload-artifact@v6
|
|
85
|
+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
86
86
|
if: steps.changes.outputs.site_changed == 'true'
|
|
87
87
|
with:
|
|
88
88
|
name: site-dist
|
|
@@ -95,15 +95,15 @@ jobs:
|
|
|
95
95
|
if: always() && !cancelled() && needs.build-site.outputs.site_changed == 'true' && needs.build-site.result == 'success' && github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
96
96
|
runs-on: ubuntu-latest
|
|
97
97
|
steps:
|
|
98
|
-
- uses: actions/download-artifact@v7
|
|
98
|
+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
99
99
|
with:
|
|
100
100
|
name: site-dist
|
|
101
101
|
path: ${{ inputs.site_path }}
|
|
102
|
-
- uses: actions/setup-node@v6
|
|
102
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
103
103
|
with:
|
|
104
104
|
node-version: 22
|
|
105
105
|
- name: Deploy to Cloudflare Pages
|
|
106
|
-
uses: cloudflare/wrangler-action@v3
|
|
106
|
+
uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3.15.0
|
|
107
107
|
with:
|
|
108
108
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
109
109
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
@@ -166,7 +166,7 @@ jobs:
|
|
|
166
166
|
}' > /tmp/slack-payload.json
|
|
167
167
|
|
|
168
168
|
- name: Send Slack notification
|
|
169
|
-
uses: slackapi/slack-github-action@v2.1.0
|
|
169
|
+
uses: slackapi/slack-github-action@b0fa283ad8fea605de13dc3f449259339835fc52 # v2.1.0
|
|
170
170
|
with:
|
|
171
171
|
webhook: ${{ secrets.SLACK_DEPLOY_WEBHOOK_URL }}
|
|
172
172
|
webhook-type: incoming-webhook
|
|
@@ -41,13 +41,13 @@ jobs:
|
|
|
41
41
|
contents: read
|
|
42
42
|
id-token: write
|
|
43
43
|
steps:
|
|
44
|
-
- uses: actions/checkout@v6
|
|
44
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
45
45
|
with:
|
|
46
46
|
ref: ${{ inputs.release_sha }}
|
|
47
47
|
|
|
48
|
-
- uses: pnpm/action-setup@v5
|
|
48
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
49
49
|
|
|
50
|
-
- uses: actions/setup-node@v6
|
|
50
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
51
51
|
with:
|
|
52
52
|
node-version: 22
|
|
53
53
|
cache: 'pnpm'
|
|
@@ -44,7 +44,7 @@ jobs:
|
|
|
44
44
|
- name: Check for package changes across pushed commits
|
|
45
45
|
id: changes
|
|
46
46
|
if: inputs.require_package_changes
|
|
47
|
-
uses: actions/github-script@v7
|
|
47
|
+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
|
48
48
|
with:
|
|
49
49
|
# Compares `before..after` from the push payload. Paginates explicitly
|
|
50
50
|
# because `compareCommits` truncates at 300 files per page — a large
|
|
@@ -80,21 +80,21 @@ jobs:
|
|
|
80
80
|
- name: Generate GitHub App token
|
|
81
81
|
id: app-token
|
|
82
82
|
if: "!inputs.require_package_changes || steps.changes.outputs.packages_changed == 'true'"
|
|
83
|
-
uses: actions/create-github-app-token@v1
|
|
83
|
+
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0
|
|
84
84
|
with:
|
|
85
85
|
app-id: ${{ secrets.RELEASE_APP_ID }}
|
|
86
86
|
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
|
87
87
|
|
|
88
|
-
- uses: actions/checkout@v6
|
|
88
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
89
89
|
if: "!inputs.require_package_changes || steps.changes.outputs.packages_changed == 'true'"
|
|
90
90
|
with:
|
|
91
91
|
fetch-depth: 0
|
|
92
92
|
token: ${{ steps.app-token.outputs.token }}
|
|
93
93
|
|
|
94
|
-
- uses: pnpm/action-setup@v5
|
|
94
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
95
95
|
if: "!inputs.require_package_changes || steps.changes.outputs.packages_changed == 'true'"
|
|
96
96
|
|
|
97
|
-
- uses: actions/setup-node@v6
|
|
97
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
98
98
|
if: "!inputs.require_package_changes || steps.changes.outputs.packages_changed == 'true'"
|
|
99
99
|
with:
|
|
100
100
|
node-version: 22
|
|
@@ -29,9 +29,9 @@ jobs:
|
|
|
29
29
|
runs-on: ubuntu-latest
|
|
30
30
|
timeout-minutes: 10
|
|
31
31
|
steps:
|
|
32
|
-
- uses: actions/checkout@v6
|
|
33
|
-
- uses: pnpm/action-setup@v5
|
|
34
|
-
- uses: actions/setup-node@v6
|
|
32
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
33
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
34
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
35
35
|
with:
|
|
36
36
|
node-version: 22
|
|
37
37
|
cache: 'pnpm'
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
continue-on-error: true
|
|
43
43
|
- name: Open issue on drift
|
|
44
44
|
if: steps.doctor.outcome == 'failure'
|
|
45
|
-
uses: actions/github-script@v7
|
|
45
|
+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
|
46
46
|
with:
|
|
47
47
|
script: |
|
|
48
48
|
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
@@ -27,13 +27,13 @@ jobs:
|
|
|
27
27
|
name: Publish tag
|
|
28
28
|
runs-on: ubuntu-latest
|
|
29
29
|
steps:
|
|
30
|
-
- uses: actions/checkout@v6
|
|
30
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
31
31
|
with:
|
|
32
32
|
ref: ${{ inputs.tag }}
|
|
33
33
|
|
|
34
|
-
- uses: pnpm/action-setup@v5
|
|
34
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
35
35
|
|
|
36
|
-
- uses: actions/setup-node@v6
|
|
36
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
37
37
|
with:
|
|
38
38
|
node-version: 22
|
|
39
39
|
cache: 'pnpm'
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
name: Publish watch
|
|
2
|
+
|
|
3
|
+
# Tripwire — confirma que toda versão publicada no npm tem uma tag git
|
|
4
|
+
# correspondente neste repo. Roda em cron de 15 em 15 min e ad-hoc via
|
|
5
|
+
# workflow_dispatch.
|
|
6
|
+
#
|
|
7
|
+
# Para cada pacote público em packages/**, compara a versão `latest` no
|
|
8
|
+
# registry com as tags `v<versão>` deste repo. Se a versão do npm não
|
|
9
|
+
# existe como tag local, abre uma issue de prioridade alta — sinal de
|
|
10
|
+
# publicação fora do fluxo (workflow comprometido, token vazado,
|
|
11
|
+
# republicação manual).
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
schedule:
|
|
15
|
+
- cron: '*/15 * * * *'
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
issues: write
|
|
21
|
+
|
|
22
|
+
concurrency:
|
|
23
|
+
group: publish-watch
|
|
24
|
+
cancel-in-progress: true
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
watch:
|
|
28
|
+
name: Verify npm versions match git tags
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
timeout-minutes: 5
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
33
|
+
with:
|
|
34
|
+
fetch-depth: 0
|
|
35
|
+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
36
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
37
|
+
with:
|
|
38
|
+
node-version: 22
|
|
39
|
+
|
|
40
|
+
- name: Compare npm latest vs git tags
|
|
41
|
+
id: check
|
|
42
|
+
run: |
|
|
43
|
+
set -e
|
|
44
|
+
mismatches=""
|
|
45
|
+
# Lista pacotes públicos do workspace. `pnpm m ls --json` retorna
|
|
46
|
+
# name, version, path, private para cada workspace package.
|
|
47
|
+
pnpm m ls --json --depth -1 > /tmp/ws.json
|
|
48
|
+
mapfile -t entries < <(
|
|
49
|
+
node -e '
|
|
50
|
+
const ws = JSON.parse(require("fs").readFileSync("/tmp/ws.json","utf8"));
|
|
51
|
+
for (const p of ws) {
|
|
52
|
+
if (p.private || !p.name) continue;
|
|
53
|
+
if (!p.name.startsWith("@")) continue;
|
|
54
|
+
process.stdout.write(p.name + "\n");
|
|
55
|
+
}
|
|
56
|
+
'
|
|
57
|
+
)
|
|
58
|
+
for name in "${entries[@]}"; do
|
|
59
|
+
[ -z "$name" ] && continue
|
|
60
|
+
npm_version=$(npm view "$name" version 2>/dev/null || true)
|
|
61
|
+
if [ -z "$npm_version" ]; then
|
|
62
|
+
echo "$name: not on npm yet, skipping"
|
|
63
|
+
continue
|
|
64
|
+
fi
|
|
65
|
+
# Tag convention: semantic-release emits `<name>@<ver>` for
|
|
66
|
+
# monorepos and `v<ver>` for single-package repos. Accept both.
|
|
67
|
+
if git rev-parse -q --verify "refs/tags/${name}@${npm_version}" >/dev/null 2>&1 \
|
|
68
|
+
|| git rev-parse -q --verify "refs/tags/v${npm_version}" >/dev/null 2>&1; then
|
|
69
|
+
echo "$name@$npm_version: tag found"
|
|
70
|
+
else
|
|
71
|
+
echo "::warning::$name@$npm_version published on npm but no matching git tag in this repo"
|
|
72
|
+
mismatches="${mismatches}- \`${name}@${npm_version}\` (no matching tag)\n"
|
|
73
|
+
fi
|
|
74
|
+
done
|
|
75
|
+
if [ -n "$mismatches" ]; then
|
|
76
|
+
{
|
|
77
|
+
echo "mismatches<<EOF"
|
|
78
|
+
printf "%b" "$mismatches"
|
|
79
|
+
echo "EOF"
|
|
80
|
+
} >> "$GITHUB_OUTPUT"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
- name: Open issue on mismatch
|
|
84
|
+
if: steps.check.outputs.mismatches != ''
|
|
85
|
+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
|
86
|
+
with:
|
|
87
|
+
script: |
|
|
88
|
+
const mismatches = `${{ steps.check.outputs.mismatches }}`;
|
|
89
|
+
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
90
|
+
|
|
91
|
+
// Não duplica: se já existe uma issue aberta com este título,
|
|
92
|
+
// só comenta nela com a evidência da rodada atual.
|
|
93
|
+
const title = 'publish-watch: versão npm sem tag git correspondente';
|
|
94
|
+
const { data: existing } = await github.rest.issues.listForRepo({
|
|
95
|
+
owner: context.repo.owner,
|
|
96
|
+
repo: context.repo.repo,
|
|
97
|
+
state: 'open',
|
|
98
|
+
labels: 'security,publish-watch',
|
|
99
|
+
per_page: 50,
|
|
100
|
+
});
|
|
101
|
+
const open = existing.find(i => i.title === title);
|
|
102
|
+
|
|
103
|
+
const body = [
|
|
104
|
+
'`publish-watch` detectou uma ou mais versões publicadas no npm que',
|
|
105
|
+
'não têm tag git correspondente neste repo. Isto pode indicar:',
|
|
106
|
+
'',
|
|
107
|
+
'- publicação fora do fluxo (workflow comprometido, token vazado, republicação manual)',
|
|
108
|
+
'- semantic-release configurado com convenção de tag diferente (revisar)',
|
|
109
|
+
'- pacote movido para outro repo sem atualizar o filtro do watch',
|
|
110
|
+
'',
|
|
111
|
+
'**Versões sem tag local:**',
|
|
112
|
+
'',
|
|
113
|
+
mismatches,
|
|
114
|
+
'',
|
|
115
|
+
`Log da rodada: ${runUrl}`,
|
|
116
|
+
'',
|
|
117
|
+
'## Próximos passos',
|
|
118
|
+
'',
|
|
119
|
+
'1. Conferir `npm view <pacote> time` para o horário da publicação.',
|
|
120
|
+
'2. Cruzar com runs de `_publish.yml` / `publish-tag.yml` recentes.',
|
|
121
|
+
'3. Se não há run correspondente, tratar como incidente: rotação de NPM_TOKEN, revisão de logs de auditoria do npm, deprecate da versão suspeita.',
|
|
122
|
+
].join('\n');
|
|
123
|
+
|
|
124
|
+
if (open) {
|
|
125
|
+
await github.rest.issues.createComment({
|
|
126
|
+
owner: context.repo.owner,
|
|
127
|
+
repo: context.repo.repo,
|
|
128
|
+
issue_number: open.number,
|
|
129
|
+
body,
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
await github.rest.issues.create({
|
|
133
|
+
owner: context.repo.owner,
|
|
134
|
+
repo: context.repo.repo,
|
|
135
|
+
title,
|
|
136
|
+
body,
|
|
137
|
+
labels: ['security', 'publish-watch'],
|
|
138
|
+
});
|
|
139
|
+
}
|
|
@@ -30,11 +30,11 @@ jobs:
|
|
|
30
30
|
should_run: ${{ steps.check.outputs.should_run }}
|
|
31
31
|
review_round: ${{ steps.check.outputs.review_round }}
|
|
32
32
|
steps:
|
|
33
|
-
- uses: actions/checkout@v6
|
|
33
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
34
34
|
|
|
35
35
|
- name: Decide whether to run
|
|
36
36
|
id: check
|
|
37
|
-
uses: actions/github-script@v8
|
|
37
|
+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
|
38
38
|
with:
|
|
39
39
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
40
40
|
script: |
|
|
@@ -95,7 +95,7 @@ jobs:
|
|
|
95
95
|
GITHUB_MODELS_MODEL: openai/gpt-4o-mini
|
|
96
96
|
MAX_DIFF_SIZE: '150000'
|
|
97
97
|
steps:
|
|
98
|
-
- uses: actions/checkout@v6
|
|
98
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
99
99
|
with:
|
|
100
100
|
fetch-depth: 0
|
|
101
101
|
|
|
@@ -390,7 +390,7 @@ jobs:
|
|
|
390
390
|
SCRIPT
|
|
391
391
|
|
|
392
392
|
- name: Post review
|
|
393
|
-
uses: actions/github-script@v8
|
|
393
|
+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
|
394
394
|
with:
|
|
395
395
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
396
396
|
script: |
|
|
@@ -236,6 +236,11 @@ templates:
|
|
|
236
236
|
required_when: publishes_to_npm
|
|
237
237
|
merge_strategy: overwrite
|
|
238
238
|
|
|
239
|
+
- source: github/workflows/publish-watch.yml
|
|
240
|
+
target: .github/workflows/publish-watch.yml
|
|
241
|
+
required_when: publishes_to_npm
|
|
242
|
+
merge_strategy: overwrite
|
|
243
|
+
|
|
239
244
|
- source: github/workflows/_deploy-site.yml
|
|
240
245
|
target: .github/workflows/_deploy-site.yml
|
|
241
246
|
required_when: has_site
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@precisa-saude/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Bootstrap and sync Precisa Saúde repositories — the `precisa` CLI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@types/prompts": "^2.4.9",
|
|
46
46
|
"tsup": "^8.3.5",
|
|
47
47
|
"typescript": "~5.7.3",
|
|
48
|
-
"@precisa-saude/tsconfig": "1.
|
|
48
|
+
"@precisa-saude/tsconfig": "1.10.0"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=22.0.0"
|