@eltonssouza/development-utility-kit 1.0.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/.claude/agents/analyst.md +198 -0
- package/.claude/agents/backend-developer.md +126 -0
- package/.claude/agents/brain-keeper.md +229 -0
- package/.claude/agents/code-reviewer.md +181 -0
- package/.claude/agents/database-engineer.md +94 -0
- package/.claude/agents/devops-engineer.md +141 -0
- package/.claude/agents/frontend-developer.md +97 -0
- package/.claude/agents/gate-keeper.md +118 -0
- package/.claude/agents/migrator.md +291 -0
- package/.claude/agents/mobile-developer.md +80 -0
- package/.claude/agents/n8n-specialist.md +94 -0
- package/.claude/agents/product-owner.md +115 -0
- package/.claude/agents/qa-engineer.md +232 -0
- package/.claude/agents/release-engineer.md +204 -0
- package/.claude/agents/scaffold.md +87 -0
- package/.claude/agents/security-engineer.md +199 -0
- package/.claude/agents/sprint-runner.md +44 -0
- package/.claude/agents/stack-resolver.md +84 -0
- package/.claude/agents/tech-lead.md +182 -0
- package/.claude/agents/update-template.md +54 -0
- package/.claude/agents/ux-designer.md +118 -0
- package/.claude/settings.json +44 -0
- package/.claude/skills/README.md +332 -0
- package/.claude/skills/active-project/SKILL.md +129 -0
- package/.claude/skills/api-integration-test/SKILL.md +64 -0
- package/.claude/skills/auto-test-guard/SKILL.md +237 -0
- package/.claude/skills/auto-test-guard/resources/backend-tests.md +20 -0
- package/.claude/skills/auto-test-guard/resources/e2e-tests.md +24 -0
- package/.claude/skills/auto-test-guard/resources/execution-report.md +49 -0
- package/.claude/skills/auto-test-guard/resources/frontend-tests.md +18 -0
- package/.claude/skills/auto-test-guard/resources/initial-setup.md +108 -0
- package/.claude/skills/auto-test-guard/resources/run-suite.md +48 -0
- package/.claude/skills/auto-test-guard/resources/senior-gate.md +19 -0
- package/.claude/skills/brain-keeper/SKILL.md +60 -0
- package/.claude/skills/brain-keeper/obsidian/app.json +9 -0
- package/.claude/skills/brain-keeper/obsidian/appearance.json +4 -0
- package/.claude/skills/brain-keeper/obsidian/core-plugins.json +20 -0
- package/.claude/skills/brain-keeper/obsidian/daily-notes.json +5 -0
- package/.claude/skills/brain-keeper/obsidian/graph.json +32 -0
- package/.claude/skills/brain-keeper/obsidian/snippets/folder-colors.css +90 -0
- package/.claude/skills/brain-keeper/obsidian/templates.json +5 -0
- package/.claude/skills/brain-keeper/templates/README.md +51 -0
- package/.claude/skills/brain-keeper/templates/adr.md +40 -0
- package/.claude/skills/brain-keeper/templates/bug.md +35 -0
- package/.claude/skills/brain-keeper/templates/daily.md +38 -0
- package/.claude/skills/brain-keeper/templates/feature.md +62 -0
- package/.claude/skills/brain-keeper/templates/meeting.md +34 -0
- package/.claude/skills/brain-keeper/templates/tech-debt.md +21 -0
- package/.claude/skills/caveman/SKILL.md +187 -0
- package/.claude/skills/create-stack-pack/SKILL.md +281 -0
- package/.claude/skills/grill-me/SKILL.md +79 -0
- package/.claude/skills/honcho-memory/SKILL.md +207 -0
- package/.claude/skills/honcho-memory/docs/api-endpoints-verified.md +75 -0
- package/.claude/skills/honcho-memory/hooks/on-prompt-submit.js +221 -0
- package/.claude/skills/honcho-memory/hooks/on-stop.js +193 -0
- package/.claude/skills/honcho-memory/lib/honcho-client.js +363 -0
- package/.claude/skills/honcho-memory/lib/memory-injector.js +93 -0
- package/.claude/skills/honcho-memory/package.json +32 -0
- package/.claude/skills/honcho-memory/scripts/cli.js +370 -0
- package/.claude/skills/honcho-memory/scripts/setup.js +109 -0
- package/.claude/skills/honcho-memory/tests/t001-api-endpoints-verified.test.js +89 -0
- package/.claude/skills/honcho-memory/tests/t002-structure.test.js +97 -0
- package/.claude/skills/honcho-memory/tests/t003-honcho-client.test.js +162 -0
- package/.claude/skills/honcho-memory/tests/t004-soft-delete.test.js +259 -0
- package/.claude/skills/honcho-memory/tests/t005-memory-injector.test.js +175 -0
- package/.claude/skills/honcho-memory/tests/t006-on-prompt-submit.test.js +215 -0
- package/.claude/skills/honcho-memory/tests/t007-on-stop.test.js +165 -0
- package/.claude/skills/honcho-memory/tests/t008-cli.test.js +214 -0
- package/.claude/skills/honcho-memory/tests/t009-setup.test.js +232 -0
- package/.claude/skills/honcho-memory/tests/t010-skill-md.test.js +114 -0
- package/.claude/skills/honcho-memory/tests/t011-settings-hooks.test.js +105 -0
- package/.claude/skills/honcho-memory/tests/t012-docs-update.test.js +106 -0
- package/.claude/skills/honcho-memory/tests/t013-smoke-e2e.test.js +90 -0
- package/.claude/skills/pair-debug/SKILL.md +288 -0
- package/.claude/skills/prd-ready-check/SKILL.md +58 -0
- package/.claude/skills/project-manager/SKILL.md +167 -0
- package/.claude/skills/quality-standards/SKILL.md +201 -0
- package/.claude/skills/quick-feature/SKILL.md +264 -0
- package/.claude/skills/run-sprint/SKILL.md +342 -0
- package/.claude/skills/scaffold/SKILL.md +58 -0
- package/.claude/skills/stack-discovery/SKILL.md +159 -0
- package/.claude/skills/test-coverage-auditor/SKILL.md +59 -0
- package/.claude/skills/to-issues/SKILL.md +163 -0
- package/.claude/skills/to-prd/SKILL.md +130 -0
- package/.claude/skills/update-template/SKILL.md +254 -0
- package/.claude/stacks/CODEOWNERS +30 -0
- package/.claude/stacks/README.md +88 -0
- package/.claude/stacks/_template.md +116 -0
- package/.claude/stacks/java/spring-boot-3.md +376 -0
- package/.claude/stacks/java/spring-boot-4.md +438 -0
- package/.claude/stacks/typescript/angular-18.md +420 -0
- package/.claude/stacks/typescript/angular-19.md +397 -0
- package/.claude/stacks/typescript/angular-21.md +494 -0
- package/CLAUDE.md +453 -0
- package/README.md +391 -0
- package/bin/cli.js +773 -0
- package/bin/lib/backup.js +62 -0
- package/bin/lib/detect-stack.js +476 -0
- package/bin/lib/help.js +233 -0
- package/bin/lib/identity.js +108 -0
- package/bin/lib/local-dir.js +69 -0
- package/bin/lib/manifest.js +236 -0
- package/bin/lib/sync-all.js +394 -0
- package/bin/lib/version-check.js +398 -0
- package/dashboard/db.js +199 -0
- package/dashboard/package.json +22 -0
- package/dashboard/public/app.js +709 -0
- package/dashboard/public/content/docs/agents-reference.en.md +911 -0
- package/dashboard/public/content/docs/architecture-overview.en.md +260 -0
- package/dashboard/public/content/docs/autonomy-matrix.en.md +186 -0
- package/dashboard/public/content/docs/git-flow.en.md +525 -0
- package/dashboard/public/content/docs/honcho-memory.en.md +394 -0
- package/dashboard/public/content/docs/hooks-reference.en.md +420 -0
- package/dashboard/public/content/docs/pipeline.en.md +400 -0
- package/dashboard/public/content/docs/quality-gate.en.md +315 -0
- package/dashboard/public/content/docs/skills-reference.en.md +500 -0
- package/dashboard/public/content/docs/stack-rules.en.md +362 -0
- package/dashboard/public/content/docs/troubleshooting.en.md +637 -0
- package/dashboard/public/content/manifest.json +102 -0
- package/dashboard/public/content/manual/backend.en.md +1138 -0
- package/dashboard/public/content/manual/existing-project.en.md +831 -0
- package/dashboard/public/content/manual/frontend.en.md +1065 -0
- package/dashboard/public/content/manual/fullstack.en.md +1508 -0
- package/dashboard/public/content/manual/mobile.en.md +866 -0
- package/dashboard/public/index.html +108 -0
- package/dashboard/public/style.css +610 -0
- package/dashboard/public/vendor/marked.min.js +69 -0
- package/dashboard/rtk.js +143 -0
- package/dashboard/server-app.js +403 -0
- package/dashboard/server.js +104 -0
- package/dashboard/test/sprint1.test.js +406 -0
- package/dashboard/test/sprint2.test.js +571 -0
- package/dashboard/test/sprint3.test.js +560 -0
- package/package.json +33 -0
- package/scripts/hooks/subagent-telemetry.sh +14 -0
- package/scripts/hooks/telemetry-writer.js +250 -0
- package/scripts/latest-versions.json +56 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* telemetry-writer.js
|
|
6
|
+
* Reads a SubagentStop JSON payload from stdin, normalises the model name,
|
|
7
|
+
* and persists the event to ~/.claude/telemetry.db via better-sqlite3.
|
|
8
|
+
* Falls back to sql.js, then to NDJSON queue if native bindings are absent.
|
|
9
|
+
* Never throws an uncaught exception — all errors are silently logged.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
const CLAUDE_DIR = path.join(os.homedir(), '.claude');
|
|
17
|
+
const DB_PATH = path.join(CLAUDE_DIR, 'telemetry.db');
|
|
18
|
+
const QUEUE_PATH = path.join(CLAUDE_DIR, 'telemetry-queue.ndjson');
|
|
19
|
+
const ERROR_LOG = path.join(CLAUDE_DIR, 'telemetry-errors.log');
|
|
20
|
+
|
|
21
|
+
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
function logError(msg, err) {
|
|
24
|
+
try {
|
|
25
|
+
const line = `${new Date().toISOString()} ${msg}${err ? ': ' + err.message : ''}\n`;
|
|
26
|
+
fs.appendFileSync(ERROR_LOG, line);
|
|
27
|
+
} catch (_) {
|
|
28
|
+
// last-resort: swallow
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function normaliseModel(raw) {
|
|
33
|
+
if (!raw || typeof raw !== 'string') return 'other';
|
|
34
|
+
const lower = raw.toLowerCase();
|
|
35
|
+
if (lower.includes('opus')) return 'opus';
|
|
36
|
+
if (lower.includes('sonnet')) return 'sonnet';
|
|
37
|
+
if (lower.includes('haiku')) return 'haiku';
|
|
38
|
+
return 'other';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const CREATE_TABLE = `
|
|
42
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
43
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
44
|
+
project_path TEXT NOT NULL,
|
|
45
|
+
project_name TEXT NOT NULL,
|
|
46
|
+
model TEXT NOT NULL,
|
|
47
|
+
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
48
|
+
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
49
|
+
subagent_type TEXT,
|
|
50
|
+
session_id TEXT,
|
|
51
|
+
agent_id TEXT,
|
|
52
|
+
agent_type TEXT,
|
|
53
|
+
ts INTEGER NOT NULL
|
|
54
|
+
)
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const CREATE_IDX_TS = 'CREATE INDEX IF NOT EXISTS idx_events_ts ON events(ts)';
|
|
58
|
+
const CREATE_IDX_PROJECT = 'CREATE INDEX IF NOT EXISTS idx_events_project ON events(project_path)';
|
|
59
|
+
const CREATE_IDX_SESSION = 'CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id)';
|
|
60
|
+
|
|
61
|
+
// Idempotent migrations for DBs created by previous writer versions.
|
|
62
|
+
const ALTER_STATEMENTS = [
|
|
63
|
+
'ALTER TABLE events ADD COLUMN session_id TEXT',
|
|
64
|
+
'ALTER TABLE events ADD COLUMN agent_id TEXT',
|
|
65
|
+
'ALTER TABLE events ADD COLUMN agent_type TEXT',
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const INSERT_SQL = `
|
|
69
|
+
INSERT INTO events
|
|
70
|
+
(project_path, project_name, model, input_tokens, output_tokens,
|
|
71
|
+
subagent_type, session_id, agent_id, agent_type, ts)
|
|
72
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
// ── SQLite backends ───────────────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Attempt to open DB via better-sqlite3 (native, synchronous).
|
|
79
|
+
* Returns a { run(sql, params) } adapter or throws.
|
|
80
|
+
*/
|
|
81
|
+
function tryBetterSqlite3(event) {
|
|
82
|
+
// Look for better-sqlite3 relative to the dashboard/ directory first
|
|
83
|
+
// (Sprint 2 will install it there), then fall back to standard resolution.
|
|
84
|
+
const candidates = [
|
|
85
|
+
path.join(__dirname, '..', '..', 'dashboard', 'node_modules', 'better-sqlite3'),
|
|
86
|
+
'better-sqlite3',
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
let Database;
|
|
90
|
+
for (const candidate of candidates) {
|
|
91
|
+
try {
|
|
92
|
+
Database = require(candidate);
|
|
93
|
+
break;
|
|
94
|
+
} catch (_) {
|
|
95
|
+
// try next
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!Database) throw new Error('better-sqlite3 not available');
|
|
100
|
+
|
|
101
|
+
fs.mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
102
|
+
const db = new Database(DB_PATH);
|
|
103
|
+
db.exec(CREATE_TABLE);
|
|
104
|
+
db.exec(CREATE_IDX_TS);
|
|
105
|
+
db.exec(CREATE_IDX_PROJECT);
|
|
106
|
+
db.exec(CREATE_IDX_SESSION);
|
|
107
|
+
for (const stmt of ALTER_STATEMENTS) {
|
|
108
|
+
try { db.exec(stmt); } catch (_) { /* column already exists */ }
|
|
109
|
+
}
|
|
110
|
+
db.prepare(INSERT_SQL).run(
|
|
111
|
+
event.project_path,
|
|
112
|
+
event.project_name,
|
|
113
|
+
event.model,
|
|
114
|
+
event.input_tokens,
|
|
115
|
+
event.output_tokens,
|
|
116
|
+
event.subagent_type,
|
|
117
|
+
event.session_id,
|
|
118
|
+
event.agent_id,
|
|
119
|
+
event.agent_type,
|
|
120
|
+
event.ts
|
|
121
|
+
);
|
|
122
|
+
db.close();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Attempt to open DB via sql.js (pure-JS, WASM).
|
|
127
|
+
* Returns after persisting or throws.
|
|
128
|
+
*/
|
|
129
|
+
function trySqlJs(event) {
|
|
130
|
+
const initSqlJs = require('sql.js');
|
|
131
|
+
|
|
132
|
+
fs.mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
133
|
+
|
|
134
|
+
// Load existing DB bytes if available
|
|
135
|
+
let fileBuffer = null;
|
|
136
|
+
if (fs.existsSync(DB_PATH)) {
|
|
137
|
+
fileBuffer = fs.readFileSync(DB_PATH);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// initSqlJs returns a Promise
|
|
141
|
+
return initSqlJs().then((SQL) => {
|
|
142
|
+
const db = fileBuffer ? new SQL.Database(fileBuffer) : new SQL.Database();
|
|
143
|
+
db.run(CREATE_TABLE);
|
|
144
|
+
db.run(CREATE_IDX_TS);
|
|
145
|
+
db.run(CREATE_IDX_PROJECT);
|
|
146
|
+
db.run(CREATE_IDX_SESSION);
|
|
147
|
+
for (const stmt of ALTER_STATEMENTS) {
|
|
148
|
+
try { db.run(stmt); } catch (_) { /* column already exists */ }
|
|
149
|
+
}
|
|
150
|
+
db.run(INSERT_SQL, [
|
|
151
|
+
event.project_path,
|
|
152
|
+
event.project_name,
|
|
153
|
+
event.model,
|
|
154
|
+
event.input_tokens,
|
|
155
|
+
event.output_tokens,
|
|
156
|
+
event.subagent_type,
|
|
157
|
+
event.session_id,
|
|
158
|
+
event.agent_id,
|
|
159
|
+
event.agent_type,
|
|
160
|
+
event.ts,
|
|
161
|
+
]);
|
|
162
|
+
const data = db.export();
|
|
163
|
+
fs.writeFileSync(DB_PATH, Buffer.from(data));
|
|
164
|
+
db.close();
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Last-resort fallback: append event as NDJSON line.
|
|
170
|
+
*/
|
|
171
|
+
function appendNdjson(event) {
|
|
172
|
+
fs.mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
173
|
+
const line = JSON.stringify(event) + '\n';
|
|
174
|
+
fs.appendFileSync(QUEUE_PATH, line);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── main ─────────────────────────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
async function main() {
|
|
180
|
+
// Read all stdin
|
|
181
|
+
let raw = '';
|
|
182
|
+
try {
|
|
183
|
+
await new Promise((resolve, reject) => {
|
|
184
|
+
process.stdin.setEncoding('utf8');
|
|
185
|
+
process.stdin.on('data', (chunk) => { raw += chunk; });
|
|
186
|
+
process.stdin.on('end', resolve);
|
|
187
|
+
process.stdin.on('error', reject);
|
|
188
|
+
});
|
|
189
|
+
} catch (err) {
|
|
190
|
+
logError('stdin read error', err);
|
|
191
|
+
process.exit(0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Parse JSON — tolerate empty / invalid stdin gracefully
|
|
195
|
+
let payload = {};
|
|
196
|
+
try {
|
|
197
|
+
if (raw.trim()) {
|
|
198
|
+
payload = JSON.parse(raw.trim());
|
|
199
|
+
}
|
|
200
|
+
} catch (err) {
|
|
201
|
+
logError('stdin JSON parse error', err);
|
|
202
|
+
// Continue with empty payload — we still record the event with defaults
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Build event record.
|
|
206
|
+
// Prefer `cwd` from the payload (Claude Code injects it for every hook event);
|
|
207
|
+
// fall back to CLAUDE_PROJECT_DIR for environments that still set it.
|
|
208
|
+
const projectPath = payload.cwd || process.env.CLAUDE_PROJECT_DIR || 'unknown';
|
|
209
|
+
const segments = projectPath.split(/[\\/]/);
|
|
210
|
+
const projectName = segments[segments.length - 1] || 'unknown';
|
|
211
|
+
|
|
212
|
+
const usage = payload.usage || {};
|
|
213
|
+
const event = {
|
|
214
|
+
project_path: projectPath,
|
|
215
|
+
project_name: projectName,
|
|
216
|
+
model: normaliseModel(payload.model),
|
|
217
|
+
input_tokens: parseInt(usage.input_tokens, 10) || 0,
|
|
218
|
+
output_tokens: parseInt(usage.output_tokens, 10) || 0,
|
|
219
|
+
subagent_type: payload.agent_type || payload.type || null,
|
|
220
|
+
session_id: payload.session_id || null,
|
|
221
|
+
agent_id: payload.agent_id || null,
|
|
222
|
+
agent_type: payload.agent_type || null,
|
|
223
|
+
ts: (Date.now() / 1000) | 0,
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// Persistence — try each backend in order
|
|
227
|
+
try {
|
|
228
|
+
tryBetterSqlite3(event);
|
|
229
|
+
process.exit(0);
|
|
230
|
+
} catch (e1) {
|
|
231
|
+
logError('better-sqlite3 failed, trying sql.js', e1);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
await trySqlJs(event);
|
|
236
|
+
process.exit(0);
|
|
237
|
+
} catch (e2) {
|
|
238
|
+
logError('sql.js failed, falling back to NDJSON', e2);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
appendNdjson(event);
|
|
243
|
+
} catch (e3) {
|
|
244
|
+
logError('NDJSON append failed', e3);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
process.exit(0);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
main();
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_updated": "2026-05-27",
|
|
3
|
+
"_source": "manually curated; refresh via `duk install --refresh-versions` (future) or edit here",
|
|
4
|
+
"java": {
|
|
5
|
+
"latest_lts": "25",
|
|
6
|
+
"latest": "26"
|
|
7
|
+
},
|
|
8
|
+
"spring-boot": {
|
|
9
|
+
"latest": "4.0.0",
|
|
10
|
+
"latest_3x": "3.4.0"
|
|
11
|
+
},
|
|
12
|
+
"angular": {
|
|
13
|
+
"latest": "21.1.0"
|
|
14
|
+
},
|
|
15
|
+
"node": {
|
|
16
|
+
"latest_lts": "22",
|
|
17
|
+
"latest": "24"
|
|
18
|
+
},
|
|
19
|
+
"react": {
|
|
20
|
+
"latest": "19.0.0"
|
|
21
|
+
},
|
|
22
|
+
"react-native": {
|
|
23
|
+
"latest": "0.84.0"
|
|
24
|
+
},
|
|
25
|
+
"expo": {
|
|
26
|
+
"latest": "54.0.0"
|
|
27
|
+
},
|
|
28
|
+
"python": {
|
|
29
|
+
"latest_stable": "3.13",
|
|
30
|
+
"latest": "3.14"
|
|
31
|
+
},
|
|
32
|
+
"django": {
|
|
33
|
+
"latest": "5.1.0"
|
|
34
|
+
},
|
|
35
|
+
"fastapi": {
|
|
36
|
+
"latest": "0.115.0"
|
|
37
|
+
},
|
|
38
|
+
"go": {
|
|
39
|
+
"latest": "1.23.0"
|
|
40
|
+
},
|
|
41
|
+
"gin": {
|
|
42
|
+
"latest": "1.10.0"
|
|
43
|
+
},
|
|
44
|
+
"echo": {
|
|
45
|
+
"latest": "4.13.0"
|
|
46
|
+
},
|
|
47
|
+
"postgres": {
|
|
48
|
+
"latest_stable": "17"
|
|
49
|
+
},
|
|
50
|
+
"redis": {
|
|
51
|
+
"latest_stable": "7"
|
|
52
|
+
},
|
|
53
|
+
"mongodb": {
|
|
54
|
+
"latest_stable": "8"
|
|
55
|
+
}
|
|
56
|
+
}
|