@digital-lake/lognexus 1.0.0 → 1.2.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/README.md +101 -7
- package/dist/audit/audit.d.ts +17 -1
- package/dist/audit/audit.d.ts.map +1 -1
- package/dist/audit/audit.js +55 -15
- package/dist/audit/audit.js.map +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +160 -2
- package/dist/cli.js.map +1 -1
- package/dist/commit.d.ts +27 -0
- package/dist/commit.d.ts.map +1 -0
- package/dist/commit.js +211 -0
- package/dist/commit.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +125 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/notes/attach.d.ts +1 -0
- package/dist/notes/attach.d.ts.map +1 -1
- package/dist/notes/attach.js +29 -2
- package/dist/notes/attach.js.map +1 -1
- package/dist/notes/notes.d.ts +1 -0
- package/dist/notes/notes.d.ts.map +1 -1
- package/dist/notes/notes.js.map +1 -1
- package/dist/scaffold.d.ts +1 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +4 -4
- package/dist/state/manager.d.ts.map +1 -1
- package/dist/state/manager.js +11 -1
- package/dist/state/manager.js.map +1 -1
- package/dist/telemetry/collector.d.ts +31 -0
- package/dist/telemetry/collector.d.ts.map +1 -0
- package/dist/telemetry/collector.js +257 -0
- package/dist/telemetry/collector.js.map +1 -0
- package/dist/telemetry/detector.d.ts +15 -0
- package/dist/telemetry/detector.d.ts.map +1 -0
- package/dist/telemetry/detector.js +120 -0
- package/dist/telemetry/detector.js.map +1 -0
- package/dist/telemetry/index.d.ts +5 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +5 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/report.d.ts +7 -0
- package/dist/telemetry/report.d.ts.map +1 -0
- package/dist/telemetry/report.js +98 -0
- package/dist/telemetry/report.js.map +1 -0
- package/dist/telemetry/schema.d.ts +140 -0
- package/dist/telemetry/schema.d.ts.map +1 -0
- package/dist/telemetry/schema.js +78 -0
- package/dist/telemetry/schema.js.map +1 -0
- package/dist/timeline/timeline.d.ts.map +1 -1
- package/dist/timeline/timeline.js +8 -3
- package/dist/timeline/timeline.js.map +1 -1
- package/package.json +16 -5
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<a href="https://www.npmjs.com/package/@digital-lake/lognexus"><img src="https://img.shields.io/npm/v/@digital-lake/lognexus.svg?color=blue" alt="npm version"></a>
|
|
14
14
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
|
|
15
15
|
<a href="https://github.com/digital-lake-ai/lognexus"><img src="https://img.shields.io/badge/org-Digital%20Lake-indigo.svg" alt="Digital Lake"></a>
|
|
16
|
+
<a href="https://ko-fi.com/digitallake"><img src="https://img.shields.io/badge/Ko--fi-Fuel_the_AI-ff5e5b?logo=ko-fi&logoColor=white" alt="Ko-fi - Fuel the AI"></a>
|
|
16
17
|
</p>
|
|
17
18
|
|
|
18
19
|
---
|
|
@@ -37,11 +38,12 @@ Issues (Why & Goals) ──▶ Branches (Task Scopes) ──▶ Commits (Context
|
|
|
37
38
|
|
|
38
39
|
## Key Features
|
|
39
40
|
|
|
40
|
-
- **Universal Multi-Model Support:** Native cognitive guidelines and prompt specifications for **Anthropic Claude**, **OpenAI**, **Google Gemini**, and **
|
|
41
|
+
- **Universal Multi-Model Support:** Native cognitive guidelines and prompt specifications for **Anthropic Claude**, **OpenAI**, **Google Gemini**, **DeepSeek**, and **Kimi K2.7 Code**.
|
|
41
42
|
- **Universal Client Compatibility:** Drop-in support for **Claude Code**, **Cursor**, **Codex**, **Google Antigravity**, and **Kimi Code / VS Code**.
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
44
|
-
- **
|
|
43
|
+
- **Atomic Commit Engine (`lognexus commit` & MCP `lognexus_commit`):** Validates subtask file contracts, verifies reviewer separation, injects authorship trailers, commits changes, marks subtasks completed, and attaches Git Notes in a single ~0.15s execution.
|
|
44
|
+
- **Cross-Model Review Gates:** Non-negotiable review separation (`Authored-by:` vs `Reviewed-by:`) enforced both at pre-flight note attachment time and during branch audits. No model merges its own code without independent verification from another model family.
|
|
45
|
+
- **Contract-First Subtasks & Alphanumeric Tickets:** Tasks are bounded by strict decision budgets, file allowlists, and stop conditions—supporting both GitHub issues (`feat(#42/T1)`) and Jira/Linear ticket schemes (`feat(SLM-201/T1)`).
|
|
46
|
+
- **Persistent State & Session Recovery:** Local session state engine (`.lognexus/state.json`) prevents amnesia across context compactations and conversation resets, retaining completed subtask metadata through the closing commit.
|
|
45
47
|
- **Git Notes Engine (Quiet Mode / `git-ai` v3):** Attaches structured session payloads and contracts to commits under `refs/notes/lognexus` without changing commit SHAs.
|
|
46
48
|
- **Native MCP Stdio Server (`lognexus mcp`):** Zero-dependency JSON-RPC 2.0 stdio server exposing LogNexus tools, live state resources, and prompts to Claude Desktop, Cursor, and any MCP client.
|
|
47
49
|
- **Journey Timeline & Review Gate Audit:** Reconstructs the complete branch journey into structured PR descriptions (`lognexus timeline --pr-body`) and programmatically audits review gate separation (`lognexus audit`).
|
|
@@ -146,6 +148,17 @@ npx @digital-lake/lognexus state set-task T1 "Add user schema"
|
|
|
146
148
|
npx @digital-lake/lognexus state finish-task T1
|
|
147
149
|
```
|
|
148
150
|
|
|
151
|
+
Execute an **Atomic Commit** (validates subtask contract, enforces review-gate separation, injects trailers, commits, marks subtask completed, and attaches Git Note in a single ~0.15s call):
|
|
152
|
+
```bash
|
|
153
|
+
npx @digital-lake/lognexus commit -m "feat(#42/T1): add user schema" \
|
|
154
|
+
--author "gemini/flash (antigravity)" \
|
|
155
|
+
--reviewer "gemini/pro (lead-architect)" \
|
|
156
|
+
--finish-task
|
|
157
|
+
|
|
158
|
+
# Or read message from file (safe against Windows shell quote-stripping):
|
|
159
|
+
npx @digital-lake/lognexus commit -F commit-msg.txt --finish-task
|
|
160
|
+
```
|
|
161
|
+
|
|
149
162
|
Quiet Mode with Git Notes (`refs/notes/lognexus`, standard `git-ai` v3):
|
|
150
163
|
```bash
|
|
151
164
|
npx @digital-lake/lognexus note attach HEAD
|
|
@@ -160,6 +173,28 @@ npx @digital-lake/lognexus timeline main --pr-body
|
|
|
160
173
|
npx @digital-lake/lognexus audit main
|
|
161
174
|
```
|
|
162
175
|
|
|
176
|
+
Opt-in Telemetry, Stack Profiling & ROI Cost-Savings Engine:
|
|
177
|
+
```bash
|
|
178
|
+
# Check telemetry status (disabled by default, 0% overhead)
|
|
179
|
+
npx @digital-lake/lognexus telemetry status
|
|
180
|
+
|
|
181
|
+
# Enable local telemetry (stores metrics only in .lognexus/telemetry.json)
|
|
182
|
+
npx @digital-lake/lognexus telemetry enable
|
|
183
|
+
|
|
184
|
+
# Or enable anonymous community telemetry (explicit GDPR opt-in)
|
|
185
|
+
npx @digital-lake/lognexus telemetry enable --share --accept-terms
|
|
186
|
+
|
|
187
|
+
# Generate .lognexus/telemetry.md report with ROI metrics
|
|
188
|
+
npx @digital-lake/lognexus telemetry report
|
|
189
|
+
|
|
190
|
+
# Inspect the exact Zero-PII payload before sending
|
|
191
|
+
npx @digital-lake/lognexus telemetry inspect
|
|
192
|
+
|
|
193
|
+
# Disable telemetry immediately
|
|
194
|
+
npx @digital-lake/lognexus telemetry disable
|
|
195
|
+
```
|
|
196
|
+
*Read our strict Zero-PII policy in [`docs/TELEMETRY_PRIVACY.md`](docs/TELEMETRY_PRIVACY.md).*
|
|
197
|
+
|
|
163
198
|
### 2. Connect via Model Context Protocol (MCP)
|
|
164
199
|
|
|
165
200
|
LogNexus includes a native, lightweight JSON-RPC 2.0 stdio server (`lognexus mcp`) with zero external SDK dependencies. Connect it to Claude Desktop, Cursor, Google Antigravity, or any MCP-compliant client:
|
|
@@ -176,8 +211,13 @@ LogNexus includes a native, lightweight JSON-RPC 2.0 stdio server (`lognexus mcp
|
|
|
176
211
|
}
|
|
177
212
|
```
|
|
178
213
|
|
|
214
|
+
**Or install automatically via Smithery:**
|
|
215
|
+
```bash
|
|
216
|
+
npx -y @smithery/cli install @digital-lake/lognexus --client claude
|
|
217
|
+
```
|
|
218
|
+
|
|
179
219
|
**Exposed Capabilities:**
|
|
180
|
-
- **Tools:** `lognexus_status`, `lognexus_state_get`, `lognexus_state_sync`, `lognexus_state_set_task`, `lognexus_state_finish_task`, `lognexus_state_clear`, `lognexus_note_show`, `lognexus_note_attach`, `lognexus_timeline`, `lognexus_audit`
|
|
220
|
+
- **Tools:** `lognexus_status`, `lognexus_state_get`, `lognexus_state_sync`, `lognexus_state_set_task`, `lognexus_state_finish_task`, `lognexus_state_clear`, `lognexus_commit`, `lognexus_note_show`, `lognexus_note_attach`, `lognexus_timeline`, `lognexus_audit`, `lognexus_telemetry`
|
|
181
221
|
- **Resources:** `lognexus://state`, `lognexus://routing`
|
|
182
222
|
- **Prompts:** `lognexus-plan`, `lognexus-review`
|
|
183
223
|
|
|
@@ -196,6 +236,44 @@ LogNexus includes a native, lightweight JSON-RPC 2.0 stdio server (`lognexus mcp
|
|
|
196
236
|
|
|
197
237
|
---
|
|
198
238
|
|
|
239
|
+
## ⚡ Production Telemetry & Field Benchmark
|
|
240
|
+
|
|
241
|
+
<div align="center">
|
|
242
|
+
|
|
243
|
+

|
|
244
|
+
-238636?style=for-the-badge&labelColor=0d1117)
|
|
245
|
+

|
|
246
|
+
-238636?style=for-the-badge&labelColor=0d1117)
|
|
247
|
+
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
LogNexus was battle-tested in a high-intensity production deployment governing the end-to-end engineering of **Taranis**—a deterministic static analysis CLI and AI migration skill operating over **250,000+ lines of legacy code** with 22 AST/CFG rules (`SPH-001`..`SPH-022`).
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
|
|
254
|
+
║ LOGNEXUS TELEMETRY HUD // PRODUCTION SWARM BENCHMARK (CASE STUDY: TARANIS) ║
|
|
255
|
+
╠═════════════════════════════════════════════╦════════════════════════════════════════════════╣
|
|
256
|
+
║ ▸ GOVERNED FEATURES 12 Issues (#1-#12) ║ ▸ ORPHAN / UNTRACKED COMMITS 0 (0.0%) ║
|
|
257
|
+
║ ▸ VERIFIED COMMITS 38 / 38 Signed ║ ▸ SELF-APPROVAL VIOLATIONS 0 Blocked ║
|
|
258
|
+
║ ▸ GIT NOTES ATTACHED 100% (git-ai v3) ║ ▸ SCOPE CREEP INCIDENTS 0 (Allowlist) ║
|
|
259
|
+
║ ▸ TEST SUITE INTEGRITY 536 Passed (100%) ║ ▸ ATOMIC COMMIT LATENCY ~0.15s / op ║
|
|
260
|
+
╚═════════════════════════════════════════════╩════════════════════════════════════════════════╝
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Multi-Model Swarm Performance Matrix
|
|
264
|
+
|
|
265
|
+
By enforcing **Closed Delegation Contracts** (`allowedFiles`, `forbiddenFiles`, `decisionBudget: "none"`) and **Cross-Model Review Gates**, LogNexus coordinated three distinct AI model families in production without a single context leak or rogue commit:
|
|
266
|
+
|
|
267
|
+
| Model Family | Assigned Tier | Production Strengths Observed | Optimal Contract Fit |
|
|
268
|
+
| :--- | :---: | :--- | :--- |
|
|
269
|
+
| **Google Antigravity / Gemini Pro** | `tier-1` & `tier-2`<br>*(Architect & Orchestrator)* | • Zero-drift multi-branch coordination<br>• Strict review-gate enforcement (`lognexus audit`)<br>• Rapid root-cause regression triage | Architecture synthesis, closed contract authoring, cross-model code review, release governance. |
|
|
270
|
+
| **DeepSeek V3 / R1** | `tier-3`<br>*(Scoped Implementer)* | • Ultra-low latency & token cost<br>• Exceptional at mathematical AST parsing, pushdown automata & CFG tokenization<br>• Strict adherence to stop conditions when hitting out-of-scope test assertions | Algorithmic engines, deterministic parsers, isolated single-file modules (`<500` LOC). |
|
|
271
|
+
| **Kimi K2.7 Code** | `tier-2` & `tier-3`<br>*(High-Context Implementer)* | • Massive context retention with zero file truncation on large modules (`>500` LOC)<br>• Flawless single-shot multi-file generation (rule catalogs + visitors + test suites) | Large-context refactorings, multi-file rule catalogs, CI/CD matrices & standalone packaging. |
|
|
272
|
+
|
|
273
|
+
> **Key Takeaway:** Contract-driven development paired with `refs/notes/lognexus` completely eliminated scope creep by Tier-3 implementers while keeping the public Git commit graph 100% clean and human-readable.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
199
277
|
## Disambiguation
|
|
200
278
|
|
|
201
279
|
**LogNexus** by Digital Lake is an open-source development framework and Git memory system for AI agents. It is not affiliated with academic research papers on industrial log compression (e.g. ISSTA 2026).
|
|
@@ -207,15 +285,31 @@ LogNexus includes a native, lightweight JSON-RPC 2.0 stdio server (`lognexus mcp
|
|
|
207
285
|
LogNexus is an independent hard fork and continuation of [`shiplog`](https://github.com/devallibus/shiplog), originally created by **devallibus** under the MIT License.
|
|
208
286
|
|
|
209
287
|
We extend our deep gratitude to **devallibus** for pioneering the concept of Git-as-knowledge-graph for AI development. LogNexus builds upon that foundation by:
|
|
210
|
-
- Expanding the model ecosystem to provide first-class native support for **Google Gemini** and **
|
|
288
|
+
- Expanding the model ecosystem to provide first-class native support for **Google Gemini**, **DeepSeek**, and **Kimi** alongside **Claude** and **OpenAI**.
|
|
211
289
|
- Formalizing the multi-model tier routing taxonomy and closed delegation contracts.
|
|
212
|
-
- Introducing the repository scaffolding CLI (`@digital-lake/lognexus`).
|
|
290
|
+
- Introducing the repository scaffolding CLI, Atomic Commit Engine, and native MCP server (`@digital-lake/lognexus`).
|
|
213
291
|
- Providing seamless backwards-compatibility for existing `.shiplog` envelopes and workflows.
|
|
214
292
|
|
|
215
293
|
Additional inspirations and patterns are derived from [OrchestKit](https://github.com/yonatangross/orchestkit) and [Superpowers](https://github.com/obra/superpowers). Detailed license texts are preserved in the [`LICENSES/`](LICENSES/) directory and in [`NOTICE.md`](NOTICE.md).
|
|
216
294
|
|
|
217
295
|
---
|
|
218
296
|
|
|
297
|
+
<div align="center">
|
|
298
|
+
|
|
299
|
+
### Did you find this project useful? 🤖⚡
|
|
300
|
+
|
|
301
|
+
Maintaining and evolving open-source agentic infrastructure takes time, dedication, and... quite a few **AI tokens** to power multi-model benchmarking, automated testing, and continuous architecture updates.
|
|
302
|
+
|
|
303
|
+
If **LogNexus** saved you time, prevented context amnesia in your workflows, and you'd like to help cover the API and compute costs to keep it evolving, consider fueling the AI with a token:
|
|
304
|
+
|
|
305
|
+
[](https://ko-fi.com/digitallake)
|
|
306
|
+
|
|
307
|
+
*Every contribution goes straight into compute power, multi-model benchmarks, new MCP capabilities, and continuous improvements!*
|
|
308
|
+
|
|
309
|
+
</div>
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
219
313
|
## License
|
|
220
314
|
|
|
221
315
|
LogNexus is released under the [MIT License](LICENSE).
|
package/dist/audit/audit.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface AuditViolation {
|
|
2
2
|
commitSha: string;
|
|
3
3
|
shortSha: string;
|
|
4
|
-
rule: "commit-format" | "authored-by-trailer" | "git-note-presence" | "contract-files" | "review-gate-separation";
|
|
4
|
+
rule: "commit-format" | "authored-by-trailer" | "git-note-presence" | "contract-files" | "review-gate-separation" | "base-branch-range";
|
|
5
5
|
message: string;
|
|
6
6
|
severity: "error" | "warn";
|
|
7
7
|
}
|
|
@@ -14,6 +14,22 @@ export interface AuditResult {
|
|
|
14
14
|
warnings: number;
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
+
export declare const TICKET_PATTERN_SOURCE = "(?:#\\d+|[A-Z][A-Z0-9]*-\\d+)";
|
|
18
|
+
export declare const COMMIT_FORMAT_PATTERN: RegExp;
|
|
19
|
+
export declare const SUBJECT_TASK_PATTERN: RegExp;
|
|
20
|
+
export interface Identity {
|
|
21
|
+
full: string;
|
|
22
|
+
family: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function parseIdentity(value: string | null): Identity | null;
|
|
25
|
+
export declare function extractTrailers(commitBody: string): {
|
|
26
|
+
author: string | null;
|
|
27
|
+
reviewer: string | null;
|
|
28
|
+
};
|
|
29
|
+
export declare function checkSelfApproval(authorStr: string | null, reviewerStr: string | null): {
|
|
30
|
+
isSelfApproval: boolean;
|
|
31
|
+
message?: string;
|
|
32
|
+
};
|
|
17
33
|
export declare function auditBranch(baseBranch?: string, targetDir?: string): AuditResult;
|
|
18
34
|
export declare function formatAuditResult(result: AuditResult): string;
|
|
19
35
|
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/audit/audit.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EACA,eAAe,GACf,qBAAqB,GACrB,mBAAmB,GACnB,gBAAgB,GAChB,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/audit/audit.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EACA,eAAe,GACf,qBAAqB,GACrB,mBAAmB,GACnB,gBAAgB,GAChB,wBAAwB,GACxB,mBAAmB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAGD,eAAO,MAAM,qBAAqB,kCAAkC,CAAC;AACrE,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,oBAAoB,QAGhC,CAAC;AAaF,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,CAUnE;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG;IACnD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAiBA;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAc/C;AA4ID,wBAAgB,WAAW,CACzB,UAAU,GAAE,MAAe,EAC3B,SAAS,GAAE,MAAsB,GAChC,WAAW,CAyBb;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAW7D"}
|
package/dist/audit/audit.js
CHANGED
|
@@ -2,10 +2,12 @@ import { execSync } from "node:child_process";
|
|
|
2
2
|
import { getNote } from "../notes/notes.js";
|
|
3
3
|
import { getJourneyTimeline } from "../timeline/timeline.js";
|
|
4
4
|
const VALID_TYPES = "feat, fix, docs, refactor, test, chore, style, perf";
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
export const TICKET_PATTERN_SOURCE = "(?:#\\d+|[A-Z][A-Z0-9]*-\\d+)";
|
|
6
|
+
export const COMMIT_FORMAT_PATTERN = new RegExp(`^(feat|fix|docs|refactor|test|chore|style|perf)\\(${TICKET_PATTERN_SOURCE}(\\/T\\d+(?:-T?\\d+)?)?\\): \\S+`);
|
|
7
|
+
export const SUBJECT_TASK_PATTERN = new RegExp(`\\(${TICKET_PATTERN_SOURCE}\\/(T\\d+(?:-T?\\d+)?)\\)`, "i");
|
|
7
8
|
const IDENTITY_PATTERN = /(\S+\/\S+)/;
|
|
8
|
-
|
|
9
|
+
const TRAILER_PATTERN = /^\s*(Authored-by|Reviewed-by|Last-code-by|Updated-by):\s*(.+)$/gim;
|
|
10
|
+
export function parseIdentity(value) {
|
|
9
11
|
if (value === null)
|
|
10
12
|
return null;
|
|
11
13
|
const match = value.match(IDENTITY_PATTERN);
|
|
@@ -15,6 +17,36 @@ function parseIdentity(value) {
|
|
|
15
17
|
}
|
|
16
18
|
return { full: value.trim().toLowerCase(), family: match[1].toLowerCase() };
|
|
17
19
|
}
|
|
20
|
+
export function extractTrailers(commitBody) {
|
|
21
|
+
let author = null;
|
|
22
|
+
let reviewer = null;
|
|
23
|
+
for (const match of commitBody.matchAll(TRAILER_PATTERN)) {
|
|
24
|
+
const key = match[1].toLowerCase();
|
|
25
|
+
const value = match[2].trim();
|
|
26
|
+
if (value === "")
|
|
27
|
+
continue;
|
|
28
|
+
if (key === "authored-by") {
|
|
29
|
+
author = value;
|
|
30
|
+
}
|
|
31
|
+
else if (key === "reviewed-by") {
|
|
32
|
+
reviewer = value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { author, reviewer };
|
|
36
|
+
}
|
|
37
|
+
export function checkSelfApproval(authorStr, reviewerStr) {
|
|
38
|
+
const author = parseIdentity(authorStr);
|
|
39
|
+
const reviewer = parseIdentity(reviewerStr);
|
|
40
|
+
if (author !== null && reviewer !== null) {
|
|
41
|
+
if (author.full === reviewer.full || author.family === reviewer.family) {
|
|
42
|
+
return {
|
|
43
|
+
isSelfApproval: true,
|
|
44
|
+
message: `Self-approval detected: author '${authorStr}' and reviewer '${reviewerStr}' share the same identity or model family ('${author.family}').`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { isSelfApproval: false };
|
|
49
|
+
}
|
|
18
50
|
function normalizePath(value) {
|
|
19
51
|
return value.replace(/\\/g, "/").replace(/^\.\//, "").trim();
|
|
20
52
|
}
|
|
@@ -76,18 +108,15 @@ function auditCommit(item, targetDir) {
|
|
|
76
108
|
severity: "error",
|
|
77
109
|
});
|
|
78
110
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
severity: "error",
|
|
89
|
-
});
|
|
90
|
-
}
|
|
111
|
+
const selfApprovalCheck = checkSelfApproval(item.author, item.reviewer);
|
|
112
|
+
if (selfApprovalCheck.isSelfApproval) {
|
|
113
|
+
violations.push({
|
|
114
|
+
...base,
|
|
115
|
+
rule: "review-gate-separation",
|
|
116
|
+
message: selfApprovalCheck.message ??
|
|
117
|
+
`Self-approval detected: author '${item.author}' and reviewer '${item.reviewer}' share the same identity.`,
|
|
118
|
+
severity: "error",
|
|
119
|
+
});
|
|
91
120
|
}
|
|
92
121
|
const note = getNote(item.sha, { cwd: targetDir });
|
|
93
122
|
if (note === null) {
|
|
@@ -145,6 +174,17 @@ function auditCommit(item, targetDir) {
|
|
|
145
174
|
export function auditBranch(baseBranch = "main", targetDir = process.cwd()) {
|
|
146
175
|
const timeline = getJourneyTimeline(baseBranch, targetDir);
|
|
147
176
|
const violations = timeline.items.flatMap((item) => auditCommit(item, targetDir));
|
|
177
|
+
const normalizedCurrent = timeline.branch.replace(/^refs\/heads\//, "");
|
|
178
|
+
const normalizedBase = baseBranch.replace(/^refs\/heads\//, "").replace(/^origin\//, "");
|
|
179
|
+
if (normalizedCurrent === normalizedBase && timeline.commitCount === 0) {
|
|
180
|
+
violations.push({
|
|
181
|
+
commitSha: "HEAD",
|
|
182
|
+
shortSha: "HEAD",
|
|
183
|
+
rule: "base-branch-range",
|
|
184
|
+
message: `Auditing base branch '${baseBranch}' directly: 0 commits in range ${baseBranch}..${timeline.branch}. Run from a feature branch or specify a base commit/range.`,
|
|
185
|
+
severity: "error",
|
|
186
|
+
});
|
|
187
|
+
}
|
|
148
188
|
const errors = violations.filter((violation) => violation.severity === "error").length;
|
|
149
189
|
const warnings = violations.length - errors;
|
|
150
190
|
return {
|
package/dist/audit/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/audit/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAqB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/audit/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA4BA,OAAO,EAAE,KAAK,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAErE,wBAAgB,aAAa,IAAI,MAAM,CAWtC"}
|
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { auditBranch, formatAuditResult } from "./audit/audit.js";
|
|
6
|
+
import { executeAtomicCommit, parseCommitArgs } from "./commit.js";
|
|
6
7
|
import { runDiagnostics } from "./doctor.js";
|
|
7
8
|
import { startMcpServer } from "./mcp/server.js";
|
|
8
9
|
import { attachCurrentStateToCommit } from "./notes/attach.js";
|
|
@@ -11,8 +12,11 @@ import { initProject } from "./scaffold.js";
|
|
|
11
12
|
import { clearState, finishSubtask, loadState, setSubtask } from "./state/manager.js";
|
|
12
13
|
import { syncStateFromGit } from "./state/sync.js";
|
|
13
14
|
import { getProjectStatus } from "./status.js";
|
|
15
|
+
import { buildAnonymousCommunityPayload, clearTelemetry, disableTelemetry, enableTelemetry, isTelemetryGloballyDisabled, loadTelemetry, } from "./telemetry/collector.js";
|
|
16
|
+
import { generateTelemetryReportFile } from "./telemetry/report.js";
|
|
14
17
|
import { getJourneyTimeline } from "./timeline/timeline.js";
|
|
15
18
|
const __cliDir = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
export { parseCommitArgs } from "./commit.js";
|
|
16
20
|
export function getCliVersion() {
|
|
17
21
|
try {
|
|
18
22
|
const pkgPath = join(__cliDir, "..", "package.json");
|
|
@@ -25,7 +29,7 @@ export function getCliVersion() {
|
|
|
25
29
|
catch {
|
|
26
30
|
// fallback
|
|
27
31
|
}
|
|
28
|
-
return "1.
|
|
32
|
+
return "1.2.0";
|
|
29
33
|
}
|
|
30
34
|
function printHeader() {
|
|
31
35
|
console.log("\n🔷 LogNexus CLI — Digital Lake");
|
|
@@ -40,14 +44,36 @@ Commands:
|
|
|
40
44
|
init Scaffold .lognexus/ configuration and rules in current repository
|
|
41
45
|
doctor Check Git, GitHub CLI authentication, and repository rules health
|
|
42
46
|
status Inspect current branch, active issue, and recommended tier
|
|
47
|
+
commit Atomic commit with trailers, contract validation, and Git Note
|
|
43
48
|
state Manage persistent agent state (.lognexus/state.json)
|
|
44
49
|
note Manage Git Notes under refs/notes/lognexus (git-ai standard)
|
|
45
50
|
timeline Reconstruct the branch Journey Timeline and draft a PR body
|
|
46
51
|
audit Audit commit conventions, authorship trailers and review gate
|
|
52
|
+
telemetry Opt-in performance monitoring, stack profiler and ROI report
|
|
47
53
|
mcp Start the LogNexus MCP server (stdio JSON-RPC 2.0) for native AI agents
|
|
48
54
|
version, -v Display the version of LogNexus
|
|
49
55
|
help, -h Display this help message
|
|
50
56
|
|
|
57
|
+
Telemetry Subcommands:
|
|
58
|
+
lognexus telemetry [status] Show current telemetry mode and project metrics
|
|
59
|
+
lognexus telemetry enable Enable local telemetry (zero network calls)
|
|
60
|
+
lognexus telemetry enable --share --accept-terms
|
|
61
|
+
Enable anonymous community telemetry (GDPR opt-in)
|
|
62
|
+
lognexus telemetry inspect Inspect the exact Zero-PII payload before sending
|
|
63
|
+
lognexus telemetry report [-o f] Generate .lognexus/telemetry.md report with ROI metrics
|
|
64
|
+
lognexus telemetry disable Disable all telemetry immediately
|
|
65
|
+
lognexus telemetry clear Reset local telemetry store
|
|
66
|
+
|
|
67
|
+
Commit Command:
|
|
68
|
+
lognexus commit -m "<msg>" [options]
|
|
69
|
+
lognexus commit -F <file> [options]
|
|
70
|
+
-m, --message "<msg>" Commit message (e.g. feat(#15/T1): add feature)
|
|
71
|
+
-F, --file <file> Read commit message from file
|
|
72
|
+
--author "<identity>" Author trailer (e.g. gemini/flash (antigravity))
|
|
73
|
+
--reviewer "<identity>" Optional reviewer trailer (e.g. gemini/pro)
|
|
74
|
+
--finish-task Mark active subtask as completed in state
|
|
75
|
+
--allow-empty Allow creating empty commits
|
|
76
|
+
|
|
51
77
|
State Subcommands:
|
|
52
78
|
lognexus state [show] Display current active issue and task state
|
|
53
79
|
lognexus state sync Sync state from current Git branch & GitHub
|
|
@@ -106,8 +132,9 @@ async function handleInit() {
|
|
|
106
132
|
}
|
|
107
133
|
}
|
|
108
134
|
console.log("\nNext Steps:");
|
|
109
|
-
console.log(" • Claude Code / Cursor / Codex / Antigravity / Kimi: use /lognexus plan");
|
|
135
|
+
console.log(" • Claude Code / Cursor / Codex / Antigravity / Gemini / Kimi: use /lognexus plan");
|
|
110
136
|
console.log(" • Configure model tiers in .lognexus/routing.md");
|
|
137
|
+
console.log(" • Tip: install locally with 'npm i -D @digital-lake/lognexus' for instant execution (~0.15s)");
|
|
111
138
|
console.log(" • Verify environment anytime with: npx @digital-lake/lognexus doctor\n");
|
|
112
139
|
}
|
|
113
140
|
async function handleDoctor() {
|
|
@@ -343,10 +370,141 @@ async function handleAudit(args) {
|
|
|
343
370
|
process.exit(1);
|
|
344
371
|
}
|
|
345
372
|
}
|
|
373
|
+
async function handleCommit(args) {
|
|
374
|
+
let parsed;
|
|
375
|
+
try {
|
|
376
|
+
parsed = parseCommitArgs(args);
|
|
377
|
+
}
|
|
378
|
+
catch (err) {
|
|
379
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
380
|
+
console.error(`Error: ${msg}\n`);
|
|
381
|
+
printUsage();
|
|
382
|
+
process.exit(1);
|
|
383
|
+
}
|
|
384
|
+
if (!parsed.message) {
|
|
385
|
+
console.error("Error: Commit message is required (e.g. lognexus commit -m 'feat(#15/T1): add feature' or -F <file>)\n");
|
|
386
|
+
printUsage();
|
|
387
|
+
process.exit(1);
|
|
388
|
+
}
|
|
389
|
+
printHeader();
|
|
390
|
+
try {
|
|
391
|
+
const res = executeAtomicCommit({
|
|
392
|
+
message: parsed.message,
|
|
393
|
+
author: parsed.author,
|
|
394
|
+
reviewer: parsed.reviewer,
|
|
395
|
+
finishTask: parsed.finishTask,
|
|
396
|
+
allowEmpty: parsed.allowEmpty,
|
|
397
|
+
});
|
|
398
|
+
console.log(`[OK] Committed [${res.shortSha}] ${res.subject}`);
|
|
399
|
+
console.log(` Authored-by: ${res.author}`);
|
|
400
|
+
if (res.reviewer) {
|
|
401
|
+
console.log(` Reviewed-by: ${res.reviewer}`);
|
|
402
|
+
}
|
|
403
|
+
if (res.subtaskCompleted) {
|
|
404
|
+
console.log(` Subtask: ${res.subtaskCompleted} (marked completed)`);
|
|
405
|
+
}
|
|
406
|
+
console.log(" Git Note: Attached to HEAD (refs/notes/lognexus)\n");
|
|
407
|
+
}
|
|
408
|
+
catch (err) {
|
|
409
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
410
|
+
console.error(`[FAIL] Commit failed: ${msg}\n`);
|
|
411
|
+
process.exit(1);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
async function handleTelemetry(args) {
|
|
415
|
+
const sub = args[0]?.toLowerCase() || "status";
|
|
416
|
+
switch (sub) {
|
|
417
|
+
case "status": {
|
|
418
|
+
printHeader();
|
|
419
|
+
const store = loadTelemetry();
|
|
420
|
+
const globallyDisabled = isTelemetryGloballyDisabled();
|
|
421
|
+
console.log("LogNexus Telemetry Status:\n");
|
|
422
|
+
console.log(` Globally Disabled (DO_NOT_TRACK): ${globallyDisabled ? "Yes (Forced OFF)" : "No"}`);
|
|
423
|
+
console.log(` Operating Mode: ${store.mode.toUpperCase()}`);
|
|
424
|
+
console.log(` Anonymous Project ID: ${store.anonymousProjectId}`);
|
|
425
|
+
console.log(` Community Consent: ${store.consent.accepted ? "Accepted (Shared)" : "No (Local Only)"}`);
|
|
426
|
+
if (store.consent.acceptedAt) {
|
|
427
|
+
console.log(` Consent Recorded At: ${store.consent.acceptedAt}`);
|
|
428
|
+
}
|
|
429
|
+
console.log(` Detected Stacks: ${store.detectedStacks.join(", ") || "(none)"}`);
|
|
430
|
+
console.log(` Total Commits Monitored: ${store.summary.totalCommits}`);
|
|
431
|
+
console.log(` Estimated Cost Savings: ${store.summary.estimatedCostSavingsPct}%\n`);
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
case "enable": {
|
|
435
|
+
printHeader();
|
|
436
|
+
const share = args.includes("--share");
|
|
437
|
+
const acceptTerms = args.includes("--accept-terms");
|
|
438
|
+
try {
|
|
439
|
+
const res = enableTelemetry({ share, acceptTerms });
|
|
440
|
+
if (res.mode === "community") {
|
|
441
|
+
console.log("[OK] Telemetry enabled in COMMUNITY mode.");
|
|
442
|
+
console.log(" Terms accepted. Anonymous non-sensitive metrics will help mature MCP & routing.");
|
|
443
|
+
console.log(" Full policy & payload schema: docs/TELEMETRY_PRIVACY.md\n");
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
console.log("[OK] Telemetry enabled in LOCAL mode.");
|
|
447
|
+
console.log(" Metrics are stored strictly locally in .lognexus/telemetry.json.");
|
|
448
|
+
console.log(" Zero network calls are made. Run 'lognexus telemetry report' to generate a report.\n");
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
catch (err) {
|
|
452
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
453
|
+
console.error(`[FAIL] ${msg}\n`);
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
case "disable": {
|
|
459
|
+
printHeader();
|
|
460
|
+
disableTelemetry();
|
|
461
|
+
console.log("[OK] Telemetry disabled. Zero metrics will be recorded or transmitted.\n");
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
case "inspect": {
|
|
465
|
+
printHeader();
|
|
466
|
+
const store = loadTelemetry();
|
|
467
|
+
const payload = buildAnonymousCommunityPayload(store);
|
|
468
|
+
console.log("Anonymous Telemetry Payload (Zero-PII Audit):\n");
|
|
469
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
470
|
+
console.log("\nNote: No code, file paths, file names, commit messages, or identities are included.\n");
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
case "report": {
|
|
474
|
+
printHeader();
|
|
475
|
+
let outputPath;
|
|
476
|
+
const outIdx = args.findIndex((a) => a === "--output" || a === "-o");
|
|
477
|
+
if (outIdx !== -1 && args[outIdx + 1]) {
|
|
478
|
+
outputPath = args[outIdx + 1];
|
|
479
|
+
}
|
|
480
|
+
const res = generateTelemetryReportFile(process.cwd(), outputPath);
|
|
481
|
+
console.log("[OK] Telemetry & ROI Performance Report generated:");
|
|
482
|
+
console.log(` Output file: ${res.filePath}\n`);
|
|
483
|
+
console.log(res.content);
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
case "clear": {
|
|
487
|
+
printHeader();
|
|
488
|
+
clearTelemetry();
|
|
489
|
+
console.log("[OK] Local telemetry store cleared and reset.\n");
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
default:
|
|
493
|
+
console.error(`Unknown telemetry subcommand: ${sub}\n`);
|
|
494
|
+
printUsage();
|
|
495
|
+
process.exit(1);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
346
498
|
async function main() {
|
|
347
499
|
const args = process.argv.slice(2);
|
|
348
500
|
const command = args[0]?.toLowerCase();
|
|
349
501
|
switch (command) {
|
|
502
|
+
case "commit":
|
|
503
|
+
await handleCommit(args.slice(1));
|
|
504
|
+
break;
|
|
505
|
+
case "telemetry":
|
|
506
|
+
await handleTelemetry(args.slice(1));
|
|
507
|
+
break;
|
|
350
508
|
case "init":
|
|
351
509
|
await handleInit();
|
|
352
510
|
break;
|