@adaptiqai/code 0.1.0 → 0.1.1

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 (2) hide show
  1. package/lib/index.js +122 -30
  2. package/package.json +2 -2
package/lib/index.js CHANGED
@@ -23413,7 +23413,7 @@ function lex(text3, language) {
23413
23413
  let last = 0;
23414
23414
  let lastAt = -1;
23415
23415
  let heredoc = null;
23416
- const cut = (from, to, literal) => {
23416
+ const cut = (from, to, literal2) => {
23417
23417
  if (from > start) bare.push(text3.slice(start, from));
23418
23418
  const length = to - from;
23419
23419
  let breaks = 0;
@@ -23423,11 +23423,11 @@ function lex(text3, language) {
23423
23423
  depths.push(depth);
23424
23424
  }
23425
23425
  }
23426
- if (breaks === 0) bare.push(literal && length >= 2 ? `"${" ".repeat(length - 2)}"` : " ".repeat(length));
23426
+ if (breaks === 0) bare.push(literal2 && length >= 2 ? `"${" ".repeat(length - 2)}"` : " ".repeat(length));
23427
23427
  else {
23428
23428
  let blanked = text3.slice(from, to).replace(/[^\n]/g, " ");
23429
- if (literal && blanked[0] === " ") blanked = `"${blanked.slice(1)}`;
23430
- if (literal && blanked[blanked.length - 1] === " ") blanked = `${blanked.slice(0, -1)}"`;
23429
+ if (literal2 && blanked[0] === " ") blanked = `"${blanked.slice(1)}`;
23430
+ if (literal2 && blanked[blanked.length - 1] === " ") blanked = `${blanked.slice(0, -1)}"`;
23431
23431
  bare.push(blanked);
23432
23432
  }
23433
23433
  start = to;
@@ -26061,6 +26061,17 @@ var AdaptiqHttpError = class extends Error {
26061
26061
  }
26062
26062
  };
26063
26063
 
26064
+ // ../core/lib/tool-failures.js
26065
+ import { AsyncLocalStorage } from "node:async_hooks";
26066
+ var PASSING = [CODES.server, CODES.timeout, CODES.transport, CODES.busy, CODES.preparing, CODES.empty, CODES.conversationUnavailable];
26067
+ var inCall = new AsyncLocalStorage();
26068
+ async function sent(options, once) {
26069
+ const tries = inCall.getStore();
26070
+ return tries === void 0 || tries.ended ? await once() : await tries.send(options, once);
26071
+ }
26072
+ var UNKNOWN_TURN_MS = 2 * 6e4;
26073
+ var KEPT_MS = 10 * 6e4;
26074
+
26064
26075
  // ../core/lib/api.js
26065
26076
  var AdaptiqApi = class {
26066
26077
  apiBase;
@@ -26094,12 +26105,17 @@ var AdaptiqApi = class {
26094
26105
  return credential;
26095
26106
  }
26096
26107
  /**
26097
- * Call one JSON route.
26108
+ * Call one JSON route. Inside an agent tool's call, passing trouble is
26109
+ * asked again a few times first (tool-failures.ts).
26098
26110
  * @param path - path under the API origin, starting with `/v1/`.
26099
26111
  * @param options - method, body, headers, cancellation.
26100
26112
  * @returns the decoded body, or null for 204 and allowed statuses.
26101
26113
  */
26102
26114
  async json(path, options = {}) {
26115
+ return await sent(options, async () => await this.once(path, options));
26116
+ }
26117
+ /** One try of {@link json}. */
26118
+ async once(path, options) {
26103
26119
  let credential = await this.credential();
26104
26120
  for (let attempt = 0; attempt < 2; attempt++) {
26105
26121
  const response = await this.send(path, options, credential.token);
@@ -26123,10 +26139,18 @@ var AdaptiqApi = class {
26123
26139
  }
26124
26140
  if (response.status === 204)
26125
26141
  return null;
26142
+ let text3;
26126
26143
  try {
26127
- return await response.json();
26128
- } catch {
26144
+ text3 = await response.text();
26145
+ } catch (error) {
26146
+ throw new AdaptiqHttpError(transportFailure(error));
26147
+ }
26148
+ if (text3.trim() === "")
26129
26149
  return null;
26150
+ try {
26151
+ return JSON.parse(text3);
26152
+ } catch (error) {
26153
+ throw new AdaptiqHttpError(transportFailure(error));
26130
26154
  }
26131
26155
  }
26132
26156
  return null;
@@ -26157,6 +26181,7 @@ var AdaptiqApi = class {
26157
26181
  import { createHash as createHash2, randomUUID } from "node:crypto";
26158
26182
  import { hostname } from "node:os";
26159
26183
  var REFRESH_MARGIN_MS = 2 * 6e4;
26184
+ var EARLY_REFRESH_PAUSE_MS = 3e4;
26160
26185
  var DEVICE_TIMEOUT_MS = 10 * 6e4;
26161
26186
  var UNREACHABLE = "AdaptiqAI can't be reached. Check your internet connection and try again.";
26162
26187
  function deviceLabel(value) {
@@ -26304,6 +26329,10 @@ var AuthManager = class {
26304
26329
  source = null;
26305
26330
  label = null;
26306
26331
  refreshing = null;
26332
+ /** When a refresh made before the token ran out last failed. */
26333
+ earlyRefreshFailedAt = -Infinity;
26334
+ /** API keys the server refused (401) in this process: never sent again. */
26335
+ refusedKeys = /* @__PURE__ */ new Set();
26307
26336
  constructor(options) {
26308
26337
  this.options = options;
26309
26338
  this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
@@ -26346,7 +26375,7 @@ var AuthManager = class {
26346
26375
  this.set("connected");
26347
26376
  return;
26348
26377
  }
26349
- if (await this.options.store.apiKey() !== void 0) {
26378
+ if (await this.usableKey() !== void 0) {
26350
26379
  this.source = "api-key";
26351
26380
  this.set("connected");
26352
26381
  return;
@@ -26361,17 +26390,30 @@ var AuthManager = class {
26361
26390
  async credential() {
26362
26391
  const stored = await this.options.store.read();
26363
26392
  if (stored !== void 0 && stored.apiBase === this.options.apiBase) {
26364
- if (stored.expiresAt - this.now() > REFRESH_MARGIN_MS) {
26393
+ const current = () => {
26365
26394
  if (this.state !== "connected" && this.state !== "signing-in") {
26366
26395
  this.source = "device";
26367
26396
  this.label = stored.workspaceLabel;
26368
26397
  this.set("connected");
26369
26398
  }
26370
26399
  return { kind: "device", token: stored.access, workspaceLabel: stored.workspaceLabel };
26400
+ };
26401
+ const left = stored.expiresAt - this.now();
26402
+ if (left > REFRESH_MARGIN_MS)
26403
+ return current();
26404
+ if (left > 0) {
26405
+ if (this.now() - this.earlyRefreshFailedAt < EARLY_REFRESH_PAUSE_MS)
26406
+ return current();
26407
+ try {
26408
+ return await this.refresh(stored.access);
26409
+ } catch {
26410
+ this.earlyRefreshFailedAt = this.now();
26411
+ return current();
26412
+ }
26371
26413
  }
26372
26414
  return await this.refresh(stored.access);
26373
26415
  }
26374
- const key = await this.options.store.apiKey();
26416
+ const key = await this.usableKey();
26375
26417
  if (key !== void 0) {
26376
26418
  if (this.state === "signed-out") {
26377
26419
  this.source = "api-key";
@@ -26443,7 +26485,8 @@ var AuthManager = class {
26443
26485
  }
26444
26486
  /**
26445
26487
  * React to a 401 on a request made with `token`: rotate once for a device
26446
- * credential; an API key cannot recover, so the connection counts as expired.
26488
+ * credential; a refused API key is skipped for the next one the harness
26489
+ * has, and with none left the connection counts as expired.
26447
26490
  * @param token - the rejected access token.
26448
26491
  * @returns a fresh credential to retry with, or undefined.
26449
26492
  */
@@ -26453,10 +26496,20 @@ var AuthManager = class {
26453
26496
  return await this.refresh(token);
26454
26497
  if (stored !== void 0)
26455
26498
  return await this.credential();
26499
+ this.refusedKeys.add(token);
26500
+ const next = await this.usableKey();
26501
+ if (next !== void 0)
26502
+ return { kind: "api-key", token: next, workspaceLabel: null };
26456
26503
  this.source = null;
26457
26504
  this.set("expired");
26458
26505
  return void 0;
26459
26506
  }
26507
+ /** @returns the first API key the server has not refused, if any. */
26508
+ async usableKey() {
26509
+ const store = this.options.store;
26510
+ const keys = store.apiKeys === void 0 ? [await store.apiKey()] : await store.apiKeys();
26511
+ return keys.find((key) => key !== void 0 && key !== "" && !this.refusedKeys.has(key));
26512
+ }
26460
26513
  /**
26461
26514
  * Start a browser approval. The poll continues in the background; the
26462
26515
  * returned link and code are what the person needs.
@@ -26620,6 +26673,7 @@ var FOLLOW_MS = 3 * 36e5;
26620
26673
 
26621
26674
  // ../core/lib/update.js
26622
26675
  var RELEASE_AGE_MS = 24 * 36e5;
26676
+ var OFFER_AGE_MS = 48 * 36e5;
26623
26677
 
26624
26678
  // ../core/lib/workspace.js
26625
26679
  var UNDO_WINDOW_MS = 15 * 6e4;
@@ -26630,13 +26684,51 @@ var ATTACH_BACKOFF_MAX_MS = 10 * 6e4;
26630
26684
  var ATTACH_DEADLINE_MS = 6 * 36e5;
26631
26685
  var SESSION_BACKOFF_MAX_MS = 5 * 6e4;
26632
26686
 
26687
+ // ../core/lib/commands.js
26688
+ var ACTIONS = [
26689
+ ["", "workspace, models and memory"],
26690
+ ["signin", "connect your AdaptiqAI account in the browser"],
26691
+ ["private", "stop saving new messages of this conversation"],
26692
+ ["remember", "save this conversation to memory again"],
26693
+ ["knowledge", "knowledge used in this conversation, and what else you can use"],
26694
+ ["use <name>", "use a collection or an earlier conversation here"],
26695
+ ["stop <name>", "stop using it here (nothing is deleted)"],
26696
+ ["open", "open this conversation in AdaptiqAI Knowledge"],
26697
+ ["diagnostics", "a report you can send to support (no secrets)"],
26698
+ ["signout", "forget the connection on this computer"]
26699
+ ];
26700
+ var COMMAND_HINT = ["status", ...ACTIONS.slice(1).map(([action]) => action.split(" ")[0])].join(" \xB7 ");
26701
+
26702
+ // ../core/lib/preparing.js
26703
+ var PREPARING_MOST_MS = 15 * 6e4;
26704
+
26705
+ // ../core/lib/reading.js
26706
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
26707
+
26708
+ // ../core/lib/series.js
26709
+ var MONTHS = [
26710
+ "januar februar marts april maj juni juli august september oktober november december",
26711
+ "january february march april may june july august september october november december",
26712
+ "jan feb mar apr maj jun jul aug sep okt nov dec",
26713
+ "jan feb mar apr may jun jul aug sep oct nov dec"
26714
+ ].map((words) => words.split(" "));
26715
+ var TOKEN = new RegExp(`(\\d+|(?<!\\p{L})(?:${[...new Set(MONTHS.flat())].sort((a, b) => b.length - a.length).join("|")})(?!\\p{L}))`, "iu");
26716
+
26633
26717
  // ../core/lib/reading.js
26634
26718
  var READ_PER_REPLY = 13e4;
26635
- var READING_NOTE = `A collection used here is in your memory, but a large one is read in parts: each reply reads what matches the conversation (about ${formatTokens(READ_PER_REPLY)} tokens of it), never all of it at once. To work in it: contents lists its documents; find searches its text for words and gives the exact lines as document:line; open reads one document (around a line, if given) in your next reply. Before you say something is not there, find it; for an overview, take contents first; answer from what you read, citing document:line.`;
26719
+ var READING_NOTE = `A collection used here is in your memory, but a large one is read in parts: each reply reads what matches the conversation (about ${formatTokens(READ_PER_REPLY)} tokens of it), never all of it at once. contents lists its documents; open shows a document's exact lines (around a line, if given; more: true reads on). Before you say something is not there, find it; for an overview, take contents first. Answer from what these actions return, citing document:line as a result shows it, and never name a document or a line no result showed.`;
26720
+ var READS_IDLE_MS = 10 * 6e4;
26721
+ var ORIGINAL_BYTES = 16 * 1024 * 1024;
26722
+ var KNOWN_CHARS = 32 * 1024 * 1024;
26723
+ var calls = new AsyncLocalStorage2();
26636
26724
 
26637
26725
  // ../core/lib/tools.js
26638
26726
  var SOURCE_LIMIT = 6 * 1024 * 1024;
26639
26727
 
26728
+ // ../core/lib/turns.js
26729
+ var OFFER = new RegExp("(?<!\\p{L})(?:knowledge|collection|ncm|viden|samling)|\u77E5\u8BC6|\u96C6\u5408", "iu");
26730
+ var OFFER_DOES = new RegExp("(?<!\\p{L})(?:save|make|create|add|put|keep|store|turn|remember|gem|gemme|lav|lave|opret|oprette|tilf\xF8j|tilf\xF8je|l\xE6g|l\xE6gge)(?!\\p{L})|\u4FDD\u5B58|\u521B\u5EFA|\u505A\u6210|\u653E\u8FDB|\u52A0\u5165|\u5B58", "iu");
26731
+
26640
26732
  // src/ncm/client.ts
26641
26733
  var import_undici = __toESM(require_undici(), 1);
26642
26734
  var READY_TIMEOUT_MS = 30 * 6e4;
@@ -27012,7 +27104,7 @@ var NcmClient = class {
27012
27104
  };
27013
27105
  async function readStream(response, started, withTools = false) {
27014
27106
  let text3 = "";
27015
- const calls = [];
27107
+ const calls2 = [];
27016
27108
  let first = null;
27017
27109
  let usage = {};
27018
27110
  let finish = null;
@@ -27043,7 +27135,7 @@ async function readStream(response, started, withTools = false) {
27043
27135
  if (typeof choice.finish_reason === "string") finish = choice.finish_reason;
27044
27136
  const delta = choice.delta ?? {};
27045
27137
  for (const part of delta.tool_calls ?? []) {
27046
- const call = calls[part.index ?? calls.length] ??= { id: "", name: "", arguments: "" };
27138
+ const call = calls2[part.index ?? calls2.length] ??= { id: "", name: "", arguments: "" };
27047
27139
  if (part.id !== void 0) call.id = part.id;
27048
27140
  if (part.function?.name !== void 0) call.name += part.function.name;
27049
27141
  if (part.function?.arguments !== void 0) call.arguments += part.function.arguments;
@@ -27056,7 +27148,7 @@ async function readStream(response, started, withTools = false) {
27056
27148
  }
27057
27149
  if (done2) break;
27058
27150
  }
27059
- const toolCalls = calls.filter((call) => call !== void 0 && call.name !== "").map((call, index) => ({ ...call, id: call.id || `call-${index}` }));
27151
+ const toolCalls = calls2.filter((call) => call !== void 0 && call.name !== "").map((call, index) => ({ ...call, id: call.id || `call-${index}` }));
27060
27152
  if (withTools && toolCalls.length > 0) {
27061
27153
  const number2 = (value) => typeof value === "number" ? value : null;
27062
27154
  return { text: text3.trim(), ttftMs: first, promptTokens: number2(usage.prompt_tokens), cachedTokens: number2((usage.prompt_tokens_details ?? {}).cached_tokens), completionTokens: number2(usage.completion_tokens), toolCalls };
@@ -27083,7 +27175,7 @@ import { spawn } from "node:child_process";
27083
27175
  import { mkdir, open, readFile as readFile2, rename, rm, stat, writeFile } from "node:fs/promises";
27084
27176
  import { homedir, hostname as hostname2 } from "node:os";
27085
27177
  import { join as join3 } from "node:path";
27086
- var VERSION = true ? "0.1.0" : "0.0.0";
27178
+ var VERSION = true ? "0.1.1" : "0.0.0";
27087
27179
  var DEFAULT_API_BASE = "https://api.adaptiqai.com";
27088
27180
  function signInDir(env = process.env) {
27089
27181
  return join3(env.XDG_CONFIG_HOME || join3(homedir(), ".config"), "adaptiq", "mcp");
@@ -28450,17 +28542,17 @@ ${options.system ?? role.system}`,
28450
28542
  let answer2 = await this.deps.memory.ask(collections, turn, { ...common, history, ...tools === void 0 ? {} : { tools } });
28451
28543
  const spent = { prompt: answer2.promptTokens ?? 0, cached: answer2.cachedTokens ?? 0, completion: answer2.completionTokens ?? 0, lookups: 0, fallbacks: 0 };
28452
28544
  for (let step = 1; view !== void 0 && (answer2.toolCalls?.length ?? 0) > 0; step++) {
28453
- const calls = answer2.toolCalls;
28454
- spent.lookups += calls.length;
28545
+ const calls2 = answer2.toolCalls;
28546
+ spent.lookups += calls2.length;
28455
28547
  const last = step >= MAX_TOOL_STEPS;
28456
- const looked = await Promise.all(calls.map((call) => runLookup(call, view)));
28548
+ const looked = await Promise.all(calls2.map((call) => runLookup(call, view)));
28457
28549
  spent.fallbacks += looked.filter((result) => result.fellBack).length;
28458
- const results = calls.map((call, index) => ({ role: "tool", tool_call_id: call.id, content: looked[index].text }));
28550
+ const results = calls2.map((call, index) => ({ role: "tool", tool_call_id: call.id, content: looked[index].text }));
28459
28551
  const after = results.at(-1);
28460
28552
  history = [
28461
28553
  ...history,
28462
28554
  ...turn === "" ? [] : [{ role: "user", content: turn }],
28463
- { role: "assistant", content: answer2.text, tool_calls: calls.map((call) => ({ id: call.id, type: "function", function: { name: call.name, arguments: call.arguments } })) },
28555
+ { role: "assistant", content: answer2.text, tool_calls: calls2.map((call) => ({ id: call.id, type: "function", function: { name: call.name, arguments: call.arguments } })) },
28464
28556
  ...results.slice(0, -1),
28465
28557
  { ...after, content: `${after.content}
28466
28558
 
@@ -29268,7 +29360,7 @@ async function createCodeApp(cwd, options = {}) {
29268
29360
  return await skipped("This worktree is not compiled yet; `adaptiqai-code sync` here compiles it.");
29269
29361
  }
29270
29362
  }
29271
- const sent = await states.exclusive(async () => {
29363
+ const sent2 = await states.exclusive(async () => {
29272
29364
  const current = await scan();
29273
29365
  const saved = await state2();
29274
29366
  const previous = saved?.base ?? null;
@@ -29317,13 +29409,13 @@ async function createCodeApp(cwd, options = {}) {
29317
29409
  await states.save(next);
29318
29410
  return { plan, collection: track.collection, desired, pending: desired !== null && desired !== track.version };
29319
29411
  });
29320
- const wait = sent.plan.kind !== "none" || sent.pending && opts.background !== true;
29321
- if (wait && opts.noWait !== true && sent.collection !== "") {
29412
+ const wait = sent2.plan.kind !== "none" || sent2.pending && opts.background !== true;
29413
+ if (wait && opts.noWait !== true && sent2.collection !== "") {
29322
29414
  try {
29323
- const ready = await service.ready(sent.collection, sent.desired, opts.signal === void 0 ? {} : { signal: opts.signal });
29415
+ const ready = await service.ready(sent2.collection, sent2.desired, opts.signal === void 0 ? {} : { signal: opts.signal });
29324
29416
  await states.exclusive(async () => {
29325
29417
  const saved = await state2();
29326
- if (saved?.base == null || saved.base.collection !== sent.collection || (saved.desiredVersion ?? null) !== sent.desired) return;
29418
+ if (saved?.base == null || saved.base.collection !== sent2.collection || (saved.desiredVersion ?? null) !== sent2.desired) return;
29327
29419
  const next = { ...saved, base: { ...saved.base, version: ready.activeVersion, tokens: ready.tokens ?? saved.base.tokens }, pendingFiles: [] };
29328
29420
  await states.save(next);
29329
29421
  });
@@ -29332,9 +29424,9 @@ async function createCodeApp(cwd, options = {}) {
29332
29424
  }
29333
29425
  }
29334
29426
  return {
29335
- changed: sent.plan.kind !== "none",
29336
- rebuiltBase: sent.plan.kind === "rebuild",
29337
- overlayFiles: sent.plan.updated.length + sent.plan.deleted.length,
29427
+ changed: sent2.plan.kind !== "none",
29428
+ rebuiltBase: sent2.plan.kind === "rebuild",
29429
+ overlayFiles: sent2.plan.updated.length + sent2.plan.deleted.length,
29338
29430
  seconds: (now() - started) / 1e3,
29339
29431
  status: await status()
29340
29432
  };
@@ -30675,7 +30767,7 @@ async function serve(handlers, input, output) {
30675
30767
  }
30676
30768
 
30677
30769
  // src/mcp/server.ts
30678
- var VERSION2 = true ? "0.1.0" : "0.0.0";
30770
+ var VERSION2 = true ? "0.1.1" : "0.0.0";
30679
30771
  var PROTOCOLS = ["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"];
30680
30772
  var INSTRUCTIONS_LIMIT = 4e3;
30681
30773
  var MAX_FANOUT2 = 16;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptiqai/code",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "AdaptiqAI Code: your whole repository compiled into the model's memory, kept current from git, shared by every agent and sub-agent.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -44,7 +44,7 @@
44
44
  "typescript": "~5.9.3",
45
45
  "undici": "~7.16.0",
46
46
  "vitest": "~3.2.7",
47
- "@adaptiqai/core": "0.2.14"
47
+ "@adaptiqai/core": "0.2.16"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "node scripts/build.mjs",