@codyswann/lisa 4.42.6 → 4.43.0
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 +4 -0
- package/all/copy-overwrite/scripts/check-orphaned-branches.mjs +7 -0
- package/all/copy-overwrite/scripts/lib/process-tree-runner.mjs +12 -2
- package/all/copy-overwrite/scripts/lisa-cross-worktree-guard.mjs +4 -0
- package/all/copy-overwrite/scripts/lisa-environment-prepare.mjs +2 -0
- package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.mjs +31 -3
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +4 -0
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +13 -0
- package/dist/cli/doctor-readiness-delivery.d.ts.map +1 -1
- package/dist/cli/doctor-readiness-delivery.js +13 -6
- package/dist/cli/doctor-readiness-delivery.js.map +1 -1
- package/dist/cli/doctor-readiness-deploy-outcome.d.ts +9 -0
- package/dist/cli/doctor-readiness-deploy-outcome.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-deploy-outcome.js +87 -0
- package/dist/cli/doctor-readiness-deploy-outcome.js.map +1 -0
- package/dist/cli/doctor-readiness-workflows.d.ts +8 -0
- package/dist/cli/doctor-readiness-workflows.d.ts.map +1 -1
- package/dist/cli/doctor-readiness-workflows.js +1 -0
- package/dist/cli/doctor-readiness-workflows.js.map +1 -1
- package/dist/configs/vitest/base.d.ts +1 -1
- package/dist/configs/vitest/base.d.ts.map +1 -1
- package/dist/configs/vitest/base.js +1 -0
- package/dist/configs/vitest/base.js.map +1 -1
- package/dist/configs/vitest/cdk.d.ts +2 -2
- package/dist/configs/vitest/cdk.d.ts.map +1 -1
- package/dist/configs/vitest/cdk.js +5 -2
- package/dist/configs/vitest/cdk.js.map +1 -1
- package/dist/configs/vitest/coverage-reports-directory.d.ts +47 -0
- package/dist/configs/vitest/coverage-reports-directory.d.ts.map +1 -0
- package/dist/configs/vitest/coverage-reports-directory.js +131 -0
- package/dist/configs/vitest/coverage-reports-directory.js.map +1 -0
- package/dist/configs/vitest/harper-fabric.d.ts +2 -2
- package/dist/configs/vitest/harper-fabric.d.ts.map +1 -1
- package/dist/configs/vitest/harper-fabric.js +5 -2
- package/dist/configs/vitest/harper-fabric.js.map +1 -1
- package/dist/configs/vitest/nestjs.d.ts +2 -2
- package/dist/configs/vitest/nestjs.d.ts.map +1 -1
- package/dist/configs/vitest/nestjs.js +5 -2
- package/dist/configs/vitest/nestjs.js.map +1 -1
- package/dist/configs/vitest/phaser.d.ts +2 -2
- package/dist/configs/vitest/phaser.d.ts.map +1 -1
- package/dist/configs/vitest/phaser.js +5 -2
- package/dist/configs/vitest/phaser.js.map +1 -1
- package/dist/configs/vitest/typescript.d.ts +2 -2
- package/dist/configs/vitest/typescript.d.ts.map +1 -1
- package/dist/configs/vitest/typescript.js +5 -2
- package/dist/configs/vitest/typescript.js.map +1 -1
- package/dist/core/deploy-release-dependence.d.ts +72 -0
- package/dist/core/deploy-release-dependence.d.ts.map +1 -0
- package/dist/core/deploy-release-dependence.js +236 -0
- package/dist/core/deploy-release-dependence.js.map +1 -0
- package/dist/core/github-actions-condition.d.ts +78 -0
- package/dist/core/github-actions-condition.d.ts.map +1 -0
- package/dist/core/github-actions-condition.js +307 -0
- package/dist/core/github-actions-condition.js.map +1 -0
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +24 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +45 -24
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/migrations/deploy-outcome-guard-edit.d.ts +11 -0
- package/dist/migrations/deploy-outcome-guard-edit.d.ts.map +1 -0
- package/dist/migrations/deploy-outcome-guard-edit.js +184 -0
- package/dist/migrations/deploy-outcome-guard-edit.js.map +1 -0
- package/dist/migrations/deploy-outcome-guard-yaml.d.ts +91 -0
- package/dist/migrations/deploy-outcome-guard-yaml.d.ts.map +1 -0
- package/dist/migrations/deploy-outcome-guard-yaml.js +180 -0
- package/dist/migrations/deploy-outcome-guard-yaml.js.map +1 -0
- package/dist/migrations/ensure-deploy-outcome-guard.d.ts +41 -0
- package/dist/migrations/ensure-deploy-outcome-guard.d.ts.map +1 -0
- package/dist/migrations/ensure-deploy-outcome-guard.js +238 -0
- package/dist/migrations/ensure-deploy-outcome-guard.js.map +1 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -0
- package/dist/migrations/index.js.map +1 -1
- package/expo/copy-overwrite/scripts/bdd/baseline.mjs +26 -7
- package/package.json +5 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/lisa/hooks/threshold-ratchet.mjs +6 -0
- package/plugins/lisa/hooks/worktree-binding-guard.mjs +31 -3
- package/plugins/lisa/scripts/design-variable-ids.mjs +2 -0
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/design-variable-ids.mjs +2 -0
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa-agy/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/threshold-ratchet.mjs +6 -0
- package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +31 -3
- package/plugins/lisa-copilot/scripts/design-variable-ids.mjs +2 -0
- package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa-copilot/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/threshold-ratchet.mjs +6 -0
- package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +31 -3
- package/plugins/lisa-cursor/scripts/design-variable-ids.mjs +2 -0
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa-cursor/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/scripts/ingest-git.mjs +2 -0
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/scripts/ingest-git.mjs +2 -0
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/scripts/ingest-git.mjs +2 -0
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/scripts/ingest-git.mjs +2 -0
- package/plugins/src/base/hooks/threshold-ratchet.mjs +6 -0
- package/plugins/src/base/hooks/worktree-binding-guard.mjs +31 -3
- package/plugins/src/base/scripts/design-variable-ids.mjs +2 -0
- package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/src/base/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/src/base/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/src/base/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/src/base/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/src/wiki/scripts/ingest-git.mjs +2 -0
- package/rails/copy-overwrite/scripts/check-threshold-ratchet.mjs +6 -0
- package/scripts/check-merge-driver-registration.mjs +2 -0
- package/scripts/check-probe-absence-direction.mjs +611 -0
- package/scripts/check-test-case-executed.mjs +184 -0
- package/scripts/install-generated-artifact-merge-driver.mjs +7 -1
- package/scripts/lib/shell-guard-refusal-coverage.mjs +18 -19
- package/typescript/copy-overwrite/scripts/check-threshold-ratchet.mjs +6 -0
- package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +4 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repair an already-seeded `deploy.yml` whose deploy job goes SILENT when its
|
|
3
|
+
* release fails (CodySwannGT/lisa#3740).
|
|
4
|
+
*
|
|
5
|
+
* ## Why a migration and not a template fix
|
|
6
|
+
*
|
|
7
|
+
* #3467 found a deploy job that was SKIPPED rather than failed when its release
|
|
8
|
+
* failed. GitHub renders a skipped job as neutral and counts a skipped required
|
|
9
|
+
* check as satisfied, so the deploy that never happened left no signal
|
|
10
|
+
* anywhere: release commit present, versions matching, every status green. A
|
|
11
|
+
* consuming repository ran eight days that way.
|
|
12
|
+
*
|
|
13
|
+
* #3738 fixed the templates. Those templates are `create-only` — Lisa seeds
|
|
14
|
+
* `deploy.yml` once and never overwrites it, because the host owns that file —
|
|
15
|
+
* so the fix reaches new adoptions and reaches nothing that already exists,
|
|
16
|
+
* which is precisely where the defect is live. `copy-overwrite` would clobber
|
|
17
|
+
* host customizations, and no reusable workflow can force a caller's job to
|
|
18
|
+
* run. A migration is the surface that reaches the installed base, exactly as
|
|
19
|
+
* `ensure-nightly-e2e-workflow-pins` does for the same `create-only` wall
|
|
20
|
+
* (#3476, #3485).
|
|
21
|
+
*
|
|
22
|
+
* ## What it will and will not touch
|
|
23
|
+
*
|
|
24
|
+
* It repairs a deploy job only when it can do BOTH halves: suppress the
|
|
25
|
+
* implicit `success()` so the job runs on a failed release, and insert the
|
|
26
|
+
* guard step that then fails it loudly. Half of that repair would be worse than
|
|
27
|
+
* the defect — a deploy job that runs on a failed release with nothing checking
|
|
28
|
+
* the release result would try to ship.
|
|
29
|
+
*
|
|
30
|
+
* It declines, leaving the doctor finding to report the file, when:
|
|
31
|
+
*
|
|
32
|
+
* - the run is `postinstallSafe`. Nobody types `bun install` meaning to rewrite
|
|
33
|
+
* a reviewed, checked-in workflow, and the interface says so outright;
|
|
34
|
+
* - the condition needs a rewrite this cannot make without guessing;
|
|
35
|
+
* - the file's shape cannot be located unambiguously;
|
|
36
|
+
* - the edited file does not parse, or does not come back repaired.
|
|
37
|
+
*
|
|
38
|
+
* The guard body is lifted from Lisa's own shipped template rather than
|
|
39
|
+
* reproduced here, so the copy a test keeps identical across the templates is
|
|
40
|
+
* the copy a host receives.
|
|
41
|
+
* @module migrations/ensure-deploy-outcome-guard
|
|
42
|
+
*/
|
|
43
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
44
|
+
import * as path from "node:path";
|
|
45
|
+
import { deployJobsSkippedByFailedRelease, releaseDependence, } from "../core/deploy-release-dependence.js";
|
|
46
|
+
import { parseRepositoryWorkflows, } from "../cli/doctor-readiness-workflows.js";
|
|
47
|
+
import { isJsonObject } from "../sync/json-path.js";
|
|
48
|
+
import { loadYaml } from "../utils/yaml.js";
|
|
49
|
+
import { GUARD_STEP_NAME, rewrittenCondition, } from "./deploy-outcome-guard-edit.js";
|
|
50
|
+
import { applyGuardEdits, extractGuardStep, } from "./deploy-outcome-guard-yaml.js";
|
|
51
|
+
/**
|
|
52
|
+
* The shipped template the guard step is read out of.
|
|
53
|
+
*
|
|
54
|
+
* The rails one specifically: its guard names the environment as
|
|
55
|
+
* `github.ref_name`, which resolves in any repository, while the expo copy
|
|
56
|
+
* reads an output only that workflow's job graph publishes. The `run:` body is
|
|
57
|
+
* identical in both — a test asserts it — so this choice is about the `env:`
|
|
58
|
+
* block travelling safely, not about the words an operator reads.
|
|
59
|
+
*/
|
|
60
|
+
const GUARD_TEMPLATE = path.join("rails", "create-only", ".github", "workflows", "deploy.yml");
|
|
61
|
+
/** The release job id the shipped template's guard step refers to. */
|
|
62
|
+
const TEMPLATE_RELEASE_JOB = "release";
|
|
63
|
+
/**
|
|
64
|
+
* Re-read one job out of an edited workflow source.
|
|
65
|
+
* @param source - The edited workflow source
|
|
66
|
+
* @param jobId - The job to read back
|
|
67
|
+
* @returns The job's condition and first step name, or null when unreadable
|
|
68
|
+
*/
|
|
69
|
+
function readBackJob(source, jobId) {
|
|
70
|
+
try {
|
|
71
|
+
const document = loadYaml(source);
|
|
72
|
+
if (!isJsonObject(document) || !isJsonObject(document.jobs))
|
|
73
|
+
return null;
|
|
74
|
+
const job = document.jobs[jobId];
|
|
75
|
+
if (!isJsonObject(job))
|
|
76
|
+
return null;
|
|
77
|
+
const steps = Array.isArray(job.steps) ? job.steps : [];
|
|
78
|
+
const first = steps[0];
|
|
79
|
+
return {
|
|
80
|
+
ifCondition: typeof job.if === "string" ? job.if : "",
|
|
81
|
+
firstStep: isJsonObject(first) && typeof first.name === "string" ? first.name : "",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Whether an edited source really repaired the job it claims to have repaired.
|
|
90
|
+
*
|
|
91
|
+
* The post-condition, not a formality: a mis-indented insertion produces a file
|
|
92
|
+
* that still parses and still skips, and writing that would replace a reported
|
|
93
|
+
* defect with an unreported one.
|
|
94
|
+
* @param source - The edited workflow source
|
|
95
|
+
* @param job - The job as originally parsed
|
|
96
|
+
* @param release - The upstream release job's id
|
|
97
|
+
* @returns True when the job now survives a failed release and carries the guard
|
|
98
|
+
*/
|
|
99
|
+
function repairHolds(source, job, release) {
|
|
100
|
+
const readBack = readBackJob(source, job.id);
|
|
101
|
+
if (readBack === null)
|
|
102
|
+
return false;
|
|
103
|
+
if (readBack.firstStep !== GUARD_STEP_NAME)
|
|
104
|
+
return false;
|
|
105
|
+
return (releaseDependence({ ...job, ifCondition: readBack.ifCondition }, release)
|
|
106
|
+
.kind === "independent");
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Turn one parsed job into the shape the dependence analysis reads.
|
|
110
|
+
* @param job - The parsed workflow job
|
|
111
|
+
* @returns The analysis input
|
|
112
|
+
*/
|
|
113
|
+
function asDependenceJob(job) {
|
|
114
|
+
return {
|
|
115
|
+
id: job.id,
|
|
116
|
+
name: job.name,
|
|
117
|
+
needs: job.needs,
|
|
118
|
+
ifCondition: job.ifCondition,
|
|
119
|
+
environment: job.environment,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Repair every repairable deploy job in one workflow's source.
|
|
124
|
+
* @param source - The host workflow's source
|
|
125
|
+
* @param workflow - The parsed workflow
|
|
126
|
+
* @param guardStep - The guard step's lines, de-indented to column zero
|
|
127
|
+
* @returns The repaired source and the jobs repaired, or null when none were
|
|
128
|
+
*/
|
|
129
|
+
function repairWorkflow(source, workflow, guardStep) {
|
|
130
|
+
const found = deployJobsSkippedByFailedRelease(workflow.jobs.map(asDependenceJob));
|
|
131
|
+
const repaired = found.reduce((carried, entry) => {
|
|
132
|
+
const condition = rewrittenCondition(entry.job, entry.release);
|
|
133
|
+
if (condition === null)
|
|
134
|
+
return carried;
|
|
135
|
+
const guard = guardStep.map(line => line.replaceAll(`needs.${TEMPLATE_RELEASE_JOB}.result`, `needs.${entry.release}.result`));
|
|
136
|
+
const edited = applyGuardEdits(carried.source, entry.job.id, condition, guard);
|
|
137
|
+
if (edited === null || !repairHolds(edited, entry.job, entry.release)) {
|
|
138
|
+
return carried;
|
|
139
|
+
}
|
|
140
|
+
return { source: edited, jobs: [...carried.jobs, entry.job.id] };
|
|
141
|
+
}, { source, jobs: [] });
|
|
142
|
+
return repaired.jobs.length === 0 ? null : repaired;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Bring an already-seeded deploy workflow up to the #3467 outcome contract.
|
|
146
|
+
*/
|
|
147
|
+
export class EnsureDeployOutcomeGuardMigration {
|
|
148
|
+
name = "ensure-deploy-outcome-guard";
|
|
149
|
+
description = "Make an already-seeded deploy job fail loudly instead of skipping silently when its release does not succeed";
|
|
150
|
+
/**
|
|
151
|
+
* Whether any host deploy workflow can be repaired.
|
|
152
|
+
* @param ctx - Migration context
|
|
153
|
+
* @returns True when at least one workflow would change
|
|
154
|
+
*/
|
|
155
|
+
async applies(ctx) {
|
|
156
|
+
return (await this.plan(ctx)).length > 0;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Rewrite every repairable deploy workflow.
|
|
160
|
+
* @param ctx - Migration context
|
|
161
|
+
* @returns Applied or no-op result
|
|
162
|
+
*/
|
|
163
|
+
async apply(ctx) {
|
|
164
|
+
const edits = await this.plan(ctx);
|
|
165
|
+
if (edits.length === 0) {
|
|
166
|
+
return { name: this.name, action: "noop" };
|
|
167
|
+
}
|
|
168
|
+
const changedFiles = edits.map(edit => edit.relative);
|
|
169
|
+
const message = `Made ${edits.flatMap(edit => edit.jobs).length} deploy job(s) fail ` +
|
|
170
|
+
"loudly instead of skipping silently when the release does not succeed";
|
|
171
|
+
if (ctx.dryRun) {
|
|
172
|
+
ctx.logger.dry(`Would update ${changedFiles.join(", ")}`);
|
|
173
|
+
return { name: this.name, action: "applied", changedFiles, message };
|
|
174
|
+
}
|
|
175
|
+
for (const edit of edits) {
|
|
176
|
+
await writeFile(edit.absolute, edit.source);
|
|
177
|
+
}
|
|
178
|
+
ctx.logger.success(message);
|
|
179
|
+
return { name: this.name, action: "applied", changedFiles, message };
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Work out which host workflows this run would rewrite.
|
|
183
|
+
* @param ctx - Migration context
|
|
184
|
+
* @returns One entry per workflow that can be repaired
|
|
185
|
+
*/
|
|
186
|
+
async plan(ctx) {
|
|
187
|
+
// A dependency install is not somebody asking for a reviewed workflow to be
|
|
188
|
+
// rewritten. The doctor finding reports these instead.
|
|
189
|
+
if (ctx.postinstallSafe === true)
|
|
190
|
+
return [];
|
|
191
|
+
const guardStep = await this.readGuardStep(ctx.lisaDir);
|
|
192
|
+
if (guardStep === null)
|
|
193
|
+
return [];
|
|
194
|
+
const workflows = await parseRepositoryWorkflows(ctx.projectDir);
|
|
195
|
+
const planned = await Promise.all(workflows.map(async (workflow) => await this.planOne(ctx, workflow, guardStep)));
|
|
196
|
+
return planned.filter((edit) => edit !== null);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Plan the repair of one workflow.
|
|
200
|
+
* @param ctx - Migration context
|
|
201
|
+
* @param workflow - The parsed workflow
|
|
202
|
+
* @param guardStep - The guard step's lines
|
|
203
|
+
* @returns The planned edit, or null when nothing here can be repaired
|
|
204
|
+
*/
|
|
205
|
+
async planOne(ctx, workflow, guardStep) {
|
|
206
|
+
const absolute = path.join(ctx.projectDir, ...workflow.file.split("/"));
|
|
207
|
+
try {
|
|
208
|
+
const source = await readFile(absolute, "utf8");
|
|
209
|
+
const repaired = repairWorkflow(source, workflow, guardStep);
|
|
210
|
+
return repaired === null
|
|
211
|
+
? null
|
|
212
|
+
: {
|
|
213
|
+
relative: workflow.file,
|
|
214
|
+
absolute,
|
|
215
|
+
source: repaired.source,
|
|
216
|
+
jobs: repaired.jobs,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Read the guard step out of Lisa's own shipped deploy template.
|
|
225
|
+
* @param lisaDir - Lisa installation directory
|
|
226
|
+
* @returns The step's lines, or null when the template cannot be read
|
|
227
|
+
*/
|
|
228
|
+
async readGuardStep(lisaDir) {
|
|
229
|
+
try {
|
|
230
|
+
const template = await readFile(path.join(lisaDir, GUARD_TEMPLATE), "utf8");
|
|
231
|
+
return extractGuardStep(template, GUARD_STEP_NAME);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=ensure-deploy-outcome-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-deploy-outcome-guard.js","sourceRoot":"","sources":["../../src/migrations/ensure-deploy-outcome-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Migration, MigrationContext, MigrationResult } from "./migration.interface.js";
|
|
2
2
|
export type { Migration, MigrationAction, MigrationContext, MigrationResult, } from "./migration.interface.js";
|
|
3
3
|
export { EnsureAuditIgnoreLocalExclusionsMigration } from "./ensure-audit-ignore-local-exclusions.js";
|
|
4
|
+
export { EnsureDeployOutcomeGuardMigration } from "./ensure-deploy-outcome-guard.js";
|
|
4
5
|
export { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-mock-accessibility-manager.js";
|
|
5
6
|
export { EnsureLearningsGitattributesMigration } from "./ensure-learnings-gitattributes.js";
|
|
6
7
|
export { EnsureLearningsMergeDriverMigration } from "./ensure-learnings-merge-driver.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,qCAAqC,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,mCAAmC,EAAE,MAAM,oCAAoC,CAAC;AACzF,OAAO,EAAE,uCAAuC,EAAE,MAAM,wCAAwC,CAAC;AACjG,OAAO,EAAE,qCAAqC,EAAE,MAAM,uCAAuC,CAAC;AAC9F,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,gCAAgC,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,wCAAwC,EAAE,MAAM,yCAAyC,CAAC;AACnG,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,mCAAmC,EAAE,MAAM,qCAAqC,CAAC;AAC1F,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,sCAAsC,CAAC;AAC5F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,gCAAgC,EAAE,MAAM,gCAAgC,CAAC;AAElF;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAElD;;;OAGG;gBACS,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE;IA6B7C;;;OAGG;IACH,MAAM,IAAI,SAAS,SAAS,EAAE;IAI9B;;;;OAIG;IACG,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;CAazE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D"}
|
package/dist/migrations/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EnsureAuditIgnoreLocalExclusionsMigration } from "./ensure-audit-ignore-local-exclusions.js";
|
|
2
|
+
import { EnsureDeployOutcomeGuardMigration } from "./ensure-deploy-outcome-guard.js";
|
|
2
3
|
import { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-mock-accessibility-manager.js";
|
|
3
4
|
import { EnsureLearningsGitattributesMigration } from "./ensure-learnings-gitattributes.js";
|
|
4
5
|
import { EnsureLearningsMergeDriverMigration } from "./ensure-learnings-merge-driver.js";
|
|
@@ -20,6 +21,7 @@ import { PruneRetiredClaudeDenyRulesMigration } from "./prune-retired-claude-den
|
|
|
20
21
|
import { ReconcileClaudeStackPluginsMigration } from "./reconcile-claude-stack-plugins.js";
|
|
21
22
|
import { UntrackCodexMarketplaceMigration } from "./untrack-codex-marketplace.js";
|
|
22
23
|
export { EnsureAuditIgnoreLocalExclusionsMigration } from "./ensure-audit-ignore-local-exclusions.js";
|
|
24
|
+
export { EnsureDeployOutcomeGuardMigration } from "./ensure-deploy-outcome-guard.js";
|
|
23
25
|
export { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-mock-accessibility-manager.js";
|
|
24
26
|
export { EnsureLearningsGitattributesMigration } from "./ensure-learnings-gitattributes.js";
|
|
25
27
|
export { EnsureLearningsMergeDriverMigration } from "./ensure-learnings-merge-driver.js";
|
|
@@ -54,6 +56,7 @@ export class MigrationRegistry {
|
|
|
54
56
|
new EnsureTsconfigLocalIncludesMigration(),
|
|
55
57
|
new EnsureTsconfigLocalFilesFallbackMigration(),
|
|
56
58
|
new EnsureAuditIgnoreLocalExclusionsMigration(),
|
|
59
|
+
new EnsureDeployOutcomeGuardMigration(),
|
|
57
60
|
new EnsureJestRnMockAccessibilityManagerMigration(),
|
|
58
61
|
new EnsureLearningsGitattributesMigration(),
|
|
59
62
|
new EnsureLearningsMergeDriverMigration(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -143,9 +143,18 @@ export function showAtRevision(root, revision, relative) {
|
|
|
143
143
|
|
|
144
144
|
/**
|
|
145
145
|
* List the feature files that existed at a revision.
|
|
146
|
+
*
|
|
147
|
+
* Three-state on purpose. `git ls-tree` exits 0 with EMPTY output for a
|
|
148
|
+
* revision that genuinely holds no features, so a non-zero exit is always
|
|
149
|
+
* "could not ask" and never "there were none". Handing both back as `[]` let
|
|
150
|
+
* one failed listing read as an empty baseline, and an empty `before` set
|
|
151
|
+
* produces no `scenario-deleted` and no `coverage-regression` finding at all —
|
|
152
|
+
* so the gate reported that nothing regressed having compared against nothing.
|
|
153
|
+
* That is the same hole `loadBaseline` already closes for the coverage map,
|
|
154
|
+
* left open on the feature files beside it.
|
|
146
155
|
* @param {string} root - Repo root.
|
|
147
156
|
* @param {string} revision - Commit-ish.
|
|
148
|
-
* @returns {string[]}
|
|
157
|
+
* @returns {{ok: boolean, files: string[]}} Listing, and whether it was taken.
|
|
149
158
|
*/
|
|
150
159
|
function featureFilesAt(root, revision) {
|
|
151
160
|
const result = git(root, [
|
|
@@ -156,11 +165,16 @@ function featureFilesAt(root, revision) {
|
|
|
156
165
|
"--",
|
|
157
166
|
"bdd/features",
|
|
158
167
|
]);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
// probe-direction: fail-closed — `ok: false` reaches `loadBaseline`, which
|
|
169
|
+
// records the baseline UNAVAILABLE instead of empty.
|
|
170
|
+
if (!result.ok) return { ok: false, files: [] };
|
|
171
|
+
return {
|
|
172
|
+
ok: true,
|
|
173
|
+
files: result.stdout
|
|
174
|
+
.split("\n")
|
|
175
|
+
.map(line => line.trim())
|
|
176
|
+
.filter(line => line.endsWith(".feature")),
|
|
177
|
+
};
|
|
164
178
|
}
|
|
165
179
|
|
|
166
180
|
/**
|
|
@@ -198,12 +212,17 @@ export function loadBaseline(root, revision, headPlatforms = new Set()) {
|
|
|
198
212
|
error = `bdd/coverage-map.json at that revision is not valid JSON: ${parseError.message}`;
|
|
199
213
|
}
|
|
200
214
|
}
|
|
215
|
+
const listing = featureFilesAt(root, revision);
|
|
201
216
|
if (binary === null) {
|
|
202
217
|
error = "git was not found, so no base revision could be read";
|
|
203
218
|
} else if (!revisionExists) {
|
|
204
219
|
error = "the requested base does not name a readable commit";
|
|
220
|
+
} else if (!listing.ok) {
|
|
221
|
+
error =
|
|
222
|
+
"the base revision's feature files could not be listed, so no scenario " +
|
|
223
|
+
"from it could be compared";
|
|
205
224
|
}
|
|
206
|
-
const documents =
|
|
225
|
+
const documents = listing.files
|
|
207
226
|
.map(file => ({ file, source: showAtRevision(root, revision, file) }))
|
|
208
227
|
.filter(document => document.source !== null);
|
|
209
228
|
const platforms = new Set([
|
package/package.json
CHANGED
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"check:pipeline-status-reads": "node scripts/check-pipeline-status-reads.mjs",
|
|
64
64
|
"check:whole-output-guards": "node scripts/check-whole-output-guards.mjs",
|
|
65
65
|
"check:empty-subject-guards": "node scripts/check-empty-subject-guards.mjs",
|
|
66
|
+
"check:probe-absence-direction": "node scripts/check-probe-absence-direction.mjs",
|
|
66
67
|
"check:shell-guard-refusals": "bun run build && $npm_execpath run lisa-test-run -- --adapter direct -- node scripts/check-shell-guard-refusal-coverage.mjs",
|
|
67
68
|
"check:workflow-inputs": "node scripts/detect-stale-workflow-inputs.mjs --project . --project typescript/create-only --project rails/create-only --json",
|
|
68
69
|
"check:conflict-markers": "node all/copy-overwrite/scripts/check-conflict-markers.mjs",
|
|
@@ -173,7 +174,7 @@
|
|
|
173
174
|
"zod-validation-error": "^4.0.0"
|
|
174
175
|
},
|
|
175
176
|
"name": "@codyswann/lisa",
|
|
176
|
-
"version": "4.
|
|
177
|
+
"version": "4.43.0",
|
|
177
178
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
178
179
|
"main": "dist/index.js",
|
|
179
180
|
"exports": {
|
|
@@ -321,7 +322,7 @@
|
|
|
321
322
|
"test": "tests"
|
|
322
323
|
},
|
|
323
324
|
"types": "./dist/index.d.ts",
|
|
324
|
-
"lisaReleaseCommit": "
|
|
325
|
-
"gitHead": "
|
|
326
|
-
"lisaReleaseTag": "v4.
|
|
325
|
+
"lisaReleaseCommit": "e7ce0fdee9ed37c14c80f0925a1e455c2e88c05f",
|
|
326
|
+
"gitHead": "e7ce0fdee9ed37c14c80f0925a1e455c2e88c05f",
|
|
327
|
+
"lisaReleaseTag": "v4.43.0"
|
|
327
328
|
}
|
|
@@ -617,6 +617,17 @@ gh api "repos/<owner>/<repo>/actions/runs?head_sha=<head>" --jq .total_count
|
|
|
617
617
|
problem. If CI were merely slow you would see runs QUEUED, not absent. Resolve
|
|
618
618
|
the conflict and the runs appear; nothing else will make them appear.
|
|
619
619
|
|
|
620
|
+
**`<head>` must be the FULL 40-character SHA.** `head_sha=` does not match a
|
|
621
|
+
prefix and does not reject one: an abbreviated SHA returns a clean
|
|
622
|
+
`total_count: 0` — not a 404, not a validation error, an absence shaped exactly
|
|
623
|
+
like "no workflow ran". Measured on one pull request's own head: `77f223b9d` →
|
|
624
|
+
`total_count 0`, `77f223b9d8ffe7b172e9cac48b068b3bcac304c3` → `total_count 4`.
|
|
625
|
+
Take the SHA from `gh pr view <pr> --json headRefOid --jq .headRefOid`, never
|
|
626
|
+
from `git log --oneline` or a truncated line in a log or a UI. Copying a short
|
|
627
|
+
SHA here makes EVERY pull request read as having no CI, and the natural next
|
|
628
|
+
action — rebase and force-push — throws away the live run you could not see
|
|
629
|
+
(#3848).
|
|
630
|
+
|
|
620
631
|
**`mergeable` is computed asynchronously.** GitHub returns `null` while it is
|
|
621
632
|
still working it out, so a single read on a freshly-opened PR can say `null` on
|
|
622
633
|
a perfectly clean branch. Treat `null` as "cannot tell yet" and re-read — never
|
|
@@ -218,6 +218,9 @@ export function hasBootstrap(key, deps = {}) {
|
|
|
218
218
|
);
|
|
219
219
|
return true;
|
|
220
220
|
} catch {
|
|
221
|
+
// probe-direction: fail-closed — false means "no bootstrap value proven
|
|
222
|
+
// present", which makes the setup flow ASK for one. A keychain that cannot
|
|
223
|
+
// be queried costs a redundant prompt, never a skipped bootstrap.
|
|
221
224
|
return false;
|
|
222
225
|
}
|
|
223
226
|
}
|
|
@@ -270,6 +270,9 @@ export function runProbe(substrate) {
|
|
|
270
270
|
});
|
|
271
271
|
return true;
|
|
272
272
|
} catch {
|
|
273
|
+
// probe-direction: fail-closed — false makes the caller behave as if no
|
|
274
|
+
// substrate existed and fall through to the provider, which is the stricter
|
|
275
|
+
// path, exactly as the paragraph above states.
|
|
273
276
|
return false;
|
|
274
277
|
}
|
|
275
278
|
}
|
|
@@ -178,6 +178,8 @@ function keychainServiceNames() {
|
|
|
178
178
|
([, name]) => name
|
|
179
179
|
);
|
|
180
180
|
} catch {
|
|
181
|
+
// probe-direction: neutral — the names only enrich a diagnostic message on a
|
|
182
|
+
// path that has already failed; no verdict reads them.
|
|
181
183
|
// A locked, absent, or oversized keychain leaves the list empty.
|
|
182
184
|
return [];
|
|
183
185
|
}
|
|
@@ -253,6 +255,8 @@ export function providerCliPresent(prefix) {
|
|
|
253
255
|
).trim()
|
|
254
256
|
);
|
|
255
257
|
} catch {
|
|
258
|
+
// probe-direction: neutral — PATH presence is reported in the explanation of
|
|
259
|
+
// an already-failing lookup; it gates nothing on its own.
|
|
256
260
|
return false;
|
|
257
261
|
}
|
|
258
262
|
}
|
|
@@ -66,6 +66,9 @@ export function locate(name, exec = boundedChildOutput) {
|
|
|
66
66
|
exec("command", ["-v", name], { encoding: "utf8", shell: true })
|
|
67
67
|
).trim();
|
|
68
68
|
} catch {
|
|
69
|
+
// probe-direction: fail-closed — null means "not proven present", and the
|
|
70
|
+
// setup flow responds by installing. A probe that cannot answer costs a
|
|
71
|
+
// redundant install, never a missing tool reported as present.
|
|
69
72
|
return null;
|
|
70
73
|
}
|
|
71
74
|
}
|
|
@@ -121,6 +121,10 @@ function git(args, cwd) {
|
|
|
121
121
|
timeout: 30_000,
|
|
122
122
|
});
|
|
123
123
|
} catch {
|
|
124
|
+
// probe-direction: fail-closed — null never reaches a verdict as "no
|
|
125
|
+
// weakening found". `changePlan` turns it into `undeterminable`, which
|
|
126
|
+
// REFUSES, and `isPromotion` falls to the strict reading that keeps the
|
|
127
|
+
// allow list pinned to the baseline.
|
|
124
128
|
return null;
|
|
125
129
|
}
|
|
126
130
|
}
|
|
@@ -166,6 +170,8 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
166
170
|
try {
|
|
167
171
|
return fs.readFileSync(path.join(root, f), "utf-8");
|
|
168
172
|
} catch {
|
|
173
|
+
// probe-direction: fail-closed — an unreadable current file compares as
|
|
174
|
+
// absent against the baseline, which is the strict side of the ratchet.
|
|
169
175
|
return null;
|
|
170
176
|
}
|
|
171
177
|
},
|
|
@@ -96,14 +96,35 @@ function git(args, cwd) {
|
|
|
96
96
|
stdio: ["ignore", "pipe", "ignore"],
|
|
97
97
|
}).trim();
|
|
98
98
|
} catch {
|
|
99
|
+
// probe-direction: neutral — this helper REPORTS, it does not decide. Both
|
|
100
|
+
// callers below read null and each one says out loud what it could not do
|
|
101
|
+
// before returning, so no gate outcome follows from this null silently
|
|
102
|
+
// (#3848). Keep that true: a caller added here that spends null as an
|
|
103
|
+
// answer has to say so at its own line.
|
|
99
104
|
return null;
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
|
|
103
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* The worktree root containing `cwd`, or null when `cwd` is not in a repo.
|
|
110
|
+
*
|
|
111
|
+
* `--show-toplevel` exits non-zero for two OPPOSITE reasons and hands back the
|
|
112
|
+
* same nothing for both: `cwd` is outside any repository — a real absence, and
|
|
113
|
+
* a call there is genuinely none of this guard's business — or git could not
|
|
114
|
+
* answer at all, where the binding is unproven rather than inapplicable. Only
|
|
115
|
+
* the second is a withdrawal of enforcement, and it is the one that must not
|
|
116
|
+
* pass for the first. `git --version` succeeds wherever git can run, so its
|
|
117
|
+
* failure is what separates them.
|
|
118
|
+
* @param {string} cwd Directory the tool call runs in.
|
|
119
|
+
* @returns {string|null} Absolute worktree root, or null.
|
|
120
|
+
*/
|
|
104
121
|
function worktreeRoot(cwd) {
|
|
105
122
|
const top = git(["rev-parse", "--show-toplevel"], cwd);
|
|
106
|
-
|
|
123
|
+
if (top) return resolve(top);
|
|
124
|
+
if (git(["--version"], cwd) === null) {
|
|
125
|
+
say("git could not be run here, so the worktree binding is NOT enforced");
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
107
128
|
}
|
|
108
129
|
|
|
109
130
|
/**
|
|
@@ -117,7 +138,14 @@ function mainCheckout(cwd) {
|
|
|
117
138
|
["rev-parse", "--path-format=absolute", "--git-common-dir"],
|
|
118
139
|
cwd
|
|
119
140
|
);
|
|
120
|
-
|
|
141
|
+
if (common) return dirname(resolve(common));
|
|
142
|
+
// Reached only for an `EnterWorktree` naming a worktree, which means a
|
|
143
|
+
// repository was already in hand — so failing here is "could not ask", and
|
|
144
|
+
// the consequence is that the claim goes unrecorded and the NEXT call's
|
|
145
|
+
// displacement check has nothing to compare against. Said out loud rather
|
|
146
|
+
// than returned as a quiet null (#3848).
|
|
147
|
+
say("git could not resolve the main checkout, so this claim is NOT recorded");
|
|
148
|
+
return null;
|
|
121
149
|
}
|
|
122
150
|
|
|
123
151
|
function stateFile(sessionId) {
|
|
@@ -298,6 +298,8 @@ async function callMcp(token, tool, args) {
|
|
|
298
298
|
.map(part => part.text ?? "")
|
|
299
299
|
.join("");
|
|
300
300
|
} catch {
|
|
301
|
+
// probe-direction: neutral — this is a design-token lookup for a generator;
|
|
302
|
+
// no gate reads the result, and null renders as a missing token.
|
|
301
303
|
return null;
|
|
302
304
|
}
|
|
303
305
|
}
|
|
@@ -617,6 +617,17 @@ gh api "repos/<owner>/<repo>/actions/runs?head_sha=<head>" --jq .total_count
|
|
|
617
617
|
problem. If CI were merely slow you would see runs QUEUED, not absent. Resolve
|
|
618
618
|
the conflict and the runs appear; nothing else will make them appear.
|
|
619
619
|
|
|
620
|
+
**`<head>` must be the FULL 40-character SHA.** `head_sha=` does not match a
|
|
621
|
+
prefix and does not reject one: an abbreviated SHA returns a clean
|
|
622
|
+
`total_count: 0` — not a 404, not a validation error, an absence shaped exactly
|
|
623
|
+
like "no workflow ran". Measured on one pull request's own head: `77f223b9d` →
|
|
624
|
+
`total_count 0`, `77f223b9d8ffe7b172e9cac48b068b3bcac304c3` → `total_count 4`.
|
|
625
|
+
Take the SHA from `gh pr view <pr> --json headRefOid --jq .headRefOid`, never
|
|
626
|
+
from `git log --oneline` or a truncated line in a log or a UI. Copying a short
|
|
627
|
+
SHA here makes EVERY pull request read as having no CI, and the natural next
|
|
628
|
+
action — rebase and force-push — throws away the live run you could not see
|
|
629
|
+
(#3848).
|
|
630
|
+
|
|
620
631
|
**`mergeable` is computed asynchronously.** GitHub returns `null` while it is
|
|
621
632
|
still working it out, so a single read on a freshly-opened PR can say `null` on
|
|
622
633
|
a perfectly clean branch. Treat `null` as "cannot tell yet" and re-read — never
|
|
@@ -218,6 +218,9 @@ export function hasBootstrap(key, deps = {}) {
|
|
|
218
218
|
);
|
|
219
219
|
return true;
|
|
220
220
|
} catch {
|
|
221
|
+
// probe-direction: fail-closed — false means "no bootstrap value proven
|
|
222
|
+
// present", which makes the setup flow ASK for one. A keychain that cannot
|
|
223
|
+
// be queried costs a redundant prompt, never a skipped bootstrap.
|
|
221
224
|
return false;
|
|
222
225
|
}
|
|
223
226
|
}
|
|
@@ -270,6 +270,9 @@ export function runProbe(substrate) {
|
|
|
270
270
|
});
|
|
271
271
|
return true;
|
|
272
272
|
} catch {
|
|
273
|
+
// probe-direction: fail-closed — false makes the caller behave as if no
|
|
274
|
+
// substrate existed and fall through to the provider, which is the stricter
|
|
275
|
+
// path, exactly as the paragraph above states.
|
|
273
276
|
return false;
|
|
274
277
|
}
|
|
275
278
|
}
|
|
@@ -178,6 +178,8 @@ function keychainServiceNames() {
|
|
|
178
178
|
([, name]) => name
|
|
179
179
|
);
|
|
180
180
|
} catch {
|
|
181
|
+
// probe-direction: neutral — the names only enrich a diagnostic message on a
|
|
182
|
+
// path that has already failed; no verdict reads them.
|
|
181
183
|
// A locked, absent, or oversized keychain leaves the list empty.
|
|
182
184
|
return [];
|
|
183
185
|
}
|
|
@@ -253,6 +255,8 @@ export function providerCliPresent(prefix) {
|
|
|
253
255
|
).trim()
|
|
254
256
|
);
|
|
255
257
|
} catch {
|
|
258
|
+
// probe-direction: neutral — PATH presence is reported in the explanation of
|
|
259
|
+
// an already-failing lookup; it gates nothing on its own.
|
|
256
260
|
return false;
|
|
257
261
|
}
|
|
258
262
|
}
|
|
@@ -66,6 +66,9 @@ export function locate(name, exec = boundedChildOutput) {
|
|
|
66
66
|
exec("command", ["-v", name], { encoding: "utf8", shell: true })
|
|
67
67
|
).trim();
|
|
68
68
|
} catch {
|
|
69
|
+
// probe-direction: fail-closed — null means "not proven present", and the
|
|
70
|
+
// setup flow responds by installing. A probe that cannot answer costs a
|
|
71
|
+
// redundant install, never a missing tool reported as present.
|
|
69
72
|
return null;
|
|
70
73
|
}
|
|
71
74
|
}
|