Skip to content

Commit 77ef737

Browse files
NagyViktNagyVikt
andauthored
Prepare fresh npm release 7.0.37 (#427)
Bump the package to the next unpublished patch version and record README/OpenSpec release notes so the registry can accept a new publish. The release lane also syncs the Active Agents extension template with the canonical workspace source because the package metadata tests proved the shipped bundle was stale after the Colony task UI merge. Constraint: npm latest was 7.0.36 before this lane Constraint: Release verification requires template/runtime parity for shipped VS Code Active Agents assets Rejected: Bump only package.json | package-lock and README release notes must stay synchronized Confidence: high Scope-risk: narrow Directive: Keep vscode/guardex-active-agents/extension.js and templates/vscode/guardex-active-agents/extension.js byte-for-byte synchronized when either changes Tested: npm test Tested: node --check bin/multiagent-safety.js Tested: npm pack --dry-run Tested: openspec validate --specs Not-tested: npm publish requires registry auth/OTP or trusted publishing Co-authored-by: NagyVikt <nagy.viktordp@gmail.com>
1 parent 507a69b commit 77ef737

6 files changed

Lines changed: 171 additions & 20 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@ Being honest about where this still has issues:
266266
<details open>
267267
<summary><strong>v7.x</strong></summary>
268268

269+
### v7.0.37
270+
- Bumped `@imdeadpool/guardex` from `7.0.36` to `7.0.37` so the current
271+
package can publish under a fresh npm version after `7.0.36` reached the
272+
registry.
273+
- Synced the shipped Active Agents template with the canonical VS Code
274+
extension source so Colony task counts and details install with the package.
275+
- No new CLI command behavior is introduced in this release lane.
276+
269277
### v7.0.36
270278
- Bumped `@imdeadpool/guardex` from `7.0.35` to `7.0.36` so the latest
271279
branch-finish cwd-prune fix can ship under a fresh npm version after PR #424.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-04-25
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Release notes
2+
3+
- Bump `@imdeadpool/guardex` from `7.0.36` to `7.0.37` for the next publishable release.
4+
- Registry baseline before the bump: `@imdeadpool/guardex@7.0.36` with `latest` pointing to `7.0.36`.
5+
- GitHub release target: `v7.0.37`.
6+
- Synced `templates/vscode/guardex-active-agents/extension.js` with the canonical `vscode/guardex-active-agents/extension.js` bundle so package install parity tests pass.
7+
- No CLI behavior changes are introduced in this release lane.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@imdeadpool/guardex",
3-
"version": "7.0.36",
3+
"version": "7.0.37",
44
"description": "Guardian T-Rex for your multi-agent repo. Isolated worktrees, file locks, and PR-only merges stop parallel Codex & Claude agents from overwriting each other's work. Auto-wires Oh My Codex, Oh My Claude, OpenSpec, and Caveman.",
55
"license": "MIT",
66
"preferGlobal": true,

templates/vscode/guardex-active-agents/extension.js

Lines changed: 151 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const fs = require('node:fs');
22
const path = require('node:path');
33
const cp = require('node:child_process');
4+
const http = require('node:http');
5+
const os = require('node:os');
46
const vscode = require('vscode');
57
const {
68
clearWorktreeActivityCache,
@@ -40,6 +42,84 @@ const ACTIVE_AGENTS_EXTENSION_ID = 'Recodee.gitguardex-active-agents';
4042
const RESTART_EXTENSION_HOST_COMMAND = 'workbench.action.restartExtensionHost';
4143
const REFRESH_POLL_INTERVAL_MS = 30_000;
4244
const INSPECT_PANEL_VIEW_TYPE = 'gitguardex.activeAgents.inspect';
45+
const COLONY_DEFAULT_PORT = 37777;
46+
const COLONY_SNAPSHOT_TTL_MS = 5_000;
47+
const COLONY_FETCH_TIMEOUT_MS = 800;
48+
49+
function colonyDataDir() {
50+
return process.env.COLONY_HOME
51+
|| process.env.CAVEMEM_HOME
52+
|| path.join(os.homedir(), '.colony');
53+
}
54+
55+
function readColonyPort() {
56+
try {
57+
const raw = fs.readFileSync(path.join(colonyDataDir(), 'settings.json'), 'utf8');
58+
const parsed = JSON.parse(raw);
59+
const port = Number(parsed?.workerPort);
60+
return Number.isFinite(port) && port > 0 ? port : COLONY_DEFAULT_PORT;
61+
} catch (_error) {
62+
return COLONY_DEFAULT_PORT;
63+
}
64+
}
65+
66+
function fetchColonyJson(urlPath) {
67+
return new Promise((resolve) => {
68+
const req = http.get(
69+
{
70+
hostname: '127.0.0.1',
71+
port: readColonyPort(),
72+
path: urlPath,
73+
timeout: COLONY_FETCH_TIMEOUT_MS,
74+
},
75+
(res) => {
76+
if (res.statusCode !== 200) {
77+
res.resume();
78+
resolve(null);
79+
return;
80+
}
81+
let body = '';
82+
res.setEncoding('utf8');
83+
res.on('data', (chunk) => {
84+
body += chunk;
85+
});
86+
res.on('end', () => {
87+
try {
88+
resolve(JSON.parse(body));
89+
} catch (_error) {
90+
resolve(null);
91+
}
92+
});
93+
},
94+
);
95+
req.on('error', () => resolve(null));
96+
req.on('timeout', () => {
97+
req.destroy();
98+
resolve(null);
99+
});
100+
});
101+
}
102+
103+
const colonyTasksCache = new Map();
104+
105+
async function readColonyTasksForRepo(repoRoot) {
106+
const cached = colonyTasksCache.get(repoRoot);
107+
if (cached && Date.now() - cached.at < COLONY_SNAPSHOT_TTL_MS) {
108+
return cached.tasks;
109+
}
110+
const tasks = await fetchColonyJson(
111+
`/api/colony/tasks?repo_root=${encodeURIComponent(repoRoot)}`,
112+
);
113+
const resolved = Array.isArray(tasks) ? tasks : [];
114+
colonyTasksCache.set(repoRoot, { at: Date.now(), tasks: resolved });
115+
return resolved;
116+
}
117+
118+
function compactColonyBranchLabel(branch) {
119+
if (typeof branch !== 'string' || !branch) return 'unknown';
120+
const parts = branch.split('/').filter(Boolean);
121+
return parts.length > 2 ? parts.slice(-2).join('/') : branch;
122+
}
43123
const GIT_CONFIGURATION_SECTION = 'git';
44124
const REPO_SCAN_IGNORED_FOLDERS_SETTING = 'repositoryScanIgnoredFolders';
45125
const BUNDLED_FILE_ICONS_MANIFEST_RELATIVE = path.join('fileicons', 'gitguardex-fileicons.json');
@@ -840,10 +920,18 @@ function buildOverviewDescription(summary) {
840920
formatCountLabel(summary?.workingCount || 0, 'working agent'),
841921
formatCountLabel(summary?.finishedCount || 0, 'finished agent'),
842922
formatCountLabel(summary?.idleCount || 0, 'idle agent'),
923+
summary?.colonyTaskCount
924+
? formatCountLabel(summary.colonyTaskCount, 'colony task')
925+
: '',
926+
summary?.pendingHandoffCount
927+
? formatCountLabel(summary.pendingHandoffCount, 'pending handoff')
928+
: '',
843929
formatCountLabel(summary?.unassignedChangeCount || 0, 'unassigned change'),
844930
formatCountLabel(summary?.lockedFileCount || 0, 'locked file'),
845931
formatCountLabel(summary?.conflictCount || 0, 'conflict'),
846-
].join(' · ');
932+
]
933+
.filter(Boolean)
934+
.join(' · ');
847935
}
848936

849937
function buildRepoDescription(summary) {
@@ -1252,7 +1340,9 @@ class RepoItem extends vscode.TreeItem {
12521340
this.changes = changes;
12531341
this.unassignedChanges = options.unassignedChanges || [];
12541342
this.lockEntries = options.lockEntries || [];
1255-
this.overview = options.overview || buildRepoOverview(sessions, this.unassignedChanges, this.lockEntries);
1343+
this.colonyTasks = Array.isArray(options.colonyTasks) ? options.colonyTasks : [];
1344+
this.overview = options.overview
1345+
|| buildRepoOverview(sessions, this.unassignedChanges, this.lockEntries, this.colonyTasks);
12561346
this.description = buildRepoDescription(this.overview);
12571347
this.tooltip = buildRepoTooltip(repoRoot, this.overview);
12581348
this.iconPath = themeIcon('repo');
@@ -2524,7 +2614,8 @@ function countChangedPaths(repoRoot, sessions, changes) {
25242614
return changedKeys.size;
25252615
}
25262616

2527-
function buildRepoOverview(sessions, unassignedChanges, lockEntries) {
2617+
function buildRepoOverview(sessions, unassignedChanges, lockEntries, colonyTasks = []) {
2618+
const colonyTaskList = Array.isArray(colonyTasks) ? colonyTasks : [];
25282619
return {
25292620
sessionCount: sessions.length,
25302621
workingCount: countWorkingSessions(sessions),
@@ -2536,6 +2627,11 @@ function buildRepoOverview(sessions, unassignedChanges, lockEntries) {
25362627
(total, session) => total + (session.conflictCount || 0),
25372628
0,
25382629
) + (unassignedChanges || []).filter((change) => change.hasForeignLock).length,
2630+
colonyTaskCount: colonyTaskList.length,
2631+
pendingHandoffCount: colonyTaskList.reduce(
2632+
(total, task) => total + (task.pending_handoff_count || 0),
2633+
0,
2634+
),
25392635
};
25402636
}
25412637

@@ -3023,12 +3119,14 @@ class ActiveAgentsProvider {
30233119

30243120
const { repoRootChanges } = partitionChangesByOwnership(sessions, changes);
30253121
const unassignedChanges = sortUnassignedChanges(repoRootChanges);
3122+
const colonyTasks = Array.isArray(entry.colonyTasks) ? entry.colonyTasks : [];
30263123
return {
30273124
...entry,
30283125
sessions,
30293126
changes,
30303127
unassignedChanges,
3031-
overview: buildRepoOverview(sessions, unassignedChanges, entry.lockEntries),
3128+
colonyTasks,
3129+
overview: buildRepoOverview(sessions, unassignedChanges, entry.lockEntries, colonyTasks),
30323130
};
30333131
});
30343132

@@ -3140,6 +3238,37 @@ class ActiveAgentsProvider {
31403238
iconId: 'file-directory',
31413239
}));
31423240
}
3241+
const colonyTaskList = Array.isArray(element.colonyTasks) ? element.colonyTasks : [];
3242+
if (colonyTaskList.length > 0) {
3243+
const colonyItems = colonyTaskList.map((task) => {
3244+
const pendingLabel = task.pending_handoff_count > 0
3245+
? formatCountLabel(task.pending_handoff_count, 'pending handoff')
3246+
: 'quiet';
3247+
const participantLabel =
3248+
(task.participants || []).map((p) => p.agent).filter(Boolean).join(', ')
3249+
|| 'no participants';
3250+
return new DetailItem(
3251+
`#${task.id} · ${compactColonyBranchLabel(task.branch)}`,
3252+
`${participantLabel} · ${pendingLabel}`,
3253+
{
3254+
iconId: task.pending_handoff_count > 0 ? 'warning' : 'comment-discussion',
3255+
tooltip: [
3256+
task.branch,
3257+
`task #${task.id}`,
3258+
participantLabel,
3259+
task.pending_handoff_count > 0
3260+
? formatCountLabel(task.pending_handoff_count, 'pending handoff')
3261+
: '',
3262+
].filter(Boolean).join('\n'),
3263+
},
3264+
);
3265+
});
3266+
advancedItems.push(new SectionItem('Colony tasks', colonyItems, {
3267+
description: String(colonyItems.length),
3268+
collapsedState: vscode.TreeItemCollapsibleState.Collapsed,
3269+
iconId: 'organization',
3270+
}));
3271+
}
31433272
if (advancedItems.length > 0) {
31443273
sectionItems.push(new SectionItem('Advanced details', advancedItems, {
31453274
description: String(advancedItems.length),
@@ -3166,24 +3295,29 @@ class ActiveAgentsProvider {
31663295
overview: entry.overview,
31673296
unassignedChanges: entry.unassignedChanges,
31683297
lockEntries: entry.lockEntries,
3298+
colonyTasks: entry.colonyTasks,
31693299
}));
31703300
}
31713301

31723302
async loadRepoEntries() {
31733303
const repoEntries = await findRepoSessionEntries();
3174-
return repoEntries.map((entry) => {
3175-
const repoRoot = entry.repoRoot;
3176-
const lockRegistry = this.getLockRegistryForRepo(repoRoot);
3177-
const currentBranch = readCurrentBranch(repoRoot);
3178-
return {
3179-
repoRoot,
3180-
sessions: entry.sessions.map((session) => decorateSession(session, lockRegistry)),
3181-
changes: readRepoChanges(repoRoot).map((change) => (
3182-
decorateChange(change, lockRegistry, currentBranch)
3183-
)),
3184-
lockEntries: Array.from(lockRegistry.entriesByPath.entries()),
3185-
};
3186-
});
3304+
return Promise.all(
3305+
repoEntries.map(async (entry) => {
3306+
const repoRoot = entry.repoRoot;
3307+
const lockRegistry = this.getLockRegistryForRepo(repoRoot);
3308+
const currentBranch = readCurrentBranch(repoRoot);
3309+
const colonyTasks = await readColonyTasksForRepo(repoRoot);
3310+
return {
3311+
repoRoot,
3312+
sessions: entry.sessions.map((session) => decorateSession(session, lockRegistry)),
3313+
changes: readRepoChanges(repoRoot).map((change) => (
3314+
decorateChange(change, lockRegistry, currentBranch)
3315+
)),
3316+
lockEntries: Array.from(lockRegistry.entriesByPath.entries()),
3317+
colonyTasks,
3318+
};
3319+
}),
3320+
);
31873321
}
31883322
}
31893323

0 commit comments

Comments
 (0)