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 +5 -4
- package/bin/syntropic.js +40 -0
- package/commands/config-utils.js +1 -1
- package/commands/init.js +1 -34
- package/commands/report.js +15 -4
- package/package.json +1 -1
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
|
-
|
|
|
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'),
|
package/commands/config-utils.js
CHANGED
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
|
|
308
|
+
scripts/health-check.js Local health check script
|
|
342
309
|
|
|
343
310
|
Tools configured: ${selectedTools.map(t => TOOLS[t].label).join(', ')}
|
|
344
311
|
|
package/commands/report.js
CHANGED
|
@@ -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
|
|
140
|
-
|
|
141
|
-
|
|
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
|
|
155
|
+
return false; // Build failed — report 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.
|
|
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"
|