@imdeadpool/guardex 7.0.41 → 7.0.43
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 +68 -13
- package/package.json +2 -1
- package/skills/gitguardex/SKILL.md +13 -0
- package/skills/guardex-merge-skills-to-dev/SKILL.md +59 -0
- package/src/agents/cleanup-sessions.js +126 -0
- package/src/agents/detect.js +160 -0
- package/src/agents/finish.js +172 -0
- package/src/agents/inspect.js +189 -0
- package/src/agents/launch.js +240 -0
- package/src/agents/registry.js +133 -0
- package/src/agents/selection-panel.js +571 -0
- package/src/agents/sessions.js +151 -0
- package/src/agents/start.js +591 -0
- package/src/agents/status.js +143 -0
- package/src/agents/terminal.js +152 -0
- package/src/budget/index.js +343 -0
- package/src/ci-init/index.js +265 -0
- package/src/cli/args.js +305 -1
- package/src/cli/main.js +262 -132
- package/src/cockpit/action-runner.js +3 -0
- package/src/cockpit/actions.js +80 -0
- package/src/cockpit/control.js +1121 -0
- package/src/cockpit/index.js +426 -0
- package/src/cockpit/keybindings.js +224 -0
- package/src/cockpit/kitty-layout.js +549 -0
- package/src/cockpit/kitty-tree.js +144 -0
- package/src/cockpit/layout.js +224 -0
- package/src/cockpit/logs-reader.js +182 -0
- package/src/cockpit/menu.js +204 -0
- package/src/cockpit/pane-actions.js +597 -0
- package/src/cockpit/pane-menu.js +387 -0
- package/src/cockpit/projects-finder.js +178 -0
- package/src/cockpit/render.js +215 -0
- package/src/cockpit/settings-render.js +128 -0
- package/src/cockpit/settings.js +124 -0
- package/src/cockpit/shortcuts.js +24 -0
- package/src/cockpit/sidebar.js +311 -0
- package/src/cockpit/state.js +72 -0
- package/src/cockpit/theme.js +128 -0
- package/src/cockpit/welcome.js +266 -0
- package/src/context.js +76 -33
- package/src/doctor/index.js +3 -2
- package/src/finish/index.js +39 -2
- package/src/git/index.js +65 -0
- package/src/kitty/command.js +101 -0
- package/src/kitty/runtime.js +250 -0
- package/src/output/index.js +1 -1
- package/src/pr-review.js +241 -0
- package/src/scaffold/index.js +19 -0
- package/src/submodule/index.js +288 -0
- package/src/terminal/index.js +120 -0
- package/src/terminal/kitty.js +622 -0
- package/src/terminal/tmux.js +126 -0
- package/src/tmux/command.js +27 -0
- package/src/tmux/session.js +89 -0
- package/templates/AGENTS.multiagent-safety.md +27 -1
- package/templates/codex/skills/gitguardex/SKILL.md +2 -0
- package/templates/githooks/pre-commit +22 -1
- package/templates/github/workflows/README.md +87 -0
- package/templates/github/workflows/ci-full.yml +55 -0
- package/templates/github/workflows/ci.yml +56 -0
- package/templates/github/workflows/cr.yml +20 -1
- package/templates/scripts/agent-branch-finish.sh +544 -26
- package/templates/scripts/agent-branch-start.sh +89 -22
- package/templates/scripts/agent-preflight.sh +89 -0
- package/templates/scripts/agent-worktree-prune.sh +96 -5
- package/templates/scripts/codex-agent.sh +41 -6
- package/templates/scripts/openspec/init-plan-workspace.sh +43 -0
- package/templates/scripts/review-bot-watch.sh +31 -2
- package/templates/scripts/agent-session-state.js +0 -171
- package/templates/scripts/install-vscode-active-agents-extension.js +0 -135
- package/templates/vscode/guardex-active-agents/README.md +0 -34
- package/templates/vscode/guardex-active-agents/extension.js +0 -3782
- package/templates/vscode/guardex-active-agents/fileicons/gitguardex-fileicons.json +0 -54
- package/templates/vscode/guardex-active-agents/fileicons/icons/agent.svg +0 -5
- package/templates/vscode/guardex-active-agents/fileicons/icons/branch.svg +0 -7
- package/templates/vscode/guardex-active-agents/fileicons/icons/config.svg +0 -4
- package/templates/vscode/guardex-active-agents/fileicons/icons/hook.svg +0 -4
- package/templates/vscode/guardex-active-agents/fileicons/icons/openspec.svg +0 -5
- package/templates/vscode/guardex-active-agents/fileicons/icons/plan.svg +0 -4
- package/templates/vscode/guardex-active-agents/fileicons/icons/spec.svg +0 -5
- package/templates/vscode/guardex-active-agents/icon.png +0 -0
- package/templates/vscode/guardex-active-agents/media/active-agents-hivemind.svg +0 -14
- package/templates/vscode/guardex-active-agents/package.json +0 -169
- package/templates/vscode/guardex-active-agents/session-schema.js +0 -1348
package/src/cli/main.js
CHANGED
|
@@ -5,7 +5,17 @@ const sandboxModule = require('../sandbox');
|
|
|
5
5
|
const toolchainModule = require('../toolchain');
|
|
6
6
|
const finishCommands = require('../finish');
|
|
7
7
|
const doctorModule = require('../doctor');
|
|
8
|
+
const submoduleModule = require('../submodule');
|
|
9
|
+
const agentInspect = require('../agents/inspect');
|
|
10
|
+
const agentStatus = require('../agents/status');
|
|
11
|
+
const agentCleanupSessions = require('../agents/cleanup-sessions');
|
|
12
|
+
const { finishAgentSession } = require('../agents/finish');
|
|
8
13
|
const sessionSeverityReport = require('../report/session-severity');
|
|
14
|
+
const budgetModule = require('../budget');
|
|
15
|
+
const ciInitModule = require('../ci-init');
|
|
16
|
+
const cockpitModule = require('../cockpit');
|
|
17
|
+
const agentsStart = require('../agents/start');
|
|
18
|
+
const prReviewModule = require('../pr-review');
|
|
9
19
|
const {
|
|
10
20
|
fs,
|
|
11
21
|
path,
|
|
@@ -83,6 +93,7 @@ const {
|
|
|
83
93
|
readConfiguredProtectedBranches,
|
|
84
94
|
readProtectedBranches,
|
|
85
95
|
ensureSetupProtectedBranches,
|
|
96
|
+
ensureSubmoduleAutoSync,
|
|
86
97
|
writeProtectedBranches,
|
|
87
98
|
readGitConfig,
|
|
88
99
|
resolveBaseBranch,
|
|
@@ -127,6 +138,7 @@ const {
|
|
|
127
138
|
parseDoctorArgs,
|
|
128
139
|
parseTargetFlag,
|
|
129
140
|
parseReviewArgs,
|
|
141
|
+
parsePrReviewArgs,
|
|
130
142
|
parseAgentsArgs,
|
|
131
143
|
parseReportArgs,
|
|
132
144
|
parseSyncArgs,
|
|
@@ -177,6 +189,7 @@ const {
|
|
|
177
189
|
installUserLevelAsset,
|
|
178
190
|
removeLegacyManagedRepoFile,
|
|
179
191
|
ensureAgentsSnippet,
|
|
192
|
+
ensureClaudeAgentsLink,
|
|
180
193
|
ensureManagedGitignore,
|
|
181
194
|
buildRepoVscodeSettings,
|
|
182
195
|
ensureRepoVscodeSettings,
|
|
@@ -377,6 +390,9 @@ function runSetupBootstrapInternal(options) {
|
|
|
377
390
|
installPayload.operations.push(
|
|
378
391
|
ensureSetupProtectedBranches(installPayload.repoRoot, Boolean(options.dryRun)),
|
|
379
392
|
);
|
|
393
|
+
installPayload.operations.push(
|
|
394
|
+
...ensureSubmoduleAutoSync(installPayload.repoRoot, Boolean(options.dryRun)),
|
|
395
|
+
);
|
|
380
396
|
|
|
381
397
|
let parentWorkspace = null;
|
|
382
398
|
if (options.parentWorkspaceView) {
|
|
@@ -880,6 +896,17 @@ function isInteractiveTerminal() {
|
|
|
880
896
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
881
897
|
}
|
|
882
898
|
|
|
899
|
+
function legacyDefaultStatusEnabled() {
|
|
900
|
+
return envFlagIsTruthy(process.env.GUARDEX_LEGACY_STATUS);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function defaultCockpitDisabled() {
|
|
904
|
+
const raw = process.env.GUARDEX_DEFAULT_COCKPIT;
|
|
905
|
+
if (raw == null) return false;
|
|
906
|
+
const normalized = String(raw).trim().toLowerCase();
|
|
907
|
+
return ['0', 'false', 'no', 'off'].includes(normalized);
|
|
908
|
+
}
|
|
909
|
+
|
|
883
910
|
function parseAutoApproval(name) {
|
|
884
911
|
const raw = process.env[name];
|
|
885
912
|
if (raw == null) return null;
|
|
@@ -1241,84 +1268,6 @@ function promptYesNoStrict(question) {
|
|
|
1241
1268
|
}
|
|
1242
1269
|
}
|
|
1243
1270
|
|
|
1244
|
-
const VSCODE_EXTENSION_ID = 'Recodee.gitguardex-active-agents';
|
|
1245
|
-
const VSCODE_EXTENSION_DISPLAY_NAME = 'GitGuardex Active Agents';
|
|
1246
|
-
|
|
1247
|
-
function maybePromptInstallVscodeExtension(options) {
|
|
1248
|
-
if (options.dryRun) {
|
|
1249
|
-
console.log(
|
|
1250
|
-
`[${TOOL_NAME}] (dry-run) Would offer to install VS Code extension '${VSCODE_EXTENSION_ID}'.`,
|
|
1251
|
-
);
|
|
1252
|
-
return;
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
if (envFlagIsTruthy(process.env.GUARDEX_SKIP_VSCODE_EXT_PROMPT)) {
|
|
1256
|
-
return;
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
const codeProbe = cp.spawnSync('code', ['--version'], { stdio: 'ignore' });
|
|
1260
|
-
if (codeProbe.error || codeProbe.status !== 0) {
|
|
1261
|
-
return;
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
const listProbe = cp.spawnSync('code', ['--list-extensions'], {
|
|
1265
|
-
encoding: 'utf8',
|
|
1266
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
1267
|
-
});
|
|
1268
|
-
if (!listProbe.error && listProbe.status === 0) {
|
|
1269
|
-
const alreadyInstalled = String(listProbe.stdout || '')
|
|
1270
|
-
.split('\n')
|
|
1271
|
-
.some((line) => line.trim().toLowerCase() === VSCODE_EXTENSION_ID.toLowerCase());
|
|
1272
|
-
if (alreadyInstalled) {
|
|
1273
|
-
console.log(
|
|
1274
|
-
`[${TOOL_NAME}] ✅ VS Code extension '${VSCODE_EXTENSION_ID}' already installed.`,
|
|
1275
|
-
);
|
|
1276
|
-
return;
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
let approved;
|
|
1281
|
-
if (options.yesGlobalInstall) {
|
|
1282
|
-
approved = true;
|
|
1283
|
-
} else if (options.noGlobalInstall) {
|
|
1284
|
-
approved = false;
|
|
1285
|
-
} else if (!isInteractiveTerminal()) {
|
|
1286
|
-
console.log(
|
|
1287
|
-
`[${TOOL_NAME}] Optional VS Code extension '${VSCODE_EXTENSION_ID}' ` +
|
|
1288
|
-
`(${VSCODE_EXTENSION_DISPLAY_NAME}) not installed. ` +
|
|
1289
|
-
`Install later: code --install-extension ${VSCODE_EXTENSION_ID}`,
|
|
1290
|
-
);
|
|
1291
|
-
return;
|
|
1292
|
-
} else {
|
|
1293
|
-
approved = promptYesNoStrict(
|
|
1294
|
-
`Install VS Code extension '${VSCODE_EXTENSION_ID}' (${VSCODE_EXTENSION_DISPLAY_NAME}) now?`,
|
|
1295
|
-
);
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
if (!approved) {
|
|
1299
|
-
console.log(
|
|
1300
|
-
`[${TOOL_NAME}] ⚠️ VS Code extension skipped. ` +
|
|
1301
|
-
`Set GUARDEX_SKIP_VSCODE_EXT_PROMPT=1 to silence or run 'code --install-extension ${VSCODE_EXTENSION_ID}' later.`,
|
|
1302
|
-
);
|
|
1303
|
-
return;
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
const install = cp.spawnSync('code', ['--install-extension', VSCODE_EXTENSION_ID], {
|
|
1307
|
-
stdio: 'inherit',
|
|
1308
|
-
});
|
|
1309
|
-
if (install.error || install.status !== 0) {
|
|
1310
|
-
console.log(
|
|
1311
|
-
`[${TOOL_NAME}] ⚠️ VS Code extension install failed. ` +
|
|
1312
|
-
`Retry manually: code --install-extension ${VSCODE_EXTENSION_ID}`,
|
|
1313
|
-
);
|
|
1314
|
-
return;
|
|
1315
|
-
}
|
|
1316
|
-
console.log(
|
|
1317
|
-
`[${TOOL_NAME}] ✅ VS Code extension '${VSCODE_EXTENSION_ID}' installed. ` +
|
|
1318
|
-
`Reload the VS Code window to activate it.`,
|
|
1319
|
-
);
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
1271
|
function resolveGlobalInstallApproval(options) {
|
|
1323
1272
|
if (options.yesGlobalInstall && options.noGlobalInstall) {
|
|
1324
1273
|
throw new Error('Cannot use both --yes-global-install and --no-global-install');
|
|
@@ -1557,6 +1506,7 @@ function runInstallInternal(options) {
|
|
|
1557
1506
|
|
|
1558
1507
|
if (!options.skipAgents) {
|
|
1559
1508
|
operations.push(ensureAgentsSnippet(repoRoot, Boolean(options.dryRun), { force: Boolean(options.force) }));
|
|
1509
|
+
operations.push(ensureClaudeAgentsLink(repoRoot, Boolean(options.dryRun)));
|
|
1560
1510
|
}
|
|
1561
1511
|
|
|
1562
1512
|
const hookResult = configureHooks(repoRoot, Boolean(options.dryRun));
|
|
@@ -1640,6 +1590,7 @@ function runFixInternal(options) {
|
|
|
1640
1590
|
|
|
1641
1591
|
if (!options.skipAgents) {
|
|
1642
1592
|
operations.push(ensureAgentsSnippet(repoRoot, Boolean(options.dryRun), { force: Boolean(options.force) }));
|
|
1593
|
+
operations.push(ensureClaudeAgentsLink(repoRoot, Boolean(options.dryRun)));
|
|
1643
1594
|
}
|
|
1644
1595
|
|
|
1645
1596
|
const hookResult = configureHooks(repoRoot, Boolean(options.dryRun));
|
|
@@ -1947,6 +1898,7 @@ function collectServicesSnapshot() {
|
|
|
1947
1898
|
...requiredSystemTools.map((tool) => ({
|
|
1948
1899
|
name: tool.name,
|
|
1949
1900
|
displayName: tool.displayName || tool.name,
|
|
1901
|
+
command: tool.command,
|
|
1950
1902
|
status: tool.status,
|
|
1951
1903
|
})),
|
|
1952
1904
|
];
|
|
@@ -2016,9 +1968,7 @@ function status(rawArgs) {
|
|
|
2016
1968
|
target: process.cwd(),
|
|
2017
1969
|
json: false,
|
|
2018
1970
|
});
|
|
2019
|
-
const forceCompact = envFlagIsTruthy(process.env.GUARDEX_COMPACT_STATUS);
|
|
2020
1971
|
const forceExpand = envFlagIsTruthy(process.env.GUARDEX_VERBOSE_STATUS) || verboseFlag;
|
|
2021
|
-
const interactive = Boolean(process.stdout.isTTY);
|
|
2022
1972
|
const invokedBasename = getInvokedCliName();
|
|
2023
1973
|
|
|
2024
1974
|
let snapshot = collectServicesSnapshot();
|
|
@@ -2071,17 +2021,24 @@ function status(rawArgs) {
|
|
|
2071
2021
|
return payload;
|
|
2072
2022
|
}
|
|
2073
2023
|
|
|
2074
|
-
const
|
|
2075
|
-
const
|
|
2024
|
+
const compact = !forceExpand;
|
|
2025
|
+
const activeServiceCount = services.filter((service) => service.status === 'active').length;
|
|
2026
|
+
const inactiveServiceCount = services.length - activeServiceCount;
|
|
2076
2027
|
|
|
2077
2028
|
console.log(`[${TOOL_NAME}] CLI: ${payload.cli.runtime}`);
|
|
2078
2029
|
if (!toolchain.ok) {
|
|
2079
|
-
|
|
2030
|
+
const detectionError = compact
|
|
2031
|
+
? String(toolchain.error || '').split(/\r?\n/).find(Boolean) || 'unknown error'
|
|
2032
|
+
: toolchain.error;
|
|
2033
|
+
console.log(`[${TOOL_NAME}] ⚠️ Could not detect global services: ${detectionError}`);
|
|
2080
2034
|
}
|
|
2081
2035
|
|
|
2082
2036
|
if (compact) {
|
|
2037
|
+
const serviceSummary = inactiveServiceCount === 0
|
|
2038
|
+
? `${activeServiceCount}/${services.length} ${statusDot('active')} active`
|
|
2039
|
+
: `${activeServiceCount}/${services.length} ${statusDot('degraded')} active (${inactiveServiceCount} inactive)`;
|
|
2083
2040
|
console.log(
|
|
2084
|
-
`[${TOOL_NAME}] Global services: ${
|
|
2041
|
+
`[${TOOL_NAME}] Global services: ${serviceSummary}`,
|
|
2085
2042
|
);
|
|
2086
2043
|
} else {
|
|
2087
2044
|
console.log(`[${TOOL_NAME}] Global services:`);
|
|
@@ -2094,19 +2051,25 @@ function status(rawArgs) {
|
|
|
2094
2051
|
.filter((service) => service.status !== 'active')
|
|
2095
2052
|
.map((service) => service.displayName || service.name);
|
|
2096
2053
|
if (inactiveOptionalCompanions.length > 0) {
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
.
|
|
2104
|
-
|
|
2105
|
-
|
|
2054
|
+
if (compact) {
|
|
2055
|
+
console.log(
|
|
2056
|
+
`[${TOOL_NAME}] Optional companion tools inactive: ${inactiveOptionalCompanions.length} (run '${SHORT_TOOL_NAME} setup')`,
|
|
2057
|
+
);
|
|
2058
|
+
} else {
|
|
2059
|
+
console.log(
|
|
2060
|
+
`[${TOOL_NAME}] Optional companion tools inactive: ${inactiveOptionalCompanions.join(', ')}`,
|
|
2061
|
+
);
|
|
2062
|
+
for (const warning of toolchainModule.describeMissingGlobalDependencyWarnings(
|
|
2063
|
+
npmServices
|
|
2064
|
+
.filter((service) => service.status === 'inactive')
|
|
2065
|
+
.map((service) => service.packageName),
|
|
2066
|
+
)) {
|
|
2067
|
+
console.log(`[${TOOL_NAME}] ${warning}`);
|
|
2068
|
+
}
|
|
2069
|
+
console.log(
|
|
2070
|
+
`[${TOOL_NAME}] Run '${SHORT_TOOL_NAME} setup' to install missing companions with an explicit Y/N prompt.`,
|
|
2071
|
+
);
|
|
2106
2072
|
}
|
|
2107
|
-
console.log(
|
|
2108
|
-
`[${TOOL_NAME}] Run '${SHORT_TOOL_NAME} setup' to install missing companions with an explicit Y/N prompt.`,
|
|
2109
|
-
);
|
|
2110
2073
|
}
|
|
2111
2074
|
const missingSystemTools = requiredSystemTools.filter((tool) => tool.status !== 'active');
|
|
2112
2075
|
if (missingSystemTools.length > 0) {
|
|
@@ -2114,9 +2077,11 @@ function status(rawArgs) {
|
|
|
2114
2077
|
.map((tool) => tool.displayName || tool.name)
|
|
2115
2078
|
.join(', ');
|
|
2116
2079
|
console.log(`[${TOOL_NAME}] ⚠️ Missing required system tool(s): ${tools}`);
|
|
2117
|
-
|
|
2118
|
-
const
|
|
2119
|
-
|
|
2080
|
+
if (!compact) {
|
|
2081
|
+
for (const tool of missingSystemTools) {
|
|
2082
|
+
const reasonText = tool.reason ? ` (${tool.reason})` : '';
|
|
2083
|
+
console.log(` - install ${tool.name}: ${tool.installHint}${reasonText}`);
|
|
2084
|
+
}
|
|
2120
2085
|
}
|
|
2121
2086
|
}
|
|
2122
2087
|
|
|
@@ -2387,6 +2352,10 @@ function doctor(rawArgs) {
|
|
|
2387
2352
|
target: topRepoRoot,
|
|
2388
2353
|
};
|
|
2389
2354
|
|
|
2355
|
+
if (!singleRepoOptions.json) {
|
|
2356
|
+
printRequiredSystemToolStatus();
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2390
2359
|
const blocked = protectedBaseWriteBlock(singleRepoOptions, { requireBootstrap: false });
|
|
2391
2360
|
if (blocked) {
|
|
2392
2361
|
doctorModule.runDoctorInSandbox(singleRepoOptions, blocked, {
|
|
@@ -2501,6 +2470,13 @@ function review(rawArgs) {
|
|
|
2501
2470
|
process.exitCode = typeof result.status === 'number' ? result.status : 1;
|
|
2502
2471
|
}
|
|
2503
2472
|
|
|
2473
|
+
function prReview(rawArgs) {
|
|
2474
|
+
const options = parsePrReviewArgs(rawArgs);
|
|
2475
|
+
const result = prReviewModule.runPrReview(options);
|
|
2476
|
+
prReviewModule.printPrReviewResult(result);
|
|
2477
|
+
process.exitCode = 0;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2504
2480
|
function agentsStatePathForRepo(repoRoot) {
|
|
2505
2481
|
return path.join(repoRoot, AGENTS_BOTS_STATE_RELATIVE);
|
|
2506
2482
|
}
|
|
@@ -2642,10 +2618,58 @@ function spawnDetachedAgentProcess({ command, args, cwd, logPath }) {
|
|
|
2642
2618
|
|
|
2643
2619
|
function agents(rawArgs) {
|
|
2644
2620
|
const options = parseAgentsArgs(rawArgs);
|
|
2621
|
+
if (['files', 'diff', 'locks'].includes(options.subcommand)) {
|
|
2622
|
+
process.stdout.write(agentInspect.runInspectCommand(options));
|
|
2623
|
+
process.exitCode = 0;
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2645
2627
|
const repoRoot = resolveRepoRoot(options.target);
|
|
2646
2628
|
const statePath = agentsStatePathForRepo(repoRoot);
|
|
2647
2629
|
|
|
2630
|
+
if (options.subcommand === 'finish') {
|
|
2631
|
+
const result = finishAgentSession(repoRoot, options);
|
|
2632
|
+
if (options.json) {
|
|
2633
|
+
process.stdout.write(`${JSON.stringify(result.evidence, null, 2)}\n`);
|
|
2634
|
+
}
|
|
2635
|
+
process.exitCode = 0;
|
|
2636
|
+
return;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
if (options.subcommand === 'cleanup-sessions') {
|
|
2640
|
+
process.stdout.write(agentCleanupSessions.runCleanupSessionsCommand(repoRoot, options));
|
|
2641
|
+
process.exitCode = 0;
|
|
2642
|
+
return;
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2648
2645
|
if (options.subcommand === 'start') {
|
|
2646
|
+
if (agentsStart.shouldUseInteractivePanel(options, process.stdin, process.stdout)) {
|
|
2647
|
+
agentsStart.startInteractiveAgentPanel(repoRoot, options, {
|
|
2648
|
+
onDone(result) {
|
|
2649
|
+
process.exitCode = result.status;
|
|
2650
|
+
},
|
|
2651
|
+
});
|
|
2652
|
+
return;
|
|
2653
|
+
}
|
|
2654
|
+
if (options.dryRun) {
|
|
2655
|
+
const output = agentsStart.dryRunStart(options, repoRoot);
|
|
2656
|
+
process.stdout.write(output.endsWith('\n') ? output : `${output}\n`);
|
|
2657
|
+
process.exitCode = 0;
|
|
2658
|
+
return;
|
|
2659
|
+
}
|
|
2660
|
+
if (options.panel && !options.task) {
|
|
2661
|
+
process.stderr.write('[gitguardex] gx agents start --panel requires an interactive terminal when no task is provided.\n');
|
|
2662
|
+
process.exitCode = 1;
|
|
2663
|
+
return;
|
|
2664
|
+
}
|
|
2665
|
+
if (options.task) {
|
|
2666
|
+
const result = agentsStart.startAgentLane(repoRoot, options);
|
|
2667
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
2668
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
2669
|
+
process.exitCode = result.status;
|
|
2670
|
+
return;
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2649
2673
|
const existingState = readAgentsState(repoRoot);
|
|
2650
2674
|
const existingReviewPid = Number.parseInt(String(existingState?.review?.pid || ''), 10);
|
|
2651
2675
|
const existingCleanupPid = Number.parseInt(String(existingState?.cleanup?.pid || ''), 10);
|
|
@@ -2786,18 +2810,7 @@ function agents(rawArgs) {
|
|
|
2786
2810
|
return;
|
|
2787
2811
|
}
|
|
2788
2812
|
|
|
2789
|
-
|
|
2790
|
-
if (!existingState) {
|
|
2791
|
-
console.log(`[${TOOL_NAME}] Repo agents status: inactive (${repoRoot})`);
|
|
2792
|
-
process.exitCode = 0;
|
|
2793
|
-
return;
|
|
2794
|
-
}
|
|
2795
|
-
|
|
2796
|
-
const reviewPid = Number.parseInt(String(existingState?.review?.pid || ''), 10);
|
|
2797
|
-
const cleanupPid = Number.parseInt(String(existingState?.cleanup?.pid || ''), 10);
|
|
2798
|
-
console.log(
|
|
2799
|
-
`[${TOOL_NAME}] Repo agents status: review=${processAlive(reviewPid) ? 'running' : 'stopped'}(pid=${reviewPid || 0}), cleanup=${processAlive(cleanupPid) ? 'running' : 'stopped'}(pid=${cleanupPid || 0})`,
|
|
2800
|
-
);
|
|
2813
|
+
process.stdout.write(agentStatus.runStatusCommand(repoRoot, options));
|
|
2801
2814
|
process.exitCode = 0;
|
|
2802
2815
|
}
|
|
2803
2816
|
|
|
@@ -2955,20 +2968,7 @@ function setup(rawArgs) {
|
|
|
2955
2968
|
}
|
|
2956
2969
|
}
|
|
2957
2970
|
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
const requiredSystemTools = toolchainModule.detectRequiredSystemTools();
|
|
2961
|
-
const missingSystemTools = requiredSystemTools.filter((tool) => tool.status !== 'active');
|
|
2962
|
-
if (missingSystemTools.length === 0) {
|
|
2963
|
-
console.log(`[${TOOL_NAME}] ✅ Required system tools available (${requiredSystemTools.map((tool) => tool.name).join(', ')}).`);
|
|
2964
|
-
} else {
|
|
2965
|
-
const names = missingSystemTools.map((tool) => tool.name).join(', ');
|
|
2966
|
-
console.log(`[${TOOL_NAME}] ⚠️ Missing required system tool(s): ${names}`);
|
|
2967
|
-
for (const tool of missingSystemTools) {
|
|
2968
|
-
const reasonText = tool.reason ? ` (${tool.reason})` : '';
|
|
2969
|
-
console.log(`[${TOOL_NAME}] Install ${tool.name}: ${tool.installHint}${reasonText}`);
|
|
2970
|
-
}
|
|
2971
|
-
}
|
|
2971
|
+
printRequiredSystemToolStatus();
|
|
2972
2972
|
|
|
2973
2973
|
const topRepoRoot = resolveRepoRoot(options.target);
|
|
2974
2974
|
const discoveredRepos = options.recursive
|
|
@@ -3082,6 +3082,22 @@ function setup(rawArgs) {
|
|
|
3082
3082
|
}
|
|
3083
3083
|
}
|
|
3084
3084
|
|
|
3085
|
+
function printRequiredSystemToolStatus() {
|
|
3086
|
+
const requiredSystemTools = toolchainModule.detectRequiredSystemTools();
|
|
3087
|
+
const missingSystemTools = requiredSystemTools.filter((tool) => tool.status !== 'active');
|
|
3088
|
+
if (missingSystemTools.length === 0) {
|
|
3089
|
+
console.log(`[${TOOL_NAME}] ✅ Required system tools available (${requiredSystemTools.map((tool) => tool.name).join(', ')}).`);
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
3092
|
+
|
|
3093
|
+
const names = missingSystemTools.map((tool) => tool.name).join(', ');
|
|
3094
|
+
console.log(`[${TOOL_NAME}] ⚠️ Missing required system tool(s): ${names}`);
|
|
3095
|
+
for (const tool of missingSystemTools) {
|
|
3096
|
+
const reasonText = tool.reason ? ` (${tool.reason})` : '';
|
|
3097
|
+
console.log(`[${TOOL_NAME}] Install ${tool.name}: ${tool.installHint}${reasonText}`);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3085
3101
|
function ensureMainBranch(repoRoot) {
|
|
3086
3102
|
const branchResult = gitRun(repoRoot, ['rev-parse', '--abbrev-ref', 'HEAD'], { allowFailure: true });
|
|
3087
3103
|
if (branchResult.status !== 0) {
|
|
@@ -3249,6 +3265,25 @@ function renderGeneratedReleaseNotes(entries, currentTag, previousTag) {
|
|
|
3249
3265
|
return `GitGuardex ${currentTag}\n\n${intro}\n\n${sections}`;
|
|
3250
3266
|
}
|
|
3251
3267
|
|
|
3268
|
+
function describeGhAuthFailure(ghBin, authStatus) {
|
|
3269
|
+
if (authStatus.error) {
|
|
3270
|
+
return `unable to run '${ghBin} auth status': ${authStatus.error.message}`;
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3273
|
+
const authDetails = (authStatus.stderr || authStatus.stdout || '').trim();
|
|
3274
|
+
const apiProbe = run(ghBin, ['api', 'user', '--jq', '.login'], { timeout: 20_000 });
|
|
3275
|
+
if (apiProbe.status === 0) {
|
|
3276
|
+
return '';
|
|
3277
|
+
}
|
|
3278
|
+
|
|
3279
|
+
const apiDetails = (apiProbe.stderr || apiProbe.stdout || apiProbe.error?.message || '').trim();
|
|
3280
|
+
if (/error connecting to api\.github\.com|could not resolve host|failed to connect|network is unreachable|connection timed out|temporary failure in name resolution/i.test(apiDetails)) {
|
|
3281
|
+
return `GitHub API is unreachable, so '${ghBin} auth status' cannot validate the stored token. This is a network or sandbox connectivity problem, not proof that the token is invalid.${apiDetails ? `\n${apiDetails}` : ''}`;
|
|
3282
|
+
}
|
|
3283
|
+
|
|
3284
|
+
return `'${ghBin}' auth is unavailable.${authDetails ? `\n${authDetails}` : ''}`;
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3252
3287
|
function buildReleaseNotesFromReadme(repoRoot, currentTag, previousTag) {
|
|
3253
3288
|
const readme = readRepoReadme(repoRoot);
|
|
3254
3289
|
const entries = parseReadmeReleaseEntries(readme);
|
|
@@ -3276,12 +3311,11 @@ function release(rawArgs) {
|
|
|
3276
3311
|
}
|
|
3277
3312
|
|
|
3278
3313
|
const ghAuthStatus = run(GH_BIN, ['auth', 'status'], { timeout: 20_000 });
|
|
3279
|
-
if (ghAuthStatus.error) {
|
|
3280
|
-
throw new Error(`Release blocked: unable to run '${GH_BIN} auth status': ${ghAuthStatus.error.message}`);
|
|
3281
|
-
}
|
|
3282
3314
|
if (ghAuthStatus.status !== 0) {
|
|
3283
|
-
const
|
|
3284
|
-
|
|
3315
|
+
const ghAuthFailure = describeGhAuthFailure(GH_BIN, ghAuthStatus);
|
|
3316
|
+
if (ghAuthFailure) {
|
|
3317
|
+
throw new Error(`Release blocked: ${ghAuthFailure}`);
|
|
3318
|
+
}
|
|
3285
3319
|
}
|
|
3286
3320
|
|
|
3287
3321
|
const releasePackageJson = readReleaseRepoPackageJson(repoRoot);
|
|
@@ -3416,6 +3450,7 @@ function prompt(rawArgs) {
|
|
|
3416
3450
|
}
|
|
3417
3451
|
|
|
3418
3452
|
function branch(rawArgs) {
|
|
3453
|
+
const activeCwd = process.cwd();
|
|
3419
3454
|
const [subcommand, ...rest] = rawArgs;
|
|
3420
3455
|
if (subcommand === 'start') {
|
|
3421
3456
|
const { target, passthrough } = extractTargetedArgs(rest);
|
|
@@ -3424,7 +3459,10 @@ function branch(rawArgs) {
|
|
|
3424
3459
|
}
|
|
3425
3460
|
if (subcommand === 'finish') {
|
|
3426
3461
|
const { target, passthrough } = extractTargetedArgs(rest);
|
|
3427
|
-
invokePackageAsset('branchFinish', passthrough, {
|
|
3462
|
+
invokePackageAsset('branchFinish', passthrough, {
|
|
3463
|
+
cwd: resolveRepoRoot(target),
|
|
3464
|
+
env: { GUARDEX_FINISH_ACTIVE_CWD: activeCwd },
|
|
3465
|
+
});
|
|
3428
3466
|
return;
|
|
3429
3467
|
}
|
|
3430
3468
|
if (subcommand === 'merge') return merge(rest);
|
|
@@ -3501,10 +3539,14 @@ function locks(rawArgs) {
|
|
|
3501
3539
|
}
|
|
3502
3540
|
|
|
3503
3541
|
function worktree(rawArgs) {
|
|
3542
|
+
const activeCwd = process.cwd();
|
|
3504
3543
|
const [subcommand, ...rest] = rawArgs;
|
|
3505
3544
|
if (subcommand === 'prune') {
|
|
3506
3545
|
const { target, passthrough } = extractTargetedArgs(rest);
|
|
3507
|
-
invokePackageAsset('worktreePrune', passthrough, {
|
|
3546
|
+
invokePackageAsset('worktreePrune', passthrough, {
|
|
3547
|
+
cwd: resolveRepoRoot(target),
|
|
3548
|
+
env: { GUARDEX_PRUNE_ACTIVE_CWD: process.env.GUARDEX_PRUNE_ACTIVE_CWD || activeCwd },
|
|
3549
|
+
});
|
|
3508
3550
|
return;
|
|
3509
3551
|
}
|
|
3510
3552
|
throw new Error(`Usage: ${SHORT_TOOL_NAME} worktree prune [cleanup-options]`);
|
|
@@ -3616,6 +3658,81 @@ function sync(rawArgs) {
|
|
|
3616
3658
|
return finishCommands.sync(rawArgs);
|
|
3617
3659
|
}
|
|
3618
3660
|
|
|
3661
|
+
function submodule(rawArgs) {
|
|
3662
|
+
const parsed = parseTargetFlag(rawArgs || [], process.cwd());
|
|
3663
|
+
const [subcommand, ...rest] = parsed.args;
|
|
3664
|
+
|
|
3665
|
+
if (!subcommand || subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
|
|
3666
|
+
console.log(
|
|
3667
|
+
`${TOOL_NAME} submodule commands:\n` +
|
|
3668
|
+
` ${TOOL_NAME} submodule advance [<path>] [--push] [--dry-run] [--branch <ref>] [--no-commit] [--target <path>]\n\n` +
|
|
3669
|
+
` advance — for each submodule listed in .gitmodules, fetch the tracked branch's\n` +
|
|
3670
|
+
` remote tip, advance the parent pointer, and (when on a non-protected\n` +
|
|
3671
|
+
` branch) commit the bump. Use --push to publish in one step.`,
|
|
3672
|
+
);
|
|
3673
|
+
return;
|
|
3674
|
+
}
|
|
3675
|
+
|
|
3676
|
+
if (subcommand !== 'advance') {
|
|
3677
|
+
throw new Error(`Unknown submodule subcommand: ${subcommand}. Try '${SHORT_TOOL_NAME} submodule help'.`);
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3680
|
+
let push = false;
|
|
3681
|
+
let dryRun = false;
|
|
3682
|
+
let commit = true;
|
|
3683
|
+
let branchOverride = '';
|
|
3684
|
+
let pathArg = '';
|
|
3685
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
3686
|
+
const arg = rest[i];
|
|
3687
|
+
if (arg === '--push') {
|
|
3688
|
+
push = true;
|
|
3689
|
+
continue;
|
|
3690
|
+
}
|
|
3691
|
+
if (arg === '--dry-run' || arg === '-n') {
|
|
3692
|
+
dryRun = true;
|
|
3693
|
+
continue;
|
|
3694
|
+
}
|
|
3695
|
+
if (arg === '--no-commit') {
|
|
3696
|
+
commit = false;
|
|
3697
|
+
continue;
|
|
3698
|
+
}
|
|
3699
|
+
if (arg === '--branch' || arg === '-b') {
|
|
3700
|
+
branchOverride = rest[i + 1] || '';
|
|
3701
|
+
i += 1;
|
|
3702
|
+
continue;
|
|
3703
|
+
}
|
|
3704
|
+
if (arg.startsWith('--branch=')) {
|
|
3705
|
+
branchOverride = arg.slice('--branch='.length);
|
|
3706
|
+
continue;
|
|
3707
|
+
}
|
|
3708
|
+
if (arg.startsWith('--')) {
|
|
3709
|
+
throw new Error(`Unknown option for '${SHORT_TOOL_NAME} submodule advance': ${arg}`);
|
|
3710
|
+
}
|
|
3711
|
+
if (pathArg) {
|
|
3712
|
+
throw new Error(`'${SHORT_TOOL_NAME} submodule advance' accepts at most one submodule path (got '${pathArg}' and '${arg}')`);
|
|
3713
|
+
}
|
|
3714
|
+
pathArg = arg;
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
const result = submoduleModule.advance({
|
|
3718
|
+
target: parsed.target,
|
|
3719
|
+
path: pathArg,
|
|
3720
|
+
push,
|
|
3721
|
+
dryRun,
|
|
3722
|
+
commit,
|
|
3723
|
+
branch: branchOverride,
|
|
3724
|
+
});
|
|
3725
|
+
submoduleModule.printAdvanceResult(result);
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
function cockpit(rawArgs) {
|
|
3729
|
+
cockpitModule.openCockpit(rawArgs, {
|
|
3730
|
+
resolveRepoRoot,
|
|
3731
|
+
toolName: TOOL_NAME,
|
|
3732
|
+
});
|
|
3733
|
+
process.exitCode = 0;
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3619
3736
|
function protect(rawArgs) {
|
|
3620
3737
|
const parsed = parseTargetFlag(rawArgs, process.cwd());
|
|
3621
3738
|
const [subcommand, ...rest] = parsed.args;
|
|
@@ -3698,6 +3815,14 @@ async function main() {
|
|
|
3698
3815
|
const args = process.argv.slice(2);
|
|
3699
3816
|
|
|
3700
3817
|
if (args.length === 0) {
|
|
3818
|
+
if (isInteractiveTerminal() && !legacyDefaultStatusEnabled() && !defaultCockpitDisabled()) {
|
|
3819
|
+
cockpitModule.openDefaultCockpit({
|
|
3820
|
+
resolveRepoRoot,
|
|
3821
|
+
toolName: TOOL_NAME,
|
|
3822
|
+
});
|
|
3823
|
+
process.exitCode = 0;
|
|
3824
|
+
return;
|
|
3825
|
+
}
|
|
3701
3826
|
toolchainModule.maybeSelfUpdateBeforeStatus();
|
|
3702
3827
|
toolchainModule.maybeOpenSpecUpdateBeforeStatus();
|
|
3703
3828
|
const statusPayload = status([]);
|
|
@@ -3747,6 +3872,7 @@ async function main() {
|
|
|
3747
3872
|
}
|
|
3748
3873
|
|
|
3749
3874
|
if (command === 'prompt') return prompt(rest);
|
|
3875
|
+
if (command === 'pr-review') return prReview(rest);
|
|
3750
3876
|
if (command === 'doctor') return doctor(rest);
|
|
3751
3877
|
if (command === 'branch') return branch(rest);
|
|
3752
3878
|
if (command === 'pivot') return pivot(rest);
|
|
@@ -3758,13 +3884,17 @@ async function main() {
|
|
|
3758
3884
|
if (command === 'install-agent-skills') return installAgentSkills(rest);
|
|
3759
3885
|
if (command === 'internal') return internal(rest);
|
|
3760
3886
|
if (command === 'agents') return agents(rest);
|
|
3887
|
+
if (command === 'cockpit') return cockpit(rest);
|
|
3761
3888
|
if (command === 'merge') return merge(rest);
|
|
3762
3889
|
if (command === 'finish') return finish(rest);
|
|
3763
3890
|
if (command === 'report') return report(rest);
|
|
3764
3891
|
if (command === 'protect') return protect(rest);
|
|
3765
3892
|
if (command === 'sync') return sync(rest);
|
|
3893
|
+
if (command === 'submodule') return submodule(rest);
|
|
3766
3894
|
if (command === 'cleanup') return cleanup(rest);
|
|
3767
3895
|
if (command === 'release') return release(rest);
|
|
3896
|
+
if (command === 'budget') return budgetModule.runBudgetCommand(rest);
|
|
3897
|
+
if (command === 'ci-init') return ciInitModule.runCiInitCommand(rest);
|
|
3768
3898
|
|
|
3769
3899
|
const suggestion = maybeSuggestCommand(command);
|
|
3770
3900
|
if (suggestion) {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function parseAgentBranchStartMetadata(output) {
|
|
4
|
+
const outputText = String(output || '');
|
|
5
|
+
const branchMatch = outputText.match(/^\[agent-branch-start\] (?:Created branch|Reusing existing branch): (.+)$/m);
|
|
6
|
+
const worktreeMatch = outputText.match(/^\[agent-branch-start\] Worktree: (.+)$/m);
|
|
7
|
+
return {
|
|
8
|
+
branch: branchMatch ? branchMatch[1].trim() : undefined,
|
|
9
|
+
worktreePath: worktreeMatch ? worktreeMatch[1].trim() : undefined,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function firstString(...values) {
|
|
14
|
+
for (const value of values) {
|
|
15
|
+
if (typeof value === 'string' && value.length > 0) return value;
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeStartResult(result) {
|
|
21
|
+
const payload = result && typeof result === 'object' ? result : {};
|
|
22
|
+
const metadata = parseAgentBranchStartMetadata(payload.stdout);
|
|
23
|
+
const ok = Object.prototype.hasOwnProperty.call(payload, 'ok')
|
|
24
|
+
? Boolean(payload.ok)
|
|
25
|
+
: typeof payload.status === 'number'
|
|
26
|
+
? payload.status === 0
|
|
27
|
+
: true;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
ok,
|
|
31
|
+
sessionId: firstString(payload.sessionId, payload.session?.id, payload.id),
|
|
32
|
+
branch: firstString(payload.branch, payload.lane?.branch, metadata.branch),
|
|
33
|
+
worktreePath: firstString(payload.worktreePath, payload.worktree?.path, payload.path, metadata.worktreePath),
|
|
34
|
+
message: firstString(
|
|
35
|
+
payload.message,
|
|
36
|
+
ok ? payload.stdout : payload.stderr,
|
|
37
|
+
ok ? 'Started agent lane.' : 'Failed to start agent lane.',
|
|
38
|
+
),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function resolveStartImplementation(deps = {}) {
|
|
43
|
+
if (typeof deps.startImplementation === 'function') return deps.startImplementation;
|
|
44
|
+
if (typeof deps.startAgentLane === 'function') return deps.startAgentLane;
|
|
45
|
+
if (typeof deps.startAgent === 'function') return deps.startAgent;
|
|
46
|
+
|
|
47
|
+
const startModule = require('../agents/start');
|
|
48
|
+
if (typeof startModule === 'function') return startModule;
|
|
49
|
+
if (typeof startModule.startAgentLane === 'function') return startModule.startAgentLane;
|
|
50
|
+
if (typeof startModule.startAgent === 'function') return startModule.startAgent;
|
|
51
|
+
if (typeof startModule.start === 'function') return startModule.start;
|
|
52
|
+
|
|
53
|
+
throw new Error('gx agents start implementation is unavailable');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function startAgentLane(options = {}, deps = {}) {
|
|
57
|
+
const repoRoot = firstString(options.repoRoot, deps.repoRoot, process.cwd());
|
|
58
|
+
const normalizedOptions = {
|
|
59
|
+
task: options.task,
|
|
60
|
+
agent: options.agent,
|
|
61
|
+
base: options.base,
|
|
62
|
+
claims: Array.isArray(options.claims) ? options.claims : [],
|
|
63
|
+
metadata: options.metadata && typeof options.metadata === 'object' ? options.metadata : {},
|
|
64
|
+
};
|
|
65
|
+
const startImplementation = resolveStartImplementation(deps);
|
|
66
|
+
const result = startImplementation(repoRoot, normalizedOptions);
|
|
67
|
+
|
|
68
|
+
if (result && typeof result.then === 'function') {
|
|
69
|
+
return result.then(normalizeStartResult);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return normalizeStartResult(result);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
startAgentLane,
|
|
77
|
+
normalizeStartResult,
|
|
78
|
+
parseAgentBranchStartMetadata,
|
|
79
|
+
resolveStartImplementation,
|
|
80
|
+
};
|