dual-brain 0.1.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.
- package/AGENTS.md +97 -0
- package/CLAUDE.md +147 -0
- package/LICENSE +21 -0
- package/README.md +197 -0
- package/agents/implementer.md +22 -0
- package/agents/researcher.md +25 -0
- package/agents/verifier.md +30 -0
- package/bin/dual-brain.mjs +2868 -0
- package/hooks/auto-update-wrapper.mjs +102 -0
- package/hooks/auto-update.sh +67 -0
- package/hooks/budget-balancer.mjs +679 -0
- package/hooks/control-panel.mjs +1195 -0
- package/hooks/cost-logger.mjs +286 -0
- package/hooks/cost-report.mjs +351 -0
- package/hooks/decision-ledger.mjs +299 -0
- package/hooks/dual-brain-review.mjs +404 -0
- package/hooks/dual-brain-think.mjs +393 -0
- package/hooks/enforce-tier.mjs +469 -0
- package/hooks/failure-detector.mjs +138 -0
- package/hooks/gpt-work-dispatcher.mjs +512 -0
- package/hooks/head-guard.mjs +105 -0
- package/hooks/health-check.mjs +444 -0
- package/hooks/install-git-hooks.mjs +106 -0
- package/hooks/model-registry.mjs +859 -0
- package/hooks/plan-generator.mjs +544 -0
- package/hooks/profiles.mjs +254 -0
- package/hooks/quality-gate.mjs +355 -0
- package/hooks/risk-classifier.mjs +41 -0
- package/hooks/session-report.mjs +514 -0
- package/hooks/setup-wizard.mjs +130 -0
- package/hooks/summary-checkpoint.mjs +432 -0
- package/hooks/task-classifier.mjs +328 -0
- package/hooks/test-orchestrator.mjs +1077 -0
- package/hooks/vibe-memory.mjs +463 -0
- package/hooks/vibe-router.mjs +387 -0
- package/hooks/wave-orchestrator.mjs +1397 -0
- package/install.mjs +1541 -0
- package/mcp-server/README.md +81 -0
- package/mcp-server/index.mjs +388 -0
- package/orchestrator.json +215 -0
- package/package.json +108 -0
- package/playbooks/debug.json +49 -0
- package/playbooks/refactor.json +57 -0
- package/playbooks/security-audit.json +57 -0
- package/playbooks/security.json +38 -0
- package/playbooks/test-gen.json +48 -0
- package/plugin.json +22 -0
- package/review-rules.md +17 -0
- package/shell-hook.sh +26 -0
- package/skills/go.md +22 -0
- package/skills/review.md +19 -0
- package/skills/status.md +13 -0
- package/skills/think.md +22 -0
- package/src/brief.mjs +266 -0
- package/src/decide.mjs +635 -0
- package/src/decompose.mjs +331 -0
- package/src/detect.mjs +345 -0
- package/src/dispatch.mjs +942 -0
- package/src/health.mjs +253 -0
- package/src/index.mjs +44 -0
- package/src/install-hooks.mjs +100 -0
- package/src/playbook.mjs +257 -0
- package/src/profile.mjs +990 -0
- package/src/redact.mjs +192 -0
- package/src/repo.mjs +292 -0
- package/src/session.mjs +1036 -0
- package/src/tui.mjs +197 -0
- package/src/update-check.mjs +35 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// auto-update-wrapper.mjs — PostToolUse hook (Node.js entry point).
|
|
3
|
+
// Runs once per session, checks for dual-brain updates, installs silently.
|
|
4
|
+
// The parent exits immediately; all npm work happens in a detached child.
|
|
5
|
+
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
8
|
+
import { join, dirname, resolve } from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const WORKSPACE = resolve(__dirname, '..');
|
|
13
|
+
const STATE_DIR = join(WORKSPACE, '.dualbrain');
|
|
14
|
+
const LOCK_FILE = join(STATE_DIR, '.update-checked');
|
|
15
|
+
const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000;
|
|
16
|
+
|
|
17
|
+
// ── 1. Already checked recently? ─────────────────────────────────────────────
|
|
18
|
+
if (existsSync(LOCK_FILE)) {
|
|
19
|
+
try {
|
|
20
|
+
const lastCheck = parseInt(readFileSync(LOCK_FILE, 'utf8').trim(), 10);
|
|
21
|
+
if (Number.isFinite(lastCheck) && Date.now() - lastCheck < TWENTY_FOUR_HOURS) {
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
// Corrupt lock file — proceed with check
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ── 2. Write lock BEFORE spawning (prevents concurrent session races) ─────────
|
|
30
|
+
try {
|
|
31
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
32
|
+
writeFileSync(LOCK_FILE, String(Date.now()));
|
|
33
|
+
} catch {
|
|
34
|
+
process.exit(0); // Can't write state — bail silently
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ── 3. Resolve local version ─────────────────────────────────────────────────
|
|
38
|
+
let localVersion = '';
|
|
39
|
+
try {
|
|
40
|
+
const pkg = JSON.parse(readFileSync(join(WORKSPACE, 'package.json'), 'utf8'));
|
|
41
|
+
localVersion = pkg.version || '';
|
|
42
|
+
} catch {
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!localVersion) process.exit(0);
|
|
47
|
+
|
|
48
|
+
// ── 4. Detach background worker — parent returns immediately ─────────────────
|
|
49
|
+
// The worker script is inlined as a node -e string to avoid needing a temp file.
|
|
50
|
+
const workerScript = `
|
|
51
|
+
import { spawnSync } from 'child_process';
|
|
52
|
+
import { readFileSync } from 'fs';
|
|
53
|
+
|
|
54
|
+
const localVersion = ${JSON.stringify(localVersion)};
|
|
55
|
+
|
|
56
|
+
// 3-second timeout npm check
|
|
57
|
+
const npmResult = spawnSync('npm', ['view', 'dual-brain', 'version'], {
|
|
58
|
+
encoding: 'utf8',
|
|
59
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
60
|
+
timeout: 3000,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const latestVersion = (npmResult.stdout || '').trim();
|
|
64
|
+
if (!latestVersion) process.exit(0);
|
|
65
|
+
|
|
66
|
+
// Compare: is latest strictly greater than local?
|
|
67
|
+
function versionGt(a, b) {
|
|
68
|
+
const ap = a.replace(/^v/i, '').split('.').map(n => parseInt(n, 10) || 0);
|
|
69
|
+
const bp = b.replace(/^v/i, '').split('.').map(n => parseInt(n, 10) || 0);
|
|
70
|
+
const len = Math.max(ap.length, bp.length);
|
|
71
|
+
for (let i = 0; i < len; i++) {
|
|
72
|
+
const diff = (bp[i] || 0) - (ap[i] || 0);
|
|
73
|
+
if (diff !== 0) return diff > 0;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!versionGt(localVersion, latestVersion)) process.exit(0);
|
|
79
|
+
|
|
80
|
+
// Newer version found — print notice then install
|
|
81
|
+
process.stderr.write('dual-brain: updating v' + localVersion + ' → ' + latestVersion + '...\\n');
|
|
82
|
+
|
|
83
|
+
spawnSync('npx', ['-y', 'dual-brain@latest', '--quiet'], {
|
|
84
|
+
stdio: 'ignore',
|
|
85
|
+
timeout: 120000,
|
|
86
|
+
});
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
const child = spawn(
|
|
90
|
+
process.execPath,
|
|
91
|
+
['--input-type=module'],
|
|
92
|
+
{
|
|
93
|
+
detached: true,
|
|
94
|
+
stdio: ['pipe', 'ignore', 'ignore'],
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
child.stdin.write(workerScript);
|
|
99
|
+
child.stdin.end();
|
|
100
|
+
child.unref(); // Let parent exit without waiting
|
|
101
|
+
|
|
102
|
+
process.exit(0);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# auto-update.sh — PostToolUse hook that silently keeps dual-brain current.
|
|
3
|
+
#
|
|
4
|
+
# Runs once per session (lock file prevents repeated checks).
|
|
5
|
+
# Never blocks: npm check has a 3-second timeout, install is backgrounded.
|
|
6
|
+
# Exit 0 always — update failures are silent, not fatal.
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
WORKSPACE="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
12
|
+
STATE_DIR="${WORKSPACE}/.dualbrain"
|
|
13
|
+
LOCK_FILE="${STATE_DIR}/.update-checked"
|
|
14
|
+
TWENTY_FOUR_HOURS=86400 # seconds
|
|
15
|
+
|
|
16
|
+
# ── 1. Already checked recently? ────────────────────────────────────────────
|
|
17
|
+
if [[ -f "${LOCK_FILE}" ]]; then
|
|
18
|
+
last_check=$(cat "${LOCK_FILE}" 2>/dev/null || echo 0)
|
|
19
|
+
now=$(date +%s)
|
|
20
|
+
age=$(( now - last_check ))
|
|
21
|
+
if (( age < TWENTY_FOUR_HOURS )); then
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# ── 2. Write lock BEFORE doing anything (prevents concurrent session races) ──
|
|
27
|
+
mkdir -p "${STATE_DIR}"
|
|
28
|
+
date +%s > "${LOCK_FILE}"
|
|
29
|
+
|
|
30
|
+
# ── 3. Get local version ─────────────────────────────────────────────────────
|
|
31
|
+
PKG_JSON="${WORKSPACE}/package.json"
|
|
32
|
+
if [[ ! -f "${PKG_JSON}" ]]; then
|
|
33
|
+
exit 0
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
local_version=$(node -e "try{process.stdout.write(JSON.parse(require('fs').readFileSync('${PKG_JSON}','utf8')).version||'')}catch(e){}" 2>/dev/null || true)
|
|
37
|
+
if [[ -z "${local_version}" ]]; then
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# ── 4. Check npm for latest (3-second timeout, silent on failure) ─────────────
|
|
42
|
+
latest_version=$(timeout 3 npm view dual-brain version 2>/dev/null || true)
|
|
43
|
+
if [[ -z "${latest_version}" ]]; then
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# ── 5. Compare versions ───────────────────────────────────────────────────────
|
|
48
|
+
# Returns 1 if $1 < $2 (newer available), 0 otherwise
|
|
49
|
+
version_lt() {
|
|
50
|
+
[ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ] && [ "$1" != "$2" ]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if ! version_lt "${local_version}" "${latest_version}"; then
|
|
54
|
+
# Already up to date — lock file already updated above
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# ── 6. Newer version found — update in background ────────────────────────────
|
|
59
|
+
echo "dual-brain: updating v${local_version} → v${latest_version}..." >&2
|
|
60
|
+
|
|
61
|
+
# Spawn a completely detached background process so this hook returns immediately
|
|
62
|
+
nohup bash -c "
|
|
63
|
+
npx -y dual-brain@latest --quiet 2>/dev/null || true
|
|
64
|
+
" > /dev/null 2>&1 &
|
|
65
|
+
disown $! 2>/dev/null || true
|
|
66
|
+
|
|
67
|
+
exit 0
|