@nforma.ai/nforma 0.2.1
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/LICENSE +22 -0
- package/README.md +1024 -0
- package/agents/qgsd-codebase-mapper.md +764 -0
- package/agents/qgsd-debugger.md +1201 -0
- package/agents/qgsd-executor.md +472 -0
- package/agents/qgsd-integration-checker.md +443 -0
- package/agents/qgsd-phase-researcher.md +502 -0
- package/agents/qgsd-plan-checker.md +643 -0
- package/agents/qgsd-planner.md +1182 -0
- package/agents/qgsd-project-researcher.md +621 -0
- package/agents/qgsd-quorum-orchestrator.md +628 -0
- package/agents/qgsd-quorum-slot-worker.md +41 -0
- package/agents/qgsd-quorum-synthesizer.md +133 -0
- package/agents/qgsd-quorum-test-worker.md +37 -0
- package/agents/qgsd-quorum-worker.md +161 -0
- package/agents/qgsd-research-synthesizer.md +239 -0
- package/agents/qgsd-roadmapper.md +660 -0
- package/agents/qgsd-verifier.md +628 -0
- package/bin/accept-debug-invariant.cjs +165 -0
- package/bin/account-manager.cjs +719 -0
- package/bin/aggregate-requirements.cjs +466 -0
- package/bin/analyze-assumptions.cjs +757 -0
- package/bin/analyze-state-space.cjs +921 -0
- package/bin/attribute-trace-divergence.cjs +150 -0
- package/bin/auth-drivers/gh-cli.cjs +93 -0
- package/bin/auth-drivers/index.cjs +46 -0
- package/bin/auth-drivers/pool.cjs +67 -0
- package/bin/auth-drivers/simple.cjs +95 -0
- package/bin/autoClosePtoF.cjs +110 -0
- package/bin/blessed-terminal.cjs +350 -0
- package/bin/build-phase-index.cjs +472 -0
- package/bin/call-quorum-slot.cjs +541 -0
- package/bin/ccr-secure-config.cjs +99 -0
- package/bin/ccr-secure-start.cjs +83 -0
- package/bin/check-bundled-sdks.cjs +177 -0
- package/bin/check-coverage-guard.cjs +112 -0
- package/bin/check-liveness-fairness.cjs +95 -0
- package/bin/check-mcp-health.cjs +123 -0
- package/bin/check-provider-health.cjs +395 -0
- package/bin/check-results-exit.cjs +24 -0
- package/bin/check-spec-sync.cjs +360 -0
- package/bin/check-trace-redaction.cjs +271 -0
- package/bin/check-trace-schema-drift.cjs +99 -0
- package/bin/compareDrift.cjs +21 -0
- package/bin/conformance-schema.cjs +12 -0
- package/bin/count-scenarios.cjs +420 -0
- package/bin/debt-dedup.cjs +144 -0
- package/bin/debt-ledger.cjs +61 -0
- package/bin/debt-retention.cjs +76 -0
- package/bin/debt-state-machine.cjs +80 -0
- package/bin/detect-coverage-gaps.cjs +204 -0
- package/bin/detect-project-intent.cjs +362 -0
- package/bin/export-prism-constants.cjs +164 -0
- package/bin/extract-annotations.cjs +633 -0
- package/bin/extractFormalExpected.cjs +104 -0
- package/bin/fingerprint-drift.cjs +24 -0
- package/bin/fingerprint-issue.cjs +46 -0
- package/bin/formal-core.cjs +519 -0
- package/bin/formal-ref-linker.cjs +141 -0
- package/bin/formal-test-sync.cjs +788 -0
- package/bin/generate-formal-specs.cjs +588 -0
- package/bin/generate-petri-net.cjs +397 -0
- package/bin/generate-phase-spec.cjs +249 -0
- package/bin/generate-proposed-changes.cjs +194 -0
- package/bin/generate-tla-cfg.cjs +122 -0
- package/bin/generate-traceability-matrix.cjs +701 -0
- package/bin/generate-triage-bundle.cjs +300 -0
- package/bin/gh-account-rotate.cjs +34 -0
- package/bin/initialize-model-registry.cjs +105 -0
- package/bin/install-formal-tools.cjs +382 -0
- package/bin/install.js +2424 -0
- package/bin/isNumericThreshold.cjs +34 -0
- package/bin/issue-classifier.cjs +151 -0
- package/bin/levenshtein.cjs +74 -0
- package/bin/lint-formal-models.cjs +580 -0
- package/bin/load-baseline-requirements.cjs +275 -0
- package/bin/manage-agents-core.cjs +815 -0
- package/bin/migrate-formal-dir.cjs +172 -0
- package/bin/migrate-planning.cjs +206 -0
- package/bin/migrate-to-slots.cjs +255 -0
- package/bin/nForma.cjs +2726 -0
- package/bin/observe-config.cjs +353 -0
- package/bin/observe-debt-writer.cjs +140 -0
- package/bin/observe-handler-grafana.cjs +128 -0
- package/bin/observe-handler-internal.cjs +301 -0
- package/bin/observe-handler-logstash.cjs +153 -0
- package/bin/observe-handler-prometheus.cjs +185 -0
- package/bin/observe-handlers.cjs +436 -0
- package/bin/observe-registry.cjs +131 -0
- package/bin/observe-render.cjs +168 -0
- package/bin/planning-paths.cjs +167 -0
- package/bin/polyrepo.cjs +560 -0
- package/bin/prism-priority.cjs +153 -0
- package/bin/probe-quorum-slots.cjs +167 -0
- package/bin/promote-model.cjs +225 -0
- package/bin/propose-debug-invariants.cjs +165 -0
- package/bin/providers.json +392 -0
- package/bin/pty-proxy.py +129 -0
- package/bin/qgsd-solve.cjs +2477 -0
- package/bin/quorum-consensus-gate.cjs +238 -0
- package/bin/quorum-formal-context.cjs +183 -0
- package/bin/quorum-slot-dispatch.cjs +934 -0
- package/bin/read-policy.cjs +60 -0
- package/bin/requirement-map.cjs +63 -0
- package/bin/requirements-core.cjs +247 -0
- package/bin/resolve-cli.cjs +101 -0
- package/bin/review-mcp-logs.cjs +294 -0
- package/bin/run-account-manager-tlc.cjs +188 -0
- package/bin/run-account-pool-alloy.cjs +158 -0
- package/bin/run-alloy.cjs +153 -0
- package/bin/run-audit-alloy.cjs +187 -0
- package/bin/run-breaker-tlc.cjs +181 -0
- package/bin/run-formal-check.cjs +395 -0
- package/bin/run-formal-verify.cjs +701 -0
- package/bin/run-installer-alloy.cjs +188 -0
- package/bin/run-oauth-rotation-prism.cjs +132 -0
- package/bin/run-oscillation-tlc.cjs +202 -0
- package/bin/run-phase-tlc.cjs +228 -0
- package/bin/run-prism.cjs +446 -0
- package/bin/run-protocol-tlc.cjs +201 -0
- package/bin/run-quorum-composition-alloy.cjs +155 -0
- package/bin/run-sensitivity-sweep.cjs +231 -0
- package/bin/run-stop-hook-tlc.cjs +188 -0
- package/bin/run-tlc.cjs +467 -0
- package/bin/run-transcript-alloy.cjs +173 -0
- package/bin/run-uppaal.cjs +264 -0
- package/bin/secrets.cjs +134 -0
- package/bin/sensitivity-report.cjs +219 -0
- package/bin/sensitivity-sweep-feedback.cjs +194 -0
- package/bin/set-secret.cjs +29 -0
- package/bin/setup-telemetry-cron.sh +36 -0
- package/bin/sweepPtoF.cjs +63 -0
- package/bin/sync-baseline-requirements.cjs +290 -0
- package/bin/task-envelope.cjs +360 -0
- package/bin/telemetry-collector.cjs +229 -0
- package/bin/unified-mcp-server.mjs +735 -0
- package/bin/update-agents.cjs +369 -0
- package/bin/update-scoreboard.cjs +1134 -0
- package/bin/validate-debt-entry.cjs +207 -0
- package/bin/validate-invariant.cjs +419 -0
- package/bin/validate-memory.cjs +389 -0
- package/bin/validate-requirements-haiku.cjs +435 -0
- package/bin/validate-traces.cjs +438 -0
- package/bin/verify-formal-results.cjs +124 -0
- package/bin/verify-quorum-health.cjs +273 -0
- package/bin/write-check-result.cjs +106 -0
- package/bin/xstate-to-tla.cjs +483 -0
- package/bin/xstate-trace-walker.cjs +205 -0
- package/commands/qgsd/add-phase.md +43 -0
- package/commands/qgsd/add-requirement.md +24 -0
- package/commands/qgsd/add-todo.md +47 -0
- package/commands/qgsd/audit-milestone.md +37 -0
- package/commands/qgsd/check-todos.md +45 -0
- package/commands/qgsd/cleanup.md +18 -0
- package/commands/qgsd/close-formal-gaps.md +33 -0
- package/commands/qgsd/complete-milestone.md +136 -0
- package/commands/qgsd/debug.md +166 -0
- package/commands/qgsd/discuss-phase.md +83 -0
- package/commands/qgsd/execute-phase.md +117 -0
- package/commands/qgsd/fix-tests.md +27 -0
- package/commands/qgsd/formal-test-sync.md +32 -0
- package/commands/qgsd/health.md +22 -0
- package/commands/qgsd/help.md +22 -0
- package/commands/qgsd/insert-phase.md +32 -0
- package/commands/qgsd/join-discord.md +18 -0
- package/commands/qgsd/list-phase-assumptions.md +46 -0
- package/commands/qgsd/map-codebase.md +71 -0
- package/commands/qgsd/map-requirements.md +20 -0
- package/commands/qgsd/mcp-restart.md +176 -0
- package/commands/qgsd/mcp-set-model.md +134 -0
- package/commands/qgsd/mcp-setup.md +1371 -0
- package/commands/qgsd/mcp-status.md +274 -0
- package/commands/qgsd/mcp-update.md +238 -0
- package/commands/qgsd/new-milestone.md +44 -0
- package/commands/qgsd/new-project.md +42 -0
- package/commands/qgsd/observe.md +260 -0
- package/commands/qgsd/pause-work.md +38 -0
- package/commands/qgsd/plan-milestone-gaps.md +34 -0
- package/commands/qgsd/plan-phase.md +44 -0
- package/commands/qgsd/polyrepo.md +50 -0
- package/commands/qgsd/progress.md +24 -0
- package/commands/qgsd/queue.md +54 -0
- package/commands/qgsd/quick.md +133 -0
- package/commands/qgsd/quorum-test.md +275 -0
- package/commands/qgsd/quorum.md +707 -0
- package/commands/qgsd/reapply-patches.md +110 -0
- package/commands/qgsd/remove-phase.md +31 -0
- package/commands/qgsd/research-phase.md +189 -0
- package/commands/qgsd/resume-work.md +40 -0
- package/commands/qgsd/set-profile.md +34 -0
- package/commands/qgsd/settings.md +39 -0
- package/commands/qgsd/solve.md +565 -0
- package/commands/qgsd/sync-baselines.md +119 -0
- package/commands/qgsd/triage.md +233 -0
- package/commands/qgsd/update.md +37 -0
- package/commands/qgsd/verify-work.md +38 -0
- package/hooks/dist/config-loader.js +297 -0
- package/hooks/dist/conformance-schema.cjs +12 -0
- package/hooks/dist/gsd-context-monitor.js +64 -0
- package/hooks/dist/qgsd-check-update.js +62 -0
- package/hooks/dist/qgsd-circuit-breaker.js +682 -0
- package/hooks/dist/qgsd-precompact.js +156 -0
- package/hooks/dist/qgsd-prompt.js +653 -0
- package/hooks/dist/qgsd-session-start.js +122 -0
- package/hooks/dist/qgsd-slot-correlator.js +58 -0
- package/hooks/dist/qgsd-spec-regen.js +86 -0
- package/hooks/dist/qgsd-statusline.js +91 -0
- package/hooks/dist/qgsd-stop.js +553 -0
- package/hooks/dist/qgsd-token-collector.js +133 -0
- package/hooks/dist/unified-mcp-server.mjs +669 -0
- package/package.json +95 -0
- package/scripts/build-hooks.js +46 -0
- package/scripts/postinstall.js +48 -0
- package/scripts/secret-audit.sh +45 -0
- package/templates/qgsd.json +49 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* update-agents.cjs — Detect, display, and update sub-coding agent CLIs.
|
|
5
|
+
*
|
|
6
|
+
* Exports:
|
|
7
|
+
* updateAgents() — interactive update flow (display table + prompt)
|
|
8
|
+
* getUpdateStatuses() — parallel version detection, returns Map<name, {current, latest, status}>
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { spawnSync } = require('child_process');
|
|
13
|
+
const inquirer = require('inquirer');
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// CLI metadata map — keyed by binary basename
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
const CLI_META = {
|
|
20
|
+
codex: { installType: 'npm-global', pkg: '@openai/codex' },
|
|
21
|
+
gemini: { installType: 'npm-global', pkg: '@google/gemini-cli' },
|
|
22
|
+
opencode: { installType: 'npm-global', pkg: 'opencode' },
|
|
23
|
+
copilot: { installType: 'gh-extension', ext: 'github/gh-copilot' },
|
|
24
|
+
ccr: { installType: 'npm-global', pkg: 'claude-code-router' },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Build CLI list from providers.json
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
function buildCliList() {
|
|
32
|
+
let providers = [];
|
|
33
|
+
try {
|
|
34
|
+
const data = require('./providers.json');
|
|
35
|
+
providers = data.providers || [];
|
|
36
|
+
} catch (_) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Deduplicate by binary basename
|
|
41
|
+
const seen = new Set();
|
|
42
|
+
const list = [];
|
|
43
|
+
for (const p of providers) {
|
|
44
|
+
if (!p.cli) continue;
|
|
45
|
+
const binName = path.basename(p.cli);
|
|
46
|
+
if (seen.has(binName)) continue;
|
|
47
|
+
seen.add(binName);
|
|
48
|
+
const meta = CLI_META[binName];
|
|
49
|
+
if (!meta) continue; // skip unknown CLIs
|
|
50
|
+
list.push({ name: binName, meta });
|
|
51
|
+
}
|
|
52
|
+
return list;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Semver comparison (no external package)
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns true if version a >= version b (strips leading 'v').
|
|
61
|
+
*/
|
|
62
|
+
function semverGte(a, b) {
|
|
63
|
+
if (!a || !b) return false;
|
|
64
|
+
const parse = (v) =>
|
|
65
|
+
String(v)
|
|
66
|
+
.replace(/^v/, '')
|
|
67
|
+
.split('.')
|
|
68
|
+
.map((n) => parseInt(n, 10) || 0);
|
|
69
|
+
const pa = parse(a);
|
|
70
|
+
const pb = parse(b);
|
|
71
|
+
const len = Math.max(pa.length, pb.length);
|
|
72
|
+
for (let i = 0; i < len; i++) {
|
|
73
|
+
const na = pa[i] || 0;
|
|
74
|
+
const nb = pb[i] || 0;
|
|
75
|
+
if (na > nb) return true;
|
|
76
|
+
if (na < nb) return false;
|
|
77
|
+
}
|
|
78
|
+
return true; // equal
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Derive status string
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Returns 'up-to-date' | 'update-available' | 'unknown'
|
|
87
|
+
*/
|
|
88
|
+
function deriveStatus(current, latest) {
|
|
89
|
+
if (!current || !latest) return 'unknown';
|
|
90
|
+
return semverGte(current, latest) ? 'up-to-date' : 'update-available';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Detect current installed version
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
async function detectCurrent(meta) {
|
|
98
|
+
try {
|
|
99
|
+
if (meta.installType === 'npm-global') {
|
|
100
|
+
const res = spawnSync('npm', ['list', '-g', meta.pkg, '--depth=0', '--json'], {
|
|
101
|
+
encoding: 'utf8',
|
|
102
|
+
timeout: 8000,
|
|
103
|
+
});
|
|
104
|
+
if (res.status === 0 && res.stdout) {
|
|
105
|
+
const parsed = JSON.parse(res.stdout);
|
|
106
|
+
const dep = parsed.dependencies && parsed.dependencies[meta.pkg];
|
|
107
|
+
if (dep && dep.version) return dep.version;
|
|
108
|
+
}
|
|
109
|
+
} else if (meta.installType === 'gh-extension') {
|
|
110
|
+
const res = spawnSync('gh', ['extension', 'list'], {
|
|
111
|
+
encoding: 'utf8',
|
|
112
|
+
timeout: 6000,
|
|
113
|
+
});
|
|
114
|
+
if (res.status === 0 && res.stdout) {
|
|
115
|
+
const lines = res.stdout.split('\n');
|
|
116
|
+
for (const line of lines) {
|
|
117
|
+
// Format: github/gh-copilot v1.2.3 or similar tab-delimited
|
|
118
|
+
if (line.includes('copilot')) {
|
|
119
|
+
// Extract version token (starts with v or is a semver-like number)
|
|
120
|
+
const match = line.match(/\b(v?\d+\.\d+[\.\d]*)\b/);
|
|
121
|
+
if (match) return match[1].replace(/^v/, '');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (_) {
|
|
127
|
+
// fall through
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Detect latest available version
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
async function detectLatest(meta) {
|
|
137
|
+
try {
|
|
138
|
+
if (meta.installType === 'npm-global') {
|
|
139
|
+
const res = spawnSync('npm', ['view', meta.pkg, 'version'], {
|
|
140
|
+
encoding: 'utf8',
|
|
141
|
+
timeout: 8000,
|
|
142
|
+
});
|
|
143
|
+
if (res.status === 0 && res.stdout) {
|
|
144
|
+
const v = res.stdout.trim();
|
|
145
|
+
if (v) return v;
|
|
146
|
+
}
|
|
147
|
+
} else if (meta.installType === 'gh-extension') {
|
|
148
|
+
const res = spawnSync(
|
|
149
|
+
'gh',
|
|
150
|
+
['extension', 'upgrade', '--dry-run', 'copilot'],
|
|
151
|
+
{ encoding: 'utf8', stderr: 'pipe', timeout: 8000 }
|
|
152
|
+
);
|
|
153
|
+
const combined = (res.stdout || '') + (res.stderr || '');
|
|
154
|
+
if (/already up.?to.?date/i.test(combined)) {
|
|
155
|
+
// Return current version as latest (they're the same)
|
|
156
|
+
return await detectCurrent(meta);
|
|
157
|
+
}
|
|
158
|
+
// Try to parse a version from the output
|
|
159
|
+
const match = combined.match(/\b(v?\d+\.\d+[\.\d]*)\b/);
|
|
160
|
+
if (match) return match[1].replace(/^v/, '');
|
|
161
|
+
// Could not determine latest
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
} catch (_) {
|
|
165
|
+
// fall through
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
// ANSI helpers
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
const RESET = '\x1b[0m';
|
|
175
|
+
const YELLOW = '\x1b[33m';
|
|
176
|
+
const GREEN = '\x1b[32m';
|
|
177
|
+
const DIM = '\x1b[90m';
|
|
178
|
+
|
|
179
|
+
function colorStatus(status) {
|
|
180
|
+
if (status === 'update-available') return YELLOW + '\u2191 update available' + RESET;
|
|
181
|
+
if (status === 'up-to-date') return GREEN + '\u2713 up to date' + RESET;
|
|
182
|
+
return DIM + '? unknown' + RESET;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
// getUpdateStatuses() — parallel, exported
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
async function getUpdateStatuses() {
|
|
190
|
+
try {
|
|
191
|
+
const cliList = buildCliList();
|
|
192
|
+
const results = await Promise.all(
|
|
193
|
+
cliList.map(async ({ name, meta }) => {
|
|
194
|
+
try {
|
|
195
|
+
const current = await detectCurrent(meta);
|
|
196
|
+
const latest = await detectLatest(meta);
|
|
197
|
+
const status = deriveStatus(current, latest);
|
|
198
|
+
return [name, { current, latest, status }];
|
|
199
|
+
} catch (_) {
|
|
200
|
+
return [name, { current: null, latest: null, status: 'unknown' }];
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
return new Map(results);
|
|
205
|
+
} catch (_) {
|
|
206
|
+
return new Map();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// Print version table
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
|
|
214
|
+
function printTable(rows) {
|
|
215
|
+
const W = { cli: 10, installType: 13, current: 10, latest: 10 };
|
|
216
|
+
|
|
217
|
+
const header =
|
|
218
|
+
' ' +
|
|
219
|
+
'CLI'.padEnd(W.cli) +
|
|
220
|
+
'Install'.padEnd(W.installType) +
|
|
221
|
+
'Current'.padEnd(W.current) +
|
|
222
|
+
'Latest'.padEnd(W.latest) +
|
|
223
|
+
'Status';
|
|
224
|
+
|
|
225
|
+
const sep =
|
|
226
|
+
' ' +
|
|
227
|
+
'\u2500'.repeat(W.cli - 1) +
|
|
228
|
+
' ' +
|
|
229
|
+
'\u2500'.repeat(W.installType - 1) +
|
|
230
|
+
' ' +
|
|
231
|
+
'\u2500'.repeat(W.current - 1) +
|
|
232
|
+
' ' +
|
|
233
|
+
'\u2500'.repeat(W.latest - 1) +
|
|
234
|
+
' ' +
|
|
235
|
+
'\u2500'.repeat(18);
|
|
236
|
+
|
|
237
|
+
console.log('\n' + header);
|
|
238
|
+
console.log(sep);
|
|
239
|
+
|
|
240
|
+
for (const row of rows) {
|
|
241
|
+
const line =
|
|
242
|
+
' ' +
|
|
243
|
+
row.name.padEnd(W.cli) +
|
|
244
|
+
row.meta.installType.padEnd(W.installType) +
|
|
245
|
+
(row.current || '—').padEnd(W.current) +
|
|
246
|
+
(row.latest || '—').padEnd(W.latest) +
|
|
247
|
+
colorStatus(row.status);
|
|
248
|
+
console.log(line);
|
|
249
|
+
}
|
|
250
|
+
console.log('');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
// Run update for one CLI
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
function runUpdate({ name, meta }) {
|
|
258
|
+
try {
|
|
259
|
+
let result;
|
|
260
|
+
if (meta.installType === 'npm-global') {
|
|
261
|
+
result = spawnSync('npm', ['install', '-g', `${meta.pkg}@latest`], {
|
|
262
|
+
stdio: 'inherit',
|
|
263
|
+
timeout: 60000,
|
|
264
|
+
});
|
|
265
|
+
} else if (meta.installType === 'gh-extension') {
|
|
266
|
+
result = spawnSync('gh', ['extension', 'upgrade', 'copilot'], {
|
|
267
|
+
stdio: 'inherit',
|
|
268
|
+
timeout: 30000,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
if (result && result.status === 0) {
|
|
272
|
+
console.log(`\n Updated: ${name}`);
|
|
273
|
+
} else {
|
|
274
|
+
console.log(`\n \x1b[31mError updating ${name} (exit ${result ? result.status : '?'})\x1b[0m`);
|
|
275
|
+
}
|
|
276
|
+
} catch (err) {
|
|
277
|
+
console.log(`\n \x1b[31mError updating ${name}: ${err.message}\x1b[0m`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
// updateAgents() — interactive, exported
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
async function updateAgents() {
|
|
286
|
+
const cliList = buildCliList();
|
|
287
|
+
|
|
288
|
+
if (cliList.length === 0) {
|
|
289
|
+
console.log('\n No known agent CLIs found in providers.json.\n');
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Detect versions sequentially for display (consistent with user-visible flow)
|
|
294
|
+
const rows = [];
|
|
295
|
+
for (const { name, meta } of cliList) {
|
|
296
|
+
let current = null;
|
|
297
|
+
let latest = null;
|
|
298
|
+
let status = 'unknown';
|
|
299
|
+
try {
|
|
300
|
+
current = await detectCurrent(meta);
|
|
301
|
+
latest = await detectLatest(meta);
|
|
302
|
+
status = deriveStatus(current, latest);
|
|
303
|
+
} catch (_) {
|
|
304
|
+
// keep defaults
|
|
305
|
+
}
|
|
306
|
+
rows.push({ name, meta, current, latest, status });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
printTable(rows);
|
|
310
|
+
|
|
311
|
+
const outdated = rows.filter((r) => r.status === 'update-available');
|
|
312
|
+
|
|
313
|
+
if (outdated.length === 0) {
|
|
314
|
+
console.log(' All agents are up to date.\n');
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const { action } = await inquirer.prompt([
|
|
319
|
+
{
|
|
320
|
+
type: 'list',
|
|
321
|
+
name: 'action',
|
|
322
|
+
message: 'Update options:',
|
|
323
|
+
choices: [
|
|
324
|
+
{ name: 'Update all outdated', value: 'all' },
|
|
325
|
+
{ name: 'Select individual agents', value: 'select' },
|
|
326
|
+
{ name: 'Skip', value: 'skip' },
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
]);
|
|
330
|
+
|
|
331
|
+
if (action === 'skip') {
|
|
332
|
+
console.log('\n Skipped.\n');
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
let toUpdate = outdated;
|
|
337
|
+
|
|
338
|
+
if (action === 'select') {
|
|
339
|
+
const { chosen } = await inquirer.prompt([
|
|
340
|
+
{
|
|
341
|
+
type: 'checkbox',
|
|
342
|
+
name: 'chosen',
|
|
343
|
+
message: 'Select agents to update:',
|
|
344
|
+
choices: outdated.map((r) => ({
|
|
345
|
+
name: `${r.name} (${r.current || '?'} -> ${r.latest || '?'})`,
|
|
346
|
+
value: r.name,
|
|
347
|
+
})),
|
|
348
|
+
},
|
|
349
|
+
]);
|
|
350
|
+
toUpdate = outdated.filter((r) => chosen.includes(r.name));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (toUpdate.length === 0) {
|
|
354
|
+
console.log('\n Nothing selected.\n');
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
for (const row of toUpdate) {
|
|
359
|
+
runUpdate(row);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
console.log('');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ---------------------------------------------------------------------------
|
|
366
|
+
// Exports
|
|
367
|
+
// ---------------------------------------------------------------------------
|
|
368
|
+
|
|
369
|
+
module.exports = { updateAgents, getUpdateStatuses };
|