forge-workflow 0.1.0-beta.5 → 0.1.0-beta.7
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/AGENTS.md +4 -0
- package/CHANGELOG.md +48 -0
- package/CLAUDE.md +0 -12
- package/CODING_STANDARDS.md +72 -0
- package/bin/forge.js +12 -1
- package/docs/guides/MIGRATION.md +3 -3
- package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +4 -0
- package/docs/reference/INSTALL.md +4 -0
- package/docs/reference/LEGACY_CLAIM_REPAIR.md +112 -0
- package/docs/reference/RELEASE.md +4 -4
- package/docs/reference/github-accounts.md +134 -0
- package/docs/reference/shepherd.md +63 -13
- package/lib/adapters/pr-state-adapter.js +15 -2
- package/lib/base-remote.js +138 -0
- package/lib/beta5-compatibility-evidence.js +1093 -0
- package/lib/bun-lockfile-proof.js +413 -0
- package/lib/bun-workflow-pins.js +461 -0
- package/lib/capabilities/index.js +9 -0
- package/lib/capabilities/model.js +141 -0
- package/lib/capabilities/probes.js +347 -0
- package/lib/codex-skills.js +2 -2
- package/lib/commands/_manifest.js +1 -0
- package/lib/commands/_registry.js +48 -18
- package/lib/commands/clean.js +57 -1
- package/lib/commands/doctor.js +37 -6
- package/lib/commands/gate.js +197 -27
- package/lib/commands/github.js +215 -0
- package/lib/commands/hooks.js +54 -6
- package/lib/commands/memory.js +66 -2
- package/lib/commands/merge.js +720 -73
- package/lib/commands/plan.js +33 -2
- package/lib/commands/pr.js +2 -0
- package/lib/commands/preflight.js +10 -2
- package/lib/commands/push.js +120 -9
- package/lib/commands/recall.js +95 -61
- package/lib/commands/release.js +23 -2
- package/lib/commands/remember.js +28 -4
- package/lib/commands/serve.js +26 -9
- package/lib/commands/setup.js +132 -4
- package/lib/commands/shepherd.js +578 -72
- package/lib/commands/ship.js +15 -69
- package/lib/commands/skill.js +8 -0
- package/lib/commands/team.js +47 -8
- package/lib/commands/test.js +163 -4
- package/lib/commands/validate.js +78 -22
- package/lib/commands/worktree.js +155 -19
- package/lib/fixtures/beta5-corpus/v1/README.md +9 -0
- package/lib/fixtures/beta5-corpus/v1/contract/command-contract.json +26 -0
- package/lib/fixtures/beta5-corpus/v1/contract/package-contract.json +13 -0
- package/lib/fixtures/beta5-corpus/v1/contract/workflow-stage-matrix.json +8 -0
- package/lib/fixtures/beta5-corpus/v1/manifest.json +25 -0
- package/lib/fixtures/beta5-corpus/v1/state/comments.jsonl +1 -0
- package/lib/fixtures/beta5-corpus/v1/state/config.yaml +6 -0
- package/lib/fixtures/beta5-corpus/v1/state/dependencies.jsonl +1 -0
- package/lib/fixtures/beta5-corpus/v1/state/issues.jsonl +2 -0
- package/lib/fixtures/beta5-corpus/v1/state/kernel.sql +20 -0
- package/lib/forge-issues.js +78 -0
- package/lib/gate-events.js +98 -10
- package/lib/github-context.js +308 -0
- package/lib/global-flags.js +1 -0
- package/lib/hook-renderer.js +29 -1
- package/lib/issue-render.js +19 -0
- package/lib/kernel/broker.js +723 -31
- package/lib/kernel/claim-reconciler.js +238 -0
- package/lib/kernel/lease-enforcer.js +9 -4
- package/lib/kernel/legacy-claim-repair.js +442 -0
- package/lib/kernel/live-claim-projection.js +26 -0
- package/lib/kernel/migrations.js +118 -3
- package/lib/kernel/readiness-model.js +184 -12
- package/lib/kernel/schema.js +49 -1
- package/lib/kernel/sqlite-driver.js +3322 -183
- package/lib/kernel/taxonomy-validator.js +4 -1
- package/lib/kernel/windows-private-acl.js +239 -0
- package/lib/memory/hygiene.js +191 -0
- package/lib/memory/router.js +94 -27
- package/lib/memory/usage-evidence.js +4 -0
- package/lib/memory-digest.js +59 -0
- package/lib/merge-rules.js +135 -17
- package/lib/npm-publish-workflow.js +233 -40
- package/lib/package-root.js +2 -0
- package/lib/pr-monitor/auto-actions.js +169 -28
- package/lib/pr-monitor/differ.js +110 -4
- package/lib/pr-monitor/events.js +0 -0
- package/lib/pr-monitor/flow-monitor.js +1424 -0
- package/lib/pr-monitor/gather.js +251 -44
- package/lib/pr-monitor/journal.js +0 -37
- package/lib/pr-monitor/monitor.js +117 -10
- package/lib/pr-monitor/process-identity.js +117 -0
- package/lib/pr-monitor/reconcile-executor.js +1101 -625
- package/lib/pr-monitor/reconcile.js +0 -0
- package/lib/pr-monitor/render-summary.js +121 -24
- package/lib/pr-monitor/review-preflight.js +269 -0
- package/lib/pr-monitor/shepherd-lease.js +28 -19
- package/lib/pr-monitor/verdict.js +438 -0
- package/lib/pr-monitor/watch-lifecycle.js +144 -38
- package/lib/pr-monitor/watch-owner.js +1414 -0
- package/lib/pr-monitor/watch.js +129 -58
- package/lib/pr-shepherd.js +17 -3
- package/lib/project-memory.js +145 -3
- package/lib/protected-state-authority.js +799 -4
- package/lib/protected-state-surfaces.js +181 -3
- package/lib/release-readiness.js +2 -3
- package/lib/review-adapter.js +65 -0
- package/lib/skills-sync.js +65 -32
- package/lib/validation/risk-manifest.js +339 -0
- package/lib/validation-receipt.js +190 -0
- package/lib/workflow/enforce-stage.js +44 -0
- package/lib/workflow/plan-authority.js +225 -0
- package/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
- package/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
- package/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
- package/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
- package/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
- package/node_modules/@forge/contracts/index.js +32 -0
- package/node_modules/@forge/contracts/package.json +35 -0
- package/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
- package/node_modules/@forge/contracts/src/baseline.js +23 -0
- package/node_modules/@forge/contracts/src/canonical.js +151 -0
- package/node_modules/@forge/contracts/src/definitions.js +176 -0
- package/node_modules/@forge/contracts/src/identity.js +42 -0
- package/node_modules/@forge/contracts/src/schema.js +72 -0
- package/node_modules/@forge/contracts/src/validate.js +305 -0
- package/node_modules/@forge/flow/index.js +114 -0
- package/node_modules/@forge/flow/package.json +34 -0
- package/node_modules/@forge/flow/src/bounded-loop.js +415 -0
- package/node_modules/@forge/flow/src/efficiency-supervisor.js +89 -0
- package/node_modules/@forge/flow/src/executor.js +279 -0
- package/node_modules/@forge/flow/src/monitor-durability.js +419 -0
- package/node_modules/@forge/flow/src/monitor-runtime.js +460 -0
- package/node_modules/@forge/flow/src/process-lifecycle.js +469 -0
- package/node_modules/@forge/flow/src/skill-runtime.js +343 -0
- package/node_modules/@forge/memory/index.js +331 -0
- package/node_modules/@forge/memory/package.json +34 -0
- package/node_modules/@forge/memory/src/authority-provider.js +67 -0
- package/node_modules/@forge/memory/src/backend-registry.js +166 -0
- package/node_modules/@forge/memory/src/feedback-intake.js +243 -0
- package/node_modules/@forge/memory/src/pr-lifecycle-authority.js +946 -0
- package/node_modules/@forge/memory/src/usage-evidence.js +205 -0
- package/package.json +16 -4
- package/packages/flow/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/index.js +32 -0
- package/packages/flow/node_modules/@forge/contracts/package.json +35 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/src/baseline.js +23 -0
- package/packages/flow/node_modules/@forge/contracts/src/canonical.js +151 -0
- package/packages/flow/node_modules/@forge/contracts/src/definitions.js +176 -0
- package/packages/flow/node_modules/@forge/contracts/src/identity.js +42 -0
- package/packages/flow/node_modules/@forge/contracts/src/schema.js +72 -0
- package/packages/flow/node_modules/@forge/contracts/src/validate.js +305 -0
- package/packages/memory/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/index.js +32 -0
- package/packages/memory/node_modules/@forge/contracts/package.json +35 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/src/baseline.js +23 -0
- package/packages/memory/node_modules/@forge/contracts/src/canonical.js +151 -0
- package/packages/memory/node_modules/@forge/contracts/src/definitions.js +176 -0
- package/packages/memory/node_modules/@forge/contracts/src/identity.js +42 -0
- package/packages/memory/node_modules/@forge/contracts/src/schema.js +72 -0
- package/packages/memory/node_modules/@forge/contracts/src/validate.js +305 -0
- package/scripts/commitlint.js +13 -15
- package/scripts/generate-risk-manifest.js +91 -0
- package/scripts/github-context-bridge.sh +10 -0
- package/scripts/legacy-claim-repair.js +145 -0
- package/scripts/lib/behavioral-eval-runtime.js +3 -2
- package/scripts/process-tree.js +14 -2
- package/scripts/protected-state-check.js +440 -17
- package/scripts/sync-agent-skills.js +333 -34
- package/scripts/test-full-suite.js +704 -18
- package/scripts/test-profile.js +13 -3
- package/scripts/test.js +96 -15
- package/skills/coverage.json +1 -0
- package/skills/review/SKILL.md +2 -0
- package/skills/review/evals/scorecard.json +2 -2
- package/skills/setup/SKILL.md +18 -0
- package/skills/setup/evals/scorecard.json +3 -3
- package/skills/shepherd/SKILL.md +19 -2
- package/skills/shepherd/evals/scorecard.json +3 -3
- package/skills/validate/SKILL.md +3 -0
- package/skills/validate/evals/scorecard.json +1 -1
package/lib/commands/serve.js
CHANGED
|
@@ -31,6 +31,7 @@ const fs = require('node:fs');
|
|
|
31
31
|
const path = require('node:path');
|
|
32
32
|
const crypto = require('node:crypto');
|
|
33
33
|
const { spawn } = require('node:child_process');
|
|
34
|
+
const { githubWorkerEnvironment } = require('../pr-monitor/watch-lifecycle');
|
|
34
35
|
|
|
35
36
|
// Shared-machine hardening (single-instance lock, owner-only perms + audit,
|
|
36
37
|
// hash-chained mutation journal). No dependency on serve.js, so a top-level
|
|
@@ -237,12 +238,21 @@ async function routeMutation(verb, args, projectRoot, deps = {}) {
|
|
|
237
238
|
// Snapshot (GET /data.json) — regenerate on demand, debounced.
|
|
238
239
|
// ---------------------------------------------------------------------------
|
|
239
240
|
|
|
240
|
-
function defaultGenerate(projectRoot, dashboardDir) {
|
|
241
|
+
function defaultGenerate(projectRoot, dashboardDir, deps = {}) {
|
|
241
242
|
return new Promise((resolve, reject) => {
|
|
242
243
|
const script = path.join(dashboardDir, 'generate-snapshot.mjs');
|
|
243
|
-
const
|
|
244
|
+
const env = githubWorkerEnvironment(projectRoot, deps);
|
|
245
|
+
let child;
|
|
246
|
+
try {
|
|
247
|
+
child = (deps.spawn || spawn)(process.execPath, [script], {
|
|
248
|
+
cwd: projectRoot, stdio: 'ignore', windowsHide: true, ...(env ? { env } : {}),
|
|
249
|
+
});
|
|
250
|
+
} catch {
|
|
251
|
+
reject(new Error('snapshot generation failed'));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
244
254
|
const timer = setTimeout(() => { child.kill(); reject(new Error('snapshot generation timed out')); }, GEN_TIMEOUT_MS);
|
|
245
|
-
child.on('error', (
|
|
255
|
+
child.on('error', () => { clearTimeout(timer); reject(new Error('snapshot generation failed')); });
|
|
246
256
|
child.on('exit', (code) => {
|
|
247
257
|
clearTimeout(timer);
|
|
248
258
|
if (code === 0) resolve();
|
|
@@ -409,7 +419,7 @@ function buildContext(projectRoot, dashboardDir, token, deps = {}) {
|
|
|
409
419
|
buffer: null,
|
|
410
420
|
lastGen: 0,
|
|
411
421
|
inFlight: null,
|
|
412
|
-
generate: deps.generate || defaultGenerate,
|
|
422
|
+
generate: deps.generate || ((root, dir) => defaultGenerate(root, dir, deps)),
|
|
413
423
|
},
|
|
414
424
|
};
|
|
415
425
|
}
|
|
@@ -438,13 +448,16 @@ function browserOpener() {
|
|
|
438
448
|
return { file: '/usr/bin/xdg-open', args: [] };
|
|
439
449
|
}
|
|
440
450
|
|
|
441
|
-
function openBrowser(url) {
|
|
451
|
+
function openBrowser(url, projectRoot = process.cwd(), deps = {}) {
|
|
442
452
|
try {
|
|
443
453
|
const { file, args } = browserOpener();
|
|
454
|
+
const env = githubWorkerEnvironment(projectRoot, deps);
|
|
444
455
|
// windowsHide keeps this detached opener from flashing a console window on
|
|
445
456
|
// Windows (Node defaults windowsHide to false); background/detached spawns
|
|
446
457
|
// must stay silent (issue 931e7924).
|
|
447
|
-
const child = spawn(file, [...args, url], {
|
|
458
|
+
const child = (deps.spawn || spawn)(file, [...args, url], {
|
|
459
|
+
detached: true, stdio: 'ignore', windowsHide: true, ...(env ? { env } : {}),
|
|
460
|
+
});
|
|
448
461
|
// spawn() failures (e.g. the opener binary is missing) surface ASYNChronously
|
|
449
462
|
// as an 'error' event, NOT via the try/catch — an unhandled one would crash
|
|
450
463
|
// `forge serve`. Opening a browser is best-effort; swallow it (URL is printed).
|
|
@@ -480,7 +493,7 @@ function announceServe(server, token, options, resolve) {
|
|
|
480
493
|
`\nforge serve — interactive dashboard (loopback only)\n ${url}\n`
|
|
481
494
|
+ ' Token dies with this process. Press Ctrl-C to stop.\n\n',
|
|
482
495
|
);
|
|
483
|
-
if (options.open) openBrowser(url);
|
|
496
|
+
if (options.open) openBrowser(url, options.projectRoot, options.deps);
|
|
484
497
|
installServeShutdown(server, resolve, options.onClose);
|
|
485
498
|
}
|
|
486
499
|
|
|
@@ -535,7 +548,7 @@ function verifyJournalAtStartup(projectRoot, warn = (m) => process.stderr.write(
|
|
|
535
548
|
return result;
|
|
536
549
|
}
|
|
537
550
|
|
|
538
|
-
async function handler(args, flags = {}, projectRoot = process.cwd(),
|
|
551
|
+
async function handler(args, flags = {}, projectRoot = process.cwd(), opts = {}) {
|
|
539
552
|
const { port, open } = parseServeArgs(args, flags);
|
|
540
553
|
const dashboardDir = path.join(projectRoot, 'web', 'dashboard');
|
|
541
554
|
if (!fs.existsSync(path.join(dashboardDir, 'index.html'))) {
|
|
@@ -558,10 +571,12 @@ async function handler(args, flags = {}, projectRoot = process.cwd(), _opts = {}
|
|
|
558
571
|
verifyJournalAtStartup(projectRoot);
|
|
559
572
|
|
|
560
573
|
const token = mintToken();
|
|
561
|
-
const ctx = buildContext(projectRoot, dashboardDir, token);
|
|
574
|
+
const ctx = buildContext(projectRoot, dashboardDir, token, opts);
|
|
562
575
|
const server = createServeServer(ctx);
|
|
563
576
|
return startListening(server, port, token, {
|
|
564
577
|
open,
|
|
578
|
+
projectRoot,
|
|
579
|
+
deps: opts,
|
|
565
580
|
onClose: () => security.releaseLock(projectRoot),
|
|
566
581
|
});
|
|
567
582
|
}
|
|
@@ -575,6 +590,8 @@ module.exports = {
|
|
|
575
590
|
routeMutation,
|
|
576
591
|
parseServeArgs,
|
|
577
592
|
buildContext,
|
|
593
|
+
defaultGenerate,
|
|
594
|
+
openBrowser,
|
|
578
595
|
createServeServer,
|
|
579
596
|
verifyToken,
|
|
580
597
|
isLoopbackRequest,
|
package/lib/commands/setup.js
CHANGED
|
@@ -13,7 +13,7 @@ const fs = require('node:fs');
|
|
|
13
13
|
const os = require('node:os');
|
|
14
14
|
const path = require('node:path');
|
|
15
15
|
const readline = require('node:readline');
|
|
16
|
-
const { execSync } = require('node:child_process');
|
|
16
|
+
const { execFileSync, execSync } = require('node:child_process');
|
|
17
17
|
|
|
18
18
|
// Compute packageDir relative to this file (lib/commands/setup.js -> project root).
|
|
19
19
|
// packageDir stays a runtime value for asset copying; requires use static
|
|
@@ -91,6 +91,10 @@ const initCommand = require('./init');
|
|
|
91
91
|
const fileUtils = require('../file-utils');
|
|
92
92
|
const detectionUtils = require('../detection-utils');
|
|
93
93
|
const { detectHusky, migrateHusky } = require('../husky-migration');
|
|
94
|
+
const {
|
|
95
|
+
issueGeneratedHarnessClaudeAuthorization,
|
|
96
|
+
completeGeneratedHarnessClaudeAuthorization,
|
|
97
|
+
} = require('../protected-state-authority');
|
|
94
98
|
|
|
95
99
|
// --- Module-level state (deferred from ForgeContext migration) ---
|
|
96
100
|
// Follow-up tracked in forge-vi7v: migrate setup state to a ForgeContext instance passed via handler args.
|
|
@@ -163,6 +167,92 @@ function safeExec(cmd, opts = {}) {
|
|
|
163
167
|
}
|
|
164
168
|
}
|
|
165
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Resolve the current source revision without passing Git arguments through a shell.
|
|
172
|
+
* @param {string} cwd - Repository working directory
|
|
173
|
+
* @param {Function} commandRunner - execFileSync-compatible runner for tests
|
|
174
|
+
* @returns {string} Full source HEAD, or empty when Git cannot resolve it
|
|
175
|
+
*/
|
|
176
|
+
function resolveCurrentSourceHead(cwd = projectRoot, commandRunner = execFileSync) {
|
|
177
|
+
try {
|
|
178
|
+
return commandRunner('git', ['rev-parse', '--verify', 'HEAD^{commit}'], {
|
|
179
|
+
cwd,
|
|
180
|
+
stdio: 'pipe',
|
|
181
|
+
}).toString().trim();
|
|
182
|
+
} catch (_e) { // NOSONAR — fail closed when the source revision is unavailable
|
|
183
|
+
return '';
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Normalize Git's Windows checkout line endings before authorizing the exact
|
|
189
|
+
* root CLAUDE.md pointer bytes.
|
|
190
|
+
* @param {Buffer|string} content - Existing CLAUDE.md bytes
|
|
191
|
+
* @returns {Buffer} LF-normalized content
|
|
192
|
+
*/
|
|
193
|
+
function normalizeClaudePointerContent(content) {
|
|
194
|
+
return Buffer.from(String(content || '').replace(/\r\n/g, '\n'));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function readCleanClaudePointerWorktreeContent(cwd, commandRunner) {
|
|
198
|
+
const tempIndexDir = fs.mkdtempSync(path.join(os.tmpdir(), 'forge-claude-index-'));
|
|
199
|
+
const tempIndex = path.join(tempIndexDir, 'index');
|
|
200
|
+
const env = { ...process.env, GIT_INDEX_FILE: tempIndex };
|
|
201
|
+
try {
|
|
202
|
+
commandRunner('git', ['read-tree', 'HEAD'], {
|
|
203
|
+
cwd,
|
|
204
|
+
env,
|
|
205
|
+
stdio: 'pipe',
|
|
206
|
+
});
|
|
207
|
+
commandRunner('git', ['add', '--', 'CLAUDE.md'], {
|
|
208
|
+
cwd,
|
|
209
|
+
env,
|
|
210
|
+
stdio: 'pipe',
|
|
211
|
+
});
|
|
212
|
+
return commandRunner('git', ['show', ':CLAUDE.md'], {
|
|
213
|
+
cwd,
|
|
214
|
+
env,
|
|
215
|
+
encoding: null,
|
|
216
|
+
stdio: 'pipe',
|
|
217
|
+
});
|
|
218
|
+
} finally {
|
|
219
|
+
fs.rmSync(tempIndexDir, { recursive: true, force: true });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Read the exact staged CLAUDE.md bytes that the protected-state hook will hash.
|
|
225
|
+
* @param {string} cwd - Repository working directory
|
|
226
|
+
* @param {Function} commandRunner - execFileSync-compatible runner for tests
|
|
227
|
+
* @returns {Buffer} Staged bytes, or the worktree bytes when the file is untracked
|
|
228
|
+
*/
|
|
229
|
+
function readStagedClaudePointerContent(cwd = projectRoot, commandRunner = execFileSync) {
|
|
230
|
+
try {
|
|
231
|
+
const stagedContent = commandRunner('git', ['show', ':CLAUDE.md'], {
|
|
232
|
+
cwd,
|
|
233
|
+
encoding: null,
|
|
234
|
+
stdio: 'pipe',
|
|
235
|
+
});
|
|
236
|
+
try {
|
|
237
|
+
return readCleanClaudePointerWorktreeContent(cwd, commandRunner);
|
|
238
|
+
} catch (_worktreeError) {
|
|
239
|
+
return stagedContent;
|
|
240
|
+
}
|
|
241
|
+
} catch (showError) {
|
|
242
|
+
try {
|
|
243
|
+
commandRunner('git', ['ls-files', '--error-unmatch', '--', 'CLAUDE.md'], {
|
|
244
|
+
cwd,
|
|
245
|
+
encoding: 'utf8',
|
|
246
|
+
stdio: 'pipe',
|
|
247
|
+
});
|
|
248
|
+
throw showError;
|
|
249
|
+
} catch (trackedError) {
|
|
250
|
+
if (trackedError?.status !== 1) throw showError;
|
|
251
|
+
}
|
|
252
|
+
return readCleanClaudePointerWorktreeContent(cwd, commandRunner);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
166
256
|
/**
|
|
167
257
|
* Detect package manager
|
|
168
258
|
*/
|
|
@@ -1649,6 +1739,13 @@ function ensureDirWithNote(dir, purpose) { // eslint-disable-line no-unused-vars
|
|
|
1649
1739
|
|
|
1650
1740
|
// Setup core documentation and directories
|
|
1651
1741
|
function setupCoreDocs() {
|
|
1742
|
+
// Review skills reference this root contract in every installed repository.
|
|
1743
|
+
// It is a consumer-owned extension point after creation, so setup never overwrites it.
|
|
1744
|
+
const codingStandardsDest = path.join(projectRoot, 'CODING_STANDARDS.md');
|
|
1745
|
+
if (!fs.existsSync(codingStandardsDest)) {
|
|
1746
|
+
copyFile(path.join(getPackageRoot(packageDir), 'CODING_STANDARDS.md'), 'CODING_STANDARDS.md');
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1652
1749
|
// docs/planning/ and docs/research/ are created lazily on first use
|
|
1653
1750
|
// by /plan Phase 1 and Phase 2 respectively, via ensureDirWithNote().
|
|
1654
1751
|
// TEMPLATE.md and PROGRESS.md are also deferred to first use.
|
|
@@ -2053,7 +2150,7 @@ function setupCursorHooksConfig() {
|
|
|
2053
2150
|
|
|
2054
2151
|
// Helper: Create agent link file
|
|
2055
2152
|
// When symlinkOnly is true (--symlink flag), skip copy fallback
|
|
2056
|
-
function createAgentLinkFile(agent, symlinkOnly = false) {
|
|
2153
|
+
async function createAgentLinkFile(agent, symlinkOnly = false) {
|
|
2057
2154
|
if (!shouldLinkAgentsMd(agent)) return;
|
|
2058
2155
|
|
|
2059
2156
|
const result = createSymlinkOrCopy('AGENTS.md', agent.linkFile, { symlinkOnly });
|
|
@@ -2061,6 +2158,33 @@ function createAgentLinkFile(agent, symlinkOnly = false) {
|
|
|
2061
2158
|
const action = result === 'linked' ? 'Linked' : result === 'copied' ? 'Copied' : 'Preserved import';
|
|
2062
2159
|
console.log(` ${action}: ${agent.linkFile}`);
|
|
2063
2160
|
}
|
|
2161
|
+
if (agent.linkFile !== 'CLAUDE.md' || result !== 'existing-import') return;
|
|
2162
|
+
|
|
2163
|
+
try {
|
|
2164
|
+
const sourceHead = resolveCurrentSourceHead();
|
|
2165
|
+
const content = readStagedClaudePointerContent();
|
|
2166
|
+
const actor = process.env.FORGE_PROTECTED_STATE_ACTOR || process.env.FORGE_ACTOR || process.env.USER || process.env.USERNAME || 'unknown';
|
|
2167
|
+
const authorization = await issueGeneratedHarnessClaudeAuthorization(projectRoot, {
|
|
2168
|
+
actor,
|
|
2169
|
+
content,
|
|
2170
|
+
sourceHead,
|
|
2171
|
+
});
|
|
2172
|
+
if (!authorization.success) {
|
|
2173
|
+
console.warn(` Warning: Could not authorize existing CLAUDE.md import: ${authorization.error}`);
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
2176
|
+
const completion = await completeGeneratedHarnessClaudeAuthorization(projectRoot, {
|
|
2177
|
+
actor,
|
|
2178
|
+
capabilityId: authorization.capabilityId,
|
|
2179
|
+
content,
|
|
2180
|
+
sourceHead,
|
|
2181
|
+
});
|
|
2182
|
+
if (!completion.success) {
|
|
2183
|
+
console.warn(` Warning: Could not complete CLAUDE.md import authorization: ${completion.error}`);
|
|
2184
|
+
}
|
|
2185
|
+
} catch (error) {
|
|
2186
|
+
console.warn(` Warning: Could not record CLAUDE.md import authorization: ${error.message}`);
|
|
2187
|
+
}
|
|
2064
2188
|
}
|
|
2065
2189
|
|
|
2066
2190
|
// Setup specific agent
|
|
@@ -2117,7 +2241,7 @@ async function setupAgent(agentKey, skipFiles = {}, options = {}) {
|
|
|
2117
2241
|
}
|
|
2118
2242
|
|
|
2119
2243
|
// Create link file (SYMLINK_ONLY = --symlink flag disables copy fallback)
|
|
2120
|
-
createAgentLinkFile(agent, SYMLINK_ONLY);
|
|
2244
|
+
await createAgentLinkFile(agent, SYMLINK_ONLY);
|
|
2121
2245
|
}
|
|
2122
2246
|
|
|
2123
2247
|
|
|
@@ -3927,8 +4051,9 @@ function dryRunSetup(agents, options = {}) { // NOSONAR — Extracted as-is from
|
|
|
3927
4051
|
}
|
|
3928
4052
|
}
|
|
3929
4053
|
|
|
3930
|
-
//
|
|
4054
|
+
// Root policy files
|
|
3931
4055
|
addFileAction('AGENTS.md', 'Copy workflow documentation');
|
|
4056
|
+
addFileAction('CODING_STANDARDS.md', 'Install Forge coding standards');
|
|
3932
4057
|
|
|
3933
4058
|
// Per-agent planned actions
|
|
3934
4059
|
for (const agentKey of agents) {
|
|
@@ -4526,6 +4651,9 @@ module.exports = {
|
|
|
4526
4651
|
repairRuntimeReadiness,
|
|
4527
4652
|
_showBanner: showBanner,
|
|
4528
4653
|
backupAndRemoveLegacyCursorRules,
|
|
4654
|
+
resolveCurrentSourceHead,
|
|
4655
|
+
normalizeClaudePointerContent,
|
|
4656
|
+
readStagedClaudePointerContent,
|
|
4529
4657
|
|
|
4530
4658
|
// State accessors for testing
|
|
4531
4659
|
_getState: () => ({ projectRoot, FORCE_MODE, VERBOSE_MODE, NON_INTERACTIVE, SYMLINK_ONLY, PKG_MANAGER }),
|