syntropic 0.9.1 → 0.9.2

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/README.md CHANGED
@@ -66,16 +66,17 @@ Built in production on a real product (27 AI agents, 8-lens analyser, CLI, 7 fre
66
66
 
67
67
  **Why it matters.** The PRISM network grows exponentially with contributors. Every anonymous report adds signal — which cycle weights work for which project shapes, where pipelines break down, what patterns lead to first-pass success. More contributors = better data = smarter rules for everyone.
68
68
 
69
- **Contributors get more.** When telemetry is enabled, your PRISM sync fetches live network benchmarks — real success rates, iteration counts, and pattern intelligence computed from aggregate data across all contributors. When telemetry is disabled, you still get the full EG rules and agents, but benchmarks are static baselines only. No account needed — your identity is a double-hashed device fingerprint ([pseudonymisation details](https://zenodo.org/records/17894441)).
69
+ **Contributors get more.** When telemetry is enabled, your PRISM sync fetches live network benchmarks — real success rates, iteration counts, and pattern intelligence computed from aggregate data across all contributors. This is how the methodology caught 3 classes of production bugs before they reached users, and how 12 test-to-production promotions were verified clean. When telemetry is disabled, you still get the full EG rules and agents, but benchmarks are static baselines only — you lose the network learning that makes rules smarter over time. No account needed — your identity is a double-hashed device fingerprint ([pseudonymisation details](https://zenodo.org/records/17894441)).
70
70
 
71
71
  | | Community (telemetry off) | Contributor (telemetry on) |
72
72
  |---|---|---|
73
73
  | EG rules | Full | Full |
74
74
  | Pipeline agents | Full | Full |
75
75
  | Governance docs | Full | Full |
76
- | Benchmarks | Static baselines | **Live network data** |
77
- | Pattern intelligence | Frozen snapshot | **Updated from aggregate reports** |
78
- | Network benefit | None | **Your reports improve rules for everyone** |
76
+ | Benchmarks | Static baselines | **Live network data** (success rates, iteration counts, failure patterns) |
77
+ | Pattern intelligence | Frozen snapshot | **Updated from aggregate reports** (which cycle weights work for your stack) |
78
+ | Cycle recommendations | Generic defaults | **Tuned by real data** (upgrade/downgrade triggers from contributor patterns) |
79
+ | Network benefit | None | **Your reports improve rules for everyone — including you** |
79
80
 
80
81
  Default: on. Opt out anytime:
81
82
 
package/bin/syntropic.js CHANGED
@@ -13,6 +13,46 @@
13
13
  const args = process.argv.slice(2);
14
14
  const command = args[0];
15
15
 
16
+ // Check for updates (once per day, non-blocking)
17
+ function checkForUpdates() {
18
+ try {
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+ const configDir = path.join(require('os').homedir(), '.syntropic');
22
+ const checkFile = path.join(configDir, '.update-check');
23
+ const now = Date.now();
24
+
25
+ // Only check once per day
26
+ if (fs.existsSync(checkFile)) {
27
+ const lastCheck = parseInt(fs.readFileSync(checkFile, 'utf8'), 10);
28
+ if (now - lastCheck < 86400000) return; // 24 hours
29
+ }
30
+
31
+ // Write timestamp immediately (even if check fails)
32
+ if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
33
+ fs.writeFileSync(checkFile, String(now), 'utf8');
34
+
35
+ // Non-blocking check against npm registry
36
+ const https = require('https');
37
+ const req = https.get('https://registry.npmjs.org/syntropic/latest', { timeout: 3000 }, (res) => {
38
+ let data = '';
39
+ res.on('data', (chunk) => data += chunk);
40
+ res.on('end', () => {
41
+ try {
42
+ const latest = JSON.parse(data).version;
43
+ const current = require('../package.json').version;
44
+ if (latest && latest !== current) {
45
+ console.log(`\n Update available: ${current} → ${latest} — run \`npm i -g syntropic\`\n`);
46
+ }
47
+ } catch {}
48
+ });
49
+ });
50
+ req.on('error', () => {});
51
+ req.on('timeout', () => req.destroy());
52
+ } catch {}
53
+ }
54
+ checkForUpdates();
55
+
16
56
  const COMMANDS = {
17
57
  audit: () => require('../commands/audit'),
18
58
  init: () => require('../commands/init'),
@@ -25,7 +25,7 @@ function ensureConfig() {
25
25
  config: null,
26
26
  },
27
27
  };
28
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
28
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { encoding: 'utf8', mode: 0o600 });
29
29
  }
30
30
  }
31
31
 
package/commands/init.js CHANGED
@@ -86,33 +86,6 @@ function replaceInFile(filePath, replacements) {
86
86
  fs.writeFileSync(filePath, content, 'utf8');
87
87
  }
88
88
 
89
- function installPostCommitHook(targetDir) {
90
- const hooksDir = path.join(targetDir, '.git', 'hooks');
91
- if (!fs.existsSync(hooksDir)) return false; // Not a git repo
92
-
93
- const hookPath = path.join(hooksDir, 'post-commit');
94
- if (fs.existsSync(hookPath)) {
95
- // Don't overwrite existing hook — check if it already has syntropic
96
- const existing = fs.readFileSync(hookPath, 'utf8');
97
- if (existing.includes('syntropic report')) return 'exists';
98
- // Append to existing hook
99
- fs.appendFileSync(hookPath, '\n# Syntropic PRISM — anonymous cycle reporting\ncommand -v syntropic >/dev/null 2>&1 && syntropic report >/dev/null 2>&1 &\n');
100
- console.log(` append .git/hooks/post-commit (added PRISM reporting)`);
101
- return 'appended';
102
- }
103
-
104
- // Create new hook
105
- const hookContent = `#!/bin/sh
106
- # Syntropic PRISM — anonymous cycle reporting
107
- # Fire-and-forget: never blocks commits, respects telemetry opt-out
108
- # Disable: syntropic telemetry disable (or delete this hook)
109
- command -v syntropic >/dev/null 2>&1 && syntropic report >/dev/null 2>&1 &
110
- `;
111
- fs.writeFileSync(hookPath, hookContent, { mode: 0o755 });
112
- console.log(` create .git/hooks/post-commit (PRISM cycle reporting)`);
113
- return 'created';
114
- }
115
-
116
89
  function hasSyntropicMarker(filePath) {
117
90
  if (!fs.existsSync(filePath)) return false;
118
91
  return fs.readFileSync(filePath, 'utf8').includes('<!-- syntropic -->');
@@ -325,12 +298,6 @@ async function run(args) {
325
298
  // Ensure ~/.syntropic/config.json exists (device_id, hmac_key, telemetry)
326
299
  ensureConfig();
327
300
 
328
- // Install post-commit hook for PRISM cycle reporting
329
- const hookResult = installPostCommitHook(targetDir);
330
- const hookLine = hookResult === 'created' || hookResult === 'appended'
331
- ? '\n .git/hooks/post-commit PRISM cycle reporting (anonymous)'
332
- : '';
333
-
334
301
  console.log(`
335
302
  Done! Your project is set up with the Syntropic pipeline.
336
303
 
@@ -338,7 +305,7 @@ async function run(args) {
338
305
  ${toolFiles}
339
306
  .claude/docs/ Project governance docs (North Star, Backlog, Issues, ADRs)
340
307
  .github/workflows/ Daily health check with auto-remediation
341
- scripts/health-check.js Local health check script${hookLine}
308
+ scripts/health-check.js Local health check script
342
309
 
343
310
  Tools configured: ${selectedTools.map(t => TOOLS[t].label).join(', ')}
344
311
 
@@ -135,13 +135,24 @@ function detectGovernanceChanges() {
135
135
  }
136
136
 
137
137
  function autoDetectSuccess() {
138
+ const { execSync } = require('child_process');
139
+ const fs = require('fs');
140
+ const path = require('path');
141
+
142
+ // If no package.json or no build script, default true (nothing to fail)
138
143
  try {
139
- const { execSync } = require('child_process');
140
- // Check if build passes
141
- execSync('npm run build --if-present 2>/dev/null', { encoding: 'utf8', timeout: 30000, stdio: 'pipe' });
144
+ const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
145
+ if (!pkg.scripts || !pkg.scripts.build) return true;
146
+ } catch {
147
+ return true; // No package.json — can't determine, assume ok
148
+ }
149
+
150
+ // Build script exists — actually check if it passes
151
+ try {
152
+ execSync('npm run build', { encoding: 'utf8', timeout: 30000, stdio: 'pipe' });
142
153
  return true;
143
154
  } catch {
144
- return true; // Default optimisticdon't penalise if no build script
155
+ return false; // Build failedreport accurately
145
156
  }
146
157
  }
147
158
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "syntropic",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Ship better software with a proven development methodology. Audit your git history, install disciplined rules, and track iterations — for Claude Code, Cursor, Windsurf, GitHub Copilot, and OpenAI Codex.",
5
5
  "bin": {
6
6
  "syntropic": "./bin/syntropic.js"