@ai-development-environment/control-agent 0.0.91 → 0.0.93

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.
@@ -51245,6 +51245,89 @@ function opencodeQuestionResolution(value) {
51245
51245
  const requestId = data.requestID ?? properties.requestID;
51246
51246
  return typeof requestId === "string" ? requestId : void 0;
51247
51247
  }
51248
+ function stringArray3(value) {
51249
+ return Array.isArray(value) ? value.map(String) : [];
51250
+ }
51251
+ function opencodePermissionRequest(value, fallbackSurface) {
51252
+ const event = asRecord(value);
51253
+ const payload = asRecord(event.payload);
51254
+ const type = String(payload.type ?? event.type ?? "");
51255
+ if (type && type !== "permission.asked" && type !== "permission.v2.asked")
51256
+ return null;
51257
+ const properties = asRecord(payload.properties ?? event.properties);
51258
+ const request = type ? asRecord(
51259
+ properties.request ?? properties.data ?? payload.data ?? event.data ?? properties
51260
+ ) : event;
51261
+ const permission = request.permission ?? request.action;
51262
+ if (typeof permission !== "string") return null;
51263
+ return {
51264
+ id: String(request.id ?? properties.id ?? "permission"),
51265
+ sessionId: typeof request.sessionID === "string" ? request.sessionID : typeof properties.sessionID === "string" ? properties.sessionID : void 0,
51266
+ surface: type === "permission.v2.asked" ? "V2" : fallbackSurface ?? "LEGACY",
51267
+ permission,
51268
+ patterns: stringArray3(request.patterns ?? request.resources),
51269
+ always: stringArray3(request.always ?? request.save)
51270
+ };
51271
+ }
51272
+ function opencodePermissionResolution(value) {
51273
+ const event = asRecord(value);
51274
+ const payload = asRecord(event.payload);
51275
+ const type = String(payload.type ?? event.type ?? "");
51276
+ if (type !== "permission.replied" && type !== "permission.v2.replied")
51277
+ return void 0;
51278
+ const properties = asRecord(payload.properties ?? event.properties);
51279
+ const data = asRecord(payload.data ?? event.data ?? properties.data);
51280
+ const requestId = data.requestID ?? properties.requestID;
51281
+ return typeof requestId === "string" ? requestId : void 0;
51282
+ }
51283
+ function permissionQuestions(request) {
51284
+ const permission = request.permission.replaceAll("_", " ");
51285
+ const targets = request.patterns.length ? ` for ${request.patterns.join(", ")}` : "";
51286
+ return [
51287
+ {
51288
+ id: "permission",
51289
+ header: "Permission required",
51290
+ prompt: `OpenCode requests ${permission} permission${targets}.`,
51291
+ multiSelect: false,
51292
+ allowCustom: false,
51293
+ options: [
51294
+ {
51295
+ label: "Allow once",
51296
+ description: "Approve only this request."
51297
+ },
51298
+ ...request.always.length ? [
51299
+ {
51300
+ label: "Always allow",
51301
+ description: `Approve this request and remember ${request.always.join(", ")}.`
51302
+ }
51303
+ ] : [],
51304
+ {
51305
+ label: "Reject",
51306
+ description: "Deny this request and let OpenCode continue safely."
51307
+ }
51308
+ ]
51309
+ }
51310
+ ];
51311
+ }
51312
+ function permissionReply(value) {
51313
+ const selected = answerArrays(value).flat().map((answer) => answer.trim().toLowerCase()).filter(Boolean);
51314
+ if (selected.length !== 1)
51315
+ throw new Error("Select one response for the OpenCode permission request");
51316
+ switch (selected[0]) {
51317
+ case "allow once":
51318
+ case "once":
51319
+ return "once";
51320
+ case "always allow":
51321
+ case "allow always":
51322
+ case "always":
51323
+ return "always";
51324
+ case "reject":
51325
+ case "deny":
51326
+ return "reject";
51327
+ default:
51328
+ throw new Error(`Unknown OpenCode permission response: ${selected[0]}`);
51329
+ }
51330
+ }
51248
51331
  function responseItems(value) {
51249
51332
  const data = resultData(value);
51250
51333
  if (Array.isArray(data)) return data;
@@ -51373,6 +51456,7 @@ var OpenCodeAdapter = class {
51373
51456
  let stopReason = null;
51374
51457
  const streamController = new AbortController();
51375
51458
  const questionSurfaces = /* @__PURE__ */ new Map();
51459
+ const permissionSurfaces = /* @__PURE__ */ new Map();
51376
51460
  const pendingQuestions = /* @__PURE__ */ new Set();
51377
51461
  let sawQuestion = false;
51378
51462
  const reportQuestion = async (request) => {
@@ -51388,6 +51472,19 @@ var OpenCodeAdapter = class {
51388
51472
  throw error;
51389
51473
  }
51390
51474
  };
51475
+ const reportPermission = async (request) => {
51476
+ if (permissionSurfaces.has(request.id)) return;
51477
+ permissionSurfaces.set(request.id, request.surface);
51478
+ pendingQuestions.add(request.id);
51479
+ sawQuestion = true;
51480
+ try {
51481
+ await callbacks.onQuestion(request.id, permissionQuestions(request));
51482
+ } catch (error) {
51483
+ permissionSurfaces.delete(request.id);
51484
+ pendingQuestions.delete(request.id);
51485
+ throw error;
51486
+ }
51487
+ };
51391
51488
  const reconcileLegacyQuestions = async () => {
51392
51489
  const response = await client2.question.list(
51393
51490
  { directory: cwd },
@@ -51410,6 +51507,27 @@ var OpenCodeAdapter = class {
51410
51507
  await reportQuestion(request);
51411
51508
  }
51412
51509
  };
51510
+ const reconcileLegacyPermissions = async () => {
51511
+ const response = await client2.permission.list(
51512
+ { directory: cwd },
51513
+ { signal: AbortSignal.timeout(QUESTION_RECONCILIATION_TIMEOUT_MS) }
51514
+ );
51515
+ for (const value of responseItems(response)) {
51516
+ const request = opencodePermissionRequest(value, "LEGACY");
51517
+ if (request?.sessionId === nativeId) await reportPermission(request);
51518
+ }
51519
+ };
51520
+ const reconcileV2Permissions = async () => {
51521
+ const response = await client2.v2.session.permission.list(
51522
+ { sessionID: nativeId },
51523
+ { signal: AbortSignal.timeout(QUESTION_RECONCILIATION_TIMEOUT_MS) }
51524
+ );
51525
+ for (const value of responseItems(response)) {
51526
+ const request = opencodePermissionRequest(value, "V2");
51527
+ if (request && (!request.sessionId || request.sessionId === nativeId))
51528
+ await reportPermission(request);
51529
+ }
51530
+ };
51413
51531
  const eventTask = (async () => {
51414
51532
  try {
51415
51533
  const subscription = await client2.event.subscribe(
@@ -51420,8 +51538,13 @@ var OpenCodeAdapter = class {
51420
51538
  if (eventSessionId(event) !== nativeId) continue;
51421
51539
  const question = opencodeQuestionRequest(event);
51422
51540
  if (question) await reportQuestion(question);
51541
+ const permission = opencodePermissionRequest(event);
51542
+ if (permission) await reportPermission(permission);
51423
51543
  const resolvedRequestId = opencodeQuestionResolution(event);
51424
51544
  if (resolvedRequestId) pendingQuestions.delete(resolvedRequestId);
51545
+ const resolvedPermissionId = opencodePermissionResolution(event);
51546
+ if (resolvedPermissionId)
51547
+ pendingQuestions.delete(resolvedPermissionId);
51425
51548
  const record = asRecord(event);
51426
51549
  const payload = asRecord(record.payload);
51427
51550
  const type = String(payload.type ?? record.type ?? "event");
@@ -51475,6 +51598,14 @@ var OpenCodeAdapter = class {
51475
51598
  "V2",
51476
51599
  reconcileV2Questions
51477
51600
  );
51601
+ const legacyPermissionReconciliationTask = questionReconciliationTask(
51602
+ "LEGACY permission",
51603
+ reconcileLegacyPermissions
51604
+ );
51605
+ const v2PermissionReconciliationTask = questionReconciliationTask(
51606
+ "V2 permission",
51607
+ reconcileV2Permissions
51608
+ );
51478
51609
  const send = async (prompt, attachments) => {
51479
51610
  const response = await client2.session.prompt({
51480
51611
  sessionID: nativeId,
@@ -51500,7 +51631,9 @@ var OpenCodeAdapter = class {
51500
51631
  let response = await send(input.prompt, input.attachments);
51501
51632
  await Promise.allSettled([
51502
51633
  reconcileLegacyQuestions(),
51503
- reconcileV2Questions()
51634
+ reconcileV2Questions(),
51635
+ reconcileLegacyPermissions(),
51636
+ reconcileV2Permissions()
51504
51637
  ]);
51505
51638
  while (!stopReason && pendingQuestions.size) {
51506
51639
  await waitForPoll(streamController.signal);
@@ -51547,7 +51680,9 @@ var OpenCodeAdapter = class {
51547
51680
  await Promise.allSettled([
51548
51681
  eventTask,
51549
51682
  legacyQuestionReconciliationTask,
51550
- v2QuestionReconciliationTask
51683
+ v2QuestionReconciliationTask,
51684
+ legacyPermissionReconciliationTask,
51685
+ v2PermissionReconciliationTask
51551
51686
  ]);
51552
51687
  isolatedRuntime?.server.close();
51553
51688
  }
@@ -51563,7 +51698,20 @@ var OpenCodeAdapter = class {
51563
51698
  await send(prompt, attachments);
51564
51699
  },
51565
51700
  async answer(requestId, answers) {
51566
- if (questionSurfaces.get(requestId) === "V2") {
51701
+ const permissionSurface = permissionSurfaces.get(requestId);
51702
+ if (permissionSurface === "V2") {
51703
+ await client2.v2.session.permission.reply({
51704
+ sessionID: nativeId,
51705
+ requestID: requestId,
51706
+ reply: permissionReply(answers)
51707
+ });
51708
+ } else if (permissionSurface === "LEGACY") {
51709
+ await client2.permission.reply({
51710
+ requestID: requestId,
51711
+ directory: cwd,
51712
+ reply: permissionReply(answers)
51713
+ });
51714
+ } else if (questionSurfaces.get(requestId) === "V2") {
51567
51715
  await client2.v2.session.question.reply({
51568
51716
  sessionID: nativeId,
51569
51717
  requestID: requestId,
@@ -51577,6 +51725,7 @@ var OpenCodeAdapter = class {
51577
51725
  });
51578
51726
  }
51579
51727
  pendingQuestions.delete(requestId);
51728
+ permissionSurfaces.delete(requestId);
51580
51729
  }
51581
51730
  };
51582
51731
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-development-environment/control-agent",
3
- "version": "0.0.91",
3
+ "version": "0.0.93",
4
4
  "description": "Control agent for the AI Development Environment",
5
5
  "license": "MIT",
6
6
  "repository": {