@imdeadpool/guardex 7.0.41 → 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 (118) hide show
  1. package/README.md +94 -13
  2. package/package.json +3 -1
  3. package/skills/gitguardex/SKILL.md +13 -0
  4. package/skills/guardex-merge-skills-to-dev/SKILL.md +59 -0
  5. package/skills/gx-act/SKILL.md +82 -0
  6. package/src/agents/cleanup-sessions.js +126 -0
  7. package/src/agents/finish.js +172 -0
  8. package/src/agents/inspect.js +202 -0
  9. package/src/agents/launch.js +249 -0
  10. package/src/agents/registry.js +133 -0
  11. package/src/agents/selection-panel.js +571 -0
  12. package/src/agents/sessions.js +151 -0
  13. package/src/agents/start.js +591 -0
  14. package/src/agents/status.js +146 -0
  15. package/src/agents/terminal.js +152 -0
  16. package/src/budget/index.js +344 -0
  17. package/src/ci-init/index.js +265 -0
  18. package/src/cli/args.js +357 -3
  19. package/src/cli/commands/agents.js +364 -0
  20. package/src/cli/commands/bootstrap.js +92 -0
  21. package/src/cli/commands/branch.js +127 -0
  22. package/src/cli/commands/claude.js +674 -0
  23. package/src/cli/commands/doctor.js +268 -0
  24. package/src/cli/commands/finish.js +26 -0
  25. package/src/cli/commands/mcp.js +122 -0
  26. package/src/cli/commands/misc.js +304 -0
  27. package/src/cli/commands/pr.js +439 -0
  28. package/src/cli/commands/prompt.js +92 -0
  29. package/src/cli/commands/release.js +305 -0
  30. package/src/cli/commands/report.js +244 -0
  31. package/src/cli/commands/review.js +32 -0
  32. package/src/cli/commands/setup.js +242 -0
  33. package/src/cli/commands/status.js +338 -0
  34. package/src/cli/commands/watch.js +234 -0
  35. package/src/cli/main.js +85 -3613
  36. package/src/cli/shared/repo-env.js +161 -0
  37. package/src/cli/shared/sandbox.js +417 -0
  38. package/src/cli/shared/scaffolding.js +535 -0
  39. package/src/cli/shared/toolchain-shims.js +420 -0
  40. package/src/cockpit/action-runner.js +3 -0
  41. package/src/cockpit/actions.js +80 -0
  42. package/src/cockpit/control.js +1121 -0
  43. package/src/cockpit/index.js +426 -0
  44. package/src/cockpit/kitty-layout.js +549 -0
  45. package/src/cockpit/kitty-tree.js +144 -0
  46. package/src/cockpit/logs-reader.js +182 -0
  47. package/src/cockpit/menu.js +204 -0
  48. package/src/cockpit/pane-actions.js +597 -0
  49. package/src/cockpit/pane-menu.js +387 -0
  50. package/src/cockpit/projects-finder.js +178 -0
  51. package/src/cockpit/render.js +215 -0
  52. package/src/cockpit/settings-render.js +128 -0
  53. package/src/cockpit/settings.js +124 -0
  54. package/src/cockpit/shortcuts.js +24 -0
  55. package/src/cockpit/sidebar.js +311 -0
  56. package/src/cockpit/state.js +72 -0
  57. package/src/cockpit/theme.js +128 -0
  58. package/src/cockpit/welcome.js +266 -0
  59. package/src/context.js +304 -43
  60. package/src/core/runtime.js +6 -1
  61. package/src/doctor/index.js +45 -15
  62. package/src/finish/index.js +186 -7
  63. package/src/finish/preflight.js +177 -0
  64. package/src/finish/review-gate.js +182 -0
  65. package/src/git/index.js +511 -4
  66. package/src/hooks/index.js +0 -64
  67. package/src/kitty/command.js +101 -0
  68. package/src/kitty/runtime.js +250 -0
  69. package/src/mcp/collect.js +370 -0
  70. package/src/mcp/server.js +157 -0
  71. package/src/output/index.js +68 -2
  72. package/src/pr-review.js +264 -0
  73. package/src/pr.js +381 -0
  74. package/src/sandbox/index.js +13 -2
  75. package/src/scaffold/agent-worktree-prep.js +213 -0
  76. package/src/scaffold/index.js +127 -10
  77. package/src/speckit/index.js +226 -0
  78. package/src/submodule/index.js +288 -0
  79. package/src/terminal/index.js +45 -0
  80. package/src/terminal/kitty.js +622 -0
  81. package/src/terminal/tmux.js +125 -0
  82. package/src/tmux/command.js +27 -0
  83. package/src/tmux/session.js +89 -0
  84. package/src/toolchain/index.js +20 -0
  85. package/templates/AGENTS.monorepo-apps.md +26 -0
  86. package/templates/AGENTS.multiagent-safety.md +63 -323
  87. package/templates/AGENTS.multiagent-safety.min.md +11 -0
  88. package/templates/codex/skills/gitguardex/SKILL.md +2 -0
  89. package/templates/codex/skills/gx-act/SKILL.md +82 -0
  90. package/templates/githooks/pre-commit +44 -20
  91. package/templates/github/workflows/README.md +87 -0
  92. package/templates/github/workflows/ci-full.yml +55 -0
  93. package/templates/github/workflows/ci.yml +56 -0
  94. package/templates/github/workflows/cr.yml +20 -1
  95. package/templates/scripts/agent-branch-finish.sh +519 -23
  96. package/templates/scripts/agent-branch-merge.sh +4 -1
  97. package/templates/scripts/agent-branch-start.sh +176 -24
  98. package/templates/scripts/agent-preflight.sh +115 -0
  99. package/templates/scripts/agent-worktree-prune.sh +96 -5
  100. package/templates/scripts/codex-agent.sh +41 -97
  101. package/templates/scripts/openspec/init-plan-workspace.sh +43 -0
  102. package/templates/scripts/review-bot-watch.sh +31 -2
  103. package/templates/scripts/agent-session-state.js +0 -171
  104. package/templates/scripts/install-vscode-active-agents-extension.js +0 -135
  105. package/templates/vscode/guardex-active-agents/README.md +0 -34
  106. package/templates/vscode/guardex-active-agents/extension.js +0 -3782
  107. package/templates/vscode/guardex-active-agents/fileicons/gitguardex-fileicons.json +0 -54
  108. package/templates/vscode/guardex-active-agents/fileicons/icons/agent.svg +0 -5
  109. package/templates/vscode/guardex-active-agents/fileicons/icons/branch.svg +0 -7
  110. package/templates/vscode/guardex-active-agents/fileicons/icons/config.svg +0 -4
  111. package/templates/vscode/guardex-active-agents/fileicons/icons/hook.svg +0 -4
  112. package/templates/vscode/guardex-active-agents/fileicons/icons/openspec.svg +0 -5
  113. package/templates/vscode/guardex-active-agents/fileicons/icons/plan.svg +0 -4
  114. package/templates/vscode/guardex-active-agents/fileicons/icons/spec.svg +0 -5
  115. package/templates/vscode/guardex-active-agents/icon.png +0 -0
  116. package/templates/vscode/guardex-active-agents/media/active-agents-hivemind.svg +0 -14
  117. package/templates/vscode/guardex-active-agents/package.json +0 -169
  118. package/templates/vscode/guardex-active-agents/session-schema.js +0 -1348
@@ -0,0 +1,182 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ const DEFAULT_TAIL_BYTES = 32 * 1024;
7
+ const DEFAULT_LIMIT = 200;
8
+ const DEFAULT_LOG_GLOBS = ['apps/logs', '.omc/logs', '.omx/logs'];
9
+
10
+ const LEVELS = ['info', 'warning', 'error', 'debug'];
11
+ const LEVEL_PATTERNS = [
12
+ { level: 'error', regex: /\b(error|err|exception|fail(?:ed|ure)?|fatal|panic|traceback)\b/i },
13
+ { level: 'warning', regex: /\b(warn|warning|deprecated|caution)\b/i },
14
+ { level: 'debug', regex: /\b(debug|trace|verbose)\b/i },
15
+ ];
16
+
17
+ function text(value, fallback = '') {
18
+ if (typeof value === 'string') return value || fallback;
19
+ if (value === null || value === undefined) return fallback;
20
+ return String(value) || fallback;
21
+ }
22
+
23
+ function classifyLevel(line) {
24
+ for (const { level, regex } of LEVEL_PATTERNS) {
25
+ if (regex.test(line)) return level;
26
+ }
27
+ return 'info';
28
+ }
29
+
30
+ function pickFs(options = {}) {
31
+ return options.fs || fs;
32
+ }
33
+
34
+ function listLogPaths(root, options = {}) {
35
+ const fsImpl = pickFs(options);
36
+ const globs = Array.isArray(options.globs) && options.globs.length > 0 ? options.globs : DEFAULT_LOG_GLOBS;
37
+ const seen = new Set();
38
+ const paths = [];
39
+
40
+ for (const glob of globs) {
41
+ const dir = path.isAbsolute(glob) ? glob : path.join(root, glob);
42
+ pushLogsFromDir(dir, fsImpl, seen, paths);
43
+ }
44
+
45
+ return paths;
46
+ }
47
+
48
+ function pushLogsFromDir(dir, fsImpl, seen, paths) {
49
+ let entries;
50
+ try {
51
+ entries = fsImpl.readdirSync(dir, { withFileTypes: true });
52
+ } catch (_error) {
53
+ return;
54
+ }
55
+ for (const entry of entries) {
56
+ const full = path.join(dir, entry.name);
57
+ if (entry.isDirectory()) {
58
+ pushLogsFromDir(full, fsImpl, seen, paths);
59
+ continue;
60
+ }
61
+ if (!entry.isFile()) continue;
62
+ if (!entry.name.endsWith('.log')) continue;
63
+ if (seen.has(full)) continue;
64
+ seen.add(full);
65
+ paths.push(full);
66
+ }
67
+ }
68
+
69
+ function tailFile(file, options = {}) {
70
+ const fsImpl = pickFs(options);
71
+ const tailBytes = Number.isFinite(options.tailBytes) && options.tailBytes > 0
72
+ ? options.tailBytes
73
+ : DEFAULT_TAIL_BYTES;
74
+ let stat;
75
+ try {
76
+ stat = fsImpl.statSync(file, { throwIfNoEntry: false });
77
+ } catch (_error) {
78
+ return [];
79
+ }
80
+ if (!stat) return [];
81
+
82
+ const size = Number.isFinite(stat.size) ? stat.size : 0;
83
+ const start = size > tailBytes ? size - tailBytes : 0;
84
+
85
+ let content = '';
86
+ try {
87
+ if (typeof fsImpl.openSync === 'function' && typeof fsImpl.readSync === 'function' && typeof fsImpl.closeSync === 'function' && start > 0) {
88
+ const fd = fsImpl.openSync(file, 'r');
89
+ try {
90
+ const buffer = Buffer.alloc(size - start);
91
+ fsImpl.readSync(fd, buffer, 0, buffer.length, start);
92
+ content = buffer.toString('utf8');
93
+ } finally {
94
+ fsImpl.closeSync(fd);
95
+ }
96
+ } else if (typeof fsImpl.readFileSync === 'function') {
97
+ content = fsImpl.readFileSync(file, 'utf8');
98
+ if (content.length > tailBytes) content = content.slice(content.length - tailBytes);
99
+ }
100
+ } catch (_error) {
101
+ return [];
102
+ }
103
+
104
+ const lines = content.split('\n');
105
+ return lines.map((line, index) => ({ line, partial: index === 0 && start > 0 }));
106
+ }
107
+
108
+ function readLogs(options = {}) {
109
+ const root = text(options.repoRoot || options.root || process.cwd(), process.cwd());
110
+ const limit = Number.isFinite(options.limit) && options.limit > 0 ? options.limit : DEFAULT_LIMIT;
111
+ const sources = options.sources || listLogPaths(root, options);
112
+ const entries = [];
113
+
114
+ for (const source of sources) {
115
+ const tail = tailFile(source, options);
116
+ const sourceName = path.relative(root, source) || source;
117
+ for (let i = 0; i < tail.length; i += 1) {
118
+ const { line, partial } = tail[i];
119
+ if (partial && i === 0) continue;
120
+ const trimmed = line.replace(/\r$/, '');
121
+ if (!trimmed) continue;
122
+ entries.push({
123
+ source: sourceName,
124
+ line: trimmed,
125
+ level: classifyLevel(trimmed),
126
+ });
127
+ }
128
+ }
129
+
130
+ if (entries.length > limit) {
131
+ entries.splice(0, entries.length - limit);
132
+ }
133
+
134
+ return {
135
+ entries,
136
+ sources: sources.map((source) => path.relative(root, source) || source),
137
+ counts: tallyLevels(entries),
138
+ };
139
+ }
140
+
141
+ function tallyLevels(entries) {
142
+ const counts = { all: entries.length };
143
+ for (const level of LEVELS) counts[level] = 0;
144
+ for (const entry of entries) {
145
+ counts[entry.level] = (counts[entry.level] || 0) + 1;
146
+ }
147
+ return counts;
148
+ }
149
+
150
+ function filterEntries(entries, filter) {
151
+ const value = String(filter || 'all').toLowerCase();
152
+ if (value === 'all' || value === '') return entries.slice();
153
+ if (value === 'by-pane' || value === 'by-source') {
154
+ const groups = new Map();
155
+ for (const entry of entries) {
156
+ const key = entry.source || 'unknown';
157
+ const arr = groups.get(key) || [];
158
+ arr.push(entry);
159
+ groups.set(key, arr);
160
+ }
161
+ const ordered = [];
162
+ for (const [, arr] of groups) ordered.push(...arr);
163
+ return ordered;
164
+ }
165
+ if (LEVELS.includes(value)) {
166
+ return entries.filter((entry) => entry.level === value);
167
+ }
168
+ return entries.slice();
169
+ }
170
+
171
+ module.exports = {
172
+ DEFAULT_LIMIT,
173
+ DEFAULT_LOG_GLOBS,
174
+ DEFAULT_TAIL_BYTES,
175
+ LEVELS,
176
+ classifyLevel,
177
+ filterEntries,
178
+ listLogPaths,
179
+ readLogs,
180
+ tailFile,
181
+ tallyLevels,
182
+ };
@@ -0,0 +1,204 @@
1
+ 'use strict';
2
+
3
+ const paneMenu = require('./pane-menu');
4
+ const { colorize, getCockpitTheme, stripAnsi } = require('./theme');
5
+
6
+ const {
7
+ PANE_MENU_ACTIONS,
8
+ PANE_MENU_ACTION_IDS,
9
+ PANE_MENU_FOOTER,
10
+ normalizePaneMenuKey,
11
+ } = paneMenu;
12
+
13
+ const PANE_MENU_ITEMS = Object.freeze([
14
+ { id: PANE_MENU_ACTION_IDS.VIEW, label: 'View', hotkey: 'v', needsSession: true },
15
+ { id: PANE_MENU_ACTION_IDS.HIDE_PANE, label: 'Hide Pane', hotkey: 'h', needsSession: true },
16
+ { id: PANE_MENU_ACTION_IDS.CLOSE, label: 'Close', hotkey: 'x', danger: true, needsSession: true },
17
+ { id: PANE_MENU_ACTION_IDS.MERGE, label: 'Merge / Finish', hotkey: 'm', needsSession: true, needsWorktree: true, needsBranch: true },
18
+ { id: PANE_MENU_ACTION_IDS.CREATE_PR, label: 'Create GitHub PR', hotkey: 'p', needsSession: true, needsWorktree: true, needsBranch: true },
19
+ { id: PANE_MENU_ACTION_IDS.RENAME, label: 'Rename', hotkey: 'r', needsSession: true },
20
+ { id: PANE_MENU_ACTION_IDS.COPY_PATH, label: 'Copy Path', hotkey: 'c', needsSession: true, needsWorktree: true },
21
+ { id: PANE_MENU_ACTION_IDS.OPEN_EDITOR, label: 'Open in Editor', hotkey: 'o', needsSession: true, needsWorktree: true },
22
+ { id: PANE_MENU_ACTION_IDS.TOGGLE_AUTOPILOT, label: 'Toggle Autopilot', hotkey: 'a', needsSession: true, needsWorktree: true, needsBranch: true },
23
+ { id: PANE_MENU_ACTION_IDS.CREATE_CHILD_WORKTREE, label: 'Create Child Worktree', hotkey: 'b', needsSession: true, needsWorktree: true, needsBranch: true },
24
+ { id: PANE_MENU_ACTION_IDS.BROWSE_FILES, label: 'Browse Files', hotkey: 'f', needsSession: true, needsWorktree: true },
25
+ { id: PANE_MENU_ACTION_IDS.ADD_TERMINAL, label: 'Add Terminal to Worktree', hotkey: 'T', needsSession: true, needsWorktree: true },
26
+ { id: PANE_MENU_ACTION_IDS.ADD_AGENT, label: 'Add Agent to Worktree', hotkey: 'A', needsSession: true, needsWorktree: true, needsBranch: true },
27
+ ]);
28
+
29
+ function firstString(...values) {
30
+ for (const value of values) {
31
+ if (typeof value === 'string' && value.trim().length > 0) {
32
+ return value.trim();
33
+ }
34
+ }
35
+ return '';
36
+ }
37
+
38
+ function fileName(value) {
39
+ const text = String(value || '').replace(/[/\\]+$/, '');
40
+ const parts = text.split(/[/\\]+/).filter(Boolean);
41
+ return parts[parts.length - 1] || '';
42
+ }
43
+
44
+ function selectedPaneName(session = {}, context = {}) {
45
+ return firstString(
46
+ context.name,
47
+ session.displayName,
48
+ session.paneName,
49
+ session.name,
50
+ session.agentName,
51
+ session.agent,
52
+ fileName(session.worktreePath),
53
+ fileName(session.path),
54
+ session.branch,
55
+ session.id,
56
+ 'selected pane',
57
+ );
58
+ }
59
+
60
+ function paneMenuTitle(name) {
61
+ const text = String(name || '').trim() || 'selected pane';
62
+ return text.startsWith('Menu:') ? text : `Menu: ${text}`;
63
+ }
64
+
65
+ function selectedSession(context = {}) {
66
+ return context.session || context.selectedSession || context.pane || context.lane || null;
67
+ }
68
+
69
+ function resolveBranch(session = {}, context = {}) {
70
+ return firstString(
71
+ context.branch,
72
+ session.branch,
73
+ session.lane && session.lane.branch,
74
+ );
75
+ }
76
+
77
+ function resolveWorktreePath(session = {}, context = {}) {
78
+ return firstString(
79
+ context.worktreePath,
80
+ context.path,
81
+ session.worktreePath,
82
+ session.worktree && session.worktree.path,
83
+ session.path,
84
+ );
85
+ }
86
+
87
+ function resolveWorktreeExists(session = {}, context = {}, worktreePath = '') {
88
+ if (typeof context.worktreeExists === 'boolean') return context.worktreeExists;
89
+ if (typeof session.worktreeExists === 'boolean') return session.worktreeExists;
90
+ return worktreePath.length > 0;
91
+ }
92
+
93
+ function disabledReason(item, context) {
94
+ if (item.needsSession && !context.selected) return 'No pane selected';
95
+
96
+ const reasons = [];
97
+ if (item.needsWorktree && !context.worktreeExists) reasons.push('Worktree missing');
98
+ if (item.needsBranch && !context.branch) reasons.push('Branch missing');
99
+ return reasons.join('; ');
100
+ }
101
+
102
+ function createPaneMenuItems(context) {
103
+ return PANE_MENU_ITEMS.map((item) => {
104
+ const reason = disabledReason(item, context);
105
+ return {
106
+ id: item.id,
107
+ label: item.label,
108
+ hotkey: item.hotkey,
109
+ shortcut: item.hotkey,
110
+ enabled: reason.length === 0,
111
+ danger: Boolean(item.danger),
112
+ reason,
113
+ };
114
+ });
115
+ }
116
+
117
+ function createPaneMenuState(options = {}) {
118
+ const session = selectedSession(options);
119
+ const selected = Boolean(session) && options.selected !== false;
120
+ const source = session || {};
121
+ const branch = selected ? resolveBranch(source, options) : '';
122
+ const worktreePath = selected ? resolveWorktreePath(source, options) : '';
123
+ const context = {
124
+ selected,
125
+ branch,
126
+ worktreePath,
127
+ worktreeExists: selected && resolveWorktreeExists(source, options, worktreePath),
128
+ };
129
+ const items = Array.isArray(options.items) && options.items.length > 0
130
+ ? options.items.map((item) => ({ ...item }))
131
+ : createPaneMenuItems(context);
132
+
133
+ return paneMenu.createPaneMenuState({
134
+ ...options,
135
+ session,
136
+ title: paneMenuTitle(firstString(options.title, selectedPaneName(source, options))),
137
+ items,
138
+ });
139
+ }
140
+
141
+ function applyPaneMenuKey(state = {}, rawKey) {
142
+ return paneMenu.applyPaneMenuKey(createPaneMenuState(state), rawKey);
143
+ }
144
+
145
+ function themeMenuLine(line, state, theme) {
146
+ const plain = stripAnsi(line);
147
+ if (/^[┌├└+]/.test(plain)) {
148
+ return colorize(line, 'border', theme);
149
+ }
150
+ if (plain.includes('Menu:')) {
151
+ return colorize(line, 'title', theme);
152
+ }
153
+ if (plain.includes('status:')) {
154
+ return colorize(line, 'warning', theme);
155
+ }
156
+ if (plain.includes('Close')) {
157
+ return colorize(line, plain.includes('>') ? 'selected' : 'danger', theme);
158
+ }
159
+ if (plain.includes('>')) {
160
+ return colorize(line, 'selected', theme);
161
+ }
162
+ if (plain.includes(PANE_MENU_FOOTER)) {
163
+ return colorize(line, 'secondary', theme);
164
+ }
165
+ return line;
166
+ }
167
+
168
+ function applyMenuTheme(output, state, options) {
169
+ const theme = getCockpitTheme(options.theme || state.theme || (state.settings && state.settings.theme), options);
170
+ if (!theme.color) {
171
+ return output;
172
+ }
173
+ return `${String(output).replace(/\n$/, '').split('\n').map((line) => themeMenuLine(line, state, theme)).join('\n')}\n`;
174
+ }
175
+
176
+ function renderPaneMenu(state = {}, options = {}) {
177
+ const selectedIndex = Number.isInteger(options.selectedIndex)
178
+ ? options.selectedIndex
179
+ : state.selectedIndex;
180
+ const current = createPaneMenuState({ ...state, selectedIndex });
181
+ const output = paneMenu.renderPaneMenu(current, options).replace(/\u25b6/g, '>');
182
+ return applyMenuTheme(output, current, options);
183
+ }
184
+
185
+ function buildLaneMenu(session, context = {}) {
186
+ return createPaneMenuState({ ...context, session });
187
+ }
188
+
189
+ function renderLaneMenu(menu, options = {}) {
190
+ return renderPaneMenu(menu, options);
191
+ }
192
+
193
+ module.exports = {
194
+ PANE_MENU_ACTIONS,
195
+ PANE_MENU_ACTION_IDS,
196
+ PANE_MENU_FOOTER,
197
+ PANE_MENU_ITEMS,
198
+ applyPaneMenuKey,
199
+ buildLaneMenu,
200
+ createPaneMenuState,
201
+ normalizePaneMenuKey,
202
+ renderLaneMenu,
203
+ renderPaneMenu,
204
+ };