@essentialai/cogent-plugin 3.25.9 → 3.25.10
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cogent",
|
|
3
|
-
"version": "3.25.
|
|
3
|
+
"version": "3.25.10",
|
|
4
4
|
"description": "Inter-session communication bridge for Claude Code with Slack integration. Enables CC agents and Slack team members to communicate in real time.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Essential AI Solutions",
|
package/bridge/cogent-bridge.mjs
CHANGED
|
@@ -26475,8 +26475,8 @@ var init_stdio2 = __esm({
|
|
|
26475
26475
|
// src/constants.ts
|
|
26476
26476
|
import { createRequire } from "node:module";
|
|
26477
26477
|
function resolveVersion() {
|
|
26478
|
-
if ("3.25.
|
|
26479
|
-
return "3.25.
|
|
26478
|
+
if ("3.25.10") {
|
|
26479
|
+
return "3.25.10";
|
|
26480
26480
|
}
|
|
26481
26481
|
try {
|
|
26482
26482
|
const require2 = createRequire(import.meta.url);
|
|
@@ -26692,6 +26692,9 @@ ${issues}`);
|
|
|
26692
26692
|
_config = Object.freeze(data);
|
|
26693
26693
|
return _config;
|
|
26694
26694
|
}
|
|
26695
|
+
function readOnlyWake(config2) {
|
|
26696
|
+
return config2.COGENT_READ_ONLY_WAKE || config2.COGENT_WAKE_TOOLS === "read";
|
|
26697
|
+
}
|
|
26695
26698
|
function getConfig() {
|
|
26696
26699
|
if (!_config) throw new Error("Config not loaded. Call loadConfig() first.");
|
|
26697
26700
|
return _config;
|
|
@@ -26755,11 +26758,44 @@ var init_config = __esm({
|
|
|
26755
26758
|
// launches via the daemon (see bin/cogent-codex) and sets this to `app-server`.
|
|
26756
26759
|
// Only affects COGENT_PLATFORM=codex; claude/gemini/mail rails never read it.
|
|
26757
26760
|
COGENT_CODEX_WAKE: import_zod2.z.enum(["auto", "exec-resume", "app-server"]).default("auto"),
|
|
26758
|
-
// COG-86: what a Claude wake may do. `
|
|
26759
|
-
// run commands or commit. A wake resumes the SAME session
|
|
26760
|
-
// tell reliably that the terminal is there; on 2026-10-15
|
|
26761
|
-
//
|
|
26762
|
-
|
|
26761
|
+
// COG-86 / COG-88: what a Claude wake may do. `full` (default) = every tool, as before 3.25.9. `read` = Read,
|
|
26762
|
+
// Glob and Grep only: the wake answers but cannot edit, run commands or commit. A wake resumes the SAME session
|
|
26763
|
+
// a human may have open in a terminal, and nothing can tell reliably that the terminal is there; on 2026-10-15
|
|
26764
|
+
// a full-tool wake edited a live session's files, then committed and pushed. 3.25.9 made `read` the default;
|
|
26765
|
+
// the operator reversed that on 2026-10-16 (COG-88): read-only is an opt-in, switched with the environment
|
|
26766
|
+
// variable COGENT_READ_ONLY_WAKE (below) or here. An EMPTY value counts as unset — a host that substitutes an empty
|
|
26767
|
+
// string for a missing setting must not take the bridge down. Case and surrounding spaces are ignored
|
|
26768
|
+
// ("Read", "read " = read), the same rule COGENT_READ_ONLY_WAKE uses — a user opting in must not stop the
|
|
26769
|
+
// bridge over a capital letter. Any other unknown value still fails loudly.
|
|
26770
|
+
// Read it through readOnlyWake(), never directly: either opt-in turns read-only on.
|
|
26771
|
+
COGENT_WAKE_TOOLS: import_zod2.z.preprocess(
|
|
26772
|
+
(v) => {
|
|
26773
|
+
if (typeof v !== "string") return v;
|
|
26774
|
+
const s = v.trim().toLowerCase();
|
|
26775
|
+
return s === "" ? void 0 : s;
|
|
26776
|
+
},
|
|
26777
|
+
import_zod2.z.enum(["read", "full"]).default("full")
|
|
26778
|
+
),
|
|
26779
|
+
// COG-88: the read-only wake opt-in — an ENVIRONMENT VARIABLE only: no plugin setting, so no Claude Code
|
|
26780
|
+
// version floor. Plugin users set it in the "env" block of ~/.claude/settings.json or export it in the shell
|
|
26781
|
+
// (both reach the plugin's MCP server and its SessionStart hook — measured, Claude Code 2.1.74 and 2.1.302); a custom/Team config sets it
|
|
26782
|
+
// in its server env block. Applied at bridge start: /reload-plugins does NOT restart the server (measured).
|
|
26783
|
+
// The plugin's .mcp.json must NEVER set this key (nor COGENT_WAKE_TOOLS): a plugin env-block key wins over the
|
|
26784
|
+
// shell and settings.json, so any value there would silently block the user's opt-in (measured).
|
|
26785
|
+
//
|
|
26786
|
+
// FUTURE /config option (operator, 2026-10-16: may become the only switch; NOT shipped now). It would be a
|
|
26787
|
+
// plugin.json "userConfig": { "read_only_wake": { "type": "boolean", ... } } mapped by plugin/.mcp.json
|
|
26788
|
+
// "COGENT_READ_ONLY_WAKE": "${user_config.read_only_wake}" — Claude Code passes the STRING "true"/"false"
|
|
26789
|
+
// (measured, 2.1.301). userConfig needs Claude Code >= 2.1.75: 2.1.74 and older reject the manifest
|
|
26790
|
+
// ('Unrecognized key: "userConfig"') and load NONE of the plugin (measured 2026-10-16). Adding that env line
|
|
26791
|
+
// also ends the env-variable path for plugin users (the block wins), so the two cannot ship side by side, and
|
|
26792
|
+
// the guards in src/config.test.ts and cogent-plugin/scripts/sync-from-plugin.test.mjs must change with it.
|
|
26793
|
+
//
|
|
26794
|
+
// Only an explicit affirmative turns it on. Anything else is OFF and never an error — "", "false", a typo, or
|
|
26795
|
+
// an unsubstituted "${user_config.read_only_wake}": a config error here would stop the bridge, which is worse
|
|
26796
|
+
// than a wake that behaves as it did before 3.25.9. The plugin's SessionStart notice reads it with the same rule
|
|
26797
|
+
// (readOnlyWakeFromEnv in plugin/hooks/check-on-stop.lib.mjs, parity-tested).
|
|
26798
|
+
COGENT_READ_ONLY_WAKE: import_zod2.z.string().optional().transform((v) => v !== void 0 && ["true", "1", "yes", "on"].includes(v.trim().toLowerCase())),
|
|
26763
26799
|
// Auto-recovery for a blocked Codex sandbox. On a host where the OS sandbox
|
|
26764
26800
|
// can't initialize (unprivileged user namespaces blocked — Ubuntu 24.04's
|
|
26765
26801
|
// apparmor_restrict_unprivileged_userns, containers, hardened kernels),
|
|
@@ -27424,15 +27460,17 @@ async function execClaude(sessionId, message, cwd, timeoutMs) {
|
|
|
27424
27460
|
// (the Monitor tool, loaded through ToolSearch, ran a shell and wrote a file) and would miss every tool a later
|
|
27425
27461
|
// claude adds. --tools is variadic, so it must be followed by another option, never by the message. A claude
|
|
27426
27462
|
// too old to know --tools exits "unknown option" — the wake fails, it never runs with every tool.
|
|
27427
|
-
|
|
27463
|
+
// COG-88: opt-in (COGENT_READ_ONLY_WAKE=true or COGENT_WAKE_TOOLS=read in the env); off by default.
|
|
27464
|
+
...readOnlyWake(config2) ? ["--tools", READ_ONLY_WAKE_TOOLS, "--append-system-prompt", READ_ONLY_WAKE_NOTICE] : [],
|
|
27428
27465
|
"-p",
|
|
27429
|
-
truncated
|
|
27466
|
+
readOnlyWake(config2) ? `${truncated}${READ_ONLY_WAKE_PROMPT_SEPARATOR}${READ_ONLY_WAKE_NOTICE}` : truncated
|
|
27430
27467
|
];
|
|
27431
27468
|
const cleanEnv = buildResumeEnv(process.env, "CLAUDE", ["CLAUDE_CONFIG_DIR"]);
|
|
27432
27469
|
if (resolvedRoot && resolvedRoot !== path10.resolve(claudeConfigDir())) {
|
|
27433
27470
|
cleanEnv.CLAUDE_CONFIG_DIR = resolvedRoot;
|
|
27434
27471
|
}
|
|
27435
27472
|
cleanEnv.COGENT_CHECK_ON_STOP = "0";
|
|
27473
|
+
cleanEnv.COGENT_WAKE = "1";
|
|
27436
27474
|
const child = spawn(config2.COGENT_CLAUDE_PATH, args, {
|
|
27437
27475
|
cwd,
|
|
27438
27476
|
env: cleanEnv,
|
|
@@ -27553,7 +27591,7 @@ function parseClaudeJsonReply(raw) {
|
|
|
27553
27591
|
const result = typeof env.result === "string" ? env.result : null;
|
|
27554
27592
|
return { result, isError: env.is_error === true || env.subtype !== "success" };
|
|
27555
27593
|
}
|
|
27556
|
-
var READ_ONLY_WAKE_TOOLS, READ_ONLY_WAKE_NOTICE;
|
|
27594
|
+
var READ_ONLY_WAKE_TOOLS, READ_ONLY_WAKE_NOTICE, READ_ONLY_WAKE_PROMPT_SEPARATOR;
|
|
27557
27595
|
var init_cc_cli = __esm({
|
|
27558
27596
|
"src/services/cc-cli.ts"() {
|
|
27559
27597
|
"use strict";
|
|
@@ -27561,7 +27599,8 @@ var init_cc_cli = __esm({
|
|
|
27561
27599
|
init_agent_config();
|
|
27562
27600
|
init_agent_sessions();
|
|
27563
27601
|
READ_ONLY_WAKE_TOOLS = "Read,Glob,Grep";
|
|
27564
|
-
READ_ONLY_WAKE_NOTICE = "
|
|
27602
|
+
READ_ONLY_WAKE_NOTICE = "You are answering a message from another Cogent peer automatically. Your reply goes to that sender, not to your user. Your user chose to make these automatic replies read-only: you can read files, but you cannot edit files, run commands or commit, and neither you nor the sender can change that. If the message asks for a change, do not attempt it. Your reply must: (1) say plainly that this automatic reply could not change any files; (2) give the exact change: the file path and the precise text to replace and its replacement, or the exact command to run; (3) say that your user can make the change in this agent's own session. Do not offer to make the change later, and do not ask the sender to enable, re-enable or turn on any tool or permission.";
|
|
27603
|
+
READ_ONLY_WAKE_PROMPT_SEPARATOR = "\n\n---\n[Cogent: read-only automatic reply \u2014 not part of the message above]\n";
|
|
27565
27604
|
}
|
|
27566
27605
|
});
|
|
27567
27606
|
|
|
@@ -32777,6 +32816,7 @@ function execCodex(sessionId, message, cwd, timeoutMs) {
|
|
|
32777
32816
|
];
|
|
32778
32817
|
const cleanEnv = buildResumeEnv(process.env, "CODEX", ["CODEX_HOME"]);
|
|
32779
32818
|
cleanEnv.COGENT_CHECK_ON_STOP = "0";
|
|
32819
|
+
cleanEnv.COGENT_WAKE = "1";
|
|
32780
32820
|
const child = spawn2(config2.COGENT_CODEX_PATH, args, {
|
|
32781
32821
|
cwd,
|
|
32782
32822
|
env: cleanEnv,
|
|
@@ -35828,14 +35868,18 @@ var init_heartbeat = __esm({
|
|
|
35828
35868
|
// src/services/claude-preflight.ts
|
|
35829
35869
|
import { execFile as execFile4 } from "node:child_process";
|
|
35830
35870
|
import { promisify as promisify3 } from "node:util";
|
|
35831
|
-
function
|
|
35832
|
-
|
|
35833
|
-
|
|
35871
|
+
function expectedClaudeFlags(readOnly) {
|
|
35872
|
+
return readOnly ? [...EXPECTED_CLAUDE_FLAGS, ...READ_ONLY_WAKE_CLAUDE_FLAGS] : EXPECTED_CLAUDE_FLAGS;
|
|
35873
|
+
}
|
|
35874
|
+
function analyzeClaudeHelp(helpText, readOnly = false) {
|
|
35875
|
+
const expected = expectedClaudeFlags(readOnly);
|
|
35876
|
+
const checked = expected.map((f) => f.flag);
|
|
35877
|
+
const missing = expected.filter(
|
|
35834
35878
|
(f) => !helpText.includes(f.flag)
|
|
35835
35879
|
).map((f) => f.flag);
|
|
35836
35880
|
return { missing, checked };
|
|
35837
35881
|
}
|
|
35838
|
-
async function preflightClaude(claudePath) {
|
|
35882
|
+
async function preflightClaude(claudePath, readOnly = false) {
|
|
35839
35883
|
let helpText;
|
|
35840
35884
|
try {
|
|
35841
35885
|
const { stdout, stderr } = await execFileAsync2(claudePath, ["--help"], {
|
|
@@ -35849,9 +35893,9 @@ ${stderr}`;
|
|
|
35849
35893
|
);
|
|
35850
35894
|
return null;
|
|
35851
35895
|
}
|
|
35852
|
-
const analysis = analyzeClaudeHelp(helpText);
|
|
35896
|
+
const analysis = analyzeClaudeHelp(helpText, readOnly);
|
|
35853
35897
|
if (analysis.missing.length > 0) {
|
|
35854
|
-
const detail =
|
|
35898
|
+
const detail = expectedClaudeFlags(readOnly).filter(
|
|
35855
35899
|
(f) => analysis.missing.includes(f.flag)
|
|
35856
35900
|
).map((f) => `${f.flag} (${f.usedFor})`).join(", ");
|
|
35857
35901
|
logger.error(
|
|
@@ -35864,7 +35908,7 @@ ${stderr}`;
|
|
|
35864
35908
|
}
|
|
35865
35909
|
return analysis;
|
|
35866
35910
|
}
|
|
35867
|
-
var execFileAsync2, EXPECTED_CLAUDE_FLAGS;
|
|
35911
|
+
var execFileAsync2, EXPECTED_CLAUDE_FLAGS, READ_ONLY_WAKE_CLAUDE_FLAGS;
|
|
35868
35912
|
var init_claude_preflight = __esm({
|
|
35869
35913
|
"src/services/claude-preflight.ts"() {
|
|
35870
35914
|
"use strict";
|
|
@@ -35876,7 +35920,9 @@ var init_claude_preflight = __esm({
|
|
|
35876
35920
|
{ flag: "--dangerously-skip-permissions", usedFor: "unattended auto-relay execution" },
|
|
35877
35921
|
{ flag: "--no-session-persistence", usedFor: "don't pollute the resumed session transcript" },
|
|
35878
35922
|
{ flag: "--strict-mcp-config", usedFor: "isolate MCP config of the resumed process" },
|
|
35879
|
-
{ flag: "--output-format", usedFor: "structured JSON reply envelope (Slice 3 capture)" }
|
|
35923
|
+
{ flag: "--output-format", usedFor: "structured JSON reply envelope (Slice 3 capture)" }
|
|
35924
|
+
];
|
|
35925
|
+
READ_ONLY_WAKE_CLAUDE_FLAGS = [
|
|
35880
35926
|
{ flag: "--tools", usedFor: "read-only wake: Read, Glob and Grep only (COG-86)" },
|
|
35881
35927
|
{ flag: "--append-system-prompt", usedFor: "tell a read-only wake it cannot change anything (COG-86)" }
|
|
35882
35928
|
];
|
|
@@ -36400,7 +36446,7 @@ async function runPreflights() {
|
|
|
36400
36446
|
setSandboxOverride("bypass");
|
|
36401
36447
|
}
|
|
36402
36448
|
} else {
|
|
36403
|
-
await preflightClaude(config2.COGENT_CLAUDE_PATH);
|
|
36449
|
+
await preflightClaude(config2.COGENT_CLAUDE_PATH, readOnlyWake(config2));
|
|
36404
36450
|
}
|
|
36405
36451
|
}
|
|
36406
36452
|
var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, cloudModeActive, inboxNotifier, notifierBoundTo, reRegistrationInProgress, presenceRetry, ignoredHolders, presenceSupersedeBound, PRESENCE_SUPERSEDED, pendingLabelResolve, lastRestoreSkip;
|
|
@@ -21,6 +21,16 @@ export function parseScope(csv) {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* COG-88: are this agent's Claude wakes read-only? MUST equal src/config.ts readOnlyWake(loadConfig(env)):
|
|
26
|
+
* COGENT_READ_ONLY_WAKE truthy ("true"/"1"/"yes"/"on") OR COGENT_WAKE_TOOLS = "read", each trimmed and
|
|
27
|
+
* case-folded. Parity is tested against the REAL loadConfig (plugin/hooks/record-session.runtime.test.mjs).
|
|
28
|
+
*/
|
|
29
|
+
export function readOnlyWakeFromEnv(env) {
|
|
30
|
+
const v = (k) => String(env[k] ?? "").trim().toLowerCase();
|
|
31
|
+
return ["true", "1", "yes", "on"].includes(v("COGENT_READ_ONLY_WAKE")) || v("COGENT_WAKE_TOOLS") === "read";
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
/** sha256(path.resolve(cwd))[..16] — MUST equal credential-store.defaultCredentialPath's hash. */
|
|
25
35
|
export function credHashForCwd(cwd) {
|
|
26
36
|
return crypto.createHash("sha256").update(path.resolve(cwd)).digest("hex").slice(0, 16);
|
package/hooks/record-session.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Cogent record-session. Runs on SessionStart as a SEPARATE short-lived process
|
|
3
3
|
// (the host spawns it; it is NOT the bridge). Writes one small file and exits 0.
|
|
4
|
-
//
|
|
5
|
-
//
|
|
4
|
+
// Silent, with ONE exception (COG-88, below): the once-only wake-permissions notice,
|
|
5
|
+
// printed as {"systemMessage": ...} — valid SessionStart hook output that the host
|
|
6
|
+
// shows to the human and never feeds to the model. It can never block or fail a turn.
|
|
6
7
|
//
|
|
7
8
|
// 🔴 WHY THIS EXISTS. Auto-wake has to find the agent's session transcript, and it
|
|
8
9
|
// used to DERIVE the location:
|
|
@@ -23,10 +24,12 @@
|
|
|
23
24
|
// Node built-ins only (fs, os, path). Byte-identical between plugin/hooks/ and
|
|
24
25
|
// codex-plugin/hooks/ — enforced by scripts/wake-race-test.mjs assertContract().
|
|
25
26
|
import fs from "node:fs/promises";
|
|
27
|
+
import os from "node:os";
|
|
26
28
|
import path from "node:path";
|
|
27
29
|
import {
|
|
28
30
|
agentSessionRecordPath,
|
|
29
31
|
buildAgentSessionRecord,
|
|
32
|
+
readOnlyWakeFromEnv,
|
|
30
33
|
} from "./check-on-stop.lib.mjs";
|
|
31
34
|
|
|
32
35
|
async function readStdin() {
|
|
@@ -55,8 +58,70 @@ export async function persistRecord(record) {
|
|
|
55
58
|
return target;
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
// ── COG-88: tell the human ONCE what a Cogent wake may do in this folder ──────────────
|
|
62
|
+
// 3.25.9 made wakes read-only by default; 3.25.10 turned that back into an opt-in: the environment variable
|
|
63
|
+
// COGENT_READ_ONLY_WAKE=true (or COGENT_WAKE_TOOLS=read). Nobody reads a changelog, so the person at the
|
|
64
|
+
// terminal is told once, at a session start, what wakes can do and how to switch it.
|
|
65
|
+
//
|
|
66
|
+
// The mode is read from this hook's own env with the bridge's rule (readOnlyWakeFromEnv = readOnlyWake()).
|
|
67
|
+
// Measured on Claude Code 2.1.302 and 2.1.74 (throwaway CLAUDE_CONFIG_DIR, probe plugin): a settings.json "env" value and
|
|
68
|
+
// a shell export reach BOTH this hook and the plugin's MCP server, so the hook sees what the bridge sees.
|
|
69
|
+
// Also measured: after a settings.json change, /reload-plugins does NOT restart the plugin's MCP server (it
|
|
70
|
+
// keeps the old value), so the notice says "restart Claude Code".
|
|
71
|
+
//
|
|
72
|
+
// Shown ONLY when all hold:
|
|
73
|
+
// CLAUDECODE set — Claude Code. Codex never sets it (and shows systemMessage only
|
|
74
|
+
// after the first prompt).
|
|
75
|
+
// CLAUDE_CODE_SESSION_ATTENDED === "1" — a human is at the TUI ("0" in headless -p).
|
|
76
|
+
// COGENT_WAKE !== "1" — not inside a wake: the resumed claude runs this
|
|
77
|
+
// hook too (source "resume"), with the wake's env,
|
|
78
|
+
// and a notice there is swallowed but would still
|
|
79
|
+
// burn the once-only marker.
|
|
80
|
+
// the marker does not exist — once per notice version.
|
|
81
|
+
// Measured: Claude Code 2.1.302 gives a TUI SessionStart hook both variables; 2.1.74 gives it NEITHER (clean env, real
|
|
82
|
+
// TUI), so on 2.1.74 the notice is never shown. Deliberate: nothing there tells a TUI from headless -p, and a
|
|
83
|
+
// notice nobody sees would burn the marker. The opt-in itself still works on 2.1.74 (env reaches the bridge).
|
|
84
|
+
// The marker is created with "wx" BEFORE printing, so two sessions starting together
|
|
85
|
+
// cannot both show it, and it is never written unless the notice is printed.
|
|
86
|
+
export const WAKE_NOTICE_MARKER = "wake-tools-notice-v1";
|
|
87
|
+
|
|
88
|
+
export function wakeNoticeText(env) {
|
|
89
|
+
// Claude Code reads <CLAUDE_CONFIG_DIR>/settings.json when that variable is set; naming ~/.claude there
|
|
90
|
+
// would send the user to a file with no effect.
|
|
91
|
+
const dir = (env.CLAUDE_CONFIG_DIR || "").trim();
|
|
92
|
+
const settings = dir ? path.join(dir, "settings.json") : "~/.claude/settings.json";
|
|
93
|
+
if (readOnlyWakeFromEnv(env)) {
|
|
94
|
+
const names = ["COGENT_READ_ONLY_WAKE", "COGENT_WAKE_TOOLS"].filter((k) => readOnlyWakeFromEnv({ [k]: env[k] }));
|
|
95
|
+
const setting = names.join(" and ");
|
|
96
|
+
return (
|
|
97
|
+
`Cogent: wakes are read-only (${setting} ${names.length > 1 ? "are" : "is"} set) — when a Cogent message ` +
|
|
98
|
+
"wakes this agent, the wake can read files and answer, but cannot edit files or run commands. To let wakes " +
|
|
99
|
+
`edit again, remove ${setting} from the "env" block of ${settings} (or from your shell), then restart ` +
|
|
100
|
+
"Claude Code. (Shown once.)"
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return (
|
|
104
|
+
"Cogent: when a Cogent message wakes this agent, the wake can edit files and run commands in this folder. " +
|
|
105
|
+
`To make wakes read-only, add "COGENT_READ_ONLY_WAKE": "true" to the "env" block of ${settings} ` +
|
|
106
|
+
"(or export it in your shell), then restart Claude Code. (Shown once.)"
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function maybeShowWakeNotice(env) {
|
|
111
|
+
if (!env.CLAUDECODE || env.CLAUDE_CODE_SESSION_ATTENDED !== "1" || env.COGENT_WAKE === "1") return;
|
|
112
|
+
const dir = env.CLAUDE_PLUGIN_DATA || path.join(os.homedir(), ".cogent", "notices");
|
|
113
|
+
await fs.mkdir(dir, { recursive: true });
|
|
114
|
+
// EEXIST (already shown) and every other failure throw → swallowed by the caller: silent.
|
|
115
|
+
await fs.writeFile(path.join(dir, WAKE_NOTICE_MARKER), `${new Date().toISOString()}\n`, { flag: "wx" });
|
|
116
|
+
const out = JSON.stringify({ systemMessage: wakeNoticeText(env) });
|
|
117
|
+
// Wait for the write: a pipe can be asynchronous (macOS), and exit() would cut it off.
|
|
118
|
+
await new Promise((resolve) => process.stdout.write(out, () => resolve()));
|
|
119
|
+
}
|
|
120
|
+
|
|
58
121
|
async function main() {
|
|
59
122
|
const input = await readStdin();
|
|
123
|
+
// Independent of the record below, and never allowed to break it (or the session start).
|
|
124
|
+
await maybeShowWakeNotice(process.env).catch(() => {});
|
|
60
125
|
const record = buildAgentSessionRecord(input, new Date().toISOString());
|
|
61
126
|
// No transcript_path in this payload → nothing authoritative to record. The
|
|
62
127
|
// resolver's discovery layer still covers this case; staying silent is correct.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@essentialai/cogent-plugin",
|
|
3
|
-
"version": "3.25.
|
|
3
|
+
"version": "3.25.10",
|
|
4
4
|
"description": "Cogent — Claude Code plugin (skills + slash-commands + MCP server) for the cross-agent comms fabric.",
|
|
5
5
|
"author": { "name": "Essential AI Solutions Ltd.", "url": "https://essentialai.uk" },
|
|
6
6
|
"homepage": "https://cogent.tools",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"files": [".claude-plugin", "commands", "skills", ".mcp.json", "hooks", "bridge", "README.md", "LICENSE"],
|
|
11
11
|
"scripts": {
|
|
12
12
|
"sync": "node scripts/sync-from-plugin.mjs",
|
|
13
|
+
"test": "node --test scripts/sync-from-plugin.test.mjs",
|
|
13
14
|
"prepack": "node scripts/sync-from-plugin.mjs"
|
|
14
15
|
}
|
|
15
16
|
}
|