repo-harness 0.19.4 → 0.19.5

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.
Files changed (43) hide show
  1. package/README.es.md +2 -2
  2. package/README.fr.md +2 -2
  3. package/README.ja.md +2 -2
  4. package/README.md +2 -2
  5. package/README.zh-CN.md +2 -2
  6. package/agents/fleet/explorer.md +2 -2
  7. package/agents/fleet/fast-worker.md +3 -3
  8. package/agents/fleet/root-cause-prover.md +2 -2
  9. package/assets/hooks/lib/workflow-state.sh +9 -1
  10. package/assets/reference-configs/external-tooling.md +12 -11
  11. package/assets/skill-version.json +2 -2
  12. package/assets/templates/helpers/check-agent-tooling.sh +1 -1
  13. package/assets/templates/helpers/contract-run.ts +8 -1
  14. package/assets/templates/helpers/ensure-task-workflow.sh +2 -2
  15. package/assets/templates/helpers/install-agent-fleet.sh +17 -39
  16. package/assets/templates/helpers/verify-contract.sh +11 -1
  17. package/assets/templates/helpers/verify-sprint.sh +11 -1
  18. package/dist/hook-entry.js +1266 -1298
  19. package/dist/operator-ui/assets/index-CqlPK3N5.js +9 -0
  20. package/dist/operator-ui/index.html +1 -1
  21. package/package.json +12 -12
  22. package/scripts/axr5-archctx-clean-room.ts +1 -1
  23. package/scripts/axr6-stop-host-cycle.ts +4 -4
  24. package/scripts/axr7-consumer-e2e.ts +2 -2
  25. package/scripts/check-agent-tooling.sh +1 -1
  26. package/scripts/contract-run.ts +8 -1
  27. package/scripts/ensure-task-workflow.sh +2 -2
  28. package/scripts/install-agent-fleet.sh +17 -39
  29. package/scripts/lib/project-init-lib.sh +2 -2
  30. package/scripts/verify-contract.sh +11 -1
  31. package/scripts/verify-sprint.sh +11 -1
  32. package/src/cli/commands/global-runtime.ts +28 -4
  33. package/src/cli/index.ts +5 -2
  34. package/src/cli/installer/install-profile.ts +98 -6
  35. package/src/core/architecture/projection.ts +3 -3
  36. package/src/core/refactor/policy.ts +1 -1
  37. package/src/core/state/artifact-parsers.ts +14 -2
  38. package/src/effects/collaboration/handoff-store.ts +3 -3
  39. package/src/effects/collaboration/signal-store.ts +3 -3
  40. package/src/effects/evidence/attested-import.ts +2 -1
  41. package/src/effects/evidence/post-bash-importer.ts +2 -1
  42. package/src/effects/evidence/verify-producer.ts +2 -1
  43. package/dist/operator-ui/assets/index-f7BlYVSB.js +0 -9
package/README.es.md CHANGED
@@ -702,8 +702,8 @@ repositorio adopte la misma política.
702
702
 
703
703
  ## Versión actual
704
704
 
705
- - Paquete npm: `repo-harness@0.19.4`
706
- - Sello de workflow generado: `repo-harness@0.19.4+template@0.19.4`
705
+ - Paquete npm: `repo-harness@0.19.5`
706
+ - Sello de workflow generado: `repo-harness@0.19.5+template@0.19.5`
707
707
  - Repositorio de GitHub: `Ancienttwo/repo-harness`
708
708
  - Notas de versión e historial: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
709
709
 
package/README.fr.md CHANGED
@@ -697,8 +697,8 @@ adopte la même policy.
697
697
 
698
698
  ## Release actuelle
699
699
 
700
- - Package npm : `repo-harness@0.19.4`
701
- - Generated workflow stamp : `repo-harness@0.19.4+template@0.19.4`
700
+ - Package npm : `repo-harness@0.19.5`
701
+ - Generated workflow stamp : `repo-harness@0.19.5+template@0.19.5`
702
702
  - Dépôt GitHub : `Ancienttwo/repo-harness`
703
703
  - Notes et historique de release : [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
704
704
 
package/README.ja.md CHANGED
@@ -694,8 +694,8 @@ commit script や hooks に組み込まないでください。
694
694
 
695
695
  ## 現在の Release
696
696
 
697
- - npm package:`repo-harness@0.19.4`
698
- - Generated workflow stamp:`repo-harness@0.19.4+template@0.19.4`
697
+ - npm package:`repo-harness@0.19.5`
698
+ - Generated workflow stamp:`repo-harness@0.19.5+template@0.19.5`
699
699
  - GitHub repository:`Ancienttwo/repo-harness`
700
700
  - Release notes and history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
701
701
 
package/README.md CHANGED
@@ -665,8 +665,8 @@ repo-harness commit scripts or hooks unless that repo adopts the same policy.
665
665
 
666
666
  ## Current Release
667
667
 
668
- - npm package: `repo-harness@0.19.4`
669
- - Generated workflow stamp: `repo-harness@0.19.4+template@0.19.4`
668
+ - npm package: `repo-harness@0.19.5`
669
+ - Generated workflow stamp: `repo-harness@0.19.5+template@0.19.5`
670
670
  - GitHub repository: `Ancienttwo/repo-harness`
671
671
  - Release notes and history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
672
672
 
package/README.zh-CN.md CHANGED
@@ -630,8 +630,8 @@ commit script 或 hook,除非目标仓库采用同样的 policy。
630
630
 
631
631
  ## 当前 Release
632
632
 
633
- - npm package:`repo-harness@0.19.4`
634
- - Generated workflow stamp:`repo-harness@0.19.4+template@0.19.4`
633
+ - npm package:`repo-harness@0.19.5`
634
+ - Generated workflow stamp:`repo-harness@0.19.5+template@0.19.5`
635
635
  - GitHub repository:`Ancienttwo/repo-harness`
636
636
  - Release notes 和 history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
637
637
 
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: explorer
3
- description: Read-only codebase explorer on Sonnet at high effort. Use to locate files, symbols, call paths, tests, uncertainties, and candidate affected surfaces before implementation or judgment. Returns `FINDINGS: COMPLETE/PARTIAL/BLOCKED` with file:line evidence; never edits, decides architecture, or judges acceptance — hand the map to fast-worker, deep-reasoner, or gatekeeper.
3
+ description: Read-only codebase explorer on Sonnet at medium effort. Use to locate files, symbols, call paths, tests, uncertainties, and candidate affected surfaces before implementation or judgment. Returns `FINDINGS: COMPLETE/PARTIAL/BLOCKED` with file:line evidence; never edits, decides architecture, or judges acceptance — hand the map to fast-worker, deep-reasoner, or gatekeeper.
4
4
  tools: ["Read", "Grep", "Glob", "Bash"]
5
5
  model: sonnet
6
- effort: high
6
+ effort: medium
7
7
  ---
8
8
 
9
9
  You are the read-only explorer. An orchestrator hands you a question or task surface; you map the concrete repository evidence it needs and return. You do not edit, decide architecture, or judge acceptance.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: fast-worker
3
- description: Fast execution worker on Opus at medium effort. Use for well-scoped implementation, tests, refactoring, documentation, and mechanical changes; verifies with the project's real commands and returns `RESULT: DONE/PARTIAL/BLOCKED` with the evidence. Not for planning, architecture, or high-risk judgment — those go to deep-reasoner or stay with the orchestrator.
4
- model: opus
5
- effort: medium
3
+ description: Fast execution worker on Sonnet at high effort. Use for well-scoped implementation, tests, refactoring, documentation, and mechanical changes; verifies with the project's real commands and returns `RESULT: DONE/PARTIAL/BLOCKED` with the evidence. Not for planning, architecture, or high-risk judgment — those go to deep-reasoner or stay with the orchestrator.
4
+ model: sonnet
5
+ effort: high
6
6
  ---
7
7
 
8
8
  You are a fast execution worker. An orchestrator hands you well-scoped tasks — implementation, tests, refactoring, documentation, mechanical changes — and you execute them directly and return. You do not plan, decide architecture, or ship.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: root-cause-prover
3
- description: Bugfix diagnosis and pre-fix evidence specialist on Opus at high effort. Use to prove a concrete root cause, reproduce it, add a candidate regression guard, and capture the existing four-field Root Cause Evidence shape before implementation; returns `DIAGNOSIS: CONFIRMED|LIKELY|BLOCKED`. It never fixes production source or changes the gate.
3
+ description: Bugfix diagnosis and pre-fix evidence specialist on Opus at xhigh effort. Use to prove a concrete root cause, reproduce it, add a candidate regression guard, and capture the existing four-field Root Cause Evidence shape before implementation; returns `DIAGNOSIS: CONFIRMED|LIKELY|BLOCKED`. It never fixes production source or changes the gate.
4
4
  tools: ["Read", "Grep", "Glob", "Bash"]
5
5
  model: opus
6
- effort: high
6
+ effort: xhigh
7
7
  ---
8
8
 
9
9
  You are the bounded bugfix diagnosis and pre-fix evidence specialist. The orchestrator gives you an active bugfix contract in an isolated worktree; you prove or falsify the cause and prepare evidence for the existing gate. You never implement the production fix or reinterpret the gate.
@@ -1862,7 +1862,15 @@ workflow_contract_allows_path() {
1862
1862
  esac
1863
1863
 
1864
1864
  if [[ "$section" == "allowed_paths" && "$trimmed" =~ ^-[[:space:]]*(.+)$ ]]; then
1865
- item="$(workflow_strip_quotes "${BASH_REMATCH[1]}")"
1865
+ item="${BASH_REMATCH[1]}"
1866
+ # Drop a YAML inline comment: `#` at the start or after whitespace, outside a leading quoted scalar.
1867
+ case "$item" in
1868
+ \"*\"*) item="\"$(printf '%s' "${item:1}" | cut -d'"' -f1)\"" ;;
1869
+ \'*\'*) item="'$(printf '%s' "${item:1}" | cut -d"'" -f1)'" ;;
1870
+ *) item="$(printf '%s' "$item" | sed -E 's/^#.*$//; s/[[:space:]]+#.*$//')" ;;
1871
+ esac
1872
+ item="$(workflow_strip_quotes "$item")"
1873
+ [[ -n "$item" ]] || continue
1866
1874
  pattern="$item"
1867
1875
  if [[ "$pattern" == */ ]]; then
1868
1876
  [[ "$file_path" == "$pattern"* ]] && return 0
@@ -517,7 +517,7 @@ Minimal manifest shape:
517
517
  "run_id": "20260629T023507Z-aibridge-screenshot",
518
518
  "provider": {
519
519
  "name": "aibridge",
520
- "version": "1.5.0"
520
+ "version": "1.6.1"
521
521
  },
522
522
  "subject": {
523
523
  "task_type": "unity.ui",
@@ -609,7 +609,7 @@ diff -qr ~/.agents/skills/geju ~/.codex/skills/geju
609
609
  ### CodeGraph
610
610
 
611
611
  ```bash
612
- bun add -g @colbymchenry/codegraph@1.5.0 && codegraph sync . && codegraph status .
612
+ bun add -g @colbymchenry/codegraph@1.6.1 && codegraph sync . && codegraph status .
613
613
  ```
614
614
 
615
615
  ## Agent Fleet
@@ -639,23 +639,24 @@ mapping.
639
639
  |---|---|---|---|
640
640
  | `opus` | `gpt-6-astra` | `low`, `medium`, `high`, `xhigh`, `max` | same string, unchanged |
641
641
  | `sonnet`, `haiku` | `gpt-6-luna` | `low`, `medium`, `high`, `xhigh`, `max` | same string, unchanged |
642
- | `fable` | `gpt-6-sol` | `low`, `medium`, `high`, `xhigh`, `max` | same string, unchanged |
642
+ | `fable` | `gpt-6.1-sol` | `low`, `medium`, `high`, `xhigh`, `max` | same string, unchanged |
643
643
 
644
- Five per-agent target overrides are applied after tuple validation, on top of
644
+ Seven per-agent target overrides are applied after tuple validation, on top of
645
645
  the family row above, and are the only model/effort remaps in the generator:
646
- `fast-worker` (`opus`/`medium`) targets `gpt-6-sol` at `medium` reasoning;
647
- `deep-worker` (`opus`/`high`) targets `gpt-6-sol` at `xhigh` reasoning;
646
+ `explorer` (`sonnet`/`medium`) targets `gpt-6-luna` at `high` reasoning;
647
+ `deep-reasoner` (`opus`/`xhigh`) targets `gpt-6-astra` at `high` reasoning;
648
+ `fast-worker` (`sonnet`/`high`) targets `gpt-6.1-sol` at `medium` reasoning;
649
+ `deep-worker` (`opus`/`high`) targets `gpt-6.1-sol` at `high` reasoning;
648
650
  `gatekeeper` (`opus`/`high`) targets `gpt-6-astra` at `medium` reasoning;
649
- `root-cause-prover` and `harness-evaluator` (`opus`/`high`) target `gpt-6-sol`
650
- at `high` reasoning.
651
- Every other agent's Codex model and effort follow the family row unchanged.
651
+ `root-cause-prover` (`opus`/`xhigh`) targets `gpt-6-astra` at `high` reasoning;
652
+ `harness-evaluator` (`opus`/`high`) targets `gpt-6-astra` at `medium` reasoning.
652
653
 
653
654
  `fast-worker`, `deep-worker`, `root-cause-prover`, and `harness-evaluator`
654
655
  receive `sandbox_mode = "workspace-write"`; every other role receives
655
656
  `sandbox_mode = "read-only"`. Current assignments are explorer
656
- (`sonnet/high`), deep-reasoner (`opus/xhigh`), fast-worker (`opus/medium`),
657
+ (`sonnet/medium`), deep-reasoner (`opus/xhigh`), fast-worker (`sonnet/high`),
657
658
  deep-worker (`opus/high`), gatekeeper (`opus/high`), root-cause-prover
658
- (`opus/high`), and harness-evaluator (`opus/high`). Root-cause-prover's prompt further limits
659
+ (`opus/xhigh`), and harness-evaluator (`opus/high`). Root-cause-prover's prompt further limits
659
660
  writes to bugfix evidence inside the active contract's allowed paths;
660
661
  harness-evaluator runs existing skill/adoption surfaces only when both repo and
661
662
  HOME pass the runner's disposable boundary: skills uses `--require-disposable`,
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.19.4",
3
- "templateVersion": "0.19.4",
2
+ "version": "0.19.5",
3
+ "templateVersion": "0.19.5",
4
4
  "skillName": "repo-harness",
5
5
  "contractId": "tasks-first-harness-v1",
6
6
  "compatibility": {
@@ -1071,7 +1071,7 @@ function readAgentFleetSource(agent) {
1071
1071
  return { status: "read", path: sourcePath, hash: source.hash };
1072
1072
  }
1073
1073
 
1074
- // Read-only mirror of install-agent-fleet.sh's loadUserManagedReceipt(): this
1074
+ // Read-only mirror of install-profile.ts's readAgentFleetUserManagedReceipt(): this
1075
1075
  // checker never writes ~/.repo-harness/agent-fleet-user-managed.json, it only
1076
1076
  // consults it so an operator-accepted customized file is not misreported as
1077
1077
  // drift. Any malformation invalidates the whole receipt (fail-closed) rather
@@ -337,7 +337,14 @@ function parseList(block: string, key: string): string[] {
337
337
  if (!inList) continue;
338
338
  if (/^\S/.test(line) || /^\s+[a-zA-Z0-9_-]+:/.test(line)) break;
339
339
  const match = line.match(/^\s*-\s*(.+)$/);
340
- if (match) values.push(match[1].trim().replace(/^["']|["']$/g, ""));
340
+ if (!match) continue;
341
+ let value = match[1].trim();
342
+ const quote = value[0];
343
+ const close = quote === '"' || quote === "'" ? value.indexOf(quote, 1) : -1;
344
+ // Drop a YAML inline comment: `#` at the start or after whitespace, outside a leading quoted scalar.
345
+ value = close > 0 ? value.slice(0, close + 1) : value.replace(/(^|\s+)#.*$/, "").trim();
346
+ value = value.replace(/^["']|["']$/g, "");
347
+ if (value.length > 0) values.push(value);
341
348
  }
342
349
  return values;
343
350
  }
@@ -1016,8 +1016,8 @@ ARCHITECTURE_INDEX_EOF
1016
1016
  "provider": "archctx",
1017
1017
  "proposal_author": "local",
1018
1018
  "stages": {
1019
- "scan": { "provider_version": "0.5.13", "required_features": ["module-statistics-v1", "refactor-assessment-v1", "recommendation-v3"] },
1020
- "verify": { "provider_version": "0.5.13", "required_features": ["refactor-resolution-v1"] }
1019
+ "scan": { "provider_version": "0.6.1", "required_features": ["module-statistics-v1", "refactor-assessment-v1", "recommendation-v3"] },
1020
+ "verify": { "provider_version": "0.6.1", "required_features": ["refactor-resolution-v1"] }
1021
1021
  },
1022
1022
  "workflow_routing": {
1023
1023
  "module_refactor": "work_package",
@@ -111,11 +111,16 @@ const MANAGED_AGENTS = ["explorer", "deep-reasoner", "fast-worker", "deep-worker
111
111
  const WRITABLE_AGENTS = new Set(["fast-worker", "deep-worker", "root-cause-prover", "harness-evaluator"]);
112
112
  const CLAUDE_TARGET_DIR = path.join(HOME, ".claude", "agents");
113
113
  const CODEX_TARGET_DIR = path.join(HOME, ".codex", "agents");
114
- const USER_MANAGED_RECEIPT_PATH = path.join(HOME, ".repo-harness", "agent-fleet-user-managed.json");
115
114
  const SOURCE_DIR = process.env.REPO_HARNESS_AGENT_FLEET_SOURCE_DIR;
116
- const { readInstalledProfile, managedInstallSurfaceIsCurrent } = require(
115
+ const {
116
+ readInstalledProfile,
117
+ managedInstallSurfaceIsCurrent,
118
+ agentFleetUserManagedReceiptPath,
119
+ readAgentFleetUserManagedReceipt,
120
+ } = require(
117
121
  path.join(SOURCE_DIR, "../../src/cli/installer/install-profile.ts"),
118
122
  );
123
+ const USER_MANAGED_RECEIPT_PATH = agentFleetUserManagedReceiptPath({ ...process.env, HOME });
119
124
  const installedProfile = readInstalledProfile();
120
125
 
121
126
  // A generated persona carries role identity only. The anti-extras execution
@@ -145,18 +150,20 @@ const MODEL_EFFORT_MAP = {
145
150
  opus: buildFamilyEffortMap("Opus", "gpt-6-astra", "GPT-6 Astra"),
146
151
  sonnet: buildFamilyEffortMap("Sonnet", "gpt-6-luna", "GPT-6 Luna"),
147
152
  haiku: buildFamilyEffortMap("Haiku", "gpt-6-luna", "GPT-6 Luna"),
148
- fable: buildFamilyEffortMap("Fable", "gpt-6-sol", "GPT-6 Sol"),
153
+ fable: buildFamilyEffortMap("Fable", "gpt-6.1-sol", "GPT-6.1 Sol"),
149
154
  };
150
155
 
151
156
  // Per-agent Codex target overrides — the only model/effort remaps in the fleet.
152
- // Execution and diagnostic roles use Sol or Luna; the gatekeeper uses Astra.
153
- // Explorer and deep-reasoner follow the family default.
157
+ // Every role carries an explicit target so Codex model/effort never drift with
158
+ // the Claude-side family default.
154
159
  const AGENT_TARGET_OVERRIDES = {
155
- "fast-worker": { model: "gpt-6-sol", effort: "medium", targetDescription: "GPT-6 Sol at medium reasoning" },
156
- "deep-worker": { model: "gpt-6-sol", effort: "xhigh", targetDescription: "GPT-6 Sol at xhigh reasoning" },
160
+ explorer: { model: "gpt-6-luna", effort: "high", targetDescription: "GPT-6 Luna at high reasoning" },
161
+ "deep-reasoner": { model: "gpt-6-astra", effort: "high", targetDescription: "GPT-6 Astra at high reasoning" },
162
+ "fast-worker": { model: "gpt-6.1-sol", effort: "medium", targetDescription: "GPT-6.1 Sol at medium reasoning" },
163
+ "deep-worker": { model: "gpt-6.1-sol", effort: "high", targetDescription: "GPT-6.1 Sol at high reasoning" },
157
164
  gatekeeper: { model: "gpt-6-astra", effort: "medium", targetDescription: "GPT-6 Astra at medium reasoning" },
158
- "root-cause-prover": { model: "gpt-6-sol", effort: "high", targetDescription: "GPT-6 Sol at high reasoning" },
159
- "harness-evaluator": { model: "gpt-6-sol", effort: "high", targetDescription: "GPT-6 Sol at high reasoning" },
165
+ "root-cause-prover": { model: "gpt-6-astra", effort: "high", targetDescription: "GPT-6 Astra at high reasoning" },
166
+ "harness-evaluator": { model: "gpt-6-astra", effort: "medium", targetDescription: "GPT-6 Astra at medium reasoning" },
160
167
  };
161
168
 
162
169
  function readSource(agent) {
@@ -313,33 +320,6 @@ function validateUserManagedCodex(agent, content) {
313
320
  }
314
321
  }
315
322
 
316
- function loadUserManagedReceipt(allowedPaths) {
317
- if (!fs.existsSync(USER_MANAGED_RECEIPT_PATH)) return { ok: true, hashes: new Map() };
318
- try {
319
- const parsed = JSON.parse(fs.readFileSync(USER_MANAGED_RECEIPT_PATH, "utf8"));
320
- if (
321
- parsed?.protocol !== 1
322
- || parsed?.authority !== "user-managed-agent-fleet"
323
- || !Array.isArray(parsed.files)
324
- ) return { ok: false, hashes: new Map() };
325
- const hashes = new Map();
326
- for (const entry of parsed.files) {
327
- if (
328
- !entry
329
- || typeof entry.path !== "string"
330
- || !allowedPaths.has(entry.path)
331
- || typeof entry.sha256 !== "string"
332
- || !/^sha256:[a-f0-9]{64}$/.test(entry.sha256)
333
- || hashes.has(entry.path)
334
- ) return { ok: false, hashes: new Map() };
335
- hashes.set(entry.path, entry.sha256);
336
- }
337
- return { ok: true, hashes };
338
- } catch (_error) {
339
- return { ok: false, hashes: new Map() };
340
- }
341
- }
342
-
343
323
  function writeUserManagedReceipt(files) {
344
324
  fs.mkdirSync(path.dirname(USER_MANAGED_RECEIPT_PATH), { recursive: true });
345
325
  const receipt = {
@@ -434,8 +414,6 @@ const targets = prepared.flatMap(({ agent, source, parsed, mapped }) => {
434
414
  },
435
415
  ];
436
416
  });
437
- const allowedTargetPaths = new Set(targets.map((target) => target.path));
438
-
439
417
  if (acceptUserManaged) {
440
418
  const acceptedFiles = [];
441
419
  let invalid = false;
@@ -470,7 +448,7 @@ if (acceptUserManaged) {
470
448
 
471
449
  const receipt = force
472
450
  ? { ok: true, hashes: new Map() }
473
- : loadUserManagedReceipt(allowedTargetPaths);
451
+ : readAgentFleetUserManagedReceipt({ ...process.env, HOME });
474
452
  if (!receipt.ok) {
475
453
  console.log("[fleet] user-managed receipt: invalid");
476
454
  process.exit(1);
@@ -190,8 +190,18 @@ contract_allowed_paths() {
190
190
  in_paths && /^[[:space:]]*-[[:space:]]*/ {
191
191
  line = $0
192
192
  sub(/^[[:space:]]*-[[:space:]]*/, "", line)
193
+ # Drop a YAML inline comment: `#` at the start or after whitespace, outside a leading quoted scalar.
194
+ q = substr(line, 1, 1)
195
+ close_at = (q == "\"" || q == "'\''") ? index(substr(line, 2), q) : 0
196
+ if (close_at > 0) {
197
+ line = substr(line, 1, close_at + 1)
198
+ } else {
199
+ sub(/^#.*$/, "", line)
200
+ sub(/[[:space:]]+#.*$/, "", line)
201
+ }
193
202
  gsub(/^["'\''`]+|["'\''`]+$/, "", line)
194
- print trim(line)
203
+ line = trim(line)
204
+ if (line != "") print line
195
205
  }
196
206
  '
197
207
  }
@@ -193,8 +193,18 @@ contract_allowed_paths() {
193
193
  in_paths && /^[[:space:]]*-[[:space:]]*/ {
194
194
  line = $0
195
195
  sub(/^[[:space:]]*-[[:space:]]*/, "", line)
196
+ # Drop a YAML inline comment: `#` at the start or after whitespace, outside a leading quoted scalar.
197
+ q = substr(line, 1, 1)
198
+ close_at = (q == "\"" || q == "'\''") ? index(substr(line, 2), q) : 0
199
+ if (close_at > 0) {
200
+ line = substr(line, 1, close_at + 1)
201
+ } else {
202
+ sub(/^#.*$/, "", line)
203
+ sub(/[[:space:]]+#.*$/, "", line)
204
+ }
196
205
  gsub(/^["'\''`]+|["'\''`]+$/, "", line)
197
- print trim(line)
206
+ line = trim(line)
207
+ if (line != "") print line
198
208
  }
199
209
  '
200
210
  }