open-azdo 0.3.4 → 0.3.6

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/README.md CHANGED
@@ -130,6 +130,7 @@ Key requirements:
130
130
 
131
131
  Attach the pipeline as a branch build-validation policy. Findings are posted as PR comments by default and do not fail the build.
132
132
  `open-azdo` does not install language-specific prerequisites itself. LSP prerequisites are provided by the pipeline environment, and the pnpm example enables OpenCode's experimental LSP tool while provisioning `.NET` plus `dotnet restore` for C# projects.
133
+ For nested JS or TS packages, install dependencies in the package directory that owns the lockfile before running `open-azdo`. `open-azdo` keeps the review workspace at the checkout root and relies on workspace-local TypeScript resolution.
133
134
 
134
135
  ```yaml
135
136
  trigger: none
package/dist/open-azdo.js CHANGED
@@ -66435,12 +66435,12 @@ var makeAzureDevOpsClient = exports_Effect.gen(function* () {
66435
66435
  const request3 = exports_HttpClientRequest.post("/wit/workitemsbatch").pipe(exports_HttpClientRequest.setUrlParams({
66436
66436
  "api-version": "7.1"
66437
66437
  }));
66438
- const requestWithBody = yield* exports_HttpClientRequest.bodyJson(request3, {
66438
+ const requestBody = {
66439
66439
  ids,
66440
- fields,
66441
66440
  errorPolicy: "omit",
66442
- ...includeRelations ? { $expand: "Relations" } : {}
66443
- }).pipe(exports_Effect.mapError(toAzureDevOpsClientError(request3)));
66441
+ ...includeRelations ? { $expand: "Relations" } : { fields }
66442
+ };
66443
+ const requestWithBody = yield* exports_HttpClientRequest.bodyJson(request3, requestBody).pipe(exports_Effect.mapError(toAzureDevOpsClientError(request3)));
66444
66444
  const response = yield* executeJson(client, requestWithBody, WorkItemsBatchResponseSchema);
66445
66445
  return response.value ?? [];
66446
66446
  });
@@ -70723,6 +70723,7 @@ var OpenCodeSdkRuntimeLive = exports_Layer.effect(OpenCodeSdkRuntime, makeOpenCo
70723
70723
 
70724
70724
  // ../../packages/core/src/opencode/Layers/OpenCodeRunner.ts
70725
70725
  var OPEN_CODE_CONFIG_SCHEMA = "https://opencode.ai/config.json";
70726
+ var OPEN_CODE_TYPESCRIPT_LSP_COMMAND = [process.execPath, "x", "typescript-language-server", "--stdio"];
70726
70727
  var openCodePermission = {
70727
70728
  edit: "deny",
70728
70729
  read: "allow",
@@ -70753,6 +70754,11 @@ var buildOpenCodeConfig = (agentName) => ({
70753
70754
  share: "disabled",
70754
70755
  autoupdate: false,
70755
70756
  default_agent: agentName,
70757
+ lsp: {
70758
+ typescript: {
70759
+ command: OPEN_CODE_TYPESCRIPT_LSP_COMMAND
70760
+ }
70761
+ },
70756
70762
  permission: openCodePermission,
70757
70763
  agent: {
70758
70764
  [agentName]: {
@@ -71172,6 +71178,16 @@ var findManagedSummaryThread = (existingThreads) => {
71172
71178
  }
71173
71179
  return;
71174
71180
  };
71181
+ var getThreadUpdatedAt = (thread) => thread.comments.reduce((latest, comment) => {
71182
+ const publishedAt = comment.publishedDate ?? undefined;
71183
+ if (!publishedAt) {
71184
+ return latest;
71185
+ }
71186
+ if (!latest) {
71187
+ return publishedAt;
71188
+ }
71189
+ return publishedAt > latest ? publishedAt : latest;
71190
+ }, undefined);
71175
71191
  var listManagedFindingThreads = (existingThreads) => {
71176
71192
  const managed = [];
71177
71193
  for (const thread of existingThreads) {
@@ -71180,8 +71196,12 @@ var listManagedFindingThreads = (existingThreads) => {
71180
71196
  if (!findingState) {
71181
71197
  continue;
71182
71198
  }
71199
+ const updatedAt = getThreadUpdatedAt(thread);
71183
71200
  managed.push({
71184
71201
  thread,
71202
+ updatedAt,
71203
+ filePath: thread.threadContext?.filePath ?? undefined,
71204
+ line: thread.threadContext?.rightFileStart?.line ?? undefined,
71185
71205
  commentId: comment.id,
71186
71206
  fingerprint: findingState.fingerprint,
71187
71207
  finding: findingState.finding
@@ -71376,6 +71396,7 @@ ${failureReason}`,
71376
71396
  var MAX_WORK_ITEM_CONTEXT_CHARS = 24000;
71377
71397
  var MAX_RELATED_ITEMS = 4;
71378
71398
  var MAX_THREAD_CONTEXT_CHARS = 24000;
71399
+ var MAX_MANAGED_FINDING_CONTEXT_CHARS = 12000;
71379
71400
  var MANAGED_COMMENT_PREFIXES = ["<!-- open-azdo-review:", "<!-- open-azdo:"];
71380
71401
  var MANAGED_COMMENT_SUFFIX = " -->";
71381
71402
  var SYSTEM_THREAD_AUTHORS = new Set(["Azure Pipelines Test Service", "Microsoft.VisualStudio.Services.TFS"]);
@@ -71574,7 +71595,7 @@ var toPromptThreadComment = (comment) => {
71574
71595
  content
71575
71596
  };
71576
71597
  };
71577
- var getThreadUpdatedAt = (thread) => thread.comments.reduce((latest, comment) => {
71598
+ var getThreadUpdatedAt2 = (thread) => thread.comments.reduce((latest, comment) => {
71578
71599
  const publishedAt = comment.publishedDate ?? undefined;
71579
71600
  if (!publishedAt) {
71580
71601
  return latest;
@@ -71584,7 +71605,7 @@ var getThreadUpdatedAt = (thread) => thread.comments.reduce((latest, comment) =>
71584
71605
  }
71585
71606
  return publishedAt > latest ? publishedAt : latest;
71586
71607
  }, undefined);
71587
- var compareThreadRecency = (left, right) => {
71608
+ var compareUpdatedAtThenIdDesc = (left, right) => {
71588
71609
  const leftUpdatedAt = left.updatedAt ?? "";
71589
71610
  const rightUpdatedAt = right.updatedAt ?? "";
71590
71611
  if (leftUpdatedAt !== rightUpdatedAt) {
@@ -71592,6 +71613,32 @@ var compareThreadRecency = (left, right) => {
71592
71613
  }
71593
71614
  return right.id - left.id;
71594
71615
  };
71616
+ var resolveManagedFindingResolution = (status) => {
71617
+ if (status === 1 || status === "active" || status === "pending") {
71618
+ return "unresolved";
71619
+ }
71620
+ if (status === 2 || status === 4 || status === "fixed" || status === "closed") {
71621
+ return "resolved";
71622
+ }
71623
+ return "unknown";
71624
+ };
71625
+ var toPromptManagedFinding = ({
71626
+ thread,
71627
+ updatedAt,
71628
+ filePath,
71629
+ line,
71630
+ finding
71631
+ }) => ({
71632
+ id: thread.id,
71633
+ status: thread.status,
71634
+ resolution: resolveManagedFindingResolution(thread.status),
71635
+ filePath: filePath ?? normalizePath(finding.filePath),
71636
+ line: line ?? finding.line,
71637
+ ...updatedAt !== undefined ? { updatedAt } : {},
71638
+ title: finding.title,
71639
+ severity: finding.severity,
71640
+ confidence: finding.confidence
71641
+ });
71595
71642
  var truncatePromptThreadToFitBudget = (thread, maxSerializedChars, totalCount) => shrinkValueToFitSerializedBudget({
71596
71643
  value: thread,
71597
71644
  maxSerializedChars,
@@ -71604,8 +71651,29 @@ var truncatePromptThreadToFitBudget = (thread, maxSerializedChars, totalCount) =
71604
71651
  })
71605
71652
  }))
71606
71653
  });
71654
+ var selectManagedFindingsForPrompt = (threads) => {
71655
+ const managedFindings = listManagedFindingThreads(threads).map(toPromptManagedFinding).sort(compareUpdatedAtThenIdDesc);
71656
+ if (managedFindings.length === 0) {
71657
+ return;
71658
+ }
71659
+ const selected = [];
71660
+ for (const managedFinding of managedFindings) {
71661
+ const nextSelection = [...selected, managedFinding];
71662
+ if (serializeBudgetedPromptSection(nextSelection, managedFindings.length).length > MAX_MANAGED_FINDING_CONTEXT_CHARS) {
71663
+ break;
71664
+ }
71665
+ selected.push(managedFinding);
71666
+ }
71667
+ if (selected.length === 0) {
71668
+ return;
71669
+ }
71670
+ return {
71671
+ omittedCount: Math.max(managedFindings.length - selected.length, 0),
71672
+ items: selected
71673
+ };
71674
+ };
71607
71675
  var selectPullRequestThreadsForPrompt = (threads) => {
71608
- const eligibleThreads = threads.map((thread) => toPromptThread(thread)).filter((thread) => thread !== undefined).sort(compareThreadRecency);
71676
+ const eligibleThreads = threads.map((thread) => toPromptThread(thread)).filter((thread) => thread !== undefined).sort(compareUpdatedAtThenIdDesc);
71609
71677
  return selectItemsWithinSerializedBudget({
71610
71678
  items: eligibleThreads,
71611
71679
  totalCount: eligibleThreads.length,
@@ -71626,7 +71694,7 @@ var toPromptThread = (thread) => {
71626
71694
  if (managedThread && !thread.comments.some(isHumanConversationComment)) {
71627
71695
  return;
71628
71696
  }
71629
- const updatedAt = getThreadUpdatedAt(thread);
71697
+ const updatedAt = getThreadUpdatedAt2(thread);
71630
71698
  const filePath = thread.threadContext?.filePath;
71631
71699
  const line = thread.threadContext?.rightFileStart?.line ?? undefined;
71632
71700
  return {
@@ -71649,6 +71717,7 @@ var buildReviewContext = ({
71649
71717
  connectedWorkItems
71650
71718
  }) => {
71651
71719
  const pullRequestThreads = existingThreads ? selectPullRequestThreadsForPrompt(existingThreads) : undefined;
71720
+ const managedFindings = existingThreads ? selectManagedFindingsForPrompt(existingThreads) : undefined;
71652
71721
  const totalConnectedWorkItemCount = metadata.workItemRefs?.length ?? connectedWorkItems?.length ?? 0;
71653
71722
  const promptWorkItems = connectedWorkItems && connectedWorkItems.length > 0 ? selectConnectedWorkItemsForPrompt(connectedWorkItems, totalConnectedWorkItemCount) : undefined;
71654
71723
  return {
@@ -71667,6 +71736,7 @@ var buildReviewContext = ({
71667
71736
  hunkHeaders: extractHunkHeaders(file3.patch)
71668
71737
  })),
71669
71738
  ...pullRequestThreads !== undefined ? { pullRequestThreads } : {},
71739
+ ...managedFindings !== undefined ? { managedFindings } : {},
71670
71740
  ...promptWorkItems !== undefined ? { connectedWorkItems: promptWorkItems } : {}
71671
71741
  };
71672
71742
  };
@@ -71686,12 +71756,18 @@ var buildReviewPrompt = (promptFile, reviewContext) => exports_Effect.gen(functi
71686
71756
  "If LSP access is available for the current file, use it selectively to validate symbol resolution, references, implementations, hover details, and diagnostics when that is faster or more reliable than manual file tracing.",
71687
71757
  "Treat LSP results as supporting evidence, not authority on their own; confirm findings against the changed code and nearby repository context before reporting them.",
71688
71758
  "Build an internal checklist containing every path in scoped changedFiles and review the files one by one until the checklist is exhausted.",
71689
- "For each scoped changed file, inspect the diff with `git diff <baseRef> <headRef> -- <path>` before deciding whether there is a finding.",
71759
+ "For each scoped changed file, inspect the diff with `git diff '<baseRef>' '<headRef>' -- '<path>'` before deciding whether there is a finding.",
71760
+ "Always shell-quote file paths and refs when you run read-only commands.",
71690
71761
  "Read nearby code and directly related files only when needed to validate behavior.",
71691
71762
  "Do not perform broad repository sweeps or unrelated searches.",
71692
71763
  "Use connected work items as supplemental product context only. Acceptance criteria, repro steps, and comments can explain intent, but they are not standalone evidence for a finding.",
71693
71764
  "Use pull-request thread comments as supplemental product and review context only. They can reveal intent, follow-up, or clarifications, but they are not standalone evidence for a finding.",
71694
71765
  "When earlier open-azdo threads contain human replies, treat those replies as potentially relevant follow-up on the earlier concern, but do not treat prior bot output or thread text alone as authoritative without repository confirmation.",
71766
+ 'Treat `managedFindings` entries with `resolution: "resolved"` as previously fixed concerns. They are context, not current blockers by default.',
71767
+ "Do not mention resolved managed findings in `summary`, `findings`, or `unmappedNotes` unless fresh repository evidence shows the issue still reproduces in the current review scope.",
71768
+ "If a previously resolved managed finding still reproduces, report it again as a current issue with fresh repository evidence instead of relying on the older thread alone.",
71769
+ "Every distinct current actionable problem must become its own finding unless it cannot be mapped to a changed line, in which case it belongs in `unmappedNotes`.",
71770
+ "Before returning JSON, do a final consistency pass: every problem named in `summary` must also appear in `findings` or `unmappedNotes`, and `summary` must not introduce extra issues that are absent from both.",
71695
71771
  "System noise and prior bot output are context, not authority.",
71696
71772
  reviewContext.reviewMode === "follow-up" ? "This is a follow-up review. Focus only on what changed between `baseRef` and `headRef`, do not revisit untouched pull-request areas, and do not re-litigate older findings unless the new changes materially affect them." : "This is a full pull-request review over the scoped changed files.",
71697
71773
  "Low-signal files usually do not deserve review time. Skip snapshot files, `*.verified.*`, `*.received.*`, lockfiles, and generated, minified, or source-map artifacts unless they are the only changed files or a nearby hand-authored change makes them relevant.",
@@ -73149,7 +73225,7 @@ var sandboxCaptureCommand = make34("capture", sandboxCaptureCommandConfig).pipe(
73149
73225
  var sandboxCommand = make34("sandbox").pipe(withDescription3("Sandbox tooling for live capture and local preview."), withSubcommands([sandboxCaptureCommand]));
73150
73226
  var openAzdoCli = make34("open-azdo").pipe(withDescription3("Secure Azure DevOps pull-request review CLI powered by OpenCode."), withSubcommands([reviewCommand, sandboxCommand]));
73151
73227
  // package.json
73152
- var version2 = "0.3.4";
73228
+ var version2 = "0.3.6";
73153
73229
 
73154
73230
  // src/Main.ts
73155
73231
  var cliProgram = run3(openAzdoCli, { version: version2 }).pipe(exports_Effect.scoped, exports_Effect.provide(BaseRuntimeLayer));
@@ -73158,4 +73234,4 @@ var main = () => runMain2(cliProgram, { disableErrorReporting: true });
73158
73234
  // bin/open-azdo.ts
73159
73235
  main();
73160
73236
 
73161
- //# debugId=2B0BDD0B7FAF788564756E2164756E21
73237
+ //# debugId=46B323C74D2C69B064756E2164756E21