open-multi-agent-kit 0.91.0 → 0.93.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 (168) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/README.md +2 -2
  3. package/dist/core/agent-session.d.ts +29 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +89 -21
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/command-safety.d.ts.map +1 -1
  8. package/dist/core/command-safety.js +0 -50
  9. package/dist/core/command-safety.js.map +1 -1
  10. package/dist/core/compaction/branch-summarization.d.ts +5 -1
  11. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  12. package/dist/core/compaction/branch-summarization.js +5 -7
  13. package/dist/core/compaction/branch-summarization.js.map +1 -1
  14. package/dist/core/compaction/compaction.d.ts +12 -3
  15. package/dist/core/compaction/compaction.d.ts.map +1 -1
  16. package/dist/core/compaction/compaction.js +28 -15
  17. package/dist/core/compaction/compaction.js.map +1 -1
  18. package/dist/core/compaction/transaction.d.ts.map +1 -1
  19. package/dist/core/compaction/transaction.js +7 -3
  20. package/dist/core/compaction/transaction.js.map +1 -1
  21. package/dist/core/context-budget-headroom-candidates.d.ts.map +1 -1
  22. package/dist/core/context-budget-headroom-candidates.js +21 -11
  23. package/dist/core/context-budget-headroom-candidates.js.map +1 -1
  24. package/dist/core/context-budget-system-prompt-items.d.ts +1 -0
  25. package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
  26. package/dist/core/context-budget-system-prompt-items.js +7 -8
  27. package/dist/core/context-budget-system-prompt-items.js.map +1 -1
  28. package/dist/core/extensions/builtin/command-safety-gate.d.ts +8 -0
  29. package/dist/core/extensions/builtin/command-safety-gate.d.ts.map +1 -1
  30. package/dist/core/extensions/builtin/command-safety-gate.js +23 -0
  31. package/dist/core/extensions/builtin/command-safety-gate.js.map +1 -1
  32. package/dist/core/extensions/runner.d.ts.map +1 -1
  33. package/dist/core/extensions/runner.js +4 -0
  34. package/dist/core/extensions/runner.js.map +1 -1
  35. package/dist/core/extensions/types.d.ts +2 -0
  36. package/dist/core/extensions/types.d.ts.map +1 -1
  37. package/dist/core/extensions/types.js.map +1 -1
  38. package/dist/core/keybindings.d.ts +5 -0
  39. package/dist/core/keybindings.d.ts.map +1 -1
  40. package/dist/core/keybindings.js +5 -0
  41. package/dist/core/keybindings.js.map +1 -1
  42. package/dist/core/loadouts.d.ts.map +1 -1
  43. package/dist/core/loadouts.js +27 -48
  44. package/dist/core/loadouts.js.map +1 -1
  45. package/dist/core/model-resolver.d.ts +41 -3
  46. package/dist/core/model-resolver.d.ts.map +1 -1
  47. package/dist/core/model-resolver.js +17 -9
  48. package/dist/core/model-resolver.js.map +1 -1
  49. package/dist/core/provider-resilience.d.ts.map +1 -1
  50. package/dist/core/provider-resilience.js +3 -1
  51. package/dist/core/provider-resilience.js.map +1 -1
  52. package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -1
  53. package/dist/core/reasoning-router-v4-weights.js +9 -3
  54. package/dist/core/reasoning-router-v4-weights.js.map +1 -1
  55. package/dist/core/reasoning-router-v4.d.ts.map +1 -1
  56. package/dist/core/reasoning-router-v4.js +94 -24
  57. package/dist/core/reasoning-router-v4.js.map +1 -1
  58. package/dist/core/resource-loader.d.ts.map +1 -1
  59. package/dist/core/resource-loader.js +11 -5
  60. package/dist/core/resource-loader.js.map +1 -1
  61. package/dist/core/session-file-compaction.d.ts.map +1 -1
  62. package/dist/core/session-file-compaction.js +39 -5
  63. package/dist/core/session-file-compaction.js.map +1 -1
  64. package/dist/core/session-termination.d.ts.map +1 -1
  65. package/dist/core/session-termination.js +1 -1
  66. package/dist/core/session-termination.js.map +1 -1
  67. package/dist/core/settings-manager.d.ts +3 -0
  68. package/dist/core/settings-manager.d.ts.map +1 -1
  69. package/dist/core/settings-manager.js +8 -0
  70. package/dist/core/settings-manager.js.map +1 -1
  71. package/dist/core/system-prompt.d.ts.map +1 -1
  72. package/dist/core/system-prompt.js +36 -31
  73. package/dist/core/system-prompt.js.map +1 -1
  74. package/dist/core/tools/bash.d.ts +2 -0
  75. package/dist/core/tools/bash.d.ts.map +1 -1
  76. package/dist/core/tools/bash.js +38 -11
  77. package/dist/core/tools/bash.js.map +1 -1
  78. package/dist/main.d.ts.map +1 -1
  79. package/dist/main.js +112 -11
  80. package/dist/main.js.map +1 -1
  81. package/dist/modes/interactive/components/control-panel-box.d.ts +27 -0
  82. package/dist/modes/interactive/components/control-panel-box.d.ts.map +1 -1
  83. package/dist/modes/interactive/components/control-panel-box.js +60 -8
  84. package/dist/modes/interactive/components/control-panel-box.js.map +1 -1
  85. package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
  86. package/dist/modes/interactive/components/control-panel-layout.js +100 -45
  87. package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
  88. package/dist/modes/interactive/components/control-panel-runtime-status.d.ts +9 -0
  89. package/dist/modes/interactive/components/control-panel-runtime-status.d.ts.map +1 -1
  90. package/dist/modes/interactive/components/control-panel-runtime-status.js +10 -8
  91. package/dist/modes/interactive/components/control-panel-runtime-status.js.map +1 -1
  92. package/dist/modes/interactive/components/control-panel-sparkles.d.ts +5 -0
  93. package/dist/modes/interactive/components/control-panel-sparkles.d.ts.map +1 -1
  94. package/dist/modes/interactive/components/control-panel-sparkles.js +14 -9
  95. package/dist/modes/interactive/components/control-panel-sparkles.js.map +1 -1
  96. package/dist/modes/interactive/components/footer.d.ts +10 -0
  97. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  98. package/dist/modes/interactive/components/footer.js +3 -3
  99. package/dist/modes/interactive/components/footer.js.map +1 -1
  100. package/dist/modes/interactive/components/status-sidebar.d.ts +49 -0
  101. package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -0
  102. package/dist/modes/interactive/components/status-sidebar.js +253 -0
  103. package/dist/modes/interactive/components/status-sidebar.js.map +1 -0
  104. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  105. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  106. package/dist/modes/interactive/interactive-mode.js +94 -20
  107. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  108. package/dist/modes/interactive/theme/omk-neon-control.json +13 -13
  109. package/dist/modes/print-mode.d.ts.map +1 -1
  110. package/dist/modes/print-mode.js +9 -0
  111. package/dist/modes/print-mode.js.map +1 -1
  112. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  113. package/dist/modes/rpc/rpc-mode.js +1 -0
  114. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  115. package/dist/utils/clipboard.d.ts.map +1 -1
  116. package/dist/utils/clipboard.js +19 -8
  117. package/dist/utils/clipboard.js.map +1 -1
  118. package/docs/adaptorch-preview-spec.md +174 -0
  119. package/docs/adaptorch-preview.md +1 -1
  120. package/docs/compaction.md +20 -13
  121. package/docs/correctness-wall.md +13 -5
  122. package/docs/custom-provider.md +8 -8
  123. package/docs/development.md +2 -2
  124. package/docs/docs.json +4 -0
  125. package/docs/environment-variables.md +90 -0
  126. package/docs/extensions.md +8 -8
  127. package/docs/index.md +1 -0
  128. package/docs/json.md +4 -4
  129. package/docs/providers.md +1 -1
  130. package/docs/rpc.md +5 -2
  131. package/docs/session-format.md +5 -5
  132. package/docs/settings.md +1 -0
  133. package/docs/skills.md +2 -0
  134. package/docs/themes.md +2 -2
  135. package/docs/tui.md +4 -4
  136. package/docs/usage.md +4 -0
  137. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  138. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  139. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  140. package/examples/extensions/gondolin/package-lock.json +2 -2
  141. package/examples/extensions/gondolin/package.json +1 -1
  142. package/examples/extensions/sandbox/package-lock.json +2 -2
  143. package/examples/extensions/sandbox/package.json +1 -1
  144. package/examples/extensions/subagent/README.md +35 -10
  145. package/examples/extensions/subagent/adaptive-agent-runtime.test.ts +234 -0
  146. package/examples/extensions/subagent/adaptive-agent-runtime.ts +240 -0
  147. package/examples/extensions/subagent/adaptive-result.ts +112 -0
  148. package/examples/extensions/subagent/agents.test.ts +86 -0
  149. package/examples/extensions/subagent/agents.ts +18 -4
  150. package/examples/extensions/subagent/capabilities.ts +15 -1
  151. package/examples/extensions/subagent/checkpoint-runtime.test.ts +125 -0
  152. package/examples/extensions/subagent/checkpoint-runtime.ts +198 -0
  153. package/examples/extensions/subagent/deadline-budget.test.ts +135 -0
  154. package/examples/extensions/subagent/deadline-budget.ts +242 -0
  155. package/examples/extensions/subagent/deadline-profile-store.test.ts +72 -0
  156. package/examples/extensions/subagent/deadline-profile-store.ts +172 -0
  157. package/examples/extensions/subagent/domain-profiles.ts +272 -0
  158. package/examples/extensions/subagent/fixtures/fake-omk-json.mjs +13 -0
  159. package/examples/extensions/subagent/fixtures/hanging-process-tree.mjs +40 -0
  160. package/examples/extensions/subagent/index.ts +253 -137
  161. package/examples/extensions/subagent/managed-process.test.ts +178 -0
  162. package/examples/extensions/subagent/managed-process.ts +236 -0
  163. package/examples/extensions/subagent/subagent-extension-smoke.test.ts +112 -0
  164. package/examples/extensions/subagent/subagent-runtime-types.ts +76 -0
  165. package/examples/extensions/with-deps/package-lock.json +2 -2
  166. package/examples/extensions/with-deps/package.json +1 -1
  167. package/npm-shrinkwrap.json +21 -21
  168. package/package.json +10 -7
@@ -0,0 +1,172 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import {
4
+ type DeadlineProfile,
5
+ type DeadlineProfileDb,
6
+ type DeadlineProfileSample,
7
+ getDeadlineProfile,
8
+ updateDeadlineProfiles,
9
+ } from "./deadline-budget.ts";
10
+
11
+ const MAX_PROFILE_FILE_BYTES = 1024 * 1024;
12
+ const MAX_PROFILE_ENTRIES = 1_000;
13
+ const LOCK_RETRY_COUNT = 200;
14
+ const LOCK_RETRY_MS = 10;
15
+ const STALE_LOCK_MS = 30_000;
16
+
17
+ export class DeadlineProfileLockError extends Error {
18
+ constructor(filePath: string) {
19
+ super(`Timed out acquiring deadline profile lock for ${filePath}`);
20
+ this.name = "DeadlineProfileLockError";
21
+ }
22
+ }
23
+
24
+ export class DeadlineProfileStore {
25
+ private readonly filePath: string;
26
+ private db: DeadlineProfileDb = emptyDb();
27
+ private mutationTail: Promise<void> = Promise.resolve();
28
+
29
+ constructor(filePath: string) {
30
+ this.filePath = filePath;
31
+ }
32
+
33
+ async profileFor(provider: string, model: string): Promise<DeadlineProfile | undefined> {
34
+ await this.mutationTail;
35
+ this.db = await readDb(this.filePath);
36
+ return getDeadlineProfile(this.db, provider, model);
37
+ }
38
+
39
+ async record(sample: DeadlineProfileSample): Promise<DeadlineProfile> {
40
+ let recorded: DeadlineProfile | undefined;
41
+ const operation = this.mutationTail.then(async () => {
42
+ await withProfileLock(this.filePath, async () => {
43
+ this.db = updateDeadlineProfiles(await readDb(this.filePath), sample);
44
+ recorded = getDeadlineProfile(this.db, sample.provider, sample.model);
45
+ if (recorded === undefined) throw new Error("Deadline profile update did not produce a profile");
46
+ await writeAtomically(this.filePath, JSON.stringify(this.db));
47
+ });
48
+ });
49
+ this.mutationTail = operation.catch(() => undefined);
50
+ await operation;
51
+ if (recorded === undefined) throw new Error("Deadline profile update did not complete");
52
+ return recorded;
53
+ }
54
+ }
55
+
56
+ async function withProfileLock<T>(filePath: string, operation: () => Promise<T>): Promise<T> {
57
+ const lockPath = `${filePath}.lock`;
58
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
59
+ for (let attempt = 0; attempt < LOCK_RETRY_COUNT; attempt++) {
60
+ try {
61
+ await fs.promises.mkdir(lockPath);
62
+ try {
63
+ return await operation();
64
+ } finally {
65
+ await fs.promises.rm(lockPath, { recursive: true, force: true });
66
+ }
67
+ } catch (error) {
68
+ if (!isAlreadyExists(error)) throw error;
69
+ await removeStaleLock(lockPath);
70
+ await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
71
+ }
72
+ }
73
+ throw new DeadlineProfileLockError(filePath);
74
+ }
75
+
76
+ async function removeStaleLock(lockPath: string): Promise<void> {
77
+ try {
78
+ const stats = await fs.promises.stat(lockPath);
79
+ if (Date.now() - stats.mtimeMs > STALE_LOCK_MS) {
80
+ await fs.promises.rm(lockPath, { recursive: true, force: true });
81
+ }
82
+ } catch {
83
+ return;
84
+ }
85
+ }
86
+
87
+ function isAlreadyExists(error: unknown): boolean {
88
+ return error instanceof Error && "code" in error && error.code === "EEXIST";
89
+ }
90
+
91
+ async function readDb(filePath: string): Promise<DeadlineProfileDb> {
92
+ try {
93
+ const handle = await fs.promises.open(filePath, "r");
94
+ try {
95
+ const stats = await handle.stat();
96
+ if (stats.size > MAX_PROFILE_FILE_BYTES) return emptyDb();
97
+ return parseDb(JSON.parse(await handle.readFile("utf8")));
98
+ } finally {
99
+ await handle.close();
100
+ }
101
+ } catch {
102
+ return emptyDb();
103
+ }
104
+ }
105
+
106
+ async function writeAtomically(filePath: string, content: string): Promise<void> {
107
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
108
+ const tempPath = `${filePath}.${process.pid}.${process.hrtime.bigint()}.tmp`;
109
+ try {
110
+ await fs.promises.writeFile(tempPath, content, { encoding: "utf8", mode: 0o600 });
111
+ await fs.promises.rename(tempPath, filePath);
112
+ } finally {
113
+ await fs.promises.rm(tempPath, { force: true });
114
+ }
115
+ }
116
+
117
+ function parseDb(value: unknown): DeadlineProfileDb {
118
+ if (!isRecord(value) || value.version !== 1 || !isRecord(value.profiles)) return emptyDb();
119
+ const profiles: Record<string, DeadlineProfile> = Object.create(null);
120
+ for (const [key, raw] of Object.entries(value.profiles).slice(0, MAX_PROFILE_ENTRIES)) {
121
+ const parsed = parseProfile(raw);
122
+ if (parsed !== undefined) profiles[key] = parsed;
123
+ }
124
+ return { version: 1, profiles };
125
+ }
126
+
127
+ function parseProfile(value: unknown): DeadlineProfile | undefined {
128
+ if (!isRecord(value) || typeof value.provider !== "string" || typeof value.model !== "string") return undefined;
129
+ const samples = readCount(value.samples);
130
+ const completions = readCount(value.completions);
131
+ const cutoffs = readCount(value.cutoffs);
132
+ const aborts = readCount(value.aborts);
133
+ const failures = readCount(value.failures);
134
+ const ewmaElapsedMs = readCount(value.ewmaElapsedMs);
135
+ const ewmaMsPerWorkUnit = readCount(value.ewmaMsPerWorkUnit);
136
+ if ([samples, completions, cutoffs, aborts, failures, ewmaElapsedMs, ewmaMsPerWorkUnit].includes(undefined)) {
137
+ return undefined;
138
+ }
139
+ return {
140
+ provider: value.provider.slice(0, 256),
141
+ model: value.model.slice(0, 256),
142
+ samples: samples ?? 0,
143
+ completions: completions ?? 0,
144
+ cutoffs: cutoffs ?? 0,
145
+ aborts: aborts ?? 0,
146
+ failures: failures ?? 0,
147
+ ewmaElapsedMs: ewmaElapsedMs ?? 0,
148
+ ewmaMsPerWorkUnit: ewmaMsPerWorkUnit ?? 0,
149
+ completedDurationsMs: readDurations(value.completedDurationsMs),
150
+ cutoffDurationsMs: readDurations(value.cutoffDurationsMs),
151
+ };
152
+ }
153
+
154
+ function readCount(value: unknown): number | undefined {
155
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : undefined;
156
+ }
157
+
158
+ function readDurations(value: unknown): number[] {
159
+ if (!Array.isArray(value)) return [];
160
+ return value
161
+ .map(readCount)
162
+ .filter((duration): duration is number => duration !== undefined && duration > 0)
163
+ .slice(-24);
164
+ }
165
+
166
+ function emptyDb(): DeadlineProfileDb {
167
+ return { version: 1, profiles: {} };
168
+ }
169
+
170
+ function isRecord(value: unknown): value is Record<string, unknown> {
171
+ return typeof value === "object" && value !== null && !Array.isArray(value);
172
+ }
@@ -23,6 +23,278 @@ export interface DomainProfile {
23
23
 
24
24
  /** All domain profiles, ordered so that more specific domains precede general ones. */
25
25
  export const DOMAIN_PROFILES: readonly DomainProfile[] = [
26
+ // ── OMK-native elite domains (prepended — name-weighted, high specificity) ──
27
+
28
+ {
29
+ id: "omk-core-eng",
30
+ label: "OMK Core Engineering Lanes",
31
+ keywords: [
32
+ /omk-?coder/i,
33
+ /omk-?explorer/i,
34
+ /omk-?reviewer/i,
35
+ /omk-?tester/i,
36
+ /omk-?architect/i,
37
+ /omk-?qa\b/i,
38
+ /omk-?diffsurgeon/i,
39
+ /omk-?vision-?debugger/i,
40
+ /diff.?surgeon/i,
41
+ /vision.?debugger/i,
42
+ /\bcodemod\b/i,
43
+ /\btypecheck\b/i,
44
+ ],
45
+ skillPool: [
46
+ "programming",
47
+ "debugging",
48
+ "ponytail",
49
+ "ast-grep",
50
+ "lsp",
51
+ "refactor",
52
+ "review-work",
53
+ "code-review",
54
+ "tdd-workflow",
55
+ "git-master",
56
+ "gstack",
57
+ "remove-ai-slops",
58
+ "ponytail-review",
59
+ "ponytail-audit",
60
+ "visual-qa",
61
+ "frontend",
62
+ "understand-anything",
63
+ "headroom",
64
+ "ulw-plan",
65
+ "python-testing",
66
+ "golang-testing",
67
+ "rust-testing",
68
+ ],
69
+ defaultMcp: [
70
+ "filesystem",
71
+ "context7",
72
+ "memory",
73
+ "understand-anything",
74
+ "lean-ctx",
75
+ "chrome-devtools",
76
+ "playwright",
77
+ "zai-vision",
78
+ ],
79
+ defaultHooks: [
80
+ "session-context",
81
+ "post-format",
82
+ "typecheck-after-edit",
83
+ "eslint-after-edit",
84
+ "stop-verify",
85
+ "branch-diff-snapshot",
86
+ ],
87
+ },
88
+
89
+ {
90
+ id: "omk-orchestration",
91
+ label: "OMK Orchestration & Lanes",
92
+ keywords: [
93
+ /omk-?conductor/i,
94
+ /omk-?router/i,
95
+ /omk-?planner/i,
96
+ /omk-?aggregator/i,
97
+ /omk-?integrator/i,
98
+ /omk-?loopback/i,
99
+ /omk-?worktree/i,
100
+ /\bconductor\b/i,
101
+ /\blane.?grant/i,
102
+ /omk-?ontology/i,
103
+ /\bsubagent/i,
104
+ /\borchestrat/i,
105
+ ],
106
+ skillPool: [
107
+ "adaptorch-route",
108
+ "adaptorch",
109
+ "omk-plan",
110
+ "ulw-plan",
111
+ "understand-anything",
112
+ "headroom",
113
+ "omk-loop",
114
+ "omk-agent-ops",
115
+ "omk-engineering",
116
+ "gstack",
117
+ "git-master",
118
+ ],
119
+ defaultMcp: ["adaptorch", "memory", "understand-anything"],
120
+ defaultHooks: ["session-context", "precompact-checkpoint", "subagent-stop-audit"],
121
+ },
122
+ {
123
+ id: "omk-godmode-research",
124
+ label: "OMK Max-Capability Research",
125
+ keywords: [
126
+ /omk-?godmode/i,
127
+ /omk-?godmod/i,
128
+ /\bgodmode\b/i,
129
+ /offensive-?jailbreak/i,
130
+ /full.?spectrum/i,
131
+ /max-?capability/i,
132
+ ],
133
+ skillPool: [
134
+ "omk-godmod",
135
+ "offensive-jailbreak",
136
+ "reverse-skill",
137
+ "programming",
138
+ "insane-search",
139
+ "debugging",
140
+ "security-review",
141
+ "omk-crawling",
142
+ ],
143
+ defaultMcp: ["filesystem", "memory", "fetch", "firecrawl", "ghidra", "playwright"],
144
+ defaultHooks: ["session-context", "subagent-stop-audit"],
145
+ },
146
+ {
147
+ id: "omk-reverse",
148
+ label: "OMK Reverse Engineering",
149
+ keywords: [
150
+ /omk-?re\b/i,
151
+ /reverse-?skill/i,
152
+ /reverse.?engineer/i,
153
+ /\bdecompile/i,
154
+ /\bghidra\b/i,
155
+ /\bjadx\b/i,
156
+ /\bctf\b/i,
157
+ /\bapk\b/i,
158
+ ],
159
+ skillPool: ["reverse-skill", "security-review", "programming", "insane-search", "debugging", "omk-crawling"],
160
+ defaultMcp: ["filesystem", "memory", "ghidra", "chrome-devtools", "playwright"],
161
+ defaultHooks: ["session-context", "subagent-stop-audit"],
162
+ },
163
+ {
164
+ id: "omk-crawl-search",
165
+ label: "OMK Crawl & Hard-Web Fetch",
166
+ keywords: [
167
+ /omk-?crawler/i,
168
+ /omk-?crawling/i,
169
+ /insane-?search/i,
170
+ /\bwaf\b/i,
171
+ /blocked.?url/i,
172
+ /web.?fetch/i,
173
+ /hard.?web/i,
174
+ ],
175
+ skillPool: ["insane-search", "omk-crawling", "adaptorch", "headroom", "gstack"],
176
+ defaultMcp: ["fetch", "firecrawl", "playwright", "chrome-devtools", "memory"],
177
+ defaultHooks: ["session-context"],
178
+ },
179
+ {
180
+ id: "omk-minimalism",
181
+ label: "OMK Ponytail Minimalism",
182
+ keywords: [
183
+ /omk-?ponytail/i,
184
+ /\bponytail\b/i,
185
+ /\byagni\b/i,
186
+ /over-?engineer/i,
187
+ /slopcutter/i,
188
+ /remove-?ai-?slop/i,
189
+ /\bminimalism\b/i,
190
+ ],
191
+ skillPool: [
192
+ "ponytail",
193
+ "ponytail-review",
194
+ "ponytail-audit",
195
+ "remove-ai-slops",
196
+ "refactor",
197
+ "programming",
198
+ "docs-write-concisely",
199
+ "polish",
200
+ ],
201
+ defaultMcp: ["filesystem", "context7", "memory"],
202
+ defaultHooks: ["post-format", "typecheck-after-edit"],
203
+ },
204
+ {
205
+ id: "omk-debug-perf",
206
+ label: "OMK Debug & Performance",
207
+ keywords: [
208
+ /omk-?debugger/i,
209
+ /omk-?perf/i,
210
+ /omk-?tdd/i,
211
+ /omk-?sre/i,
212
+ /root-?cause/i,
213
+ /\bheisenbug\b/i,
214
+ /\bflaky\b/i,
215
+ /\bincident\b/i,
216
+ /\bbenchmark\b/i,
217
+ /\bhotspot\b/i,
218
+ ],
219
+ skillPool: [
220
+ "debugging",
221
+ "tdd-workflow",
222
+ "programming",
223
+ "ast-grep",
224
+ "lsp",
225
+ "python-testing",
226
+ "golang-testing",
227
+ "rust-testing",
228
+ "refactor",
229
+ "ponytail",
230
+ "omk-loop",
231
+ "omk-agent-ops",
232
+ "gstack",
233
+ ],
234
+ defaultMcp: ["filesystem", "context7", "memory", "github"],
235
+ defaultHooks: ["typecheck-after-edit", "post-format", "session-context"],
236
+ },
237
+ {
238
+ id: "omk-ship",
239
+ label: "OMK Release & Gstack Ship",
240
+ keywords: [
241
+ /omk-?release/i,
242
+ /omk-?gstack/i,
243
+ /\bgstack\b/i,
244
+ /\bchangelog\b/i,
245
+ /\bsemver\b/i,
246
+ /\bcut.?release\b/i,
247
+ /\bland.?pr\b/i,
248
+ /worktree/i,
249
+ ],
250
+ skillPool: [
251
+ "gstack",
252
+ "git-master",
253
+ "review-work",
254
+ "programming",
255
+ "omk-agent-ops",
256
+ "docs-update-docs",
257
+ "omk-loop",
258
+ ],
259
+ defaultMcp: ["filesystem", "memory", "github"],
260
+ defaultHooks: [
261
+ "release-check-before-stop",
262
+ "npm-audit-summary",
263
+ "branch-diff-snapshot",
264
+ "protect-secrets",
265
+ "stop-verify",
266
+ "worktree-create-guard",
267
+ ],
268
+ },
269
+ {
270
+ id: "omk-docs-ui",
271
+ label: "OMK Docs & Frontend",
272
+ keywords: [
273
+ /omk-?docs/i,
274
+ /omk-?frontend/i,
275
+ /docs-write-concisely/i,
276
+ /docs-update-docs/i,
277
+ /\breadme\b/i,
278
+ /tech.?writing/i,
279
+ /visual-?qa/i,
280
+ /\ba11y\b/i,
281
+ ],
282
+ skillPool: [
283
+ "docs-write-concisely",
284
+ "docs-update-docs",
285
+ "remove-ai-slops",
286
+ "polish",
287
+ "frontend",
288
+ "frontend-patterns",
289
+ "visual-qa",
290
+ "programming",
291
+ "ponytail",
292
+ "headroom",
293
+ ],
294
+ defaultMcp: ["filesystem", "memory", "context7", "chrome-devtools", "playwright", "zai-vision"],
295
+ defaultHooks: ["post-format", "typecheck-after-edit", "eslint-after-edit", "session-context"],
296
+ },
297
+
26
298
  {
27
299
  id: "frontend-web",
28
300
  label: "Frontend & Web",
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+
3
+ process.stdout.write(
4
+ `${JSON.stringify({
5
+ type: "message_end",
6
+ message: {
7
+ role: "assistant",
8
+ content: [{ type: "text", text: "fixture subagent completed" }],
9
+ provider: "fixture-provider",
10
+ model: "fixture-model",
11
+ },
12
+ })}\n`,
13
+ );
@@ -0,0 +1,40 @@
1
+ import { spawn } from "node:child_process";
2
+
3
+ const normalOrphan = process.argv.includes("--normal-orphan");
4
+
5
+ if (!process.argv.includes("--parent-exits") && !normalOrphan) {
6
+ process.on("SIGTERM", () => {
7
+ // Exercise the managed runner's SIGKILL escalation path.
8
+ });
9
+ }
10
+
11
+ // The grandchild ignores SIGTERM so the managed runner must escalate to
12
+ // SIGKILL. It writes "ready" on its stdout (piped back to this parent) only
13
+ // AFTER installing its SIGTERM handler. The parent waits for that signal
14
+ // before exiting or settling into its keep-alive loop, so the runner never
15
+ // signals the process group while the grandchild is still in its startup
16
+ // window (a fresh `node -e` process needs ~50-100ms before its first JS line
17
+ // runs). Without this handshake a SIGTERM can land before the handler is
18
+ // installed, killing the grandchild via the default handler and making the
19
+ // SIGKILL escalation (cleanup.killSent) a timing race.
20
+ const grandchild = spawn(
21
+ process.execPath,
22
+ ["-e", "process.on('SIGTERM', () => {}); process.stdout.write('ready'); setInterval(() => {}, 1000)"],
23
+ {
24
+ stdio: ["ignore", "pipe", "ignore"],
25
+ },
26
+ );
27
+
28
+ process.stdout.write(`${JSON.stringify({ grandchildPid: grandchild.pid })}\n`);
29
+
30
+ const startMain = () => {
31
+ if (normalOrphan) setTimeout(() => process.exit(0), 20);
32
+ else setInterval(() => {}, 1000);
33
+ };
34
+
35
+ let started = false;
36
+ grandchild.stdout.on("data", () => {
37
+ if (started) return;
38
+ started = true;
39
+ startMain();
40
+ });