@skyf0xx/hedgehog 6.2.2 → 6.2.3
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 +1 -0
- package/README.zh-CN.md +1 -0
- package/bin/cli.mjs +1 -6
- package/package.json +8 -3
- package/src/db/drift.mjs +0 -1
- package/src/db/gate.mjs +1 -1
- package/src/db/notes.mjs +1 -1
- package/src/db/overrides.mjs +1 -1
- package/src/db/plan.mjs +2 -2
- package/src/db/rebuild.mjs +2 -2
- package/src/db/reconcile.mjs +1 -1
- package/src/db/verify.mjs +1 -0
- package/src/db/worktree.mjs +1 -1
- package/src/hosts/gemini/gemini-extension.json +1 -1
- package/src/registry/fetch.mjs +2 -2
- package/src/skills/hedgehog-daily/SKILL.md +20 -11
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ English | [简体中文](README.zh-CN.md)
|
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[](https://github.com/skyf0xx/hedgehog/actions/workflows/codeql.yml)
|
|
14
14
|
[](https://github.com/skyf0xx/hedgehog/actions/workflows/check.yml)
|
|
15
|
+
[](https://www.bestpractices.dev/projects/14399)
|
|
15
16
|
|
|
16
17
|
AI can write code in seconds.
|
|
17
18
|
|
package/README.zh-CN.md
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[](https://github.com/skyf0xx/hedgehog/actions/workflows/codeql.yml)
|
|
14
14
|
[](https://github.com/skyf0xx/hedgehog/actions/workflows/check.yml)
|
|
15
|
+
[](https://www.bestpractices.dev/projects/14399)
|
|
15
16
|
|
|
16
17
|
AI 能在几秒钟内写出代码。
|
|
17
18
|
|
package/bin/cli.mjs
CHANGED
|
@@ -78,17 +78,13 @@ import {
|
|
|
78
78
|
createWorktree,
|
|
79
79
|
hedgehogWorktrees,
|
|
80
80
|
branchName,
|
|
81
|
-
worktreePath,
|
|
82
81
|
intentReadyToMerge,
|
|
83
|
-
intentTaskStatuses,
|
|
84
82
|
mergeBranch,
|
|
85
83
|
removeWorktree,
|
|
86
84
|
intentFileCommitted,
|
|
87
85
|
onHedgehogBranch,
|
|
88
|
-
loadAbandoned,
|
|
89
86
|
writeAbandonedFile,
|
|
90
87
|
applyAbandonment,
|
|
91
|
-
replayAbandonments,
|
|
92
88
|
ABANDONED_DIR,
|
|
93
89
|
} from '../src/db/worktree.mjs';
|
|
94
90
|
import { loadOverrides, addOverride, orphanedOverrides, OVERRIDES_DIR } from '../src/db/overrides.mjs';
|
|
@@ -126,7 +122,6 @@ const BLOCKED_REASON_LABELS = {
|
|
|
126
122
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
127
123
|
const PKG_ROOT = resolve(__dirname, '..');
|
|
128
124
|
const DEST_ROOT = process.cwd();
|
|
129
|
-
const DEFAULT_CORE = 'full-stack-app';
|
|
130
125
|
|
|
131
126
|
// The version of the payload this CLI carries — what `init` and
|
|
132
127
|
// `update` stamp into the project they write to.
|
|
@@ -3342,7 +3337,7 @@ async function reconcileCommand(args) {
|
|
|
3342
3337
|
if (sub === 'list') {
|
|
3343
3338
|
const reconciliations = await loadReconciliations();
|
|
3344
3339
|
const db = openDb({ readOnly: true });
|
|
3345
|
-
let orphaned
|
|
3340
|
+
let orphaned;
|
|
3346
3341
|
try {
|
|
3347
3342
|
orphaned = orphanedReconciliations(db, reconciliations);
|
|
3348
3343
|
} finally {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyf0xx/hedgehog",
|
|
3
|
-
"version": "6.2.
|
|
3
|
+
"version": "6.2.3",
|
|
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": {
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"hedgehog": "bin/cli.mjs"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"
|
|
17
|
+
"lint": "eslint .",
|
|
18
|
+
"check": "npm run lint && node scripts/check.mjs",
|
|
18
19
|
"repro": "node --experimental-sqlite repro/run-all.mjs",
|
|
19
20
|
"release": "node scripts/bump-package-version.mjs",
|
|
20
21
|
"release:plugin": "node scripts/bump-plugin-version.mjs"
|
|
@@ -43,5 +44,9 @@
|
|
|
43
44
|
"scaffold",
|
|
44
45
|
"hedgehog"
|
|
45
46
|
],
|
|
46
|
-
"license": "MIT"
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@eslint/js": "^10.0.1",
|
|
50
|
+
"eslint": "^10.9.1"
|
|
51
|
+
}
|
|
47
52
|
}
|
package/src/db/drift.mjs
CHANGED
|
@@ -32,7 +32,6 @@ import {
|
|
|
32
32
|
CORE_MODULE,
|
|
33
33
|
loadIntentDependencies,
|
|
34
34
|
} from './plan.mjs';
|
|
35
|
-
import { loadOverrides } from './overrides.mjs';
|
|
36
35
|
|
|
37
36
|
// Statuses a field rewrite is safe on: nothing has been built, leased,
|
|
38
37
|
// committed, or failed against these rows yet, so moving their ALLOWED
|
package/src/db/gate.mjs
CHANGED
package/src/db/notes.mjs
CHANGED
|
@@ -79,7 +79,7 @@ export async function loadNotes(notesDir = NOTES_DIR) {
|
|
|
79
79
|
try {
|
|
80
80
|
parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
81
81
|
} catch (err) {
|
|
82
|
-
throw new Error(`could not read notes file ${path}: ${err.message}
|
|
82
|
+
throw new Error(`could not read notes file ${path}: ${err.message}`, { cause: err });
|
|
83
83
|
}
|
|
84
84
|
const { task, notes } = validateNotesFile(parsed, path);
|
|
85
85
|
byTask.set(task, notes);
|
package/src/db/overrides.mjs
CHANGED
|
@@ -122,7 +122,7 @@ export async function loadOverrides(overridesDir = OVERRIDES_DIR) {
|
|
|
122
122
|
try {
|
|
123
123
|
parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
124
124
|
} catch (err) {
|
|
125
|
-
throw new Error(`could not read override file ${path}: ${err.message}
|
|
125
|
+
throw new Error(`could not read override file ${path}: ${err.message}`, { cause: err });
|
|
126
126
|
}
|
|
127
127
|
const record = validateOverride(parsed, path);
|
|
128
128
|
if (!byTask.has(record.task)) byTask.set(record.task, []);
|
package/src/db/plan.mjs
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// graph holds. Without it such a layer compiles once per intent and
|
|
20
20
|
// every copy but the first is a replay of the same command.
|
|
21
21
|
|
|
22
|
-
import { composeScope
|
|
22
|
+
import { composeScope } from './overrides.mjs';
|
|
23
23
|
|
|
24
24
|
export function fillModule(template, module) {
|
|
25
25
|
return template.replaceAll('{module}', module);
|
|
@@ -535,7 +535,7 @@ export function planTasks(db, core, overrides = new Map(), { excludeIntentIds =
|
|
|
535
535
|
const compiledOnceTaskIds = [];
|
|
536
536
|
// Once-tasks that a newly compiled intent hangs a prerequisite on.
|
|
537
537
|
const onceTasksGainingPrereqs = [];
|
|
538
|
-
let reopenedOnceTaskIds
|
|
538
|
+
let reopenedOnceTaskIds;
|
|
539
539
|
|
|
540
540
|
db.exec('BEGIN IMMEDIATE');
|
|
541
541
|
try {
|
package/src/db/rebuild.mjs
CHANGED
|
@@ -198,12 +198,12 @@ async function replayIntents(db, intentsDir) {
|
|
|
198
198
|
try {
|
|
199
199
|
parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
200
200
|
} catch (err) {
|
|
201
|
-
throw new Error(`could not read intent file ${path}: ${err.message}
|
|
201
|
+
throw new Error(`could not read intent file ${path}: ${err.message}`, { cause: err });
|
|
202
202
|
}
|
|
203
203
|
try {
|
|
204
204
|
records.push({ file, intent: normalizeIntent(parsed) });
|
|
205
205
|
} catch (err) {
|
|
206
|
-
throw new Error(`invalid intent file ${path}: ${err.message}
|
|
206
|
+
throw new Error(`invalid intent file ${path}: ${err.message}`, { cause: err });
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
|
package/src/db/reconcile.mjs
CHANGED
|
@@ -148,7 +148,7 @@ export async function loadReconciliations(reconciledDir = RECONCILED_DIR) {
|
|
|
148
148
|
try {
|
|
149
149
|
parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
150
150
|
} catch (err) {
|
|
151
|
-
throw new Error(`could not read reconciliation file ${path}: ${err.message}
|
|
151
|
+
throw new Error(`could not read reconciliation file ${path}: ${err.message}`, { cause: err });
|
|
152
152
|
}
|
|
153
153
|
const record = validateReconciled(parsed, path);
|
|
154
154
|
byTask.set(record.task, record);
|
package/src/db/verify.mjs
CHANGED
|
@@ -562,6 +562,7 @@ export function verifyTask(db, taskId, owner) {
|
|
|
562
562
|
`the cause (a rejecting git hook, commit signing, or git identity), then ` +
|
|
563
563
|
`re-run \`hedgehog verify ${task.id} --owner ${owner}\`, or hand it back ` +
|
|
564
564
|
`with \`hedgehog release ${task.id} --owner ${owner}\`.\n\n${err.message}`,
|
|
565
|
+
{ cause: err },
|
|
565
566
|
);
|
|
566
567
|
}
|
|
567
568
|
|
package/src/db/worktree.mjs
CHANGED
|
@@ -376,7 +376,7 @@ export async function loadAbandoned(abandonedDir = ABANDONED_DIR) {
|
|
|
376
376
|
try {
|
|
377
377
|
parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
378
378
|
} catch (err) {
|
|
379
|
-
throw new Error(`could not read abandonment file ${path}: ${err.message}
|
|
379
|
+
throw new Error(`could not read abandonment file ${path}: ${err.message}`, { cause: err });
|
|
380
380
|
}
|
|
381
381
|
const record = validateAbandoned(parsed, path);
|
|
382
382
|
byIntent.set(record.intent, record);
|
package/src/registry/fetch.mjs
CHANGED
|
@@ -122,14 +122,14 @@ async function packAndExtract(entry) {
|
|
|
122
122
|
tarball = join(tmp, JSON.parse(stdout)[0].filename);
|
|
123
123
|
} catch (err) {
|
|
124
124
|
await rm(tmp, { recursive: true, force: true });
|
|
125
|
-
throw new Error(unresolvableMessage(entry, spec, err));
|
|
125
|
+
throw new Error(unresolvableMessage(entry, spec, err), { cause: err });
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
try {
|
|
129
129
|
await execFileAsync('tar', ['-xzf', tarball, '-C', tmp]);
|
|
130
130
|
} catch (err) {
|
|
131
131
|
await rm(tmp, { recursive: true, force: true });
|
|
132
|
-
throw new Error(`Could not extract ${entry.package} from ${tarball}: ${err.message}
|
|
132
|
+
throw new Error(`Could not extract ${entry.package} from ${tarball}: ${err.message}`, { cause: err });
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
const root = join(tmp, TARBALL_ROOT);
|
|
@@ -29,22 +29,31 @@ with a real cost, taken on stated conditions — not the safe default.
|
|
|
29
29
|
## The three exits
|
|
30
30
|
|
|
31
31
|
Decide by the conditions, in order. The first one that holds is the exit.
|
|
32
|
+
Re-plan is checked first, and its check is a read to make, not a
|
|
33
|
+
suspicion to already hold — do not reach Change-work or Tweak without
|
|
34
|
+
having made it.
|
|
32
35
|
|
|
33
36
|
### Re-plan
|
|
34
37
|
|
|
35
|
-
The
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
for an adopted one.
|
|
38
|
+
The core's own loop skill names which artifact governs this project —
|
|
39
|
+
the brief and layer sequence for a shipped core, `.hedgehog/core-design.md`
|
|
40
|
+
for an authored one, `.hedgehog/adoption.md` for an adopted one. Read
|
|
41
|
+
that artifact, then check:
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
already built.
|
|
43
|
+
- Does anything the request needs contradict a statement locked there —
|
|
44
|
+
an interface, a stack choice, a scope boundary?
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
If it holds, this is Re-plan — regardless of how many layers the request
|
|
47
|
+
reaches or whether every file it touches already exists. Route to
|
|
48
|
+
`planner`'s re-entry pass, which adds intents for new work without
|
|
49
|
+
re-running planning from scratch and without disturbing anything already
|
|
50
|
+
built.
|
|
51
|
+
|
|
52
|
+
Where the contradiction means the request is a different project rather
|
|
53
|
+
than an extension of this one, say so plainly instead of routing. That
|
|
54
|
+
artifact is never rewritten to accommodate new scope.
|
|
55
|
+
|
|
56
|
+
If it does not hold, move on to Change-work.
|
|
48
57
|
|
|
49
58
|
### Change-work
|
|
50
59
|
|