@axiomatic-labs/claudeflow 2.13.65 → 2.13.66
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/lib/hook-overrides.js +17 -0
- package/lib/panel.js +71 -0
- package/package.json +1 -1
package/lib/hook-overrides.js
CHANGED
|
@@ -57,6 +57,7 @@ function defaultOverrides() {
|
|
|
57
57
|
disabledReminders: [],
|
|
58
58
|
enforcementDisabled: false,
|
|
59
59
|
runToCompletionReminderEnabled: false,
|
|
60
|
+
cwdLockEnabled: false,
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -69,6 +70,7 @@ function readOverrides(projectRoot) {
|
|
|
69
70
|
disabledReminders: Array.isArray(data.disabledReminders) ? data.disabledReminders : [],
|
|
70
71
|
enforcementDisabled: data.enforcementDisabled === true,
|
|
71
72
|
runToCompletionReminderEnabled: data.runToCompletionReminderEnabled === true,
|
|
73
|
+
cwdLockEnabled: data.cwdLockEnabled === true,
|
|
72
74
|
};
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -209,6 +211,20 @@ function toggleRunToCompletionReminder(projectRoot, { enable }) {
|
|
|
209
211
|
return { state: enable ? 'on' : 'off' };
|
|
210
212
|
}
|
|
211
213
|
|
|
214
|
+
// Toggle the cwd-lock hook. Independent of the master enforcement switch —
|
|
215
|
+
// the CwdChanged hook is not in the enforcement-catalog and ignores the
|
|
216
|
+
// master switch by design (you can lock cwd even with enforcement off).
|
|
217
|
+
function toggleCwdLock(projectRoot, { enable }) {
|
|
218
|
+
if (typeof enable !== 'boolean') return { state: 'error', reason: 'enable-required' };
|
|
219
|
+
const overrides = readOverrides(projectRoot);
|
|
220
|
+
if (overrides.cwdLockEnabled === enable) {
|
|
221
|
+
return { state: 'noop', reason: enable ? 'already-on' : 'already-off' };
|
|
222
|
+
}
|
|
223
|
+
overrides.cwdLockEnabled = enable;
|
|
224
|
+
writeOverrides(projectRoot, overrides);
|
|
225
|
+
return { state: enable ? 'on' : 'off' };
|
|
226
|
+
}
|
|
227
|
+
|
|
212
228
|
// Toggle a single reminder by id. Same persistence file, same hot-reload
|
|
213
229
|
// semantics — `reload-reminder.js` re-reads overrides on every invocation.
|
|
214
230
|
function toggleReminderOverride(projectRoot, { id, disable }) {
|
|
@@ -240,6 +256,7 @@ module.exports = {
|
|
|
240
256
|
toggleReminderOverride,
|
|
241
257
|
toggleEnforcementMode,
|
|
242
258
|
toggleRunToCompletionReminder,
|
|
259
|
+
toggleCwdLock,
|
|
243
260
|
normalizeHandlerPath,
|
|
244
261
|
matchesOverride,
|
|
245
262
|
};
|
package/lib/panel.js
CHANGED
|
@@ -30,6 +30,7 @@ const {
|
|
|
30
30
|
toggleReminderOverride,
|
|
31
31
|
toggleEnforcementMode,
|
|
32
32
|
toggleRunToCompletionReminder,
|
|
33
|
+
toggleCwdLock,
|
|
33
34
|
normalizeHandlerPath,
|
|
34
35
|
} = require('./hook-overrides.js');
|
|
35
36
|
|
|
@@ -363,6 +364,14 @@ function getRunToCompletionInfo(cwd) {
|
|
|
363
364
|
};
|
|
364
365
|
}
|
|
365
366
|
|
|
367
|
+
function getCwdLockInfo(cwd) {
|
|
368
|
+
const overrides = readOverrides(cwd);
|
|
369
|
+
return {
|
|
370
|
+
on: overrides.cwdLockEnabled === true,
|
|
371
|
+
handler: 'CwdChanged/lock-cwd.js',
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
366
375
|
function getActivePlanInfo(cwd) {
|
|
367
376
|
const p = path.join(cwd, '.claudeflow', 'state', 'active-plan.json');
|
|
368
377
|
let raw;
|
|
@@ -618,6 +627,7 @@ function collectStatus(cwd) {
|
|
|
618
627
|
reminders: getRemindersInfo(cwd),
|
|
619
628
|
enforcement: getEnforcementInfo(cwd),
|
|
620
629
|
runToCompletion: getRunToCompletionInfo(cwd),
|
|
630
|
+
cwdLock: getCwdLockInfo(cwd),
|
|
621
631
|
observer: getObserverInfo(cwd),
|
|
622
632
|
activePlan: getActivePlanInfo(cwd),
|
|
623
633
|
logs: getLogsInfo(cwd),
|
|
@@ -800,6 +810,11 @@ details[open] summary { padding-bottom: 8px; border-bottom: 1px solid var(--bord
|
|
|
800
810
|
<label class="enforce-switch"><input type="checkbox" id="run-to-completion-toggle" /><span class="enforce-slider"></span></label>
|
|
801
811
|
<span class="enforce-state" id="run-to-completion-state">…</span>
|
|
802
812
|
</span>
|
|
813
|
+
<span class="enforce-pill" id="cwd-lock-pill" title="Hard block — fires on Claude Code CwdChanged event. When the agent runs cd Subdir + cmd and the cwd would persist away from the project root, the change is blocked with a guidance message. Use (cd Subdir + cmd) subshells or absolute paths instead.">
|
|
814
|
+
<span class="enforce-label">Lock cwd</span>
|
|
815
|
+
<label class="enforce-switch"><input type="checkbox" id="cwd-lock-toggle" /><span class="enforce-slider"></span></label>
|
|
816
|
+
<span class="enforce-state" id="cwd-lock-state">…</span>
|
|
817
|
+
</span>
|
|
803
818
|
<label class="toggle"><input type="checkbox" id="auto" checked /> auto-refresh 5s</label>
|
|
804
819
|
<button id="refresh">Refresh</button>
|
|
805
820
|
</span>
|
|
@@ -936,6 +951,20 @@ function renderHeader() {
|
|
|
936
951
|
} else if (rtcPill) {
|
|
937
952
|
rtcPill.style.display = 'none';
|
|
938
953
|
}
|
|
954
|
+
const lock = state.cwdLock;
|
|
955
|
+
const lockPill = document.getElementById('cwd-lock-pill');
|
|
956
|
+
const lockCb = document.getElementById('cwd-lock-toggle');
|
|
957
|
+
const lockLbl = document.getElementById('cwd-lock-state');
|
|
958
|
+
if (lock && lockPill) {
|
|
959
|
+
lockPill.dataset.state = lock.on ? 'on' : 'off';
|
|
960
|
+
lockCb.checked = lock.on;
|
|
961
|
+
lockLbl.textContent = lock.on ? 'ON' : 'OFF';
|
|
962
|
+
lockPill.title = lock.on
|
|
963
|
+
? 'Lock cwd is ON — any persistent change of working directory away from the project root is blocked via the CwdChanged hook. Use (cd Subdir + cmd) subshells or absolute paths.'
|
|
964
|
+
: 'Lock cwd is OFF — the agent can cd into subdirectories and the cwd will persist across tool calls. Click to enforce a single project-root cwd.';
|
|
965
|
+
} else if (lockPill) {
|
|
966
|
+
lockPill.style.display = 'none';
|
|
967
|
+
}
|
|
939
968
|
}
|
|
940
969
|
|
|
941
970
|
function severityFor(id) {
|
|
@@ -1872,6 +1901,34 @@ document.getElementById('run-to-completion-toggle').onchange = (e) => {
|
|
|
1872
1901
|
toggleRunToCompletion(e.target.checked);
|
|
1873
1902
|
};
|
|
1874
1903
|
|
|
1904
|
+
async function toggleCwdLockUI(enable) {
|
|
1905
|
+
try {
|
|
1906
|
+
const r = await fetch('/api/cwd-lock/toggle', {
|
|
1907
|
+
method: 'POST',
|
|
1908
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1909
|
+
body: JSON.stringify({ enable }),
|
|
1910
|
+
});
|
|
1911
|
+
const result = await r.json();
|
|
1912
|
+
if (!r.ok || result.state === 'error') {
|
|
1913
|
+
showToast('Toggle failed: ' + (result.reason || result.error || 'unknown'), 'err');
|
|
1914
|
+
} else if (result.state === 'noop') {
|
|
1915
|
+
showToast('Cwd lock already in target state', 'ok');
|
|
1916
|
+
} else {
|
|
1917
|
+
showToast(enable
|
|
1918
|
+
? 'Cwd lock ON — cd away from project root will be BLOCKED on next CwdChanged.'
|
|
1919
|
+
: 'Cwd lock OFF — agent can freely change directory.',
|
|
1920
|
+
'ok');
|
|
1921
|
+
}
|
|
1922
|
+
} catch (e) {
|
|
1923
|
+
showToast('Network error: ' + e.message, 'err');
|
|
1924
|
+
}
|
|
1925
|
+
await refresh();
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
document.getElementById('cwd-lock-toggle').onchange = (e) => {
|
|
1929
|
+
toggleCwdLockUI(e.target.checked);
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1875
1932
|
document.getElementById('refresh').onclick = refresh;
|
|
1876
1933
|
document.getElementById('auto').onchange = (e) => {
|
|
1877
1934
|
if (timer) clearInterval(timer);
|
|
@@ -1981,6 +2038,20 @@ function handler(cwd) {
|
|
|
1981
2038
|
return send(status, JSON.stringify(result), 'application/json');
|
|
1982
2039
|
}
|
|
1983
2040
|
|
|
2041
|
+
if (req.method === 'POST' && route === '/api/cwd-lock/toggle') {
|
|
2042
|
+
const raw = await readRequestBody(req);
|
|
2043
|
+
let payload;
|
|
2044
|
+
try { payload = JSON.parse(raw); }
|
|
2045
|
+
catch { return send(400, JSON.stringify({ error: 'invalid json' }), 'application/json'); }
|
|
2046
|
+
const { enable } = payload;
|
|
2047
|
+
if (typeof enable !== 'boolean') {
|
|
2048
|
+
return send(400, JSON.stringify({ error: 'enable required' }), 'application/json');
|
|
2049
|
+
}
|
|
2050
|
+
const result = toggleCwdLock(cwd, { enable });
|
|
2051
|
+
const status = result.state === 'error' ? 500 : 200;
|
|
2052
|
+
return send(status, JSON.stringify(result), 'application/json');
|
|
2053
|
+
}
|
|
2054
|
+
|
|
1984
2055
|
if (req.method === 'POST' && route === '/api/run-to-completion/toggle') {
|
|
1985
2056
|
const raw = await readRequestBody(req);
|
|
1986
2057
|
let payload;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axiomatic-labs/claudeflow",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.66",
|
|
4
4
|
"description": "Claudeflow — AI-powered development toolkit for Claude Code. Skills, agents, hooks, and quality gates that ship production apps.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claudeflow": "./bin/cli.js"
|