@skyf0xx/hedgehog 6.2.10 → 6.2.12

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/bin/cli.mjs CHANGED
@@ -13,10 +13,11 @@
13
13
  // npx @skyf0xx/hedgehog update refresh the installed agents + skills
14
14
  // npx @skyf0xx/hedgehog --help
15
15
 
16
- import { cp, mkdir, access, readdir, stat, rm, readFile, writeFile } from 'node:fs/promises';
16
+ import { cp, mkdir, access, readdir, stat, rm, readFile, writeFile, mkdtemp } from 'node:fs/promises';
17
17
  import { constants, existsSync, realpathSync } from 'node:fs';
18
18
  import { fileURLToPath } from 'node:url';
19
19
  import { dirname, join, relative, resolve } from 'node:path';
20
+ import { tmpdir } from 'node:os';
20
21
  import { spawn, execFileSync } from 'node:child_process';
21
22
  import { dbInit, DB_PATH, dbAbsPath, openDb, openDbAt } from '../src/db/init.mjs';
22
23
  import { loadCore, lintCore, isModuleAxis } from '../src/db/core.mjs';
@@ -121,6 +122,40 @@ const BLOCKED_REASON_LABELS = {
121
122
 
122
123
  const __dirname = dirname(fileURLToPath(import.meta.url));
123
124
  const PKG_ROOT = resolve(__dirname, '..');
125
+
126
+ // The copywriting core never installs into the directory it was invoked
127
+ // from — every draft it produces is ephemeral scratch, and only the
128
+ // finished piece is meant to reach the user's real project (as a plain
129
+ // file, copied out by hedgehog-copywriting-loop's own courtesy-export
130
+ // step). Relying on every caller (an agent reading a skill's prose, a
131
+ // human typing the command by hand) to remember to cd into a scratch
132
+ // directory first is exactly the kind of instruction that gets skipped
133
+ // under context pressure — so `init --copywriting` enforces it here
134
+ // instead, unconditionally, before DEST_ROOT is ever read. This has to
135
+ // run before any other module-level state is computed from `process.cwd()`
136
+ // — a raw argv scan rather than the full async arg parser lower in this
137
+ // file, since nothing below has run yet at this point in module load.
138
+ const ORIGDIR = process.cwd();
139
+ {
140
+ // Catches both the shorthand (`--copywriting`) and the generic named-core
141
+ // form (`--core copywriting`, `--core=copywriting`) — namedCore()/
142
+ // coreFlags() do the real resolution later, async, off the registry, but
143
+ // this has to run synchronously before that and before DEST_ROOT below,
144
+ // so it matches the raw argv directly rather than waiting for it.
145
+ const rest = process.argv.slice(2);
146
+ const coreIdx = rest.indexOf('--core');
147
+ const isCopywriting =
148
+ rest.includes('--copywriting') ||
149
+ rest[coreIdx + 1] === 'copywriting' ||
150
+ rest.includes('--core=copywriting');
151
+ if (isCopywriting) {
152
+ const scratch = await mkdtemp(join(tmpdir(), 'hedgehog-copywriting-'));
153
+ process.chdir(scratch);
154
+ // No ANSI helpers yet — `dim` etc. are defined further down, after
155
+ // DEST_ROOT, and this has to run before DEST_ROOT is computed.
156
+ console.log(` (copywriting installs to a scratch directory, never here — using ${scratch})`);
157
+ }
158
+ }
124
159
  const DEST_ROOT = process.cwd();
125
160
 
126
161
  // The version of the payload this CLI carries — what `init` and
@@ -865,9 +900,22 @@ async function init({ force, core, host = DEFAULT_HOST, hostOnly = false, global
865
900
  ` 0. ${bold(`npx @skyf0xx/hedgehog@latest update`)} ${dim(`(picks up ${globalInstall.latest} before intake begins)`)}`,
866
901
  );
867
902
  }
868
- // A core that landed a workspace landed its root package.json with it,
869
- // so there are dependencies to install before the first commit.
870
- if (core?.manifest.workspace) {
903
+ // Copywriting never lands anywhere the caller can see directly (see the
904
+ // chdir into a scratch tempdir at module load, above) — the ordinary
905
+ // "commit here, describe what you want to build" steps assume a project
906
+ // the human is looking at, which this scratch directory isn't. Point at
907
+ // the loop skill instead; it owns pnpm install, the draft/checkCopy()
908
+ // cycle, and the courtesy export of the finished piece back to ORIGDIR.
909
+ if (core?.manifest.name === 'copywriting') {
910
+ console.log(
911
+ ` 1. Read ${bold(`${HOSTS[host].skillsDir}/hedgehog-copywriting-loop/SKILL.md`)} and follow it`,
912
+ );
913
+ console.log(dim(` for everything from here, staying inside ${bold(DEST_ROOT)}.`));
914
+ console.log(
915
+ dim(` The finished piece lands back at ${bold(ORIGDIR)} on its own — nothing`),
916
+ );
917
+ console.log(dim(' else needs doing there.'));
918
+ } else if (core?.manifest.workspace) {
871
919
  // `pnpm install` before the first commit, not after it. The core's
872
920
  // commit gate is lefthook, and lefthook's hooks are written by its
873
921
  // own postinstall — so a commit made before the install is a commit
@@ -900,19 +948,23 @@ async function init({ force, core, host = DEFAULT_HOST, hostOnly = false, global
900
948
  // the session that ran this install — no restart, no dependence on whether
901
949
  // the harness re-scans its agent directory, and no chance of a bare
902
950
  // `planner` resolving to an unrelated global agent of the same name.
903
- const agents = HOSTS[host].agentsDir;
904
- const skills = HOSTS[host].skillsDir;
905
- console.log(
906
- dim(
907
- ` Read ${bold(`${agents}/planner.md`)} and follow it — it runs planning\n` +
908
- ` intake (${skills}/hedgehog-planning-intake/SKILL.md), then hands\n` +
909
- ` off to ${agents}/bootstrap.md.\n` +
910
- ` Some hosts register agents/skills once, at session start: if a\n` +
911
- ` later dispatch by name reports one of these as not found, read\n` +
912
- ` its file directly instead — it becomes dispatchable by name after\n` +
913
- ` a session restart or a fresh context.`,
914
- ),
915
- );
951
+ // Copywriting's own branch above already named its hand-off (the loop
952
+ // skill, not planner/bootstrap — this core has no bootstrap step).
953
+ if (core?.manifest.name !== 'copywriting') {
954
+ const agents = HOSTS[host].agentsDir;
955
+ const skills = HOSTS[host].skillsDir;
956
+ console.log(
957
+ dim(
958
+ ` Read ${bold(`${agents}/planner.md`)} and follow it it runs planning\n` +
959
+ ` intake (${skills}/hedgehog-planning-intake/SKILL.md), then hands\n` +
960
+ ` off to ${agents}/bootstrap.md.\n` +
961
+ ` Some hosts register agents/skills once, at session start: if a\n` +
962
+ ` later dispatch by name reports one of these as not found, read\n` +
963
+ ` its file directly instead — it becomes dispatchable by name after\n` +
964
+ ` a session restart or a fresh context.`,
965
+ ),
966
+ );
967
+ }
916
968
  console.log();
917
969
  if (core) {
918
970
  console.log(dim(`Core: ${bold(core.manifest.name)} ${dim(`(${core.version})`)}.`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyf0xx/hedgehog",
3
- "version": "6.2.10",
3
+ "version": "6.2.12",
4
4
  "description": "Install the Hedgehog build discipline (agents + skills) into a repo, for Claude Code, Cursor, or Gemini CLI.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -17,8 +17,7 @@
17
17
  "lint": "eslint .",
18
18
  "check": "npm run lint && node scripts/check.mjs",
19
19
  "repro": "node --experimental-sqlite repro/run-all.mjs",
20
- "release": "node scripts/bump-package-version.mjs",
21
- "release:plugin": "node scripts/bump-plugin-version.mjs"
20
+ "release": "node scripts/bump-package-version.mjs"
22
21
  },
23
22
  "files": [
24
23
  "bin",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgehog",
3
- "version": "6.2.10",
3
+ "version": "6.2.12",
4
4
  "description": "Hedgehog build discipline: ordered, tested, verified build steps.",
5
5
  "contextFileName": "GEMINI.md"
6
6
  }
@@ -55,10 +55,10 @@
55
55
  {
56
56
  "name": "copywriting",
57
57
  "flag": "--copywriting",
58
- "package": "@skyf0xx/hedgehog-core-copywriting",
59
- "version": "^0.1.1",
58
+ "package": "@skyf0xx/hedgehog-core-copywriting-prose-engineering",
59
+ "version": "^0.2.0",
60
60
  "language": "typescript",
61
- "repository": "https://github.com/skyf0xx/hedgehog-core-copywriting",
61
+ "repository": "https://github.com/skyf0xx/hedgehog-core-copywriting-prose-engineering",
62
62
  "selects_when": "The description asks for a piece of writing or prose to be written or fixed as its own deliverable — marketing copy, a product announcement, UI microcopy strings, docs prose, an email, a pitch, an article, an essay, a blog post, or any other standalone written piece — with no page, app, or other artifact being built around it. Concrete signals: \"write an article about X\", \"write copy for X\", \"help me write a blog post\", \"make this sound less like AI\", \"fix this copy\", \"improve this writing\", \"draft a product announcement\", a request to run text through an AI-tell or humanizer check. Not just marketing/product framing — any standalone prose request qualifies, articles and essays included. The core drafts against `checkCopy()`, a real script running deterministic AI-tell and prose-quality checks (banned vocabulary, passive voice, readability score, sentence-length variance), not an agent's own self-review — a piece of writing ships because the script exited 0. This is the core most often confused with landing-page: landing-page's own copy skill still owns copy that's part of a full page build (headline, hero, section copy sequenced through that core's Chain Method); route here only when the writing is the entire ask, not one stage of a larger build."
63
63
  }
64
64
  ]