copilot-usage-studio 0.1.0 → 0.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.
@@ -0,0 +1,91 @@
1
+ # Copilot Memory
2
+
3
+ Copilot Usage Studio indexes locally saved GitHub Copilot memories and plans so a developer can see what Copilot has stored across VS Code workspaces.
4
+
5
+ ## Observed storage
6
+
7
+ Workspace-scoped files:
8
+
9
+ ```text
10
+ <VS Code User>/workspaceStorage/<workspace-id>/GitHub.copilot-chat/memory-tool/memories/
11
+ ```
12
+
13
+ Global files:
14
+
15
+ ```text
16
+ <VS Code User>/globalStorage/github.copilot-chat/memory-tool/memories/
17
+ ```
18
+
19
+ Observed workspace layouts include:
20
+
21
+ ```text
22
+ memories/repo/<topic>.md
23
+ memories/<base64-session-id>/plan.md
24
+ memories/<base64-session-id>/<research>.md
25
+ ```
26
+
27
+ The base64 directory decodes to the same session UUID used by Agent Debug Logs and transcripts. This gives the app a source-backed link between a saved plan or research note and the run that created it.
28
+
29
+ ## Normalized record
30
+
31
+ Each indexed Markdown file records:
32
+
33
+ - stable local id derived from its absolute path
34
+ - `kind`: `memory` or `plan`
35
+ - `scope`: `global`, `repository`, `session`, or `workspace`
36
+ - title, excerpt, and full Markdown content
37
+ - workspace name when applicable
38
+ - decoded session id when applicable
39
+ - absolute and relative source paths
40
+ - created and modified timestamps
41
+ - byte, character, and line counts
42
+
43
+ The scanner reads Markdown files once during the normal local scan. It skips files larger than 1 MiB and caps each memory root at 5,000 files. These limits protect refresh performance without affecting normal observed memory stores, whose files are small.
44
+
45
+ ## Product boundary
46
+
47
+ Version one is a read-only knowledge library:
48
+
49
+ - search all saved memory content
50
+ - filter by plan/memory, scope, and workspace
51
+ - read the Markdown source
52
+ - link session-scoped files to imported runs
53
+ - show observed recall frequency, time, session, returned content size, and the following model request
54
+ - open the file or reveal it through the local runtime
55
+
56
+ The browser does not receive arbitrary filesystem access. Open/reveal actions identify a memory by its scanner-generated id, and the runtime accepts only files present in the current scanned snapshot.
57
+
58
+ ## Observed recall evidence
59
+
60
+ Agent Debug Logs provide a useful distinction between a memory being available and actually being recalled:
61
+
62
+ - VS Code injects a memory inventory into model input. The observed inventory names available user, session, and repository memory files, but does not include every file's full contents.
63
+ - When the agent calls the `memory` tool with `command: "view"`, the tool event records the requested memory path and returned content.
64
+ - That tool result is then present in the following model request. The app can therefore say that a specific memory was loaded before a specific model call.
65
+ - The following model call exposes exact total input, cached input, output, and source usage when those fields are present. It does not expose a separate token total or cost for the memory text alone.
66
+
67
+ In the June 15, 2026 local log sample, 46 JSONL files contained 127 model requests with a memory inventory and 18 explicit memory-tool operations across 11 sessions. Fifteen operations were reads, including repeated reads of the repository memory. These counts establish that recall is observable, but they are only a local sample and not a VS Code API contract.
68
+
69
+ The recall view shows:
70
+
71
+ - which memory path was read
72
+ - when and in which session it was read
73
+ - the returned content size
74
+ - the next model call and that call's total token/usage facts
75
+
76
+ It must not label the entire following request as memory cost or derive an exact memory-only token charge from character count.
77
+
78
+ ## What the app does not claim
79
+
80
+ A saved memory is evidence that Copilot wrote a local file. A matching `memory view` tool event is evidence that Copilot later recalled it and included the returned content in the request chain.
81
+
82
+ Therefore the first version does not label memories as useful, stale, harmful, or token-consuming. Those conclusions require a matching Agent Debug Log or request side-file showing that the memory was included in a model request.
83
+
84
+ Future evidence-backed opportunities:
85
+
86
+ - flag conflicting or old memories for review
87
+ - compare request input before and after a memory is edited or removed
88
+ - help turn a proven durable memory into repository instructions
89
+ - map repository memories to code/domain areas when paths or content provide a reliable relationship
90
+
91
+ Editing and deletion remain later work. The files are technically accessible, but VS Code's indexing and lifecycle contract is not documented strongly enough to make destructive management a first-release feature.
@@ -2,7 +2,7 @@
2
2
 
3
3
  The app is intended to run locally, near the VS Code data it reads. It should not require a hosted SaaS backend for the core workflow.
4
4
 
5
- Current release posture: early local developer preview. The npm package is prepared and locally verified; clone-and-run remains available until version `0.1.0` is published to the registry.
5
+ Current release posture: early local developer preview. Version `0.1.0` is published publicly on npm, while clone-and-run remains available for contributors and development builds.
6
6
 
7
7
  Packaging foundation now available: the scanner exposes an in-memory Node API through `lib/scanner-api.mjs`. The existing scan command uses that same API and only adds argument parsing plus JSON persistence. This is the common core for the next local host, an `npx` command, Electron packaging, and a future thin VS Code extension.
8
8
 
@@ -33,7 +33,7 @@ http://127.0.0.1:4200/
33
33
 
34
34
  Why: this is the fastest loop while the UI and scanner are changing. `npm start` launches the Angular dev server and the local runtime together. The runtime serves the last valid snapshot immediately, performs a background startup scan, and powers the in-app refresh action.
35
35
 
36
- ## First Public Release Path
36
+ ## Install From npm
37
37
 
38
38
  The npm package is configured for a one-command local launch:
39
39
 
@@ -41,7 +41,7 @@ The npm package is configured for a one-command local launch:
41
41
  npx copilot-usage-studio
42
42
  ```
43
43
 
44
- This command will become available after the package owner publishes version `0.1.0` to npm. It starts the packaged production UI and scanner runtime on `http://127.0.0.1:4312/` by default.
44
+ This starts the packaged production UI and scanner runtime on `http://127.0.0.1:4312/` by default. It downloads the latest published npm version rather than the current GitHub `main` branch.
45
45
 
46
46
  Useful packaged commands:
47
47
 
@@ -54,10 +54,10 @@ npx copilot-usage-studio --help
54
54
 
55
55
  The CLI requires Node.js 22.5 or newer because optional VS Code `state.vscdb` enrichment uses Node's built-in SQLite support.
56
56
 
57
- Before registry publication, use the repository flow:
57
+ For development or the current GitHub source, use the repository flow:
58
58
 
59
59
  ```bash
60
- git clone <repo-url>
60
+ git clone https://github.com/fortunes-guardian/copilot-usage-studio.git
61
61
  cd copilot-usage-studio
62
62
  npm install
63
63
  npm start
@@ -76,7 +76,7 @@ npm run test:scripts
76
76
  npm run build
77
77
  ```
78
78
 
79
- Release copy should describe the app as a local Copilot usage debugger for VS Code. The strongest promise is: "VS Code already logs useful usage data locally; this app makes it understandable for developers who do not have billing-console access."
79
+ Release copy should describe the app as a local Copilot usage inspector for VS Code. The strongest promise is: "VS Code already logs useful usage data locally; this app makes it understandable for developers who do not have billing-console access."
80
80
 
81
81
  ### Packaged Data Location
82
82
 
@@ -88,7 +88,57 @@ The packaged CLI stores its current normalized snapshot outside the npm installa
88
88
 
89
89
  The npm tarball contains the compiled UI, scanner, pricing table, and runtime code. It must never contain `public/data/sessions.json` or any other developer's imported session data.
90
90
 
91
- ### Publishing
91
+ ## Automated Releases
92
+
93
+ GitHub Actions is the release control plane:
94
+
95
+ - `.github/workflows/ci.yml` runs the full release gate for pull requests and pushes to `main`.
96
+ - `.github/workflows/release.yml` runs automatically for version tags such as `v0.1.1`, with a manual existing-tag mode for repair and backfill.
97
+ - The release workflow verifies that the tag matches `package.json`, publishes the exact tagged source, and creates the matching GitHub Release.
98
+ - A failed workflow can be rerun safely: an existing npm version is accepted only when its published `gitHead` matches the exact tagged commit. Conflicting or unverifiable versions are refused.
99
+ - New versions must pass the full release gate before publication. An exact-commit backfill of an already-published historical version skips its old test suite and only repairs the missing GitHub Release.
100
+
101
+ This keeps GitHub, npm, and the source tag tied to the same commit. Ordinary pushes never publish.
102
+
103
+ ### One-Time npm Setup
104
+
105
+ Commit and push the workflow files first, then configure npm Trusted Publishing for the existing `copilot-usage-studio` package:
106
+
107
+ 1. Open the package settings on npm and add a GitHub Actions trusted publisher.
108
+ 2. Set organization or user to `fortunes-guardian`.
109
+ 3. Set repository to `copilot-usage-studio`.
110
+ 4. Set workflow filename to `release.yml`.
111
+ 5. Allow the `npm publish` action.
112
+ 6. Leave the environment blank unless the workflow is later changed to use a protected GitHub environment.
113
+
114
+ The workflow uses GitHub's OIDC identity, so no long-lived `NPM_TOKEN` repository secret is required. npm automatically adds provenance for a public package published from a public repository through Trusted Publishing.
115
+
116
+ ### Publishing a Version
117
+
118
+ Start from an up-to-date, clean `main` branch. Choose the semantic-version bump that matches the change:
119
+
120
+ ```bash
121
+ git switch main
122
+ git pull --ff-only
123
+ npm run release:check
124
+ npm version patch
125
+ git push origin main --follow-tags
126
+ ```
127
+
128
+ `npm version patch` updates both `package.json` and `package-lock.json`, creates a version commit, and creates an annotated `vX.Y.Z` tag. Use `npm version minor` for a backward-compatible feature release or `npm version major` for a breaking release.
129
+
130
+ After the tag is pushed:
131
+
132
+ 1. Watch the **Release** workflow in GitHub Actions.
133
+ 2. Confirm the new version appears on npm.
134
+ 3. Confirm GitHub created a Release for the same tag.
135
+ 4. Run `npx copilot-usage-studio@X.Y.Z --version` from a clean directory as a final smoke test.
136
+
137
+ If CI or release validation fails, fix the issue on `main` and publish a new version. Do not move or reuse a public release tag, and do not overwrite an npm version; both are immutable release coordinates.
138
+
139
+ The workflow also has a manual **Run workflow** action with a required existing tag. Use this to repair or backfill the GitHub Release for an exact tag. For the already-published first version, ensure `v0.1.0` exists on GitHub, then run the workflow once with `v0.1.0`; it will verify npm's published `gitHead`, skip the historical release gate and npm publication, and create the missing GitHub Release.
140
+
141
+ ### Manual Emergency Fallback
92
142
 
93
143
  Run the full package gate:
94
144
 
@@ -102,7 +152,7 @@ Inspect the tarball list, confirm no local session data or absolute paths are pr
102
152
  npm publish --access public
103
153
  ```
104
154
 
105
- Publishing is an external release action and should not be automated from ordinary development commands.
155
+ Use this only if Trusted Publishing or GitHub Actions is unavailable. The normal path is the tag-driven workflow above.
106
156
 
107
157
  If the browser shows updated markup with stale component styles, stop the dev server and restart it with a cache reset:
108
158
 
@@ -26,7 +26,7 @@ import { scanVsCodeSessions } from './lib/scanner-api.mjs';
26
26
  const sessionData = await scanVsCodeSessions();
27
27
  ```
28
28
 
29
- The result is the normalized `SessionData` document consumed by the Angular UI. No file is created or changed.
29
+ The result is the normalized `SessionData` document consumed by the Angular UI. It contains imported `sessions` plus a sibling `memories` collection for observed Copilot Markdown memories and plans. No file is created or changed.
30
30
 
31
31
  This is the intended path for:
32
32
 
@@ -96,7 +96,7 @@ There is one parser and pricing implementation. Future hosts should not copy sca
96
96
 
97
97
  ## Privacy And Source Rules
98
98
 
99
- The API reads local VS Code Copilot storage and can encounter prompts, file paths, repository context, tool schemas, and tool results. Hosts must keep results local unless a user explicitly exports them.
99
+ The API reads local VS Code Copilot storage and can encounter prompts, file paths, repository context, tool schemas, tool results, saved memories, and saved plans. Hosts must keep results local unless a user explicitly exports them.
100
100
 
101
101
  The API does not change evidence rules:
102
102
 
@@ -105,5 +105,6 @@ The API does not change evidence rules:
105
105
  - cached input remains separate from normal input and output
106
106
  - chat snapshots remain fallback data
107
107
  - SQLite is metadata enrichment, not a billing source
108
+ - saved memory files are indexed as local artifacts; their presence does not prove they were recalled into a model request
108
109
 
109
- See [data-ingestion.md](data-ingestion.md), [debug-log-schema.md](debug-log-schema.md), and [pricing.md](pricing.md) for those contracts.
110
+ See [data-ingestion.md](data-ingestion.md), [copilot-memory.md](copilot-memory.md), [debug-log-schema.md](debug-log-schema.md), and [pricing.md](pricing.md) for those contracts.
@@ -1,6 +1,7 @@
1
+ import { spawn } from 'node:child_process';
1
2
  import { createReadStream, existsSync, readFileSync, statSync } from 'node:fs';
2
3
  import { createServer } from 'node:http';
3
- import { extname, join, normalize, resolve, sep } from 'node:path';
4
+ import { dirname, extname, join, normalize, resolve, sep } from 'node:path';
4
5
 
5
6
  import { scanVsCodeSessions, writeSessionData } from './scanner-api.mjs';
6
7
 
@@ -29,7 +30,9 @@ export function createLocalRuntime(options = {}) {
29
30
  const scanOptions = options.scanOptions ?? {};
30
31
  const scanner = options.scanner ?? scanVsCodeSessions;
31
32
  const writer = options.writer ?? writeSessionData;
33
+ const openPath = options.openPath ?? openLocalPath;
32
34
  const logger = options.logger ?? console;
35
+ const backendOnly = options.backendOnly === true;
33
36
 
34
37
  let sessionData = readCachedSessionData(dataFile, logger)
35
38
  ?? (seedDataFile ? readCachedSessionData(seedDataFile, logger) : null);
@@ -46,6 +49,7 @@ export function createLocalRuntime(options = {}) {
46
49
  scanning: Boolean(activeScan),
47
50
  hasData: Boolean(sessionData),
48
51
  sessionCount: sessionData?.sessions?.length ?? 0,
52
+ memoryCount: sessionData?.memories?.length ?? 0,
49
53
  generatedAt: sessionData?.generatedAt ?? '',
50
54
  lastScanStartedAt,
51
55
  lastScanCompletedAt,
@@ -123,6 +127,19 @@ export function createLocalRuntime(options = {}) {
123
127
  }
124
128
  }
125
129
 
130
+ const memoryAction = url.pathname.match(/^\/api\/memories\/([a-f0-9]{24})\/open$/);
131
+ if (request.method === 'POST' && memoryAction) {
132
+ const memory = sessionData?.memories?.find((candidate) => candidate.id === memoryAction[1]);
133
+ if (!memory) {
134
+ return sendJson(response, 404, { error: 'Memory file not found in the current scan.' });
135
+ }
136
+
137
+ const body = await readJsonBody(request);
138
+ const action = body?.action === 'reveal' ? 'reveal' : 'open';
139
+ await openPath(memory.sourcePath, action);
140
+ return sendJson(response, 200, { ok: true, action });
141
+ }
142
+
126
143
  if (request.method !== 'GET' && request.method !== 'HEAD') {
127
144
  return sendJson(response, 405, { error: 'Method not allowed.' });
128
145
  }
@@ -144,7 +161,11 @@ export function createLocalRuntime(options = {}) {
144
161
  server.listen(port, host, () => {
145
162
  server.off('error', rejectListen);
146
163
  const address = server.address();
147
- logger.log(`Copilot Usage Studio local runtime: http://${host}:${address.port}/`);
164
+ logger.log(
165
+ backendOnly
166
+ ? `Copilot Usage Studio backend API: http://${host}:${address.port}/ (used by the dev server)`
167
+ : `Copilot Usage Studio local app: http://${host}:${address.port}/`,
168
+ );
148
169
  resolveListen(address);
149
170
 
150
171
  if (options.scanOnStart !== false) {
@@ -167,6 +188,60 @@ export function createLocalRuntime(options = {}) {
167
188
  }
168
189
  }
169
190
 
191
+ function readJsonBody(request) {
192
+ return new Promise((resolveBody, rejectBody) => {
193
+ const chunks = [];
194
+ let size = 0;
195
+ request.on('data', (chunk) => {
196
+ size += chunk.length;
197
+ if (size > 16 * 1024) {
198
+ rejectBody(new Error('Request body is too large.'));
199
+ request.destroy();
200
+ return;
201
+ }
202
+ chunks.push(chunk);
203
+ });
204
+ request.on('end', () => {
205
+ if (!chunks.length) {
206
+ resolveBody({});
207
+ return;
208
+ }
209
+ try {
210
+ resolveBody(JSON.parse(Buffer.concat(chunks).toString('utf8')));
211
+ } catch {
212
+ rejectBody(new Error('Request body must be valid JSON.'));
213
+ }
214
+ });
215
+ request.on('error', rejectBody);
216
+ });
217
+ }
218
+
219
+ function openLocalPath(path, action) {
220
+ const target = resolve(path);
221
+ let command;
222
+ let args;
223
+
224
+ if (process.platform === 'win32') {
225
+ command = 'explorer.exe';
226
+ args = action === 'reveal' ? ['/select,', target] : [target];
227
+ } else if (process.platform === 'darwin') {
228
+ command = 'open';
229
+ args = action === 'reveal' ? ['-R', target] : [target];
230
+ } else {
231
+ command = 'xdg-open';
232
+ args = [action === 'reveal' ? dirname(target) : target];
233
+ }
234
+
235
+ return new Promise((resolveOpen, rejectOpen) => {
236
+ const child = spawn(command, args, { detached: true, stdio: 'ignore', windowsHide: true });
237
+ child.once('error', rejectOpen);
238
+ child.once('spawn', () => {
239
+ child.unref();
240
+ resolveOpen();
241
+ });
242
+ });
243
+ }
244
+
170
245
  function readCachedSessionData(dataFile, logger) {
171
246
  if (!existsSync(dataFile)) {
172
247
  return null;
package/package.json CHANGED
@@ -1,54 +1,55 @@
1
- {
2
- "name": "copilot-usage-studio",
3
- "version": "0.1.0",
4
- "description": "Local VS Code GitHub Copilot usage, cost, and session insights.",
5
- "type": "module",
6
- "bin": {
7
- "copilot-usage-studio": "bin/copilot-usage-studio.mjs"
8
- },
9
- "files": [
10
- "CHANGELOG.md",
11
- "bin/",
12
- "data/github-copilot-pricing.json",
13
- "dist/copilot-usage-studio/browser/",
14
- "docs/local-deployment.md",
15
- "docs/pricing.md",
16
- "docs/scanner-api.md",
17
- "lib/",
18
- "scripts/pricing-utils.mjs",
19
- "scripts/scan-vscode-sessions.mjs"
20
- ],
21
- "scripts": {
22
- "ng": "ng",
23
- "start": "node scripts/start-local-dev.mjs",
24
- "start:angular": "ng serve --proxy-config proxy.conf.json",
25
- "start:clean": "npm run clean:ng-cache && node scripts/start-local-dev.mjs",
26
- "runtime": "node scripts/local-runtime.mjs",
27
- "preview:local": "npm run build && node scripts/local-runtime.mjs",
28
- "cli": "node bin/copilot-usage-studio.mjs",
29
- "prebuild": "node scripts/clean-dist.mjs",
30
- "build": "ng build",
31
- "watch": "ng build --watch --configuration development",
32
- "test": "ng test",
33
- "test:scripts": "node --test scripts/*.test.mjs",
34
- "clean:ng-cache": "ng cache clean",
35
- "refresh:data": "npm run scan && npm run verify:data",
36
- "scan": "node scripts/scan-vscode-sessions.mjs",
37
- "verify:data": "node scripts/verify-session-data.mjs",
38
- "schema:audit": "node scripts/audit-vscode-schema.mjs",
39
- "schema:accept": "node scripts/audit-vscode-schema.mjs --accept",
40
- "verify:package": "node scripts/verify-package.mjs",
41
- "release:check": "npm run test:scripts && npm test -- --watch=false && npm run build && npm run verify:package",
42
- "prepack": "npm run build"
43
- },
44
- "exports": {
45
- ".": "./lib/cli.mjs",
46
- "./scanner": "./lib/scanner-api.mjs",
47
- "./local-runtime": "./lib/local-runtime.mjs"
48
- },
49
- "engines": {
50
- "node": ">=22.5.0"
51
- },
1
+ {
2
+ "name": "copilot-usage-studio",
3
+ "version": "0.2.0",
4
+ "description": "Local VS Code GitHub Copilot usage, cost, and session insights.",
5
+ "type": "module",
6
+ "bin": {
7
+ "copilot-usage-studio": "bin/copilot-usage-studio.mjs"
8
+ },
9
+ "files": [
10
+ "CHANGELOG.md",
11
+ "bin/",
12
+ "data/github-copilot-pricing.json",
13
+ "dist/copilot-usage-studio/browser/",
14
+ "docs/local-deployment.md",
15
+ "docs/copilot-memory.md",
16
+ "docs/pricing.md",
17
+ "docs/scanner-api.md",
18
+ "lib/",
19
+ "scripts/pricing-utils.mjs",
20
+ "scripts/scan-vscode-sessions.mjs"
21
+ ],
22
+ "scripts": {
23
+ "ng": "ng",
24
+ "start": "node scripts/start-local-dev.mjs",
25
+ "start:angular": "ng serve --proxy-config proxy.conf.json",
26
+ "start:clean": "npm run clean:ng-cache && node scripts/start-local-dev.mjs",
27
+ "runtime": "node scripts/local-runtime.mjs",
28
+ "preview:local": "npm run build && node scripts/local-runtime.mjs",
29
+ "cli": "node bin/copilot-usage-studio.mjs",
30
+ "prebuild": "node scripts/clean-dist.mjs",
31
+ "build": "ng build",
32
+ "watch": "ng build --watch --configuration development",
33
+ "test": "ng test",
34
+ "test:scripts": "node --test scripts/*.test.mjs",
35
+ "clean:ng-cache": "ng cache clean",
36
+ "refresh:data": "npm run scan && npm run verify:data",
37
+ "scan": "node scripts/scan-vscode-sessions.mjs",
38
+ "verify:data": "node scripts/verify-session-data.mjs",
39
+ "schema:audit": "node scripts/audit-vscode-schema.mjs",
40
+ "schema:accept": "node scripts/audit-vscode-schema.mjs --accept",
41
+ "verify:package": "node scripts/verify-package.mjs",
42
+ "release:check": "npm run test:scripts && npm test -- --watch=false && npm run build && npm run verify:package",
43
+ "prepack": "npm run build"
44
+ },
45
+ "exports": {
46
+ ".": "./lib/cli.mjs",
47
+ "./scanner": "./lib/scanner-api.mjs",
48
+ "./local-runtime": "./lib/local-runtime.mjs"
49
+ },
50
+ "engines": {
51
+ "node": ">=22.5.0"
52
+ },
52
53
  "repository": {
53
54
  "type": "git",
54
55
  "url": "git+https://github.com/fortunes-guardian/copilot-usage-studio.git"
@@ -57,30 +58,30 @@
57
58
  "url": "https://github.com/fortunes-guardian/copilot-usage-studio/issues"
58
59
  },
59
60
  "homepage": "https://github.com/fortunes-guardian/copilot-usage-studio#readme",
60
- "keywords": [
61
- "github-copilot",
62
- "vscode",
63
- "ai-usage",
64
- "token-cost",
65
- "developer-tools"
66
- ],
67
- "license": "MIT",
68
- "packageManager": "npm@11.11.0",
69
- "devDependencies": {
70
- "@angular/build": "^21.2.9",
71
- "@angular/cli": "^21.2.9",
72
- "@angular/common": "^21.2.0",
73
- "@angular/compiler": "^21.2.0",
74
- "@angular/compiler-cli": "^21.2.0",
75
- "@angular/core": "^21.2.0",
76
- "@angular/forms": "^21.2.0",
77
- "@angular/platform-browser": "^21.2.0",
78
- "@angular/router": "^21.2.0",
79
- "jsdom": "^28.0.0",
80
- "prettier": "^3.8.1",
81
- "rxjs": "~7.8.0",
82
- "tslib": "^2.3.0",
83
- "typescript": "~5.9.2",
84
- "vitest": "^4.0.8"
85
- }
86
- }
61
+ "keywords": [
62
+ "github-copilot",
63
+ "vscode",
64
+ "ai-usage",
65
+ "token-cost",
66
+ "developer-tools"
67
+ ],
68
+ "license": "MIT",
69
+ "packageManager": "npm@11.11.0",
70
+ "devDependencies": {
71
+ "@angular/build": "^21.2.9",
72
+ "@angular/cli": "^21.2.9",
73
+ "@angular/common": "^21.2.0",
74
+ "@angular/compiler": "^21.2.0",
75
+ "@angular/compiler-cli": "^21.2.0",
76
+ "@angular/core": "^21.2.0",
77
+ "@angular/forms": "^21.2.0",
78
+ "@angular/platform-browser": "^21.2.0",
79
+ "@angular/router": "^21.2.0",
80
+ "jsdom": "^28.0.0",
81
+ "prettier": "^3.8.1",
82
+ "rxjs": "~7.8.0",
83
+ "tslib": "^2.3.0",
84
+ "typescript": "~5.9.2",
85
+ "vitest": "^4.0.8"
86
+ }
87
+ }