@doikayt/typescript-build-config 0.1.32 → 0.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -50,7 +50,7 @@ via the pipeline files it installs into each consumer repo and the canonical rel
50
50
  These steps set up — in a fresh "new-developer" environment — a local git repo
51
51
  with a skeleton demo app plus all the standard Doikayt build configuration:
52
52
  tooling that auto-documents the code in the repo and lets it be pushed to
53
- GitHub, built on GitHub's CI servers, and (for a library) published to npm. Steps
53
+ Codeberg, built by Woodpecker CI, and (for a library) published to npm. Steps
54
54
  are minimal here — each links to the section that explains _what_ and _why_.
55
55
 
56
56
  ### 1. One-time machine setup (once per machine)
@@ -59,13 +59,34 @@ Clone this base repo and install the shared team
59
59
  [shell aliases](#team-shell-aliases). This only sets up the aliases
60
60
  (`dk-scaffold`, `mkrepo`); it does **not** configure any project:
61
61
 
62
+ 🛑 **STOP here if you are a contributor/maintainer of `typescript-build-config` itself** If you intend to
63
+ push commits back to *this* repo, you're in the wrong place — the clone below is
64
+ HTTPS, read-only for this repo. Start here instead: [For Maintainers](#for-maintainers).
65
+
62
66
  ```bash
63
- git clone https://github.com/doikayt/typescript-build-config.git # HTTPS: no SSH key needed
67
+ git clone https://codeberg.org/doikayt/typescript-build-config.git # HTTPS: no SSH key needed
68
+ #
69
+ ## Alternative using ssh key: git clone ssh://git@codeberg.org/doikayt/typescript-build-config.git
70
+ #
71
+ #
72
+ #
64
73
  cd typescript-build-config
65
74
  ./assets/shell/install.sh # adds `source assets/shell/aliases.sh` to your rc (idempotent)
66
- exec $SHELL # reload
75
+ exec $SHELL # replaces this shell with a fresh one that reloads your rc
67
76
  ```
68
77
 
78
+ The aliases are now active in this shell. Run `tools-help` to confirm — it prints every
79
+ command you now have available (`dk-scaffold`, `mkrepo`, and more) with a one-line
80
+ summary of what each does. From here, go to
81
+ [2. Create a new project](#2-create-a-new-project-repeatable) below.
82
+
83
+ **Re-running this after `aliases.sh` changed?** Always use `exec $SHELL` (a fresh
84
+ shell), not `source assets/shell/aliases.sh` in your existing terminal. If a function
85
+ it defines shares a name with something your shell already has loaded (an old alias
86
+ from a previous version, for instance), sourcing directly can fail with a confusing
87
+ `syntax error near unexpected token`. A fresh shell never had the stale definition to
88
+ begin with.
89
+
69
90
  ### 2. Create a new project (repeatable)
70
91
 
71
92
  The two paths below are **alternatives that reach the same result** — a project
@@ -74,7 +95,7 @@ wired to this base package.
74
95
  #### dk-scaffold
75
96
 
76
97
  `dk-scaffold` is the one-command wrapper that also (optionally) creates the
77
- GitHub repo and pushes it. Just run it with a first argument naming your project
98
+ Codeberg repo and pushes it. Just run it with a first argument naming your project
78
99
  and a second indicating `lib` (a published library) or `app` (a standalone
79
100
  app/utility, the default) — see [library vs app](#usage) and
80
101
  [Packaging concepts](docs/packaging-concepts.md):
@@ -83,6 +104,16 @@ app/utility, the default) — see [library vs app](#usage) and
83
104
  dk-scaffold my-project lib
84
105
  ```
85
106
 
107
+ **Where the project lands.** `dk-scaffold <name>` creates a `<name>/` subdirectory in the
108
+ directory you ran it from (for example `~/projects/my-project/`) and leaves your shell
109
+ inside it. Two variants scaffold in place instead of creating a subdirectory:
110
+
111
+ - run it from inside an empty directory that is already named `<name>`
112
+ - pass `.` as the name, which uses the current directory's name as the project name
113
+
114
+ `dk-scaffold` will look like it is prompting you, but just wait a moment: the script
115
+ fills in the appropriate answers itself. It prints a note saying so; pass `-q` to hide it.
116
+
86
117
  #### Run dk-scaffold's steps individually
87
118
 
88
119
  The steps below mirror the work `dk-scaffold` does under the hood — either for a
@@ -105,8 +136,8 @@ throwaway **app** (nothing publishes) unless noted. Do the one-time
105
136
  [machine setup](#1-one-time-machine-setup-once-per-machine) first so `dk-scaffold`
106
137
  is on your PATH.
107
138
 
108
- **Level 0 — local (no external GitHub/npm accounts needed).** Scaffold and run
109
- the same gate CI runs — no GitHub repo, no push:
139
+ **Level 0 — local (no external Codeberg/npm accounts needed).** Scaffold and run
140
+ the same gate CI runs — no Codeberg repo, no push:
110
141
 
111
142
  ```bash
112
143
  dk-scaffold my-demo --local
@@ -118,20 +149,24 @@ declarations, and `update-all-format` fill the README's TOC + UML markers
118
149
  (mermaid **source** — rendered at Level 1). `npm publish --dry-run` **refuses** —
119
150
  proof the app archetype never publishes.
120
151
 
121
- **Level 1 — push to your own GitHub.** Bring a GitHub account and the `gh` CLI.
122
- Sign in, point the wrapper at your account, and drop `--local`:
152
+ The project is created in `./my-demo/` (a subdirectory of wherever you ran the command),
153
+ and your shell's CWD (current working directory) gets set to the root of this new project.
154
+ This means you can run `npm test` or `npm run build` right away.
155
+
156
+ **Level 1 — push to your own Codeberg.** Bring a Codeberg account and an API token.
157
+ Export the token, point the wrapper at your account, and drop `--local`:
123
158
 
124
159
  ```bash
125
- gh auth login # one-time: sign in to GitHub
126
- export REPO_OWNER=<your-github-username> # target owner for the repo
127
- dk-scaffold my-demo # app (private) — no npm creds
160
+ export CODEBERG_TOKEN=<your-codeberg-token> # repository-creation token
161
+ export REPO_OWNER=<your-codeberg-org> # target owner for the repo
162
+ dk-scaffold my-demo # app (public repo) — no npm creds
128
163
  ```
129
164
 
130
165
  Now it creates the repo and pushes — and you see what Level 0 couldn't: the
131
166
  **mermaid diagrams rendered** (example
132
167
  [here](https://github.com/doikayt/build-tools/blob/main/javascript/tooling-core/README.md#package-structure))
133
- and the **CI job go green** in Actions (example:
134
- [this project's runs](https://github.com/doikayt/typescript-build-config/actions)).
168
+ and the **CI job goes green** in Woodpecker CI (example:
169
+ [this project's runs](https://ci.codeberg.org/repos/doikayt/typescript-build-config)).
135
170
  Push a follow-up **`feat:`** commit and the **release job** version-bumps + tags —
136
171
  nothing published (app). (The initial `chore: scaffold` push releases nothing;
137
172
  `feat:` / `fix:` triggers it.)
@@ -139,14 +174,14 @@ nothing published (app). (The initial `chore: scaffold` push releases nothing;
139
174
 
140
175
  The screen cast below shows the process for Level 1. Note:
141
176
 
142
- - When we log in to our test account (associated with a dummy GitHub account,
177
+ - When we log in to our test account (associated with a dummy Codeberg account,
143
178
  not doikayt) we see:
144
179
  - no repos initially
145
180
  - no doikayt aliases registered in `.bashrc`
146
- - After we run `dk-scaffold demo`, we need to input 'y' to install, then we see:
181
+ - After we run `dk-scaffold demo`, the install proceeds automatically, then we see:
147
182
  - lots of output showing the project being configured and built
148
- - a push to GitHub
149
- - a build and release triggered on GitHub
183
+ - a push to Codeberg
184
+ - a build and release triggered by Woodpecker CI
150
185
  - since we did not select `lib`, we got an app build profile, for which
151
186
  there is no publish to npm
152
187
 
@@ -158,14 +193,14 @@ The screen cast below shows the process for Level 1. Note:
158
193
  alt="update-markdown-toc demo">
159
194
  </p>
160
195
 
161
- After we ran the screen cast steps we were able to screenshot how our push triggered a build o
162
- onthe Github CI servers.
196
+ After we ran the screen cast steps we were able to screenshot how our push triggered a build on
197
+ Woodpecker CI.
163
198
 
164
199
  <p align="center">
165
200
  <img
166
201
  src="docs/github-actions.png"
167
202
  width="720"
168
- alt="github-actions-view">
203
+ alt="woodpecker-ci-view">
169
204
  </p>
170
205
 
171
206
 
@@ -208,7 +243,7 @@ is _why_.)
208
243
  | **Stubs** — `src/top-level/*` seeded into the project root | Zero-config entry points that only `extends` the presets | Minimal setup |
209
244
  | **Pipeline** — `src/pipeline/*` copied on install | A working release + changeset workflow with no hand-wiring; drift is diff-warned | Both |
210
245
  | **Convention checks** — postinstall warns on missing `ci` / `update-all-format` | An install-time nudge toward the shared command surface | Consistency |
211
- | **`ci` gate** — `release.yml` runs `npm run ci` | Fail-closed enforcement: a repo that ignores the convention cannot release | Consistency (hard teeth) |
246
+ | **`ci` gate** — `.woodpecker.yml` runs `npm run ci` | Fail-closed enforcement: a repo that ignores the convention cannot release | Consistency (hard teeth) |
212
247
  | **Policy doc** — `docs/RELEASE-PROCESS.md`, linked never copied | One canonical release policy, impossible to drift | Consistency |
213
248
  | **Assets** — `assets/image/*` seeded into `docs/assets/` | Shared brand logos with no per-repo copies to maintain | Minimal setup |
214
249
  | **Shell aliases** — `assets/shell/aliases.sh`, cloned + sourced (never shipped to npm) | One standard way for the team to create and scaffold repos (`mkrepo`, `dk-*`) | Consistency |
@@ -335,10 +370,10 @@ versions of these tools may produce peer dependency conflicts.
335
370
  - TypeScript config (`tsconfig.json`, `tsconfig.test.json`, `tsconfig.eslint.json`)
336
371
  - Postinstall script that copies starter top-level config files into your
337
372
  project root, extending the configs installed under `node_modules`
338
- - GitHub Actions release workflow (`.github/workflows/release.yml`)
373
+ - Woodpecker CI release workflow (`.woodpecker.yml`)
339
374
  - Changeset config (`.changeset/config.json`)
340
375
  - Auto-changeset script (`scripts/auto-changeset.sh`)
341
- - NPM token diagnostic workflow (`.github/workflows/verify-npm-token.yml`) — see
376
+ - NPM token diagnostic instructions — see
342
377
  [Troubleshooting Publish Auth](docs/RELEASE-PROCESS.md#troubleshooting-publish-auth)
343
378
  - Playwright config helper (`@doikayt/typescript-build-config/playwright`) — `nixChromiumLaunchOptions()`
344
379
  discovers the system Chromium on quirky NixOS; `definePlaywrightConfig()` wraps `defineConfig` and
@@ -410,7 +445,7 @@ components.
410
445
  │ │ prettier.config.js … │
411
446
  │ └────extends────► presets living in │
412
447
  │ node_modules (chan. 1) │
413
- │ owned pipeline: .github/workflows/release.yml │
448
+ │ owned pipeline: .woodpecker.yml │
414
449
  │ scripts/auto-changeset.sh │
415
450
  │ owned assets: docs/assets/doikayt-logo.* │
416
451
  │ CONTRIBUTING.md ─cites URL─► RELEASE-PROCESS.md│
@@ -502,9 +537,7 @@ On `npm update`, the behavior per file is:
502
537
  This means local customisations are never silently overwritten, but you are
503
538
  notified when your copy has drifted from the upstream version.
504
539
 
505
- The release pipeline requires an `NPM` secret stored at the GitHub organisation
506
- level. All repos under the org inherit it automatically — no per-repo secret
507
- configuration is needed.
540
+ The release pipeline requires `NPM` and `CODEBERG_TOKEN` secrets in Woodpecker.
508
541
 
509
542
  ## Conventions Every Project Must Adhere To
510
543
 
@@ -601,7 +634,7 @@ directly.
601
634
 
602
635
  ## Publishing
603
636
 
604
- Releases are automated via Changesets and GitHub Actions. The full policy —
637
+ Releases are automated via Changesets and Woodpecker CI. The full policy —
605
638
  commit-prefix → bump mapping, forcing or suppressing a release, resolving
606
639
  `changeset status` errors, verifying a release, troubleshooting publish auth —
607
640
  is documented in [docs/RELEASE-PROCESS.md](docs/RELEASE-PROCESS.md). That
@@ -620,28 +653,32 @@ present. For majors this is mandatory: a breaking-change commit (`feat!:` or
620
653
  `BREAKING CHANGE` in the body) with no handwritten changeset fails the
621
654
  release job until one is committed.
622
655
 
623
- **Manual publish (emergency):** trigger the workflow manually via
624
- **GitHub Actions → CI / Release → Run workflow** on the `main` branch.
656
+ **Manual publish (emergency):** trigger a Woodpecker pipeline on the `main` branch.
625
657
 
626
658
  ## Team shell aliases
627
659
 
628
660
  Installed by [Quick start](#quick-start) step 1 (or manually: add
629
- `source <clone-path>/assets/shell/aliases.sh` to your shell rc). They require `gh`
630
- (authenticated) and `node`/`npm`.
661
+ `source <clone-path>/assets/shell/aliases.sh` to your shell rc). They require
662
+ `curl`, `CODEBERG_TOKEN`, and `node`/`npm`.
631
663
 
632
664
  | Alias | What it does |
633
665
  | --- | --- |
634
666
  | `mkrepo <name>` | Create a public repo in the `doikayt` org (guards against duplicates). |
667
+ | `addpush [name]` | Wire up the current directory to an existing Codeberg repo (create it first with `mkrepo`) and push. Defaults `name` to the current directory. |
635
668
  | `dk-new` | `npm init -y` + `@doikayt` scope. |
636
669
  | `dk-init` | Scaffold the build config into the current project. |
637
- | `dk-scaffold <name>\|. [lib\|app]` | Create the repo, scaffold, and push — one command (defaults to app). Pass `.` to scaffold in the current directory, using its leaf name as `@doikayt/<package-name>`. |
670
+ | `dk-scaffold <name>\|. [lib\|app] [--local] [-q]` | Create the repo, scaffold, and push — one command (defaults to app). Pass `.` to scaffold in the current directory, using its leaf name as `@doikayt/<package-name>`. `--local` skips the repo and push; `-q` hides the auto-answered-prompts note. |
671
+ | `gp` | Pull with rebase, then push the current branch. The everyday git sync command — requires the branch to already track a remote. |
672
+ | `gpu` | First push of a new local branch: sets it up to track `origin` and pushes (or just wires up tracking if `origin` already has a same-named branch). |
673
+ | `trackify` | Set the upstream tracking branch for the current branch to the same-named branch on `origin`, without pushing. Fails if that remote branch doesn't exist yet. |
674
+ | `tools-help` | Print every alias/function in `aliases.sh`, grouped, with a one-line summary parsed from each one's own doc comment — the full, always-current list (diff helpers, cleanup helpers, etc.) lives there instead of being duplicated in this table. |
638
675
 
639
676
  ## For Maintainers
640
677
 
641
678
  ### Clone and install
642
679
 
643
680
  ```bash
644
- git clone git@github.com:doikayt/typescript-build-config.git
681
+ git clone git@codeberg.org:doikayt/typescript-build-config.git
645
682
  cd typescript-build-config
646
683
  npm install
647
684
  ```
@@ -679,3 +716,6 @@ by hand, with what to look for at each step — follow
679
716
  MIT
680
717
 
681
718
 
719
+
720
+ [![Remember the USS Liberty!](https://badge.techforpalestine.org/ceasefire-now)](https://techforpalestine.org/learn-more)
721
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doikayt/typescript-build-config",
3
- "version": "0.1.32",
3
+ "version": "0.1.37",
4
4
  "description": "Shared build configuration for TypeScript projects — ESLint, Prettier, tsconfig, and Playwright presets",
5
5
  "_comments": {
6
6
  "exports": "This block lists the config files that will be extended by files in in src/toplevel - which are copied to consuming project root folder. An example: eslint.config.js imports from '@doikayt/typescript-build-config/eslint'.",
@@ -43,8 +43,8 @@
43
43
  "@playwright/test": "^1.40.0"
44
44
  },
45
45
  "dependencies": {
46
- "@typescript-eslint/eslint-plugin": "^8.0.0",
47
- "@typescript-eslint/parser": "^8.0.0",
46
+ "@typescript-eslint/eslint-plugin": "^8.57.1",
47
+ "@typescript-eslint/parser": "^8.57.1",
48
48
  "eslint": "^9.0.0",
49
49
  "prettier": "^3.0.0"
50
50
  },
@@ -59,12 +59,12 @@
59
59
  "license": "MIT",
60
60
  "repository": {
61
61
  "type": "git",
62
- "url": "git+ssh://git@github.com/doikayt/typescript-build-config.git"
62
+ "url": "git+ssh://git@codeberg.org/doikayt/typescript-build-config.git"
63
63
  },
64
64
  "peerDependencies": {
65
+ "@playwright/test": ">=1.40.0",
65
66
  "@typescript-eslint/eslint-plugin": "^8.57.1",
66
- "@typescript-eslint/parser": "^8.57.1",
67
- "@playwright/test": ">=1.40.0"
67
+ "@typescript-eslint/parser": "^8.57.1"
68
68
  },
69
69
  "peerDependenciesMeta": {
70
70
  "@playwright/test": {
@@ -31,7 +31,7 @@ export function canonicalScripts({ ui = false, library = false } = {}) {
31
31
  }
32
32
 
33
33
  export function devDependencyNames({ ui = false } = {}) {
34
- // @changesets/cli is required by the release pipeline (release.yml runs
34
+ // @changesets/cli is required by the release pipeline (.woodpecker.yml runs
35
35
  // `npx changeset version` / `publish`), so every consumer needs it installed —
36
36
  // otherwise `npx changeset` can't resolve the `changeset` bin and the release
37
37
  // job fails with "could not determine executable to run".
package/src/init.js CHANGED
@@ -28,6 +28,17 @@ function seedFile(src, destPath) {
28
28
  return "seeded";
29
29
  }
30
30
 
31
+ // Write an MIT LICENSE from the template when the project has none. The holder
32
+ // is the owning org (REPO_OWNER); without one, a neutral "project contributors".
33
+ function seedLicense(destPath, { holder, year }) {
34
+ if (existsSync(destPath)) return "skipped";
35
+ const text = readFileSync(resolve(templatesDir, "LICENSE"), "utf8")
36
+ .replace("{{YEAR}}", String(year))
37
+ .replace("{{HOLDER}}", holder);
38
+ writeFileSync(destPath, text);
39
+ return "seeded";
40
+ }
41
+
31
42
  // Recursively copy a template directory tree into the project.
32
43
  function copyDir(srcDir, destDir) {
33
44
  mkdirSync(destDir, { recursive: true });
@@ -83,6 +94,8 @@ export async function runInit({
83
94
  promptText,
84
95
  resolveDevVersions = resolveVersions,
85
96
  log = console.log,
97
+ licenseHolder = process.env.REPO_OWNER,
98
+ licenseYear = new Date().getFullYear(),
86
99
  } = {}) {
87
100
  // One readline interface for all prompts (see createAskYesNo); close it even
88
101
  // on error so a leftover interface never keeps the process alive.
@@ -98,6 +111,8 @@ export async function runInit({
98
111
  askText,
99
112
  resolveDevVersions,
100
113
  log,
114
+ licenseHolder,
115
+ licenseYear,
101
116
  });
102
117
  } finally {
103
118
  ownAsk?.close();
@@ -110,6 +125,8 @@ async function collectAndScaffold({
110
125
  askText,
111
126
  resolveDevVersions,
112
127
  log,
128
+ licenseHolder,
129
+ licenseYear,
113
130
  }) {
114
131
  const pkgPath = resolve(cwd, "package.json");
115
132
  const raw = readFileSync(pkgPath, "utf8");
@@ -146,12 +163,13 @@ async function collectAndScaffold({
146
163
  const scripts = canonicalScripts({ ui, library });
147
164
  const devDependencies = resolveDevVersions(devDependencyNames({ ui }));
148
165
 
149
- const fields = packageFields({ library });
166
+ const fields = { ...packageFields({ library }), license: "MIT" };
150
167
  // `npm init -y` seeds these placeholders; treat them as unset so the canonical
151
- // `test` script and (for a library) `main` replace them instead of shadowing.
168
+ // `test` script, `license` and (for a library) `main` replace them instead of
169
+ // shadowing.
152
170
  const replaceDefaults = {
153
171
  scripts: { test: 'echo "Error: no test specified" && exit 1' },
154
- fields: { main: "index.js" },
172
+ fields: { main: "index.js", license: "ISC" },
155
173
  };
156
174
  if (library) {
157
175
  // The chosen name is a deliberate publish decision, so it replaces whatever
@@ -177,6 +195,17 @@ async function collectAndScaffold({
177
195
  (result === "seeded" ? seededConfigs : keptConfigs).push(name);
178
196
  }
179
197
 
198
+ // Codeberg's CI access request requires a LICENSE file. Seed one only when
199
+ // the project's license is MIT (the canonical one), so a consumer who chose a
200
+ // different license is never handed a contradicting file.
201
+ if (JSON.parse(text).license === "MIT") {
202
+ const result = seedLicense(resolve(cwd, "LICENSE"), {
203
+ holder: licenseHolder || "the project contributors",
204
+ year: licenseYear,
205
+ });
206
+ (result === "seeded" ? seededConfigs : keptConfigs).push("LICENSE");
207
+ }
208
+
180
209
  const demo = wantDemo
181
210
  ? scaffoldDemo({ cwd })
182
211
  : {
@@ -3,9 +3,18 @@ import { resolve } from "path";
3
3
  import { spawnSync } from "child_process";
4
4
  import { scopeName } from "./scope-name.js";
5
5
 
6
+ export function npmExecutableName() {
7
+ return process.platform === "win32" ? "npm.cmd" : "npm";
8
+ }
9
+
6
10
  // Default `npm init -y` runner. Injectable so runNew is testable without npm.
7
11
  function npmInitY(cwd) {
8
- const res = spawnSync("npm", ["init", "-y"], { cwd, stdio: "inherit" });
12
+ const npmCommand = npmExecutableName();
13
+ const res = spawnSync(npmCommand, ["init", "-y"], {
14
+ cwd,
15
+ stdio: "inherit",
16
+ shell: process.platform === "win32",
17
+ });
9
18
  if (res.error) throw res.error;
10
19
  if (res.status !== 0)
11
20
  throw new Error(`npm init -y exited with ${res.status}`);
@@ -0,0 +1,50 @@
1
+ # Canonical pipeline is maintained in src/pipeline/woodpecker.yml.
2
+ # Keep this root copy in sync for this repository.
3
+ steps:
4
+ ci:
5
+ image: node:22
6
+ commands:
7
+ - npm ci
8
+ - npm run ci
9
+ - if [ "$CI_PIPELINE_EVENT" = "pull_request" ]; then npx changeset status; fi
10
+ when:
11
+ - event: [push, pull_request, tag]
12
+
13
+ verify-npm-token:
14
+ image: node:22
15
+ commands:
16
+ - 'echo "//registry.npmjs.org/:_authToken=$NPM" > ~/.npmrc'
17
+ - npm whoami
18
+ environment:
19
+ NPM:
20
+ from_secret: NPM
21
+ when:
22
+ - event: manual
23
+
24
+ release:
25
+ image: node:22
26
+ depends_on:
27
+ - ci
28
+ commands:
29
+ - apt-get update && apt-get install -y --no-install-recommends git bash
30
+ - npm ci
31
+ - 'if [ "$(git rev-parse --is-shallow-repository)" = true ]; then git fetch --unshallow --tags --force; else git fetch --tags --force; fi'
32
+ - git config user.name "doikayt-release-bot"
33
+ - git config user.email "doikayt-release-bot@codeberg.org"
34
+ - bash scripts/auto-changeset.sh
35
+ - npx changeset version
36
+ - git add .
37
+ - 'git diff --staged --quiet || git commit -m "chore: release [CI SKIP]"'
38
+ - git remote set-url origin "https://$CODEBERG_TOKEN@codeberg.org/$CI_REPO.git"
39
+ - git push origin HEAD:main
40
+ - 'echo "//registry.npmjs.org/:_authToken=$NPM" > ~/.npmrc'
41
+ - npx changeset publish
42
+ - git push origin --tags
43
+ environment:
44
+ CODEBERG_TOKEN:
45
+ from_secret: CODEBERG_TOKEN
46
+ NPM:
47
+ from_secret: NPM
48
+ when:
49
+ - event: push
50
+ branch: main
@@ -9,12 +9,35 @@ import { resolve, dirname } from "path";
9
9
  import { execSync } from "child_process";
10
10
  import { tmpdir } from "os";
11
11
  import { join } from "path";
12
+ import { fileURLToPath } from "url";
12
13
 
13
14
  const PREFIX = "[@doikayt/typescript-build-config]";
14
15
 
16
+ export function normalizeProjectRoot(rawPath) {
17
+ if (!rawPath) return rawPath;
18
+
19
+ let normalized = rawPath.replace(/^[A-Za-z]:\\C:\\/, "C:\\");
20
+ normalized = normalized.replace(
21
+ /^\/([A-Za-z])\//,
22
+ (_, drive) => `${drive.toUpperCase()}:\\`,
23
+ );
24
+ normalized = normalized.replace(/^\//, "");
25
+ normalized = normalized.replace(/\\+/g, "\\");
26
+
27
+ if (/^([A-Za-z]):\\/.test(normalized)) {
28
+ return normalized.replace(/\\+/g, "\\");
29
+ }
30
+
31
+ if (/^([A-Za-z]):\//.test(normalized)) {
32
+ return normalized.replace(/\//g, "\\");
33
+ }
34
+
35
+ return normalized;
36
+ }
37
+
15
38
  console.log(`${PREFIX} Running postinstall...`);
16
39
 
17
- const projectRoot = process.env.INIT_CWD ?? process.cwd();
40
+ const projectRoot = normalizeProjectRoot(process.env.INIT_CWD ?? process.cwd());
18
41
  const projectPkgPath = resolve(projectRoot, "package.json");
19
42
 
20
43
  // Installed via `npx @doikayt/... new` into a bare dir (or otherwise before a
@@ -34,8 +57,8 @@ if (projectPkg.name === "@doikayt/typescript-build-config") {
34
57
  process.exit(0);
35
58
  }
36
59
 
37
- const srcDir = new URL("top-level", import.meta.url).pathname;
38
- const pipelineDir = new URL("pipeline", import.meta.url).pathname;
60
+ const srcDir = fileURLToPath(new URL("top-level", import.meta.url));
61
+ const pipelineDir = fileURLToPath(new URL("pipeline", import.meta.url));
39
62
 
40
63
  // --- Top-level config files: all-or-nothing ---
41
64
 
@@ -72,13 +95,9 @@ if (alreadyExist.length > 0) {
72
95
  // --- Pipeline files: per-file copy/warn/diff ---
73
96
 
74
97
  const pipelineFiles = [
75
- { src: "release.yml", dest: ".github/workflows/release.yml" },
98
+ { src: "woodpecker.yml", dest: ".woodpecker.yml" },
76
99
  { src: "changeset-config.json", dest: ".changeset/config.json" },
77
100
  { src: "auto-changeset.sh", dest: "scripts/auto-changeset.sh" },
78
- {
79
- src: "verify-npm-token.yml",
80
- dest: ".github/workflows/verify-npm-token.yml",
81
- },
82
101
  ];
83
102
 
84
103
  for (const { src, dest } of pipelineFiles) {
@@ -111,7 +130,7 @@ for (const { src, dest } of pipelineFiles) {
111
130
 
112
131
  // --- Asset files: seeded into docs/assets/, same per-file copy/warn as pipeline ---
113
132
 
114
- const assetDir = new URL("../assets/image", import.meta.url).pathname;
133
+ const assetDir = fileURLToPath(new URL("../assets/image", import.meta.url));
115
134
 
116
135
  const assetFiles = [
117
136
  { src: "doikayt-logo.png", dest: "docs/assets/doikayt-logo.png" },
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) {{YEAR}} {{HOLDER}}
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -9,7 +9,7 @@
9
9
  > before you write any code. Replace them with your own whenever you like —
10
10
  > `init` printed the exact paths to delete.
11
11
 
12
- Run `npm run update-all-format` to fill the blocks below; GitHub renders the
12
+ Run `npm run update-all-format` to fill the blocks below; Codeberg renders the
13
13
  Mermaid diagrams inline from the fenced blocks.
14
14
 
15
15
  ## Build Pipeline
@@ -40,3 +40,5 @@ npm test # the seeded vitest test passes
40
40
  npm run update-all-format # fills the doc blocks above
41
41
  git commit -am "feat: initial version" && git push # feat:/fix: cut a release (npm publish if a library)
42
42
  ```
43
+
44
+ [![Free Palestine!](https://badge.techforpalestine.org/ceasefire-now)](https://techforpalestine.org/learn-more)
@@ -1,2 +1,3 @@
1
1
  The math-engine component: a small, dependency-free arithmetic core. It validates
2
2
  operands and returns a structured result describing the operation performed.
3
+
@@ -1,72 +0,0 @@
1
- name: CI / Release
2
-
3
- permissions:
4
- contents: write
5
-
6
- on:
7
- workflow_dispatch:
8
- push:
9
- branches: [main]
10
- pull_request:
11
-
12
- jobs:
13
- ci:
14
- runs-on: ubuntu-latest
15
- steps:
16
- - uses: actions/checkout@v5
17
- - uses: actions/setup-node@v5
18
- with:
19
- node-version: 22
20
- cache: npm
21
- - run: npm ci
22
- - run: npm run ci
23
- - name: Check Changesets (PR only)
24
- if: github.event_name == 'pull_request'
25
- run: npx changeset status
26
-
27
- release:
28
- needs: ci
29
- if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
30
- permissions:
31
- contents: write
32
- id-token: write
33
- concurrency:
34
- group: release
35
- cancel-in-progress: false
36
- runs-on: ubuntu-latest
37
- steps:
38
- - uses: actions/checkout@v5
39
- with:
40
- fetch-depth: 0
41
- - uses: actions/setup-node@v5
42
- with:
43
- node-version: 22
44
- registry-url: https://registry.npmjs.org
45
- cache: npm
46
- - run: npm ci
47
- - name: Configure git
48
- run: |
49
- git config user.name "github-actions[bot]"
50
- git config user.email "github-actions[bot]@users.noreply.github.com"
51
- - name: Auto-generate changeset from commits
52
- run: bash scripts/auto-changeset.sh
53
- - name: Apply version bumps
54
- run: npx changeset version
55
- - name: Commit and push version bumps
56
- run: |
57
- git add .
58
- git diff --staged --quiet && echo "No changesets to release" || \
59
- (git commit -m "chore: release [skip ci]" && git push)
60
- - name: Publish
61
- id: publish
62
- run: npx changeset publish
63
- env:
64
- NODE_AUTH_TOKEN: ${{ secrets.NPM }}
65
- - name: Push release tags
66
- run: git push --tags
67
- - name: Post-publish hook (optional)
68
- if: steps.publish.outcome == 'success'
69
- run: |
70
- node -e "process.exit(require('./package.json').scripts?.['post-publish'] ? 0 : 1)" \
71
- && npm run post-publish \
72
- || echo "No post-publish script — skipping"
@@ -1,17 +0,0 @@
1
- name: Verify NPM Token
2
-
3
- on:
4
- workflow_dispatch:
5
-
6
- jobs:
7
- verify-token:
8
- runs-on: ubuntu-latest
9
- steps:
10
- - uses: actions/setup-node@v5
11
- with:
12
- node-version: 22
13
- registry-url: https://registry.npmjs.org
14
- - name: Check npm auth
15
- run: npm whoami
16
- env:
17
- NODE_AUTH_TOKEN: ${{ secrets.NPM }}