@trydecember/cli 0.4.9 → 0.4.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.
Files changed (3) hide show
  1. package/README.md +14 -0
  2. package/dist/december.js +175 -33
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -16,6 +16,20 @@ December is a (so much) better coding agent for terminal and cloud. It understan
16
16
 
17
17
  1. Install December:
18
18
 
19
+ macOS & Linux:
20
+
21
+ ```bash
22
+ curl -fsSL https://trydecember.com/install.sh | bash
23
+ ```
24
+
25
+ Windows:
26
+
27
+ ```powershell
28
+ irm https://trydecember.com/install.ps1 | iex
29
+ ```
30
+
31
+ npm:
32
+
19
33
  ```bash
20
34
  npm install -g @trydecember/cli
21
35
  ```
package/dist/december.js CHANGED
@@ -65,7 +65,7 @@ var package_default;
65
65
  var init_package = __esm(() => {
66
66
  package_default = {
67
67
  name: "@trydecember/cli",
68
- version: "0.4.9",
68
+ version: "0.4.10",
69
69
  description: "a (so much) better coding agent for terminal and cloud.",
70
70
  homepage: "https://trydecember.com",
71
71
  repository: {
@@ -106769,7 +106769,7 @@ function resolveAntigravityModel(model) {
106769
106769
  function antigravityProvider(token, options) {
106770
106770
  const endpoint = options?.endpoint || ANTIGRAVITY_DEFAULT_ENDPOINT;
106771
106771
  const fetchFn = options?.fetchFn || fetch;
106772
- const bearerToken = token || process.env.ANTIGRAVITY_TOKEN || process.env.GEMINI_OAUTH_TOKEN || process.env.GOOGLE_OAUTH_TOKEN || "dummy-key";
106772
+ let bearerToken = token || process.env.ANTIGRAVITY_TOKEN || process.env.GEMINI_OAUTH_TOKEN || process.env.GOOGLE_OAUTH_TOKEN || "dummy-key";
106773
106773
  return createProvider({
106774
106774
  id: "antigravity",
106775
106775
  name: "Antigravity",
@@ -106903,6 +106903,14 @@ function antigravityProvider(token, options) {
106903
106903
  model: resolveAntigravityModel(modelOptions?.model),
106904
106904
  request: innerRequest
106905
106905
  };
106906
+ if (options?.getToken) {
106907
+ try {
106908
+ const freshToken = await options.getToken();
106909
+ if (freshToken) {
106910
+ bearerToken = freshToken;
106911
+ }
106912
+ } catch {}
106913
+ }
106906
106914
  const headers = {
106907
106915
  "Content-Type": "application/json",
106908
106916
  Accept: "text/event-stream",
@@ -106918,6 +106926,24 @@ function antigravityProvider(token, options) {
106918
106926
  body: JSON.stringify(requestBody),
106919
106927
  signal
106920
106928
  });
106929
+ if (!response.ok && (response.status === 401 || response.status === 403) && options?.getToken) {
106930
+ try {
106931
+ const freshToken = await options.getToken();
106932
+ if (freshToken && freshToken !== bearerToken) {
106933
+ bearerToken = freshToken;
106934
+ headers.Authorization = `Bearer ${bearerToken}`;
106935
+ const retryResponse = await fetchFn(targetUrl, {
106936
+ method: "POST",
106937
+ headers,
106938
+ body: JSON.stringify(requestBody),
106939
+ signal
106940
+ });
106941
+ if (retryResponse.ok) {
106942
+ response = retryResponse;
106943
+ }
106944
+ }
106945
+ } catch {}
106946
+ }
106921
106947
  if (!response.ok && (response.status === 404 || response.status === 403 || response.status === 429 || response.status === 503)) {
106922
106948
  const fallbackEndpoint = endpoint.includes("daily-cloudcode-pa") ? endpoint.replace("daily-cloudcode-pa", "cloudcode-pa") : endpoint.includes("cloudcode-pa") && !endpoint.includes("daily-") ? endpoint.replace("cloudcode-pa", "daily-cloudcode-pa") : null;
106923
106949
  if (fallbackEndpoint) {
@@ -112944,6 +112970,7 @@ var init_gemini2 = __esm(() => {
112944
112970
  subscriptionType: "gemini_advanced",
112945
112971
  source: "local_import",
112946
112972
  updatedAt: Date.now(),
112973
+ expiresAt: Date.now() + 55 * 60 * 1000,
112947
112974
  extra: { source: "gcloud_cli" }
112948
112975
  };
112949
112976
  }
@@ -112951,6 +112978,17 @@ var init_gemini2 = __esm(() => {
112951
112978
  },
112952
112979
  async refreshToken(bundle) {
112953
112980
  if (!bundle.refreshToken) {
112981
+ if (bundle.extra?.source === "gcloud_cli") {
112982
+ const fresh = getGcloudToken();
112983
+ if (fresh) {
112984
+ return {
112985
+ ...bundle,
112986
+ accessToken: fresh,
112987
+ updatedAt: Date.now(),
112988
+ expiresAt: Date.now() + 55 * 60 * 1000
112989
+ };
112990
+ }
112991
+ }
112954
112992
  return bundle;
112955
112993
  }
112956
112994
  const clientId = bundle.extra?.client_id || process.env.GOOGLE_OAUTH_CLIENT_ID || process.env.GEMINI_OAUTH_CLIENT_ID || DEFAULT_CLIENT_ID;
@@ -113087,6 +113125,8 @@ You can also run \`gcloud auth application-default login\` or set \`ANTIGRAVITY_
113087
113125
  return false;
113088
113126
  if (!bundle.accessToken && !bundle.refreshToken)
113089
113127
  return false;
113128
+ if (bundle.extra?.source === "gcloud_cli")
113129
+ return true;
113090
113130
  if (bundle.expiresAt && bundle.expiresAt < Date.now() && !bundle.refreshToken) {
113091
113131
  return false;
113092
113132
  }
@@ -113141,7 +113181,7 @@ async function resolveSubscriptionToken(provider, bundle) {
113141
113181
  return bundle;
113142
113182
  }
113143
113183
  const fiveMinutes = 5 * 60 * 1000;
113144
- const isExpiringSoon = !bundle.accessToken || bundle.expiresAt !== undefined && Date.now() >= bundle.expiresAt - fiveMinutes;
113184
+ const isExpiringSoon = !bundle.accessToken || bundle.expiresAt !== undefined && Date.now() >= bundle.expiresAt - fiveMinutes || bundle.expiresAt === undefined && bundle.refreshToken !== undefined && (bundle.updatedAt === undefined || Date.now() - bundle.updatedAt > 50 * 60 * 1000);
113145
113185
  const isCopilotRaw = bundle.provider === "copilot" && (bundle.accessToken.startsWith("gho_") || bundle.accessToken.startsWith("ghu_") || bundle.accessToken.startsWith("ghp_") || bundle.accessToken.startsWith("github_pat_"));
113146
113186
  if (isExpiringSoon || isCopilotRaw) {
113147
113187
  try {
@@ -113255,6 +113295,9 @@ function getLegacyConfigDir() {
113255
113295
  if (isTestEnv && home === os9.homedir()) {
113256
113296
  return path17.join(os9.tmpdir(), "december-test-config", ".config", "december");
113257
113297
  }
113298
+ if (process.env.XDG_CONFIG_HOME) {
113299
+ return path17.join(process.env.XDG_CONFIG_HOME, "december");
113300
+ }
113258
113301
  return path17.join(home, ".config", "december");
113259
113302
  }
113260
113303
  function getLegacyConfigFile() {
@@ -113313,15 +113356,36 @@ async function loadConfig() {
113313
113356
  throw readErr;
113314
113357
  }
113315
113358
  }
113316
- let config = JSON.parse(data);
113359
+ let config;
113360
+ try {
113361
+ config = JSON.parse(data);
113362
+ } catch {
113363
+ try {
113364
+ const repaired = data.replace(/,\s*([\]}])/g, "$1");
113365
+ config = JSON.parse(repaired);
113366
+ } catch {
113367
+ try {
113368
+ const backupFile = `${configFile}.corrupt.${Date.now()}`;
113369
+ await fs17.writeFile(backupFile, data, "utf-8");
113370
+ } catch {}
113371
+ return { providers: {} };
113372
+ }
113373
+ }
113317
113374
  try {
113318
113375
  const workspacePath = path17.join(process.cwd(), ".december", "settings.json");
113319
113376
  const wData = await fs17.readFile(workspacePath, "utf-8");
113320
113377
  const workspaceConfig = JSON.parse(wData);
113321
113378
  config = deepMergeSettings(config, workspaceConfig);
113322
113379
  } catch {}
113323
- if (!config.activeProvider && config.providers && Object.keys(config.providers).length > 0) {
113324
- config.activeProvider = Object.keys(config.providers)[0];
113380
+ if (!config.activeProvider) {
113381
+ if (config.providers && Object.keys(config.providers).length > 0) {
113382
+ config.activeProvider = Object.keys(config.providers)[0];
113383
+ } else if (config.subscriptions && Object.keys(config.subscriptions).length > 0) {
113384
+ config.activeProvider = Object.keys(config.subscriptions)[0];
113385
+ if (!config.authPriority) {
113386
+ config.authPriority = "subscription";
113387
+ }
113388
+ }
113325
113389
  }
113326
113390
  return config;
113327
113391
  } catch {
@@ -113372,21 +113436,24 @@ function resolveSubscriptionBundle(config) {
113372
113436
  if (activeProvider && config.subscriptions[activeProvider]) {
113373
113437
  return { provider: activeProvider, bundle: config.subscriptions[activeProvider] };
113374
113438
  }
113375
- const hasByokForActive = !!(activeProvider && config.providers && config.providers[activeProvider]);
113376
- if (config.authPriority === "subscription" || !hasByokForActive) {
113377
- if (activeProvider === "anthropic" && config.subscriptions["claude"]) {
113439
+ if (activeProvider) {
113440
+ if ((activeProvider === "anthropic" || activeProvider === "claude") && config.subscriptions["claude"]) {
113378
113441
  return { provider: "claude", bundle: config.subscriptions["claude"] };
113379
113442
  }
113380
- if (activeProvider === "openai" && config.subscriptions["codex"]) {
113443
+ if ((activeProvider === "openai" || activeProvider === "codex" || activeProvider === "chatgpt") && config.subscriptions["codex"]) {
113381
113444
  return { provider: "codex", bundle: config.subscriptions["codex"] };
113382
113445
  }
113383
- if (activeProvider === "google" && config.subscriptions["gemini"]) {
113384
- return { provider: "gemini", bundle: config.subscriptions["gemini"] };
113446
+ if ((activeProvider === "google" || activeProvider === "gemini" || activeProvider === "antigravity") && (config.subscriptions["gemini"] || config.subscriptions["google"] || config.subscriptions["antigravity"])) {
113447
+ const bundle = config.subscriptions["gemini"] || config.subscriptions["google"] || config.subscriptions["antigravity"];
113448
+ return { provider: bundle.provider || "gemini", bundle };
113385
113449
  }
113386
113450
  }
113387
- if (config.authPriority === "subscription") {
113451
+ const hasByokForActive = !!(activeProvider && config.providers && config.providers[activeProvider]);
113452
+ if (config.authPriority === "subscription" || !hasByokForActive || !activeProvider) {
113388
113453
  const firstKey = Object.keys(config.subscriptions)[0];
113389
- return { provider: firstKey, bundle: config.subscriptions[firstKey] };
113454
+ if (firstKey && config.subscriptions[firstKey]) {
113455
+ return { provider: firstKey, bundle: config.subscriptions[firstKey] };
113456
+ }
113390
113457
  }
113391
113458
  return;
113392
113459
  }
@@ -113412,7 +113479,7 @@ async function getProviderConfig() {
113412
113479
  authMethod: "byok"
113413
113480
  };
113414
113481
  }
113415
- if (subMatch && config.authPriority !== "byok" && config.authPriority !== "december") {
113482
+ if (subMatch && (config.authPriority === "subscription" || !hasByokConfig && config.authPriority !== "december" || config.authPriority !== "byok" && config.authPriority !== "december")) {
113416
113483
  await Promise.resolve().then(() => init_subscription_manager());
113417
113484
  const resolvedBundle = await resolveSubscriptionToken(subMatch.provider, subMatch.bundle);
113418
113485
  const targetProvider = resolvedBundle.provider || subMatch.provider;
@@ -114781,7 +114848,7 @@ function isPermissionDeniedError2(errMsg) {
114781
114848
  }
114782
114849
  function detectInstallMethod(options) {
114783
114850
  const configMethod = options?.configInstallMethod;
114784
- const validMethods = ["npm", "bun", "pnpm", "npx", "source"];
114851
+ const validMethods = ["npm", "bun", "pnpm", "npx", "curl", "source"];
114785
114852
  if (configMethod && validMethods.includes(configMethod)) {
114786
114853
  return configMethod;
114787
114854
  }
@@ -114803,6 +114870,9 @@ function detectInstallMethod(options) {
114803
114870
  if (combined.includes("/_npx/") || combined.includes("\\_npx\\") || combined.includes("/.bunx/") || env.npm_config_user_agent?.includes("npx")) {
114804
114871
  return "npx";
114805
114872
  }
114873
+ if (execPath.includes(".december/bin") || combined.includes(".december/bin") || execPath.includes(".local/bin/december") || combined.includes(".local/bin/december") || execPath.endsWith("/december") && !execPath.includes("node_modules") && !execPath.includes(".bun") && !execPath.includes("/node") || execPath.endsWith("/december.exe") || combined.includes("december.exe")) {
114874
+ return "curl";
114875
+ }
114806
114876
  if (combined.includes(".bun/bin") || combined.includes("/.bun/") || execPath.includes("/bun") && !execPath.endsWith("/node")) {
114807
114877
  return "bun";
114808
114878
  }
@@ -114813,6 +114883,15 @@ function detectInstallMethod(options) {
114813
114883
  }
114814
114884
  function getUpdateCommand(method, _platform = process.platform) {
114815
114885
  switch (method) {
114886
+ case "curl": {
114887
+ const isWin = _platform === "win32" || process.platform === "win32";
114888
+ const cmd = isWin ? 'powershell -c "irm https://trydecember.com/install.ps1 | iex"' : "curl -fsSL https://trydecember.com/install.sh | bash";
114889
+ return {
114890
+ command: cmd,
114891
+ manualCmd: cmd,
114892
+ description: isWin ? "Standalone binary via PowerShell installer" : "Standalone binary via curl installer"
114893
+ };
114894
+ }
114816
114895
  case "bun": {
114817
114896
  return {
114818
114897
  command: "bun add -g @trydecember/cli@latest",
@@ -114874,8 +114953,8 @@ async function performCliUpdate(options) {
114874
114953
  });
114875
114954
  if (!options?.configInstallMethod && preDiagnosis?.activeBinary?.manager) {
114876
114955
  const activeMgr = preDiagnosis.activeBinary.manager;
114877
- if (activeMgr === "bun" || activeMgr === "npm" || activeMgr === "pnpm" || activeMgr === "source") {
114878
- detectedMethod = activeMgr;
114956
+ if (activeMgr === "bun" || activeMgr === "npm" || activeMgr === "pnpm" || activeMgr === "curl" || activeMgr === "standalone" || activeMgr === "source") {
114957
+ detectedMethod = activeMgr === "standalone" ? "curl" : activeMgr;
114879
114958
  }
114880
114959
  }
114881
114960
  const method = detectedMethod;
@@ -114892,6 +114971,19 @@ async function performCliUpdate(options) {
114892
114971
  output: msg
114893
114972
  };
114894
114973
  }
114974
+ if (method === "curl") {
114975
+ const msg = `Standalone installation detected. To update, re-run the installer:
114976
+ ${manualCmd}`;
114977
+ options?.onProgress?.(msg);
114978
+ return {
114979
+ success: true,
114980
+ method: "curl",
114981
+ command,
114982
+ manualCmd,
114983
+ verified: true,
114984
+ output: msg
114985
+ };
114986
+ }
114895
114987
  if (method === "npx") {
114896
114988
  const msg = "Running December CLI via npx/bunx. Each invocation automatically uses the latest version.";
114897
114989
  options?.onProgress?.(msg);
@@ -176865,11 +176957,26 @@ function instantiateProvider(provider, apiKey, options) {
176865
176957
  }
176866
176958
  return openaiProvider(undefined, apiKey);
176867
176959
  }
176868
- case "antigravity":
176960
+ case "antigravity": {
176961
+ const subscription = options?.subscription;
176962
+ const getToken = subscription ? async () => {
176963
+ try {
176964
+ const refreshed = await resolveSubscriptionToken("gemini", subscription);
176965
+ if (refreshed?.accessToken) {
176966
+ subscription.accessToken = refreshed.accessToken;
176967
+ subscription.expiresAt = refreshed.expiresAt;
176968
+ subscription.endpoint = refreshed.endpoint;
176969
+ return refreshed.accessToken;
176970
+ }
176971
+ } catch {}
176972
+ return subscription.accessToken;
176973
+ } : undefined;
176869
176974
  return antigravityProvider(apiKey, {
176870
176975
  endpoint: options?.baseURL,
176871
- headers: options?.headers
176976
+ headers: options?.headers,
176977
+ getToken
176872
176978
  });
176979
+ }
176873
176980
  case "claude":
176874
176981
  case "anthropic": {
176875
176982
  if (options?.authMethod === "subscription" || options?.subscription) {
@@ -176888,9 +176995,23 @@ function instantiateProvider(provider, apiKey, options) {
176888
176995
  case "google": {
176889
176996
  if (options?.authMethod === "subscription" || options?.subscription) {
176890
176997
  const endpoint = options?.baseURL || options?.subscription?.endpoint;
176998
+ const subscription = options?.subscription;
176999
+ const getToken = subscription ? async () => {
177000
+ try {
177001
+ const refreshed = await resolveSubscriptionToken("gemini", subscription);
177002
+ if (refreshed?.accessToken) {
177003
+ subscription.accessToken = refreshed.accessToken;
177004
+ subscription.expiresAt = refreshed.expiresAt;
177005
+ subscription.endpoint = refreshed.endpoint;
177006
+ return refreshed.accessToken;
177007
+ }
177008
+ } catch {}
177009
+ return subscription.accessToken;
177010
+ } : undefined;
176891
177011
  return antigravityProvider(apiKey, {
176892
177012
  endpoint,
176893
- headers: options?.headers
177013
+ headers: options?.headers,
177014
+ getToken
176894
177015
  });
176895
177016
  }
176896
177017
  return geminiProvider(apiKey);
@@ -264868,7 +264989,7 @@ var init_header = __esm(async () => {
264868
264989
  })
264869
264990
  ]
264870
264991
  }),
264871
- announcement.bullets.map((bullet, idx) => /* @__PURE__ */ jsx_runtime17.jsxs(Box_default, {
264992
+ announcement.bullets.slice(0, 3).map((bullet, idx) => /* @__PURE__ */ jsx_runtime17.jsxs(Box_default, {
264872
264993
  children: [
264873
264994
  /* @__PURE__ */ jsx_runtime17.jsx(Text3, {
264874
264995
  color: THEME.colors.brand,
@@ -277012,6 +277133,24 @@ var init_use_agent_session = __esm(async () => {
277012
277133
  import_react71 = __toESM(require_react(), 1);
277013
277134
  });
277014
277135
 
277136
+ // src/utils/banner.ts
277137
+ function resolveAnnouncement(options) {
277138
+ const { config, isInline = false, isNewVersion = false, releaseHighlights } = options;
277139
+ if (config.showChangelogBanner === false) {
277140
+ return null;
277141
+ }
277142
+ if (!releaseHighlights || !Array.isArray(releaseHighlights.bullets) || releaseHighlights.bullets.length === 0) {
277143
+ return null;
277144
+ }
277145
+ if (isInline && !isNewVersion) {
277146
+ return null;
277147
+ }
277148
+ return {
277149
+ ...releaseHighlights,
277150
+ bullets: releaseHighlights.bullets.slice(0, 3)
277151
+ };
277152
+ }
277153
+
277015
277154
  // src/index.ts
277016
277155
  init_package();
277017
277156
  import path41 from "node:path";
@@ -277152,12 +277291,12 @@ Options:
277152
277291
  }
277153
277292
  // src/constants/release-highlights.json
277154
277293
  var release_highlights_default = {
277155
- version: "0.4.9",
277156
- title: "What's New in v0.4.9",
277294
+ version: "0.4.10",
277295
+ title: "What's New in v0.4.10",
277157
277296
  bullets: [
277158
- "*(tui)* Remove expand mode and make thoughts transient with live topic tracking",
277159
- "*(tui)* Implement ephemeral discovery and silent reads for clean terminal history",
277160
- "*(cli)* Stream transient thinking topics and initialize turn with thinking status"
277297
+ "Restore curl and powershell installers with client os detection and binary releases",
277298
+ "Use official gnu bash and powershell vector icons in install dropdown",
277299
+ "Show changelog highlights on every launch capped to 3 bullets"
277161
277300
  ],
277162
277301
  url: "https://trydecember.com/docs/changelog"
277163
277302
  };
@@ -277488,15 +277627,18 @@ Executing Headless Task: "${parsedArgs.prompt}"
277488
277627
  agent.loadContext().catch(() => {});
277489
277628
  }
277490
277629
  await Promise.resolve().then(() => init_bin_discovery());
277491
- const isFirstRun = !config.lastSeenVersion || compareVersions(package_default.version, config.lastSeenVersion) > 0;
277492
- let announcement = null;
277493
- if (isFirstRun) {
277494
- if (release_highlights_default && Array.isArray(release_highlights_default.bullets) && release_highlights_default.bullets.length > 0) {
277495
- announcement = release_highlights_default;
277496
- }
277630
+ const isNewVersion = !config.lastSeenVersion || compareVersions(package_default.version, config.lastSeenVersion) > 0;
277631
+ if (isNewVersion) {
277497
277632
  config.lastSeenVersion = package_default.version;
277498
277633
  saveConfig(config).catch(() => {});
277499
277634
  }
277635
+ await Promise.resolve();
277636
+ const announcement = resolveAnnouncement({
277637
+ config,
277638
+ isInline: parsedArgs.isInline,
277639
+ isNewVersion,
277640
+ releaseHighlights: release_highlights_default
277641
+ });
277500
277642
  function AppWrapper(props) {
277501
277643
  const [latestVersion, setLatestVersion] = React.useState(undefined);
277502
277644
  React.useEffect(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trydecember/cli",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
4
4
  "description": "a (so much) better coding agent for terminal and cloud.",
5
5
  "homepage": "https://trydecember.com",
6
6
  "repository": {