@imdeadpool/guardex 7.0.43 → 7.1.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.
Files changed (63) hide show
  1. package/README.md +26 -0
  2. package/package.json +2 -1
  3. package/skills/gx-act/SKILL.md +82 -0
  4. package/src/agents/inspect.js +17 -4
  5. package/src/agents/launch.js +10 -1
  6. package/src/agents/status.js +9 -6
  7. package/src/budget/index.js +2 -1
  8. package/src/cli/args.js +52 -2
  9. package/src/cli/commands/agents.js +364 -0
  10. package/src/cli/commands/bootstrap.js +92 -0
  11. package/src/cli/commands/branch.js +127 -0
  12. package/src/cli/commands/claude.js +674 -0
  13. package/src/cli/commands/doctor.js +268 -0
  14. package/src/cli/commands/finish.js +26 -0
  15. package/src/cli/commands/mcp.js +122 -0
  16. package/src/cli/commands/misc.js +304 -0
  17. package/src/cli/commands/pr.js +439 -0
  18. package/src/cli/commands/prompt.js +92 -0
  19. package/src/cli/commands/release.js +305 -0
  20. package/src/cli/commands/report.js +244 -0
  21. package/src/cli/commands/review.js +32 -0
  22. package/src/cli/commands/setup.js +242 -0
  23. package/src/cli/commands/status.js +338 -0
  24. package/src/cli/commands/watch.js +234 -0
  25. package/src/cli/main.js +68 -3726
  26. package/src/cli/shared/repo-env.js +161 -0
  27. package/src/cli/shared/sandbox.js +417 -0
  28. package/src/cli/shared/scaffolding.js +535 -0
  29. package/src/cli/shared/toolchain-shims.js +420 -0
  30. package/src/context.js +229 -11
  31. package/src/core/runtime.js +6 -1
  32. package/src/doctor/index.js +42 -13
  33. package/src/finish/index.js +147 -5
  34. package/src/finish/preflight.js +177 -0
  35. package/src/finish/review-gate.js +182 -0
  36. package/src/git/index.js +446 -4
  37. package/src/hooks/index.js +0 -64
  38. package/src/mcp/collect.js +370 -0
  39. package/src/mcp/server.js +157 -0
  40. package/src/output/index.js +67 -1
  41. package/src/pr-review.js +23 -0
  42. package/src/pr.js +381 -0
  43. package/src/sandbox/index.js +13 -2
  44. package/src/scaffold/agent-worktree-prep.js +213 -0
  45. package/src/scaffold/index.js +108 -10
  46. package/src/speckit/index.js +226 -0
  47. package/src/terminal/index.js +1 -76
  48. package/src/terminal/tmux.js +0 -1
  49. package/src/toolchain/index.js +20 -0
  50. package/templates/AGENTS.monorepo-apps.md +26 -0
  51. package/templates/AGENTS.multiagent-safety.md +61 -347
  52. package/templates/AGENTS.multiagent-safety.min.md +11 -0
  53. package/templates/codex/skills/gx-act/SKILL.md +82 -0
  54. package/templates/githooks/pre-commit +22 -19
  55. package/templates/scripts/agent-branch-finish.sh +8 -30
  56. package/templates/scripts/agent-branch-merge.sh +4 -1
  57. package/templates/scripts/agent-branch-start.sh +88 -3
  58. package/templates/scripts/agent-preflight.sh +31 -5
  59. package/templates/scripts/agent-worktree-prune.sh +1 -1
  60. package/templates/scripts/codex-agent.sh +0 -91
  61. package/src/agents/detect.js +0 -160
  62. package/src/cockpit/keybindings.js +0 -224
  63. package/src/cockpit/layout.js +0 -224
@@ -1,224 +0,0 @@
1
- 'use strict';
2
-
3
- const { PANE_MENU_ACTION_IDS } = require('./pane-menu');
4
-
5
- const DEFAULT_ACTION_ROWS = Object.freeze(['new-agent', 'terminal', 'settings', 'shortcuts']);
6
- const VALID_MODES = new Set(['main', 'menu', 'settings', 'shortcuts', 'new-agent', 'terminal', 'prompt']);
7
-
8
- function action(type, payload = {}) {
9
- return { type, payload };
10
- }
11
-
12
- const NAVIGATION_BINDINGS = {
13
- j: action('next'),
14
- down: action('next'),
15
- k: action('previous'),
16
- up: action('previous'),
17
- enter: action('view-selected'),
18
- };
19
-
20
- const MAIN_BINDINGS = {
21
- n: action('new-agent'),
22
- t: action('terminal'),
23
- m: action('menu'),
24
- 'alt-shift-m': action('menu'),
25
- s: action('settings'),
26
- '?': action('shortcuts'),
27
- x: action(PANE_MENU_ACTION_IDS.CLOSE),
28
- b: action(PANE_MENU_ACTION_IDS.CREATE_CHILD_WORKTREE),
29
- f: action(PANE_MENU_ACTION_IDS.BROWSE_FILES),
30
- h: action(PANE_MENU_ACTION_IDS.HIDE_PANE),
31
- P: action(PANE_MENU_ACTION_IDS.PROJECT_FOCUS),
32
- a: action(PANE_MENU_ACTION_IDS.ADD_AGENT),
33
- A: action(PANE_MENU_ACTION_IDS.ADD_TERMINAL),
34
- r: action(PANE_MENU_ACTION_IDS.REOPEN_CLOSED_WORKTREE),
35
- D: action('doctor'),
36
- d: action('diff'),
37
- l: action('locks'),
38
- y: action('sync'),
39
- F: action('finish'),
40
- c: action('cleanup-sessions'),
41
- q: action('quit'),
42
- ...NAVIGATION_BINDINGS,
43
- };
44
-
45
- const BASE_BINDINGS = {
46
- main: MAIN_BINDINGS,
47
- menu: {
48
- ...NAVIGATION_BINDINGS,
49
- esc: action('close-menu'),
50
- q: action('quit'),
51
- },
52
- settings: {
53
- ...NAVIGATION_BINDINGS,
54
- esc: action('close-settings'),
55
- q: action('quit'),
56
- },
57
- shortcuts: {
58
- esc: action('close-popup'),
59
- q: action('quit'),
60
- },
61
- 'new-agent': {
62
- enter: action('agent:start'),
63
- esc: action('close-popup'),
64
- q: action('quit'),
65
- },
66
- terminal: {
67
- enter: action('terminal:open'),
68
- esc: action('close-popup'),
69
- q: action('quit'),
70
- },
71
- prompt: {},
72
- };
73
-
74
- function cloneAction(binding) {
75
- return action(binding.type, { ...binding.payload });
76
- }
77
-
78
- function cloneBindings(bindings) {
79
- return Object.fromEntries(
80
- Object.entries(bindings).map(([mode, modeBindings]) => [
81
- mode,
82
- Object.fromEntries(
83
- Object.entries(modeBindings).map(([key, binding]) => [key, cloneAction(binding)]),
84
- ),
85
- ]),
86
- );
87
- }
88
-
89
- function defaultKeybindings() {
90
- return cloneBindings(BASE_BINDINGS);
91
- }
92
-
93
- function normalizeMode(context = {}) {
94
- return VALID_MODES.has(context.mode) ? context.mode : 'main';
95
- }
96
-
97
- function normalizeKey(key) {
98
- if (key && typeof key === 'object') {
99
- if ((key.meta || key.alt) && key.shift && String(key.name || key.key || '').toLowerCase() === 'm') {
100
- return 'alt-shift-m';
101
- }
102
- return normalizeKey(key.name || key.sequence || key.key || '');
103
- }
104
- if (key === '\r' || key === '\n') return 'enter';
105
- if (key === '\x1bM' || key === '\x1bm') return 'alt-shift-m';
106
- if (key === '\x1b') return 'esc';
107
- if (typeof key !== 'string') return '';
108
-
109
- const normalized = key.trim();
110
- if (normalized === '\x1bM' || normalized === '\x1bm') return 'alt-shift-m';
111
- if (/^alt(?:\+|-)?shift(?:\+|-)?m$/i.test(normalized)) return 'alt-shift-m';
112
- if (normalized.length === 1) return normalized;
113
-
114
- const namedKey = normalized.toLowerCase();
115
- if (namedKey === 'arrowdown') return 'down';
116
- if (namedKey === 'arrowup') return 'up';
117
- if (namedKey === 'return') return 'enter';
118
- if (namedKey === 'escape') return 'esc';
119
- return namedKey;
120
- }
121
-
122
- function resolveKeyAction(key, context = {}) {
123
- const mode = normalizeMode(context);
124
- const normalizedKey = normalizeKey(key);
125
- const keybindings = context.keybindings || BASE_BINDINGS;
126
- const binding = keybindings[mode] && keybindings[mode][normalizedKey];
127
-
128
- if (!binding) {
129
- return action('noop', { key: normalizedKey, mode });
130
- }
131
-
132
- return action(binding.type, {
133
- ...binding.payload,
134
- key: normalizedKey,
135
- mode,
136
- });
137
- }
138
-
139
- function number(value, fallback) {
140
- const parsed = Number(value);
141
- return Number.isFinite(parsed) ? parsed : fallback;
142
- }
143
-
144
- function wrapIndex(index, length) {
145
- if (length <= 0) return 0;
146
- const next = Number.isInteger(index) ? index : 0;
147
- return ((next % length) + length) % length;
148
- }
149
-
150
- function actionRows(state = {}) {
151
- if (!Array.isArray(state.actionRows) || state.actionRows.length === 0) {
152
- return [...DEFAULT_ACTION_ROWS];
153
- }
154
- return state.actionRows.map((row) => String(row || '').trim()).filter(Boolean);
155
- }
156
-
157
- function moveSelection(state = {}, direction) {
158
- const sessions = Array.isArray(state.sessions) ? state.sessions : [];
159
- if (sessions.length > 0) {
160
- return {
161
- ...state,
162
- selectedScope: 'lane',
163
- selectedIndex: wrapIndex(number(state.selectedIndex, 0) + direction, sessions.length),
164
- selectedSessionId: '',
165
- };
166
- }
167
-
168
- const rows = actionRows(state);
169
- return {
170
- ...state,
171
- actionRows: rows,
172
- selectedScope: 'action',
173
- selectedIndex: 0,
174
- actionIndex: wrapIndex(number(state.actionIndex, 0) + direction, rows.length),
175
- selectedSessionId: '',
176
- };
177
- }
178
-
179
- function closeMode(state = {}) {
180
- return {
181
- ...state,
182
- mode: 'main',
183
- lastIntent: null,
184
- };
185
- }
186
-
187
- function applyCockpitKey(state = {}, key) {
188
- const current = {
189
- ...state,
190
- mode: normalizeMode(state),
191
- };
192
- const resolved = resolveKeyAction(key, current);
193
-
194
- switch (resolved.type) {
195
- case 'next':
196
- return moveSelection(current, 1);
197
- case 'previous':
198
- return moveSelection(current, -1);
199
- case 'new-agent':
200
- return { ...current, mode: 'new-agent', lastIntent: null };
201
- case 'terminal':
202
- return { ...current, mode: 'terminal', lastIntent: null };
203
- case 'shortcuts':
204
- return { ...current, mode: 'shortcuts', lastIntent: null };
205
- case 'settings':
206
- return { ...current, mode: 'settings', lastIntent: null };
207
- case 'menu':
208
- return { ...current, mode: 'menu', lastIntent: null };
209
- case 'close-menu':
210
- case 'close-settings':
211
- case 'close-popup':
212
- return closeMode(current);
213
- case 'quit':
214
- return { ...current, shouldExit: true };
215
- default:
216
- return current;
217
- }
218
- }
219
-
220
- module.exports = {
221
- applyCockpitKey,
222
- defaultKeybindings,
223
- resolveKeyAction,
224
- };
@@ -1,224 +0,0 @@
1
- const DEFAULT_SESSION_NAME = 'guardex';
2
- const DEFAULT_SIDEBAR_WIDTH = 34;
3
- const DEFAULT_TERMINAL_COLUMNS = 120;
4
- const DEFAULT_TERMINAL_ROWS = 40;
5
- const MIN_CONTENT_COLUMNS = 20;
6
-
7
- function text(value, fallback = '') {
8
- if (typeof value === 'string') return value.trim() || fallback;
9
- if (value === null || value === undefined) return fallback;
10
- return String(value).trim() || fallback;
11
- }
12
-
13
- function positiveInteger(value, fallback) {
14
- const parsed = Number.parseInt(String(value), 10);
15
- return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
16
- }
17
-
18
- function sidebarWidthFor(value, terminalColumns) {
19
- const requested = positiveInteger(value, DEFAULT_SIDEBAR_WIDTH);
20
- if (terminalColumns <= MIN_CONTENT_COLUMNS) {
21
- return Math.max(1, terminalColumns - 1);
22
- }
23
- return Math.min(requested, terminalColumns - MIN_CONTENT_COLUMNS);
24
- }
25
-
26
- function shellQuote(value) {
27
- return `'${String(value).replace(/'/g, "'\\''")}'`;
28
- }
29
-
30
- function normalizeSessions(sessions) {
31
- if (!Array.isArray(sessions)) return [];
32
- return sessions.map((session, index) => ({
33
- sessionId: text(session.sessionId || session.id, `session-${index + 1}`),
34
- branch: text(session.branch),
35
- worktreePath: text(session.worktreePath),
36
- command: text(session.command),
37
- }));
38
- }
39
-
40
- function paneTarget(sessionName, paneIndex) {
41
- return `${sessionName}:0.${paneIndex}`;
42
- }
43
-
44
- function windowTarget(sessionName) {
45
- return `${sessionName}:0`;
46
- }
47
-
48
- function agentGrid(count) {
49
- if (count <= 1) return { columns: 1, rows: 1 };
50
- const columns = Math.ceil(Math.sqrt(count));
51
- return {
52
- columns,
53
- rows: Math.ceil(count / columns),
54
- };
55
- }
56
-
57
- function dimension(total, parts, index) {
58
- const base = Math.floor(total / parts);
59
- const remainder = total % parts;
60
- return base + (index < remainder ? 1 : 0);
61
- }
62
-
63
- function offset(total, parts, index) {
64
- let value = 0;
65
- for (let part = 0; part < index; part += 1) {
66
- value += dimension(total, parts, part);
67
- }
68
- return value;
69
- }
70
-
71
- function agentGeometry(index, count, sidebarWidth, terminalColumns, terminalRows) {
72
- const mainColumns = Math.max(1, terminalColumns - sidebarWidth);
73
- const grid = agentGrid(count);
74
- const column = index % grid.columns;
75
- const row = Math.floor(index / grid.columns);
76
- return {
77
- x: sidebarWidth + offset(mainColumns, grid.columns, column),
78
- y: offset(terminalRows, grid.rows, row),
79
- width: dimension(mainColumns, grid.columns, column),
80
- height: dimension(terminalRows, grid.rows, row),
81
- };
82
- }
83
-
84
- function sidebarPane(sessionName, sidebarWidth, terminalRows, command) {
85
- return {
86
- role: 'sidebar',
87
- target: paneTarget(sessionName, 0),
88
- width: sidebarWidth,
89
- height: terminalRows,
90
- command,
91
- };
92
- }
93
-
94
- function agentCommand(session) {
95
- if (session.command) return session.command;
96
- if (!session.worktreePath) return 'gx agents status';
97
- return `cd ${shellQuote(session.worktreePath)} && exec ${'${SHELL:-bash}'}`;
98
- }
99
-
100
- function agentPane(sessionName, session, index, count, selectedSessionId, sidebarWidth, terminalColumns, terminalRows) {
101
- return {
102
- role: 'agent',
103
- target: paneTarget(sessionName, index + 1),
104
- sessionId: session.sessionId,
105
- branch: session.branch,
106
- worktreePath: session.worktreePath,
107
- selected: session.sessionId === selectedSessionId,
108
- command: agentCommand(session),
109
- ...agentGeometry(index, count, sidebarWidth, terminalColumns, terminalRows),
110
- };
111
- }
112
-
113
- function detailsPane(sessionName, paneIndex, sidebarWidth, terminalColumns, terminalRows, command) {
114
- return {
115
- role: 'details',
116
- target: paneTarget(sessionName, paneIndex),
117
- x: sidebarWidth,
118
- y: 0,
119
- width: Math.max(1, terminalColumns - sidebarWidth),
120
- height: terminalRows,
121
- command,
122
- };
123
- }
124
-
125
- function sendKeysCommand(role, target, command) {
126
- return {
127
- role,
128
- args: ['send-keys', '-t', target, command, 'C-m'],
129
- };
130
- }
131
-
132
- function buildTmuxCommands(plan) {
133
- const commands = [
134
- {
135
- role: 'session',
136
- args: ['new-session', '-d', '-s', plan.sessionName],
137
- },
138
- sendKeysCommand('sidebar', plan.panes[0].target, plan.panes[0].command),
139
- ];
140
-
141
- const contentPanes = plan.panes.filter((pane) => pane.role !== 'sidebar');
142
- if (contentPanes.length > 0) {
143
- commands.push({
144
- role: 'content',
145
- args: ['split-window', '-h', '-t', plan.panes[0].target],
146
- });
147
- commands.push({
148
- role: 'sidebar',
149
- args: ['resize-pane', '-t', plan.panes[0].target, '-x', String(plan.sidebarWidth)],
150
- });
151
- }
152
-
153
- for (let index = 1; index < contentPanes.length; index += 1) {
154
- commands.push({
155
- role: contentPanes[index].role,
156
- args: ['split-window', index % 2 === 1 ? '-h' : '-v', '-t', contentPanes[index - 1].target],
157
- });
158
- }
159
-
160
- if (contentPanes.filter((pane) => pane.role === 'agent').length > 1) {
161
- commands.push({
162
- role: 'layout',
163
- args: ['select-layout', '-t', windowTarget(plan.sessionName), 'tiled'],
164
- });
165
- commands.push({
166
- role: 'sidebar',
167
- args: ['resize-pane', '-t', plan.panes[0].target, '-x', String(plan.sidebarWidth)],
168
- });
169
- }
170
-
171
- for (const pane of contentPanes) {
172
- commands.push(sendKeysCommand(pane.role, pane.target, pane.command));
173
- }
174
-
175
- return commands;
176
- }
177
-
178
- function planCockpitLayout(options = {}) {
179
- const sessions = normalizeSessions(options.sessions);
180
- const terminalColumns = positiveInteger(options.terminalColumns, DEFAULT_TERMINAL_COLUMNS);
181
- const terminalRows = positiveInteger(options.terminalRows, DEFAULT_TERMINAL_ROWS);
182
- const sessionName = text(options.sessionName, DEFAULT_SESSION_NAME);
183
- const sidebarWidth = sidebarWidthFor(options.sidebarWidth, terminalColumns);
184
- const sidebarCommand = text(options.sidebarCommand, 'gx agents status');
185
- const selectedSessionId = text(options.selectedSessionId);
186
- const panes = [
187
- sidebarPane(sessionName, sidebarWidth, terminalRows, sidebarCommand),
188
- ];
189
-
190
- if (sessions.length === 0) {
191
- panes.push(detailsPane(sessionName, 1, sidebarWidth, terminalColumns, terminalRows, 'gx agents status'));
192
- } else {
193
- sessions.forEach((session, index) => {
194
- panes.push(agentPane(
195
- sessionName,
196
- session,
197
- index,
198
- sessions.length,
199
- selectedSessionId,
200
- sidebarWidth,
201
- terminalColumns,
202
- terminalRows,
203
- ));
204
- });
205
- }
206
-
207
- const plan = {
208
- sessionName,
209
- terminalColumns,
210
- terminalRows,
211
- sidebarWidth,
212
- panes,
213
- };
214
- return {
215
- ...plan,
216
- tmuxCommands: buildTmuxCommands(plan),
217
- };
218
- }
219
-
220
- module.exports = {
221
- DEFAULT_SESSION_NAME,
222
- DEFAULT_SIDEBAR_WIDTH,
223
- planCockpitLayout,
224
- };