@indigoai-us/hq-cli 5.345.78 → 5.345.79
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 +4 -1
- package/dist/lib/doctor/fix/apply.d.ts +6 -3
- package/dist/lib/doctor/fix/apply.js +43 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
-
## [5.345.
|
|
5
|
+
## [5.345.79] — 2026-10-11
|
|
6
6
|
- `hq lanes` no longer fails every list, message, or admission command when
|
|
7
7
|
one lane still has leftover queue details from an older worker-profile wait.
|
|
8
8
|
Those leftover details are dropped on read, cleared when the queue reason
|
|
9
9
|
changes, and one unreadable lane is skipped so the rest of the host stays
|
|
10
10
|
usable.
|
|
11
|
+
- `hq doctor --fix` still refreshes a stale company sync journal when
|
|
12
|
+
`.claude/`, `.codex/`, or `.grok/` has uncommitted changes. Those dirty
|
|
13
|
+
files still block hook-file repairs unless you pass `--force`.
|
|
11
14
|
|
|
12
15
|
## [5.345.77] — 2026-10-10
|
|
13
16
|
- Local bots no longer fail a turn when the installed Codex is too old for the
|
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
* wrapped in guardrails that are NOT polish — each is a PRD acceptance criterion:
|
|
6
6
|
*
|
|
7
7
|
* 1. Dirty-tree refusal. If the working tree has uncommitted changes under
|
|
8
|
-
* `.claude/`, `.codex/`, or `.grok/`, `--fix` refuses
|
|
9
|
-
* unless `--force`, so
|
|
10
|
-
* in-flight edits to the security layer.
|
|
8
|
+
* `.claude/`, `.codex/`, or `.grok/`, `--fix` refuses hook-file repairs
|
|
9
|
+
* and exits non-zero unless `--force`, so those writes can never be
|
|
10
|
+
* tangled up with unrelated in-flight edits to the security layer.
|
|
11
|
+
* Repairs that do not write those trees (a stale-company `refresh-sync`
|
|
12
|
+
* pull) still run: the SessionStart health hook never passes `--force`,
|
|
13
|
+
* and blocking the pull left `sync.journal.<slug>` WARN after `--fix`.
|
|
11
14
|
* 2. Allowlist only. It repairs the classified safe classes — restore an
|
|
12
15
|
* execute bit, add a hook id to the gate profiles it is missing from,
|
|
13
16
|
* re-register a script present on disk, or pull a company whose local
|
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
* wrapped in guardrails that are NOT polish — each is a PRD acceptance criterion:
|
|
6
6
|
*
|
|
7
7
|
* 1. Dirty-tree refusal. If the working tree has uncommitted changes under
|
|
8
|
-
* `.claude/`, `.codex/`, or `.grok/`, `--fix` refuses
|
|
9
|
-
* unless `--force`, so
|
|
10
|
-
* in-flight edits to the security layer.
|
|
8
|
+
* `.claude/`, `.codex/`, or `.grok/`, `--fix` refuses hook-file repairs
|
|
9
|
+
* and exits non-zero unless `--force`, so those writes can never be
|
|
10
|
+
* tangled up with unrelated in-flight edits to the security layer.
|
|
11
|
+
* Repairs that do not write those trees (a stale-company `refresh-sync`
|
|
12
|
+
* pull) still run: the SessionStart health hook never passes `--force`,
|
|
13
|
+
* and blocking the pull left `sync.journal.<slug>` WARN after `--fix`.
|
|
11
14
|
* 2. Allowlist only. It repairs the classified safe classes — restore an
|
|
12
15
|
* execute bit, add a hook id to the gate profiles it is missing from,
|
|
13
16
|
* re-register a script present on disk, or pull a company whose local
|
|
@@ -107,20 +110,34 @@ export async function applyFixes(options) {
|
|
|
107
110
|
...over,
|
|
108
111
|
});
|
|
109
112
|
// 1. Dirty-tree refusal (AC8). Never write over uncommitted security-layer
|
|
110
|
-
// edits unless the user forces it.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
// edits unless the user forces it. Probe once; hook-file plans are
|
|
114
|
+
// dropped per pass so a stale-journal pull can still run.
|
|
115
|
+
const dirty = options.force
|
|
116
|
+
? []
|
|
117
|
+
: (options.dirtyCheck ?? uncommittedHookConfigChanges)(hqRoot);
|
|
118
|
+
const refuseDirtyHookWrites = (plans) => {
|
|
119
|
+
if (dirty.length === 0)
|
|
120
|
+
return plans;
|
|
121
|
+
const allowed = plans.filter((plan) => plan.relpath.length === 0);
|
|
122
|
+
if (allowed.length === plans.length)
|
|
123
|
+
return plans;
|
|
124
|
+
if (allowed.length === 0)
|
|
125
|
+
return "refuse";
|
|
126
|
+
writeErr(`hq doctor --fix: skipping hook-file repairs — uncommitted changes under ` +
|
|
127
|
+
`${HOOK_CONFIG_DIRS.join(", ")}. Refreshing sync journals still runs; ` +
|
|
128
|
+
`re-run with --force to repair hook files.\n`);
|
|
129
|
+
return allowed;
|
|
130
|
+
};
|
|
131
|
+
const refuseDirtyTree = () => {
|
|
132
|
+
writeErr(`hq doctor --fix: refusing to run — uncommitted changes under ` +
|
|
133
|
+
`${HOOK_CONFIG_DIRS.join(", ")}:\n` +
|
|
134
|
+
dirty.map((line) => ` ${line}`).join("\n") +
|
|
135
|
+
`\nCommit or stash them, or re-run with --force.\n`);
|
|
136
|
+
return empty({ exitCode: 1, refused: "dirty-tree" });
|
|
137
|
+
};
|
|
121
138
|
// Resolve the customer-visible manual-only output gate once per fix run.
|
|
122
|
-
//
|
|
123
|
-
//
|
|
139
|
+
// Fail open to the pre-change output if the identity is absent or the
|
|
140
|
+
// registry lookup fails.
|
|
124
141
|
let showManualOnlyRemediations = false;
|
|
125
142
|
try {
|
|
126
143
|
showManualOnlyRemediations =
|
|
@@ -172,7 +189,16 @@ export async function applyFixes(options) {
|
|
|
172
189
|
];
|
|
173
190
|
};
|
|
174
191
|
for (let pass = 1; pass <= MAX_FIX_PASSES; pass += 1) {
|
|
175
|
-
const
|
|
192
|
+
const plannedThisPass = refuseDirtyHookWrites(buildPlans(findings));
|
|
193
|
+
if (plannedThisPass === "refuse") {
|
|
194
|
+
if (planned.length === 0)
|
|
195
|
+
return refuseDirtyTree();
|
|
196
|
+
write(`Pass ${pass}/${MAX_FIX_PASSES}: remaining repairs write hook files; ` +
|
|
197
|
+
`stopped because the tree is dirty.\n`);
|
|
198
|
+
refused = "dirty-tree";
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
const plans = plannedThisPass;
|
|
176
202
|
if (plans.length === 0)
|
|
177
203
|
break;
|
|
178
204
|
fixableCount += plans.length;
|