@imdeadpool/guardex 7.0.23 → 7.0.25
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 +30 -3
- package/package.json +1 -1
- package/src/cli/args.js +9 -0
- package/src/cli/main.js +7 -2
- package/src/context.js +22 -0
- package/src/doctor/index.js +158 -5
- package/src/finish/index.js +1 -0
- package/src/report/session-severity.js +77 -8
- package/templates/AGENTS.multiagent-safety.md +3 -0
- package/templates/codex/skills/guardex-merge-skills-to-dev/SKILL.md +3 -2
- package/templates/scripts/agent-branch-finish.sh +155 -5
- package/templates/scripts/agent-branch-start.sh +35 -0
- package/templates/scripts/agent-worktree-prune.sh +22 -1
- package/templates/vscode/guardex-active-agents/README.md +6 -3
- package/templates/vscode/guardex-active-agents/extension.js +1706 -247
- package/templates/vscode/guardex-active-agents/fileicons/gitguardex-fileicons.json +54 -0
- package/templates/vscode/guardex-active-agents/fileicons/icons/agent.svg +4 -0
- package/templates/vscode/guardex-active-agents/fileicons/icons/branch.svg +4 -0
- package/templates/vscode/guardex-active-agents/fileicons/icons/config.svg +4 -0
- package/templates/vscode/guardex-active-agents/fileicons/icons/hook.svg +3 -0
- package/templates/vscode/guardex-active-agents/fileicons/icons/openspec.svg +5 -0
- package/templates/vscode/guardex-active-agents/fileicons/icons/plan.svg +4 -0
- package/templates/vscode/guardex-active-agents/fileicons/icons/spec.svg +4 -0
- package/templates/vscode/guardex-active-agents/media/active-agents-hivemind.svg +14 -0
- package/templates/vscode/guardex-active-agents/package.json +39 -11
- package/templates/vscode/guardex-active-agents/session-schema.js +226 -8
package/README.md
CHANGED
|
@@ -140,7 +140,7 @@ That's it. Install and update via `@imdeadpool/guardex`. Setup installs the mini
|
|
|
140
140
|
</div>
|
|
141
141
|
|
|
142
142
|
> [!NOTE]
|
|
143
|
-
> In this repo, `CLAUDE.md` is a symlink to `AGENTS.md`, so Claude reads the same contract. Optional Codex/Claude companion files
|
|
143
|
+
> In this repo, `CLAUDE.md` is a symlink to `AGENTS.md`, so Claude reads the same contract. Optional Codex/Claude companion files still install at the user level with `gx install-agent-skills`, while the generic repo skill catalog is available through `npx skills add recodeee/` or directly via `npx skills add recodeee/gitguardex`.
|
|
144
144
|
|
|
145
145
|
### Decision flow
|
|
146
146
|
|
|
@@ -266,7 +266,7 @@ To install the real companion into local VS Code from a GitGuardex-wired repo:
|
|
|
266
266
|
node scripts/install-vscode-active-agents-extension.js
|
|
267
267
|
```
|
|
268
268
|
|
|
269
|
-
It adds
|
|
269
|
+
It adds a dedicated `Active Agents` Activity Bar container with a hive icon, shows the live active-agent count as a badge on that icon, groups each live repo into `ACTIVE AGENTS` and `CHANGES` sections, splits `ACTIVE AGENTS` into `BLOCKED`, `WORKING NOW`, `IDLE`, `STALLED`, and `DEAD` when those states are present, mirrors the selected session or active-agent count in the VS Code status bar, reads `.omx/state/active-sessions/*.json`, derives session state from git conflict markers, dirty worktree status, PID liveness, and recent file mtimes, and surfaces working/dead counts in the repo/header affordances. Reload the VS Code window after install.
|
|
270
270
|
|
|
271
271
|
---
|
|
272
272
|
|
|
@@ -459,6 +459,23 @@ npm i -g oh-my-claude-sisyphus@latest
|
|
|
459
459
|
Repo: <https://github.com/Yeachan-Heo/oh-my-claudecode>
|
|
460
460
|
[](https://github.com/Yeachan-Heo/oh-my-claudecode)
|
|
461
461
|
|
|
462
|
+
### GitGuardex skills - install the repo skill catalog through `npx skills`
|
|
463
|
+
|
|
464
|
+
For agents that already support the generic `skills` installer flow, GitGuardex now exposes its repo skill catalog directly. You can start from the broader `recodeee` source or jump straight into this repo's catalog.
|
|
465
|
+
|
|
466
|
+
```sh
|
|
467
|
+
npx skills add recodeee/
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
```sh
|
|
471
|
+
npx skills add recodeee/gitguardex
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
This repo currently exposes `gitguardex` and `guardex-merge-skills-to-dev` through that flow. If the picker does not show a separate `guardex` skill, that is expected: `guardex` remains the legacy CLI alias, while the repo skill itself is named `gitguardex`. Use `gx install-agent-skills` when you want the Codex/Claude user-home startup files instead of the generic `skills` catalog.
|
|
475
|
+
|
|
476
|
+
Repo: <https://github.com/recodeee/gitguardex>
|
|
477
|
+
[](https://github.com/recodeee/gitguardex)
|
|
478
|
+
|
|
462
479
|
### Caveman — output compression for long agent runs
|
|
463
480
|
|
|
464
481
|
Ultra-compressed response mode for Claude/Codex-style agents. Useful when you want less output-token churn during long reviews, debug loops, or multi-agent sessions.
|
|
@@ -609,7 +626,7 @@ vscode/guardex-active-agents/README.md
|
|
|
609
626
|
|
|
610
627
|
Legacy compatibility note: older repos may still contain repo-local workflow scripts under `scripts/`. Direct `gx branch ...`, `gx locks ...`, `gx finish`, `gx cleanup`, `gx merge`, and `gx migrate` do not require them. `gx migrate` removes those leftover workflow shims by default. The CLI still honors repo-local `scripts/review-bot-watch.sh` and `scripts/codex-agent.sh` when they are already present so older repos can keep working during migration.
|
|
611
628
|
|
|
612
|
-
Optional Codex/Claude user-level companions still install with `gx install-agent-skills`;
|
|
629
|
+
Optional Codex/Claude user-level companions still install with `gx install-agent-skills`; the generic repo skill catalog is available with `npx skills add recodeee/` or directly via `npx skills add recodeee/gitguardex`. Neither path copies those user-home files into each repo.
|
|
613
630
|
|
|
614
631
|
---
|
|
615
632
|
|
|
@@ -672,6 +689,16 @@ npm pack --dry-run
|
|
|
672
689
|
<details>
|
|
673
690
|
<summary><strong>v7.x</strong></summary>
|
|
674
691
|
|
|
692
|
+
### v7.0.25
|
|
693
|
+
- Bumped `@imdeadpool/guardex` from `7.0.24` to `7.0.25` so npm and GitHub Releases can ship the current `main` payload.
|
|
694
|
+
- The bundled `GitGuardex Active Agents` VS Code companion now self-heals stale repo-scan ignore settings in older repos, keeps plain managed sandboxes visible in Source Control, and preserves cleanup truth so the tree matches actual sandbox state.
|
|
695
|
+
- Bumped the shipped Active Agents companion manifests from `0.0.8` to `0.0.9` so local VS Code installs can pick up the newer workspace build and show the refreshed extension version from this release.
|
|
696
|
+
|
|
697
|
+
### v7.0.24
|
|
698
|
+
- Bumped `@imdeadpool/guardex` from `7.0.23` to `7.0.24` so GitHub Releases and the npm publish retry can advance together after `v7.0.23` landed on GitHub but not on npm.
|
|
699
|
+
- Release verification no longer loses its base ref on tag-triggered runs, so the publish workflow keeps the history it needs before packing and publish checks.
|
|
700
|
+
- Keep the release scoped to version and release automation metadata only; the packaged Guardex CLI payload stays aligned with the already-verified `main` branch contents.
|
|
701
|
+
|
|
675
702
|
### v7.0.23
|
|
676
703
|
- Bumped `@imdeadpool/guardex` from `7.0.22` to `7.0.23` so GitHub release and npm can advance together after `7.0.22` reached npm without a matching published GitHub release.
|
|
677
704
|
- Active Agents stays easier to scan and more truthful: the package repo remains the canonical source, inspect/install paths stay loadable across VS Code churn, and session rows group under worktrees with clearer merged-cleanup truth.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imdeadpool/guardex",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.25",
|
|
4
4
|
"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.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"preferGlobal": true,
|
package/src/cli/args.js
CHANGED
|
@@ -770,6 +770,7 @@ function parseFinishArgs(rawArgs, defaults = {}) {
|
|
|
770
770
|
cleanup: defaults.cleanup ?? true,
|
|
771
771
|
keepRemote: false,
|
|
772
772
|
noAutoCommit: false,
|
|
773
|
+
parentGitlinkCommit: defaults.parentGitlinkCommit ?? true,
|
|
773
774
|
failFast: false,
|
|
774
775
|
commitMessage: '',
|
|
775
776
|
mergeMode: defaults.mergeMode || 'pr',
|
|
@@ -865,6 +866,14 @@ function parseFinishArgs(rawArgs, defaults = {}) {
|
|
|
865
866
|
options.noAutoCommit = true;
|
|
866
867
|
continue;
|
|
867
868
|
}
|
|
869
|
+
if (arg === '--parent-gitlink-commit') {
|
|
870
|
+
options.parentGitlinkCommit = true;
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
if (arg === '--no-parent-gitlink-commit') {
|
|
874
|
+
options.parentGitlinkCommit = false;
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
868
877
|
if (arg === '--fail-fast') {
|
|
869
878
|
options.failFast = true;
|
|
870
879
|
continue;
|
package/src/cli/main.js
CHANGED
|
@@ -2431,15 +2431,20 @@ function report(rawArgs) {
|
|
|
2431
2431
|
const options = parseReportArgs(rawArgs);
|
|
2432
2432
|
const subcommand = options.subcommand || 'help';
|
|
2433
2433
|
if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
|
|
2434
|
+
const sessionSeverityHelpDetails = sessionSeverityReport.renderSessionSeverityHelpDetails()
|
|
2435
|
+
.split('\n')
|
|
2436
|
+
.map((line) => ` ${line}`)
|
|
2437
|
+
.join('\n');
|
|
2434
2438
|
console.log(
|
|
2435
2439
|
`${TOOL_NAME} report commands:\n` +
|
|
2436
2440
|
` ${TOOL_NAME} report scorecard [--target <path>] [--repo github.com/<owner>/<repo>] [--scorecard-json <file>] [--output-dir <path>] [--date YYYY-MM-DD] [--dry-run] [--json]\n` +
|
|
2437
|
-
` ${TOOL_NAME}
|
|
2441
|
+
` ${sessionSeverityReport.renderSessionSeverityCommand(TOOL_NAME)}\n` +
|
|
2442
|
+
`${sessionSeverityHelpDetails}\n` +
|
|
2438
2443
|
`\n` +
|
|
2439
2444
|
`Examples:\n` +
|
|
2440
2445
|
` ${TOOL_NAME} report scorecard --repo github.com/recodeecom/multiagent-safety\n` +
|
|
2441
2446
|
` ${TOOL_NAME} report scorecard --scorecard-json ./scorecard.json --date 2026-04-10\n` +
|
|
2442
|
-
` ${TOOL_NAME}
|
|
2447
|
+
` ${sessionSeverityReport.renderSessionSeverityExample(TOOL_NAME)}`,
|
|
2443
2448
|
);
|
|
2444
2449
|
process.exitCode = 0;
|
|
2445
2450
|
return;
|
package/src/context.js
CHANGED
|
@@ -129,6 +129,14 @@ const TEMPLATE_FILES = [
|
|
|
129
129
|
'vscode/guardex-active-agents/session-schema.js',
|
|
130
130
|
'vscode/guardex-active-agents/README.md',
|
|
131
131
|
'vscode/guardex-active-agents/icon.png',
|
|
132
|
+
'vscode/guardex-active-agents/fileicons/gitguardex-fileicons.json',
|
|
133
|
+
'vscode/guardex-active-agents/fileicons/icons/agent.svg',
|
|
134
|
+
'vscode/guardex-active-agents/fileicons/icons/branch.svg',
|
|
135
|
+
'vscode/guardex-active-agents/fileicons/icons/config.svg',
|
|
136
|
+
'vscode/guardex-active-agents/fileicons/icons/hook.svg',
|
|
137
|
+
'vscode/guardex-active-agents/fileicons/icons/openspec.svg',
|
|
138
|
+
'vscode/guardex-active-agents/fileicons/icons/plan.svg',
|
|
139
|
+
'vscode/guardex-active-agents/fileicons/icons/spec.svg',
|
|
132
140
|
];
|
|
133
141
|
|
|
134
142
|
const PACKAGE_ROOT_SOURCE_OVERRIDES = new Set([
|
|
@@ -139,6 +147,14 @@ const PACKAGE_ROOT_SOURCE_OVERRIDES = new Set([
|
|
|
139
147
|
'vscode/guardex-active-agents/session-schema.js',
|
|
140
148
|
'vscode/guardex-active-agents/README.md',
|
|
141
149
|
'vscode/guardex-active-agents/icon.png',
|
|
150
|
+
'vscode/guardex-active-agents/fileicons/gitguardex-fileicons.json',
|
|
151
|
+
'vscode/guardex-active-agents/fileicons/icons/agent.svg',
|
|
152
|
+
'vscode/guardex-active-agents/fileicons/icons/branch.svg',
|
|
153
|
+
'vscode/guardex-active-agents/fileicons/icons/config.svg',
|
|
154
|
+
'vscode/guardex-active-agents/fileicons/icons/hook.svg',
|
|
155
|
+
'vscode/guardex-active-agents/fileicons/icons/openspec.svg',
|
|
156
|
+
'vscode/guardex-active-agents/fileicons/icons/plan.svg',
|
|
157
|
+
'vscode/guardex-active-agents/fileicons/icons/spec.svg',
|
|
142
158
|
]);
|
|
143
159
|
|
|
144
160
|
const LEGACY_WORKFLOW_SHIM_SPECS = [
|
|
@@ -263,8 +279,12 @@ const AGENT_WORKTREE_RELATIVE_DIRS = [
|
|
|
263
279
|
const MANAGED_REPO_SCAN_IGNORED_FOLDERS = [
|
|
264
280
|
'.omx/agent-worktrees',
|
|
265
281
|
'**/.omx/agent-worktrees',
|
|
282
|
+
'.omx/.tmp-worktrees',
|
|
283
|
+
'**/.omx/.tmp-worktrees',
|
|
266
284
|
'.omc/agent-worktrees',
|
|
267
285
|
'**/.omc/agent-worktrees',
|
|
286
|
+
'.omc/.tmp-worktrees',
|
|
287
|
+
'**/.omc/.tmp-worktrees',
|
|
268
288
|
];
|
|
269
289
|
const MANAGED_GITIGNORE_PATHS = [
|
|
270
290
|
'.omx/',
|
|
@@ -427,6 +447,8 @@ const AI_SETUP_PARTS = [
|
|
|
427
447
|
'gx branch start "<task>" "<agent>"',
|
|
428
448
|
'then gx locks claim --branch "<agent-branch>" <file...> -> inspect once -> patch once -> verify once -> gx branch finish',
|
|
429
449
|
'batch discovery, git/PR, and CI by phase; avoid repeated peeks or stdin loops',
|
|
450
|
+
'checkpoint after each milestone: Task -> Done -> Current status -> Next; keep only the latest checkpoint(s) in active context',
|
|
451
|
+
'summarize tool results, keep stdin/process chatter ephemeral, and keep execution log separate from reasoning context',
|
|
430
452
|
],
|
|
431
453
|
execLines: [
|
|
432
454
|
'gx branch start "<task>" "<agent>"',
|
package/src/doctor/index.js
CHANGED
|
@@ -314,6 +314,118 @@ function doctorFinishFlowIsPending(output) {
|
|
|
314
314
|
);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
function verifyDoctorSandboxCleanup(repoRoot, metadata) {
|
|
318
|
+
const branchExists = Boolean(metadata.branch) && gitRefExists(repoRoot, `refs/heads/${metadata.branch}`);
|
|
319
|
+
const worktreeExists = Boolean(metadata.worktreePath) && fs.existsSync(metadata.worktreePath);
|
|
320
|
+
|
|
321
|
+
if (!branchExists && !worktreeExists) {
|
|
322
|
+
return {
|
|
323
|
+
status: 'verified',
|
|
324
|
+
note: 'doctor sandbox cleanup verified',
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const cleanup = cleanupProtectedBaseSandbox(repoRoot, metadata);
|
|
329
|
+
const branchStillExists = Boolean(metadata.branch) && gitRefExists(repoRoot, `refs/heads/${metadata.branch}`);
|
|
330
|
+
const worktreeStillExists = Boolean(metadata.worktreePath) && fs.existsSync(metadata.worktreePath);
|
|
331
|
+
if (branchStillExists || worktreeStillExists) {
|
|
332
|
+
return {
|
|
333
|
+
status: 'failed',
|
|
334
|
+
note:
|
|
335
|
+
'doctor sandbox cleanup incomplete ' +
|
|
336
|
+
`(branch=${branchStillExists ? 'present' : 'missing'}, worktree=${worktreeStillExists ? 'present' : 'missing'})`,
|
|
337
|
+
cleanup,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
status: 'verified',
|
|
343
|
+
note: 'doctor sandbox cleanup verified',
|
|
344
|
+
cleanup,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function verifyDoctorSandboxRemoteCleanup(repoRoot, metadata) {
|
|
349
|
+
if (!metadata.branch || !hasOriginRemote(repoRoot)) {
|
|
350
|
+
return {
|
|
351
|
+
status: 'skipped',
|
|
352
|
+
note: 'doctor sandbox remote cleanup skipped',
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const remoteBefore = run(
|
|
357
|
+
'git',
|
|
358
|
+
['-C', repoRoot, 'ls-remote', '--heads', 'origin', metadata.branch],
|
|
359
|
+
{ timeout: 20_000 },
|
|
360
|
+
);
|
|
361
|
+
if (isSpawnFailure(remoteBefore)) {
|
|
362
|
+
throw remoteBefore.error;
|
|
363
|
+
}
|
|
364
|
+
if (remoteBefore.status !== 0) {
|
|
365
|
+
return {
|
|
366
|
+
status: 'failed',
|
|
367
|
+
note: 'doctor sandbox remote branch inspection failed',
|
|
368
|
+
stdout: remoteBefore.stdout || '',
|
|
369
|
+
stderr: remoteBefore.stderr || '',
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
if (!String(remoteBefore.stdout || '').trim()) {
|
|
373
|
+
return {
|
|
374
|
+
status: 'verified',
|
|
375
|
+
note: 'doctor sandbox remote cleanup verified',
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const deleteResult = run(
|
|
380
|
+
'git',
|
|
381
|
+
['-C', repoRoot, 'push', 'origin', '--delete', metadata.branch],
|
|
382
|
+
{ timeout: 30_000 },
|
|
383
|
+
);
|
|
384
|
+
if (isSpawnFailure(deleteResult)) {
|
|
385
|
+
throw deleteResult.error;
|
|
386
|
+
}
|
|
387
|
+
if (deleteResult.status !== 0) {
|
|
388
|
+
return {
|
|
389
|
+
status: 'failed',
|
|
390
|
+
note: 'doctor sandbox remote branch cleanup failed',
|
|
391
|
+
stdout: deleteResult.stdout || '',
|
|
392
|
+
stderr: deleteResult.stderr || '',
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const remoteAfter = run(
|
|
397
|
+
'git',
|
|
398
|
+
['-C', repoRoot, 'ls-remote', '--heads', 'origin', metadata.branch],
|
|
399
|
+
{ timeout: 20_000 },
|
|
400
|
+
);
|
|
401
|
+
if (isSpawnFailure(remoteAfter)) {
|
|
402
|
+
throw remoteAfter.error;
|
|
403
|
+
}
|
|
404
|
+
if (remoteAfter.status !== 0) {
|
|
405
|
+
return {
|
|
406
|
+
status: 'failed',
|
|
407
|
+
note: 'doctor sandbox remote cleanup recheck failed',
|
|
408
|
+
stdout: remoteAfter.stdout || '',
|
|
409
|
+
stderr: remoteAfter.stderr || '',
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
if (String(remoteAfter.stdout || '').trim()) {
|
|
413
|
+
return {
|
|
414
|
+
status: 'failed',
|
|
415
|
+
note: 'doctor sandbox remote branch still present after cleanup',
|
|
416
|
+
stdout: remoteAfter.stdout || '',
|
|
417
|
+
stderr: remoteAfter.stderr || '',
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return {
|
|
422
|
+
status: 'verified',
|
|
423
|
+
note: 'doctor sandbox remote cleanup verified',
|
|
424
|
+
stdout: deleteResult.stdout || '',
|
|
425
|
+
stderr: deleteResult.stderr || '',
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
317
429
|
function finishDoctorSandboxBranch(blocked, metadata, options = {}) {
|
|
318
430
|
if (!hasOriginRemote(blocked.repoRoot)) {
|
|
319
431
|
return {
|
|
@@ -353,8 +465,8 @@ function finishDoctorSandboxBranch(blocked, metadata, options = {}) {
|
|
|
353
465
|
|
|
354
466
|
const finishResult = runPackageAsset(
|
|
355
467
|
'branchFinish',
|
|
356
|
-
['--branch', metadata.branch, '--base', blocked.branch, '--via-pr', waitForMergeArg, '--cleanup'],
|
|
357
|
-
{ cwd:
|
|
468
|
+
['--branch', metadata.branch, '--base', blocked.branch, '--via-pr', waitForMergeArg, '--no-cleanup'],
|
|
469
|
+
{ cwd: blocked.repoRoot, timeout: finishTimeoutMs },
|
|
358
470
|
);
|
|
359
471
|
if (isSpawnFailure(finishResult)) {
|
|
360
472
|
return {
|
|
@@ -384,11 +496,52 @@ function finishDoctorSandboxBranch(blocked, metadata, options = {}) {
|
|
|
384
496
|
};
|
|
385
497
|
}
|
|
386
498
|
|
|
499
|
+
let cleanupVerification;
|
|
500
|
+
try {
|
|
501
|
+
cleanupVerification = verifyDoctorSandboxCleanup(blocked.repoRoot, metadata);
|
|
502
|
+
} catch (error) {
|
|
503
|
+
return {
|
|
504
|
+
status: 'failed',
|
|
505
|
+
note: `doctor sandbox cleanup verification failed: ${error.message}`,
|
|
506
|
+
stdout: finishResult.stdout || '',
|
|
507
|
+
stderr: finishResult.stderr || '',
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
if (cleanupVerification.status === 'failed') {
|
|
511
|
+
return {
|
|
512
|
+
status: 'failed',
|
|
513
|
+
note: cleanupVerification.note,
|
|
514
|
+
stdout: finishResult.stdout || '',
|
|
515
|
+
stderr: finishResult.stderr || '',
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
let remoteCleanupVerification;
|
|
520
|
+
try {
|
|
521
|
+
remoteCleanupVerification = verifyDoctorSandboxRemoteCleanup(blocked.repoRoot, metadata);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
return {
|
|
524
|
+
status: 'failed',
|
|
525
|
+
note: `doctor sandbox remote cleanup verification failed: ${error.message}`,
|
|
526
|
+
stdout: finishResult.stdout || '',
|
|
527
|
+
stderr: finishResult.stderr || '',
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
if (remoteCleanupVerification.status === 'failed') {
|
|
531
|
+
return {
|
|
532
|
+
status: 'failed',
|
|
533
|
+
note: remoteCleanupVerification.note,
|
|
534
|
+
stdout: [finishResult.stdout || '', remoteCleanupVerification.stdout || ''].filter(Boolean).join('\n'),
|
|
535
|
+
stderr: [finishResult.stderr || '', remoteCleanupVerification.stderr || ''].filter(Boolean).join('\n'),
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
387
539
|
return {
|
|
388
540
|
status: 'completed',
|
|
389
|
-
note: 'doctor sandbox finish flow completed',
|
|
390
|
-
stdout: finishResult.stdout || '',
|
|
391
|
-
stderr: finishResult.stderr || '',
|
|
541
|
+
note: 'doctor sandbox finish flow completed and cleanup verified',
|
|
542
|
+
stdout: [finishResult.stdout || '', remoteCleanupVerification.stdout || ''].filter(Boolean).join('\n'),
|
|
543
|
+
stderr: [finishResult.stderr || '', remoteCleanupVerification.stderr || ''].filter(Boolean).join('\n'),
|
|
544
|
+
cleanup: cleanupVerification.cleanup,
|
|
392
545
|
};
|
|
393
546
|
}
|
|
394
547
|
|
package/src/finish/index.js
CHANGED
|
@@ -317,6 +317,7 @@ function finish(rawArgs, defaults = {}) {
|
|
|
317
317
|
if (options.keepRemote) {
|
|
318
318
|
finishArgs.push('--keep-remote-branch');
|
|
319
319
|
}
|
|
320
|
+
finishArgs.push(options.parentGitlinkCommit ? '--parent-gitlink-commit' : '--no-parent-gitlink-commit');
|
|
320
321
|
|
|
321
322
|
if (options.dryRun) {
|
|
322
323
|
console.log(`[${TOOL_NAME}] [dry-run] Would run: gx branch finish ${finishArgs.join(' ')}`);
|
|
@@ -4,7 +4,8 @@ const TASK_SIZE_UPPER_BOUNDS = {
|
|
|
4
4
|
'large-change': 8_000_000,
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
const TASK_SIZE_VALUES =
|
|
7
|
+
const TASK_SIZE_VALUES = Object.keys(TASK_SIZE_UPPER_BOUNDS);
|
|
8
|
+
const TASK_SIZE_SET = new Set(TASK_SIZE_VALUES);
|
|
8
9
|
const FRAGMENTATION_PRESET_SCORES = {
|
|
9
10
|
clean: 0,
|
|
10
11
|
'few-extra-checks': 5,
|
|
@@ -32,6 +33,50 @@ const DRIVER_LABELS = {
|
|
|
32
33
|
finishPath: 'finish-path discipline',
|
|
33
34
|
postProof: 'post-proof drift',
|
|
34
35
|
};
|
|
36
|
+
const LABEL_BANDS = [
|
|
37
|
+
{ max: 15, label: 'Healthy' },
|
|
38
|
+
{ max: 30, label: 'Mildly fragmented' },
|
|
39
|
+
{ max: 50, label: 'Inefficient' },
|
|
40
|
+
{ max: 75, label: 'Runaway' },
|
|
41
|
+
{ max: 100, label: 'Catastrophic' },
|
|
42
|
+
];
|
|
43
|
+
const SESSION_SEVERITY_SUBCOMMAND = 'session-severity';
|
|
44
|
+
const SESSION_SEVERITY_USAGE_ARGS = [
|
|
45
|
+
`--task-size <${TASK_SIZE_VALUES.join('|')}>`,
|
|
46
|
+
'--tokens <count>',
|
|
47
|
+
'--exec-count <count>',
|
|
48
|
+
'--write-stdin-count <count>',
|
|
49
|
+
'--completion-before-tail <yes|no>',
|
|
50
|
+
'[--expected-bound <count>]',
|
|
51
|
+
`[--fragmentation <${Object.keys(FRAGMENTATION_PRESET_SCORES).join('|')}|0-25>]`,
|
|
52
|
+
`[--finish-path <${Object.keys(FINISH_PATH_PRESET_SCORES).join('|')}|0-15>]`,
|
|
53
|
+
`[--post-proof <${Object.keys(POST_PROOF_PRESET_SCORES).join('|')}|0-15>]`,
|
|
54
|
+
'[--json]',
|
|
55
|
+
].join(' ');
|
|
56
|
+
const SESSION_SEVERITY_COMMAND_TAIL = `${SESSION_SEVERITY_SUBCOMMAND} ${SESSION_SEVERITY_USAGE_ARGS}`;
|
|
57
|
+
const SESSION_SEVERITY_EXAMPLE_ARGS = [
|
|
58
|
+
'--task-size',
|
|
59
|
+
'narrow-patch',
|
|
60
|
+
'--tokens',
|
|
61
|
+
'3850000',
|
|
62
|
+
'--exec-count',
|
|
63
|
+
'18',
|
|
64
|
+
'--write-stdin-count',
|
|
65
|
+
'6',
|
|
66
|
+
'--completion-before-tail',
|
|
67
|
+
'yes',
|
|
68
|
+
'--fragmentation',
|
|
69
|
+
'14',
|
|
70
|
+
'--finish-path',
|
|
71
|
+
'6',
|
|
72
|
+
'--post-proof',
|
|
73
|
+
'4',
|
|
74
|
+
];
|
|
75
|
+
const SESSION_SEVERITY_EXAMPLE_TAIL = `${SESSION_SEVERITY_SUBCOMMAND} ${SESSION_SEVERITY_EXAMPLE_ARGS.join(' ')}`;
|
|
76
|
+
|
|
77
|
+
function formatInteger(value) {
|
|
78
|
+
return Number(value).toLocaleString('en-US');
|
|
79
|
+
}
|
|
35
80
|
|
|
36
81
|
function parseRequiredPositiveInteger(name, rawValue, { allowZero = true } = {}) {
|
|
37
82
|
const parsed = Number.parseInt(String(rawValue || ''), 10);
|
|
@@ -58,8 +103,8 @@ function clampScore(value, min, max) {
|
|
|
58
103
|
|
|
59
104
|
function parseTaskSize(rawTaskSize) {
|
|
60
105
|
const normalized = String(rawTaskSize || '').trim();
|
|
61
|
-
if (!
|
|
62
|
-
throw new Error(`--task-size must be one of: ${
|
|
106
|
+
if (!TASK_SIZE_SET.has(normalized)) {
|
|
107
|
+
throw new Error(`--task-size must be one of: ${TASK_SIZE_VALUES.join(', ')}`);
|
|
63
108
|
}
|
|
64
109
|
return normalized;
|
|
65
110
|
}
|
|
@@ -123,11 +168,7 @@ function scorePostProof(completionBeforeTail, override) {
|
|
|
123
168
|
}
|
|
124
169
|
|
|
125
170
|
function labelForTotal(total) {
|
|
126
|
-
|
|
127
|
-
if (total <= 30) return 'Mildly fragmented';
|
|
128
|
-
if (total <= 50) return 'Inefficient';
|
|
129
|
-
if (total <= 75) return 'Runaway';
|
|
130
|
-
return 'Catastrophic';
|
|
171
|
+
return LABEL_BANDS.find((band) => total <= band.max)?.label || LABEL_BANDS[LABEL_BANDS.length - 1].label;
|
|
131
172
|
}
|
|
132
173
|
|
|
133
174
|
function buildSessionSeverityReport(options) {
|
|
@@ -205,9 +246,37 @@ function renderSessionSeverityReport(report) {
|
|
|
205
246
|
].join('\n');
|
|
206
247
|
}
|
|
207
248
|
|
|
249
|
+
function renderSessionSeverityHelpDetails() {
|
|
250
|
+
const taskSizeDefaults = TASK_SIZE_VALUES
|
|
251
|
+
.map((taskSize) => `${taskSize}=${formatInteger(TASK_SIZE_UPPER_BOUNDS[taskSize])}`)
|
|
252
|
+
.join(', ');
|
|
253
|
+
const labelBands = LABEL_BANDS
|
|
254
|
+
.map((band, index) => {
|
|
255
|
+
const min = index === 0 ? 0 : LABEL_BANDS[index - 1].max + 1;
|
|
256
|
+
return `${band.label}=${min}-${band.max}`;
|
|
257
|
+
})
|
|
258
|
+
.join(', ');
|
|
259
|
+
return [`Task-size defaults: ${taskSizeDefaults}`, `Label bands: ${labelBands}`].join('\n');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function renderSessionSeverityCommand(toolName) {
|
|
263
|
+
return `${toolName} report ${SESSION_SEVERITY_COMMAND_TAIL}`;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function renderSessionSeverityExample(toolName) {
|
|
267
|
+
return `${toolName} report ${SESSION_SEVERITY_EXAMPLE_TAIL}`;
|
|
268
|
+
}
|
|
269
|
+
|
|
208
270
|
module.exports = {
|
|
271
|
+
LABEL_BANDS,
|
|
272
|
+
SESSION_SEVERITY_COMMAND_TAIL,
|
|
273
|
+
SESSION_SEVERITY_EXAMPLE_ARGS,
|
|
274
|
+
SESSION_SEVERITY_EXAMPLE_TAIL,
|
|
209
275
|
TASK_SIZE_UPPER_BOUNDS,
|
|
210
276
|
buildSessionSeverityReport,
|
|
211
277
|
renderSessionSeverityReport,
|
|
278
|
+
renderSessionSeverityHelpDetails,
|
|
279
|
+
renderSessionSeverityCommand,
|
|
280
|
+
renderSessionSeverityExample,
|
|
212
281
|
labelForTotal,
|
|
213
282
|
};
|
|
@@ -21,8 +21,11 @@ Default: less word, same proof.
|
|
|
21
21
|
- Front-load scaffold/path discovery into one grouped inspection pass. Avoid serial `ls` / `find` / `rg` / `cat` retries that only rediscover the same path state.
|
|
22
22
|
- Treat repeated `write_stdin`, repeated `sed` / `cat` peeks, and tiny diagnostic follow-up checks as strong negative signals. If they appear alongside climbing input cost, stop the probe loop and batch the next phase.
|
|
23
23
|
- Tool / hook summaries stay tiny: command, status, last meaningful lines only. Drop routine hook boilerplate.
|
|
24
|
+
- Keep raw terminal interaction out of long-lived context. For `write_stdin` or interactive babysitting, retain only process, action sent, current result, and next action.
|
|
25
|
+
- Keep execution log separate from reasoning context: full commands/stdout belong in logs, while prompt context keeps only the latest 1-2 checkpoints plus the newest tool-result summary.
|
|
24
26
|
- Treat local edit/commit, remote publish/PR, CI diagnosis, and cleanup as bounded phases. Do not spend fresh narration or approval turns on obvious safe follow-ons inside an already authorized phase unless the risk changes.
|
|
25
27
|
- When a session turns fragmented, collapse back to inspect once, patch once, verify once, and summarize once.
|
|
28
|
+
- Use a fixed checkpoint shape when compacting: `Task`, `Done`, `Current status`, and `Next`.
|
|
26
29
|
- Keep `.omx/notepad.md` lean: live handoffs only. Use exactly `branch`, `task`, `blocker`, `next step`, and `evidence`; move narrative proof into OpenSpec artifacts, PRs, or command output.
|
|
27
30
|
|
|
28
31
|
## OMX Caveman Style
|
|
@@ -9,6 +9,7 @@ Use this skill when you only want to promote Codex skill file updates into the b
|
|
|
9
9
|
|
|
10
10
|
## What this merges
|
|
11
11
|
|
|
12
|
+
- `skills/**/SKILL.md`
|
|
12
13
|
- `.codex/skills/**/SKILL.md`
|
|
13
14
|
- `templates/codex/skills/**/SKILL.md`
|
|
14
15
|
|
|
@@ -33,7 +34,7 @@ gx branch start "merge-skill-files-to-${BASE_BRANCH}" "skill-merge" "$BASE_BRANC
|
|
|
33
34
|
|
|
34
35
|
```sh
|
|
35
36
|
SOURCE_BRANCH="<agent-branch>"
|
|
36
|
-
git checkout "$SOURCE_BRANCH" -- ':(glob).codex/skills/**/SKILL.md' ':(glob)templates/codex/skills/**/SKILL.md'
|
|
37
|
+
git checkout "$SOURCE_BRANCH" -- ':(glob)skills/**/SKILL.md' ':(glob).codex/skills/**/SKILL.md' ':(glob)templates/codex/skills/**/SKILL.md'
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
5. Verify scope before commit:
|
|
@@ -46,7 +47,7 @@ git diff --name-only
|
|
|
46
47
|
6. Commit and merge back to base using guardex finish flow:
|
|
47
48
|
|
|
48
49
|
```sh
|
|
49
|
-
git add .codex/skills templates/codex/skills
|
|
50
|
+
git add skills .codex/skills templates/codex/skills
|
|
50
51
|
git commit -m "Merge skill file updates into ${BASE_BRANCH}"
|
|
51
52
|
gx branch finish --branch "$(git rev-parse --abbrev-ref HEAD)" --base "$BASE_BRANCH" --via-pr --wait-for-merge --cleanup
|
|
52
53
|
```
|