spidersan 0.6.0 ā 0.10.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/CHANGELOG.md +65 -51
- package/README.md +238 -3
- package/dist/bin/spidersan.d.ts.map +1 -1
- package/dist/bin/spidersan.js +13 -1
- package/dist/bin/spidersan.js.map +1 -1
- package/dist/commands/abandon.d.ts.map +1 -1
- package/dist/commands/abandon.js +1 -9
- package/dist/commands/abandon.js.map +1 -1
- package/dist/commands/ai.d.ts +15 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +498 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/auto.d.ts.map +1 -1
- package/dist/commands/auto.js +2 -1
- package/dist/commands/auto.js.map +1 -1
- package/dist/commands/bot.d.ts +16 -0
- package/dist/commands/bot.d.ts.map +1 -0
- package/dist/commands/bot.js +416 -0
- package/dist/commands/bot.js.map +1 -0
- package/dist/commands/conflicts.d.ts.map +1 -1
- package/dist/commands/conflicts.js +49 -77
- package/dist/commands/conflicts.js.map +1 -1
- package/dist/commands/context.d.ts +8 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +104 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/cross-conflicts.d.ts.map +1 -1
- package/dist/commands/cross-conflicts.js +10 -44
- package/dist/commands/cross-conflicts.js.map +1 -1
- package/dist/commands/depends.d.ts.map +1 -1
- package/dist/commands/depends.js +1 -9
- package/dist/commands/depends.js.map +1 -1
- package/dist/commands/fleet-status.d.ts +14 -0
- package/dist/commands/fleet-status.d.ts.map +1 -0
- package/dist/commands/fleet-status.js +127 -0
- package/dist/commands/fleet-status.js.map +1 -0
- package/dist/commands/git-watch.d.ts +24 -0
- package/dist/commands/git-watch.d.ts.map +1 -0
- package/dist/commands/git-watch.js +84 -0
- package/dist/commands/git-watch.js.map +1 -0
- package/dist/commands/index.d.ts +5 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/merge-order.d.ts.map +1 -1
- package/dist/commands/merge-order.js +18 -67
- package/dist/commands/merge-order.js.map +1 -1
- package/dist/commands/merged.d.ts.map +1 -1
- package/dist/commands/merged.js +1 -9
- package/dist/commands/merged.js.map +1 -1
- package/dist/commands/pulse.d.ts.map +1 -1
- package/dist/commands/pulse.js +82 -82
- package/dist/commands/pulse.js.map +1 -1
- package/dist/commands/queen.d.ts.map +1 -1
- package/dist/commands/queen.js +11 -7
- package/dist/commands/queen.js.map +1 -1
- package/dist/commands/ready-check.d.ts +2 -1
- package/dist/commands/ready-check.d.ts.map +1 -1
- package/dist/commands/ready-check.js +6 -30
- package/dist/commands/ready-check.js.map +1 -1
- package/dist/commands/register.d.ts.map +1 -1
- package/dist/commands/register.js +22 -37
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/torrent.d.ts.map +1 -1
- package/dist/commands/torrent.js +29 -18
- package/dist/commands/torrent.js.map +1 -1
- package/dist/commands/watch.d.ts +6 -0
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +117 -30
- package/dist/commands/watch.js.map +1 -1
- package/dist/lib/ai/context-builder.d.ts +16 -0
- package/dist/lib/ai/context-builder.d.ts.map +1 -0
- package/dist/lib/ai/context-builder.js +216 -0
- package/dist/lib/ai/context-builder.js.map +1 -0
- package/dist/lib/ai/event-handler.d.ts +21 -0
- package/dist/lib/ai/event-handler.d.ts.map +1 -0
- package/dist/lib/ai/event-handler.js +98 -0
- package/dist/lib/ai/event-handler.js.map +1 -0
- package/dist/lib/ai/index.d.ts +13 -0
- package/dist/lib/ai/index.d.ts.map +1 -0
- package/dist/lib/ai/index.js +11 -0
- package/dist/lib/ai/index.js.map +1 -0
- package/dist/lib/ai/llm-client.d.ts +37 -0
- package/dist/lib/ai/llm-client.d.ts.map +1 -0
- package/dist/lib/ai/llm-client.js +225 -0
- package/dist/lib/ai/llm-client.js.map +1 -0
- package/dist/lib/ai/reasoner.d.ts +11 -0
- package/dist/lib/ai/reasoner.d.ts.map +1 -0
- package/dist/lib/ai/reasoner.js +246 -0
- package/dist/lib/ai/reasoner.js.map +1 -0
- package/dist/lib/ai/setup.d.ts +40 -0
- package/dist/lib/ai/setup.d.ts.map +1 -0
- package/dist/lib/ai/setup.js +154 -0
- package/dist/lib/ai/setup.js.map +1 -0
- package/dist/lib/ai/types.d.ts +135 -0
- package/dist/lib/ai/types.d.ts.map +1 -0
- package/dist/lib/ai/types.js +39 -0
- package/dist/lib/ai/types.js.map +1 -0
- package/dist/lib/colony-subscriber.d.ts +15 -12
- package/dist/lib/colony-subscriber.d.ts.map +1 -1
- package/dist/lib/colony-subscriber.js +146 -65
- package/dist/lib/colony-subscriber.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +18 -4
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/conflict-analyzer.d.ts +33 -0
- package/dist/lib/conflict-analyzer.d.ts.map +1 -0
- package/dist/lib/conflict-analyzer.js +114 -0
- package/dist/lib/conflict-analyzer.js.map +1 -0
- package/dist/lib/conflict-renderer.d.ts +7 -0
- package/dist/lib/conflict-renderer.d.ts.map +1 -0
- package/dist/lib/conflict-renderer.js +162 -0
- package/dist/lib/conflict-renderer.js.map +1 -0
- package/dist/lib/conflict-tier.d.ts +20 -0
- package/dist/lib/conflict-tier.d.ts.map +1 -0
- package/dist/lib/conflict-tier.js +49 -0
- package/dist/lib/conflict-tier.js.map +1 -0
- package/dist/lib/crypto.js +1 -1
- package/dist/lib/crypto.js.map +1 -1
- package/dist/lib/git-events-subscriber.d.ts +59 -0
- package/dist/lib/git-events-subscriber.d.ts.map +1 -0
- package/dist/lib/git-events-subscriber.js +779 -0
- package/dist/lib/git-events-subscriber.js.map +1 -0
- package/dist/lib/git.d.ts +15 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +180 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/github.d.ts.map +1 -1
- package/dist/lib/github.js +14 -9
- package/dist/lib/github.js.map +1 -1
- package/dist/lib/graph.d.ts +23 -0
- package/dist/lib/graph.d.ts.map +1 -0
- package/dist/lib/graph.js +134 -0
- package/dist/lib/graph.js.map +1 -0
- package/dist/lib/hub.d.ts +31 -0
- package/dist/lib/hub.d.ts.map +1 -0
- package/dist/lib/hub.js +92 -0
- package/dist/lib/hub.js.map +1 -0
- package/dist/lib/pulse-renderer.d.ts +19 -0
- package/dist/lib/pulse-renderer.d.ts.map +1 -0
- package/dist/lib/pulse-renderer.js +108 -0
- package/dist/lib/pulse-renderer.js.map +1 -0
- package/dist/lib/register-renderer.d.ts +10 -0
- package/dist/lib/register-renderer.d.ts.map +1 -0
- package/dist/lib/register-renderer.js +19 -0
- package/dist/lib/register-renderer.js.map +1 -0
- package/dist/lib/remote-drift.d.ts +61 -0
- package/dist/lib/remote-drift.d.ts.map +1 -0
- package/dist/lib/remote-drift.js +227 -0
- package/dist/lib/remote-drift.js.map +1 -0
- package/dist/lib/salvage-analyzer.d.ts.map +1 -1
- package/dist/lib/salvage-analyzer.js +2 -3
- package/dist/lib/salvage-analyzer.js.map +1 -1
- package/dist/lib/security.d.ts +11 -0
- package/dist/lib/security.d.ts.map +1 -1
- package/dist/lib/security.js +24 -1
- package/dist/lib/security.js.map +1 -1
- package/dist/lib/session-logger.d.ts +54 -0
- package/dist/lib/session-logger.d.ts.map +1 -0
- package/dist/lib/session-logger.js +136 -0
- package/dist/lib/session-logger.js.map +1 -0
- package/dist/lib/watch-renderer.d.ts +13 -0
- package/dist/lib/watch-renderer.d.ts.map +1 -0
- package/dist/lib/watch-renderer.js +35 -0
- package/dist/lib/watch-renderer.js.map +1 -0
- package/dist/storage/adapter.d.ts +4 -0
- package/dist/storage/adapter.d.ts.map +1 -1
- package/dist/storage/branch-registry-store.d.ts +13 -0
- package/dist/storage/branch-registry-store.d.ts.map +1 -0
- package/dist/storage/branch-registry-store.js +2 -0
- package/dist/storage/branch-registry-store.js.map +1 -0
- package/dist/storage/factory.d.ts +4 -0
- package/dist/storage/factory.d.ts.map +1 -1
- package/dist/storage/factory.js +25 -9
- package/dist/storage/factory.js.map +1 -1
- package/dist/storage/git-messages.d.ts +53 -0
- package/dist/storage/git-messages.d.ts.map +1 -0
- package/dist/storage/git-messages.js +376 -0
- package/dist/storage/git-messages.js.map +1 -0
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/json-branch-registry-store.d.ts +19 -0
- package/dist/storage/json-branch-registry-store.d.ts.map +1 -0
- package/dist/storage/json-branch-registry-store.js +112 -0
- package/dist/storage/json-branch-registry-store.js.map +1 -0
- package/dist/storage/local-messages.d.ts +37 -0
- package/dist/storage/local-messages.d.ts.map +1 -0
- package/dist/storage/local-messages.js +151 -0
- package/dist/storage/local-messages.js.map +1 -0
- package/dist/storage/local.d.ts +2 -6
- package/dist/storage/local.d.ts.map +1 -1
- package/dist/storage/local.js +13 -76
- package/dist/storage/local.js.map +1 -1
- package/dist/storage/memory-branch-registry-store.d.ts +16 -0
- package/dist/storage/memory-branch-registry-store.d.ts.map +1 -0
- package/dist/storage/memory-branch-registry-store.js +65 -0
- package/dist/storage/memory-branch-registry-store.js.map +1 -0
- package/dist/storage/message-adapter.d.ts +86 -0
- package/dist/storage/message-adapter.d.ts.map +1 -0
- package/dist/storage/message-adapter.js +28 -0
- package/dist/storage/message-adapter.js.map +1 -0
- package/dist/storage/message-factory.d.ts +36 -0
- package/dist/storage/message-factory.d.ts.map +1 -0
- package/dist/storage/message-factory.js +99 -0
- package/dist/storage/message-factory.js.map +1 -0
- package/dist/storage/mycmail-adapter.d.ts +38 -0
- package/dist/storage/mycmail-adapter.d.ts.map +1 -0
- package/dist/storage/mycmail-adapter.js +300 -0
- package/dist/storage/mycmail-adapter.js.map +1 -0
- package/dist/storage/supabase-registry-sync-client-impl.d.ts +46 -0
- package/dist/storage/supabase-registry-sync-client-impl.d.ts.map +1 -0
- package/dist/storage/supabase-registry-sync-client-impl.js +322 -0
- package/dist/storage/supabase-registry-sync-client-impl.js.map +1 -0
- package/dist/storage/supabase-registry-sync-client.d.ts +9 -0
- package/dist/storage/supabase-registry-sync-client.d.ts.map +1 -0
- package/dist/storage/supabase-registry-sync-client.js +2 -0
- package/dist/storage/supabase-registry-sync-client.js.map +1 -0
- package/dist/storage/supabase.d.ts +8 -46
- package/dist/storage/supabase.d.ts.map +1 -1
- package/dist/storage/supabase.js +30 -342
- package/dist/storage/supabase.js.map +1 -1
- package/dist/tui/screen.d.ts.map +1 -1
- package/dist/tui/screen.js +5 -3
- package/dist/tui/screen.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spidersan bot ā Message-driven git operations daemon via smalltoak.
|
|
3
|
+
*
|
|
4
|
+
* Polls smalltoak for /commands, executes git actions, replies with results.
|
|
5
|
+
* Requires envoak vault injection (GIT_BOT_ENABLED=true).
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* envoak vault inject --key ... -- spidersan bot
|
|
9
|
+
* spidersan bot --once
|
|
10
|
+
* spidersan bot add <name> --path <path> --branch <branch> --push <files>
|
|
11
|
+
* spidersan bot remove <name>
|
|
12
|
+
* spidersan bot repos
|
|
13
|
+
*/
|
|
14
|
+
import { Command } from 'commander';
|
|
15
|
+
import { execFileSync } from 'child_process';
|
|
16
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
17
|
+
import { join } from 'path';
|
|
18
|
+
import { homedir } from 'os';
|
|
19
|
+
// āā Config āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
20
|
+
const CONFIG_DIR = join(homedir(), '.spidersan');
|
|
21
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'bot.json');
|
|
22
|
+
const HWM_FILE = join(CONFIG_DIR, 'bot_hwm');
|
|
23
|
+
const AGENT_NAME = 'spidersan';
|
|
24
|
+
const SMALLTOAK_URL = (process.env.SMALLTOAK_SERVER_URL || '').replace(/\/+$/, '');
|
|
25
|
+
const SMALLTOAK_TOKEN = process.env.SMALLTOAK_TOKEN || '';
|
|
26
|
+
const POLL_INTERVAL = 15_000;
|
|
27
|
+
const SYNC_INTERVAL = 90_000;
|
|
28
|
+
const RATE_LIMIT = 10_000; // ms per repo
|
|
29
|
+
const VALID_COMMANDS = new Set(['sync', 'pull', 'push', 'status', 'conflicts', 'log']);
|
|
30
|
+
const BRANCH_RE = /^[\w/.-]{1,200}$/;
|
|
31
|
+
// Minimal env for git subprocesses ā excludes bot secrets (SMALLTOAK_TOKEN etc.)
|
|
32
|
+
function gitEnv() {
|
|
33
|
+
const env = { GIT_TERMINAL_PROMPT: '0' };
|
|
34
|
+
for (const k of ['HOME', 'PATH', 'GIT_SSH_COMMAND', 'SSH_AUTH_SOCK',
|
|
35
|
+
'GIT_AUTHOR_NAME', 'GIT_AUTHOR_EMAIL',
|
|
36
|
+
'GIT_COMMITTER_NAME', 'GIT_COMMITTER_EMAIL']) {
|
|
37
|
+
if (process.env[k] !== undefined)
|
|
38
|
+
env[k] = process.env[k];
|
|
39
|
+
}
|
|
40
|
+
return env;
|
|
41
|
+
}
|
|
42
|
+
// Env for spidersan subprocesses ā full env minus bot-specific secrets
|
|
43
|
+
function spidersanEnv() {
|
|
44
|
+
const { SMALLTOAK_TOKEN: _t, SMALLTOAK_SERVER_URL: _u, GIT_BOT_ENABLED: _e, ...rest } = process.env;
|
|
45
|
+
return rest;
|
|
46
|
+
}
|
|
47
|
+
// āā Tiers āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
48
|
+
const TIERS = {
|
|
49
|
+
coordinator: {
|
|
50
|
+
agents: ['birdsan', 'bsan', 'treebird', 'trbr'],
|
|
51
|
+
commands: ['sync', 'pull', 'push', 'status', 'conflicts', 'log'],
|
|
52
|
+
},
|
|
53
|
+
specialist: {
|
|
54
|
+
agents: ['spidersan', 'ssan', 'sherlock', 'srlk', 'watsan', 'wsan',
|
|
55
|
+
'treesan', 'tsan', 'mycsan', 'mycs'],
|
|
56
|
+
commands: ['sync', 'pull', 'push', 'status', 'conflicts', 'log'],
|
|
57
|
+
},
|
|
58
|
+
worker: {
|
|
59
|
+
agents: ['nemosan', 'nemo', 'codex', 'codx', 'goose', 'goos'],
|
|
60
|
+
commands: ['status', 'log'],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
function getTier(sender) {
|
|
64
|
+
for (const [tier, cfg] of Object.entries(TIERS)) {
|
|
65
|
+
if (cfg.agents.includes(sender))
|
|
66
|
+
return tier;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
function isAuthorized(sender, command) {
|
|
71
|
+
const tier = getTier(sender);
|
|
72
|
+
if (!tier)
|
|
73
|
+
return false;
|
|
74
|
+
return TIERS[tier].commands.includes(command);
|
|
75
|
+
}
|
|
76
|
+
function loadBotConfig() {
|
|
77
|
+
if (existsSync(CONFIG_FILE)) {
|
|
78
|
+
try {
|
|
79
|
+
return JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
|
|
80
|
+
}
|
|
81
|
+
catch { /* fall through */ }
|
|
82
|
+
}
|
|
83
|
+
return { repos: {}, pollInterval: 15, syncInterval: 90, rateLimit: 10 };
|
|
84
|
+
}
|
|
85
|
+
function saveBotConfig(cfg) {
|
|
86
|
+
if (!existsSync(CONFIG_DIR))
|
|
87
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
88
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), 'utf-8');
|
|
89
|
+
}
|
|
90
|
+
// āā Command parser āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
91
|
+
function parseCommand(text, repos) {
|
|
92
|
+
if (!text || !text.startsWith('/'))
|
|
93
|
+
return null;
|
|
94
|
+
const parts = text.trim().split(/\s+/);
|
|
95
|
+
if (parts.length < 2)
|
|
96
|
+
return null;
|
|
97
|
+
const cmd = parts[0].slice(1);
|
|
98
|
+
const repo = parts[1];
|
|
99
|
+
const args = parts.slice(2);
|
|
100
|
+
if (!VALID_COMMANDS.has(cmd))
|
|
101
|
+
return null;
|
|
102
|
+
if (!(repo in repos))
|
|
103
|
+
return null;
|
|
104
|
+
for (const arg of args) {
|
|
105
|
+
if (arg.includes(".."))
|
|
106
|
+
return null;
|
|
107
|
+
if (!BRANCH_RE.test(arg))
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return { cmd, repo, args };
|
|
111
|
+
}
|
|
112
|
+
// āā Smalltoak transport āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
113
|
+
async function stRead(to, last) {
|
|
114
|
+
if (!SMALLTOAK_URL)
|
|
115
|
+
return [];
|
|
116
|
+
const params = new URLSearchParams();
|
|
117
|
+
if (to)
|
|
118
|
+
params.set('to', to);
|
|
119
|
+
if (last)
|
|
120
|
+
params.set('last', String(last));
|
|
121
|
+
const qs = params.toString() ? `?${params}` : '';
|
|
122
|
+
const headers = {};
|
|
123
|
+
if (SMALLTOAK_TOKEN)
|
|
124
|
+
headers['Authorization'] = `Bearer ${SMALLTOAK_TOKEN}`;
|
|
125
|
+
try {
|
|
126
|
+
const resp = await fetch(`${SMALLTOAK_URL}/messages${qs}`, { headers });
|
|
127
|
+
if (!resp.ok)
|
|
128
|
+
return [];
|
|
129
|
+
return await resp.json();
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function stPost(text, to, replyTo) {
|
|
136
|
+
if (!SMALLTOAK_URL)
|
|
137
|
+
return;
|
|
138
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
139
|
+
if (SMALLTOAK_TOKEN)
|
|
140
|
+
headers['Authorization'] = `Bearer ${SMALLTOAK_TOKEN}`;
|
|
141
|
+
try {
|
|
142
|
+
await fetch(`${SMALLTOAK_URL}/messages`, {
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers,
|
|
145
|
+
body: JSON.stringify({
|
|
146
|
+
text, from: AGENT_NAME, to,
|
|
147
|
+
reply_to: replyTo,
|
|
148
|
+
}),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
console.warn('[bot] stPost failed:', e);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// āā High-water mark āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
156
|
+
function loadHwm() {
|
|
157
|
+
try {
|
|
158
|
+
return parseInt(readFileSync(HWM_FILE, 'utf-8').trim(), 10) || 0;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function saveHwm(id) {
|
|
165
|
+
if (!existsSync(CONFIG_DIR))
|
|
166
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
167
|
+
writeFileSync(HWM_FILE, String(id), 'utf-8');
|
|
168
|
+
}
|
|
169
|
+
// āā Git executors āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
170
|
+
function executePull(cfg, branch) {
|
|
171
|
+
try {
|
|
172
|
+
const b = branch || cfg.branch;
|
|
173
|
+
const r = execFileSync('git', ['pull', '--ff-only', 'origin', b], { cwd: cfg.path, encoding: 'utf-8', timeout: 60_000, env: gitEnv() });
|
|
174
|
+
return r.trim().substring(0, 500);
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
return err.message;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function executePush(cfg) {
|
|
181
|
+
registerFiles(cfg);
|
|
182
|
+
const conflict = checkConflictsBefore(cfg);
|
|
183
|
+
if (conflict)
|
|
184
|
+
return conflict;
|
|
185
|
+
try {
|
|
186
|
+
for (const filePattern of cfg.autoPush) {
|
|
187
|
+
execFileSync('git', ['add', filePattern], { cwd: cfg.path, encoding: 'utf-8', env: gitEnv() });
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
execFileSync('git', ['diff', '--cached', '--quiet'], { cwd: cfg.path, encoding: 'utf-8', env: gitEnv() });
|
|
191
|
+
return 'No changes to push';
|
|
192
|
+
}
|
|
193
|
+
catch { /* has staged changes */ }
|
|
194
|
+
execFileSync('git', ['commit', '-m', 'spidersan bot auto-push'], { cwd: cfg.path, encoding: 'utf-8', env: gitEnv() });
|
|
195
|
+
const r = execFileSync('git', ['push'], { cwd: cfg.path, encoding: 'utf-8', timeout: 60_000, env: gitEnv() });
|
|
196
|
+
return r.trim().substring(0, 500) || 'Pushed';
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
return err.message;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function registerFiles(cfg) {
|
|
203
|
+
try {
|
|
204
|
+
execFileSync('spidersan', ['register',
|
|
205
|
+
'--agent', 'spidersan-bot',
|
|
206
|
+
'--files', cfg.autoPush.join(','),
|
|
207
|
+
], { cwd: cfg.path, encoding: 'utf-8', timeout: 10_000, env: spidersanEnv() });
|
|
208
|
+
}
|
|
209
|
+
catch { /* best effort */ }
|
|
210
|
+
}
|
|
211
|
+
function checkConflictsBefore(cfg) {
|
|
212
|
+
try {
|
|
213
|
+
const result = execFileSync('spidersan', ['conflicts', '--json'], { cwd: cfg.path, encoding: 'utf-8', timeout: 10_000, env: spidersanEnv() });
|
|
214
|
+
const data = JSON.parse(result);
|
|
215
|
+
const blocking = (data.conflicts || []).filter((c) => c.tier >= 2 || c.tier === 'BLOCK' || c.tier === 'PAUSE');
|
|
216
|
+
if (blocking.length > 0) {
|
|
217
|
+
const labels = blocking.map((c) => `${c.tierInfo?.label || 'T' + c.tier}: ${(c.files || [c.branch]).join(', ')}`);
|
|
218
|
+
return `BLOCKED: ${blocking.length} conflict(s) (tier 2+) ā ${labels.join('; ')}`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch { /* spidersan not available or no conflicts */ }
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
function executeSync(cfg) {
|
|
225
|
+
registerFiles(cfg);
|
|
226
|
+
const conflict = checkConflictsBefore(cfg);
|
|
227
|
+
if (conflict)
|
|
228
|
+
return conflict;
|
|
229
|
+
const pull = executePull(cfg);
|
|
230
|
+
const push = executePush(cfg);
|
|
231
|
+
return `Pull: ${pull}\nPush: ${push}`;
|
|
232
|
+
}
|
|
233
|
+
function executeStatus(cfg) {
|
|
234
|
+
try {
|
|
235
|
+
const status = execFileSync('git', ['status', '--porcelain'], { cwd: cfg.path, encoding: 'utf-8', env: gitEnv() });
|
|
236
|
+
const branch = execFileSync('git', ['branch', '--show-current'], { cwd: cfg.path, encoding: 'utf-8', env: gitEnv() });
|
|
237
|
+
return `${status.trim()}\nBranch: ${branch.trim()}`.substring(0, 500);
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
return err.message;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function executeLog(cfg, n = 10) {
|
|
244
|
+
try {
|
|
245
|
+
const limitedN = Math.min(n, 50);
|
|
246
|
+
const r = execFileSync('git', ['log', '--oneline', `-${limitedN}`], { cwd: cfg.path, encoding: 'utf-8', env: gitEnv() });
|
|
247
|
+
return r.trim().substring(0, 500);
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
return err.message;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function executeConflicts(cfg) {
|
|
254
|
+
try {
|
|
255
|
+
const r = execFileSync('spidersan', ['conflicts'], { cwd: cfg.path, encoding: 'utf-8', timeout: 60_000, env: spidersanEnv() });
|
|
256
|
+
return r.trim().substring(0, 500);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
if (err.code === 'ENOENT')
|
|
260
|
+
return 'spidersan command not found';
|
|
261
|
+
return err.message;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// āā Rate limiter āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
265
|
+
const lastAction = {};
|
|
266
|
+
function rateCheck(repo) {
|
|
267
|
+
const now = Date.now();
|
|
268
|
+
const last = lastAction[repo] || 0;
|
|
269
|
+
if (now - last < RATE_LIMIT)
|
|
270
|
+
return false;
|
|
271
|
+
lastAction[repo] = now;
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
// āā Command āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
275
|
+
export const botCommand = new Command('bot')
|
|
276
|
+
.description('Message-driven git operations daemon via smalltoak')
|
|
277
|
+
.option('--once', 'Single poll+sync cycle then exit')
|
|
278
|
+
.action(async (opts) => {
|
|
279
|
+
if (process.env.GIT_BOT_ENABLED !== 'true') {
|
|
280
|
+
console.error('Error: GIT_BOT_ENABLED not set. Run via: envoak vault inject --key ... -- spidersan bot');
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
const config = loadBotConfig();
|
|
284
|
+
if (Object.keys(config.repos).length === 0) {
|
|
285
|
+
console.error('No repos configured. Use: spidersan bot add <name> --path <path> --branch <branch> --push <files>');
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
console.log(`[bot] started ā ${Object.keys(config.repos).length} repos, poll=${POLL_INTERVAL / 1000}s, sync=${SYNC_INTERVAL / 1000}s`);
|
|
289
|
+
// Register all configured repos/branches with spidersan for conflict detection
|
|
290
|
+
for (const [name, cfg] of Object.entries(config.repos)) {
|
|
291
|
+
try {
|
|
292
|
+
execFileSync('spidersan', ['register',
|
|
293
|
+
'--agent', 'spidersan-bot',
|
|
294
|
+
'--files', cfg.autoPush.join(','),
|
|
295
|
+
'--description', `git-bot auto-sync: ${name} (${cfg.branch})`
|
|
296
|
+
], { cwd: cfg.path, encoding: 'utf-8', timeout: 10_000, env: spidersanEnv() });
|
|
297
|
+
console.log(`[bot] registered ${name} (${cfg.branch}) ā files: ${cfg.autoPush.join(', ')}`);
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
console.log(`[bot] register ${name} skipped: ${err.message.split('\n')[0]}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const executors = {
|
|
304
|
+
sync: (cfg) => executeSync(cfg),
|
|
305
|
+
pull: (cfg, args) => executePull(cfg, args[0]),
|
|
306
|
+
push: (cfg) => executePush(cfg),
|
|
307
|
+
status: (cfg) => executeStatus(cfg),
|
|
308
|
+
log: (cfg, args) => executeLog(cfg, args[0] ? parseInt(args[0]) : 10),
|
|
309
|
+
conflicts: (cfg) => executeConflicts(cfg),
|
|
310
|
+
};
|
|
311
|
+
async function processMessage(msg) {
|
|
312
|
+
const sender = msg.from || 'unknown';
|
|
313
|
+
const parsed = parseCommand(msg.text || '', config.repos);
|
|
314
|
+
if (!parsed)
|
|
315
|
+
return;
|
|
316
|
+
const { cmd, repo, args } = parsed;
|
|
317
|
+
if (!isAuthorized(sender, cmd)) {
|
|
318
|
+
const tier = getTier(sender) || 'unknown';
|
|
319
|
+
await stPost(`DENIED: /${cmd} requires specialist or coordinator tier. Your tier: ${tier}.`, sender, msg.id);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (!rateCheck(repo)) {
|
|
323
|
+
await stPost(`RATE LIMITED: wait ${RATE_LIMIT / 1000}s between actions on ${repo}.`, sender, msg.id);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const ts = new Date().toLocaleTimeString('en-US', { hour12: false });
|
|
327
|
+
console.log(`[${ts}] ${sender} ā /${cmd} ${repo} ${args.join(' ')}`.trim());
|
|
328
|
+
try {
|
|
329
|
+
const result = executors[cmd](config.repos[repo], args);
|
|
330
|
+
await stPost(`/${cmd} ${repo}: ${result.substring(0, 500)}`, sender, msg.id);
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
await stPost(`/${cmd} ${repo}: Error: ${err.message}`, sender, msg.id);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
let hwm = loadHwm();
|
|
337
|
+
let lastSync = 0;
|
|
338
|
+
const cycle = async () => {
|
|
339
|
+
const now = Date.now();
|
|
340
|
+
// Periodic auto-sync
|
|
341
|
+
if (now - lastSync >= SYNC_INTERVAL) {
|
|
342
|
+
for (const [name, cfg] of Object.entries(config.repos)) {
|
|
343
|
+
try {
|
|
344
|
+
const result = executeSync(cfg);
|
|
345
|
+
const ts = new Date().toLocaleTimeString('en-US', { hour12: false });
|
|
346
|
+
console.log(`[${ts}] auto-sync ${name}: ${result.substring(0, 100)}`);
|
|
347
|
+
}
|
|
348
|
+
catch (err) {
|
|
349
|
+
console.log(`[auto-sync] ${name} failed: ${err.message}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
lastSync = now;
|
|
353
|
+
}
|
|
354
|
+
// Poll for commands
|
|
355
|
+
try {
|
|
356
|
+
const msgs = await stRead(AGENT_NAME, 50);
|
|
357
|
+
const newMsgs = msgs.filter((m) => (m.id || 0) > hwm).sort((a, b) => a.id - b.id);
|
|
358
|
+
for (const msg of newMsgs) {
|
|
359
|
+
await processMessage(msg);
|
|
360
|
+
hwm = msg.id;
|
|
361
|
+
saveHwm(hwm);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
console.log(`[poll] error: ${err.message}`);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
// Run once or loop
|
|
369
|
+
await cycle();
|
|
370
|
+
if (opts.once)
|
|
371
|
+
return;
|
|
372
|
+
setInterval(cycle, POLL_INTERVAL);
|
|
373
|
+
// Keep process alive
|
|
374
|
+
await new Promise(() => { });
|
|
375
|
+
});
|
|
376
|
+
// Sub-commands: add, remove, repos
|
|
377
|
+
botCommand
|
|
378
|
+
.command('add <name>')
|
|
379
|
+
.description('Add a repo to the bot watchlist')
|
|
380
|
+
.requiredOption('--path <path>', 'Absolute path to repo')
|
|
381
|
+
.requiredOption('--branch <branch>', 'Branch to track')
|
|
382
|
+
.option('--push <files>', 'Comma-separated auto-push file patterns')
|
|
383
|
+
.action((name, opts) => {
|
|
384
|
+
const config = loadBotConfig();
|
|
385
|
+
config.repos[name] = {
|
|
386
|
+
path: opts.path,
|
|
387
|
+
branch: opts.branch,
|
|
388
|
+
autoPush: opts.push ? opts.push.split(',') : [],
|
|
389
|
+
};
|
|
390
|
+
saveBotConfig(config);
|
|
391
|
+
console.log(`Added repo: ${name}`);
|
|
392
|
+
});
|
|
393
|
+
botCommand
|
|
394
|
+
.command('remove <name>')
|
|
395
|
+
.description('Remove a repo from the bot watchlist')
|
|
396
|
+
.action((name) => {
|
|
397
|
+
const config = loadBotConfig();
|
|
398
|
+
delete config.repos[name];
|
|
399
|
+
saveBotConfig(config);
|
|
400
|
+
console.log(`Removed repo: ${name}`);
|
|
401
|
+
});
|
|
402
|
+
botCommand
|
|
403
|
+
.command('repos')
|
|
404
|
+
.description('List configured repos')
|
|
405
|
+
.action(() => {
|
|
406
|
+
const config = loadBotConfig();
|
|
407
|
+
const repos = Object.entries(config.repos);
|
|
408
|
+
if (repos.length === 0) {
|
|
409
|
+
console.log('No repos configured.');
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
for (const [name, cfg] of repos) {
|
|
413
|
+
console.log(` ${name}: ${cfg.path} (${cfg.branch}) push=[${cfg.autoPush.join(', ')}]`);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
//# sourceMappingURL=bot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.js","sourceRoot":"","sources":["../../src/commands/bot.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conflicts.d.ts","sourceRoot":"","sources":["../../src/commands/conflicts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"conflicts.d.ts","sourceRoot":"","sources":["../../src/commands/conflicts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiSpC,eAAO,MAAM,gBAAgB,SAuVvB,CAAC"}
|
|
@@ -19,67 +19,9 @@ import { isExcludedPath } from './register.js';
|
|
|
19
19
|
import { loadConfig } from '../lib/config.js';
|
|
20
20
|
import { logActivity } from '../lib/activity.js';
|
|
21
21
|
import { isGhAvailable, getPRDetails } from '../lib/github.js';
|
|
22
|
+
import { classifyWithLabel } from '../lib/conflict-tier.js';
|
|
22
23
|
// Config
|
|
23
24
|
const HUB_URL = process.env.HUB_URL || 'https://hub.treebird.uk';
|
|
24
|
-
// Critical files that trigger TIER 3 blocking
|
|
25
|
-
const TIER_3_PATTERNS = [
|
|
26
|
-
/\.env$/,
|
|
27
|
-
/secrets?\./i,
|
|
28
|
-
/credentials/i,
|
|
29
|
-
/password/i,
|
|
30
|
-
/api[_-]?key/i,
|
|
31
|
-
/private[_-]?key/i,
|
|
32
|
-
/\.pem$/,
|
|
33
|
-
/auth\.(ts|js)$/,
|
|
34
|
-
/security\.(ts|js)$/,
|
|
35
|
-
];
|
|
36
|
-
// Important files that trigger TIER 2 pause
|
|
37
|
-
const TIER_2_PATTERNS = [
|
|
38
|
-
/package\.json$/,
|
|
39
|
-
/package-lock\.json$/,
|
|
40
|
-
/tsconfig\.json$/,
|
|
41
|
-
/CLAUDE\.md$/,
|
|
42
|
-
/\.gitignore$/,
|
|
43
|
-
/server\.(ts|js)$/,
|
|
44
|
-
/index\.(ts|js)$/,
|
|
45
|
-
/config\.(ts|js)$/,
|
|
46
|
-
];
|
|
47
|
-
// Optimization: Pre-compile static patterns
|
|
48
|
-
const COMPILED_TIER_3 = compilePatterns(TIER_3_PATTERNS);
|
|
49
|
-
const COMPILED_TIER_2 = compilePatterns(TIER_2_PATTERNS);
|
|
50
|
-
function getConflictTier(file, compiledHigh = [], compiledMedium = []) {
|
|
51
|
-
// Check TIER 3 first (most critical)
|
|
52
|
-
const tier3 = [...COMPILED_TIER_3, ...compiledHigh];
|
|
53
|
-
for (const pattern of tier3) {
|
|
54
|
-
if (pattern.test(file)) {
|
|
55
|
-
return {
|
|
56
|
-
tier: 3,
|
|
57
|
-
label: 'BLOCK',
|
|
58
|
-
icon: 'š“',
|
|
59
|
-
action: 'Merge blocked. Resolve conflict first.'
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
// Check TIER 2
|
|
64
|
-
const tier2 = [...COMPILED_TIER_2, ...compiledMedium];
|
|
65
|
-
for (const pattern of tier2) {
|
|
66
|
-
if (pattern.test(file)) {
|
|
67
|
-
return {
|
|
68
|
-
tier: 2,
|
|
69
|
-
label: 'PAUSE',
|
|
70
|
-
icon: 'š ',
|
|
71
|
-
action: 'Coordinate with other agent before proceeding.'
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// Default: TIER 1
|
|
76
|
-
return {
|
|
77
|
-
tier: 1,
|
|
78
|
-
label: 'WARN',
|
|
79
|
-
icon: 'š”',
|
|
80
|
-
action: 'Consider coordinating, but safe to proceed.'
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
25
|
function getCurrentBranch() {
|
|
84
26
|
try {
|
|
85
27
|
return execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { encoding: 'utf-8' }).trim();
|
|
@@ -89,11 +31,19 @@ function getCurrentBranch() {
|
|
|
89
31
|
}
|
|
90
32
|
}
|
|
91
33
|
async function notifyHub(branch, conflicts) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
34
|
+
let hasTier3 = false;
|
|
35
|
+
let hasTier2 = false;
|
|
36
|
+
for (const c of conflicts) {
|
|
37
|
+
if (c.tier === 3)
|
|
38
|
+
hasTier3 = true;
|
|
39
|
+
else if (c.tier === 2)
|
|
40
|
+
hasTier2 = true;
|
|
41
|
+
if (hasTier3 && hasTier2)
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
if (!hasTier3 && !hasTier2)
|
|
95
45
|
return;
|
|
96
|
-
const severity =
|
|
46
|
+
const severity = hasTier3 ? 'š“ TIER 3 BLOCK' : 'š TIER 2 PAUSE';
|
|
97
47
|
const message = `š·ļøā ļø **Conflict Alert** on \`${branch}\`\n\n${severity}\n\nConflicting files require coordination.`;
|
|
98
48
|
try {
|
|
99
49
|
await fetch(`${HUB_URL}/api/chat`, {
|
|
@@ -114,9 +64,7 @@ async function notifyHub(branch, conflicts) {
|
|
|
114
64
|
/**
|
|
115
65
|
* Wake a conflicting agent and send them a message about what to fix
|
|
116
66
|
*/
|
|
117
|
-
async function wakeConflictingAgent(agentId, myBranch, theirBranch,
|
|
118
|
-
const fileList = conflictingFiles.slice(0, 5).join(', ');
|
|
119
|
-
const more = conflictingFiles.length > 5 ? ` (+${conflictingFiles.length - 5} more)` : '';
|
|
67
|
+
async function wakeConflictingAgent(agentId, myBranch, theirBranch, _conflictingFiles) {
|
|
120
68
|
// 1. Wake the agent via Hub
|
|
121
69
|
try {
|
|
122
70
|
const wakeResponse = await fetch(`${HUB_URL}/api/wake/${agentId}`, {
|
|
@@ -389,12 +337,23 @@ export const conflictsCommand = new Command('conflicts')
|
|
|
389
337
|
for (const branch of allBranches) {
|
|
390
338
|
if (branch.name === targetBranch || branch.status !== 'active')
|
|
391
339
|
continue;
|
|
392
|
-
|
|
340
|
+
// Performance Optimization: Replace .filter() with a standard loop to avoid array allocation.
|
|
341
|
+
// Short-circuit using O(1) Set lookup (targetFilesSet.has) before calling the expensive isExcludedPath.
|
|
342
|
+
const overlappingFiles = [];
|
|
343
|
+
for (let i = 0; i < branch.files.length; i++) {
|
|
344
|
+
const f = branch.files[i];
|
|
345
|
+
if (targetFilesSet.has(f) && !isExcludedPath(f)) {
|
|
346
|
+
overlappingFiles.push(f);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
393
349
|
if (overlappingFiles.length > 0) {
|
|
394
350
|
// Get highest tier for this conflict
|
|
395
351
|
let maxTier = { tier: 1, label: 'WARN', icon: 'š”', action: '' };
|
|
396
352
|
for (const file of overlappingFiles) {
|
|
397
|
-
const fileTier =
|
|
353
|
+
const fileTier = classifyWithLabel(file, {
|
|
354
|
+
extraTier3: compiledHigh,
|
|
355
|
+
extraTier2: compiledMedium,
|
|
356
|
+
});
|
|
398
357
|
if (fileTier.tier > maxTier.tier) {
|
|
399
358
|
maxTier = fileTier;
|
|
400
359
|
}
|
|
@@ -435,22 +394,31 @@ export const conflictsCommand = new Command('conflicts')
|
|
|
435
394
|
}
|
|
436
395
|
// Sort by tier (highest first)
|
|
437
396
|
conflicts.sort((a, b) => b.tier - a.tier);
|
|
397
|
+
let tier3Count = 0;
|
|
398
|
+
let tier2Count = 0;
|
|
399
|
+
let tier1Count = 0;
|
|
400
|
+
for (const c of conflicts) {
|
|
401
|
+
if (c.tier === 3)
|
|
402
|
+
tier3Count++;
|
|
403
|
+
else if (c.tier === 2)
|
|
404
|
+
tier2Count++;
|
|
405
|
+
else if (c.tier === 1)
|
|
406
|
+
tier1Count++;
|
|
407
|
+
}
|
|
438
408
|
// Log conflict detection to activity log
|
|
439
409
|
if (conflicts.length > 0) {
|
|
440
410
|
logActivity({
|
|
441
411
|
event: 'conflict_detected',
|
|
442
412
|
branch: targetBranch,
|
|
443
413
|
details: {
|
|
444
|
-
tier3:
|
|
445
|
-
tier2:
|
|
446
|
-
tier1:
|
|
414
|
+
tier3: tier3Count,
|
|
415
|
+
tier2: tier2Count,
|
|
416
|
+
tier1: tier1Count,
|
|
447
417
|
conflicting_branches: conflicts.map(c => c.branch),
|
|
448
418
|
}
|
|
449
419
|
});
|
|
450
420
|
}
|
|
451
421
|
// Check for blocking conditions
|
|
452
|
-
const tier3Count = conflicts.filter(c => c.tier === 3).length;
|
|
453
|
-
const tier2Count = conflicts.filter(c => c.tier === 2).length;
|
|
454
422
|
const shouldBlock = options.strict && (tier3Count > 0 || tier2Count > 0);
|
|
455
423
|
// Notify Hub if requested
|
|
456
424
|
if (options.notify && (tier3Count > 0 || tier2Count > 0)) {
|
|
@@ -463,7 +431,7 @@ export const conflictsCommand = new Command('conflicts')
|
|
|
463
431
|
summary: {
|
|
464
432
|
tier3: tier3Count,
|
|
465
433
|
tier2: tier2Count,
|
|
466
|
-
tier1:
|
|
434
|
+
tier1: tier1Count,
|
|
467
435
|
blocked: shouldBlock
|
|
468
436
|
}
|
|
469
437
|
}, null, 2));
|
|
@@ -483,14 +451,17 @@ export const conflictsCommand = new Command('conflicts')
|
|
|
483
451
|
for (const conflict of conflicts) {
|
|
484
452
|
console.log(`${conflict.tierInfo.icon} TIER ${conflict.tier} (${conflict.tierInfo.label}): ${conflict.branch}`);
|
|
485
453
|
for (const file of conflict.files) {
|
|
486
|
-
const fileTier =
|
|
454
|
+
const fileTier = classifyWithLabel(file, {
|
|
455
|
+
extraTier3: compiledHigh,
|
|
456
|
+
extraTier2: compiledMedium,
|
|
457
|
+
});
|
|
487
458
|
console.log(` ${fileTier.icon} ${file}`);
|
|
488
459
|
}
|
|
489
460
|
console.log(` ā ${conflict.tierInfo.action}`);
|
|
490
461
|
console.log('');
|
|
491
462
|
}
|
|
492
463
|
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
493
|
-
console.log(`š Summary: š“ ${tier3Count} BLOCK | š ${tier2Count} PAUSE | š” ${
|
|
464
|
+
console.log(`š Summary: š“ ${tier3Count} BLOCK | š ${tier2Count} PAUSE | š” ${tier1Count} WARN`);
|
|
494
465
|
// Offer add/add resolution suggestions for likely add/add files
|
|
495
466
|
suggestAddAddResolution(conflicts);
|
|
496
467
|
// Show semantic analysis results
|
|
@@ -567,10 +538,11 @@ export const conflictsCommand = new Command('conflicts')
|
|
|
567
538
|
console.log('\nš RE-CHECKING CONFLICTS...\n');
|
|
568
539
|
const { execFileSync } = await import('child_process');
|
|
569
540
|
try {
|
|
541
|
+
const { getCLIPath } = await import('../lib/security.js');
|
|
570
542
|
// Security: Use execFileSync with argument array
|
|
571
543
|
const safeBranch = validateBranchName(targetBranch);
|
|
572
544
|
const tierArg = String(parseInt(options.tier, 10) || 1);
|
|
573
|
-
execFileSync(
|
|
545
|
+
execFileSync(process.execPath, [getCLIPath(), 'conflicts', '--branch', safeBranch, '--tier', tierArg], {
|
|
574
546
|
encoding: 'utf-8',
|
|
575
547
|
stdio: 'inherit'
|
|
576
548
|
});
|