overlane 0.1.124 → 0.1.126

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/dist/overlane.mjs CHANGED
@@ -4545,7 +4545,7 @@ function isRef(value) {
4545
4545
  function cloneIssues(issues) {
4546
4546
  return issues.map((iss) => iss.path ? { ...iss, path: iss.path.slice() } : { ...iss });
4547
4547
  }
4548
- function isRecursive(inst, stack, resolve13) {
4548
+ function isRecursive(inst, stack, resolve14) {
4549
4549
  const cached2 = recursive.get(inst);
4550
4550
  if (cached2 !== void 0)
4551
4551
  return cached2 ? PROVEN : NONE;
@@ -4555,7 +4555,7 @@ function isRecursive(inst, stack, resolve13) {
4555
4555
  let result = NONE;
4556
4556
  const check2 = (child) => {
4557
4557
  if (result !== PROVEN && child?._zod) {
4558
- const answer = isRecursive(child, stack, resolve13);
4558
+ const answer = isRecursive(child, stack, resolve14);
4559
4559
  if (answer > result)
4560
4560
  result = answer;
4561
4561
  }
@@ -4566,7 +4566,7 @@ function isRecursive(inst, stack, resolve13) {
4566
4566
  const desc = Object.getOwnPropertyDescriptor(sh, key);
4567
4567
  if (spread && !desc.enumerable)
4568
4568
  continue;
4569
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve13) : NONE;
4569
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve14) : NONE;
4570
4570
  if (child > answer)
4571
4571
  answer = child;
4572
4572
  }
@@ -4630,7 +4630,7 @@ function isRecursive(inst, stack, resolve13) {
4630
4630
  break;
4631
4631
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
4632
4632
  case "lazy": {
4633
- const inner = def._cachedInner ?? (resolve13 ? inst._zod.innerType : void 0);
4633
+ const inner = def._cachedInner ?? (resolve14 ? inst._zod.innerType : void 0);
4634
4634
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
4635
4635
  break;
4636
4636
  }
@@ -20409,7 +20409,14 @@ var init_zod = __esm({
20409
20409
  });
20410
20410
 
20411
20411
  // ../contracts/src/common.ts
20412
- var identifier, TenantId, ProjectId, TaskId, CommitSha, Sha256Digest, Timestamp, SemVer, SchemaVersion;
20412
+ function withCompat(fill, schema) {
20413
+ return external_exports.preprocess((raw) => typeof raw === "object" && raw !== null && !Array.isArray(raw) ? fill(raw) : raw, schema);
20414
+ }
20415
+ function resolveProvider(record3) {
20416
+ if (record3.provider !== void 0) return record3.provider;
20417
+ return record3.repository !== void 0 && record3.repository !== null ? "github" : DEFAULT_PROVIDER;
20418
+ }
20419
+ var identifier, TenantId, ProjectId, TaskId, CommitSha, Sha256Digest, Timestamp, SemVer, SchemaVersion, PROVIDERS, Provider, DEFAULT_PROVIDER;
20413
20420
  var init_common = __esm({
20414
20421
  "../contracts/src/common.ts"() {
20415
20422
  "use strict";
@@ -20423,6 +20430,9 @@ var init_common = __esm({
20423
20430
  Timestamp = external_exports.iso.datetime({ offset: true });
20424
20431
  SemVer = external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/, "must be a semantic version");
20425
20432
  SchemaVersion = external_exports.literal("1");
20433
+ PROVIDERS = ["overlane", "github", "gitlab"];
20434
+ Provider = external_exports.enum(PROVIDERS);
20435
+ DEFAULT_PROVIDER = "overlane";
20426
20436
  }
20427
20437
  });
20428
20438
 
@@ -20448,7 +20458,7 @@ var init_executor = __esm({
20448
20458
  });
20449
20459
 
20450
20460
  // ../contracts/src/evidence.ts
20451
- var EvidenceLevel, EvidenceSubject, InputDigests, recordBase, MachineEvidence, HumanEvidence, EvidenceRecord;
20461
+ var EvidenceLevel, EvidenceSubject, InputDigests, recordBase, MachineRunner, MachineEvidence, HumanEvidence, EvidenceRecord;
20452
20462
  var init_evidence = __esm({
20453
20463
  "../contracts/src/evidence.ts"() {
20454
20464
  "use strict";
@@ -20477,15 +20487,20 @@ var init_evidence = __esm({
20477
20487
  recordedAt: Timestamp,
20478
20488
  executor: Executor
20479
20489
  };
20490
+ MachineRunner = withCompat(
20491
+ (runner) => runner["provider"] === void 0 ? { ...runner, provider: runner["environment"] === "github-checks" ? "github" : "overlane" } : runner,
20492
+ external_exports.object({
20493
+ provider: Provider,
20494
+ identity: external_exports.string().min(1),
20495
+ environment: external_exports.string().min(1)
20496
+ }).strict()
20497
+ );
20480
20498
  MachineEvidence = external_exports.object({
20481
20499
  ...recordBase,
20482
20500
  level: external_exports.enum(["L0", "L1", "L2", "L3"]),
20483
20501
  checkId: external_exports.string().min(1),
20484
20502
  checkDefinitionDigest: Sha256Digest,
20485
- runner: external_exports.object({
20486
- identity: external_exports.string().min(1),
20487
- environment: external_exports.string().min(1)
20488
- }).strict(),
20503
+ runner: MachineRunner,
20489
20504
  startedAt: Timestamp,
20490
20505
  finishedAt: Timestamp,
20491
20506
  exitStatus: external_exports.number().int(),
@@ -20700,7 +20715,21 @@ var init_domain_event = __esm({
20700
20715
  });
20701
20716
 
20702
20717
  // ../contracts/src/api.ts
20703
- var apiPaths, HARNESS_SCOPES, HarnessScope, RepositoryRef, CreateProjectRequest, UpdateProjectRequest, ProjectRecord, WhoAmI, ApiError;
20718
+ function checkProviderShape(value, ctx) {
20719
+ const provider = resolveProvider(value);
20720
+ const nested = value.repository?.provider;
20721
+ if (nested !== void 0 && nested !== provider) {
20722
+ ctx.addIssue({ code: "custom", path: ["repository", "provider"], message: "repository.provider must match provider" });
20723
+ }
20724
+ if (provider !== "overlane" && value.repository === void 0) {
20725
+ ctx.addIssue({ code: "custom", path: ["repository"], message: `a ${provider} project needs a repository` });
20726
+ }
20727
+ const host = value.repository?.host;
20728
+ if (host !== void 0 && host !== HOSTS[provider]) {
20729
+ ctx.addIssue({ code: "custom", path: ["repository", "host"], message: `host must be ${HOSTS[provider]} for provider ${provider}; name the provider for a repository that is not on github.com` });
20730
+ }
20731
+ }
20732
+ var apiPaths, HARNESS_SCOPES, HarnessScope, RepositoryRef, ProjectConnection, HOSTS, ProjectRepository, fillProvider, CreateProjectRequest, UpdateProjectRequest, ProjectRecord, WhoAmI, ApiError;
20704
20733
  var init_api2 = __esm({
20705
20734
  "../contracts/src/api.ts"() {
20706
20735
  "use strict";
@@ -20720,24 +20749,58 @@ var init_api2 = __esm({
20720
20749
  owner: external_exports.string().regex(/^[A-Za-z0-9-]{1,39}$/),
20721
20750
  name: external_exports.string().regex(/^[A-Za-z0-9._-]{1,100}$/)
20722
20751
  }).strict();
20723
- CreateProjectRequest = external_exports.object({
20724
- repository: RepositoryRef,
20725
- name: external_exports.string().min(1).max(100),
20726
- /** ADR 0018: the hosted code layer is off unless a project turns it on. Missing means false. */
20727
- codeLayer: external_exports.boolean().optional()
20752
+ ProjectConnection = external_exports.object({
20753
+ provider: Provider,
20754
+ /** The GitHub App installation number; GitHub only. */
20755
+ installationId: external_exports.number().int().positive().optional(),
20756
+ /** The provider's own identifier for the repository or project. */
20757
+ externalId: external_exports.string().min(1).max(200).optional()
20728
20758
  }).strict();
20759
+ HOSTS = { overlane: "overlane", github: "github.com", gitlab: "gitlab.com" };
20760
+ ProjectRepository = external_exports.object({
20761
+ provider: Provider.optional(),
20762
+ host: external_exports.enum(["github.com", "gitlab.com", "overlane"]).optional(),
20763
+ owner: external_exports.string().min(1).max(200),
20764
+ name: external_exports.string().regex(/^[A-Za-z0-9._-]{1,100}$/)
20765
+ }).strict().superRefine((repository, ctx) => {
20766
+ const provider = repository.provider ?? (repository.host === "gitlab.com" ? "gitlab" : repository.host === "overlane" ? "overlane" : "github");
20767
+ if (repository.host !== void 0 && repository.host !== HOSTS[provider]) {
20768
+ ctx.addIssue({ code: "custom", path: ["host"], message: `host must be ${HOSTS[provider]} for provider ${provider}` });
20769
+ }
20770
+ const pattern = provider === "gitlab" ? /^[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/ : /^[A-Za-z0-9-]{1,39}$/;
20771
+ if (!pattern.test(repository.owner)) ctx.addIssue({ code: "custom", path: ["owner"], message: "owner is not valid for this provider" });
20772
+ });
20773
+ fillProvider = (record3) => record3["provider"] === void 0 ? { ...record3, provider: resolveProvider({ repository: record3["repository"] }) } : record3;
20774
+ CreateProjectRequest = withCompat(
20775
+ fillProvider,
20776
+ external_exports.object({
20777
+ provider: Provider,
20778
+ repository: ProjectRepository.optional(),
20779
+ connection: ProjectConnection.optional(),
20780
+ name: external_exports.string().min(1).max(100),
20781
+ /** ADR 0018: the hosted code layer is off unless a project turns it on. Missing means false. */
20782
+ codeLayer: external_exports.boolean().optional()
20783
+ }).strict().superRefine(checkProviderShape)
20784
+ );
20729
20785
  UpdateProjectRequest = external_exports.object({ codeLayer: external_exports.boolean() }).strict();
20730
- ProjectRecord = external_exports.object({
20731
- tenantId: TenantId,
20732
- projectId: ProjectId,
20733
- name: external_exports.string().min(1).max(100),
20734
- repository: RepositoryRef,
20735
- releaseVersion: external_exports.string().min(1),
20736
- releaseDigest: Sha256Digest,
20737
- createdAt: Timestamp,
20738
- /** ADR 0018: registers the MCP `code` tool and opens the code routes. Missing in older records means false. */
20739
- codeLayer: external_exports.boolean().default(false)
20740
- }).strict();
20786
+ ProjectRecord = withCompat(
20787
+ fillProvider,
20788
+ external_exports.object({
20789
+ tenantId: TenantId,
20790
+ projectId: ProjectId,
20791
+ name: external_exports.string().min(1).max(100),
20792
+ /** Missing in records from before ADR 0050: reads as `github` with a repository, else `overlane`. */
20793
+ provider: Provider,
20794
+ /** Absent for a native project that has no repository yet. */
20795
+ repository: ProjectRepository.optional(),
20796
+ connection: ProjectConnection.optional(),
20797
+ releaseVersion: external_exports.string().min(1),
20798
+ releaseDigest: Sha256Digest,
20799
+ createdAt: Timestamp,
20800
+ /** ADR 0018: registers the MCP `code` tool and opens the code routes. Missing in older records means false. */
20801
+ codeLayer: external_exports.boolean().default(false)
20802
+ }).strict().superRefine(checkProviderShape)
20803
+ );
20741
20804
  WhoAmI = external_exports.object({
20742
20805
  tenantId: TenantId,
20743
20806
  userId: external_exports.string().min(1),
@@ -20813,7 +20876,7 @@ var init_task_api = __esm({
20813
20876
  });
20814
20877
 
20815
20878
  // ../contracts/src/code-index.ts
20816
- var SourceRange, PRECISION, Precision, SYMBOL_KINDS, SymbolKind, IndexedSymbol, Occurrence, FileShard, ManifestEntry, ManifestUploadResponse, ShardUploadRequest, SnapshotManifest, AnswerProvenance, SymbolHit, ReferenceHit, codePaths;
20879
+ var SourceRange, PRECISION, Precision, SYMBOL_KINDS, SymbolKind, IndexedSymbol, Occurrence, FileShard, ManifestEntry, ManifestUploadResponse, ShardUploadRequest, SnapshotManifest, AnswerProvenance, SymbolHit, ReferenceHit, projectBase, codePaths;
20817
20880
  var init_code_index = __esm({
20818
20881
  "../contracts/src/code-index.ts"() {
20819
20882
  "use strict";
@@ -20856,13 +20919,14 @@ var init_code_index = __esm({
20856
20919
  SnapshotManifest = external_exports.object({
20857
20920
  schemaVersion: external_exports.literal("1"),
20858
20921
  tenantId: TenantId,
20859
- repository: RepositoryRef,
20922
+ repository: RepositoryRef.optional(),
20923
+ projectId: ProjectId.optional(),
20860
20924
  commitSha: CommitSha,
20861
20925
  branch: external_exports.string().min(1).optional(),
20862
20926
  indexers: external_exports.array(external_exports.object({ name: external_exports.string().min(1), version: external_exports.string().min(1) }).strict()).min(1),
20863
20927
  files: external_exports.array(ManifestEntry),
20864
20928
  createdAt: Timestamp
20865
- }).strict();
20929
+ }).strict().refine((manifest) => manifest.repository !== void 0 || manifest.projectId !== void 0, { message: "a manifest names a repository or a projectId" });
20866
20930
  AnswerProvenance = external_exports.object({
20867
20931
  requestedCommit: CommitSha.nullable(),
20868
20932
  indexedCommit: CommitSha.nullable(),
@@ -20874,7 +20938,12 @@ var init_code_index = __esm({
20874
20938
  }).strict();
20875
20939
  SymbolHit = external_exports.object({ path: external_exports.string().min(1), symbol: external_exports.string().min(1), name: external_exports.string().min(1), kind: SymbolKind, range: SourceRange, precision: Precision, source: external_exports.enum(["cloud", "local"]) }).strict();
20876
20940
  ReferenceHit = external_exports.object({ path: external_exports.string().min(1), symbol: external_exports.string().min(1), range: SourceRange, enclosingSymbol: external_exports.string().optional(), source: external_exports.enum(["cloud", "local"]) }).strict();
20941
+ projectBase = (tenantId, projectId) => `/v1/tenants/${encodeURIComponent(tenantId)}/projects/${encodeURIComponent(projectId)}`;
20877
20942
  codePaths = {
20943
+ projectUploadManifest: (tenantId, projectId) => `${projectBase(tenantId, projectId)}/snapshots`,
20944
+ projectUploadShards: (tenantId, projectId, commit) => `${projectBase(tenantId, projectId)}/snapshots/${commit}/shards`,
20945
+ projectPublish: (tenantId, projectId, commit) => `${projectBase(tenantId, projectId)}/snapshots/${commit}/publish`,
20946
+ projectQuery: (tenantId, projectId, tool) => `${projectBase(tenantId, projectId)}/code/${tool}`,
20878
20947
  uploadManifest: (tenantId, owner, repo) => `/v1/tenants/${encodeURIComponent(tenantId)}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/snapshots`,
20879
20948
  uploadShards: (tenantId, owner, repo, commit) => `/v1/tenants/${encodeURIComponent(tenantId)}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/snapshots/${commit}/shards`,
20880
20949
  publish: (tenantId, owner, repo, commit) => `/v1/tenants/${encodeURIComponent(tenantId)}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/snapshots/${commit}/publish`,
@@ -21938,7 +22007,7 @@ function forAgent(issue2) {
21938
22007
  const source = issue2.external?.source ?? "overlane";
21939
22008
  return AgentIssueView.parse({ ...issue2, title: { trust: "untrusted_data", source, text: issue2.title }, description: { trust: "untrusted_data", source, text: issue2.description }, notice: UNTRUSTED_NOTICE });
21940
22009
  }
21941
- var prefixed, IssueId, WorkProjectId, CycleId, LabelId, ViewId, LoopId, RequestId3, Title, Description, Name, ISSUE_STATUSES, IssueStatus, SettableIssueStatus, ASSIGNEE_TYPES, AssigneeType, Assignee, ACTOR_TYPES, ActorType, Actor, TASK_LINK_STATES, IssueTaskLink, IssueTaskLinks, IssueLinks, ISSUE_SOURCES, IssueSource, ExternalRef, record2, Label, WorkProject, Cycle, Issue, UNTRUSTED_NOTICE, UntrustedText, AgentIssueView, ISSUE_FIELDS, IssueField, FieldChangeEvent, VIEW_FIELDS, ViewField, ViewCondition, ViewDefinition, SavedView, ViewGroup, ViewResult, SyncFields, SyncEnvelope, SYNC_MODES, SyncMode, SyncConfig, SetSyncConfigRequest, SyncOutcome, SyncResult, LoopTrigger, LoopDefinition, LOOP_STOP_REASONS, LoopStopReason, LoopRun, IMPORT_SOURCES, ImportSource, ImportRequest, ImportReport, CreateIssueRequest, UpdateIssueRequest, AssignIssueRequest, AssignResult, CreateLabelRequest, CreateWorkProjectRequest, UpdateWorkProjectRequest, CreateCycleRequest, CreateViewRequest, CreateLoopRequest, UpdateLoopRequest, FireLoopRequest, IssueList, LabelList, WorkProjectList, CycleList, ViewList, LoopList, IssueEventList, base2, issuePaths;
22010
+ var prefixed, IssueId, WorkProjectId, CycleId, LabelId, ViewId, LoopId, RequestId3, Title, Description, Name, ISSUE_STATUSES, IssueStatus, SettableIssueStatus, ASSIGNEE_TYPES, AssigneeType, Assignee, ACTOR_TYPES, ActorType, Actor, TASK_LINK_STATES, IssueTaskLink, IssueTaskLinks, IssueLinks, ISSUE_SOURCES, IssueSource, ExternalRef, record2, Label, WorkProject, Cycle, Issue, UNTRUSTED_NOTICE, UntrustedText, AgentIssueView, ISSUE_FIELDS, IssueField, FieldChangeEvent, VIEW_FIELDS, ViewField, ViewCondition, ViewDefinition, SavedView, ViewGroup, ViewResult, SyncFields, SYNC_PROVIDERS, SyncProvider, SyncEnvelope, SYNC_MODES, SyncMode, SyncConfig, SetSyncConfigRequest, SyncOutcome, SyncResult, LoopTrigger, LoopDefinition, LOOP_STOP_REASONS, LoopStopReason, LoopRun, IMPORT_SOURCES, ImportSource, ImportRequest, ImportReport, CreateIssueRequest, UpdateIssueRequest, AssignIssueRequest, AssignResult, CreateLabelRequest, CreateWorkProjectRequest, UpdateWorkProjectRequest, CreateCycleRequest, CreateViewRequest, CreateLoopRequest, UpdateLoopRequest, FireLoopRequest, IssueList, LabelList, WorkProjectList, CycleList, ViewList, LoopList, IssueEventList, base2, issuePaths;
21942
22011
  var init_issues = __esm({
21943
22012
  "../contracts/src/issues.ts"() {
21944
22013
  "use strict";
@@ -22050,35 +22119,47 @@ var init_issues = __esm({
22050
22119
  ViewGroup = external_exports.object({ key: external_exports.string(), issues: external_exports.array(Issue) }).strict();
22051
22120
  ViewResult = external_exports.object({ tenantId: TenantId, viewId: ViewId.nullable(), total: external_exports.number().int().nonnegative(), groups: external_exports.array(ViewGroup) }).strict();
22052
22121
  SyncFields = external_exports.object({ title: Title.optional(), description: Description.optional(), status: SettableIssueStatus.optional(), labels: external_exports.array(external_exports.string().min(1).max(100)).optional(), assigneeLogin: external_exports.string().max(100).nullable().optional() }).strict();
22053
- SyncEnvelope = external_exports.object({
22054
- tenantId: TenantId,
22055
- projectId: ProjectId,
22056
- /** Unique per delivery or change; a second arrival does nothing. */
22057
- idempotencyKey: external_exports.string().min(8).max(200),
22058
- /** Per issue, from the source. A change at or below the highest applied sequence is late. */
22059
- sequence: external_exports.number().int().nonnegative(),
22060
- source: external_exports.enum(["github", "overlane"]),
22061
- /** The source's own clock; resolves a conflict inside the sync window with the server receive time. */
22062
- sourceTimestamp: Timestamp,
22063
- issue: external_exports.object({ externalId: external_exports.string().min(1).max(200), url: external_exports.string().url().max(500).optional() }).strict(),
22064
- change: external_exports.discriminatedUnion("kind", [
22065
- external_exports.object({ kind: external_exports.literal("upsert"), fields: SyncFields }).strict(),
22066
- /** A close carries the issue's other fields too: deliveries are snapshots, so a late earlier edit loses nothing. */
22067
- external_exports.object({ kind: external_exports.literal("external_close"), fields: SyncFields.optional() }).strict(),
22068
- external_exports.object({ kind: external_exports.literal("external_reopen"), fields: SyncFields.optional() }).strict()
22069
- ])
22070
- }).strict();
22122
+ SYNC_PROVIDERS = [...PROVIDERS, "linear", "jira"];
22123
+ SyncProvider = external_exports.enum(SYNC_PROVIDERS);
22124
+ SyncEnvelope = withCompat(
22125
+ (envelope) => envelope["provider"] === void 0 ? { ...envelope, provider: envelope["source"] } : envelope,
22126
+ external_exports.object({
22127
+ tenantId: TenantId,
22128
+ projectId: ProjectId,
22129
+ /** Unique per delivery or change; a second arrival does nothing. */
22130
+ idempotencyKey: external_exports.string().min(8).max(200),
22131
+ /** Per issue, from the source. A change at or below the highest applied sequence is late. */
22132
+ sequence: external_exports.number().int().nonnegative(),
22133
+ source: external_exports.enum(["github", "overlane"]),
22134
+ /** The system on the other side of the sync. Missing reads as `source` (github or overlane); linear, jira and gitlab name themselves here. */
22135
+ provider: SyncProvider,
22136
+ /** The source's own clock; resolves a conflict inside the sync window with the server receive time. */
22137
+ sourceTimestamp: Timestamp,
22138
+ issue: external_exports.object({ externalId: external_exports.string().min(1).max(200), url: external_exports.string().url().max(500).optional() }).strict(),
22139
+ change: external_exports.discriminatedUnion("kind", [
22140
+ external_exports.object({ kind: external_exports.literal("upsert"), fields: SyncFields }).strict(),
22141
+ /** A close carries the issue's other fields too: deliveries are snapshots, so a late earlier edit loses nothing. */
22142
+ external_exports.object({ kind: external_exports.literal("external_close"), fields: SyncFields.optional() }).strict(),
22143
+ external_exports.object({ kind: external_exports.literal("external_reopen"), fields: SyncFields.optional() }).strict()
22144
+ ])
22145
+ }).strict()
22146
+ );
22071
22147
  SYNC_MODES = ["off", "read_only", "write_back"];
22072
22148
  SyncMode = external_exports.enum(SYNC_MODES);
22073
- SyncConfig = external_exports.object({
22074
- tenantId: TenantId,
22075
- projectId: ProjectId,
22076
- repository: external_exports.string().regex(/^[\w.-]+\/[\w.-]+$/).nullable(),
22077
- mode: SyncMode,
22078
- updatedBy: external_exports.string().nullable(),
22079
- updatedAt: Timestamp.nullable()
22080
- }).strict();
22081
- SetSyncConfigRequest = external_exports.object({ requestId: RequestId3, repository: external_exports.string().regex(/^[\w.-]+\/[\w.-]+$/), mode: SyncMode }).strict();
22149
+ SyncConfig = withCompat(
22150
+ (config2) => config2["provider"] === void 0 ? { ...config2, provider: config2["repository"] === null || config2["repository"] === void 0 ? "overlane" : "github" } : config2,
22151
+ external_exports.object({
22152
+ tenantId: TenantId,
22153
+ projectId: ProjectId,
22154
+ /** Missing reads as `github` when a repository is set, otherwise `overlane` (ADR 0050). */
22155
+ provider: SyncProvider,
22156
+ repository: external_exports.string().regex(/^[\w.-]+\/[\w.-]+$/).nullable(),
22157
+ mode: SyncMode,
22158
+ updatedBy: external_exports.string().nullable(),
22159
+ updatedAt: Timestamp.nullable()
22160
+ }).strict()
22161
+ );
22162
+ SetSyncConfigRequest = external_exports.object({ requestId: RequestId3, provider: SyncProvider.optional(), repository: external_exports.string().regex(/^[\w.-]+\/[\w.-]+$/), mode: SyncMode }).strict();
22082
22163
  SyncOutcome = external_exports.enum(["applied", "replayed", "late", "ignored_off", "conflict_resolved", "external_close_recorded"]);
22083
22164
  SyncResult = external_exports.object({ tenantId: TenantId, outcome: SyncOutcome, issueId: IssueId.nullable(), idempotencyKey: external_exports.string() }).strict();
22084
22165
  LoopTrigger = external_exports.discriminatedUnion("kind", [
@@ -22192,13 +22273,23 @@ var init_issues = __esm({
22192
22273
  });
22193
22274
 
22194
22275
  // ../contracts/src/onboarding.ts
22276
+ function readLegacyRepoChoice(raw) {
22277
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return raw;
22278
+ const { kind, installationId, ...rest } = raw;
22279
+ if (kind === void 0 && installationId === void 0) return raw;
22280
+ const out2 = { ...rest };
22281
+ if (out2["provider"] === void 0 && kind !== void 0) out2["provider"] = kind === "native" ? "overlane" : kind;
22282
+ if (out2["provider"] === void 0 && installationId !== void 0) out2["provider"] = "github";
22283
+ if (installationId !== void 0 && out2["connection"] === void 0) out2["connection"] = { installationId };
22284
+ return out2;
22285
+ }
22195
22286
  function initialSteps() {
22196
22287
  return STEP_NAMES.map((step2, i2) => ({ step: step2, status: i2 === 0 ? "done" : i2 === 1 ? "active" : "pending" }));
22197
22288
  }
22198
22289
  function newProgress(tenantId, userId, at) {
22199
22290
  return { tenantId, userId, step: "agents", steps: initialSteps(), data: {}, version: 0, complete: false, updatedAt: at };
22200
22291
  }
22201
- var STEP_NAMES, StepName, StepStatus, RepairAction, FAILURE_REPAIRS, FAILURE_CODES, FailureCodeSchema, StepState, Slug, RepoChoice, OnboardingData, OnboardingProgress, AdvanceRequest, AdvanceResponse, OnboardingEvent, FirstReview, onboardingPaths, PROGRESS_FIXTURE;
22292
+ var STEP_NAMES, StepName, StepStatus, RepairAction, FAILURE_REPAIRS, FAILURE_CODES, FailureCodeSchema, StepState, Slug, RepoChoiceShape, RepoChoice, OnboardingData, OnboardingProgress, AdvanceRequest, AdvanceResponse, OnboardingEvent, FirstReview, onboardingPaths, PROGRESS_FIXTURE;
22202
22293
  var init_onboarding = __esm({
22203
22294
  "../contracts/src/onboarding.ts"() {
22204
22295
  "use strict";
@@ -22212,8 +22303,8 @@ var init_onboarding = __esm({
22212
22303
  "sign-in-cancelled": { id: "retry-sign-in", text: "Sign-in was cancelled. Try again, or use the email link." },
22213
22304
  "agent-not-connected": { id: "retry-connect", text: "The agent has not connected yet. Run the plugin command shown, then check again." },
22214
22305
  "agent-oauth-denied": { id: "reauthorise", text: "Access was denied in the agent's own sign-in. Approve it there, then check again." },
22215
- "install-cancelled": { id: "retry-install", text: "The GitHub App install was cancelled. Retry the install, or use a native repository." },
22216
- "repo-unreachable": { id: "pick-another-repo", text: "That repository could not be read. Pick another, or re-run the install to grant access." },
22306
+ "install-cancelled": { id: "retry-install", text: "The GitHub App install was cancelled. Retry the install, or continue with a native Overlane project (no GitHub account needed)." },
22307
+ "repo-unreachable": { id: "pick-another-repo", text: "That repository could not be read. Pick another, continue with a native Overlane project, or re-run the connection to grant access." },
22217
22308
  "task-failed": { id: "retry-task", text: "The first task did not finish. Retry it, or pick a smaller template." },
22218
22309
  "review-unavailable": { id: "reload-review", text: "The review is not ready. Reload it, or open the task to see its evidence." },
22219
22310
  "invite-failed": { id: "retry-invite", text: "An invitation could not be sent. Check the address and try again, or skip this step." }
@@ -22227,13 +22318,14 @@ var init_onboarding = __esm({
22227
22318
  repair: RepairAction.optional()
22228
22319
  }).strict().refine((s) => s.status === "failed" === (s.repair !== void 0 && s.failure !== void 0), { message: "a failed step carries a failure code and a repair action, and no other step does" });
22229
22320
  Slug = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,39}$/);
22230
- RepoChoice = external_exports.object({
22231
- kind: external_exports.enum(["github", "native"]),
22321
+ RepoChoiceShape = external_exports.object({
22322
+ provider: Provider.default("overlane"),
22232
22323
  owner: external_exports.string().regex(/^[A-Za-z0-9-]{1,39}$/),
22233
22324
  name: external_exports.string().regex(/^[A-Za-z0-9._-]{1,100}$/),
22234
- /** The GitHub App installation number; absent for a native repository. */
22235
- installationId: external_exports.number().int().positive().optional()
22325
+ /** Absent for a native repository. */
22326
+ connection: external_exports.object({ installationId: external_exports.number().int().positive().optional(), externalId: external_exports.string().min(1).max(200).optional() }).strict().optional()
22236
22327
  }).strict();
22328
+ RepoChoice = external_exports.preprocess(readLegacyRepoChoice, RepoChoiceShape);
22237
22329
  OnboardingData = external_exports.object({
22238
22330
  agents: external_exports.array(Slug).max(20).optional(),
22239
22331
  bots: external_exports.array(Slug).max(20).optional(),
@@ -22286,6 +22378,208 @@ var init_onboarding = __esm({
22286
22378
  }
22287
22379
  });
22288
22380
 
22381
+ // ../contracts/src/audit.ts
22382
+ function canonicalJson(value) {
22383
+ if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
22384
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
22385
+ const entries = Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
22386
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`).join(",")}}`;
22387
+ }
22388
+ function sha256Hex(text) {
22389
+ const data = new TextEncoder().encode(text);
22390
+ const bitLength = data.length * 8;
22391
+ const padded = new Uint8Array(Math.ceil((data.length + 9) / 64) * 64);
22392
+ padded.set(data);
22393
+ padded[data.length] = 128;
22394
+ const view = new DataView(padded.buffer);
22395
+ view.setUint32(padded.length - 8, Math.floor(bitLength / 2 ** 32));
22396
+ view.setUint32(padded.length - 4, bitLength >>> 0);
22397
+ const h = new Uint32Array([1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]);
22398
+ const w = new Uint32Array(64);
22399
+ const rotr = (x, n) => x >>> n | x << 32 - n;
22400
+ for (let offset = 0; offset < padded.length; offset += 64) {
22401
+ for (let i2 = 0; i2 < 16; i2 += 1) w[i2] = view.getUint32(offset + i2 * 4);
22402
+ for (let i2 = 16; i2 < 64; i2 += 1) {
22403
+ const a2 = w[i2 - 15];
22404
+ const b2 = w[i2 - 2];
22405
+ const s0 = rotr(a2, 7) ^ rotr(a2, 18) ^ a2 >>> 3;
22406
+ const s1 = rotr(b2, 17) ^ rotr(b2, 19) ^ b2 >>> 10;
22407
+ w[i2] = w[i2 - 16] + s0 + w[i2 - 7] + s1 >>> 0;
22408
+ }
22409
+ let [a, b, c, d, e, f, g, hh] = h;
22410
+ for (let i2 = 0; i2 < 64; i2 += 1) {
22411
+ const t1 = hh + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + (e & f ^ ~e & g) + K[i2] + w[i2] >>> 0;
22412
+ const t2 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + (a & b ^ a & c ^ b & c) >>> 0;
22413
+ hh = g;
22414
+ g = f;
22415
+ f = e;
22416
+ e = d + t1 >>> 0;
22417
+ d = c;
22418
+ c = b;
22419
+ b = a;
22420
+ a = t1 + t2 >>> 0;
22421
+ }
22422
+ const sums = [a, b, c, d, e, f, g, hh];
22423
+ for (let i2 = 0; i2 < 8; i2 += 1) h[i2] = h[i2] + sums[i2] >>> 0;
22424
+ }
22425
+ return [...h].map((n) => n.toString(16).padStart(8, "0")).join("");
22426
+ }
22427
+ function auditHash(prevHash, body2) {
22428
+ return sha256Hex(`${prevHash}
22429
+ ${canonicalJson(AuditEventBody.parse(body2))}`);
22430
+ }
22431
+ function chainAuditEvent(prevHash, body2) {
22432
+ const previous = prevHash ?? AUDIT_GENESIS_HASH;
22433
+ return AuditEvent.parse({ ...body2, prevHash: previous, hash: auditHash(previous, body2) });
22434
+ }
22435
+ var AUDIT_CATEGORIES, AuditCategory, AUDIT_ACTIONS, AUDIT_ACTION_NAMES, AuditActionName, AUDIT_RESULTS, AuditResult, AuditPrincipalType, AuditTarget, Hash, AUDIT_GENESIS_HASH, AuditEventBody, AuditEvent, AuditList, AuditVerification, K, FIXTURE_AT, fixtureBodies, AUDIT_FIXTURE;
22436
+ var init_audit = __esm({
22437
+ "../contracts/src/audit.ts"() {
22438
+ "use strict";
22439
+ init_zod();
22440
+ init_common();
22441
+ AUDIT_CATEGORIES = ["admin", "policy", "token"];
22442
+ AuditCategory = external_exports.enum(AUDIT_CATEGORIES);
22443
+ AUDIT_ACTIONS = {
22444
+ "member.removed": "admin",
22445
+ "member.role_changed": "admin",
22446
+ "invitation.created": "admin",
22447
+ "invitation.revoked": "admin",
22448
+ "run_policy.updated": "policy",
22449
+ "project.updated": "policy",
22450
+ "release.published": "policy",
22451
+ "release.promoted": "policy",
22452
+ "release.withdrawn": "policy",
22453
+ "release.pinned": "policy",
22454
+ "release.rolled_back": "policy",
22455
+ "memory_settings.updated": "policy",
22456
+ "issue_sync.updated": "policy",
22457
+ "loop.created": "policy",
22458
+ "loop.updated": "policy",
22459
+ "loop.deleted": "policy",
22460
+ "bot.registered": "policy",
22461
+ "bot.revoked": "policy",
22462
+ "bot.key_rotated": "policy",
22463
+ "token.created": "token",
22464
+ "token.revoked": "token"
22465
+ };
22466
+ AUDIT_ACTION_NAMES = Object.keys(AUDIT_ACTIONS);
22467
+ AuditActionName = external_exports.enum(Object.keys(AUDIT_ACTIONS));
22468
+ AUDIT_RESULTS = ["success", "denied", "failure"];
22469
+ AuditResult = external_exports.enum(AUDIT_RESULTS);
22470
+ AuditPrincipalType = external_exports.enum(["user", "agent", "system"]);
22471
+ AuditTarget = external_exports.object({ type: external_exports.string().min(1).max(40), id: external_exports.string().max(200) }).strict();
22472
+ Hash = external_exports.string().regex(/^[0-9a-f]{64}$/, "must be 64 lowercase hex characters");
22473
+ AUDIT_GENESIS_HASH = "0".repeat(64);
22474
+ AuditEventBody = external_exports.object({
22475
+ tenantId: TenantId,
22476
+ /** 1, 2, 3 ... per tenant, with no gaps. */
22477
+ seq: external_exports.number().int().positive(),
22478
+ eventId: external_exports.string().min(1).max(64),
22479
+ at: Timestamp,
22480
+ /** User ID, agent token ID or `system`. */
22481
+ actor: external_exports.string().min(1).max(200),
22482
+ principalType: AuditPrincipalType,
22483
+ role: external_exports.string().min(1).max(40).nullable(),
22484
+ action: AuditActionName,
22485
+ category: AuditCategory,
22486
+ target: AuditTarget,
22487
+ result: AuditResult
22488
+ }).strict();
22489
+ AuditEvent = AuditEventBody.extend({ prevHash: Hash, hash: Hash }).strict().refine((event) => AUDIT_ACTIONS[event.action] === event.category, { message: "category does not match the action", path: ["category"] });
22490
+ AuditList = external_exports.object({
22491
+ tenantId: TenantId,
22492
+ events: external_exports.array(AuditEvent),
22493
+ /** Pass as `after` to read the next page; null when this is the last page. */
22494
+ nextAfter: external_exports.number().int().nonnegative().nullable(),
22495
+ /** Hash of the newest row of the tenant's chain (null for an empty log). */
22496
+ head: Hash.nullable()
22497
+ }).strict();
22498
+ AuditVerification = external_exports.object({
22499
+ tenantId: TenantId,
22500
+ ok: external_exports.boolean(),
22501
+ checked: external_exports.number().int().nonnegative(),
22502
+ head: Hash.nullable(),
22503
+ /** The first row that fails (its seq) and why. */
22504
+ brokenAt: external_exports.number().int().positive().optional(),
22505
+ reason: external_exports.enum(["bad_hash", "bad_link", "bad_sequence", "wrong_tenant", "bad_category"]).optional()
22506
+ }).strict();
22507
+ K = new Uint32Array([
22508
+ 1116352408,
22509
+ 1899447441,
22510
+ 3049323471,
22511
+ 3921009573,
22512
+ 961987163,
22513
+ 1508970993,
22514
+ 2453635748,
22515
+ 2870763221,
22516
+ 3624381080,
22517
+ 310598401,
22518
+ 607225278,
22519
+ 1426881987,
22520
+ 1925078388,
22521
+ 2162078206,
22522
+ 2614888103,
22523
+ 3248222580,
22524
+ 3835390401,
22525
+ 4022224774,
22526
+ 264347078,
22527
+ 604807628,
22528
+ 770255983,
22529
+ 1249150122,
22530
+ 1555081692,
22531
+ 1996064986,
22532
+ 2554220882,
22533
+ 2821834349,
22534
+ 2952996808,
22535
+ 3210313671,
22536
+ 3336571891,
22537
+ 3584528711,
22538
+ 113926993,
22539
+ 338241895,
22540
+ 666307205,
22541
+ 773529912,
22542
+ 1294757372,
22543
+ 1396182291,
22544
+ 1695183700,
22545
+ 1986661051,
22546
+ 2177026350,
22547
+ 2456956037,
22548
+ 2730485921,
22549
+ 2820302411,
22550
+ 3259730800,
22551
+ 3345764771,
22552
+ 3516065817,
22553
+ 3600352804,
22554
+ 4094571909,
22555
+ 275423344,
22556
+ 430227734,
22557
+ 506948616,
22558
+ 659060556,
22559
+ 883997877,
22560
+ 958139571,
22561
+ 1322822218,
22562
+ 1537002063,
22563
+ 1747873779,
22564
+ 1955562222,
22565
+ 2024104815,
22566
+ 2227730452,
22567
+ 2361852424,
22568
+ 2428436474,
22569
+ 2756734187,
22570
+ 3204031479,
22571
+ 3329325298
22572
+ ]);
22573
+ FIXTURE_AT = "2026-10-09T00:00:00.000Z";
22574
+ fixtureBodies = [
22575
+ { tenantId: "tm-1", seq: 1, eventId: "aud_1", at: FIXTURE_AT, actor: "u-owner", principalType: "user", role: "owner", action: "invitation.created", category: "admin", target: { type: "invitation", id: "inv_1" }, result: "success" },
22576
+ { tenantId: "tm-1", seq: 2, eventId: "aud_2", at: "2026-10-09T00:05:00.000Z", actor: "u-admin", principalType: "user", role: "admin", action: "run_policy.updated", category: "policy", target: { type: "project", id: "prj-demo" }, result: "success" },
22577
+ { tenantId: "tm-1", seq: 3, eventId: "aud_3", at: "2026-10-09T00:10:00.000Z", actor: "u-viewer", principalType: "user", role: "viewer", action: "token.created", category: "token", target: { type: "token", id: "" }, result: "denied" }
22578
+ ];
22579
+ AUDIT_FIXTURE = fixtureBodies.reduce((rows, body2) => [...rows, chainAuditEvent(rows.at(-1)?.hash ?? null, body2)], []);
22580
+ }
22581
+ });
22582
+
22289
22583
  // ../contracts/src/docs-service.ts
22290
22584
  function scoped(shape2) {
22291
22585
  return external_exports.discriminatedUnion("visibility", [external_exports.object({ ...shape2, ...PublicScope }).strict(), external_exports.object({ ...shape2, ...PrivateScope }).strict()]);
@@ -22505,7 +22799,7 @@ var init_docs_service = __esm({
22505
22799
  function base3(tenantId, projectId) {
22506
22800
  return `/v1/tenants/${encodeURIComponent(tenantId)}/projects/${encodeURIComponent(projectId)}/review`;
22507
22801
  }
22508
- var SEVERITIES, Severity, FINDING_STATUSES, FindingStatus, counts, Finding, REVIEW_SKIP_REASONS, SkipEntry, SkipList, TokenCapNotice, REVIEW_MODES, ReviewMode, REVIEW_TRIGGERS, REVIEW_STATUSES, ReviewSummary, ReviewRun, REVIEW_PRIVACY_TEXT, ReviewSettings, UpdateReviewSettingsRequest, PullFile, PullRequestSnapshot, ReviewRunRequest, ReviewRunResponse, ReviewStatusResponse, ReviewFindingsResponse, FEEDBACK_KINDS, FeedbackRequest, LearnedRule, FeedbackResponse, AutofixRequest, AutofixResponse, RawFinding, reviewPaths;
22802
+ var SEVERITIES, Severity, FINDING_STATUSES, FindingStatus, counts, Finding, REVIEW_SKIP_REASONS, SkipEntry, SkipList, TokenCapNotice, REVIEW_MODES, ReviewMode, REVIEW_TRIGGERS, REVIEW_STATUSES, ReviewSummary, ReviewRun, REVIEW_PRIVACY_TEXT, ReviewSettings, UpdateReviewSettingsRequest, PullFile, PullRequestSnapshot, MAX_PATCH_BYTES, ReviewRunRequest, ReviewRunResponse, ReviewStatusResponse, ReviewFindingsResponse, FEEDBACK_KINDS, FeedbackRequest, LearnedRule, FeedbackResponse, AutofixRequest, AutofixResponse, RawFinding, reviewPaths;
22509
22803
  var init_review = __esm({
22510
22804
  "../contracts/src/review.ts"() {
22511
22805
  "use strict";
@@ -22520,6 +22814,9 @@ var init_review = __esm({
22520
22814
  tenantId: TenantId,
22521
22815
  id: external_exports.string().min(1),
22522
22816
  projectId: ProjectId,
22817
+ /** Where the change lives. A record from before ADR 0050 has none: read it with `reviewProvider`, which gives `github`. */
22818
+ provider: Provider.optional(),
22819
+ /** The repository key: `owner/name` for a connection, `overlane/<projectId>` or `patch/<projectId>` for native reviews. */
22523
22820
  repository: external_exports.string().min(1),
22524
22821
  pullNumber: external_exports.number().int().positive(),
22525
22822
  path: external_exports.string().min(1),
@@ -22573,6 +22870,7 @@ var init_review = __esm({
22573
22870
  tenantId: TenantId,
22574
22871
  id: external_exports.string().min(1),
22575
22872
  projectId: ProjectId,
22873
+ provider: Provider.optional(),
22576
22874
  repository: external_exports.string().min(1),
22577
22875
  pullNumber: external_exports.number().int().positive(),
22578
22876
  headSha: CommitSha,
@@ -22613,6 +22911,7 @@ var init_review = __esm({
22613
22911
  patch: external_exports.string().max(4e5).optional()
22614
22912
  }).strict();
22615
22913
  PullRequestSnapshot = external_exports.object({
22914
+ provider: Provider.optional(),
22616
22915
  repository: external_exports.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/),
22617
22916
  number: external_exports.number().int().positive(),
22618
22917
  headSha: CommitSha,
@@ -22623,10 +22922,20 @@ var init_review = __esm({
22623
22922
  fork: external_exports.boolean().default(false),
22624
22923
  files: external_exports.array(PullFile).max(3e3)
22625
22924
  }).strict();
22925
+ MAX_PATCH_BYTES = 2e6;
22626
22926
  ReviewRunRequest = external_exports.object({
22627
22927
  requestId: external_exports.string().min(1).max(128),
22628
22928
  trigger: external_exports.enum(REVIEW_TRIGGERS).default("manual"),
22629
22929
  source: external_exports.discriminatedUnion("kind", [
22930
+ external_exports.object({
22931
+ kind: external_exports.literal("patch"),
22932
+ diff: external_exports.string().min(1).max(MAX_PATCH_BYTES),
22933
+ title: external_exports.string().max(500).optional(),
22934
+ /** Names this change so a re-review of the same change merges its findings; defaults to `patch`. */
22935
+ label: external_exports.string().regex(/^[A-Za-z0-9._-]{1,64}$/).optional(),
22936
+ author: external_exports.string().min(1).max(100).optional()
22937
+ }).strict(),
22938
+ external_exports.object({ kind: external_exports.literal("overlane"), number: external_exports.number().int().positive(), repository: external_exports.string().min(1).optional() }).strict(),
22630
22939
  external_exports.object({ kind: external_exports.literal("github"), repository: external_exports.string().min(1), number: external_exports.number().int().positive() }).strict(),
22631
22940
  external_exports.object({ kind: external_exports.literal("inline"), pull: PullRequestSnapshot }).strict()
22632
22941
  ])
@@ -23444,6 +23753,7 @@ var init_src = __esm({
23444
23753
  init_memory();
23445
23754
  init_issues();
23446
23755
  init_onboarding();
23756
+ init_audit();
23447
23757
  init_docs_service();
23448
23758
  init_review();
23449
23759
  init_guardrails();
@@ -30784,25 +31094,25 @@ var require_dist = __commonJS({
30784
31094
  });
30785
31095
 
30786
31096
  // src/assets.ts
30787
- import { basename as basename4, join as join24, resolve as resolve10 } from "node:path";
31097
+ import { basename as basename5, join as join24, resolve as resolve11 } from "node:path";
30788
31098
  import { fileURLToPath } from "node:url";
30789
31099
  function packageRoot(env = process.env) {
30790
31100
  const override = env["MVRX_PACKAGE_ROOT"];
30791
31101
  if (override !== void 0 && override !== "") return override;
30792
- return resolve10(fileURLToPath(new URL(".", import.meta.url)), "..");
31102
+ return resolve11(fileURLToPath(new URL(".", import.meta.url)), "..");
30793
31103
  }
30794
31104
  function assetDir(env = process.env) {
30795
31105
  const override = env["MVRX_ASSET_DIR"];
30796
31106
  return override !== void 0 && override !== "" ? override : join24(packageRoot(env), "assets");
30797
31107
  }
30798
31108
  function assetFile(name2) {
30799
- return join24(assetDir(), basename4(name2));
31109
+ return join24(assetDir(), basename5(name2));
30800
31110
  }
30801
31111
  var VERSION;
30802
31112
  var init_assets = __esm({
30803
31113
  "src/assets.ts"() {
30804
31114
  "use strict";
30805
- VERSION = true ? "0.1.124" : "0.0.0-dev";
31115
+ VERSION = true ? "0.1.126" : "0.0.0-dev";
30806
31116
  }
30807
31117
  });
30808
31118
 
@@ -32220,7 +32530,7 @@ function createFileRegistry(...args2) {
32220
32530
  if (seen.has(protoFileName)) {
32221
32531
  continue;
32222
32532
  }
32223
- const dep = resolve13(protoFileName);
32533
+ const dep = resolve14(protoFileName);
32224
32534
  if (!dep) {
32225
32535
  throw new Error(`Unable to resolve ${protoFileName}, imported by ${file2.name}`);
32226
32536
  }
@@ -32234,7 +32544,7 @@ function createFileRegistry(...args2) {
32234
32544
  return deps.concat(...deps.map(recurseDeps));
32235
32545
  };
32236
32546
  const input2 = args2[0];
32237
- const resolve13 = args2[1];
32547
+ const resolve14 = args2[1];
32238
32548
  const seen = /* @__PURE__ */ new Set();
32239
32549
  for (const file2 of [input2, ...recurseDeps(input2)].reverse()) {
32240
32550
  addFile(file2, registry2);
@@ -34647,13 +34957,13 @@ async function Module2(moduleArg = {}) {
34647
34957
  }
34648
34958
  readAsync = /* @__PURE__ */ __name(async (url2) => {
34649
34959
  if (isFileURI(url2)) {
34650
- return new Promise((resolve13, reject) => {
34960
+ return new Promise((resolve14, reject) => {
34651
34961
  var xhr = new XMLHttpRequest();
34652
34962
  xhr.open("GET", url2, true);
34653
34963
  xhr.responseType = "arraybuffer";
34654
34964
  xhr.onload = () => {
34655
34965
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
34656
- resolve13(xhr.response);
34966
+ resolve14(xhr.response);
34657
34967
  return;
34658
34968
  }
34659
34969
  reject(xhr.status);
@@ -34849,9 +35159,9 @@ async function Module2(moduleArg = {}) {
34849
35159
  __name(receiveInstantiationResult, "receiveInstantiationResult");
34850
35160
  var info2 = getWasmImports();
34851
35161
  if (Module["instantiateWasm"]) {
34852
- return new Promise((resolve13, reject) => {
35162
+ return new Promise((resolve14, reject) => {
34853
35163
  Module["instantiateWasm"](info2, (mod, inst) => {
34854
- resolve13(receiveInstance(mod, inst));
35164
+ resolve14(receiveInstance(mod, inst));
34855
35165
  });
34856
35166
  });
34857
35167
  }
@@ -36184,8 +36494,8 @@ async function Module2(moduleArg = {}) {
36184
36494
  if (runtimeInitialized) {
36185
36495
  moduleRtn = Module;
36186
36496
  } else {
36187
- moduleRtn = new Promise((resolve13, reject) => {
36188
- readyPromiseResolve = resolve13;
36497
+ moduleRtn = new Promise((resolve14, reject) => {
36498
+ readyPromiseResolve = resolve14;
36189
36499
  readyPromiseReject = reject;
36190
36500
  });
36191
36501
  }
@@ -38734,9 +39044,9 @@ import { lstat, readFile as readFile4 } from "node:fs/promises";
38734
39044
  import { join as join25 } from "node:path";
38735
39045
  import { promisify } from "node:util";
38736
39046
  function shardKeyOf(shard) {
38737
- return `sha256:${sha256Hex(Buffer.from(`${shard.path}\0${shard.contentHash}\0${shard.precision}`, "utf8"))}`;
39047
+ return `sha256:${sha256Hex2(Buffer.from(`${shard.path}\0${shard.contentHash}\0${shard.precision}`, "utf8"))}`;
38738
39048
  }
38739
- function sha256Hex(bytes) {
39049
+ function sha256Hex2(bytes) {
38740
39050
  return createHash6("sha256").update(bytes).digest("hex");
38741
39051
  }
38742
39052
  async function listTrackedFiles(repoRoot) {
@@ -38762,7 +39072,7 @@ async function hashRegularFile(repoRoot, path) {
38762
39072
  try {
38763
39073
  const stats = await lstat(absolute);
38764
39074
  if (!stats.isFile()) return null;
38765
- return `sha256:${sha256Hex(await readFile4(absolute))}`;
39075
+ return `sha256:${sha256Hex2(await readFile4(absolute))}`;
38766
39076
  } catch (error62) {
38767
39077
  if (error62 instanceof Error && "code" in error62 && error62.code === "ENOENT") return null;
38768
39078
  throw error62;
@@ -38798,7 +39108,7 @@ async function buildSnapshot(options) {
38798
39108
  if (languageForPath(path) === null) return { path, shard: null };
38799
39109
  const bytes = await readFile4(join25(options.repoRoot, path));
38800
39110
  if (bytes.byteLength > MAX_PARSE_BYTES) return { path, shard: null };
38801
- const hash2 = `sha256:${sha256Hex(bytes)}`;
39111
+ const hash2 = `sha256:${sha256Hex2(bytes)}`;
38802
39112
  if (hash2 !== hashes.get(path)) throw new Error(`${path} changed while the snapshot was being built`);
38803
39113
  const shard = await parseDeclarations(path, bytes.toString("utf8"));
38804
39114
  return { path, shard: shard ? { ...shard, contentHash: hash2 } : null };
@@ -38812,7 +39122,8 @@ async function buildSnapshot(options) {
38812
39122
  const manifest = SnapshotManifest.parse({
38813
39123
  schemaVersion: "1",
38814
39124
  tenantId: options.tenantId,
38815
- repository: options.repository,
39125
+ ...options.repository !== void 0 ? { repository: options.repository } : {},
39126
+ ...options.projectId !== void 0 ? { projectId: options.projectId } : {},
38816
39127
  commitSha: options.commitSha,
38817
39128
  ...options.branch !== void 0 ? { branch: options.branch } : {},
38818
39129
  indexers: [...indexers.values()].sort((a, b) => compareStrings(a.name, b.name) || compareStrings(a.version, b.version)),
@@ -38843,7 +39154,9 @@ async function uploadSnapshot(options) {
38843
39154
  const doFetch = options.fetch ?? fetch;
38844
39155
  const base4 = options.serviceUrl.replace(/\/+$/, "");
38845
39156
  const manifest = SnapshotManifest.parse(options.manifest);
38846
- const { tenantId, repository, commitSha } = manifest;
39157
+ const { tenantId, repository, projectId, commitSha } = manifest;
39158
+ const byProject = projectId !== void 0 && (repository === void 0 || options.byProject === true);
39159
+ if (!byProject && repository === void 0) throw new Error("the manifest names neither a repository nor a project");
38847
39160
  const headers = { authorization: `Bearer ${options.token}`, "content-type": "application/json" };
38848
39161
  const send2 = async (path, body2) => {
38849
39162
  for (let attempt2 = 1; ; attempt2 += 1) {
@@ -38861,16 +39174,17 @@ async function uploadSnapshot(options) {
38861
39174
  failure4 = error62 instanceof Error ? error62.message : String(error62);
38862
39175
  if (attempt2 >= ATTEMPTS) throw new Error(`POST ${path} failed: ${failure4}`);
38863
39176
  }
38864
- await new Promise((resolve13) => setTimeout(resolve13, (options.retryDelayMs ?? 500) * attempt2));
39177
+ await new Promise((resolve14) => setTimeout(resolve14, (options.retryDelayMs ?? 500) * attempt2));
38865
39178
  }
38866
39179
  };
38867
- const manifestResponse = await send2(codePaths.uploadManifest(tenantId, repository.owner, repository.name), JSON.stringify(manifest));
39180
+ const manifestPath = byProject ? codePaths.projectUploadManifest(tenantId, projectId ?? "") : codePaths.uploadManifest(tenantId, repository?.owner ?? "", repository?.name ?? "");
39181
+ const manifestResponse = await send2(manifestPath, JSON.stringify(manifest));
38868
39182
  const { missing } = ManifestUploadResponse.parse(await manifestResponse.json());
38869
39183
  const wanted = new Set(missing);
38870
39184
  for (const hash2 of options.existing ?? []) wanted.delete(hash2);
38871
39185
  const maxShards = options.maxBatchShards ?? MAX_BATCH_SHARDS;
38872
39186
  const maxBytes = options.maxBatchBytes ?? MAX_BATCH_BYTES;
38873
- const shardsPath = codePaths.uploadShards(tenantId, repository.owner, repository.name, commitSha);
39187
+ const shardsPath = byProject ? codePaths.projectUploadShards(tenantId, projectId ?? "", commitSha) : codePaths.uploadShards(tenantId, repository?.owner ?? "", repository?.name ?? "", commitSha);
38874
39188
  let batch = [];
38875
39189
  let batchBytes = 0;
38876
39190
  let uploadedShards = 0;
@@ -38894,7 +39208,7 @@ async function uploadSnapshot(options) {
38894
39208
  batchBytes += size;
38895
39209
  }
38896
39210
  await flush();
38897
- await send2(codePaths.publish(tenantId, repository.owner, repository.name, commitSha), "{}");
39211
+ await send2(byProject ? codePaths.projectPublish(tenantId, projectId ?? "", commitSha) : codePaths.publish(tenantId, repository?.owner ?? "", repository?.name ?? "", commitSha), "{}");
38898
39212
  return { missing: missing.length, uploadedShards, batches };
38899
39213
  }
38900
39214
  var MAX_BATCH_SHARDS, MAX_BATCH_BYTES, ATTEMPTS, HttpError;
@@ -38939,7 +39253,7 @@ var init_oidc = __esm({
38939
39253
  // ../index-builder/src/run.ts
38940
39254
  import { execFile as execFile2 } from "node:child_process";
38941
39255
  import { mkdir as mkdir3, readdir as readdir4, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
38942
- import { join as join26, resolve as resolve11 } from "node:path";
39256
+ import { join as join26, resolve as resolve12 } from "node:path";
38943
39257
  import { parseArgs as parseArgs2 } from "node:util";
38944
39258
  import { promisify as promisify2 } from "node:util";
38945
39259
  async function git3(root, args2) {
@@ -38960,9 +39274,11 @@ async function repositoryFromRemote(root) {
38960
39274
  }
38961
39275
  }
38962
39276
  async function snapshotFromArgs(values, env) {
38963
- const root = resolve11(typeof values["root"] === "string" ? values["root"] : process.cwd());
38964
- const repoText = (typeof values["repo"] === "string" ? values["repo"] : void 0) ?? env["GITHUB_REPOSITORY"] ?? await repositoryFromRemote(root);
38965
- if (!repoText) throw new UsageError2("cannot determine the repository; pass --repo owner/name");
39277
+ const root = resolve12(typeof values["root"] === "string" ? values["root"] : process.cwd());
39278
+ const projectId = typeof values["project"] === "string" ? values["project"] : void 0;
39279
+ if (projectId !== void 0 && !ProjectId.safeParse(projectId).success) throw new UsageError2(`--project must be a project identifier, got "${projectId}"`);
39280
+ const repoText = projectId !== void 0 ? typeof values["repo"] === "string" ? values["repo"] : void 0 : (typeof values["repo"] === "string" ? values["repo"] : void 0) ?? env["GITHUB_REPOSITORY"] ?? await repositoryFromRemote(root);
39281
+ if (!repoText && projectId === void 0) throw new UsageError2("cannot determine the repository; pass --project ID, or --repo owner/name");
38966
39282
  const commit = (typeof values["commit"] === "string" ? values["commit"] : void 0) ?? env["GITHUB_SHA"] ?? await git3(root, ["rev-parse", "HEAD"]);
38967
39283
  const branch = typeof values["branch"] === "string" ? values["branch"] : void 0;
38968
39284
  const tenant = (typeof values["tenant"] === "string" ? values["tenant"] : void 0) ?? env["HARNESS_TENANT"];
@@ -38970,9 +39286,10 @@ async function snapshotFromArgs(values, env) {
38970
39286
  const scip = Array.isArray(values["scip"]) ? values["scip"] : [];
38971
39287
  return buildSnapshot({
38972
39288
  repoRoot: root,
38973
- scipFiles: scip.map((file2) => resolve11(file2)),
39289
+ scipFiles: scip.map((file2) => resolve12(file2)),
38974
39290
  tenantId: tenant,
38975
- repository: parseRepository(repoText),
39291
+ ...repoText ? { repository: parseRepository(repoText) } : {},
39292
+ ...projectId !== void 0 ? { projectId } : {},
38976
39293
  commitSha: commit,
38977
39294
  ...branch !== void 0 ? { branch } : {}
38978
39295
  });
@@ -38985,17 +39302,18 @@ async function runCli2(argv, env, out2 = console.log, err2 = console.error) {
38985
39302
  const outDir = values.out;
38986
39303
  if (!outDir) throw new UsageError2("build needs --out DIR");
38987
39304
  const built = await snapshotFromArgs({ ...values, tenant: values.tenant ?? env["HARNESS_TENANT"] ?? "local" }, env);
38988
- await writeSnapshot(resolve11(outDir), built);
38989
- out2(`built ${built.shards.length} shards (${built.uncovered.length} files uncovered) into ${resolve11(outDir)}`);
39305
+ await writeSnapshot(resolve12(outDir), built);
39306
+ out2(`built ${built.shards.length} shards (${built.uncovered.length} files uncovered) into ${resolve12(outDir)}`);
38990
39307
  return 0;
38991
39308
  }
38992
39309
  if (command === "upload") {
38993
39310
  const service = values.service;
38994
39311
  if (!service) throw new UsageError2("upload needs --service URL");
38995
39312
  const built = await snapshotFromArgs(values, env);
38996
- const token = env["ACTIONS_ID_TOKEN_REQUEST_URL"] ? await getOidcToken(values.audience ?? service, env) : env["HARNESS_TOKEN"];
38997
- if (!token) throw new UsageError2("no credentials: run in GitHub Actions with id-token: write, or set HARNESS_TOKEN");
38998
- const result = await uploadSnapshot({ serviceUrl: service, token, manifest: built.manifest, shards: built.shards });
39313
+ const byProject = values.project !== void 0;
39314
+ const token = !byProject && env["ACTIONS_ID_TOKEN_REQUEST_URL"] ? await getOidcToken(values.audience ?? service, env) : env["HARNESS_TOKEN"];
39315
+ if (!token) throw new UsageError2(byProject ? "no credentials: set HARNESS_TOKEN" : "no credentials: run in GitHub Actions with id-token: write, or set HARNESS_TOKEN");
39316
+ const result = await uploadSnapshot({ serviceUrl: service, token, manifest: built.manifest, shards: built.shards, ...byProject ? { byProject: true } : {} });
38999
39317
  out2(`published ${built.manifest.commitSha}: ${built.shards.length} shards, ${result.missing} new, ${result.batches} batches`);
39000
39318
  return 0;
39001
39319
  }
@@ -39030,10 +39348,12 @@ var init_run = __esm({
39030
39348
  init_upload();
39031
39349
  execFileAsync2 = promisify2(execFile2);
39032
39350
  USAGE = `usage:
39033
- mvrx-index build --scip FILE [--scip FILE ...] --out DIR [--repo owner/name] [--tenant ID] [--commit SHA] [--branch B] [--root DIR]
39034
- mvrx-index upload --service URL --tenant ID --repo owner/name --commit SHA [--branch B] [--scip FILE ...] [--root DIR] [--audience URL]
39351
+ mvrx-index build --scip FILE [--scip FILE ...] --out DIR [--project ID | --repo owner/name] [--tenant ID] [--commit SHA] [--branch B] [--root DIR]
39352
+ mvrx-index upload --service URL --tenant ID (--project ID | --repo owner/name) --commit SHA [--branch B] [--scip FILE ...] [--root DIR] [--audience URL]
39035
39353
 
39036
- Authentication for upload: the GitHub Actions OIDC token when ACTIONS_ID_TOKEN_REQUEST_URL is set, otherwise HARNESS_TOKEN.
39354
+ --project indexes an Overlane project (no GitHub repository needed) and uploads with HARNESS_TOKEN.
39355
+ --repo names a GitHub repository; in GitHub Actions the OIDC token is used when ACTIONS_ID_TOKEN_REQUEST_URL is set.
39356
+ Authentication for upload: HARNESS_TOKEN (always for --project), or the GitHub Actions OIDC token for --repo.
39037
39357
  `;
39038
39358
  UsageError2 = class extends Error {
39039
39359
  };
@@ -39043,6 +39363,7 @@ Authentication for upload: the GitHub Actions OIDC token when ACTIONS_ID_TOKEN_R
39043
39363
  service: { type: "string" },
39044
39364
  tenant: { type: "string" },
39045
39365
  repo: { type: "string" },
39366
+ project: { type: "string" },
39046
39367
  commit: { type: "string" },
39047
39368
  branch: { type: "string" },
39048
39369
  root: { type: "string" },
@@ -42614,14 +42935,14 @@ function inputRequiredRoundsExceededMessage(method, maxRounds) {
42614
42935
  return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
42615
42936
  }
42616
42937
  function sleep2(ms, signal) {
42617
- return new Promise((resolve13, reject) => {
42938
+ return new Promise((resolve14, reject) => {
42618
42939
  if (signal?.aborted) {
42619
42940
  reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
42620
42941
  return;
42621
42942
  }
42622
42943
  const timer = setTimeout(() => {
42623
42944
  signal?.removeEventListener("abort", onAbort);
42624
- resolve13();
42945
+ resolve14();
42625
42946
  }, ms);
42626
42947
  const onAbort = () => {
42627
42948
  clearTimeout(timer);
@@ -44417,7 +44738,7 @@ var init_src_CX2iR2pK = __esm({
44417
44738
  const flowStartedAt = Date.now();
44418
44739
  let onAbort;
44419
44740
  let cleanupMessageId;
44420
- return new Promise((resolve13, reject) => {
44741
+ return new Promise((resolve14, reject) => {
44421
44742
  const earlyReject = (error62) => {
44422
44743
  reject(error62);
44423
44744
  };
@@ -44485,7 +44806,7 @@ var init_src_CX2iR2pK = __esm({
44485
44806
  }
44486
44807
  if (decoded.kind === "invalid") return reject(decoded.error);
44487
44808
  if (decoded.kind === "input_required") {
44488
- if (options?.allowInputRequired === true) return resolve13(manualInputRequiredValue(decoded));
44809
+ if (options?.allowInputRequired === true) return resolve14(manualInputRequiredValue(decoded));
44489
44810
  const flow = {
44490
44811
  codec: codec2,
44491
44812
  request,
@@ -44497,11 +44818,11 @@ var init_src_CX2iR2pK = __esm({
44497
44818
  params
44498
44819
  }, resultSchema2, legOptions)
44499
44820
  };
44500
- return resolve13(this._resolveNonCompleteResult(decoded, flow));
44821
+ return resolve14(this._resolveNonCompleteResult(decoded, flow));
44501
44822
  }
44502
44823
  const result = decoded.result;
44503
44824
  validateStandardSchema(resultSchema2, result).then((parseResult) => {
44504
- if (parseResult.success) resolve13(parseResult.data);
44825
+ if (parseResult.success) resolve14(parseResult.data);
44505
44826
  else reject(new SdkError(SdkErrorCode.InvalidResult, `Invalid result for ${request.method}: ${parseResult.error}`));
44506
44827
  }, reject);
44507
44828
  });
@@ -47317,7 +47638,7 @@ var init_ajvProvider_CEoC_sr = __esm({
47317
47638
  ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref);
47318
47639
  const schOrFunc = root.refs[ref];
47319
47640
  if (schOrFunc) return schOrFunc;
47320
- let _sch = resolve13.call(this, root, ref);
47641
+ let _sch = resolve14.call(this, root, ref);
47321
47642
  if (_sch === void 0) {
47322
47643
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
47323
47644
  const { schemaId } = this.opts;
@@ -47343,7 +47664,7 @@ var init_ajvProvider_CEoC_sr = __esm({
47343
47664
  function sameSchemaEnv(s1, s2) {
47344
47665
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
47345
47666
  }
47346
- function resolve13(root, ref) {
47667
+ function resolve14(root, ref) {
47347
47668
  let sch;
47348
47669
  while (typeof (sch = this.refs[ref]) == "string") ref = sch;
47349
47670
  return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
@@ -47793,7 +48114,7 @@ var init_ajvProvider_CEoC_sr = __esm({
47793
48114
  else if (typeof uri === "object") uri = parse5(serialize(uri, options), options);
47794
48115
  return uri;
47795
48116
  }
47796
- function resolve13(baseURI, relativeURI, options) {
48117
+ function resolve14(baseURI, relativeURI, options) {
47797
48118
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
47798
48119
  const resolved = resolveComponent(parse5(baseURI, schemelessOptions), parse5(relativeURI, schemelessOptions), schemelessOptions, true);
47799
48120
  schemelessOptions.skipEscape = true;
@@ -47967,7 +48288,7 @@ var init_ajvProvider_CEoC_sr = __esm({
47967
48288
  const fastUri = {
47968
48289
  SCHEMES,
47969
48290
  normalize,
47970
- resolve: resolve13,
48291
+ resolve: resolve14,
47971
48292
  resolveComponent,
47972
48293
  equal,
47973
48294
  serialize,
@@ -53664,7 +53985,7 @@ var init_stdio = __esm({
53664
53985
  }
53665
53986
  send(message) {
53666
53987
  if (this._closed) return Promise.reject(/* @__PURE__ */ new Error("StdioServerTransport is closed"));
53667
- return new Promise((resolve13, reject) => {
53988
+ return new Promise((resolve14, reject) => {
53668
53989
  const json2 = serializeMessage(message);
53669
53990
  let settled = false;
53670
53991
  const onError = (error62) => {
@@ -53679,14 +54000,14 @@ var init_stdio = __esm({
53679
54000
  settled = true;
53680
54001
  this._stdout.off("error", onError);
53681
54002
  this._stdout.off("drain", onDrain);
53682
- resolve13();
54003
+ resolve14();
53683
54004
  };
53684
54005
  this._stdout.once("error", onError);
53685
54006
  if (this._stdout.write(json2)) {
53686
54007
  if (settled) return;
53687
54008
  settled = true;
53688
54009
  this._stdout.off("error", onError);
53689
- resolve13();
54010
+ resolve14();
53690
54011
  } else if (!settled) this._stdout.once("drain", onDrain);
53691
54012
  });
53692
54013
  }
@@ -53740,14 +54061,14 @@ var init_stdio = __esm({
53740
54061
  */
53741
54062
  async whenRequestsAnswered(timeoutMs) {
53742
54063
  if (this._closed || this._pendingRequests.size === 0) return true;
53743
- return await new Promise((resolve13) => {
54064
+ return await new Promise((resolve14) => {
53744
54065
  const waiter = () => {
53745
54066
  clearTimeout(timer);
53746
- resolve13(true);
54067
+ resolve14(true);
53747
54068
  };
53748
54069
  const timer = setTimeout(() => {
53749
54070
  this._drainWaiters = this._drainWaiters.filter((pending) => pending !== waiter);
53750
- resolve13(false);
54071
+ resolve14(false);
53751
54072
  }, timeoutMs);
53752
54073
  this._drainWaiters.push(waiter);
53753
54074
  });
@@ -53972,9 +54293,9 @@ var init_config = __esm({
53972
54293
 
53973
54294
  // ../code-shim/src/local.ts
53974
54295
  import { readFileSync as readFileSync13, statSync as statSync2 } from "node:fs";
53975
- import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve12, sep as sep2 } from "node:path";
54296
+ import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve13, sep as sep2 } from "node:path";
53976
54297
  function resolveInside(root, path) {
53977
- const absolute = resolve12(root, path);
54298
+ const absolute = resolve13(root, path);
53978
54299
  const rel = relative3(root, absolute);
53979
54300
  if (rel.length === 0 || rel.startsWith("..") || isAbsolute2(rel)) return null;
53980
54301
  return absolute;
@@ -55448,19 +55769,19 @@ function pkcePair() {
55448
55769
  return { verifier, challenge: base64url3(createHash("sha256").update(verifier).digest()) };
55449
55770
  }
55450
55771
  function listen(server, port) {
55451
- return new Promise((resolve13, reject) => {
55772
+ return new Promise((resolve14, reject) => {
55452
55773
  const onError = (error62) => reject(error62);
55453
55774
  server.once("error", onError);
55454
55775
  server.listen(port, "127.0.0.1", () => {
55455
55776
  server.off("error", onError);
55456
- resolve13();
55777
+ resolve14();
55457
55778
  });
55458
55779
  });
55459
55780
  }
55460
55781
  async function startLoopback(preferredPort, state) {
55461
55782
  let settle2;
55462
- const code2 = new Promise((resolve13, reject) => {
55463
- settle2 = { resolve: resolve13, reject };
55783
+ const code2 = new Promise((resolve14, reject) => {
55784
+ settle2 = { resolve: resolve14, reject };
55464
55785
  });
55465
55786
  code2.catch(() => void 0);
55466
55787
  const server = createServer((request, response) => {
@@ -55648,7 +55969,7 @@ async function requireToken(deps, serviceUrl) {
55648
55969
 
55649
55970
  // ../cli/src/project.ts
55650
55971
  init_src();
55651
- import { join as join5 } from "node:path";
55972
+ import { basename, join as join5 } from "node:path";
55652
55973
  var REMOTE_PATTERNS = [
55653
55974
  /^(?:https?|git|ssh):\/\/(?:[^@/]+@)?github\.com(?::\d+)?\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i,
55654
55975
  /^(?:[^@/]+@)?github\.com:([^/]+)\/([^/]+?)(?:\.git)?\/?$/i
@@ -55663,21 +55984,49 @@ function parseGitHubRemote(url2) {
55663
55984
  }
55664
55985
  return null;
55665
55986
  }
55666
- async function detectProject(deps) {
55987
+ function parseProvider(value) {
55988
+ if (value === void 0) return void 0;
55989
+ if (PROVIDERS.includes(value)) return value;
55990
+ throw new UsageError(`--provider must be one of ${PROVIDERS.join(", ")}`, { hint: "overlane connect --provider overlane" });
55991
+ }
55992
+ function safeName(text) {
55993
+ const cleaned = text.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|-+$/g, "");
55994
+ return cleaned.slice(0, 100) === "" ? "project" : cleaned.slice(0, 100);
55995
+ }
55996
+ function projectLabel(project) {
55997
+ return project.repository === void 0 ? project.name : `${project.repository.owner}/${project.repository.name}`;
55998
+ }
55999
+ function projectSummary(project) {
56000
+ return { provider: project.provider, ...project.repository === void 0 ? {} : { owner: project.repository.owner }, name: project.repository?.name ?? project.name, root: project.root };
56001
+ }
56002
+ function projectRequest(project) {
56003
+ if (project.provider === "github" && project.repository !== void 0) {
56004
+ return { provider: "github", repository: project.repository, name: project.name };
56005
+ }
56006
+ return { provider: "overlane", name: project.name };
56007
+ }
56008
+ async function detectProject(deps, choice = {}) {
55667
56009
  const top = await deps.exec("git", ["rev-parse", "--show-toplevel"], { cwd: deps.paths.cwd });
55668
56010
  if (top.code !== 0 || top.stdout.trim().length === 0) {
55669
- throw new UsageError("not inside a git repository (or git is not installed); run overlane from a GitHub-hosted project");
56011
+ throw new UsageError("not inside a git repository (or git is not installed); run overlane from your project folder (`git init` makes one)");
55670
56012
  }
55671
56013
  const root = top.stdout.trim();
56014
+ if (choice.name !== void 0 && (choice.name.trim().length === 0 || choice.name.length > 100)) throw new UsageError("--name must be 1 to 100 characters");
55672
56015
  const remote = await deps.exec("git", ["remote", "get-url", "origin"], { cwd: root });
55673
- if (remote.code !== 0 || remote.stdout.trim().length === 0) {
55674
- throw new UsageError("the repository has no `origin` remote; add the GitHub remote and run overlane again");
56016
+ const originUrl = remote.code === 0 ? remote.stdout.trim() : "";
56017
+ const github = originUrl.length === 0 ? null : parseGitHubRemote(originUrl);
56018
+ const wanted = choice.provider;
56019
+ if (wanted === "gitlab") {
56020
+ throw new UsageError("--provider gitlab is not available from the CLI yet; use --provider overlane (the default) and connect GitLab from the web app", { hint: "overlane connect --provider overlane" });
55675
56021
  }
55676
- const repository = parseGitHubRemote(remote.stdout);
55677
- if (repository === null) {
55678
- throw new UsageError(`origin is ${remote.stdout.trim()}, which is not a github.com repository; only GitHub projects are supported`);
56022
+ if (wanted === "github" && github === null) {
56023
+ const why = originUrl.length === 0 ? "this repository has no `origin` remote" : `origin is ${originUrl}, which is not a github.com repository`;
56024
+ throw new UsageError(`--provider github needs a github.com origin, and ${why}. Leave --provider off to make a native Overlane project, or add the GitHub remote first`, { hint: "overlane connect --provider overlane" });
55679
56025
  }
55680
- return { root, repository };
56026
+ if (github !== null && wanted !== "overlane") {
56027
+ return { root, provider: "github", name: choice.name ?? github.name, repository: github };
56028
+ }
56029
+ return { root, provider: "overlane", name: choice.name ?? (basename(root).slice(0, 100) || "project") };
55681
56030
  }
55682
56031
  async function headCommit(deps, root) {
55683
56032
  const head = await deps.exec("git", ["rev-parse", "HEAD"], { cwd: root });
@@ -55917,7 +56266,7 @@ var DEFAULT_SERVICE_URL = "https://api.overlane.dev";
55917
56266
  var CONNECT_STEPS = {
55918
56267
  "sign-up": "sign in through the browser (OAuth with PKCE), or use HARNESS_TOKEN",
55919
56268
  agents: "register the plugin with each agent's own commands (no vendor token is asked for)",
55920
- repo: "bind this GitHub project to the service",
56269
+ repo: "bind this project to the service: a native Overlane project by default, or your GitHub repository",
55921
56270
  "first-task": 'start your first task with `overlane task new "<title>"`',
55922
56271
  "first-review": "read the first review in the web app",
55923
56272
  invite: "invite teammates from the web app (optional, never blocks)"
@@ -55966,10 +56315,9 @@ async function connect(deps, options) {
55966
56315
  if (active.length === 0) {
55967
56316
  throw new CliError("none of the selected agents is installed, so there is nothing to connect", { code: "no_agent", exit: EXIT.conflict, hint: "overlane doctor" });
55968
56317
  }
55969
- const project = await detectProject(deps);
56318
+ const project = await detectProject(deps, { name: options.name, provider: options.provider });
55970
56319
  const root = project.root;
55971
- const { repository } = project;
55972
- say(deps, `Project: ${repository.owner}/${repository.name} at ${root}`);
56320
+ say(deps, `Project: ${projectLabel(project)}${project.provider === "overlane" ? " (native Overlane project; no GitHub account needed)" : " (GitHub)"} at ${root}`);
55973
56321
  const existing = readBindingFile(root);
55974
56322
  const serviceInput = options.service ?? deps.env["HARNESS_SERVICE_URL"] ?? (existing.kind === "ok" ? existing.binding.serviceUrl : DEFAULT_SERVICE_URL);
55975
56323
  if (serviceInput === void 0 || serviceInput.length === 0) {
@@ -56017,7 +56365,7 @@ async function connect(deps, options) {
56017
56365
  say(deps, `Steps (the same names as the web onboarding): ${STEP_NAMES.join(", ")}`);
56018
56366
  say(deps, "Plan");
56019
56367
  say(deps, ` sign-in: ${existingToken === null ? `browser sign-in to ${serviceUrl} (OAuth with PKCE), token kept in the OS keychain or a 0600 file in your user config directory` : `${describeStore(deps, existingToken.source)}`}`);
56020
- say(deps, ` service: GET ${serviceUrl}/v1/me, then create or look up the project for ${repository.owner}/${repository.name}`);
56368
+ say(deps, ` service: GET ${serviceUrl}/v1/me, then create or look up the project ${projectLabel(project)}`);
56021
56369
  for (const step2 of steps) say(deps, ` ${step2.agent}: ${step2.summary}
56022
56370
  $ ${formatCommand(step2)}`);
56023
56371
  if (codexEdit !== null) {
@@ -56045,7 +56393,7 @@ async function connect(deps, options) {
56045
56393
  service: serviceUrl,
56046
56394
  requests: [
56047
56395
  { method: "GET", path: apiPaths.whoami, note: existingToken === null ? "after browser sign-in" : "with the stored token" },
56048
- { method: "POST", path: apiPaths.projects("<tenantId from /v1/me>"), body: { repository, name: repository.name }, note: "creates the project or returns the existing one" },
56396
+ { method: "POST", path: apiPaths.projects("<tenantId from /v1/me>"), body: projectRequest(project), note: "creates the project or returns the existing one" },
56049
56397
  { method: "GET", path: releasePaths.publicKey(), note: "the release-signing key; a failure here does not fail connect" }
56050
56398
  ],
56051
56399
  commands: steps.map((step2) => formatCommand(step2)),
@@ -56065,7 +56413,7 @@ async function connect(deps, options) {
56065
56413
  }
56066
56414
  if (!await deps.confirm("Apply this plan?")) {
56067
56415
  say(deps, "Cancelled; nothing changed.");
56068
- return { data: emptyResult(repository, root, serviceUrl, infos, true) };
56416
+ return { data: emptyResult(project, serviceUrl, infos, true) };
56069
56417
  }
56070
56418
  }
56071
56419
  const token = await ensureToken(deps, serviceUrl);
@@ -56074,8 +56422,7 @@ async function connect(deps, options) {
56074
56422
  const wrote = [];
56075
56423
  const applied = [];
56076
56424
  const me = await whoAmI(deps, serviceUrl, token.token);
56077
- const request = { repository, name: repository.name };
56078
- const record3 = await createProject(deps, serviceUrl, me.tenantId, token.token, request);
56425
+ const record3 = await createProject(deps, serviceUrl, me.tenantId, token.token, projectRequest(project));
56079
56426
  if (record3.tenantId !== me.tenantId) throw new CliError("the service returned a project for another tenant");
56080
56427
  const servicePublicKey = await fetchServicePublicKey(deps, serviceUrl, token.token) ?? (existing.kind === "ok" ? existing.binding.servicePublicKey ?? null : null);
56081
56428
  const binding = ProjectBinding.parse({
@@ -56114,7 +56461,7 @@ async function connect(deps, options) {
56114
56461
  owned.binding = true;
56115
56462
  if (excludeNeeded && await addExclude(deps, root)) owned.excludeLine = true;
56116
56463
  say(deps, `[repo] ${CONNECT_STEPS.repo}: done`);
56117
- const next = await reportStep(deps, serviceUrl, token.token, me.tenantId, "repo", { repo: { kind: "github", owner: repository.owner, name: repository.name } });
56464
+ const next = await reportStep(deps, serviceUrl, token.token, me.tenantId, "repo", { repo: repoChoice(project) });
56118
56465
  if (next !== null) say(deps, `Next in onboarding: ${next === "repo" ? "first-task" : next} (${CONNECT_STEPS[next === "repo" ? "first-task" : next]})`);
56119
56466
  } finally {
56120
56467
  if (previousOwned !== null || owned.binding || owned.claude !== void 0 || owned.codex !== void 0) writeOwned(root, owned);
@@ -56128,7 +56475,7 @@ async function connect(deps, options) {
56128
56475
  for (const line2 of renderReports(reports)) say(deps, ` ${line2}`);
56129
56476
  return {
56130
56477
  data: {
56131
- project: { owner: repository.owner, name: repository.name, root },
56478
+ project: projectSummary(project),
56132
56479
  serviceUrl,
56133
56480
  tenantId: binding.tenantId,
56134
56481
  projectId: binding.projectId,
@@ -56142,9 +56489,13 @@ async function connect(deps, options) {
56142
56489
  }
56143
56490
  };
56144
56491
  }
56145
- function emptyResult(repository, root, serviceUrl, infos, cancelled) {
56492
+ function repoChoice(project) {
56493
+ if (project.provider === "github" && project.repository !== void 0) return { provider: "github", owner: project.repository.owner, name: project.repository.name };
56494
+ return { provider: "overlane", owner: "native", name: safeName(project.name) };
56495
+ }
56496
+ function emptyResult(project, serviceUrl, infos, cancelled) {
56146
56497
  return {
56147
- project: { owner: repository.owner, name: repository.name, root },
56498
+ project: projectSummary(project),
56148
56499
  serviceUrl,
56149
56500
  credentials: "unchanged",
56150
56501
  agents: infos.map((info2) => ({ agent: info2.agent, installed: info2.installed, detail: info2.detail })),
@@ -56207,8 +56558,8 @@ function withTimeout(deps, ms) {
56207
56558
  }
56208
56559
  async function attempt(deps, ms, work) {
56209
56560
  let timer;
56210
- const deadline = new Promise((resolve13) => {
56211
- timer = setTimeout(() => resolve13("unreachable"), ms);
56561
+ const deadline = new Promise((resolve14) => {
56562
+ timer = setTimeout(() => resolve14("unreachable"), ms);
56212
56563
  });
56213
56564
  try {
56214
56565
  return await Promise.race([work(withTimeout(deps, ms)).catch((error62) => error62 instanceof ServiceError && error62.exit === EXIT.auth ? "unauthenticated" : "unreachable"), deadline]);
@@ -57347,13 +57698,13 @@ async function readPlan(repoDir) {
57347
57698
  init_src();
57348
57699
  init_zod();
57349
57700
  import { mkdir as mkdir2, readdir as readdir3, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
57350
- import { basename as basename2, dirname as dirname7, join as join17, resolve as resolve6 } from "node:path";
57701
+ import { basename as basename3, dirname as dirname7, join as join17, resolve as resolve6 } from "node:path";
57351
57702
 
57352
57703
  // ../kit/src/detect.ts
57353
57704
  var import_yaml2 = __toESM(require_dist(), 1);
57354
57705
  init_src();
57355
57706
  import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
57356
- import { basename, join as join16, resolve as resolve5 } from "node:path";
57707
+ import { basename as basename2, join as join16, resolve as resolve5 } from "node:path";
57357
57708
  var KINDS = ["typecheck", "lint", "build", "test"];
57358
57709
  async function readOptional(file2) {
57359
57710
  try {
@@ -57498,7 +57849,7 @@ async function draftPlanForExisting(repoDir, opts = {}) {
57498
57849
  } catch {
57499
57850
  }
57500
57851
  }
57501
- const name2 = (opts.name ?? pkgName ?? basename(root)).slice(0, 100);
57852
+ const name2 = (opts.name ?? pkgName ?? basename2(root)).slice(0, 100);
57502
57853
  const milestone = opts.milestoneId ?? "M1";
57503
57854
  const allowedPaths = opts.allowedPaths ?? ["."];
57504
57855
  const tasks = [];
@@ -57696,7 +58047,7 @@ async function importSpecKit(repoDir) {
57696
58047
  const constitution = await findConstitution(root);
57697
58048
  const parsedConstitution = constitution ? parseConstitution(constitution.text) : void 0;
57698
58049
  const firstInput = /\*\*Input\*\*:\s*User description:\s*"(.*)"/.exec(features[0]?.specText ?? "")?.[1];
57699
- const name2 = (parsedConstitution?.name ?? basename2(root)).slice(0, 100);
58050
+ const name2 = (parsedConstitution?.name ?? basename3(root)).slice(0, 100);
57700
58051
  const goal = (parsedConstitution?.goal ?? firstInput ?? `Deliver ${name2}.`).slice(0, 2e3);
57701
58052
  const multi = features.length > 1;
57702
58053
  const counts2 = /* @__PURE__ */ new Map();
@@ -59069,7 +59420,7 @@ var contextCommand = defineCommand({
59069
59420
  init_src();
59070
59421
  init_zod();
59071
59422
  import { existsSync as existsSync4, readFileSync as readFileSync7 } from "node:fs";
59072
- import { basename as basename3, resolve as resolve7 } from "node:path";
59423
+ import { basename as basename4, resolve as resolve7 } from "node:path";
59073
59424
  var SERVICE_FLAG = { name: "service", type: "string", value: "URL", description: "The service address (default: HARNESS_SERVICE_URL, then the project's binding, then the hosted service)" };
59074
59425
  var TEAM_FLAG = { name: "team", type: "string", value: "TENANT_ID", description: "The team (tenant) to act on (default: the one your token belongs to)" };
59075
59426
  var ECOSYSTEM_FLAG = { name: "ecosystem", type: "string", enum: DOCS_ECOSYSTEMS, default: "npm", description: "Where the library is published" };
@@ -59181,7 +59532,7 @@ function readLockfiles(paths) {
59181
59532
  const files = paths.length > 0 ? paths : DEFAULT_LOCKFILES.filter((name2) => existsSync4(resolve7(name2)));
59182
59533
  if (files.length === 0) throw new UsageError("no lockfile found in this directory", { hint: "overlane lib pins --project <id> --lockfile pnpm-lock.yaml" });
59183
59534
  return files.map((file2) => {
59184
- const kind = LOCKFILES.find(([pattern]) => pattern.test(basename3(file2)))?.[1];
59535
+ const kind = LOCKFILES.find(([pattern]) => pattern.test(basename4(file2)))?.[1];
59185
59536
  if (kind === void 0) throw new UsageError(`${file2} is not a lockfile this command reads`, { hint: "supported: package-lock.json, pnpm-lock.yaml, yarn.lock, requirements.txt, uv.lock, Cargo.lock, go.sum" });
59186
59537
  try {
59187
59538
  return { kind, content: readFileSync7(resolve7(file2), "utf8") };
@@ -59277,7 +59628,7 @@ var libAddCommand = defineCommand({
59277
59628
  if (version2 === void 0 || files.length === 0) throw new UsageError("add needs --version and at least one --file", { hint: "overlane lib add <library> --version 1.0.0 --file README.md" });
59278
59629
  const pages = files.map((file2) => {
59279
59630
  try {
59280
- return { title: basename3(file2), text: readFileSync7(resolve7(file2), "utf8") };
59631
+ return { title: basename4(file2), text: readFileSync7(resolve7(file2), "utf8") };
59281
59632
  } catch {
59282
59633
  throw new UsageError(`cannot read ${file2}`);
59283
59634
  }
@@ -59353,7 +59704,7 @@ async function post(deps, base4, path, body2) {
59353
59704
  return { status: response.status, json: json2 };
59354
59705
  }
59355
59706
  function sleep(ms) {
59356
- return new Promise((resolve13) => setTimeout(resolve13, ms));
59707
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
59357
59708
  }
59358
59709
  async function deviceLogin(deps, service, options) {
59359
59710
  const started = await post(deps, service, "/auth/device", {});
@@ -60951,6 +61302,7 @@ var loopCommands = [loopListCommand, loopNewCommand, loopSetCommand, loopFireCom
60951
61302
  // ../cli/src/commands/review.ts
60952
61303
  init_src();
60953
61304
  import { randomUUID as randomUUID7 } from "node:crypto";
61305
+ import { resolve as resolve9 } from "node:path";
60954
61306
  var common7 = { needsAuth: true, needsNetwork: true };
60955
61307
  var requestId7 = () => `cli-${randomUUID7()}`;
60956
61308
  async function connected3(inv) {
@@ -60969,9 +61321,38 @@ async function repositoryOf(inv) {
60969
61321
  }
60970
61322
  const remote = await inv.deps.exec("git", ["remote", "get-url", "origin"], { cwd: inv.deps.paths.cwd });
60971
61323
  const match = /github\.com[:/]([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?\s*$/.exec(remote.stdout.trim());
60972
- if (remote.code !== 0 || match === null) throw new UsageError("could not read the repository from the origin remote", { hint: "overlane review run 7 --repo OWNER/NAME" });
61324
+ if (remote.code !== 0 || match === null) throw new UsageError("could not read a GitHub repository from the origin remote; to review a change without one, give the diff", { hint: "overlane review run --diff change.patch" });
60973
61325
  return `${match[1]}/${match[2]}`;
60974
61326
  }
61327
+ async function diffOf(inv) {
61328
+ const flag = textFlag(inv, "diff");
61329
+ const pull = inv.positionals[0];
61330
+ if (flag !== void 0 && pull !== void 0) throw new UsageError("give a pull request number or --diff, not both", { hint: "overlane review run --diff change.patch" });
61331
+ let from;
61332
+ let text;
61333
+ if (flag !== void 0) {
61334
+ if (flag === "-") {
61335
+ if (inv.deps.stdin === void 0) throw new UsageError("--diff - reads standard input, which is not available here", { hint: "overlane review run --diff change.patch" });
61336
+ from = "standard input";
61337
+ text = await inv.deps.stdin.read();
61338
+ } else {
61339
+ from = flag;
61340
+ text = readText(resolve9(inv.deps.paths.cwd, flag));
61341
+ if (text === null) throw new UsageError(`could not read the diff file ${flag}`, { hint: "git diff > change.patch && overlane review run --diff change.patch" });
61342
+ }
61343
+ } else if (pull === void 0) {
61344
+ if (inv.deps.stdin === void 0 || inv.deps.stdin.isTTY) {
61345
+ throw new UsageError("nothing to review: give a diff (--diff change.patch, or pipe one in) or a pull request number", { hint: "overlane review run --diff change.patch" });
61346
+ }
61347
+ from = "standard input";
61348
+ text = await inv.deps.stdin.read();
61349
+ } else {
61350
+ return void 0;
61351
+ }
61352
+ if (text.trim().length === 0) throw new UsageError(`the diff from ${from} is empty: there is nothing to review`, { hint: "git diff > change.patch && overlane review run --diff change.patch" });
61353
+ if (text.length > MAX_PATCH_BYTES) throw new UsageError(`the diff is larger than ${MAX_PATCH_BYTES} characters; review it in parts`);
61354
+ return { text, from };
61355
+ }
60975
61356
  function id(inv, what) {
60976
61357
  const value = inv.positionals[0];
60977
61358
  if (value === void 0) throw new UsageError(`${what} needs a finding ID`, { hint: "overlane review findings" });
@@ -60980,22 +61361,39 @@ function id(inv, what) {
60980
61361
  var FINDING_LINE = (finding) => `${finding.status.padEnd(9)} ${finding.severity.padEnd(8)} ${finding.path}:${finding.line} ${finding.rule ?? "see reason"} ${finding.id}`;
60981
61362
  var reviewRunCommand = defineCommand({
60982
61363
  path: ["review", "run"],
60983
- summary: "Review a GitHub pull request now and report the findings",
60984
- description: "Runs the review service on a pull request: triage, review passes under the per-PR token cap, inline findings and one updated summary. Until the project owner enables comments (`overlane review settings set --mode comments`) the run is log-only and posts nothing. Pull request text and code are data, never instructions. Needs the GitHub App's pull-request access; without it the command says the live leg is pending.",
60985
- args: [{ name: "pull", required: true, description: "The pull request number" }],
60986
- flags: [{ name: "repo", type: "string", value: "OWNER/NAME", description: "The repository (default: the origin remote of this working copy)" }],
60987
- examples: ["overlane review run 7", "overlane review run 7 --repo acme/app --dry-run"],
61364
+ summary: "Review a diff (no repository needed) or a pull request now and report the findings",
61365
+ description: "Runs the review service. The native way is a diff: `--diff change.patch`, or `--diff -` (or a pipe) to read it from standard input; it needs no repository and no GitHub account, and it is log-only. A pull request number reviews a pull request instead (native pull requests arrive with Overlane git; a GitHub one needs the GitHub connection and the App's pull-request access, otherwise the command says the live leg is pending). Deterministic checks (secret scan, static rules, diff validation) run first and alone when no model is available; a model pass is an optional second pass under the per-PR token cap. Until the project owner enables comments (`overlane review settings set --mode comments`) a pull request run is log-only and posts nothing. Diff text and code are data, never instructions.",
61366
+ args: [{ name: "pull", required: false, description: "A pull request number (omit it to review a diff)" }],
61367
+ flags: [
61368
+ { name: "diff", type: "string", value: "FILE", description: "Review this unified diff (a file, or - for standard input); needs no repository" },
61369
+ { name: "title", type: "string", value: "TEXT", description: "A title for the diff, shown in the summary" },
61370
+ { name: "label", type: "string", value: "NAME", description: "Names the diff so a re-review of the same change merges its findings (default: patch)" },
61371
+ { name: "repo", type: "string", value: "OWNER/NAME", description: "For a pull request number: the GitHub repository (default: the origin remote); not used with --diff" }
61372
+ ],
61373
+ examples: ["overlane review run --diff change.patch", "overlane review run --diff -", "overlane review run 7 --repo acme/app --dry-run"],
60988
61374
  effect: "write",
60989
61375
  ...common7,
60990
- keywords: ["code review", "review pull request", "review pr", "ai review", "check my pr", "findings"],
61376
+ keywords: ["code review", "review diff", "review patch", "review pull request", "review pr", "check my pr", "findings"],
60991
61377
  result: withDryRun(ReviewRunResponse),
60992
61378
  text: (d) => "run" in d ? [`${d.run.status} review of ${d.run.repository}#${d.run.pullNumber} (${d.run.mode}${d.run.posted ? ", posted" : ", nothing posted"}): ${d.run.findings.open} open, ${d.run.findings.fixed} fixed, ${d.run.findings.dismissed} dismissed.`, ...d.findings.filter((finding) => finding.status === "open").map(FINDING_LINE)] : [],
60993
61379
  handler: async (inv) => {
61380
+ const diff = await diffOf(inv);
61381
+ if (diff !== void 0) {
61382
+ const title = textFlag(inv, "title");
61383
+ const label = textFlag(inv, "label");
61384
+ const source = { kind: "patch", diff: diff.text, ...title === void 0 ? {} : { title }, ...label === void 0 ? {} : { label } };
61385
+ const patchBody = { requestId: requestId7(), trigger: "manual", source };
61386
+ if (inv.dryRun) return planned3(inv, "POST", reviewPaths.runs, { ...patchBody, source: { ...source, diff: `<${diff.text.length} characters from ${diff.from}>` } }, "runs the deterministic checks on the diff, then an optional model pass; nothing is posted");
61387
+ const sent = await connected3(inv);
61388
+ const patched = await sent.call(ReviewRunResponse, "POST", reviewPaths.runs(sent.tenantId, sent.projectId), patchBody);
61389
+ if (patched.run.status === "partial") say(inv.deps, "Partial review: the token cap was reached. The summary lists what was not covered.");
61390
+ return { data: patched };
61391
+ }
60994
61392
  const number4 = Number(inv.positionals[0]);
60995
- if (!Number.isInteger(number4) || number4 < 1) throw new UsageError("run needs a pull request number", { hint: "overlane review run 7" });
61393
+ if (!Number.isInteger(number4) || number4 < 1) throw new UsageError("run needs a pull request number, or a diff with --diff", { hint: "overlane review run --diff change.patch" });
60996
61394
  const repository = await repositoryOf(inv);
60997
61395
  const body2 = { requestId: requestId7(), trigger: "manual", source: { kind: "github", repository, number: number4 } };
60998
- if (inv.dryRun) return planned3(inv, "POST", reviewPaths.runs, body2, "reads the pull request through the GitHub App and runs the review");
61396
+ if (inv.dryRun) return planned3(inv, "POST", reviewPaths.runs, body2, "reads the pull request through the GitHub connection and runs the review");
60999
61397
  const { call: call2, tenantId, projectId } = await connected3(inv);
61000
61398
  const result = await call2(ReviewRunResponse, "POST", reviewPaths.runs(tenantId, projectId), body2);
61001
61399
  if (result.run.status === "partial") say(inv.deps, "Partial review: the token cap was reached. The summary lists what was not covered.");
@@ -61106,7 +61504,7 @@ var reviewSettingsCommand = defineCommand({
61106
61504
  var reviewSettingsSetCommand = defineCommand({
61107
61505
  path: ["review", "settings", "set"],
61108
61506
  summary: "Change the review mode, token cap or skip patterns",
61109
- description: "Sets how review behaves for the project. Enabling comments (`--mode comments`) lets review post inline comments and the summary on GitHub; it is log-only until then. An agent or a person can change them; a read-only viewer cannot.",
61507
+ description: "Sets how review behaves for the project. Enabling comments (`--mode comments`) lets review post inline comments and the summary on the pull request (GitHub today; native pull requests with Overlane git); it is log-only until then. A diff review never posts. An agent or a person can change them; a read-only viewer cannot.",
61110
61508
  flags: [
61111
61509
  { name: "mode", type: "string", enum: ["log_only", "comments"], description: "log_only records findings only; comments posts them" },
61112
61510
  { name: "token-cap", type: "string", value: "N", description: "Most tokens one pull request may use (1,000 to 2,000,000)" },
@@ -61192,7 +61590,7 @@ function rootHelp(specs, version2) {
61192
61590
  const lines = [
61193
61591
  ROOT_FIRST_LINE,
61194
61592
  "",
61195
- `overlane${version2 === "" ? "" : ` ${version2}`} - connect a GitHub project to Overlane, and run its tasks`,
61593
+ `overlane${version2 === "" ? "" : ` ${version2}`} - connect a project to Overlane (no GitHub account needed), and run its tasks`,
61196
61594
  "",
61197
61595
  "Usage: overlane <command> [flags] overlane <command> --help overlane schema <command>",
61198
61596
  "",
@@ -61503,7 +61901,7 @@ init_zod();
61503
61901
  // ../cli/src/connect-result.ts
61504
61902
  init_zod();
61505
61903
  var ConnectResult = external_exports.object({
61506
- project: external_exports.object({ owner: external_exports.string(), name: external_exports.string(), root: external_exports.string() }),
61904
+ project: external_exports.object({ provider: external_exports.enum(["overlane", "github", "gitlab"]).optional(), owner: external_exports.string().optional(), name: external_exports.string(), root: external_exports.string() }),
61507
61905
  serviceUrl: external_exports.string(),
61508
61906
  tenantId: external_exports.string().optional(),
61509
61907
  projectId: external_exports.string().optional(),
@@ -61648,10 +62046,10 @@ async function disconnect(deps, options) {
61648
62046
  }
61649
62047
 
61650
62048
  // ../cli/src/doctor.ts
61651
- import { resolve as resolve9 } from "node:path";
62049
+ import { resolve as resolve10 } from "node:path";
61652
62050
  init_zod();
61653
62051
  var DoctorResult = external_exports.object({
61654
- project: external_exports.object({ owner: external_exports.string(), name: external_exports.string(), root: external_exports.string() }),
62052
+ project: external_exports.object({ provider: external_exports.enum(["overlane", "github", "gitlab"]).optional(), owner: external_exports.string().optional(), name: external_exports.string(), root: external_exports.string() }),
61655
62053
  binding: external_exports.enum(["ok", "missing", "invalid"]),
61656
62054
  service: external_exports.string().optional(),
61657
62055
  credentials: external_exports.string().optional(),
@@ -61668,13 +62066,13 @@ async function doctor(deps, options) {
61668
62066
  const root = project.root;
61669
62067
  const binding = readBindingFile(root);
61670
62068
  const owned = readOwned(root);
61671
- const marketplaceRoot2 = resolve9(options.marketplaceRoot ?? owned?.marketplaceRoot ?? deps.paths.defaultMarketplaceRoot);
62069
+ const marketplaceRoot2 = resolve10(options.marketplaceRoot ?? owned?.marketplaceRoot ?? deps.paths.defaultMarketplaceRoot);
61672
62070
  const infos = await detectAgents(deps, options.agents, root);
61673
62071
  let service = "reachable";
61674
62072
  let hasToken = false;
61675
62073
  let credentials;
61676
62074
  let checked2 = false;
61677
- say(deps, `Project: ${project.repository.owner}/${project.repository.name} at ${root}`);
62075
+ say(deps, `Project: ${projectLabel(project)} at ${root}`);
61678
62076
  if (binding.kind === "ok") {
61679
62077
  const { serviceUrl } = binding.binding;
61680
62078
  const token = await findToken(deps, serviceUrl);
@@ -61698,7 +62096,7 @@ async function doctor(deps, options) {
61698
62096
  const installedStates = reports.filter((report2, index) => infos[index]?.installed === true).map((report2) => report2.state);
61699
62097
  const ready = installedStates.length > 0 && installedStates.every((state) => state === "ready");
61700
62098
  const data = {
61701
- project: { owner: project.repository.owner, name: project.repository.name, root },
62099
+ project: projectSummary(project),
61702
62100
  binding: binding.kind,
61703
62101
  ...binding.kind === "ok" ? { service: binding.binding.serviceUrl } : {},
61704
62102
  ...credentials === void 0 ? {} : { credentials },
@@ -61818,7 +62216,7 @@ function newPlan(name2, goal, withCiTask) {
61818
62216
  id: "T001",
61819
62217
  title: "Add CI",
61820
62218
  milestone: "M1",
61821
- outcome: "A GitHub Actions workflow runs the project's install, typecheck and test commands on every push and pull request.",
62219
+ outcome: "A CI workflow (GitHub Actions today; Overlane CI once native CI is available) runs the project's install, typecheck and test commands on every push and pull request.",
61822
62220
  allowedPaths: [".github/**"],
61823
62221
  acceptance: ["A workflow in .github/workflows runs on push and pull_request"],
61824
62222
  verification: ['test -n "$(ls .github/workflows/*.yml .github/workflows/*.yaml 2>/dev/null)"'],
@@ -61857,7 +62255,8 @@ function schedulerSetup(projectId) {
61857
62255
  }
61858
62256
  async function connectKit(deps, options) {
61859
62257
  if (options.mode === "new" && (options.goal === void 0 || options.goal.trim().length === 0)) throw new UsageError("--kit new needs --goal TEXT");
61860
- const { root, repository } = await detectProject(deps);
62258
+ const project = await detectProject(deps, { name: options.name, provider: options.provider });
62259
+ const { root } = project;
61861
62260
  if (await headCommit(deps, root) === null) throw new CliError("the repository has no commit yet; make an initial commit first");
61862
62261
  const planDir = join22(root, PLAN_DIR);
61863
62262
  const planExists = existsSync6(join22(planDir, "project.md"));
@@ -61869,7 +62268,7 @@ async function connectKit(deps, options) {
61869
62268
  plan3 = await readPlan(root);
61870
62269
  planSource = `${PLAN_DIR}/ already exists; kept as it is`;
61871
62270
  } else if (options.mode === "new") {
61872
- plan3 = newPlan(repository.name, options.goal ?? "", !ciExists);
62271
+ plan3 = newPlan(project.name, options.goal ?? "", !ciExists);
61873
62272
  planSource = "minimal plan from --goal";
61874
62273
  } else if (hasSpecKit(root)) {
61875
62274
  plan3 = await importSpecKit(root);
@@ -61892,7 +62291,7 @@ async function connectKit(deps, options) {
61892
62291
  const touched = [...INSTRUCTION_FILES, CI_FILE];
61893
62292
  const unsaved = await dirty(deps, root, touched);
61894
62293
  if (unsaved.length > 0 && !options.dryRun) throw new CliError(`uncommitted changes in ${unsaved.join(", ")}; commit or stash them so the kit commit holds only its own lines`);
61895
- say(deps, `Kit setup (${options.mode}) for ${repository.owner}/${repository.name}`);
62294
+ say(deps, `Kit setup (${options.mode}) for ${projectLabel(project)}`);
61896
62295
  say(deps, ` branch: create ${KIT_BRANCH}`);
61897
62296
  say(deps, ` plan: ${planSource} (${plan3.milestones.length} milestone(s), ${plan3.tasks.length} task(s))${planExists ? "" : `, written to ${PLAN_DIR}/`}`);
61898
62297
  say(deps, ciExists ? " ci: a workflow already exists; left alone" : workflow === null ? " ci: no install, typecheck or test command detected, so no workflow is written (the plan task adds it)" : ` ci: write ${CI_FILE} (pinned actions; runs ${[detected.install, ...detected.typecheck ?? [], ...detected.test].filter((c) => c !== void 0).join("; ")})`);
@@ -61969,7 +62368,7 @@ async function connectKit(deps, options) {
61969
62368
  say(deps, `Run policy set (build-ahead limit ${firstMilestone}).`);
61970
62369
  const synced = await kit.syncPlan(PlanSyncRequest.parse({ requestId: `cli-${randomUUID8()}`, sourceCommit: sha, plan: await readPlan(root) }));
61971
62370
  say(deps, `Plan synced: ${synced.created.length} created, ${synced.updated.length} updated, ${synced.unchanged.length} unchanged, ${synced.deferred.length} deferred.`);
61972
- const pr = await openPullRequest(deps, root, repository.name);
62371
+ const pr = await openPullRequest(deps, root, project.name);
61973
62372
  say(deps);
61974
62373
  for (const line2 of schedulerSetup(binding.binding.projectId)) say(deps, line2);
61975
62374
  return {
@@ -62015,18 +62414,20 @@ var AGENTS_FLAG = { name: "agents", type: "string", value: "claude,codex", descr
62015
62414
  var ROOT_FLAG = { name: "marketplace-root", type: "string", value: "DIR", description: "Folder holding the built claude/ and codex/ plugin marketplaces" };
62016
62415
  var connectCommand = defineCommand({
62017
62416
  path: ["connect"],
62018
- summary: "Connect this GitHub project: sign in, bind it, register the plugin; --kit also sets up a plan",
62019
- description: "Detects the installed agents, previews the plan, then (with --yes) signs in through the browser, creates or looks up the project on the service, runs the agents' native plugin commands, writes .harness/project.json and records what it added in .harness/owned.json so `overlane disconnect` removes only that. With --kit existing|new it also drafts the plan files, CI and a pull request. Without a terminal it never prompts: pass --yes, or --dry-run to preview.",
62417
+ summary: "Connect this project (native Overlane, or your GitHub repository): sign in, bind it, register the plugin; --kit also sets up a plan",
62418
+ description: "Works in any git project, with no GitHub account: without a GitHub origin the project is a native Overlane project named after the folder (--name renames it). With a github.com origin it binds that repository instead (--provider overlane keeps it native). Detects the installed agents, previews the plan, then (with --yes) signs in through the browser, creates or looks up the project on the service, runs the agents' native plugin commands, writes .harness/project.json and records what it added in .harness/owned.json so `overlane disconnect` removes only that. With --kit existing|new it also drafts the plan files, CI and a pull request. Without a terminal it never prompts: pass --yes, or --dry-run to preview.",
62020
62419
  flags: [
62021
62420
  { name: "service", type: "string", value: "URL", description: "Service address (https); default is the hosted service or HARNESS_SERVICE_URL" },
62022
62421
  ROOT_FLAG,
62023
62422
  AGENTS_FLAG,
62024
62423
  { name: "dry-run", type: "boolean", description: "Print the plan, the requests it would send and the files it would write; change nothing. Needs no credentials." },
62025
62424
  { name: "yes", type: "boolean", description: "Apply the plan without asking (required when there is no terminal)" },
62425
+ { name: "name", type: "string", value: "NAME", description: "The project name (default: the GitHub repository name, else this folder's name)" },
62426
+ { name: "provider", type: "string", enum: ["overlane", "github"], description: "Where the project lives: overlane (native, the default without a GitHub origin) or github (needs a github.com origin)" },
62026
62427
  { name: "kit", type: "string", enum: ["existing", "new"], description: "Also set up the project kit: plan files, CI, instruction blocks and one pull request" },
62027
62428
  { name: "goal", type: "string", value: "TEXT", description: "The project's goal; required with --kit new" }
62028
62429
  ],
62029
- examples: ["overlane connect --dry-run", "overlane connect --yes", 'overlane connect --kit new --goal "A rundown service" --yes', "overlane connect --kit existing --yes"],
62430
+ examples: ["overlane connect --dry-run", "overlane connect --yes", "overlane connect --name my-app --yes", "overlane connect --provider github --yes", 'overlane connect --kit new --goal "A rundown service" --yes', "overlane connect --kit existing --yes"],
62030
62431
  effect: "write",
62031
62432
  needsNetwork: true,
62032
62433
  keywords: ["setup", "install", "bind", "link", "onboard", "register plugin", "bootstrap", "autonomous", "plan", "kit", "get started", "initialise", "enable harness", "ci workflow", "pull request"],
@@ -62037,7 +62438,9 @@ var connectCommand = defineCommand({
62037
62438
  marketplaceRoot: textFlag(inv, "marketplace-root"),
62038
62439
  agents: parseAgentList(textFlag(inv, "agents")),
62039
62440
  dryRun: inv.dryRun,
62040
- yes: boolFlag(inv, "yes")
62441
+ yes: boolFlag(inv, "yes"),
62442
+ name: textFlag(inv, "name"),
62443
+ provider: parseProvider(textFlag(inv, "provider"))
62041
62444
  };
62042
62445
  const kit = textFlag(inv, "kit");
62043
62446
  const goal = textFlag(inv, "goal");