yadflow 4.0.0-next.3 → 4.0.0-next.4
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/CHANGELOG.md +169 -0
- package/README.md +85 -22
- package/bin/commands.mjs +3 -1
- package/bin/yad.mjs +183 -29
- package/cli/capture.mjs +4 -2
- package/cli/checkpoint.mjs +10 -10
- package/cli/claims.mjs +4 -4
- package/cli/commit.mjs +48 -12
- package/cli/docs.mjs +15 -13
- package/cli/doctor.mjs +557 -141
- package/cli/epic-state.mjs +41 -18
- package/cli/errors.mjs +3 -2
- package/cli/find-product.mjs +197 -0
- package/cli/fold.mjs +4 -4
- package/cli/gate-local.mjs +13 -13
- package/cli/gate.mjs +111 -103
- package/cli/history.mjs +13 -13
- package/cli/hook.mjs +201 -30
- package/cli/index-command.mjs +6 -6
- package/cli/lib.mjs +91 -29
- package/cli/manifest.mjs +171 -104
- package/cli/migrate.mjs +208 -17
- package/cli/mode.mjs +22 -22
- package/cli/next.mjs +6 -6
- package/cli/openpr.mjs +32 -24
- package/cli/people.mjs +22 -10
- package/cli/plan.mjs +718 -45
- package/cli/platform.mjs +13 -7
- package/cli/product-index.mjs +4 -4
- package/cli/{hubcommit.mjs → productcommit.mjs} +11 -7
- package/cli/protection.mjs +19 -9
- package/cli/reconcile.mjs +98 -23
- package/cli/repo-publish.mjs +22 -16
- package/cli/repo.mjs +128 -33
- package/cli/report.mjs +4 -2
- package/cli/review.mjs +26 -19
- package/cli/setup.mjs +105 -36
- package/cli/ship.mjs +1 -1
- package/cli/skip.mjs +4 -4
- package/cli/tidy.mjs +7 -7
- package/cli/update-commit.mjs +22 -19
- package/cli/workspace.mjs +495 -0
- package/package.json +7 -4
- package/skills/sdlc/config.yaml +14 -13
- package/skills/sdlc/module-help.csv +8 -8
- package/skills/yad-analysis/SKILL.md +6 -4
- package/skills/yad-architecture/SKILL.md +4 -3
- package/skills/yad-backfill/SKILL.md +11 -5
- package/skills/yad-backfill/references/backfill.md +33 -3
- package/skills/yad-backfill/templates/checks/backfill-check.sh +200 -17
- package/skills/yad-change/SKILL.md +1 -1
- package/skills/yad-checks/SKILL.md +48 -27
- package/skills/yad-checks/references/check-gates.md +213 -53
- package/skills/yad-checks/templates/checks/commit-message.sh +39 -13
- package/skills/yad-checks/templates/checks/contract-check.sh +472 -23
- package/skills/yad-checks/templates/checks/epic-open.sh +398 -8
- package/skills/yad-checks/templates/checks/ledger-guard.sh +75 -25
- package/skills/yad-checks/templates/checks/lineage-check.sh +391 -7
- package/skills/yad-checks/templates/checks/product-checkout.sh +141 -0
- package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +399 -8
- package/skills/yad-checks/templates/checks/risk-map-check.sh +35 -3
- package/skills/yad-checks/templates/checks/spec-link.sh +36 -3
- package/skills/yad-checks/templates/checks/verified-commits.sh +26 -2
- package/skills/yad-checks/templates/github/yad-checks.yml +33 -13
- package/skills/yad-checks/templates/github/{yad-hub-checks.yml → yad-product-checks.yml} +14 -10
- package/skills/yad-checks/templates/github/yad-update-guard.yml +1 -1
- package/skills/yad-checks/templates/github/yad-verified-commits.yml +1 -1
- package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +12 -0
- package/skills/yad-checks/templates/gitlab/{yad-hub-checks.gitlab-ci.yml → yad-product-checks.gitlab-ci.yml} +16 -16
- package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +2 -2
- package/skills/yad-checks/templates/hooks/ledger-guard-cursor.mjs +130 -0
- package/skills/yad-checks/templates/hooks/ledger-guard.mjs +117 -0
- package/skills/yad-checks/templates/hooks/yad-capture.mjs +117 -0
- package/skills/yad-commit/SKILL.md +18 -7
- package/skills/yad-connect-design/SKILL.md +1 -1
- package/skills/yad-connect-design/references/design-registry.md +1 -1
- package/skills/yad-connect-docs/SKILL.md +16 -11
- package/skills/yad-connect-docs/references/docs-registry.md +8 -8
- package/skills/yad-connect-learning/SKILL.md +1 -1
- package/skills/yad-connect-learning/references/learning-registry.md +1 -1
- package/skills/yad-connect-repos/SKILL.md +31 -8
- package/skills/yad-connect-repos/references/code-context.md +1 -1
- package/skills/yad-connect-repos/references/{hub-config.md → product-config.md} +19 -11
- package/skills/yad-connect-repos/references/repos-registry.md +1 -1
- package/skills/yad-connect-testing/SKILL.md +1 -1
- package/skills/yad-connect-testing/references/testing-registry.md +1 -1
- package/skills/yad-discovery/SKILL.md +2 -2
- package/skills/yad-discovery/references/discovery-schema.md +1 -1
- package/skills/yad-docs/SKILL.md +1 -1
- package/skills/yad-docs/references/data-mapping.md +1 -1
- package/skills/yad-docs/templates/app/package-lock.json +8 -8
- package/skills/yad-docs/templates/app/package.json +1 -1
- package/skills/yad-docs/templates/app/src/components/Canvas/FlowCanvas.tsx +2 -2
- package/skills/yad-docs-overview/references/pipeline-model.md +3 -3
- package/skills/yad-engineer-review/SKILL.md +2 -2
- package/skills/yad-engineer-review/references/ship-and-record.md +3 -3
- package/skills/yad-epic/SKILL.md +6 -4
- package/skills/yad-epic/references/state-schema.md +13 -12
- package/skills/yad-open-pr/SKILL.md +1 -1
- package/skills/yad-pair-review/SKILL.md +5 -5
- package/skills/yad-pair-review/references/session-state.md +2 -2
- package/skills/yad-pr-template/SKILL.md +14 -12
- package/skills/yad-pr-template/templates/checks/pr-template.sh +18 -16
- package/skills/yad-pr-template/templates/checks/pr-title.sh +15 -13
- package/skills/yad-pr-template/templates/{hub → product}/github/pull_request_template.md +2 -2
- package/skills/yad-pr-template/templates/{hub → product}/gitlab/merge_request_templates/Default.md +2 -2
- package/skills/{yad-hub-bridge → yad-product-bridge}/SKILL.md +15 -15
- package/skills/{yad-hub-bridge → yad-product-bridge}/references/bridge.md +15 -10
- package/skills/{yad-hub-bridge → yad-product-bridge}/references/login-roster.md +2 -2
- package/skills/{yad-hub-bridge/templates/checks/hub-route.sh → yad-product-bridge/templates/checks/product-route.sh} +2 -2
- package/skills/{yad-hub-bridge → yad-product-bridge}/templates/github/yad-gate-sync.yml +29 -16
- package/skills/{yad-hub-bridge → yad-product-bridge}/templates/gitlab/gitlab-ci.include-root.yml +1 -1
- package/skills/{yad-hub-bridge → yad-product-bridge}/templates/gitlab/yad-gate-sync.gitlab-ci.yml +5 -3
- package/skills/yad-report/SKILL.md +1 -1
- package/skills/yad-review-companion/SKILL.md +3 -3
- package/skills/yad-review-gate/SKILL.md +22 -23
- package/skills/yad-review-gate/references/gating.md +13 -13
- package/skills/yad-run/SKILL.md +2 -2
- package/skills/yad-run/references/run-loop.md +2 -2
- package/skills/yad-spec/SKILL.md +2 -1
- package/skills/yad-spec/references/spec-handoff.md +19 -10
- package/skills/yad-stories/SKILL.md +2 -2
- package/skills/yad-sync-repos/SKILL.md +19 -3
- package/skills/yad-test-cases/SKILL.md +2 -2
- package/skills/yad-ui/SKILL.md +2 -2
- package/skills/yad-checks/templates/hooks/ledger-guard-cursor.sh +0 -91
- package/skills/yad-checks/templates/hooks/ledger-guard.sh +0 -100
- package/skills/yad-checks/templates/hooks/yad-capture.sh +0 -53
package/cli/commit.mjs
CHANGED
|
@@ -1,35 +1,48 @@
|
|
|
1
1
|
// `yad commit` — commit by the SDLC conventions (CONTRIBUTING.md / config.yaml build).
|
|
2
2
|
// Subject is Conventional Commits; trailers are emitted in the fixed order
|
|
3
|
-
// Task -> Contract-Change -> Co-Authored-By. The human git author OWNS the commit;
|
|
4
|
-
// co-author (flagged with --ai, or `none` for human-only). An atomic-commit guard keeps diffs small.
|
|
3
|
+
// Task -> Contract-Change -> Ledger-Override -> Co-Authored-By. The human git author OWNS the commit;
|
|
4
|
+
// the AI is only a co-author (flagged with --ai, or `none` for human-only). An atomic-commit guard keeps diffs small.
|
|
5
5
|
// An explicit --task id is validated against the spec-link gate contract (<story>-T<NN>) so a
|
|
6
6
|
// malformed trailer fails locally rather than after a push.
|
|
7
|
+
//
|
|
8
|
+
// `--manual --reason` (E49) is the door past the Product's local ledger hook (E48): the commit runs with
|
|
9
|
+
// the hook's skip switch, and the reason is recorded as a `Ledger-Override:` trailer so the reviewer —
|
|
10
|
+
// and the CI `ledger-guard` check, which quotes it — can see why. It opens this machine's hook and
|
|
11
|
+
// nothing more: CI still fails the commit, because anyone can type a trailer.
|
|
7
12
|
import path from 'node:path';
|
|
8
13
|
import fs from 'node:fs';
|
|
9
14
|
import { c, log, ok, info, warn, fail, run, exists } from './lib.mjs';
|
|
10
15
|
import {
|
|
11
16
|
COMMIT_TYPES, AI_COAUTHORS, ATOMIC_FILE_LIMIT,
|
|
12
|
-
TASK_TRAILER, CONTRACT_CHANGE_TRAILER, COAUTHOR_TRAILER, TASK_ID_RE,
|
|
17
|
+
TASK_TRAILER, CONTRACT_CHANGE_TRAILER, LEDGER_OVERRIDE_TRAILER, COAUTHOR_TRAILER, TASK_ID_RE,
|
|
13
18
|
productConfigPath,
|
|
14
19
|
} from './manifest.mjs';
|
|
20
|
+
import { OWNING_COMMIT_ENV, stagedLedgerHits } from './hook.mjs';
|
|
15
21
|
|
|
16
22
|
// PURE — unit tested directly. Build the full commit message text.
|
|
17
|
-
export function buildCommitMessage({ type, subject, task, contractChange = false, ai = 'none', body = '' }) {
|
|
23
|
+
export function buildCommitMessage({ type, subject, task, contractChange = false, ai = 'none', body = '', override = null }) {
|
|
18
24
|
if (!COMMIT_TYPES.includes(type)) throw new Error(`invalid commit type "${type}" (one of: ${COMMIT_TYPES.join(', ')})`);
|
|
19
25
|
if (!subject || !subject.trim()) throw new Error('commit subject is required');
|
|
20
26
|
if (!(ai in AI_COAUTHORS)) throw new Error(`unknown --ai "${ai}" (one of: ${Object.keys(AI_COAUTHORS).join(', ')})`);
|
|
21
27
|
if (/\.$/.test(subject.trim())) throw new Error('subject must not end with a period');
|
|
22
28
|
// A malformed task id (e.g. a bare story `EP-x-S01` with no -T<NN>) commits fine locally but
|
|
23
29
|
// then fails the spec-link CI gate — forcing a history rewrite + force-push. Reject it here so
|
|
24
|
-
// it never enters a trailer.
|
|
25
|
-
//
|
|
30
|
+
// it never enters a trailer. A branch-derived id (taskFromBranch, which matches without case) is
|
|
31
|
+
// validated the same way, so `feat/EP-Demo-S01-T01` is caught here too, as spec-link would.
|
|
26
32
|
if (task && !TASK_ID_RE.test(task)) {
|
|
27
|
-
throw new Error(`invalid --task "${task}" (expected <
|
|
33
|
+
throw new Error(`invalid --task "${task}" (expected EP-<slug>-S<n>-T<NN> with a lowercase slug, e.g. EP-x-S01-T02) — the spec-link CI gate would reject it`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A trailer is one line: a newline in the reason would end it early and start a line git reads as
|
|
37
|
+
// body text or as a trailer of its own.
|
|
38
|
+
if (override !== null && (typeof override !== 'string' || !override.trim() || /[\r\n]/.test(override))) {
|
|
39
|
+
throw new Error('--reason must be one non-empty line (it becomes the Ledger-Override trailer)');
|
|
28
40
|
}
|
|
29
41
|
|
|
30
42
|
const trailers = [];
|
|
31
43
|
if (task) trailers.push(`${TASK_TRAILER}: ${task}`);
|
|
32
44
|
if (contractChange) trailers.push(`${CONTRACT_CHANGE_TRAILER}: yes`);
|
|
45
|
+
if (override !== null) trailers.push(`${LEDGER_OVERRIDE_TRAILER}: ${override.trim()}`);
|
|
33
46
|
const co = AI_COAUTHORS[ai];
|
|
34
47
|
if (co) trailers.push(`${COAUTHOR_TRAILER}: ${co.name} <${co.email}>`);
|
|
35
48
|
|
|
@@ -47,11 +60,31 @@ export function taskFromBranch(branch = '') {
|
|
|
47
60
|
|
|
48
61
|
export async function runCommit(root, opts = {}) {
|
|
49
62
|
log(c.bold('\nyad commit'));
|
|
50
|
-
|
|
63
|
+
// The repo's top, like every other yad command that commits — except the ledger door: a Product can be a
|
|
64
|
+
// subfolder of its repo, and the hook's refusal sends the person to `--manual` from there. Only there,
|
|
65
|
+
// because `--manual` also needs a staged file that hook refuses, so it cannot commit into a parent repo
|
|
66
|
+
// by accident; and `yad ship` (whose open-pr step needs the top) refuses `--manual`.
|
|
67
|
+
const inRepo = exists(path.join(root, '.git')) || (opts.manual && run('git', ['rev-parse', '--show-toplevel'], { cwd: root }).ok);
|
|
68
|
+
if (!inRepo) { fail('not a git repo'); process.exitCode = 1; return; }
|
|
69
|
+
// --manual and --reason come as a pair: an override with no reason records nothing, and a reason with
|
|
70
|
+
// no --manual would be silently dropped.
|
|
71
|
+
if (opts.manual && opts.reason === undefined) { fail('--manual needs --reason "<why>" — the reason is recorded in the commit as a Ledger-Override trailer'); process.exitCode = 1; return; }
|
|
72
|
+
if (!opts.manual && opts.reason !== undefined) { fail('--reason is only for --manual (the ledger override)'); process.exitCode = 1; return; }
|
|
51
73
|
|
|
52
74
|
const staged = run('git', ['diff', '--cached', '--name-only'], { cwd: root }).stdout.split('\n').filter(Boolean);
|
|
53
75
|
if (!staged.length) { fail('nothing staged — `git add` your atomic change first'); process.exitCode = 1; return; }
|
|
54
76
|
|
|
77
|
+
// An override is recorded only when there is something to override: a staged file the Product's
|
|
78
|
+
// ledger hook refuses. In a code repo, on a local ledger, or for a new epic's seed, nothing is.
|
|
79
|
+
// Asked without the skip switch: a YAD_HOOK_DISABLE left set in the shell would hide every hit.
|
|
80
|
+
const hookEnv = { ...process.env };
|
|
81
|
+
delete hookEnv.YAD_HOOK_DISABLE;
|
|
82
|
+
if (opts.manual && !stagedLedgerHits({ cwd: root, env: hookEnv }).hits.length) {
|
|
83
|
+
fail('--manual: nothing staged here is a file the ledger hook refuses (it guards the CI-owned ledger on a verified Product) — commit without --manual and --reason');
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
55
88
|
if (staged.length > ATOMIC_FILE_LIMIT && !opts.force) {
|
|
56
89
|
fail(`${staged.length} files staged (atomic guard: ≤${ATOMIC_FILE_LIMIT}). Split the change, or pass --force.`);
|
|
57
90
|
for (const f of staged) info(f);
|
|
@@ -64,8 +97,8 @@ export async function runCommit(root, opts = {}) {
|
|
|
64
97
|
if (!task) {
|
|
65
98
|
// spec-link is a code-repo gate (REPO_WIRING.common), not a Product gate — so a missing Task trailer
|
|
66
99
|
// is expected on a Product PR (Shape artifact review or Product tooling) and only matters on a repo.
|
|
67
|
-
const
|
|
68
|
-
warn(
|
|
100
|
+
const onProduct = exists(productConfigPath(root));
|
|
101
|
+
warn(onProduct
|
|
69
102
|
? 'no Task trailer (none given and branch has no -S0N-T0N) — fine for a Product PR; required on code-repo tasks (spec-link gate)'
|
|
70
103
|
: 'no Task trailer (none given and branch has no -S0N-T0N) — spec-link gate will fail on a code repo');
|
|
71
104
|
}
|
|
@@ -75,17 +108,20 @@ export async function runCommit(root, opts = {}) {
|
|
|
75
108
|
message = buildCommitMessage({
|
|
76
109
|
type: opts.type, subject: opts.message, task,
|
|
77
110
|
contractChange: !!opts.contractChange, ai: opts.ai || 'none',
|
|
111
|
+
override: opts.manual ? String(opts.reason) : null,
|
|
78
112
|
});
|
|
79
113
|
} catch (e) { fail(e.message); process.exitCode = 1; return; }
|
|
80
114
|
|
|
81
115
|
// The --json answer (E1): what was (or would be) committed.
|
|
82
|
-
const answer = { message, task: task || null, files: staged, contractChange: !!opts.contractChange };
|
|
116
|
+
const answer = { message, task: task || null, files: staged, contractChange: !!opts.contractChange, manual: !!opts.manual, reason: opts.manual ? String(opts.reason).trim() : null };
|
|
83
117
|
if (opts.dryRun) { log('\n' + c.dim(message) + '\n'); info('dry run — not committed'); return { ...answer, committed: false, dryRun: true }; }
|
|
84
118
|
|
|
85
|
-
|
|
119
|
+
// Only yad's own hook is skipped — any other pre-commit hook (husky, lint-staged) still runs.
|
|
120
|
+
const r = run('git', ['commit', '-m', message], { cwd: root, ...(opts.manual ? { env: OWNING_COMMIT_ENV() } : {}) });
|
|
86
121
|
if (!r.ok) { fail(`git commit failed — ${r.stderr.split('\n')[0] || r.code}`); process.exitCode = 1; return { ...answer, committed: false, dryRun: false }; }
|
|
87
122
|
ok(`committed ${staged.length} file(s)${task ? ` for ${task}` : ''}`);
|
|
88
123
|
if (opts.contractChange) warn('Contract-Change: yes — this routes back to the architecture gate');
|
|
124
|
+
if (opts.manual) warn('Ledger-Override recorded — the ledger-guard check on the pull request still fails this commit; the reason is there for the reviewer');
|
|
89
125
|
const sha = run('git', ['rev-parse', 'HEAD'], { cwd: root });
|
|
90
126
|
return { ...answer, committed: true, dryRun: false, commit: sha.ok ? sha.stdout : null };
|
|
91
127
|
}
|
package/cli/docs.mjs
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
// and the manifest-hash staleness check (reusing the head-sha idea from repo.mjs). It NEVER touches
|
|
7
7
|
// epic state, approvals, or the contract lock — docs are an output enrichment, not a gate.
|
|
8
8
|
//
|
|
9
|
-
// Pure mapping fns (
|
|
9
|
+
// Pure mapping fns (deployTargetFromProduct / siteBasePath / docsArtifactHash / docsStale / pagesWorkflow)
|
|
10
10
|
// are exported for unit tests; the side-effecting runDocs orchestrates them.
|
|
11
11
|
import path from 'node:path';
|
|
12
12
|
import fs from 'node:fs';
|
|
13
13
|
import { createHash } from 'node:crypto';
|
|
14
|
-
import { c, log, ok, info, warn, hand, fail, readJSON,
|
|
14
|
+
import { c, log, ok, info, warn, hand, fail, readJSON, runLauncher, has, exists } from './lib.mjs';
|
|
15
15
|
import { PROJECT_FILES } from './manifest.mjs';
|
|
16
16
|
import { detectPlatform, platformReady } from './platform.mjs';
|
|
17
17
|
import { gitHead } from './setup.mjs';
|
|
@@ -35,8 +35,8 @@ export function manifestPath(root, { epic, overview } = {}) {
|
|
|
35
35
|
|
|
36
36
|
// ---- pure: platform/target + base path ----------------------------------------------------------
|
|
37
37
|
// hub.json platform -> the default Pages target (github-pages | gitlab-pages | none/build-only).
|
|
38
|
-
export function
|
|
39
|
-
const platform =
|
|
38
|
+
export function deployTargetFromProduct(productConfig = {}) {
|
|
39
|
+
const platform = productConfig?.platform || detectPlatform(productConfig?.git_url || '');
|
|
40
40
|
if (platform === 'github') return 'github-pages';
|
|
41
41
|
if (platform === 'gitlab') return 'gitlab-pages';
|
|
42
42
|
return 'none';
|
|
@@ -175,31 +175,33 @@ on:
|
|
|
175
175
|
workflow_dispatch:
|
|
176
176
|
permissions:
|
|
177
177
|
contents: read
|
|
178
|
-
pages: write
|
|
179
|
-
id-token: write
|
|
180
178
|
concurrency:
|
|
181
179
|
group: yad-docs-pages
|
|
182
180
|
cancel-in-progress: true
|
|
183
181
|
jobs:
|
|
184
182
|
build-deploy:
|
|
185
183
|
runs-on: ubuntu-latest
|
|
184
|
+
permissions:
|
|
185
|
+
contents: read
|
|
186
|
+
pages: write # publish the site
|
|
187
|
+
id-token: write # prove to Pages that this run is the deploy
|
|
186
188
|
environment:
|
|
187
189
|
name: github-pages
|
|
188
190
|
url: \${{ steps.deployment.outputs.page_url }}
|
|
189
191
|
steps:
|
|
190
|
-
- uses: actions/checkout@v7
|
|
191
|
-
- uses: actions/setup-node@
|
|
192
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
193
|
+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
192
194
|
with:
|
|
193
195
|
node-version: 20
|
|
194
196
|
- name: Build the overview + per-epic sites into ./public
|
|
195
197
|
run: |
|
|
196
198
|
${BUILD_PUBLIC.map((l) => ` ${l}`).join('\n')}
|
|
197
|
-
- uses: actions/configure-pages@v6
|
|
198
|
-
- uses: actions/upload-pages-artifact@v5
|
|
199
|
+
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
200
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
199
201
|
with:
|
|
200
202
|
path: public
|
|
201
203
|
- id: deployment
|
|
202
|
-
uses: actions/deploy-pages@v5
|
|
204
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
203
205
|
`;
|
|
204
206
|
}
|
|
205
207
|
export function pagesWorkflowPath(platform) {
|
|
@@ -233,8 +235,8 @@ function buildSite(root, t, { npmOptional = false } = {}) {
|
|
|
233
235
|
const install = exists(path.join(dir, 'package-lock.json')) ? ['ci'] : ['install'];
|
|
234
236
|
const again = 'fix the error npm printed above, then run the command again';
|
|
235
237
|
log(` ${c.dim('$')} npm ${install[0]} ${c.dim(`(${rel})`)}`);
|
|
236
|
-
if (!
|
|
237
|
-
if (!
|
|
238
|
+
if (!runLauncher('npm', install, { cwd: dir, stdio: 'inherit' }).ok) return failed(`${site}: npm ${install[0]} failed`, again);
|
|
239
|
+
if (!runLauncher('npm', ['run', 'build'], { cwd: dir, stdio: 'inherit' }).ok) return failed(`${site}: npm run build failed`, again);
|
|
238
240
|
ok(`built ${site} ${c.dim('→ ' + path.relative(root, path.join(dir, 'dist')))}`);
|
|
239
241
|
return { site, built: true, error: null };
|
|
240
242
|
}
|