oh-my-copilot 5.6.2 → 5.7.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -0
- package/bridge/__pycache__/gyoshu_bridge.cpython-312.pyc +0 -0
- package/bridge/claude-md-coordinator.cjs +2 -2
- package/bridge/cli.cjs +78578 -75769
- package/bridge/mcp-server.cjs +36510 -32259
- package/bridge/runtime-cli.cjs +95 -34
- package/bridge/team-mcp.cjs +95 -34
- package/bridge/team.js +131 -70
- package/dist/__tests__/run-cjs-fail-closed-timeout.test.d.ts +2 -0
- package/dist/__tests__/run-cjs-fail-closed-timeout.test.d.ts.map +1 -0
- package/dist/__tests__/run-cjs-fail-closed-timeout.test.js +68 -0
- package/dist/__tests__/run-cjs-fail-closed-timeout.test.js.map +1 -0
- package/dist/__tests__/session-end-process-exit.test.js +70 -2
- package/dist/__tests__/session-end-process-exit.test.js.map +1 -1
- package/dist/cli/commands/__tests__/smoke-tier2.test.d.ts +2 -0
- package/dist/cli/commands/__tests__/smoke-tier2.test.d.ts.map +1 -0
- package/dist/cli/commands/__tests__/smoke-tier2.test.js +72 -0
- package/dist/cli/commands/__tests__/smoke-tier2.test.js.map +1 -0
- package/dist/cli/commands/smoke.d.ts +36 -0
- package/dist/cli/commands/smoke.d.ts.map +1 -0
- package/dist/cli/commands/smoke.js +169 -0
- package/dist/cli/commands/smoke.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +39 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/constants/names.d.ts +1 -0
- package/dist/constants/names.d.ts.map +1 -1
- package/dist/constants/names.js +1 -0
- package/dist/constants/names.js.map +1 -1
- package/dist/hooks/session-end/index.d.ts +2 -3
- package/dist/hooks/session-end/index.d.ts.map +1 -1
- package/dist/hooks/session-end/index.js +3 -10
- package/dist/hooks/session-end/index.js.map +1 -1
- package/dist/hooks/session-end/wiki-foreground-bootstrap.d.ts +17 -0
- package/dist/hooks/session-end/wiki-foreground-bootstrap.d.ts.map +1 -0
- package/dist/hooks/session-end/wiki-foreground-bootstrap.js +20 -0
- package/dist/hooks/session-end/wiki-foreground-bootstrap.js.map +1 -0
- package/dist/lib/__tests__/atomic-write.test.js +32 -1
- package/dist/lib/__tests__/atomic-write.test.js.map +1 -1
- package/dist/lib/__tests__/mode-state-lock.test.js +121 -12
- package/dist/lib/__tests__/mode-state-lock.test.js.map +1 -1
- package/dist/lib/atomic-write.d.ts +13 -3
- package/dist/lib/atomic-write.d.ts.map +1 -1
- package/dist/lib/atomic-write.js +29 -15
- package/dist/lib/atomic-write.js.map +1 -1
- package/dist/lib/mode-state-io.d.ts +2 -2
- package/dist/lib/mode-state-io.d.ts.map +1 -1
- package/dist/lib/mode-state-io.js +16 -10
- package/dist/lib/mode-state-io.js.map +1 -1
- package/dist/mcp/__tests__/host-smoke-tool.test.d.ts +2 -0
- package/dist/mcp/__tests__/host-smoke-tool.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/host-smoke-tool.test.js +174 -0
- package/dist/mcp/__tests__/host-smoke-tool.test.js.map +1 -0
- package/dist/mcp/disable-tools.d.ts.map +1 -1
- package/dist/mcp/disable-tools.js +1 -0
- package/dist/mcp/disable-tools.js.map +1 -1
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +2 -0
- package/dist/mcp/tool-registry.js.map +1 -1
- package/dist/smoke/__tests__/copilot-sdk-driver.test.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.js +561 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.js.map +1 -0
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js +311 -0
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js.map +1 -0
- package/dist/smoke/__tests__/copilot-session-eval.test.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-session-eval.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-session-eval.test.js +264 -0
- package/dist/smoke/__tests__/copilot-session-eval.test.js.map +1 -0
- package/dist/smoke/__tests__/copilot-smoke.test.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-smoke.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-smoke.test.js +482 -0
- package/dist/smoke/__tests__/copilot-smoke.test.js.map +1 -0
- package/dist/smoke/copilot-binary.d.ts +21 -0
- package/dist/smoke/copilot-binary.d.ts.map +1 -0
- package/dist/smoke/copilot-binary.js +46 -0
- package/dist/smoke/copilot-binary.js.map +1 -0
- package/dist/smoke/copilot-sdk-driver.d.ts +186 -0
- package/dist/smoke/copilot-sdk-driver.d.ts.map +1 -0
- package/dist/smoke/copilot-sdk-driver.js +622 -0
- package/dist/smoke/copilot-sdk-driver.js.map +1 -0
- package/dist/smoke/copilot-sdk-scenarios.d.ts +159 -0
- package/dist/smoke/copilot-sdk-scenarios.d.ts.map +1 -0
- package/dist/smoke/copilot-sdk-scenarios.js +510 -0
- package/dist/smoke/copilot-sdk-scenarios.js.map +1 -0
- package/dist/smoke/copilot-session-eval.d.ts +90 -0
- package/dist/smoke/copilot-session-eval.d.ts.map +1 -0
- package/dist/smoke/copilot-session-eval.js +323 -0
- package/dist/smoke/copilot-session-eval.js.map +1 -0
- package/dist/smoke/copilot-smoke.d.ts +228 -0
- package/dist/smoke/copilot-smoke.d.ts.map +1 -0
- package/dist/smoke/copilot-smoke.js +818 -0
- package/dist/smoke/copilot-smoke.js.map +1 -0
- package/dist/smoke/process-utils.d.ts +47 -0
- package/dist/smoke/process-utils.d.ts.map +1 -0
- package/dist/smoke/process-utils.js +99 -0
- package/dist/smoke/process-utils.js.map +1 -0
- package/dist/team/__tests__/tmux-session.pane-env.test.d.ts +2 -0
- package/dist/team/__tests__/tmux-session.pane-env.test.d.ts.map +1 -0
- package/dist/team/__tests__/tmux-session.pane-env.test.js +52 -0
- package/dist/team/__tests__/tmux-session.pane-env.test.js.map +1 -0
- package/dist/team/tmux-session.d.ts +7 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +80 -18
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/tools/host-smoke-tool.d.ts +34 -0
- package/dist/tools/host-smoke-tool.d.ts.map +1 -0
- package/dist/tools/host-smoke-tool.js +133 -0
- package/dist/tools/host-smoke-tool.js.map +1 -0
- package/docs/CLAUDE.md +1 -1
- package/docs/DEVELOPERS.md +101 -0
- package/docs/HOOKS.md +1 -1
- package/docs/MIGRATION.md +71 -0
- package/docs/REFERENCE.md +42 -1
- package/docs/TOOLS.md +32 -1
- package/package.json +11 -2
- package/plugin.json +1 -1
- package/scripts/dev/repro-state-lock.mjs +1 -1
- package/scripts/lib/atomic-write.mjs +4 -2
- package/scripts/lib/state-lock.mjs +21 -12
- package/scripts/run.cjs +13 -3
- package/scripts/wiki-session-end.mjs +2 -1
- package/templates/hooks/lib/atomic-write.mjs +4 -2
|
@@ -156,33 +156,41 @@ function sameOwner(left, right) {
|
|
|
156
156
|
return Boolean(left && right && left.pid === right.pid && left.processStart === right.processStart && left.nonce === right.nonce);
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
// BigInt ids: NTFS file IDs exceed 2^53 once the MFT sequence number reaches
|
|
160
|
+
// 32, and a Number ino rounds distinct files onto the same value.
|
|
159
161
|
function ownerArtifactIdentity(path) {
|
|
160
162
|
try {
|
|
161
|
-
const stats = statSync(path);
|
|
163
|
+
const stats = statSync(path, { bigint: true });
|
|
162
164
|
return stats.isFile() ? { dev: stats.dev, ino: stats.ino } : null;
|
|
163
165
|
} catch {
|
|
164
166
|
return null;
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
169
|
|
|
168
|
-
/**
|
|
170
|
+
/** Mirrors sameFileIdentity in src/lib/atomic-write.ts: ino always, dev unless win32 reports 0 (#4156). */
|
|
169
171
|
function sameArtifactIdentity(a, b) {
|
|
170
172
|
if (a.ino !== b.ino) return false;
|
|
171
|
-
if (process.platform === 'win32' && (a.dev ===
|
|
173
|
+
if (process.platform === 'win32' && (a.dev === 0n || b.dev === 0n)) return true;
|
|
172
174
|
return a.dev === b.dev;
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
/** Remove only the exact dead publication that was inspected. */
|
|
176
178
|
function reclaimDeadOwner(path, observed, identity) {
|
|
177
|
-
// Fork fix: the liveness verdict can be seconds old (win32 probe), and the owner may have
|
|
178
|
-
// exited and been replaced meanwhile. Renaming a live replacement into quarantine lets a third
|
|
179
|
-
// contender publish before the restore, leaving two holders, so re-verify the exact artifact
|
|
180
|
-
// (owner record AND dev/ino, upstream #4149 checks only the latter) immediately before the rename.
|
|
181
|
-
const current = readOwner(path);
|
|
182
|
-
const currentIdentity = ownerArtifactIdentity(path);
|
|
183
|
-
if (current === 'absent' || !current || !sameOwner(current, observed) || !currentIdentity ||
|
|
184
|
-
!sameArtifactIdentity(currentIdentity, identity)) return 'changed';
|
|
185
179
|
const quarantinePath = `${path}.reclaim.${process.pid}.${randomUUID()}`;
|
|
180
|
+
// The liveness verdict can be seconds old (the win32 probe spawns PowerShell),
|
|
181
|
+
// and the identity alone cannot tell a replacement apart when its inode reuses
|
|
182
|
+
// the old one (or when the identity was captured after the probe). Renaming a
|
|
183
|
+
// live replacement into quarantine opens a window in which a third contender
|
|
184
|
+
// publishes, leaving two holders. Re-verify the exact artifact, owner record
|
|
185
|
+
// AND file identity, immediately before the rename. Bracketing the read with
|
|
186
|
+
// two stats binds the record that was read to the identity that was checked.
|
|
187
|
+
const before = ownerArtifactIdentity(path);
|
|
188
|
+
const current = readOwner(path);
|
|
189
|
+
const after = ownerArtifactIdentity(path);
|
|
190
|
+
if (current === 'absent' || !current || !sameOwner(current, observed) ||
|
|
191
|
+
!before || !after || !sameArtifactIdentity(before, identity) || !sameArtifactIdentity(after, identity)) {
|
|
192
|
+
return 'changed';
|
|
193
|
+
}
|
|
186
194
|
try {
|
|
187
195
|
renameSync(path, quarantinePath);
|
|
188
196
|
} catch (error) {
|
|
@@ -194,7 +202,8 @@ function reclaimDeadOwner(path, observed, identity) {
|
|
|
194
202
|
try {
|
|
195
203
|
moved = readOwner(quarantinePath);
|
|
196
204
|
movedIdentity = ownerArtifactIdentity(quarantinePath);
|
|
197
|
-
if (moved !== 'absent' && moved && movedIdentity &&
|
|
205
|
+
if (moved !== 'absent' && moved && movedIdentity &&
|
|
206
|
+
sameArtifactIdentity(movedIdentity, identity) &&
|
|
198
207
|
sameOwner(moved, observed)) {
|
|
199
208
|
try {
|
|
200
209
|
unlinkSync(quarantinePath);
|
package/scripts/run.cjs
CHANGED
|
@@ -271,8 +271,17 @@ function resolveTrustedSessionEndTarget(resolution, extraArgs) {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
|
|
274
|
+
// oh-my-copilot fail-closed contract (fork-only): with OMC_HOOK_FAIL_CLOSED=1
|
|
275
|
+
// a hook timeout exits 124 so the host records a failed hook. Unset keeps the
|
|
276
|
+
// upstream fail-open exit 0.
|
|
277
|
+
const HOOK_TIMEOUT_FAIL_CLOSED_STATUS = 124;
|
|
278
|
+
function hookTimeoutStatus() {
|
|
279
|
+
return process.env.OMC_HOOK_FAIL_CLOSED === '1' ? HOOK_TIMEOUT_FAIL_CLOSED_STATUS : 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
274
282
|
function writeTimeoutDiagnostic(targetPath, manifestHook, timeoutMs, sink) {
|
|
275
|
-
const
|
|
283
|
+
const outcome = hookTimeoutStatus() === 0 ? 'fail-open' : `fail-closed (${HOOK_TIMEOUT_FAIL_CLOSED_STATUS})`;
|
|
284
|
+
const message = `[run.cjs] Hook ${basename(targetPath)} timed out after ${timeoutMs}ms; exiting ${outcome}.\n`;
|
|
276
285
|
if (manifestHook?.event !== 'UserPromptSubmit' || isDebugHooksEnabled()) {
|
|
277
286
|
if (sink) return sink.write(process.stderr, Buffer.from(message));
|
|
278
287
|
try { process.stderr.write(message); } catch { /* protocol dest may already be closed */ }
|
|
@@ -842,7 +851,7 @@ function runGenericChild(targetPath, extraArgs, timeoutMs, manifestHook, options
|
|
|
842
851
|
if (require.main === module) {
|
|
843
852
|
sink.closeDestinations();
|
|
844
853
|
}
|
|
845
|
-
finish(
|
|
854
|
+
finish(hookTimeoutStatus()); // fork: fail-closed contract, see hookTimeoutStatus
|
|
846
855
|
});
|
|
847
856
|
}, timeoutMs);
|
|
848
857
|
|
|
@@ -996,7 +1005,8 @@ async function runWorker(targetPath, manifestHook, timeoutMs) {
|
|
|
996
1005
|
}
|
|
997
1006
|
await writeTimeoutDiagnostic(targetPath, manifestHook, timeoutMs, sink);
|
|
998
1007
|
sink.uninstall();
|
|
999
|
-
|
|
1008
|
+
// Also the SessionEnd foreground-budget path. Fork: fail-closed contract, see hookTimeoutStatus.
|
|
1009
|
+
resolve(hookTimeoutStatus());
|
|
1000
1010
|
}, timeoutMs);
|
|
1001
1011
|
|
|
1002
1012
|
try {
|
|
@@ -15,7 +15,8 @@ export async function runWikiSessionEndHook() {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
try {
|
|
18
|
-
|
|
18
|
+
// Lean entry (not index.js): the full SessionEnd graph costs ~100ms of the 300ms budget.
|
|
19
|
+
const { processWikiSessionEnd } = await import('../dist/hooks/session-end/wiki-foreground-bootstrap.js');
|
|
19
20
|
const result = await processWikiSessionEnd(frame.value);
|
|
20
21
|
console.log(JSON.stringify(result));
|
|
21
22
|
} catch (error) {
|
|
@@ -137,9 +137,11 @@ function readEmergencyJournal(path) {
|
|
|
137
137
|
} catch { return null; }
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
// BigInt ids: NTFS file IDs exceed 2^53 once the MFT sequence number reaches
|
|
141
|
+
// 32, and a Number ino rounds distinct files onto the same value.
|
|
140
142
|
function fileIdentity(path) {
|
|
141
143
|
try {
|
|
142
|
-
const stat = statSync(path);
|
|
144
|
+
const stat = statSync(path, { bigint: true });
|
|
143
145
|
return { dev: stat.dev, ino: stat.ino };
|
|
144
146
|
} catch { return null; }
|
|
145
147
|
}
|
|
@@ -157,7 +159,7 @@ function sameFileIdentity(a, b) {
|
|
|
157
159
|
// On Windows, lstat returns dev=0, so skip dev comparison when on Windows
|
|
158
160
|
// unless both are non-zero (indicating a real comparison is possible)
|
|
159
161
|
const isWindows = process.platform === 'win32';
|
|
160
|
-
if (isWindows && (a.dev ===
|
|
162
|
+
if (isWindows && (a.dev === 0n || b.dev === 0n)) {
|
|
161
163
|
return true; // Skip dev comparison on Windows when either is 0
|
|
162
164
|
}
|
|
163
165
|
|