@kenkaiiii/gg-core 5.91.2 → 5.93.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/NOTICE CHANGED
@@ -1,5 +1,5 @@
1
1
  GG Coder
2
- Copyright (C) 2025-2026 KenKai
2
+ Copyright (C) 2025-2026 Ken Kai
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify it under
5
5
  the terms of the GNU Affero General Public License as published by the Free
package/README.md CHANGED
@@ -1,68 +1,84 @@
1
- # @kenkaiiii/gg-core
1
+ <h1 align="center">@kenkaiiii/gg-core</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>Model registry, auth storage and local-model discovery. No UI, no agent loop.</strong>
4
+ <strong>Model list, sign-in and local model discovery for apps built on gg-ai.</strong>
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- <a href="https://www.npmjs.com/package/@kenkaiiii/gg-core"><img src="https://img.shields.io/npm/v/@kenkaiiii/gg-core?style=for-the-badge" alt="npm version"></a>
9
- <a href="../../LICENSE"><img src="https://img.shields.io/badge/License-AGPL--3.0-blue.svg?style=for-the-badge" alt="AGPL-3.0 License"></a>
8
+ <a href="https://www.npmjs.com/package/@kenkaiiii/gg-core"><img src="https://img.shields.io/npm/v/@kenkaiiii/gg-core?style=for-the-badge&color=blue" alt="npm version"></a>
9
+ <a href="https://www.npmjs.com/package/@kenkaiiii/gg-core"><img src="https://img.shields.io/npm/dm/@kenkaiiii/gg-core?style=for-the-badge&color=2ecc71" alt="npm downloads per month"></a>
10
+ <a href="https://github.com/KenKaiii/gg-framework/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-AGPL--3.0-blue.svg?style=for-the-badge" alt="AGPL-3.0 License"></a>
10
11
  </p>
11
12
 
12
- The shared foundation under GG Coder's app and CLI. It depends only on [`@kenkaiiii/gg-ai`](../gg-ai/README.md), never on React, Ink or the agent loop.
13
+ gg-core is the shared base under [GG Coder](https://github.com/KenKaiii/gg-framework)'s desktop app and CLI. It knows every supported model (context window, image and video support, thinking levels), signs users in to their AI subscriptions, keeps those credentials fresh, and finds models running on the user's machine.
13
14
 
14
- Part of the [GG Framework](../../README.md) monorepo.
15
-
16
- ---
15
+ It has no UI and no agent loop. Its only framework dependency is [`@kenkaiiii/gg-ai`](https://www.npmjs.com/package/@kenkaiiii/gg-ai).
17
16
 
18
17
  ## Install
19
18
 
20
19
  ```bash
21
- npm i @kenkaiiii/gg-core
20
+ npm install @kenkaiiii/gg-core
22
21
  ```
23
22
 
24
- ---
25
-
26
- ## What's inside
27
-
28
- | Area | Main exports |
29
- | --------------- | ----------------------------------------------------------------------------------------- |
30
- | Model registry | `getModel`, `getAllModels`, `getModelsForProvider`, `getDefaultModel`, `getContextWindow` |
31
- | Thinking levels | `getSupportedThinkingLevels`, `getMaxThinkingLevel`, `getDefaultThinkingLevel` |
32
- | Auth storage | `AuthStorage` (reads and writes `~/.gg/auth.json`, refreshes OAuth tokens) |
33
- | OAuth | Anthropic, OpenAI, Gemini, Kimi and xAI login flows |
34
- | Local models | `discoverLocalModels` (Ollama, LM Studio, llama.cpp, vLLM, custom endpoints) |
35
- | Paths | `getAppPaths` (every file under `~/.gg/`) |
36
- | Other | Logger, file lock, usage limits, Telegram, voice transcription, auto-update |
23
+ Needs Node.js 22 or newer. Ships ESM and CommonJS builds with TypeScript types.
37
24
 
38
- Two lighter subpath entries skip the rest of the package:
39
-
40
- ```ts
41
- import { getModel } from "@kenkaiiii/gg-core/models";
42
- import { getAppPaths } from "@kenkaiiii/gg-core/paths";
43
- ```
44
-
45
- ---
46
-
47
- ## Example
25
+ ## Quick start
48
26
 
49
27
  ```ts
50
28
  import { AuthStorage, discoverLocalModels, getModel } from "@kenkaiiii/gg-core";
51
29
 
52
30
  const model = getModel("claude-sonnet-5-5");
53
- console.log(model?.contextWindow);
31
+ console.log(model?.contextWindow, model?.supportsImages); // 1000000 true
54
32
 
33
+ // Credentials saved by `ggcoder login` or the GG Coder app, refreshed when they expire.
55
34
  const auth = new AuthStorage();
56
35
  const token = await auth.resolveToken("anthropic");
57
36
 
37
+ // Models on a running Ollama server.
58
38
  const { models } = await discoverLocalModels();
59
39
  console.log(models.map((m) => m.id));
60
40
  ```
61
41
 
62
- `AuthStorage` throws `NotLoggedInError` when a provider has no stored credentials.
42
+ `resolveToken()` throws `NotLoggedInError` when the provider has no saved credentials.
43
+
44
+ ## What's inside
45
+
46
+ | Area | Main exports |
47
+ | --------------- | -------------------------------------------------------------------------------------------------------------- |
48
+ | Models | `getModel`, `getAllModels`, `getModelsForProvider`, `getDefaultModel`, `getContextWindow`, `MODELS` |
49
+ | Thinking levels | `getSupportedThinkingLevels`, `getMaxThinkingLevel`, `getDefaultThinkingLevel`, `getNextThinkingLevel` |
50
+ | Credentials | `AuthStorage`: reads and writes `~/.gg/auth.json`, refreshes sign-in tokens, safe across processes |
51
+ | Sign-in | `loginAnthropic`, `loginOpenAI`, `loginKimi`, `loginXai`, `loginGemini` and matching `refresh…Token` functions |
52
+ | Provider list | `AUTH_PROVIDERS`: each provider's name, models and sign-in methods, ready for a login screen |
53
+ | Local models | `discoverLocalModels`, `probeEndpoint`: Ollama by default, plus LM Studio, llama.cpp, vLLM or any custom URL |
54
+ | Plan usage | `fetchSubscriptionUsage`: remaining Claude, ChatGPT and Kimi plan usage |
55
+ | Paths | `getAppPaths`: every file GG Coder keeps under `~/.gg/` |
56
+ | Other | Logger, file lock, Telegram bot, voice transcription, auto-update |
57
+
58
+ `AuthStorage` shares `~/.gg/auth.json` with GG Coder, so a user who has signed in there is already signed in to your tool. Pass a different file path to the constructor to keep your own.
59
+
60
+ ## Lighter imports
61
+
62
+ Two subpaths load only what they need, which keeps startup fast:
63
+
64
+ ```ts
65
+ import { getModel } from "@kenkaiiii/gg-core/models";
66
+ import { getAppPaths } from "@kenkaiiii/gg-core/paths";
67
+ ```
68
+
69
+ Voice transcription uses two optional dependencies (`@huggingface/transformers`, `ogg-opus-decoder`). Everything else works without them.
70
+
71
+ ## The GG Framework
72
+
73
+ | Package | What it does |
74
+ | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
75
+ | [@kenkaiiii/gg-ai](https://www.npmjs.com/package/@kenkaiiii/gg-ai) | One streaming API for every provider |
76
+ | [@kenkaiiii/gg-agent](https://www.npmjs.com/package/@kenkaiiii/gg-agent) | The agent loop: runs tools and feeds results back to the model |
77
+ | **@kenkaiiii/gg-core** | Model list, sign-in and stored credentials, local model discovery (this package) |
78
+ | [@kenkaiiii/ggcoder](https://www.npmjs.com/package/@kenkaiiii/ggcoder) | The GG Coder coding agent: CLI, tools and sessions |
63
79
 
64
- ---
80
+ Source, issues and the desktop app: [github.com/KenKaiii/gg-framework](https://github.com/KenKaiii/gg-framework).
65
81
 
66
82
  ## License
67
83
 
68
- AGPL-3.0-only. See [LICENSE](../../LICENSE).
84
+ [AGPL-3.0-only](https://github.com/KenKaiii/gg-framework/blob/main/LICENSE). You can build on it; if you distribute your changes or run them as a network service, share their source under the same license.
@@ -1148,6 +1148,7 @@ import { setTimeout as setTimeout2 } from "timers/promises";
1148
1148
  var STALE_TIMEOUT_MS = 1e4;
1149
1149
  var RETRY_INTERVAL_MS = 50;
1150
1150
  var MAX_WAIT_MS = 5e3;
1151
+ var PENDING_DELETE_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
1151
1152
  async function withFileLock(filePath, fn) {
1152
1153
  const lockPath = filePath + ".lock";
1153
1154
  await acquireLock(lockPath);
@@ -1159,13 +1160,22 @@ async function withFileLock(filePath, fn) {
1159
1160
  }
1160
1161
  async function acquireLock(lockPath) {
1161
1162
  const startTime = Date.now();
1163
+ let refusedWithoutLock = 0;
1162
1164
  while (true) {
1163
1165
  try {
1164
1166
  const info = { pid: process.pid, timestamp: Date.now() };
1165
1167
  await fs.writeFile(lockPath, JSON.stringify(info), { flag: "wx" });
1166
1168
  return;
1167
1169
  } catch (err) {
1168
- if (err.code !== "EEXIST") throw err;
1170
+ const code = err.code;
1171
+ if (code !== "EEXIST") {
1172
+ if (process.platform !== "win32" || !code || !PENDING_DELETE_CODES.has(code)) throw err;
1173
+ const lockPresent = await lockFileExists(lockPath);
1174
+ if (!lockPresent && ++refusedWithoutLock > 3) throw err;
1175
+ if (Date.now() - startTime > MAX_WAIT_MS) throw err;
1176
+ await setTimeout2(RETRY_INTERVAL_MS);
1177
+ continue;
1178
+ }
1169
1179
  try {
1170
1180
  const content = await fs.readFile(lockPath, "utf-8");
1171
1181
  const info = JSON.parse(content);
@@ -1194,6 +1204,14 @@ async function acquireLock(lockPath) {
1194
1204
  }
1195
1205
  }
1196
1206
  }
1207
+ async function lockFileExists(lockPath) {
1208
+ try {
1209
+ await fs.stat(lockPath);
1210
+ return true;
1211
+ } catch (err) {
1212
+ return err.code !== "ENOENT";
1213
+ }
1214
+ }
1197
1215
  async function releaseLock(lockPath) {
1198
1216
  await fs.unlink(lockPath).catch(() => {
1199
1217
  });
@@ -3021,4 +3039,4 @@ export {
3021
3039
  getDefaultThinkingLevel,
3022
3040
  getSummaryModel
3023
3041
  };
3024
- //# sourceMappingURL=chunk-YXPGQIOD.js.map
3042
+ //# sourceMappingURL=chunk-SDUIKPGO.js.map