@brainervirus/workit-cli 8.39.4 → 8.40.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/dist/index.js +122 -10
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -9317,7 +9317,7 @@ var package_default;
|
|
|
9317
9317
|
var init_package = __esm(() => {
|
|
9318
9318
|
package_default = {
|
|
9319
9319
|
name: "@brainervirus/workit-cli",
|
|
9320
|
-
version: "8.
|
|
9320
|
+
version: "8.40.0",
|
|
9321
9321
|
private: false,
|
|
9322
9322
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
9323
9323
|
keywords: [
|
|
@@ -9355,13 +9355,13 @@ var init_package = __esm(() => {
|
|
|
9355
9355
|
},
|
|
9356
9356
|
dependencies: {
|
|
9357
9357
|
"@babel/parser": "7.29.9",
|
|
9358
|
-
"@brainervirus/workit-cursor": "^8.
|
|
9358
|
+
"@brainervirus/workit-cursor": "^8.40.0",
|
|
9359
9359
|
"@inkjs/ui": "2.0.0",
|
|
9360
9360
|
ink: "7.1.1",
|
|
9361
9361
|
react: "19.2.8"
|
|
9362
9362
|
},
|
|
9363
9363
|
devDependencies: {
|
|
9364
|
-
"@brainervirus/workit-core": "^8.
|
|
9364
|
+
"@brainervirus/workit-core": "^8.40.0"
|
|
9365
9365
|
},
|
|
9366
9366
|
engines: {
|
|
9367
9367
|
node: ">=24"
|
|
@@ -77034,6 +77034,7 @@ var init_uninstall2 = __esm(() => {
|
|
|
77034
77034
|
// packages/workit-cli/src/verbs/grant.ts
|
|
77035
77035
|
var exports_grant = {};
|
|
77036
77036
|
__export(exports_grant, {
|
|
77037
|
+
agentMarker: () => agentMarker,
|
|
77037
77038
|
run: () => run10,
|
|
77038
77039
|
runGrant: () => runGrant
|
|
77039
77040
|
});
|
|
@@ -77372,7 +77373,90 @@ function set2(argv, io) {
|
|
|
77372
77373
|
`${name}: ${changes.map((change) => change.path.join(".")).join(", ")} updated in ${written(data.path, data.backup)}`
|
|
77373
77374
|
]);
|
|
77374
77375
|
}
|
|
77375
|
-
async function
|
|
77376
|
+
async function rm(argv, io, deps) {
|
|
77377
|
+
const [name, extra] = argv;
|
|
77378
|
+
if (!name)
|
|
77379
|
+
return usage3(io, "rm needs <name>");
|
|
77380
|
+
if (extra)
|
|
77381
|
+
return usage3(io, `unexpected argument ${extra}`);
|
|
77382
|
+
const current = load(io);
|
|
77383
|
+
if (typeof current === "number")
|
|
77384
|
+
return current;
|
|
77385
|
+
const entries = entriesOf(current);
|
|
77386
|
+
const removed = entries.find((entry) => entry.name === name);
|
|
77387
|
+
if (!removed)
|
|
77388
|
+
return emit(io, fail2("not_found", `no workspace named "${name}" in ${current.path}`));
|
|
77389
|
+
const remaining = entries.filter((entry) => entry !== removed);
|
|
77390
|
+
if (remaining.length === 0)
|
|
77391
|
+
return emit(io, fail2("blocked", `"${name}" is the last workspace in ${current.path}: it holds your vcs, policies and grants, and without it every folder falls back to the defaults; workspace rm does not remove it`, {
|
|
77392
|
+
unblock: `add the workspace that should replace it first (workit workspace add <name> --glob <g> --from ${name}), or edit ${current.path} in your own editor`
|
|
77393
|
+
}));
|
|
77394
|
+
const before = deliveredCeilingOf(removed);
|
|
77395
|
+
const defaults = ceilingOf({});
|
|
77396
|
+
const nothing = {
|
|
77397
|
+
grants: Object.fromEntries(GRANT_KINDS.map((kind) => [kind, false])),
|
|
77398
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
77399
|
+
verification: STRICTNESS[0]
|
|
77400
|
+
};
|
|
77401
|
+
const specificity = globSpecificity(removed.glob);
|
|
77402
|
+
const raised = [
|
|
77403
|
+
{ taker: "defaults", kinds: raisedKinds(before, defaults), reason: "no entry matches" },
|
|
77404
|
+
...remaining.map((entry) => ({
|
|
77405
|
+
taker: entry.name,
|
|
77406
|
+
kinds: raisedKinds(before, ceilingOf(entry)),
|
|
77407
|
+
reason: "may match a folder it covered"
|
|
77408
|
+
})),
|
|
77409
|
+
...remaining.filter((entry) => globSpecificity(entry.glob) === specificity).map((entry) => ({
|
|
77410
|
+
taker: entry.name,
|
|
77411
|
+
kinds: raisedKinds(nothing, ceilingOf(entry)),
|
|
77412
|
+
reason: "equally specific: a folder both matched was ambiguous, with nothing granted"
|
|
77413
|
+
}))
|
|
77414
|
+
].filter((raise) => raise.kinds.length > 0);
|
|
77415
|
+
if (raised.length > 0) {
|
|
77416
|
+
const kinds = [...new Set(raised.flatMap((raise) => raise.kinds))];
|
|
77417
|
+
const detail = raised.map((raise) => `${raise.taker} (${raise.reason}): ${raise.kinds.join(", ")}`).join("; ");
|
|
77418
|
+
const agent = agentMarker(io.env);
|
|
77419
|
+
if (!deps.interactive() || agent)
|
|
77420
|
+
return emit(io, fail2("blocked", `grant_raise_refused: removing "${name}" may raise ${kinds.join(", ")} for the folders it covered (${detail}); that needs the user at an interactive terminal${agent ? ` (this shell belongs to an agent: ${agent} is set)` : ""}; grants are never raised headless`, {
|
|
77421
|
+
unblock: `ask the user to run, in a terminal outside the agent host (not Claude Code's \`!\` prefix or an agent shell): workit workspace rm ${name}`
|
|
77422
|
+
}));
|
|
77423
|
+
const answer = await askOrCancel(io, () => deps.ask(`Removing workspace "${name}" may raise ${kinds.join(", ")} for the folders it covered (${detail}). An agent there may then do more without asking. Type the workspace name to confirm: `));
|
|
77424
|
+
if (answer === null)
|
|
77425
|
+
return cancelled(io);
|
|
77426
|
+
if (answer.trim() !== name)
|
|
77427
|
+
return emit(io, fail2("blocked", "workspace removal not confirmed; nothing was written"));
|
|
77428
|
+
}
|
|
77429
|
+
const result = save(current, remaining);
|
|
77430
|
+
if (!result.ok)
|
|
77431
|
+
return emit(io, fail2("invalid_input", result.error));
|
|
77432
|
+
const at = globRoot(removed.glob);
|
|
77433
|
+
let covers;
|
|
77434
|
+
try {
|
|
77435
|
+
covers = { at, workspace: resolveWorkspaceFromEntries(at, remaining)?.name ?? null };
|
|
77436
|
+
} catch (error) {
|
|
77437
|
+
covers = { at, workspace: null, error: error instanceof Error ? error.message : String(error) };
|
|
77438
|
+
}
|
|
77439
|
+
const coveringCeiling = ceilingOf(remaining.find((entry) => entry.name === covers.workspace));
|
|
77440
|
+
return emit(io, ok2({
|
|
77441
|
+
path: result.path,
|
|
77442
|
+
backup: result.backup,
|
|
77443
|
+
removed,
|
|
77444
|
+
covers: {
|
|
77445
|
+
...covers,
|
|
77446
|
+
grants: coveringCeiling.grants,
|
|
77447
|
+
defaultEndpoint: coveringCeiling.endpoint,
|
|
77448
|
+
verification: coveringCeiling.verification
|
|
77449
|
+
},
|
|
77450
|
+
takers: overlappingEntries(removed.glob, remaining).map((entry) => entry.name),
|
|
77451
|
+
raises: raised
|
|
77452
|
+
}), (data) => [
|
|
77453
|
+
`${name} (${removed.glob}) removed from ${written(data.path, data.backup)}`,
|
|
77454
|
+
data.covers.error ? ` ${data.covers.at}: ${data.covers.error}` : ` ${data.covers.at} is now ${data.covers.workspace ? `workspace ${data.covers.workspace}` : "under the defaults (no workspace)"}: ${GRANT_KINDS.map((kind) => `${kind}=${String(data.covers.grants[kind])}`).join(" ")}; default endpoint ${data.covers.defaultEndpoint}; verification ${data.covers.verification}`,
|
|
77455
|
+
...data.takers.length ? [` entries whose globs may cover its other folders: ${data.takers.join(", ")}`] : [],
|
|
77456
|
+
" workit workspace list --cwd <folder> shows which entry applies to a folder"
|
|
77457
|
+
]);
|
|
77458
|
+
}
|
|
77459
|
+
async function runWorkspace(argv, io, deps = defaultDeps2) {
|
|
77376
77460
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json" && arg !== "--");
|
|
77377
77461
|
if (sub === undefined || sub === "list")
|
|
77378
77462
|
return list2(rest, io);
|
|
@@ -77380,13 +77464,25 @@ async function runWorkspace(argv, io) {
|
|
|
77380
77464
|
return add2(rest, io);
|
|
77381
77465
|
if (sub === "set")
|
|
77382
77466
|
return set2(rest, io);
|
|
77467
|
+
if (sub === "rm")
|
|
77468
|
+
return rm(rest, io, deps);
|
|
77383
77469
|
return usage3(io, `unknown subcommand "${sub}"`);
|
|
77384
77470
|
}
|
|
77385
|
-
var USAGE5 = "workit workspace list | workspace add <name> --glob <g> [--from <parent>] | workspace set <name> <key>=<value>…", INHERITED_KEYS, GRANT_KEYS, SCOPE_KEYS, SETTABLE_KEYS, SEGMENT, UNSAFE_SEGMENTS, ceilingOf = (entry) => ({
|
|
77471
|
+
var USAGE5 = "workit workspace list | workspace add <name> --glob <g> [--from <parent>] | workspace set <name> <key>=<value>… | workspace rm <name>", INHERITED_KEYS, GRANT_KEYS, SCOPE_KEYS, SETTABLE_KEYS, SEGMENT, UNSAFE_SEGMENTS, ceilingOf = (entry) => ({
|
|
77386
77472
|
grants: { ...DEFAULT_GRANTS, ...configuredGrants(entry).grants },
|
|
77387
77473
|
endpoint: isDefaultEndpoint(entry?.defaultEndpoint) ? entry.defaultEndpoint : DEFAULT_ENDPOINT,
|
|
77388
77474
|
verification: verificationOf(entry)
|
|
77389
|
-
}),
|
|
77475
|
+
}), deliveredCeilingOf = (entry) => {
|
|
77476
|
+
const ceiling = ceilingOf(entry);
|
|
77477
|
+
const account = entry.vcs?.account;
|
|
77478
|
+
if (Object.keys(configuredGrants(entry).grants).length === 0 || account)
|
|
77479
|
+
return ceiling;
|
|
77480
|
+
return {
|
|
77481
|
+
grants: Object.fromEntries(GRANT_KINDS.map((kind) => [kind, false])),
|
|
77482
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
77483
|
+
verification: ceiling.verification
|
|
77484
|
+
};
|
|
77485
|
+
}, STRICTNESS, looser = (current, next) => STRICTNESS.indexOf(next) > STRICTNESS.indexOf(current), shadowedCeiling = (shadowed) => {
|
|
77390
77486
|
if (shadowed.length === 0)
|
|
77391
77487
|
return null;
|
|
77392
77488
|
const ceilings = shadowed.map(ceilingOf);
|
|
@@ -77406,7 +77502,11 @@ var USAGE5 = "workit workspace list | workspace add <name> --glob <g> [--from <p
|
|
|
77406
77502
|
...Object.keys(autonomy).length ? { autonomy } : {},
|
|
77407
77503
|
...looser(shadowed.verification, DEFAULT_VERIFICATION) ? { verification: shadowed.verification } : {}
|
|
77408
77504
|
};
|
|
77409
|
-
},
|
|
77505
|
+
}, defaultDeps2, raisedKinds = (before, after) => [
|
|
77506
|
+
...GRANT_KINDS.filter((kind) => raises(kind, before.grants[kind], after.grants[kind])),
|
|
77507
|
+
...raisesEndpoint(before.endpoint, after.endpoint) ? ["defaultEndpoint"] : [],
|
|
77508
|
+
...looser(before.verification, after.verification) ? ["verification"] : []
|
|
77509
|
+
], usage3 = (io, message) => emit(io, fail2("invalid_input", `${message}
|
|
77410
77510
|
usage: ${USAGE5}`)), load = (io) => {
|
|
77411
77511
|
const current = readWorkspacesResult();
|
|
77412
77512
|
if (current.status === "malformed" || current.status === "invalid")
|
|
@@ -77455,6 +77555,8 @@ var init_workspace = __esm(() => {
|
|
|
77455
77555
|
init_safe_write();
|
|
77456
77556
|
init_workspaces();
|
|
77457
77557
|
init_output();
|
|
77558
|
+
init_prompt();
|
|
77559
|
+
init_grant();
|
|
77458
77560
|
INHERITED_KEYS = [
|
|
77459
77561
|
"vcs",
|
|
77460
77562
|
"issues",
|
|
@@ -77486,6 +77588,10 @@ var init_workspace = __esm(() => {
|
|
|
77486
77588
|
SEGMENT = /^[A-Za-z0-9_-]+$/u;
|
|
77487
77589
|
UNSAFE_SEGMENTS = new Set(["__proto__", "constructor", "prototype"]);
|
|
77488
77590
|
STRICTNESS = ["independent", "self", "proportional"];
|
|
77591
|
+
defaultDeps2 = {
|
|
77592
|
+
interactive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
|
|
77593
|
+
ask: (question) => askLine(question)
|
|
77594
|
+
};
|
|
77489
77595
|
});
|
|
77490
77596
|
|
|
77491
77597
|
// packages/workit-core/src/core/heavy-rules.ts
|
|
@@ -107882,7 +107988,7 @@ var VERBS = [
|
|
|
107882
107988
|
withSubcommands({
|
|
107883
107989
|
name: "workspace",
|
|
107884
107990
|
group: "setup",
|
|
107885
|
-
summary: "Edit workspace entries without the wizard;
|
|
107991
|
+
summary: "Edit workspace entries without the wizard; a raise (rm included) needs the user at a terminal",
|
|
107886
107992
|
subcommands: [
|
|
107887
107993
|
{
|
|
107888
107994
|
name: "list",
|
|
@@ -107898,15 +108004,21 @@ var VERBS = [
|
|
|
107898
108004
|
name: "set",
|
|
107899
108005
|
usage: "workit workspace set <name> <key>=<value>…",
|
|
107900
108006
|
summary: "Change non-grant keys (dotted paths, JSON values, null removes); grants stay with workit grant set"
|
|
108007
|
+
},
|
|
108008
|
+
{
|
|
108009
|
+
name: "rm",
|
|
108010
|
+
usage: "workit workspace rm <name>",
|
|
108011
|
+
summary: "Remove an entry; if another entry or the defaults could grant its folders more, the user confirms at their own terminal"
|
|
107901
108012
|
}
|
|
107902
108013
|
],
|
|
107903
108014
|
examples: [
|
|
107904
108015
|
"workit workspace list",
|
|
107905
108016
|
"workit workspace add kit --glob '/home/me/work/libs/kit/**' --from work",
|
|
107906
|
-
"workit workspace set kit branchPolicy.integration=merge"
|
|
108017
|
+
"workit workspace set kit branchPolicy.integration=merge",
|
|
108018
|
+
"workit workspace rm kit"
|
|
107907
108019
|
],
|
|
107908
108020
|
notes: [
|
|
107909
|
-
"A new entry starts with no grants of its own. It starts at the strictest level of every entry and the defaults, so its folders never get more than they had.
|
|
108021
|
+
"A new entry starts with no grants of its own. It starts at the strictest level of every entry and the defaults, so its folders never get more than they had. rm counts every other entry and the defaults as a possible taker of the removed folders: when any could grant more, it is refused in an agent or headless shell and the user types the name to confirm at their own terminal; it never removes the last entry. Raising a grant, defaultEndpoint or verification needs the user: workit grant set <name> <kind>=<value> in their own terminal.",
|
|
107910
108022
|
"Every write keeps the previous file as workspaces.json.bak. `workit doctor` lists overlapping globs and which entry wins."
|
|
107911
108023
|
],
|
|
107912
108024
|
load: () => Promise.resolve().then(() => (init_workspace(), exports_workspace))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.40.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
6
6
|
"keywords": [
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@babel/parser": "7.29.9",
|
|
41
|
-
"@brainervirus/workit-cursor": "^8.
|
|
41
|
+
"@brainervirus/workit-cursor": "^8.40.0",
|
|
42
42
|
"@inkjs/ui": "2.0.0",
|
|
43
43
|
"ink": "7.1.1",
|
|
44
44
|
"react": "19.2.8"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@brainervirus/workit-core": "^8.
|
|
47
|
+
"@brainervirus/workit-core": "^8.40.0"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=24"
|