@synkro-sh/cli 1.4.99 → 1.4.101

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/dist/bootstrap.js CHANGED
@@ -992,7 +992,7 @@ export async function channelUp(port = 18929): Promise<boolean> {
992
992
  const done = (ok: boolean) => { try { sock.destroy(); } catch {} resolve(ok); };
993
993
  sock.once('connect', () => done(true));
994
994
  sock.once('error', () => done(false));
995
- sock.setTimeout(500, () => done(false));
995
+ sock.setTimeout(3000, () => done(false));
996
996
  });
997
997
  }
998
998
 
@@ -2016,6 +2016,7 @@ async function main() {
2016
2016
  'User intent (last human message): ' + (transcript.userIntent || 'none stated'),
2017
2017
  'Last user prompt: ' + (lastPrompt || 'none'),
2018
2018
  'Org rules: ' + JSON.stringify(config.rules),
2019
+ 'IMPORTANT: If a rule is violated, ALWAYS return ok=false with the rule_id and reason, regardless of the rule mode. Do NOT pass a command just because the rule mode is "audit". The enforcement layer handles audit vs blocking \u2014 your job is only to detect violations.',
2019
2020
  ].join('\\n');
2020
2021
 
2021
2022
  let gradeResp: string;
@@ -2964,6 +2965,9 @@ async function main() {
2964
2965
  'User intent (last human message): ' + (transcript.userIntent || 'none stated'),
2965
2966
  'Last user prompt: ' + (lastPrompt || 'none'),
2966
2967
  'Org rules: ' + JSON.stringify(config.rules),
2968
+ 'IMPORTANT: If a rule is violated, ALWAYS return ok=false with the rule_id and reason, regardless of the rule mode. Do NOT pass a command just because the rule mode is "audit". The enforcement layer handles audit vs blocking — your job is only to detect violations.',
2969
+ 'When passing (ok=true), cite which rules you checked and why they passed (e.g. "R006 satisfied: typecheck found in session history"). Be specific, not generic.',
2970
+ 'Rules with preconditions (e.g. "run X before Y") are CONSUMED after the protected action completes. Use the session history timestamps to determine ordering: a precondition satisfied before the last occurrence of the protected action does NOT satisfy the next occurrence. Each new protected action needs its precondition re-satisfied.',
2967
2971
  ].filter(Boolean).join('\\n');
2968
2972
 
2969
2973
  let gradeResp: string;
@@ -3004,7 +3008,9 @@ async function main() {
3004
3008
  });
3005
3009
  }
3006
3010
  } else {
3007
- const reason = tagStr + ' bashGuard pass: ' + (verdict.reason || 'no policy violations detected');
3011
+ const auditRuleIds = (config.rules || []).filter((r: any) => r.mode === 'audit').map((r: any) => r.rule_id || r.id).filter(Boolean);
3012
+ const auditNote = auditRuleIds.length > 0 ? ' (audit rules checked: ' + auditRuleIds.join(', ') + ')' : '';
3013
+ const reason = tagStr + ' bashGuard → pass: ' + (verdict.reason || 'no policy violations detected') + auditNote;
3008
3014
  const combined = (installScanMsg ? installScanMsg + '\\n' : '') + reason;
3009
3015
  outputJson({ systemMessage: combined, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: combined } });
3010
3016
  dispatchCapture(jwt, 'bash', 'pass', 'audit', verdict.category || 'trivial_utility',
@@ -3149,6 +3155,7 @@ async function main() {
3149
3155
  'User intent (last human message): ' + (transcript.userIntent || 'none stated'),
3150
3156
  'Last user prompt: ' + (lastPrompt || 'none'),
3151
3157
  'Org rules: ' + JSON.stringify(config.rules),
3158
+ 'IMPORTANT: If a rule is violated, ALWAYS return ok=false with the rule_id and reason, regardless of the rule mode. Do NOT pass a command just because the rule mode is "audit". The enforcement layer handles audit vs blocking \u2014 your job is only to detect violations.',
3152
3159
  ].filter(Boolean).join('\\n');
3153
3160
 
3154
3161
  let gradeResp: string;
@@ -5445,7 +5452,7 @@ __export(dockerInstall_exports, {
5445
5452
  imageTag: () => imageTag,
5446
5453
  waitForContainerReady: () => waitForContainerReady
5447
5454
  });
5448
- import { existsSync as existsSync8, mkdirSync as mkdirSync7 } from "fs";
5455
+ import { copyFileSync, existsSync as existsSync8, mkdirSync as mkdirSync7 } from "fs";
5449
5456
  import { homedir as homedir7 } from "os";
5450
5457
  import { join as join7 } from "path";
5451
5458
  import { spawnSync as spawnSync2 } from "child_process";
@@ -5472,8 +5479,13 @@ function claudeCredsHostDir() {
5472
5479
  async function dockerInstall(opts = {}) {
5473
5480
  assertDockerAvailable();
5474
5481
  const image = imageTag();
5475
- const workers = String(opts.workersPerPool ?? 4);
5482
+ const workers = String(opts.workersPerPool ?? 8);
5476
5483
  mkdirSync7(PGDATA_PATH, { recursive: true });
5484
+ mkdirSync7(CLAUDE_HOST_STATE_DIR, { recursive: true });
5485
+ const hostClaudeJson = join7(homedir7(), ".claude.json");
5486
+ if (existsSync8(hostClaudeJson)) {
5487
+ copyFileSync(hostClaudeJson, CLAUDE_HOST_STATE_FILE);
5488
+ }
5477
5489
  if (!existsSync8(MCP_JWT_PATH)) {
5478
5490
  throw new DockerInstallError(
5479
5491
  `MCP JWT missing at ${MCP_JWT_PATH}. The installer should mint this before calling dockerInstall.`
@@ -5529,7 +5541,7 @@ async function dockerInstall(opts = {}) {
5529
5541
  "-v",
5530
5542
  `${join7(homedir7(), ".claude")}:/data/claude-host:ro`,
5531
5543
  "-v",
5532
- `${join7(homedir7(), ".claude.json")}:/home/synkro/.claude.json:rw`,
5544
+ `${CLAUDE_HOST_STATE_DIR}:/data/claude-host-state:ro`,
5533
5545
  "-e",
5534
5546
  `WORKERS_PER_POOL=${workers}`,
5535
5547
  image
@@ -5574,7 +5586,7 @@ function dockerStatus() {
5574
5586
  healthz: `http://127.0.0.1:${HOST_MCP_PORT}/`
5575
5587
  };
5576
5588
  }
5577
- var SYNKRO_DIR3, MCP_JWT_PATH, SYNKRO_CREDS_PATH, PGDATA_PATH, HOST_MCP_PORT, HOST_GRADER_PORT, HOST_CWE_PORT, HOST_PG_PORT, CONTAINER_NAME, DEFAULT_IMAGE, DockerInstallError;
5589
+ var SYNKRO_DIR3, MCP_JWT_PATH, SYNKRO_CREDS_PATH, PGDATA_PATH, CLAUDE_HOST_STATE_DIR, CLAUDE_HOST_STATE_FILE, HOST_MCP_PORT, HOST_GRADER_PORT, HOST_CWE_PORT, HOST_PG_PORT, CONTAINER_NAME, DEFAULT_IMAGE, DockerInstallError;
5578
5590
  var init_dockerInstall = __esm({
5579
5591
  "cli/local-cc/dockerInstall.ts"() {
5580
5592
  "use strict";
@@ -5583,6 +5595,8 @@ var init_dockerInstall = __esm({
5583
5595
  MCP_JWT_PATH = join7(SYNKRO_DIR3, ".mcp-jwt");
5584
5596
  SYNKRO_CREDS_PATH = join7(SYNKRO_DIR3, "credentials.json");
5585
5597
  PGDATA_PATH = join7(SYNKRO_DIR3, "pgdata");
5598
+ CLAUDE_HOST_STATE_DIR = join7(SYNKRO_DIR3, "claude-host-state");
5599
+ CLAUDE_HOST_STATE_FILE = join7(CLAUDE_HOST_STATE_DIR, ".claude.json");
5586
5600
  HOST_MCP_PORT = parseInt(process.env.SYNKRO_HOST_MCP_PORT || "18931", 10);
5587
5601
  HOST_GRADER_PORT = parseInt(process.env.SYNKRO_HOST_GRADER_PORT || "18929", 10);
5588
5602
  HOST_CWE_PORT = parseInt(process.env.SYNKRO_HOST_CWE_PORT || "18930", 10);
@@ -5732,7 +5746,7 @@ function writeConfigEnv(opts) {
5732
5746
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
5733
5747
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
5734
5748
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
5735
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.99")}`
5749
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.101")}`
5736
5750
  ];
5737
5751
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
5738
5752
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -6496,7 +6510,7 @@ rl.on('line', async (line) => {
6496
6510
  });
6497
6511
 
6498
6512
  // cli/local-cc/install.ts
6499
- import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync8, chmodSync as chmodSync3, copyFileSync, renameSync as renameSync4, unlinkSync as unlinkSync4, openSync, fsyncSync, closeSync } from "fs";
6513
+ import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync8, chmodSync as chmodSync3, copyFileSync as copyFileSync2, renameSync as renameSync4, unlinkSync as unlinkSync4, openSync, fsyncSync, closeSync } from "fs";
6500
6514
  import { join as join9 } from "path";
6501
6515
  import { homedir as homedir9 } from "os";
6502
6516
  import { spawnSync as spawnSync3 } from "child_process";
@@ -6533,7 +6547,7 @@ function safelyMutateClaudeJson(mutator) {
6533
6547
  err
6534
6548
  );
6535
6549
  }
6536
- copyFileSync(CLAUDE_JSON_PATH, CLAUDE_JSON_BACKUP_PATH);
6550
+ copyFileSync2(CLAUDE_JSON_PATH, CLAUDE_JSON_BACKUP_PATH);
6537
6551
  const tmpPath = `${CLAUDE_JSON_PATH}.synkro-tmp.${process.pid}`;
6538
6552
  try {
6539
6553
  writeFileSync8(tmpPath, newText, "utf-8");
@@ -6550,7 +6564,7 @@ function safelyMutateClaudeJson(mutator) {
6550
6564
  } catch {
6551
6565
  }
6552
6566
  try {
6553
- copyFileSync(CLAUDE_JSON_BACKUP_PATH, CLAUDE_JSON_PATH);
6567
+ copyFileSync2(CLAUDE_JSON_BACKUP_PATH, CLAUDE_JSON_PATH);
6554
6568
  } catch {
6555
6569
  }
6556
6570
  throw new LocalCCInstallError(
@@ -7168,7 +7182,7 @@ var args = process.argv.slice(2);
7168
7182
  var cmd = args[0] || "";
7169
7183
  var subArgs = args.slice(1);
7170
7184
  function printVersion() {
7171
- console.log("1.4.99");
7185
+ console.log("1.4.101");
7172
7186
  }
7173
7187
  function printHelp() {
7174
7188
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents