@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,125 @@
1
+ 'use strict';
2
+
3
+ const tmuxCommand = require('../tmux/command');
4
+ const tmuxSession = require('../tmux/session');
5
+
6
+ function text(value, fallback = '') {
7
+ if (typeof value === 'string') return value.trim() || fallback;
8
+ if (value === null || value === undefined) return fallback;
9
+ return String(value).trim() || fallback;
10
+ }
11
+
12
+ function requireText(value, name) {
13
+ const normalized = text(value);
14
+ if (!normalized) {
15
+ throw new TypeError(`${name} must be a non-empty string`);
16
+ }
17
+ return normalized;
18
+ }
19
+
20
+ function targetId(target) {
21
+ if (target && typeof target === 'object') {
22
+ return requireText(target.paneId || target.tmuxPaneId || target.tmuxTarget || target.id || target.target, 'tmux target');
23
+ }
24
+ return requireText(target, 'tmux target');
25
+ }
26
+
27
+ function assertStatus(result, message) {
28
+ if (result && result.error) throw result.error;
29
+ if (!result || result.status === 0) return result;
30
+ const detail = String(result.stderr || result.stdout || '').trim();
31
+ throw new Error(`${message}${detail ? `: ${detail}` : '.'}`);
32
+ }
33
+
34
+ function defaultTmuxApi() {
35
+ return {
36
+ ensureTmuxAvailable: tmuxSession.ensureTmuxAvailable,
37
+ sessionExists: tmuxSession.sessionExists,
38
+ createSession: tmuxSession.createSession,
39
+ attachSession: tmuxSession.attachSession,
40
+ newWindowOrPane: tmuxSession.newWindowOrPane,
41
+ sendKeys: tmuxSession.sendKeys,
42
+ };
43
+ }
44
+
45
+ function createBackend(options = {}) {
46
+ const tmux = options.tmux || defaultTmuxApi();
47
+ const runTmux = typeof options.runTmux === 'function' ? options.runTmux : tmuxCommand.runTmux;
48
+
49
+ return {
50
+ name: 'tmux',
51
+ isAvailable() {
52
+ try {
53
+ if (typeof tmux.isAvailable === 'function') return Boolean(tmux.isAvailable());
54
+ tmux.ensureTmuxAvailable();
55
+ return true;
56
+ } catch (_error) {
57
+ return false;
58
+ }
59
+ },
60
+ openCockpitLayout(config = {}) {
61
+ const sessionName = requireText(config.sessionName, 'tmux sessionName');
62
+ const repoRoot = requireText(config.repoRoot, 'tmux repoRoot');
63
+ const command = requireText(config.command, 'tmux cockpit command');
64
+
65
+ tmux.ensureTmuxAvailable();
66
+
67
+ if (tmux.sessionExists(sessionName)) {
68
+ assertStatus(tmux.attachSession(sessionName), `tmux could not attach session '${sessionName}'`);
69
+ return { action: 'attached', sessionName, repoRoot };
70
+ }
71
+
72
+ assertStatus(
73
+ tmux.createSession(sessionName, repoRoot),
74
+ `tmux could not create session '${sessionName}'`,
75
+ );
76
+ assertStatus(
77
+ tmux.sendKeys(sessionName, command),
78
+ 'tmux could not start cockpit control pane',
79
+ );
80
+
81
+ if (config.attach) {
82
+ assertStatus(tmux.attachSession(sessionName), `tmux could not attach session '${sessionName}'`);
83
+ return { action: 'created-attached', sessionName, repoRoot };
84
+ }
85
+ return { action: 'created', sessionName, repoRoot };
86
+ },
87
+ launchAgentPane(config = {}) {
88
+ const session = config.session && typeof config.session === 'object' ? config.session : {};
89
+ const cwd = requireText(config.worktree || session.worktreePath || session.path, 'tmux agent worktree');
90
+ const result = tmux.newWindowOrPane({
91
+ pane: true,
92
+ split: 'horizontal',
93
+ target: config.target || session.tmuxTarget || session.tmuxSession || session.sessionName,
94
+ cwd,
95
+ name: config.title || session.title,
96
+ });
97
+ return assertStatus(result, 'tmux could not launch agent pane');
98
+ },
99
+ launchTerminalPane(config = {}) {
100
+ const result = tmux.newWindowOrPane({
101
+ pane: true,
102
+ split: 'horizontal',
103
+ target: config.target,
104
+ cwd: requireText(config.cwd, 'tmux terminal cwd'),
105
+ name: config.title,
106
+ });
107
+ return assertStatus(result, 'tmux could not launch terminal pane');
108
+ },
109
+ focusPane(target) {
110
+ return assertStatus(runTmux(['select-pane', '-t', targetId(target)]), 'tmux could not focus pane');
111
+ },
112
+ closePane(target) {
113
+ return assertStatus(runTmux(['kill-pane', '-t', targetId(target)]), 'tmux could not close pane');
114
+ },
115
+ sendText(target, value, options = {}) {
116
+ const args = ['send-keys', '-t', targetId(target), String(value === undefined || value === null ? '' : value)];
117
+ if (options.submit) args.push('C-m');
118
+ return assertStatus(runTmux(args), 'tmux could not send text');
119
+ },
120
+ };
121
+ }
122
+
123
+ module.exports = {
124
+ createBackend,
125
+ };
@@ -0,0 +1,27 @@
1
+ const runtime = require('../core/runtime');
2
+
3
+ function assertArgs(args) {
4
+ if (!Array.isArray(args)) {
5
+ throw new TypeError('tmux args must be an array');
6
+ }
7
+ for (const arg of args) {
8
+ if (typeof arg !== 'string') {
9
+ throw new TypeError('tmux args must contain only strings');
10
+ }
11
+ }
12
+ }
13
+
14
+ function runTmux(args, options = {}) {
15
+ assertArgs(args);
16
+ return runtime.run(process.env.GUARDEX_TMUX_BIN || 'tmux', args, options);
17
+ }
18
+
19
+ function isTmuxAvailable() {
20
+ const result = runTmux(['-V'], { stdio: 'pipe' });
21
+ return result.status === 0 && !result.error;
22
+ }
23
+
24
+ module.exports = {
25
+ isTmuxAvailable,
26
+ runTmux,
27
+ };
@@ -0,0 +1,89 @@
1
+ const tmux = require('./command');
2
+
3
+ function requireName(name) {
4
+ if (typeof name !== 'string' || name.trim() === '') {
5
+ throw new TypeError('tmux session name must be a non-empty string');
6
+ }
7
+ return name;
8
+ }
9
+
10
+ function addCwd(args, cwd) {
11
+ if (cwd !== undefined) {
12
+ if (typeof cwd !== 'string' || cwd.trim() === '') {
13
+ throw new TypeError('tmux cwd must be a non-empty string');
14
+ }
15
+ args.push('-c', cwd);
16
+ }
17
+ }
18
+
19
+ function ensureTmuxAvailable() {
20
+ if (tmux.isTmuxAvailable()) return;
21
+ throw new Error('tmux is required for gx cockpit. Install tmux and retry.');
22
+ }
23
+
24
+ function sessionExists(name) {
25
+ const result = tmux.runTmux(['has-session', '-t', requireName(name)], {
26
+ stdio: 'pipe',
27
+ });
28
+ return result.status === 0;
29
+ }
30
+
31
+ function createSession(name, cwd) {
32
+ const args = ['new-session', '-d', '-s', requireName(name)];
33
+ addCwd(args, cwd);
34
+ return tmux.runTmux(args);
35
+ }
36
+
37
+ function attachSession(name) {
38
+ return tmux.runTmux(['attach-session', '-t', requireName(name)], {
39
+ stdio: 'inherit',
40
+ });
41
+ }
42
+
43
+ function newWindowOrPane(options = {}) {
44
+ const {
45
+ target,
46
+ cwd,
47
+ name,
48
+ pane = false,
49
+ split = 'vertical',
50
+ } = options;
51
+ const args = pane ? ['split-window'] : ['new-window'];
52
+
53
+ if (pane) {
54
+ if (split === 'horizontal') {
55
+ args.push('-h');
56
+ } else if (split === 'vertical') {
57
+ args.push('-v');
58
+ } else {
59
+ throw new TypeError('tmux split must be horizontal or vertical');
60
+ }
61
+ }
62
+ if (target !== undefined) {
63
+ args.push('-t', requireName(target));
64
+ }
65
+ if (!pane && name !== undefined) {
66
+ args.push('-n', requireName(name));
67
+ }
68
+ addCwd(args, cwd);
69
+ return tmux.runTmux(args);
70
+ }
71
+
72
+ function sendKeys(paneId, command) {
73
+ if (typeof paneId !== 'string' || paneId.trim() === '') {
74
+ throw new TypeError('tmux pane id must be a non-empty string');
75
+ }
76
+ if (typeof command !== 'string') {
77
+ throw new TypeError('tmux command must be a string');
78
+ }
79
+ return tmux.runTmux(['send-keys', '-t', paneId, command, 'C-m']);
80
+ }
81
+
82
+ module.exports = {
83
+ ensureTmuxAvailable,
84
+ sessionExists,
85
+ createSession,
86
+ attachSession,
87
+ newWindowOrPane,
88
+ sendKeys,
89
+ };
@@ -293,7 +293,24 @@ function buildMissingCompanionInstallPrompt(missingPackages, missingLocalTools)
293
293
  return `${dependencyPrefix}Install missing companion tools now? (${installCommands.join(' && ')})`;
294
294
  }
295
295
 
296
+ // Process-scoped memo for the slow `npm list -g` probe (~1.6-2.4s). Detection is
297
+ // invariant within one gx invocation, but the bare-`gx`/`gx status` path queries
298
+ // it twice (self-update check + status snapshot). Busted after a global install.
299
+ let globalToolchainDetectionCache = null;
300
+
301
+ function resetGlobalToolchainDetectionCache() {
302
+ globalToolchainDetectionCache = null;
303
+ }
304
+
296
305
  function detectGlobalToolchainPackages() {
306
+ if (globalToolchainDetectionCache) {
307
+ return globalToolchainDetectionCache;
308
+ }
309
+ globalToolchainDetectionCache = computeGlobalToolchainPackages();
310
+ return globalToolchainDetectionCache;
311
+ }
312
+
313
+ function computeGlobalToolchainPackages() {
297
314
  const result = run(NPM_BIN, ['list', '-g', '--depth=0', '--json']);
298
315
  if (result.status !== 0) {
299
316
  const stderr = (result.stderr || '').trim();
@@ -563,6 +580,8 @@ function performCompanionInstall(missingPackages, missingLocalTools) {
563
580
  };
564
581
  }
565
582
  installed.push(...missingPackages);
583
+ // Global package set changed; drop the memo so any later detection re-probes.
584
+ resetGlobalToolchainDetectionCache();
566
585
  }
567
586
 
568
587
  for (const tool of missingLocalTools) {
@@ -599,6 +618,7 @@ module.exports = {
599
618
  describeCompanionInstallCommands,
600
619
  buildMissingCompanionInstallPrompt,
601
620
  detectGlobalToolchainPackages,
621
+ resetGlobalToolchainDetectionCache,
602
622
  detectRequiredSystemTools,
603
623
  detectOptionalLocalCompanionTools,
604
624
  askGlobalInstallForMissing,
@@ -0,0 +1,26 @@
1
+ <!-- monorepo-apps:START -->
2
+ ## Monorepo workflow (`apps/*`)
3
+
4
+ This repo has `apps/*` (storefront, backend, etc.). The **root worktree is kept on the protected base branch** so the user can keep `pnpm <app>:dev` running there and see merged-to-main state in real time. Never edit or commit on the root worktree.
5
+
6
+ ### Per-task loop
7
+
8
+ 1. **Start in a sibling worktree.** Run `gx pivot` (auto) or `gx branch start --type <kind> --task <slug>` — both spawn a worktree under `.omx/agent-worktrees/` on a fresh `agent/*` branch.
9
+ 2. **Run scoped dev servers from your worktree**, e.g. `pnpm --filter storefront dev` from `.omx/agent-worktrees/<your>/`. Pick a non-conflicting port if the user is already running the root.
10
+ 3. **Commit + push** as you go — the agent branch tracks `origin/agent/*`. The user can watch your branch live in their git client.
11
+ 4. **Ship via PR.** When the user approves the work, run `gx ship` (alias for `gx finish --via-pr --wait-for-merge --cleanup`). This: opens a PR → auto-merges to the protected base → prunes the worktree + branch.
12
+ 5. The user's root worktree is now showing the merged result on next pull.
13
+
14
+ ### Cross-app guardrails
15
+
16
+ - Edits to **both** `apps/storefront` AND `apps/backend` in one branch → split into two PRs unless they must land atomically. Reviews stay clean, rollbacks stay surgical.
17
+ - Edits to root configs (`pnpm-workspace.yaml`, `turbo.json`, `package.json`) lock every other agent. Claim → change → release fast.
18
+ - Migrations under `apps/backend/src/migrations/*` require explicit user OK before commit — they're irreversible on prod.
19
+ - Don't `pnpm install` from the root unless the user asks; do it inside your worktree if you added a dep.
20
+
21
+ ### What the user sees
22
+
23
+ - `git log --all --graph --oneline` shows every active agent branch in real time.
24
+ - `gx status` lists active worktrees + their branches.
25
+ - Each `gx ship` produces a PR — link goes in the user's GitHub notifications.
26
+ <!-- monorepo-apps:END -->