qodewk 0.1.8 → 0.1.10

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Qodewk Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # Qodewk — Proof of Shipment for the AI Coding Agent Era
2
+
3
+ > **Universal telemetry, multi-platform agent footprint harvester, and digital receipt generator for autonomous software development.**
4
+ > Built for Google Antigravity, Claude Code, Cursor, Copilot, Windsurf, Aider, and multi-agent Git workflows.
5
+
6
+ [![npm version](https://img.shields.io/npm/v/qodewk.svg?color=cc785c&label=npm%20package)](https://www.npmjs.com/package/qodewk)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
+ [![Built with Turborepo](https://img.shields.io/badge/monorepo-Turborepo-ef4444.svg)](https://turbo.build)
9
+ [![Design: Claude Warm Editorial](https://img.shields.io/badge/design-Claude%20Editorial-cc785c.svg)](https://qodewk.dev)
10
+
11
+ ---
12
+
13
+ ## ⚡️ Quickstart (Zero Install)
14
+
15
+ Run directly from any Git repository without installing any packages globally:
16
+
17
+ ```bash
18
+ # Generate monospace thermal receipt for latest commit / working tree
19
+ npx qodewk
20
+
21
+ # Harvest agent work for today (Chit-style proof of shipment)
22
+ npx qodewk --today
23
+
24
+ # Harvest agent work from the last 24 hours or 7 days
25
+ npx qodewk --since 24h
26
+ npx qodewk --since 7d
27
+
28
+ # Filter to a specific agent platform (antigravity, claude, cursor)
29
+ npx qodewk --platform antigravity
30
+
31
+ # Output machine-readable JSON telemetry
32
+ npx qodewk --json
33
+
34
+ # Publish privacy-safe receipt to web and get shareable URL
35
+ npx qodewk share
36
+
37
+ # Audit a PR branch diff range against base
38
+ npx qodewk audit --base origin/main --head HEAD --format markdown --out receipt.md
39
+ ```
40
+
41
+ ### Verified Thermal ASCII Receipt Preview
42
+ ```text
43
+ /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
44
+ | Q O D E W K |
45
+ | *** PROOF OF SHIPMENT *** |
46
+ | |
47
+ | ID: rec_8381ef3792010f9a2cfe DATE: 2026-09-28 |
48
+ | REPO: qodewk BRANCH: master |
49
+ | TASK: Antigravity Model Provider Issues |
50
+ | ==================================================== |
51
+ | ITEMS CHANGED QTY |
52
+ | ---------------------------------------------------- |
53
+ | Files Touched 1 |
54
+ | Lines Inserted + 50 |
55
+ | Lines Deleted - 58 |
56
+ | Net Code Delta - 8 |
57
+ | ---------------------------------------------------- |
58
+ | AI TELEMETRY & ATTRIBUTION |
59
+ | Provider: antigravity · gemini-3 |
60
+ | AI Written Code 88% (Human: 12%) |
61
+ | Tokens: 935k in (654k cached) / 112k out |
62
+ | Total Tokens: 1,046,640 |
63
+ | ==================================================== |
64
+ | VERIFIED AI COST $2.72 |
65
+ | CONFIDENCE: 95% [Mode: verified] |
66
+ | ==================================================== |
67
+ | |
68
+ | ||| | ||||| ||| |||| |||||| |||| ||| ||||||| ||| |
69
+ | https://qodewk.dev/r/rec_8381ef3792010f9a2cfe52… |
70
+ | |
71
+ | [✓] Source code was never uploaded to Qodewk |
72
+ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
73
+ ```
74
+
75
+ ---
76
+
77
+ ## 🌟 What's New: Universal Multi-Platform Footprint Harvester
78
+
79
+ Unlike single-vendor utilities (like Chit, which only support Claude Code CLI), **Qodewk operates globally across all major AI coding platforms**. It reads your local agent transcripts, matches them with your repository's Git revision graph, and proves what was actually shipped.
80
+
81
+ ### Supported Platforms & Harvesters
82
+
83
+ | Platform | Local Data Source / Footprint | Captured Telemetry |
84
+ |---|---|---|
85
+ | **Google Antigravity** | `~/.gemini/antigravity/conversation_summaries.db` & `brain/<id>/.../transcript.jsonl` | Shipped task titles, exact models (`Claude Opus 4.6 Thinking`, `Gemini 3.8 Flash`, etc.), tool calls (`replace_file_content`, `write_to_file`), and multi-turn tokens |
86
+ | **Claude Code CLI** | `~/.claude/projects/<slug>/sessions/*.jsonl` | User prompts, exact input/output/cached token usage, and `Edit`/`Write` file mutations |
87
+ | **Cursor IDE** | `%APPDATA%\Cursor\User\workspaceStorage\*\state.vscdb` (Win) / `Library/Application Support/Cursor/...` (Mac) | Workspace session bubbles, model types (`claude-3-5-sonnet`, `gpt-4o`), and generation timestamps |
88
+ | **Aider** | `.aider.chat.history.md` (Repository root) | Session prompts, model IDs, and code file diffs |
89
+ | **GitHub Copilot** | Git commit revision graph trailers (`Co-authored-by: Copilot`) | Commit-level author attribution |
90
+
91
+ ### Key Capabilities
92
+
93
+ 1. **Date-wise & Duration Filtering:**
94
+ Analyze agent output over arbitrary time windows (`--today`, `--since 24h`, `--since 7d`, `--since "2026-09-28"`).
95
+ 2. **AI vs. Human Code Attribution:**
96
+ Cross-references Git diff hunks against agent tool calls to calculate exact contribution percentages (e.g. `AI Written Code: 88% (Human: 12%)`).
97
+ 3. **Shipped Task Recognition:**
98
+ Extracts high-level task summaries and user prompts directly from session databases, so your receipt doubles as an instant standup or PR summary.
99
+ 4. **Never Fake Precision (Dual-Engine Provenance):**
100
+ - **`verified` (95% Confidence):** Harvested directly from local agent transcripts & SQLite databases.
101
+ - **`estimated` (45–65% Confidence):** Contextual Git diff & AST complexity fallback when operating in closed/uninstrumented environments.
102
+ 5. **Modern Frontier Rate Cards:**
103
+ Built-in pricing cards with cache read/write rates for `claude-opus-4-6-thinking`, `claude-sonnet-4-6-thinking`, `gemini-3-8-flash`, `gemini-2-5-pro`, `gpt-4o`, `o3-mini`, `deepseek-v3`, and `deepseek-r1`.
104
+
105
+ ---
106
+
107
+ ## 💻 CLI Command Reference
108
+
109
+ | Command / Option | Description | Output / Example |
110
+ |---|---|---|
111
+ | `npx qodewk` | Harvest local agent footprints and inspect Git commit | Monospace thermal receipt |
112
+ | `npx qodewk --today` | Generate receipt for all agent sessions and code written today | Daily shipment receipt |
113
+ | `npx qodewk --since <duration>` | Filter agent work by duration (e.g. `24h`, `7d`, `2026-09-28`) | Time-bounded telemetry receipt |
114
+ | `npx qodewk --platform <platform>` | Filter telemetry to a specific platform (`antigravity`, `claude`, `cursor`, `all`) | Single-platform audit |
115
+ | `npx qodewk --json` | Export machine-readable telemetry conforming to canonical `ReceiptV1` schema | Formatted JSON output |
116
+ | `npx qodewk share` | Publish privacy-safe metadata to Qodewk Cloud and generate short link | `https://qodewk.dev/r/rec_...` |
117
+ | `npx qodewk audit --base <branch>` | Calculate aggregate diff and telemetry across an entire PR branch range | Git revision delta receipt |
118
+ | `npx qodewk -f markdown -o receipt.md` | Export sticky Markdown receipt directly formatted for GitHub PR comments | File `receipt.md` |
119
+ | `npx qodewk -p <provider> -m <model>` | Override detected provider & frontier model pricing rate card | Custom model cost estimate |
120
+ | `npx qodewk --anon` | Redact sensitive repository and branch identifiers | Privacy-hardened receipt |
121
+
122
+ ---
123
+
124
+ ## 🔒 Privacy Invariant (Zero Source Exfiltration)
125
+
126
+ 1. **No Code Leaves Your Machine:** Source code files and raw Git diff bodies **never** touch the network.
127
+ 2. **Metadata Only:** Public receipts contain only file counts, line insertions/deletions, language ratios, token counts, task titles, and cryptographic hashes (`HMAC-SHA256`).
128
+ 3. **Hard 50 KB Request Cap:** The `/api/receipts` endpoint enforces a strict `50 KB` request body ceiling.
129
+ 4. **Kill Switch:** Set `QODEWK_TELEMETRY=off` to disable all cloud publishing permanently.
130
+ 5. **Local SQLite Footprint Storage:** Telemetry remains strictly stored in local SQLite (`~/.qodewk/state.db`).
131
+
132
+ ---
133
+
134
+ ## 📄 License
135
+
136
+ MIT © [Qodewk Contributors](LICENSE)
package/dist/index.cjs CHANGED
@@ -13269,6 +13269,32 @@ var path = __toESM(require("path"), 1);
13269
13269
  function computeSaltedHash(value, salt = "qodewk-default-salt") {
13270
13270
  return crypto.createHmac("sha256", salt).update(value).digest("hex");
13271
13271
  }
13272
+ function parseSinceOption(since) {
13273
+ if (!since)
13274
+ return void 0;
13275
+ if (since instanceof Date)
13276
+ return since;
13277
+ const s = since.trim().toLowerCase();
13278
+ const now = /* @__PURE__ */ new Date();
13279
+ if (s === "today") {
13280
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate());
13281
+ }
13282
+ const hoursMatch = s.match(/^(\d+)\s*h(?:ours?)?$/);
13283
+ if (hoursMatch && hoursMatch[1]) {
13284
+ const hours = parseInt(hoursMatch[1], 10);
13285
+ return new Date(now.getTime() - hours * 60 * 60 * 1e3);
13286
+ }
13287
+ const daysMatch = s.match(/^(\d+)\s*d(?:ays?)?$/);
13288
+ if (daysMatch && daysMatch[1]) {
13289
+ const days = parseInt(daysMatch[1], 10);
13290
+ return new Date(now.getTime() - days * 24 * 60 * 60 * 1e3);
13291
+ }
13292
+ const parsed = new Date(since);
13293
+ if (!isNaN(parsed.getTime())) {
13294
+ return parsed;
13295
+ }
13296
+ return void 0;
13297
+ }
13272
13298
  async function extractGitMetrics(optionsOrPath = process.cwd()) {
13273
13299
  const options = typeof optionsOrPath === "string" ? { repoPath: optionsOrPath } : optionsOrPath;
13274
13300
  const repoPath = options.repoPath || process.cwd();
@@ -13282,18 +13308,43 @@ async function extractGitMetrics(optionsOrPath = process.cwd()) {
13282
13308
  let headSha = options.headSha || "0000000000000000000000000000000000000000";
13283
13309
  let baseSha = options.baseSha;
13284
13310
  let commitMessage = void 0;
13285
- try {
13286
- const log = await git.log({ maxCount: 2 });
13287
- if (log.latest) {
13288
- if (!options.headSha) {
13289
- headSha = log.latest.hash;
13311
+ let commitsCount = 1;
13312
+ const sinceDate = parseSinceOption(options.since);
13313
+ if (sinceDate && !options.baseSha) {
13314
+ try {
13315
+ const sinceIso = sinceDate.toISOString();
13316
+ const commitsRaw = await git.raw(["log", `--since=${sinceIso}`, "--format=%H"]);
13317
+ const commitShas = commitsRaw.split("\n").map((s) => s.trim()).filter(Boolean);
13318
+ if (commitShas.length > 0) {
13319
+ commitsCount = commitShas.length;
13320
+ if (!options.headSha) {
13321
+ headSha = commitShas[0];
13322
+ }
13323
+ const oldestSha = commitShas[commitShas.length - 1];
13324
+ try {
13325
+ const parentSha = (await git.raw(["rev-parse", `${oldestSha}^`])).trim();
13326
+ baseSha = parentSha;
13327
+ } catch {
13328
+ baseSha = oldestSha;
13329
+ }
13290
13330
  }
13291
- commitMessage = log.latest.message;
13292
- if (!options.baseSha && log.all.length > 1 && log.all[1]) {
13293
- baseSha = log.all[1].hash;
13331
+ } catch {
13332
+ }
13333
+ }
13334
+ if (!baseSha) {
13335
+ try {
13336
+ const log = await git.log({ maxCount: 2 });
13337
+ if (log.latest) {
13338
+ if (!options.headSha) {
13339
+ headSha = log.latest.hash;
13340
+ }
13341
+ commitMessage = log.latest.message;
13342
+ if (!options.baseSha && log.all.length > 1 && log.all[1]) {
13343
+ baseSha = log.all[1].hash;
13344
+ }
13294
13345
  }
13346
+ } catch {
13295
13347
  }
13296
- } catch {
13297
13348
  }
13298
13349
  let repoIdentifier = path.basename(path.resolve(repoPath));
13299
13350
  try {
@@ -13308,13 +13359,18 @@ async function extractGitMetrics(optionsOrPath = process.cwd()) {
13308
13359
  const repoHash = computeSaltedHash(repoIdentifier);
13309
13360
  let diffSummary;
13310
13361
  if (baseSha && headSha && baseSha !== headSha) {
13311
- diffSummary = await git.diffSummary([`${baseSha}...${headSha}`]);
13362
+ const status = await git.status();
13363
+ if (status.files.length > 0) {
13364
+ diffSummary = await git.diffSummary([baseSha]);
13365
+ } else {
13366
+ diffSummary = await git.diffSummary([`${baseSha}..${headSha}`]);
13367
+ }
13312
13368
  } else {
13313
13369
  const status = await git.status();
13314
13370
  if (status.files.length > 0) {
13315
13371
  diffSummary = await git.diffSummary(["HEAD"]);
13316
13372
  } else if (baseSha) {
13317
- diffSummary = await git.diffSummary([`${baseSha}...${headSha}`]);
13373
+ diffSummary = await git.diffSummary([`${baseSha}..${headSha}`]);
13318
13374
  } else if (headSha !== "0000000000000000000000000000000000000000") {
13319
13375
  diffSummary = await git.diffSummary([headSha]);
13320
13376
  } else {
@@ -13359,7 +13415,8 @@ async function extractGitMetrics(optionsOrPath = process.cwd()) {
13359
13415
  baseSha,
13360
13416
  repoHash,
13361
13417
  projectAlias,
13362
- commitMessage
13418
+ commitMessage,
13419
+ commitsCount
13363
13420
  };
13364
13421
  }
13365
13422
  function mapExtensionToLanguage(ext) {
@@ -14120,7 +14177,7 @@ var LocalStateDB = class {
14120
14177
  };
14121
14178
 
14122
14179
  // ../core/dist/harvester/index.js
14123
- function parseSinceOption(since) {
14180
+ function parseSinceOption2(since) {
14124
14181
  if (!since)
14125
14182
  return void 0;
14126
14183
  if (since instanceof Date)
@@ -14148,7 +14205,7 @@ function parseSinceOption(since) {
14148
14205
  return void 0;
14149
14206
  }
14150
14207
  async function harvestUniversalFootprints(options) {
14151
- const sinceDate = parseSinceOption(options.since);
14208
+ const sinceDate = parseSinceOption2(options.since);
14152
14209
  const alias = options.projectAlias || "";
14153
14210
  let allFootprints = [];
14154
14211
  if (!options.platform || options.platform === "all" || options.platform === "antigravity") {
@@ -14318,7 +14375,8 @@ async function generateReceipt(options = {}) {
14318
14375
  const metrics = await extractGitMetrics({
14319
14376
  repoPath: options.repoPath || process.cwd(),
14320
14377
  baseSha: options.baseSha,
14321
- headSha: options.headSha
14378
+ headSha: options.headSha,
14379
+ since: options.since
14322
14380
  });
14323
14381
  const repoPath = options.repoPath || process.cwd();
14324
14382
  const harvestResult = await harvestUniversalFootprints({
@@ -14380,7 +14438,7 @@ async function generateReceipt(options = {}) {
14380
14438
  branch: options.anonymizeBranch ? "anonymized-branch" : metrics.branch,
14381
14439
  headSha: metrics.headSha,
14382
14440
  baseSha: metrics.baseSha,
14383
- commitsCount: 1
14441
+ commitsCount: metrics.commitsCount || 1
14384
14442
  },
14385
14443
  mutation: {
14386
14444
  files: metrics.files,
@@ -14569,7 +14627,8 @@ function renderTerminalReceipt(receipt, publicUrl) {
14569
14627
  printRow(`TASK: ${taskClean}`);
14570
14628
  }
14571
14629
  printDivider("=");
14572
- printRowSplit("ITEMS CHANGED", "QTY");
14630
+ const itemsHeader = receipt.repository.commitsCount && receipt.repository.commitsCount > 1 ? `ITEMS CHANGED (${receipt.repository.commitsCount} COMMITS)` : "ITEMS CHANGED";
14631
+ printRowSplit(itemsHeader, "QTY");
14573
14632
  printDivider("-");
14574
14633
  printRowSplit("Files Touched", String(receipt.mutation.files));
14575
14634
  printRowSplit("Lines Inserted", green("+ " + receipt.mutation.insertions));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qodewk",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Universal telemetry and digital receipt generator for the AI coding agent era",
5
5
  "type": "module",
6
6
  "bin": {