@ycodium-ai/agent-grok 0.2.2888 → 0.2.2896

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/dist/index.js +189 -70
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -160,7 +160,7 @@ var GROK_CARD = {
160
160
  // src/grokInstance.ts
161
161
  import * as NodeCrypto2 from "node:crypto";
162
162
  import * as NodeOS2 from "node:os";
163
- import * as NodePath4 from "node:path";
163
+ import * as NodePath5 from "node:path";
164
164
  import { mergeLaunchEnv } from "@ycodium-ai/plugin-api/executor";
165
165
  import { nodeStreamsFromHandle as nodeStreamsFromHandle2 } from "@ycodium-ai/plugin-api/process-stdin";
166
166
 
@@ -24194,6 +24194,60 @@ function approvalOutcomeForDecision(decision, optionId) {
24194
24194
  return decision !== "cancel" && optionId !== void 0 ? { outcome: "selected", optionId } : { outcome: "cancelled" };
24195
24195
  }
24196
24196
 
24197
+ // ../../packages/ycodium-acp-executor/src/artifacts.ts
24198
+ import * as NodePath from "node:path";
24199
+ import * as NodeURL from "node:url";
24200
+ function resourceLinkArtifacts(content) {
24201
+ if (content["type"] !== "resource_link" || typeof content["uri"] !== "string") return [];
24202
+ const uri = content["uri"].trim();
24203
+ let path;
24204
+ try {
24205
+ path = uri.toLowerCase().startsWith("file:") ? NodeURL.fileURLToPath(uri) : uri;
24206
+ } catch {
24207
+ return [];
24208
+ }
24209
+ if (!NodePath.isAbsolute(path)) return [];
24210
+ const name = typeof content["name"] === "string" ? content["name"].trim() : "";
24211
+ const mimeType = typeof content["mimeType"] === "string" ? content["mimeType"].trim() : "";
24212
+ return [
24213
+ {
24214
+ path,
24215
+ ...name.length > 0 ? { name } : {},
24216
+ ...mimeType.length > 0 ? { mimeType } : {}
24217
+ }
24218
+ ];
24219
+ }
24220
+ function acpArtifactEvent(input2) {
24221
+ if (input2.artifacts.length === 0) return void 0;
24222
+ const { toolCallId } = input2;
24223
+ return {
24224
+ ...input2.base,
24225
+ type: "assistant.artifact.produced",
24226
+ payload: {
24227
+ artifacts: input2.artifacts.map((artifact) => ({
24228
+ ...artifact,
24229
+ ...toolCallId !== void 0 ? { toolCallId } : {}
24230
+ }))
24231
+ }
24232
+ };
24233
+ }
24234
+ function makeArtifactEmitter(input2) {
24235
+ return (artifacts, toolCallId) => {
24236
+ const turnId = input2.turnId();
24237
+ const event = acpArtifactEvent({
24238
+ artifacts,
24239
+ toolCallId,
24240
+ base: {
24241
+ ...input2.stamp(),
24242
+ provider: input2.options.provider,
24243
+ threadId: input2.options.threadId,
24244
+ ...turnId === void 0 ? {} : { turnId }
24245
+ }
24246
+ });
24247
+ if (event !== void 0) input2.emit(event);
24248
+ };
24249
+ }
24250
+
24197
24251
  // ../../packages/ycodium-acp-executor/src/event-stream.ts
24198
24252
  var UnboundedEventStream = class {
24199
24253
  subscribers = /* @__PURE__ */ new Set();
@@ -25599,9 +25653,8 @@ function createAcpExecutor(options) {
25599
25653
  options.originBindingGeneration === void 0 ? event : { ...event, originBindingGeneration: options.originBindingGeneration }
25600
25654
  );
25601
25655
  };
25602
- const emit = (event) => {
25603
- publish(event);
25604
- };
25656
+ const emit = publish;
25657
+ const emitArtifacts = makeArtifactEmitter({ emit, stamp, options, turnId: () => activeTurnId });
25605
25658
  const failIfDisposed = () => {
25606
25659
  if (disposed) {
25607
25660
  throw new AcpExecutorDisposedError();
@@ -25704,6 +25757,8 @@ function createAcpExecutor(options) {
25704
25757
  payload: taskEvent.payload
25705
25758
  });
25706
25759
  }
25760
+ if (nextToolCall.status === "completed" && hookResult && "artifacts" in hookResult)
25761
+ emitArtifacts(hookResult.artifacts ?? [], nextToolCall.toolCallId);
25707
25762
  if (handledByHook || !decision.emit) {
25708
25763
  continue;
25709
25764
  }
@@ -25723,6 +25778,10 @@ function createAcpExecutor(options) {
25723
25778
  );
25724
25779
  continue;
25725
25780
  }
25781
+ if (event._tag === "AssistantContentBlock") {
25782
+ emitArtifacts(resourceLinkArtifacts(event.content));
25783
+ continue;
25784
+ }
25726
25785
  if (event._tag === "CompactionUpdated") {
25727
25786
  applyCompactionUpdate(event);
25728
25787
  continue;
@@ -26931,9 +26990,69 @@ function tokenizeLaunchArgs(value) {
26931
26990
  return tokens;
26932
26991
  }
26933
26992
 
26993
+ // src/deviceCodeOutput.ts
26994
+ var OUTPUT_QUIET_MS = 3e3;
26995
+ var SILENT_CAP_MS = 3e4;
26996
+ var DEVICE_CODE_URL = /https?:\/\/\S+/;
26997
+ var DEVICE_CODE_VALUE = /\b([A-Z0-9]{4,}(?:-[A-Z0-9]{4,})+)\b/;
26998
+ var deviceCodeUrl = (output2) => DEVICE_CODE_URL.exec(output2)?.[0];
26999
+ var deviceCodeValue = (output2) => DEVICE_CODE_VALUE.exec(output2)?.[1];
27000
+ var hasDeviceCode = (output2) => deviceCodeUrl(output2) !== void 0 && deviceCodeValue(output2) !== void 0;
27001
+ function readDeviceCodeOutput(stdout, onText) {
27002
+ const collected = [];
27003
+ let onCodeFound;
27004
+ const codeFound = new Promise((resolve2) => {
27005
+ onCodeFound = resolve2;
27006
+ });
27007
+ let quietTimer;
27008
+ let onQuiet;
27009
+ const outputWentQuiet = new Promise((resolve2) => {
27010
+ onQuiet = resolve2;
27011
+ });
27012
+ const text3 = (async () => {
27013
+ const decoder = new TextDecoder();
27014
+ for await (const chunk of stdout) {
27015
+ const piece = decoder.decode(chunk, { stream: true });
27016
+ collected.push(piece);
27017
+ onText(piece);
27018
+ if (onCodeFound !== void 0 && hasDeviceCode(collected.join(""))) {
27019
+ onCodeFound();
27020
+ onCodeFound = void 0;
27021
+ }
27022
+ if (onQuiet !== void 0) {
27023
+ clearTimeout(quietTimer);
27024
+ quietTimer = setTimeout(() => onQuiet?.(), OUTPUT_QUIET_MS);
27025
+ }
27026
+ }
27027
+ return collected.join("");
27028
+ })();
27029
+ const code = (async () => {
27030
+ let silentCap;
27031
+ await Promise.race([
27032
+ codeFound,
27033
+ text3.then(() => void 0),
27034
+ outputWentQuiet,
27035
+ new Promise((resolve2) => {
27036
+ silentCap = setTimeout(resolve2, SILENT_CAP_MS);
27037
+ })
27038
+ ]);
27039
+ clearTimeout(silentCap);
27040
+ clearTimeout(quietTimer);
27041
+ onQuiet = void 0;
27042
+ const output2 = collected.join("");
27043
+ const verificationUrl = deviceCodeUrl(output2);
27044
+ const userCode = deviceCodeValue(output2);
27045
+ return {
27046
+ ...userCode === void 0 ? {} : { userCode },
27047
+ ...verificationUrl === void 0 ? {} : { verificationUrl }
27048
+ };
27049
+ })();
27050
+ return { text: text3, code };
27051
+ }
27052
+
26934
27053
  // src/grokAccount.ts
26935
27054
  import * as NodeFS from "node:fs";
26936
- import * as NodePath from "node:path";
27055
+ import * as NodePath2 from "node:path";
26937
27056
  var AUTH_FILE_NAME = "auth.json";
26938
27057
  var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
26939
27058
  var readString2 = (record3, key) => {
@@ -27001,7 +27120,7 @@ var isExpired = (expiresAt, nowMs) => {
27001
27120
  };
27002
27121
  var readGrokAccount = (homePath) => {
27003
27122
  const exists = directoryExists(homePath);
27004
- const raw = readCredentialFile(NodePath.join(homePath, AUTH_FILE_NAME));
27123
+ const raw = readCredentialFile(NodePath2.join(homePath, AUTH_FILE_NAME));
27005
27124
  if (raw === void 0) return signedOutProbe(exists);
27006
27125
  const parsed = parseJsonRecord(raw);
27007
27126
  const identity = parsed === void 0 ? void 0 : findIdentityEntry(parsed);
@@ -27018,7 +27137,7 @@ var readGrokAccount = (homePath) => {
27018
27137
 
27019
27138
  // src/grokQuota.ts
27020
27139
  import * as NodeFS2 from "node:fs";
27021
- import * as NodePath2 from "node:path";
27140
+ import * as NodePath3 from "node:path";
27022
27141
  import {
27023
27142
  parseRetryAfterMs
27024
27143
  } from "@ycodium-ai/plugin-api/usage";
@@ -27065,7 +27184,7 @@ var grokQuotaWindows = (body) => {
27065
27184
  };
27066
27185
  var createGrokUsage = (input2) => {
27067
27186
  const now = input2.now ?? Date.now;
27068
- const authPath = NodePath2.join(input2.homePath, AUTH_FILE_NAME2);
27187
+ const authPath = NodePath3.join(input2.homePath, AUTH_FILE_NAME2);
27069
27188
  const readQuota = async (request) => {
27070
27189
  const baseUrlKey = GROK_CARD.modelConnectivity.baseUrlEnvKey;
27071
27190
  if (baseUrlKey !== void 0 && (input2.environment[baseUrlKey]?.trim() ?? "") !== "") {
@@ -27453,6 +27572,39 @@ function buildGrokBackgroundTaskEvents(input2) {
27453
27572
  return events;
27454
27573
  }
27455
27574
 
27575
+ // src/grokImageArtifacts.ts
27576
+ function imageGenResult(rawOutput) {
27577
+ let value = rawOutput;
27578
+ if (typeof value === "string") {
27579
+ try {
27580
+ value = JSON.parse(value);
27581
+ } catch {
27582
+ return void 0;
27583
+ }
27584
+ }
27585
+ return value !== null && typeof value === "object" && value["type"] === "ImageGen" ? value : void 0;
27586
+ }
27587
+ function sessionDirectory(path, sessionFolder, filename) {
27588
+ if (typeof sessionFolder !== "string" || sessionFolder.trim().length === 0) return void 0;
27589
+ const tail = [...sessionFolder.split(/[\\/]/).filter((part) => part.length > 0), filename];
27590
+ const parts = path.split(/([\\/])/);
27591
+ const segments = parts.filter((_, index) => index % 2 === 0);
27592
+ if (segments.length <= tail.length) return void 0;
27593
+ const matches = tail.every(
27594
+ (part, index) => segments[segments.length - tail.length + index] === part
27595
+ );
27596
+ if (!matches) return void 0;
27597
+ return parts.slice(0, parts.length - tail.length * 2).join("");
27598
+ }
27599
+ function grokImageArtifacts(rawOutput) {
27600
+ const result = imageGenResult(rawOutput);
27601
+ const path = typeof result?.["path"] === "string" ? result["path"].trim() : "";
27602
+ if (result === void 0 || path.length === 0) return [];
27603
+ const filename = typeof result["filename"] === "string" && result["filename"].trim().length > 0 ? result["filename"].trim() : path.split(/[\\/]/).at(-1) ?? path;
27604
+ const linkBase = sessionDirectory(path, result["session_folder"], filename);
27605
+ return [{ path, name: filename, ...linkBase !== void 0 ? { linkBase } : {} }];
27606
+ }
27607
+
27456
27608
  // src/grokSupport.ts
27457
27609
  import { modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
27458
27610
  var GROK_NATIVE_MODE_BY_RUNTIME_MODE = {
@@ -27746,7 +27898,7 @@ var grokPromptSettlement = {
27746
27898
 
27747
27899
  // src/grokSkills.ts
27748
27900
  import * as NodeOS from "node:os";
27749
- import * as NodePath3 from "node:path";
27901
+ import * as NodePath4 from "node:path";
27750
27902
  var INSPECT_TIMEOUT_MS = 15e3;
27751
27903
  var MAX_INSPECT_OUTPUT_BYTES = 4 * 1024 * 1024;
27752
27904
  var GROK_INSPECT_ARGS = ["inspect", "--json"];
@@ -27814,14 +27966,14 @@ async function inspectGrokWorkspace(input2) {
27814
27966
  const skills = await runGrokInspect(input2);
27815
27967
  const watched = /* @__PURE__ */ new Set([
27816
27968
  // 项目技能目录的位置没有实测,这两处只是触发重查的提示,不影响答案本身。
27817
- NodePath3.join(input2.cwd, ".grok", "skills"),
27818
- NodePath3.join(input2.cwd, ".agents", "skills")
27969
+ NodePath4.join(input2.cwd, ".grok", "skills"),
27970
+ NodePath4.join(input2.cwd, ".agents", "skills")
27819
27971
  ]);
27820
27972
  for (const skill of skills) {
27821
27973
  watched.add(skill.path);
27822
- const skillDirectory = NodePath3.dirname(skill.path);
27974
+ const skillDirectory = NodePath4.dirname(skill.path);
27823
27975
  watched.add(skillDirectory);
27824
- watched.add(NodePath3.dirname(skillDirectory));
27976
+ watched.add(NodePath4.dirname(skillDirectory));
27825
27977
  }
27826
27978
  return { skills, watchPaths: [...watched] };
27827
27979
  }
@@ -27929,22 +28081,17 @@ var EventBus = class {
27929
28081
  };
27930
28082
  }
27931
28083
  };
27932
- var DEVICE_CODE_URL = /https?:\/\/\S+/;
27933
- var DEVICE_CODE_VALUE = /\b([A-Z0-9]{4,}(?:-[A-Z0-9]{4,})+)\b/;
27934
- var deviceCodeUrl = (output2) => DEVICE_CODE_URL.exec(output2)?.[0];
27935
- var deviceCodeValue = (output2) => DEVICE_CODE_VALUE.exec(output2)?.[1];
27936
- var hasDeviceCode = (output2) => deviceCodeUrl(output2) !== void 0 && deviceCodeValue(output2) !== void 0;
27937
28084
  function expandHomePath(value) {
27938
28085
  if (value === "~") return NodeOS2.homedir();
27939
28086
  if (value.startsWith("~/") || value.startsWith("~\\")) {
27940
- return NodePath4.join(NodeOS2.homedir(), value.slice(2));
28087
+ return NodePath5.join(NodeOS2.homedir(), value.slice(2));
27941
28088
  }
27942
28089
  return value;
27943
28090
  }
27944
28091
  function resolveGrokHomePath(value) {
27945
28092
  const trimmed3 = value.trim();
27946
- if (trimmed3.length === 0) return NodePath4.join(NodeOS2.homedir(), ".grok");
27947
- return NodePath4.resolve(expandHomePath(trimmed3));
28093
+ if (trimmed3.length === 0) return NodePath5.join(NodeOS2.homedir(), ".grok");
28094
+ return NodePath5.resolve(expandHomePath(trimmed3));
27948
28095
  }
27949
28096
  function probeGrokAccount(accountPath) {
27950
28097
  const resolved = resolveGrokHomePath(accountPath);
@@ -27963,12 +28110,12 @@ function grokContinuationKey(recipe) {
27963
28110
  function resolveAccountHomePath(recipe, configuredHome) {
27964
28111
  const fromEnvironment = recipe.environment["GROK_HOME"]?.trim();
27965
28112
  if (fromEnvironment !== void 0 && fromEnvironment.length > 0) {
27966
- return NodePath4.resolve(expandHomePath(fromEnvironment));
28113
+ return NodePath5.resolve(expandHomePath(fromEnvironment));
27967
28114
  }
27968
28115
  return resolveGrokHomePath(configuredHome);
27969
28116
  }
27970
28117
  function absentPath() {
27971
- return NodePath4.join(
28118
+ return NodePath5.join(
27972
28119
  NodeOS2.tmpdir(),
27973
28120
  `ycodium-grok-no-auth-${NodeCrypto2.randomUUID()}`,
27974
28121
  "auth.json"
@@ -28075,8 +28222,7 @@ var createGrokInstance = (config2, host) => {
28075
28222
  readiness: outcome.kind === "not-started" ? outcome.readiness : "error",
28076
28223
  auth: probeAuth(),
28077
28224
  ...outcome.detail === void 0 ? {} : { detail: outcome.detail },
28078
- // 装着但握不上手时,界面照样画权限格。不报档就退回宿主四档,而那四档对这双手
28079
- // 是撒谎的——这台开发机的 grok 就长期停在这个出口上。
28225
+ // 装着但握不上手时,界面照样画权限格。不报档就退回宿主四档,而那四档对这双手是撒谎的——这台开发机的 grok 就长期停在这个出口上。
28080
28226
  ...outcome.kind === "failed" ? GROK_NATIVE_MODE_REPORT : {}
28081
28227
  };
28082
28228
  }
@@ -28174,13 +28320,16 @@ var createGrokInstance = (config2, host) => {
28174
28320
  authMethodId: resolveGrokAuthMethodId,
28175
28321
  hooks: {
28176
28322
  promptSettlement: turnUsage.settlement,
28177
- onToolCallUpdated: (update) => buildGrokBackgroundTaskEvents({
28178
- tasks: backgroundTasks,
28179
- toolCallId: update.toolCallId,
28180
- rawInput: update.rawInput,
28181
- rawOutput: update.rawOutput,
28182
- toolCallStatus: update.status,
28183
- turnId: update.turnId
28323
+ onToolCallUpdated: (update) => ({
28324
+ events: buildGrokBackgroundTaskEvents({
28325
+ tasks: backgroundTasks,
28326
+ toolCallId: update.toolCallId,
28327
+ rawInput: update.rawInput,
28328
+ rawOutput: update.rawOutput,
28329
+ toolCallStatus: update.status,
28330
+ turnId: update.turnId
28331
+ }),
28332
+ artifacts: grokImageArtifacts(update.rawOutput)
28184
28333
  }),
28185
28334
  onExtensionRequest: async (method, params, ctx) => {
28186
28335
  if (XAI_EXIT_PLAN_MODE_METHODS.includes(method)) {
@@ -28377,9 +28526,8 @@ var createGrokInstance = (config2, host) => {
28377
28526
  },
28378
28527
  /**
28379
28528
  * 设备码登录:`grok login --device-auth` 是 RFC 8628 流程,CLI 自己打印网址和
28380
- * 验证码、轮询到批准,不开浏览器,所以服务器没有图形界面也跑得起来。输出
28381
- * 格式没在这台机器上实测过(auth.x.ai 到不了),网址与验证码按宽松模式从
28382
- * stdout 里捞;捞不到就把原始输出留给用户看,流程本身不假造。
28529
+ * 验证码、轮询到批准,不开浏览器,所以服务器没有图形界面也跑得起来。怎么从
28530
+ * stdout 捞网址与验证码见 deviceCodeOutput.ts,流程本身不假造。
28383
28531
  */
28384
28532
  signIn: {
28385
28533
  start: async () => {
@@ -28393,46 +28541,17 @@ var createGrokInstance = (config2, host) => {
28393
28541
  owner: { bindingId: host.bindingId },
28394
28542
  ...Object.keys(env).length > 0 ? { env } : {}
28395
28543
  });
28396
- const collected = [];
28397
- let onCodeFound;
28398
- const codeFound = new Promise((resolve2) => {
28399
- onCodeFound = resolve2;
28400
- });
28401
- const stdoutText = (async () => {
28402
- const decoder = new TextDecoder();
28403
- for await (const chunk of handle.stdout) {
28404
- const text3 = decoder.decode(chunk, { stream: true });
28405
- collected.push(text3);
28406
- host.log.info("sign-in output", { text: text3 });
28407
- if (onCodeFound !== void 0 && hasDeviceCode(collected.join(""))) {
28408
- onCodeFound();
28409
- onCodeFound = void 0;
28410
- }
28411
- }
28412
- return collected.join("");
28413
- })();
28544
+ const output2 = readDeviceCodeOutput(
28545
+ handle.stdout,
28546
+ (text3) => host.log.info("sign-in output", { text: text3 })
28547
+ );
28548
+ const stdoutText = output2.text;
28414
28549
  const operationId = `grok-sign-in-${Date.now().toString(36)}-${signInOperations.size}`;
28415
28550
  signInOperations.set(operationId, { handle, stdoutText });
28416
28551
  void stdoutText.finally(() => {
28417
28552
  signInOperations.delete(operationId);
28418
28553
  });
28419
- let timer;
28420
- await Promise.race([
28421
- codeFound,
28422
- stdoutText.then(() => void 0),
28423
- new Promise((resolve2) => {
28424
- timer = setTimeout(resolve2, 3e3);
28425
- })
28426
- ]);
28427
- if (timer !== void 0) clearTimeout(timer);
28428
- const output2 = collected.join("");
28429
- const verificationUrl = deviceCodeUrl(output2);
28430
- const userCode = deviceCodeValue(output2);
28431
- return {
28432
- operationId,
28433
- ...userCode === void 0 ? {} : { userCode },
28434
- ...verificationUrl === void 0 ? {} : { verificationUrl }
28435
- };
28554
+ return { operationId, ...await output2.code };
28436
28555
  },
28437
28556
  cancel: async (operationId) => {
28438
28557
  const operation = signInOperations.get(operationId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-grok",
3
- "version": "0.2.2888",
3
+ "version": "0.2.2896",
4
4
  "description": "Grok executor: grok CLI over Agent Client Protocol stdio.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -21,8 +21,8 @@
21
21
  "@types/node": "24.12.4",
22
22
  "esbuild": "0.28.1",
23
23
  "vite-plus": "0.2.2",
24
- "@ycodium-ai/plugin-api": "0.2.2888",
25
- "ycodium-acp-executor": "0.2.2888",
24
+ "@ycodium-ai/plugin-api": "0.2.2896",
25
+ "ycodium-acp-executor": "0.2.2896",
26
26
  "ycodium-executor-testing": "0.0.0"
27
27
  },
28
28
  "ycodium": {