polygram 0.8.0-rc.18 → 0.8.0-rc.19

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,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "polygram",
4
- "version": "0.8.0-rc.18",
4
+ "version": "0.8.0-rc.19",
5
5
  "description": "Telegram integration for Claude Code that preserves the OpenClaw per-chat session model. Migration target for OpenClaw users. Multi-bot, multi-chat, per-topic isolation; SQLite transcripts; inline-keyboard approvals. Bundles /polygram:status|logs|pair-code|approvals admin commands and a history skill.",
6
6
  "keywords": [
7
7
  "telegram",
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Canonical-JSON stringification for chat_tool_decisions dedup.
3
+ *
4
+ * Used by polygram.js's canUseTool flow (rc.6 Phase 2 step 6):
5
+ * - lookup key for `chat_tool_decisions match_type='exact'`
6
+ * - input_pattern stored on "Always allow / Always deny" clicks
7
+ *
8
+ * Why canonical: Claude can reorder JSON keys between retries of
9
+ * the same tool call (different SDK versions, different temperature
10
+ * sampling). Without canonicalisation, the dedup digest would
11
+ * differ for semantically-identical calls and the user would see
12
+ * the same approval card twice (v4 plan §6.6 ship-breaker M8
13
+ * mitigation).
14
+ *
15
+ * Properties:
16
+ * - Keys sorted alphabetically at every nesting level
17
+ * - Arrays preserve order (only object keys are sorted)
18
+ * - No whitespace in output
19
+ * - null / undefined / primitive inputs round-trip via JSON.stringify
20
+ *
21
+ * NOT a full JSON canonicalisation spec (RFC 8785 / I-D
22
+ * cyberphone-json-canonicalization-scheme); we don't normalise
23
+ * number representations (1.0 vs 1, exponents) or string escapes.
24
+ * Sufficient for SDK-shaped tool inputs which are well-formed JSON
25
+ * objects with string keys.
26
+ */
27
+
28
+ 'use strict';
29
+
30
+ function canonicalizeToolInput(input) {
31
+ if (input == null || typeof input !== 'object') {
32
+ return JSON.stringify(input);
33
+ }
34
+ const sortRec = (v) => {
35
+ if (Array.isArray(v)) return v.map(sortRec);
36
+ if (v == null || typeof v !== 'object') return v;
37
+ const out = {};
38
+ for (const k of Object.keys(v).sort()) out[k] = sortRec(v[k]);
39
+ return out;
40
+ };
41
+ return JSON.stringify(sortRec(input));
42
+ }
43
+
44
+ module.exports = { canonicalizeToolInput };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygram",
3
- "version": "0.8.0-rc.18",
3
+ "version": "0.8.0-rc.19",
4
4
  "description": "Telegram daemon for Claude Code that preserves the OpenClaw per-chat session model. Migration path for OpenClaw users moving to Claude Code.",
5
5
  "main": "lib/ipc-client.js",
6
6
  "bin": {
package/polygram.js CHANGED
@@ -33,6 +33,7 @@ const { ProcessManager } = require('./lib/process-manager');
33
33
  const { ProcessManagerSdk } = require('./lib/process-manager-sdk');
34
34
  const { createAutosteerBuffer, makePostToolBatchHook } = require('./lib/autosteer-buffer');
35
35
  const { makeRouterPolicy, createPmRouter } = require('./lib/pm-router');
36
+ const { canonicalizeToolInput } = require('./lib/canonical-json');
36
37
  const agentLoader = require('./lib/agent-loader');
37
38
  const USE_SDK = process.env.POLYGRAM_USE_SDK === '1';
38
39
  const { createSender } = require('./lib/telegram');
@@ -1367,31 +1368,8 @@ function safeParse(s) {
1367
1368
  try { return JSON.parse(s); } catch { return s; }
1368
1369
  }
1369
1370
 
1370
- /**
1371
- * 0.8.0 Phase 2 step 6: canonical-JSON-stringify of a tool input
1372
- * object. Keys sorted alphabetically; no whitespace. Used as the
1373
- * dedup key for chat_tool_decisions match_type='exact' lookups
1374
- * and as the input_pattern stored on "Always allow" clicks.
1375
- *
1376
- * Why canonical: Claude can reorder JSON keys between retries of
1377
- * the same tool call (different SDK versions, different temperature
1378
- * sampling). Without canonicalisation, the dedup digest would
1379
- * differ for semantically-identical calls and the user would see
1380
- * the same approval card twice (ship-breaker M8 mitigation).
1381
- */
1382
- function canonicalizeToolInput(input) {
1383
- if (input == null || typeof input !== 'object') {
1384
- return JSON.stringify(input);
1385
- }
1386
- const sortRec = (v) => {
1387
- if (Array.isArray(v)) return v.map(sortRec);
1388
- if (v == null || typeof v !== 'object') return v;
1389
- const out = {};
1390
- for (const k of Object.keys(v).sort()) out[k] = sortRec(v[k]);
1391
- return out;
1392
- };
1393
- return JSON.stringify(sortRec(input));
1394
- }
1371
+ // 0.8.0-rc.18+: canonicalizeToolInput moved to lib/canonical-json.js
1372
+ // for testability. Same function, no behavior change.
1395
1373
 
1396
1374
  /**
1397
1375
  * 0.8.0 Phase 2 step 6: SDK canUseTool callback. Hands back to the