@craftsamo/signal-tools 0.1.1 → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signal-tools",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Signal tools for coding agents: chats, messages, contacts, received files and sends.",
5
5
  "author": {
6
6
  "name": "craftsamo",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signal-tools",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Signal tools for coding agents: chats, messages, contacts, received files and sends.",
5
5
  "author": {
6
6
  "name": "craftsamo",
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "signal-tools",
3
+ "version": "0.2.0",
4
+ "description": "Signal tools for coding agents: chats, messages, contacts, received files and sends.",
5
+ "author": {
6
+ "name": "craftsamo",
7
+ "url": "https://github.com/craft-agent"
8
+ },
9
+ "homepage": "https://github.com/craft-agent/signal-tools#readme",
10
+ "repository": "https://github.com/craft-agent/signal-tools",
11
+ "license": "MIT",
12
+ "skills": "./skills",
13
+ "mcpServers": {
14
+ "signal-tools": {
15
+ "command": "node",
16
+ "args": ["dist/mcp.js"],
17
+ "cwd": ".",
18
+ "env_vars": [
19
+ "SIGNAL_TOOLS_TOOLSETS",
20
+ "SIGNAL_TOOLS_READ_ONLY",
21
+ "SIGNAL_TOOLS_TOOLS",
22
+ "SIGNAL_TOOLS_EXCLUDE_TOOLS",
23
+ "SIGNAL_TOOLS_CONFIRM",
24
+ "SIGNAL_TOOLS_STATE_DIR",
25
+ "SIGNAL_TOOLS_DOWNLOAD_DIR",
26
+ "SIGNAL_TOOLS_SEND_DIRS",
27
+ "XDG_STATE_HOME"
28
+ ]
29
+ }
30
+ }
31
+ }
package/README.md CHANGED
@@ -240,10 +240,12 @@ Hermes.
240
240
  the entry points do. A tool that runs a program is tested against a fake of
241
241
  that program on `PATH`; no test reaches a real service.
242
242
  3. List it in `src/tools.ts`. A new toolset goes into `toolsets` in
243
- `src/project.ts` (and `defaultToolsets` when it is on by default).
243
+ `src/project.ts` (and `defaultToolsets` when it is on by default), and a
244
+ variable the tool reads besides the settings into `toolVariables`.
244
245
  4. Add or update the toolset's skill, `skills/<prefix>-<toolset>/SKILL.md`.
245
246
  5. Run `pnpm run build && pnpm run manifests` to list the tool in
246
- `plugin.yaml`, then describe it under "Tools and skills".
247
+ `plugin.yaml` and its variables in Codex's manifest, then describe it under
248
+ "Tools and skills".
247
249
 
248
250
  [`docs/conventions.md`](docs/conventions.md) has the rules each step follows.
249
251
 
@@ -323,17 +325,22 @@ Lists are comma-separated in a flag or a variable. Where each harness reads them
323
325
  flags and pass it the client's environment, so set the variables in the
324
326
  environment the harness runs in.
325
327
  - **Codex** passes a plugin's MCP server only a few basic variables (such as
326
- `PATH` and `HOME`), so the variables have no effect there. To change
327
- settings, or to give the server a variable it needs, add the server under
328
- `[mcp_servers]` in Codex's `config.toml` instead of using the plugin: flags
329
- go in `args`, `env_vars` names the variables to forward from Codex's
330
- environment, and `env` sets fixed values.
328
+ `PATH` and `HOME`) and those the plugin's manifest names, which are the
329
+ variables above and `XDG_STATE_HOME`, from which the state directory's
330
+ default comes: set them in the environment Codex runs in. A variable the
331
+ tools read besides the settings belongs in `toolVariables` in
332
+ `src/project.ts`; `pnpm run manifests` adds it to the manifest after the
333
+ settings' variables. To pass flags, or to give the server a variable the
334
+ package does not name, add the server under `[mcp_servers]` in Codex's
335
+ `config.toml` instead of using the plugin: flags go in `args`, `env_vars`
336
+ names the variables to forward from Codex's environment, and `env` sets
337
+ fixed values.
331
338
 
332
339
  ```toml
333
340
  [mcp_servers.signal-tools]
334
341
  command = "npx"
335
342
  args = ["-y", "@craftsamo/signal-tools@<version>", "--read-only"]
336
- env_vars = ["SIGNAL_TOOLS_STATE_DIR"]
343
+ env_vars = ["SIGNAL_TOOLS_STATE_DIR", "XDG_STATE_HOME"]
337
344
  ```
338
345
 
339
346
  ### Accounts and the sync service
@@ -404,8 +411,8 @@ one `default`), and every command takes `--state-dir` like the tools.
404
411
 
405
412
  ## Layout
406
413
 
407
- - `src/project.ts` — the package's name, tool ID prefix, setting prefix and
408
- toolsets.
414
+ - `src/project.ts` — the package's name, tool ID prefix, setting prefix,
415
+ toolsets and the other variables its tools read.
409
416
  - `src/core/` — the tool contract and the tools, free of any harness and of
410
417
  the project's names.
411
418
  - `src/tools.ts` — the list of every tool, which each entry point registers.
@@ -417,12 +424,14 @@ one `default`), and every command takes `--state-dir` like the tools.
417
424
  - `src/hermes/`, `plugin.yaml` and `__init__.py` — the Hermes plugin.
418
425
  - `skills/` — one skill per toolset, `skills/<name>/SKILL.md`, which every
419
426
  harness that takes skills loads from the package or plugin root.
420
- - `plugin.json`, `mcp.json`, `.mcp.json`, `.claude-plugin/`, `.agents/plugins/`,
427
+ - `.claude-plugin/`, `.codex-plugin/`, `.agents/plugins/`, `.mcp.json`,
421
428
  `.antigravity-plugin/` and `mcp_config.json` — the plugin manifests of the
422
- other harnesses. The root `.mcp.json` is the configuration Grok Build reads
423
- (with `${CLAUDE_PLUGIN_ROOT}`, the variable both Grok Build and Claude Code
424
- expand); when working on this repository in Claude Code, decline the project
425
- MCP server it offers from that file.
429
+ other harnesses. Codex reads `.codex-plugin/plugin.json`; a root
430
+ `plugin.json` would make it load the plugin as an Agent Plugin, whose tool
431
+ budget hides tools past a fixed size. The root `.mcp.json` is the
432
+ configuration Grok Build reads (with `${CLAUDE_PLUGIN_ROOT}`, the variable
433
+ both Grok Build and Claude Code expand); when working on this repository in
434
+ Claude Code, decline the project MCP server it offers from that file.
426
435
 
427
436
  How a release is made is in [`RELEASING.md`](RELEASING.md).
428
437
 
package/dist/cli.js CHANGED
@@ -25,7 +25,9 @@ var PROJECT = {
25
25
  /** The toolsets, in the order `all` lists them. */
26
26
  toolsets: ["account", "chats", "contacts", "files", "sends", "actions"],
27
27
  /** The toolsets on when a setting names none. */
28
- defaultToolsets: ["account", "chats", "contacts", "sends"]
28
+ defaultToolsets: ["account", "chats", "contacts", "sends"],
29
+ /** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
30
+ toolVariables: ["XDG_STATE_HOME"]
29
31
  };
30
32
 
31
33
  // src/core/account/read.ts
@@ -19750,12 +19752,24 @@ function date4(params) {
19750
19752
  }
19751
19753
 
19752
19754
  // src/core/errors.ts
19755
+ function deepFreeze(value) {
19756
+ if (value !== null && typeof value === "object") {
19757
+ Object.freeze(value);
19758
+ for (const child of Object.values(value)) {
19759
+ deepFreeze(child);
19760
+ }
19761
+ }
19762
+ return value;
19763
+ }
19753
19764
  var ToolError = class extends Error {
19754
19765
  code;
19755
19766
  constructor(code, message, options) {
19756
- super(message, options);
19767
+ super(message, options && "cause" in options ? { cause: options.cause } : void 0);
19757
19768
  this.name = "ToolError";
19758
19769
  this.code = code;
19770
+ if (options?.details !== void 0) {
19771
+ this.details = deepFreeze(JSON.parse(JSON.stringify(options.details)));
19772
+ }
19759
19773
  }
19760
19774
  };
19761
19775
  function isToolError(error62) {
@@ -25930,6 +25944,11 @@ var ALL_TOOLS = [
25930
25944
  signalMessageSend
25931
25945
  ];
25932
25946
 
25947
+ // src/entry/errors.ts
25948
+ function errorBody(code, message, details) {
25949
+ return { code, message, ...details !== void 0 && { details } };
25950
+ }
25951
+
25933
25952
  // src/entry/permission.ts
25934
25953
  function permissionResources(spec, args, ctx) {
25935
25954
  return writeTargets(spec, args, ctx);
@@ -28519,8 +28538,8 @@ function writeJson(io, document) {
28519
28538
  io.stdout(`${JSON.stringify(document)}
28520
28539
  `);
28521
28540
  }
28522
- function writeError(io, code, message) {
28523
- writeJson(io, { error: { code, message } });
28541
+ function writeError(io, code, message, details) {
28542
+ writeJson(io, { error: errorBody(code, message, details) });
28524
28543
  return EXIT_FAILED;
28525
28544
  }
28526
28545
  async function readArguments(io) {
@@ -28548,7 +28567,7 @@ async function runTool(command, io) {
28548
28567
  writeJson(io, { result });
28549
28568
  return EXIT_OK;
28550
28569
  } catch (error62) {
28551
- if (isToolError(error62)) return writeError(io, error62.code, error62.message);
28570
+ if (isToolError(error62)) return writeError(io, error62.code, error62.message, error62.details);
28552
28571
  if (isAbortError(error62)) return writeError(io, "internal_error", `${spec.id} was cancelled.`);
28553
28572
  io.stderr(`${PROGRAM2}: unexpected error while running ${spec.id}: ${errorDetail(error62)}
28554
28573
  `);
@@ -28571,7 +28590,7 @@ async function targetOf(command, io) {
28571
28590
  writeJson(io, { resources });
28572
28591
  return EXIT_OK;
28573
28592
  } catch (error62) {
28574
- if (isToolError(error62)) return writeError(io, error62.code, error62.message);
28593
+ if (isToolError(error62)) return writeError(io, error62.code, error62.message, error62.details);
28575
28594
  if (isAbortError(error62)) return writeError(io, "internal_error", "The call was cancelled.");
28576
28595
  io.stderr(`${PROGRAM2}: unexpected error while resolving the target: ${errorDetail(error62)}
28577
28596
  `);
package/dist/mcp.js CHANGED
@@ -28599,12 +28599,24 @@ var StdioServerTransport = class {
28599
28599
  };
28600
28600
 
28601
28601
  // src/core/errors.ts
28602
+ function deepFreeze(value) {
28603
+ if (value !== null && typeof value === "object") {
28604
+ Object.freeze(value);
28605
+ for (const child of Object.values(value)) {
28606
+ deepFreeze(child);
28607
+ }
28608
+ }
28609
+ return value;
28610
+ }
28602
28611
  var ToolError = class extends Error {
28603
28612
  code;
28604
28613
  constructor(code, message, options) {
28605
- super(message, options);
28614
+ super(message, options && "cause" in options ? { cause: options.cause } : void 0);
28606
28615
  this.name = "ToolError";
28607
28616
  this.code = code;
28617
+ if (options?.details !== void 0) {
28618
+ this.details = deepFreeze(JSON.parse(JSON.stringify(options.details)));
28619
+ }
28608
28620
  }
28609
28621
  };
28610
28622
  function isToolError(error62) {
@@ -28853,6 +28865,24 @@ function packageRoot(bundleUrl) {
28853
28865
  return dirname(dirname(fileURLToPath(bundleUrl)));
28854
28866
  }
28855
28867
 
28868
+ // src/project.ts
28869
+ var PROJECT = {
28870
+ /** The plugin, MCP server and program name. */
28871
+ name: "signal-tools",
28872
+ /** The command line the Hermes plugin calls. */
28873
+ cli: "signal-tools-cli",
28874
+ /** Every tool ID starts with `<toolPrefix>_`. */
28875
+ toolPrefix: "signal",
28876
+ /** Every setting's environment variable is `<envPrefix>_<SETTING>`. */
28877
+ envPrefix: "SIGNAL_TOOLS",
28878
+ /** The toolsets, in the order `all` lists them. */
28879
+ toolsets: ["account", "chats", "contacts", "files", "sends", "actions"],
28880
+ /** The toolsets on when a setting names none. */
28881
+ defaultToolsets: ["account", "chats", "contacts", "sends"],
28882
+ /** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
28883
+ toolVariables: ["XDG_STATE_HOME"]
28884
+ };
28885
+
28856
28886
  // src/entry/directory.ts
28857
28887
  import { homedir } from "node:os";
28858
28888
  import { isAbsolute as isAbsolute2, join, resolve, sep as sep2 } from "node:path";
@@ -28888,22 +28918,6 @@ function resolveDownloadDir(given, env, profile) {
28888
28918
  return given !== void 0 ? resolveGivenDirectory(given, home) : resolve2(home, DOWNLOADS_DIR, profile.name);
28889
28919
  }
28890
28920
 
28891
- // src/project.ts
28892
- var PROJECT = {
28893
- /** The plugin, MCP server and program name. */
28894
- name: "signal-tools",
28895
- /** The command line the Hermes plugin calls. */
28896
- cli: "signal-tools-cli",
28897
- /** Every tool ID starts with `<toolPrefix>_`. */
28898
- toolPrefix: "signal",
28899
- /** Every setting's environment variable is `<envPrefix>_<SETTING>`. */
28900
- envPrefix: "SIGNAL_TOOLS",
28901
- /** The toolsets, in the order `all` lists them. */
28902
- toolsets: ["account", "chats", "contacts", "files", "sends", "actions"],
28903
- /** The toolsets on when a setting names none. */
28904
- defaultToolsets: ["account", "chats", "contacts", "sends"]
28905
- };
28906
-
28907
28921
  // src/entry/profile.ts
28908
28922
  var PROJECT_PROFILE = {
28909
28923
  name: PROJECT.name,
@@ -36470,6 +36484,11 @@ var Server = class extends Protocol {
36470
36484
  }
36471
36485
  };
36472
36486
 
36487
+ // src/entry/errors.ts
36488
+ function errorBody(code, message, details) {
36489
+ return { code, message, ...details !== void 0 && { details } };
36490
+ }
36491
+
36473
36492
  // src/mcp/confirm.ts
36474
36493
  function supportsFormElicitation(server) {
36475
36494
  const elicitation = server.getClientCapabilities()?.elicitation;
@@ -36546,8 +36565,11 @@ function createWorkingDirResolver(server, fallback, ownDir) {
36546
36565
 
36547
36566
  // src/mcp/server.ts
36548
36567
  var DEFAULT_VERSION = "0.0.0";
36549
- function errorResult(code, message) {
36550
- return { isError: true, content: [{ type: "text", text: JSON.stringify({ error: { code, message } }) }] };
36568
+ function errorResult(code, message, details) {
36569
+ return {
36570
+ isError: true,
36571
+ content: [{ type: "text", text: JSON.stringify({ error: errorBody(code, message, details) }) }]
36572
+ };
36551
36573
  }
36552
36574
  function describeTool(spec) {
36553
36575
  const meta3 = toolMeta(spec);
@@ -36590,7 +36612,7 @@ function createServer(specs, settings, options = {}) {
36590
36612
  return { content: [{ type: "text", text: JSON.stringify(result) }], structuredContent: result };
36591
36613
  } catch (error62) {
36592
36614
  if (isAbortError(error62)) throw error62;
36593
- if (isToolError(error62)) return errorResult(error62.code, error62.message);
36615
+ if (isToolError(error62)) return errorResult(error62.code, error62.message, error62.details);
36594
36616
  log(
36595
36617
  `Unexpected error while running ${spec.id}: ${error62 instanceof Error ? error62.stack ?? error62.message : String(error62)}`
36596
36618
  );
@@ -36608,7 +36630,7 @@ async function main() {
36608
36630
  const settings = parseSettings(process.argv.slice(2), process.env);
36609
36631
  server = createServer(ALL_TOOLS, settings, {
36610
36632
  ownDir: packageRoot(import.meta.url),
36611
- version: true ? "0.1.1" : void 0
36633
+ version: true ? "0.2.0" : void 0
36612
36634
  });
36613
36635
  } catch (error62) {
36614
36636
  if (!isToolError(error62)) throw error62;
package/dist/opencode.js CHANGED
@@ -24,7 +24,9 @@ var PROJECT = {
24
24
  /** The toolsets, in the order `all` lists them. */
25
25
  toolsets: ["account", "chats", "contacts", "files", "sends", "actions"],
26
26
  /** The toolsets on when a setting names none. */
27
- defaultToolsets: ["account", "chats", "contacts", "sends"]
27
+ defaultToolsets: ["account", "chats", "contacts", "sends"],
28
+ /** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
29
+ toolVariables: ["XDG_STATE_HOME"]
28
30
  };
29
31
 
30
32
  // src/core/account/read.ts
@@ -19749,12 +19751,24 @@ function date4(params) {
19749
19751
  }
19750
19752
 
19751
19753
  // src/core/errors.ts
19754
+ function deepFreeze(value) {
19755
+ if (value !== null && typeof value === "object") {
19756
+ Object.freeze(value);
19757
+ for (const child of Object.values(value)) {
19758
+ deepFreeze(child);
19759
+ }
19760
+ }
19761
+ return value;
19762
+ }
19752
19763
  var ToolError = class extends Error {
19753
19764
  code;
19754
19765
  constructor(code, message, options) {
19755
- super(message, options);
19766
+ super(message, options && "cause" in options ? { cause: options.cause } : void 0);
19756
19767
  this.name = "ToolError";
19757
19768
  this.code = code;
19769
+ if (options?.details !== void 0) {
19770
+ this.details = deepFreeze(JSON.parse(JSON.stringify(options.details)));
19771
+ }
19758
19772
  }
19759
19773
  };
19760
19774
  function isToolError(error62) {
@@ -25681,6 +25695,12 @@ function permissionResources(spec, args, ctx) {
25681
25695
  return writeTargets(spec, args, ctx);
25682
25696
  }
25683
25697
 
25698
+ // src/entry/errors.ts
25699
+ function errorText(error62) {
25700
+ return `${error62.code}: ${error62.message}${error62.details !== void 0 ? `
25701
+ ${JSON.stringify(error62.details)}` : ""}`;
25702
+ }
25703
+
25684
25704
  // src/entry/profile.ts
25685
25705
  var PROJECT_PROFILE = {
25686
25706
  name: PROJECT.name,
@@ -25899,7 +25919,7 @@ async function runTool(spec, args, ctx) {
25899
25919
  return await invoke(spec, args, ctx);
25900
25920
  } catch (error62) {
25901
25921
  if (!isToolError(error62)) throw error62;
25902
- throw new Error(`${error62.code}: ${error62.message}`, { cause: error62 });
25922
+ throw new Error(errorText(error62), { cause: error62 });
25903
25923
  }
25904
25924
  }
25905
25925
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craftsamo/signal-tools",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Signal tools for coding agents: chats, messages, contacts, received files and sends.",
5
5
  "author": "craftsamo",
6
6
  "license": "MIT",
@@ -24,10 +24,9 @@
24
24
  "files": [
25
25
  "dist",
26
26
  "skills",
27
- "plugin.json",
28
- "mcp.json",
29
27
  ".mcp.json",
30
28
  ".claude-plugin",
29
+ ".codex-plugin",
31
30
  ".agents/plugins",
32
31
  ".antigravity-plugin",
33
32
  "mcp_config.json",
@@ -54,7 +53,7 @@
54
53
  "prepare": "node -e \"const fs=require('fs');if(fs.existsSync('.git')&&fs.existsSync('node_modules/husky'))require('child_process').execFileSync('husky',{stdio:'inherit'})\""
55
54
  },
56
55
  "devDependencies": {
57
- "@craftsamo/repo-kit": "^1.3.0",
56
+ "@craftsamo/repo-kit": "^1.4.0",
58
57
  "@modelcontextprotocol/sdk": "^1.32.2",
59
58
  "@opencode-ai/plugin": "^1.19.5",
60
59
  "@types/bun": "^1.4.4",
package/plugin.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  name: signal-tools
2
- version: 0.1.1
2
+ version: 0.2.0
3
3
  description: "Signal tools for coding agents: chats, messages, contacts, received files and sends."
4
4
  manifest_version: 1
5
5
  requires_hermes: ">=0.22"
@@ -36,10 +36,14 @@ def _read_document(stdout: str) -> dict[str, Any] | None:
36
36
 
37
37
 
38
38
  def _failure(code: int, stdout: str, stderr: str) -> str:
39
- """The error result of a command line that did not succeed: its ``<code>: <message>``, or its stderr."""
39
+ """The error result of a command line that did not succeed: its ``<code>: <message>`` and details line, or its stderr."""
40
40
  error = (_read_document(stdout) or {}).get("error")
41
41
  if isinstance(error, dict) and isinstance(error.get("code"), str) and isinstance(error.get("message"), str):
42
- return error_result(f"{error['code']}: {error['message']}")
42
+ message = f"{error['code']}: {error['message']}"
43
+ details = error.get("details")
44
+ if isinstance(details, dict):
45
+ message = f"{message}\n" + json.dumps(details, ensure_ascii=False, separators=(",", ":"))
46
+ return error_result(message)
43
47
  detail = stderr.strip() or f"exit status {code}"
44
48
  return error_result(f"{project.CLI_NAME} failed: {detail}")
45
49
 
package/mcp.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
3
- "mcpServers": {
4
- "signal-tools": {
5
- "type": "stdio",
6
- "command": "node",
7
- "args": ["${PLUGIN_ROOT}/dist/mcp.js"]
8
- }
9
- }
10
- }
package/plugin.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
- "name": "signal-tools",
4
- "version": "0.1.1",
5
- "description": "Signal tools for coding agents: chats, messages, contacts, received files and sends.",
6
- "author": {
7
- "name": "craftsamo",
8
- "url": "https://github.com/craft-agent"
9
- },
10
- "homepage": "https://github.com/craft-agent/signal-tools#readme",
11
- "repository": "https://github.com/craft-agent/signal-tools",
12
- "license": "MIT"
13
- }