overlane 0.1.124 → 0.1.125

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(),
@@ -22505,7 +22597,7 @@ var init_docs_service = __esm({
22505
22597
  function base3(tenantId, projectId) {
22506
22598
  return `/v1/tenants/${encodeURIComponent(tenantId)}/projects/${encodeURIComponent(projectId)}/review`;
22507
22599
  }
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;
22600
+ 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
22601
  var init_review = __esm({
22510
22602
  "../contracts/src/review.ts"() {
22511
22603
  "use strict";
@@ -22520,6 +22612,9 @@ var init_review = __esm({
22520
22612
  tenantId: TenantId,
22521
22613
  id: external_exports.string().min(1),
22522
22614
  projectId: ProjectId,
22615
+ /** Where the change lives. A record from before ADR 0050 has none: read it with `reviewProvider`, which gives `github`. */
22616
+ provider: Provider.optional(),
22617
+ /** The repository key: `owner/name` for a connection, `overlane/<projectId>` or `patch/<projectId>` for native reviews. */
22523
22618
  repository: external_exports.string().min(1),
22524
22619
  pullNumber: external_exports.number().int().positive(),
22525
22620
  path: external_exports.string().min(1),
@@ -22573,6 +22668,7 @@ var init_review = __esm({
22573
22668
  tenantId: TenantId,
22574
22669
  id: external_exports.string().min(1),
22575
22670
  projectId: ProjectId,
22671
+ provider: Provider.optional(),
22576
22672
  repository: external_exports.string().min(1),
22577
22673
  pullNumber: external_exports.number().int().positive(),
22578
22674
  headSha: CommitSha,
@@ -22613,6 +22709,7 @@ var init_review = __esm({
22613
22709
  patch: external_exports.string().max(4e5).optional()
22614
22710
  }).strict();
22615
22711
  PullRequestSnapshot = external_exports.object({
22712
+ provider: Provider.optional(),
22616
22713
  repository: external_exports.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/),
22617
22714
  number: external_exports.number().int().positive(),
22618
22715
  headSha: CommitSha,
@@ -22623,10 +22720,20 @@ var init_review = __esm({
22623
22720
  fork: external_exports.boolean().default(false),
22624
22721
  files: external_exports.array(PullFile).max(3e3)
22625
22722
  }).strict();
22723
+ MAX_PATCH_BYTES = 2e6;
22626
22724
  ReviewRunRequest = external_exports.object({
22627
22725
  requestId: external_exports.string().min(1).max(128),
22628
22726
  trigger: external_exports.enum(REVIEW_TRIGGERS).default("manual"),
22629
22727
  source: external_exports.discriminatedUnion("kind", [
22728
+ external_exports.object({
22729
+ kind: external_exports.literal("patch"),
22730
+ diff: external_exports.string().min(1).max(MAX_PATCH_BYTES),
22731
+ title: external_exports.string().max(500).optional(),
22732
+ /** Names this change so a re-review of the same change merges its findings; defaults to `patch`. */
22733
+ label: external_exports.string().regex(/^[A-Za-z0-9._-]{1,64}$/).optional(),
22734
+ author: external_exports.string().min(1).max(100).optional()
22735
+ }).strict(),
22736
+ external_exports.object({ kind: external_exports.literal("overlane"), number: external_exports.number().int().positive(), repository: external_exports.string().min(1).optional() }).strict(),
22630
22737
  external_exports.object({ kind: external_exports.literal("github"), repository: external_exports.string().min(1), number: external_exports.number().int().positive() }).strict(),
22631
22738
  external_exports.object({ kind: external_exports.literal("inline"), pull: PullRequestSnapshot }).strict()
22632
22739
  ])
@@ -30784,25 +30891,25 @@ var require_dist = __commonJS({
30784
30891
  });
30785
30892
 
30786
30893
  // src/assets.ts
30787
- import { basename as basename4, join as join24, resolve as resolve10 } from "node:path";
30894
+ import { basename as basename5, join as join24, resolve as resolve11 } from "node:path";
30788
30895
  import { fileURLToPath } from "node:url";
30789
30896
  function packageRoot(env = process.env) {
30790
30897
  const override = env["MVRX_PACKAGE_ROOT"];
30791
30898
  if (override !== void 0 && override !== "") return override;
30792
- return resolve10(fileURLToPath(new URL(".", import.meta.url)), "..");
30899
+ return resolve11(fileURLToPath(new URL(".", import.meta.url)), "..");
30793
30900
  }
30794
30901
  function assetDir(env = process.env) {
30795
30902
  const override = env["MVRX_ASSET_DIR"];
30796
30903
  return override !== void 0 && override !== "" ? override : join24(packageRoot(env), "assets");
30797
30904
  }
30798
30905
  function assetFile(name2) {
30799
- return join24(assetDir(), basename4(name2));
30906
+ return join24(assetDir(), basename5(name2));
30800
30907
  }
30801
30908
  var VERSION;
30802
30909
  var init_assets = __esm({
30803
30910
  "src/assets.ts"() {
30804
30911
  "use strict";
30805
- VERSION = true ? "0.1.124" : "0.0.0-dev";
30912
+ VERSION = true ? "0.1.125" : "0.0.0-dev";
30806
30913
  }
30807
30914
  });
30808
30915
 
@@ -32220,7 +32327,7 @@ function createFileRegistry(...args2) {
32220
32327
  if (seen.has(protoFileName)) {
32221
32328
  continue;
32222
32329
  }
32223
- const dep = resolve13(protoFileName);
32330
+ const dep = resolve14(protoFileName);
32224
32331
  if (!dep) {
32225
32332
  throw new Error(`Unable to resolve ${protoFileName}, imported by ${file2.name}`);
32226
32333
  }
@@ -32234,7 +32341,7 @@ function createFileRegistry(...args2) {
32234
32341
  return deps.concat(...deps.map(recurseDeps));
32235
32342
  };
32236
32343
  const input2 = args2[0];
32237
- const resolve13 = args2[1];
32344
+ const resolve14 = args2[1];
32238
32345
  const seen = /* @__PURE__ */ new Set();
32239
32346
  for (const file2 of [input2, ...recurseDeps(input2)].reverse()) {
32240
32347
  addFile(file2, registry2);
@@ -34647,13 +34754,13 @@ async function Module2(moduleArg = {}) {
34647
34754
  }
34648
34755
  readAsync = /* @__PURE__ */ __name(async (url2) => {
34649
34756
  if (isFileURI(url2)) {
34650
- return new Promise((resolve13, reject) => {
34757
+ return new Promise((resolve14, reject) => {
34651
34758
  var xhr = new XMLHttpRequest();
34652
34759
  xhr.open("GET", url2, true);
34653
34760
  xhr.responseType = "arraybuffer";
34654
34761
  xhr.onload = () => {
34655
34762
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
34656
- resolve13(xhr.response);
34763
+ resolve14(xhr.response);
34657
34764
  return;
34658
34765
  }
34659
34766
  reject(xhr.status);
@@ -34849,9 +34956,9 @@ async function Module2(moduleArg = {}) {
34849
34956
  __name(receiveInstantiationResult, "receiveInstantiationResult");
34850
34957
  var info2 = getWasmImports();
34851
34958
  if (Module["instantiateWasm"]) {
34852
- return new Promise((resolve13, reject) => {
34959
+ return new Promise((resolve14, reject) => {
34853
34960
  Module["instantiateWasm"](info2, (mod, inst) => {
34854
- resolve13(receiveInstance(mod, inst));
34961
+ resolve14(receiveInstance(mod, inst));
34855
34962
  });
34856
34963
  });
34857
34964
  }
@@ -36184,8 +36291,8 @@ async function Module2(moduleArg = {}) {
36184
36291
  if (runtimeInitialized) {
36185
36292
  moduleRtn = Module;
36186
36293
  } else {
36187
- moduleRtn = new Promise((resolve13, reject) => {
36188
- readyPromiseResolve = resolve13;
36294
+ moduleRtn = new Promise((resolve14, reject) => {
36295
+ readyPromiseResolve = resolve14;
36189
36296
  readyPromiseReject = reject;
36190
36297
  });
36191
36298
  }
@@ -38812,7 +38919,8 @@ async function buildSnapshot(options) {
38812
38919
  const manifest = SnapshotManifest.parse({
38813
38920
  schemaVersion: "1",
38814
38921
  tenantId: options.tenantId,
38815
- repository: options.repository,
38922
+ ...options.repository !== void 0 ? { repository: options.repository } : {},
38923
+ ...options.projectId !== void 0 ? { projectId: options.projectId } : {},
38816
38924
  commitSha: options.commitSha,
38817
38925
  ...options.branch !== void 0 ? { branch: options.branch } : {},
38818
38926
  indexers: [...indexers.values()].sort((a, b) => compareStrings(a.name, b.name) || compareStrings(a.version, b.version)),
@@ -38843,7 +38951,9 @@ async function uploadSnapshot(options) {
38843
38951
  const doFetch = options.fetch ?? fetch;
38844
38952
  const base4 = options.serviceUrl.replace(/\/+$/, "");
38845
38953
  const manifest = SnapshotManifest.parse(options.manifest);
38846
- const { tenantId, repository, commitSha } = manifest;
38954
+ const { tenantId, repository, projectId, commitSha } = manifest;
38955
+ const byProject = projectId !== void 0 && (repository === void 0 || options.byProject === true);
38956
+ if (!byProject && repository === void 0) throw new Error("the manifest names neither a repository nor a project");
38847
38957
  const headers = { authorization: `Bearer ${options.token}`, "content-type": "application/json" };
38848
38958
  const send2 = async (path, body2) => {
38849
38959
  for (let attempt2 = 1; ; attempt2 += 1) {
@@ -38861,16 +38971,17 @@ async function uploadSnapshot(options) {
38861
38971
  failure4 = error62 instanceof Error ? error62.message : String(error62);
38862
38972
  if (attempt2 >= ATTEMPTS) throw new Error(`POST ${path} failed: ${failure4}`);
38863
38973
  }
38864
- await new Promise((resolve13) => setTimeout(resolve13, (options.retryDelayMs ?? 500) * attempt2));
38974
+ await new Promise((resolve14) => setTimeout(resolve14, (options.retryDelayMs ?? 500) * attempt2));
38865
38975
  }
38866
38976
  };
38867
- const manifestResponse = await send2(codePaths.uploadManifest(tenantId, repository.owner, repository.name), JSON.stringify(manifest));
38977
+ const manifestPath = byProject ? codePaths.projectUploadManifest(tenantId, projectId ?? "") : codePaths.uploadManifest(tenantId, repository?.owner ?? "", repository?.name ?? "");
38978
+ const manifestResponse = await send2(manifestPath, JSON.stringify(manifest));
38868
38979
  const { missing } = ManifestUploadResponse.parse(await manifestResponse.json());
38869
38980
  const wanted = new Set(missing);
38870
38981
  for (const hash2 of options.existing ?? []) wanted.delete(hash2);
38871
38982
  const maxShards = options.maxBatchShards ?? MAX_BATCH_SHARDS;
38872
38983
  const maxBytes = options.maxBatchBytes ?? MAX_BATCH_BYTES;
38873
- const shardsPath = codePaths.uploadShards(tenantId, repository.owner, repository.name, commitSha);
38984
+ const shardsPath = byProject ? codePaths.projectUploadShards(tenantId, projectId ?? "", commitSha) : codePaths.uploadShards(tenantId, repository?.owner ?? "", repository?.name ?? "", commitSha);
38874
38985
  let batch = [];
38875
38986
  let batchBytes = 0;
38876
38987
  let uploadedShards = 0;
@@ -38894,7 +39005,7 @@ async function uploadSnapshot(options) {
38894
39005
  batchBytes += size;
38895
39006
  }
38896
39007
  await flush();
38897
- await send2(codePaths.publish(tenantId, repository.owner, repository.name, commitSha), "{}");
39008
+ await send2(byProject ? codePaths.projectPublish(tenantId, projectId ?? "", commitSha) : codePaths.publish(tenantId, repository?.owner ?? "", repository?.name ?? "", commitSha), "{}");
38898
39009
  return { missing: missing.length, uploadedShards, batches };
38899
39010
  }
38900
39011
  var MAX_BATCH_SHARDS, MAX_BATCH_BYTES, ATTEMPTS, HttpError;
@@ -38939,7 +39050,7 @@ var init_oidc = __esm({
38939
39050
  // ../index-builder/src/run.ts
38940
39051
  import { execFile as execFile2 } from "node:child_process";
38941
39052
  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";
39053
+ import { join as join26, resolve as resolve12 } from "node:path";
38943
39054
  import { parseArgs as parseArgs2 } from "node:util";
38944
39055
  import { promisify as promisify2 } from "node:util";
38945
39056
  async function git3(root, args2) {
@@ -38960,9 +39071,11 @@ async function repositoryFromRemote(root) {
38960
39071
  }
38961
39072
  }
38962
39073
  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");
39074
+ const root = resolve12(typeof values["root"] === "string" ? values["root"] : process.cwd());
39075
+ const projectId = typeof values["project"] === "string" ? values["project"] : void 0;
39076
+ if (projectId !== void 0 && !ProjectId.safeParse(projectId).success) throw new UsageError2(`--project must be a project identifier, got "${projectId}"`);
39077
+ 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);
39078
+ if (!repoText && projectId === void 0) throw new UsageError2("cannot determine the repository; pass --project ID, or --repo owner/name");
38966
39079
  const commit = (typeof values["commit"] === "string" ? values["commit"] : void 0) ?? env["GITHUB_SHA"] ?? await git3(root, ["rev-parse", "HEAD"]);
38967
39080
  const branch = typeof values["branch"] === "string" ? values["branch"] : void 0;
38968
39081
  const tenant = (typeof values["tenant"] === "string" ? values["tenant"] : void 0) ?? env["HARNESS_TENANT"];
@@ -38970,9 +39083,10 @@ async function snapshotFromArgs(values, env) {
38970
39083
  const scip = Array.isArray(values["scip"]) ? values["scip"] : [];
38971
39084
  return buildSnapshot({
38972
39085
  repoRoot: root,
38973
- scipFiles: scip.map((file2) => resolve11(file2)),
39086
+ scipFiles: scip.map((file2) => resolve12(file2)),
38974
39087
  tenantId: tenant,
38975
- repository: parseRepository(repoText),
39088
+ ...repoText ? { repository: parseRepository(repoText) } : {},
39089
+ ...projectId !== void 0 ? { projectId } : {},
38976
39090
  commitSha: commit,
38977
39091
  ...branch !== void 0 ? { branch } : {}
38978
39092
  });
@@ -38985,17 +39099,18 @@ async function runCli2(argv, env, out2 = console.log, err2 = console.error) {
38985
39099
  const outDir = values.out;
38986
39100
  if (!outDir) throw new UsageError2("build needs --out DIR");
38987
39101
  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)}`);
39102
+ await writeSnapshot(resolve12(outDir), built);
39103
+ out2(`built ${built.shards.length} shards (${built.uncovered.length} files uncovered) into ${resolve12(outDir)}`);
38990
39104
  return 0;
38991
39105
  }
38992
39106
  if (command === "upload") {
38993
39107
  const service = values.service;
38994
39108
  if (!service) throw new UsageError2("upload needs --service URL");
38995
39109
  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 });
39110
+ const byProject = values.project !== void 0;
39111
+ const token = !byProject && env["ACTIONS_ID_TOKEN_REQUEST_URL"] ? await getOidcToken(values.audience ?? service, env) : env["HARNESS_TOKEN"];
39112
+ 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");
39113
+ const result = await uploadSnapshot({ serviceUrl: service, token, manifest: built.manifest, shards: built.shards, ...byProject ? { byProject: true } : {} });
38999
39114
  out2(`published ${built.manifest.commitSha}: ${built.shards.length} shards, ${result.missing} new, ${result.batches} batches`);
39000
39115
  return 0;
39001
39116
  }
@@ -39030,10 +39145,12 @@ var init_run = __esm({
39030
39145
  init_upload();
39031
39146
  execFileAsync2 = promisify2(execFile2);
39032
39147
  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]
39148
+ mvrx-index build --scip FILE [--scip FILE ...] --out DIR [--project ID | --repo owner/name] [--tenant ID] [--commit SHA] [--branch B] [--root DIR]
39149
+ mvrx-index upload --service URL --tenant ID (--project ID | --repo owner/name) --commit SHA [--branch B] [--scip FILE ...] [--root DIR] [--audience URL]
39035
39150
 
39036
- Authentication for upload: the GitHub Actions OIDC token when ACTIONS_ID_TOKEN_REQUEST_URL is set, otherwise HARNESS_TOKEN.
39151
+ --project indexes an Overlane project (no GitHub repository needed) and uploads with HARNESS_TOKEN.
39152
+ --repo names a GitHub repository; in GitHub Actions the OIDC token is used when ACTIONS_ID_TOKEN_REQUEST_URL is set.
39153
+ Authentication for upload: HARNESS_TOKEN (always for --project), or the GitHub Actions OIDC token for --repo.
39037
39154
  `;
39038
39155
  UsageError2 = class extends Error {
39039
39156
  };
@@ -39043,6 +39160,7 @@ Authentication for upload: the GitHub Actions OIDC token when ACTIONS_ID_TOKEN_R
39043
39160
  service: { type: "string" },
39044
39161
  tenant: { type: "string" },
39045
39162
  repo: { type: "string" },
39163
+ project: { type: "string" },
39046
39164
  commit: { type: "string" },
39047
39165
  branch: { type: "string" },
39048
39166
  root: { type: "string" },
@@ -42614,14 +42732,14 @@ function inputRequiredRoundsExceededMessage(method, maxRounds) {
42614
42732
  return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
42615
42733
  }
42616
42734
  function sleep2(ms, signal) {
42617
- return new Promise((resolve13, reject) => {
42735
+ return new Promise((resolve14, reject) => {
42618
42736
  if (signal?.aborted) {
42619
42737
  reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
42620
42738
  return;
42621
42739
  }
42622
42740
  const timer = setTimeout(() => {
42623
42741
  signal?.removeEventListener("abort", onAbort);
42624
- resolve13();
42742
+ resolve14();
42625
42743
  }, ms);
42626
42744
  const onAbort = () => {
42627
42745
  clearTimeout(timer);
@@ -44417,7 +44535,7 @@ var init_src_CX2iR2pK = __esm({
44417
44535
  const flowStartedAt = Date.now();
44418
44536
  let onAbort;
44419
44537
  let cleanupMessageId;
44420
- return new Promise((resolve13, reject) => {
44538
+ return new Promise((resolve14, reject) => {
44421
44539
  const earlyReject = (error62) => {
44422
44540
  reject(error62);
44423
44541
  };
@@ -44485,7 +44603,7 @@ var init_src_CX2iR2pK = __esm({
44485
44603
  }
44486
44604
  if (decoded.kind === "invalid") return reject(decoded.error);
44487
44605
  if (decoded.kind === "input_required") {
44488
- if (options?.allowInputRequired === true) return resolve13(manualInputRequiredValue(decoded));
44606
+ if (options?.allowInputRequired === true) return resolve14(manualInputRequiredValue(decoded));
44489
44607
  const flow = {
44490
44608
  codec: codec2,
44491
44609
  request,
@@ -44497,11 +44615,11 @@ var init_src_CX2iR2pK = __esm({
44497
44615
  params
44498
44616
  }, resultSchema2, legOptions)
44499
44617
  };
44500
- return resolve13(this._resolveNonCompleteResult(decoded, flow));
44618
+ return resolve14(this._resolveNonCompleteResult(decoded, flow));
44501
44619
  }
44502
44620
  const result = decoded.result;
44503
44621
  validateStandardSchema(resultSchema2, result).then((parseResult) => {
44504
- if (parseResult.success) resolve13(parseResult.data);
44622
+ if (parseResult.success) resolve14(parseResult.data);
44505
44623
  else reject(new SdkError(SdkErrorCode.InvalidResult, `Invalid result for ${request.method}: ${parseResult.error}`));
44506
44624
  }, reject);
44507
44625
  });
@@ -47317,7 +47435,7 @@ var init_ajvProvider_CEoC_sr = __esm({
47317
47435
  ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref);
47318
47436
  const schOrFunc = root.refs[ref];
47319
47437
  if (schOrFunc) return schOrFunc;
47320
- let _sch = resolve13.call(this, root, ref);
47438
+ let _sch = resolve14.call(this, root, ref);
47321
47439
  if (_sch === void 0) {
47322
47440
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
47323
47441
  const { schemaId } = this.opts;
@@ -47343,7 +47461,7 @@ var init_ajvProvider_CEoC_sr = __esm({
47343
47461
  function sameSchemaEnv(s1, s2) {
47344
47462
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
47345
47463
  }
47346
- function resolve13(root, ref) {
47464
+ function resolve14(root, ref) {
47347
47465
  let sch;
47348
47466
  while (typeof (sch = this.refs[ref]) == "string") ref = sch;
47349
47467
  return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
@@ -47793,7 +47911,7 @@ var init_ajvProvider_CEoC_sr = __esm({
47793
47911
  else if (typeof uri === "object") uri = parse5(serialize(uri, options), options);
47794
47912
  return uri;
47795
47913
  }
47796
- function resolve13(baseURI, relativeURI, options) {
47914
+ function resolve14(baseURI, relativeURI, options) {
47797
47915
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
47798
47916
  const resolved = resolveComponent(parse5(baseURI, schemelessOptions), parse5(relativeURI, schemelessOptions), schemelessOptions, true);
47799
47917
  schemelessOptions.skipEscape = true;
@@ -47967,7 +48085,7 @@ var init_ajvProvider_CEoC_sr = __esm({
47967
48085
  const fastUri = {
47968
48086
  SCHEMES,
47969
48087
  normalize,
47970
- resolve: resolve13,
48088
+ resolve: resolve14,
47971
48089
  resolveComponent,
47972
48090
  equal,
47973
48091
  serialize,
@@ -53664,7 +53782,7 @@ var init_stdio = __esm({
53664
53782
  }
53665
53783
  send(message) {
53666
53784
  if (this._closed) return Promise.reject(/* @__PURE__ */ new Error("StdioServerTransport is closed"));
53667
- return new Promise((resolve13, reject) => {
53785
+ return new Promise((resolve14, reject) => {
53668
53786
  const json2 = serializeMessage(message);
53669
53787
  let settled = false;
53670
53788
  const onError = (error62) => {
@@ -53679,14 +53797,14 @@ var init_stdio = __esm({
53679
53797
  settled = true;
53680
53798
  this._stdout.off("error", onError);
53681
53799
  this._stdout.off("drain", onDrain);
53682
- resolve13();
53800
+ resolve14();
53683
53801
  };
53684
53802
  this._stdout.once("error", onError);
53685
53803
  if (this._stdout.write(json2)) {
53686
53804
  if (settled) return;
53687
53805
  settled = true;
53688
53806
  this._stdout.off("error", onError);
53689
- resolve13();
53807
+ resolve14();
53690
53808
  } else if (!settled) this._stdout.once("drain", onDrain);
53691
53809
  });
53692
53810
  }
@@ -53740,14 +53858,14 @@ var init_stdio = __esm({
53740
53858
  */
53741
53859
  async whenRequestsAnswered(timeoutMs) {
53742
53860
  if (this._closed || this._pendingRequests.size === 0) return true;
53743
- return await new Promise((resolve13) => {
53861
+ return await new Promise((resolve14) => {
53744
53862
  const waiter = () => {
53745
53863
  clearTimeout(timer);
53746
- resolve13(true);
53864
+ resolve14(true);
53747
53865
  };
53748
53866
  const timer = setTimeout(() => {
53749
53867
  this._drainWaiters = this._drainWaiters.filter((pending) => pending !== waiter);
53750
- resolve13(false);
53868
+ resolve14(false);
53751
53869
  }, timeoutMs);
53752
53870
  this._drainWaiters.push(waiter);
53753
53871
  });
@@ -53972,9 +54090,9 @@ var init_config = __esm({
53972
54090
 
53973
54091
  // ../code-shim/src/local.ts
53974
54092
  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";
54093
+ import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve13, sep as sep2 } from "node:path";
53976
54094
  function resolveInside(root, path) {
53977
- const absolute = resolve12(root, path);
54095
+ const absolute = resolve13(root, path);
53978
54096
  const rel = relative3(root, absolute);
53979
54097
  if (rel.length === 0 || rel.startsWith("..") || isAbsolute2(rel)) return null;
53980
54098
  return absolute;
@@ -55448,19 +55566,19 @@ function pkcePair() {
55448
55566
  return { verifier, challenge: base64url3(createHash("sha256").update(verifier).digest()) };
55449
55567
  }
55450
55568
  function listen(server, port) {
55451
- return new Promise((resolve13, reject) => {
55569
+ return new Promise((resolve14, reject) => {
55452
55570
  const onError = (error62) => reject(error62);
55453
55571
  server.once("error", onError);
55454
55572
  server.listen(port, "127.0.0.1", () => {
55455
55573
  server.off("error", onError);
55456
- resolve13();
55574
+ resolve14();
55457
55575
  });
55458
55576
  });
55459
55577
  }
55460
55578
  async function startLoopback(preferredPort, state) {
55461
55579
  let settle2;
55462
- const code2 = new Promise((resolve13, reject) => {
55463
- settle2 = { resolve: resolve13, reject };
55580
+ const code2 = new Promise((resolve14, reject) => {
55581
+ settle2 = { resolve: resolve14, reject };
55464
55582
  });
55465
55583
  code2.catch(() => void 0);
55466
55584
  const server = createServer((request, response) => {
@@ -55648,7 +55766,7 @@ async function requireToken(deps, serviceUrl) {
55648
55766
 
55649
55767
  // ../cli/src/project.ts
55650
55768
  init_src();
55651
- import { join as join5 } from "node:path";
55769
+ import { basename, join as join5 } from "node:path";
55652
55770
  var REMOTE_PATTERNS = [
55653
55771
  /^(?:https?|git|ssh):\/\/(?:[^@/]+@)?github\.com(?::\d+)?\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i,
55654
55772
  /^(?:[^@/]+@)?github\.com:([^/]+)\/([^/]+?)(?:\.git)?\/?$/i
@@ -55663,21 +55781,49 @@ function parseGitHubRemote(url2) {
55663
55781
  }
55664
55782
  return null;
55665
55783
  }
55666
- async function detectProject(deps) {
55784
+ function parseProvider(value) {
55785
+ if (value === void 0) return void 0;
55786
+ if (PROVIDERS.includes(value)) return value;
55787
+ throw new UsageError(`--provider must be one of ${PROVIDERS.join(", ")}`, { hint: "overlane connect --provider overlane" });
55788
+ }
55789
+ function safeName(text) {
55790
+ const cleaned = text.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|-+$/g, "");
55791
+ return cleaned.slice(0, 100) === "" ? "project" : cleaned.slice(0, 100);
55792
+ }
55793
+ function projectLabel(project) {
55794
+ return project.repository === void 0 ? project.name : `${project.repository.owner}/${project.repository.name}`;
55795
+ }
55796
+ function projectSummary(project) {
55797
+ return { provider: project.provider, ...project.repository === void 0 ? {} : { owner: project.repository.owner }, name: project.repository?.name ?? project.name, root: project.root };
55798
+ }
55799
+ function projectRequest(project) {
55800
+ if (project.provider === "github" && project.repository !== void 0) {
55801
+ return { provider: "github", repository: project.repository, name: project.name };
55802
+ }
55803
+ return { provider: "overlane", name: project.name };
55804
+ }
55805
+ async function detectProject(deps, choice = {}) {
55667
55806
  const top = await deps.exec("git", ["rev-parse", "--show-toplevel"], { cwd: deps.paths.cwd });
55668
55807
  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");
55808
+ throw new UsageError("not inside a git repository (or git is not installed); run overlane from your project folder (`git init` makes one)");
55670
55809
  }
55671
55810
  const root = top.stdout.trim();
55811
+ 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
55812
  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");
55813
+ const originUrl = remote.code === 0 ? remote.stdout.trim() : "";
55814
+ const github = originUrl.length === 0 ? null : parseGitHubRemote(originUrl);
55815
+ const wanted = choice.provider;
55816
+ if (wanted === "gitlab") {
55817
+ 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" });
55818
+ }
55819
+ if (wanted === "github" && github === null) {
55820
+ const why = originUrl.length === 0 ? "this repository has no `origin` remote" : `origin is ${originUrl}, which is not a github.com repository`;
55821
+ 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" });
55675
55822
  }
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`);
55823
+ if (github !== null && wanted !== "overlane") {
55824
+ return { root, provider: "github", name: choice.name ?? github.name, repository: github };
55679
55825
  }
55680
- return { root, repository };
55826
+ return { root, provider: "overlane", name: choice.name ?? (basename(root).slice(0, 100) || "project") };
55681
55827
  }
55682
55828
  async function headCommit(deps, root) {
55683
55829
  const head = await deps.exec("git", ["rev-parse", "HEAD"], { cwd: root });
@@ -55917,7 +56063,7 @@ var DEFAULT_SERVICE_URL = "https://api.overlane.dev";
55917
56063
  var CONNECT_STEPS = {
55918
56064
  "sign-up": "sign in through the browser (OAuth with PKCE), or use HARNESS_TOKEN",
55919
56065
  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",
56066
+ repo: "bind this project to the service: a native Overlane project by default, or your GitHub repository",
55921
56067
  "first-task": 'start your first task with `overlane task new "<title>"`',
55922
56068
  "first-review": "read the first review in the web app",
55923
56069
  invite: "invite teammates from the web app (optional, never blocks)"
@@ -55966,10 +56112,9 @@ async function connect(deps, options) {
55966
56112
  if (active.length === 0) {
55967
56113
  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
56114
  }
55969
- const project = await detectProject(deps);
56115
+ const project = await detectProject(deps, { name: options.name, provider: options.provider });
55970
56116
  const root = project.root;
55971
- const { repository } = project;
55972
- say(deps, `Project: ${repository.owner}/${repository.name} at ${root}`);
56117
+ say(deps, `Project: ${projectLabel(project)}${project.provider === "overlane" ? " (native Overlane project; no GitHub account needed)" : " (GitHub)"} at ${root}`);
55973
56118
  const existing = readBindingFile(root);
55974
56119
  const serviceInput = options.service ?? deps.env["HARNESS_SERVICE_URL"] ?? (existing.kind === "ok" ? existing.binding.serviceUrl : DEFAULT_SERVICE_URL);
55975
56120
  if (serviceInput === void 0 || serviceInput.length === 0) {
@@ -56017,7 +56162,7 @@ async function connect(deps, options) {
56017
56162
  say(deps, `Steps (the same names as the web onboarding): ${STEP_NAMES.join(", ")}`);
56018
56163
  say(deps, "Plan");
56019
56164
  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}`);
56165
+ say(deps, ` service: GET ${serviceUrl}/v1/me, then create or look up the project ${projectLabel(project)}`);
56021
56166
  for (const step2 of steps) say(deps, ` ${step2.agent}: ${step2.summary}
56022
56167
  $ ${formatCommand(step2)}`);
56023
56168
  if (codexEdit !== null) {
@@ -56045,7 +56190,7 @@ async function connect(deps, options) {
56045
56190
  service: serviceUrl,
56046
56191
  requests: [
56047
56192
  { 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" },
56193
+ { method: "POST", path: apiPaths.projects("<tenantId from /v1/me>"), body: projectRequest(project), note: "creates the project or returns the existing one" },
56049
56194
  { method: "GET", path: releasePaths.publicKey(), note: "the release-signing key; a failure here does not fail connect" }
56050
56195
  ],
56051
56196
  commands: steps.map((step2) => formatCommand(step2)),
@@ -56065,7 +56210,7 @@ async function connect(deps, options) {
56065
56210
  }
56066
56211
  if (!await deps.confirm("Apply this plan?")) {
56067
56212
  say(deps, "Cancelled; nothing changed.");
56068
- return { data: emptyResult(repository, root, serviceUrl, infos, true) };
56213
+ return { data: emptyResult(project, serviceUrl, infos, true) };
56069
56214
  }
56070
56215
  }
56071
56216
  const token = await ensureToken(deps, serviceUrl);
@@ -56074,8 +56219,7 @@ async function connect(deps, options) {
56074
56219
  const wrote = [];
56075
56220
  const applied = [];
56076
56221
  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);
56222
+ const record3 = await createProject(deps, serviceUrl, me.tenantId, token.token, projectRequest(project));
56079
56223
  if (record3.tenantId !== me.tenantId) throw new CliError("the service returned a project for another tenant");
56080
56224
  const servicePublicKey = await fetchServicePublicKey(deps, serviceUrl, token.token) ?? (existing.kind === "ok" ? existing.binding.servicePublicKey ?? null : null);
56081
56225
  const binding = ProjectBinding.parse({
@@ -56114,7 +56258,7 @@ async function connect(deps, options) {
56114
56258
  owned.binding = true;
56115
56259
  if (excludeNeeded && await addExclude(deps, root)) owned.excludeLine = true;
56116
56260
  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 } });
56261
+ const next = await reportStep(deps, serviceUrl, token.token, me.tenantId, "repo", { repo: repoChoice(project) });
56118
56262
  if (next !== null) say(deps, `Next in onboarding: ${next === "repo" ? "first-task" : next} (${CONNECT_STEPS[next === "repo" ? "first-task" : next]})`);
56119
56263
  } finally {
56120
56264
  if (previousOwned !== null || owned.binding || owned.claude !== void 0 || owned.codex !== void 0) writeOwned(root, owned);
@@ -56128,7 +56272,7 @@ async function connect(deps, options) {
56128
56272
  for (const line2 of renderReports(reports)) say(deps, ` ${line2}`);
56129
56273
  return {
56130
56274
  data: {
56131
- project: { owner: repository.owner, name: repository.name, root },
56275
+ project: projectSummary(project),
56132
56276
  serviceUrl,
56133
56277
  tenantId: binding.tenantId,
56134
56278
  projectId: binding.projectId,
@@ -56142,9 +56286,13 @@ async function connect(deps, options) {
56142
56286
  }
56143
56287
  };
56144
56288
  }
56145
- function emptyResult(repository, root, serviceUrl, infos, cancelled) {
56289
+ function repoChoice(project) {
56290
+ if (project.provider === "github" && project.repository !== void 0) return { provider: "github", owner: project.repository.owner, name: project.repository.name };
56291
+ return { provider: "overlane", owner: "native", name: safeName(project.name) };
56292
+ }
56293
+ function emptyResult(project, serviceUrl, infos, cancelled) {
56146
56294
  return {
56147
- project: { owner: repository.owner, name: repository.name, root },
56295
+ project: projectSummary(project),
56148
56296
  serviceUrl,
56149
56297
  credentials: "unchanged",
56150
56298
  agents: infos.map((info2) => ({ agent: info2.agent, installed: info2.installed, detail: info2.detail })),
@@ -56207,8 +56355,8 @@ function withTimeout(deps, ms) {
56207
56355
  }
56208
56356
  async function attempt(deps, ms, work) {
56209
56357
  let timer;
56210
- const deadline = new Promise((resolve13) => {
56211
- timer = setTimeout(() => resolve13("unreachable"), ms);
56358
+ const deadline = new Promise((resolve14) => {
56359
+ timer = setTimeout(() => resolve14("unreachable"), ms);
56212
56360
  });
56213
56361
  try {
56214
56362
  return await Promise.race([work(withTimeout(deps, ms)).catch((error62) => error62 instanceof ServiceError && error62.exit === EXIT.auth ? "unauthenticated" : "unreachable"), deadline]);
@@ -57347,13 +57495,13 @@ async function readPlan(repoDir) {
57347
57495
  init_src();
57348
57496
  init_zod();
57349
57497
  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";
57498
+ import { basename as basename3, dirname as dirname7, join as join17, resolve as resolve6 } from "node:path";
57351
57499
 
57352
57500
  // ../kit/src/detect.ts
57353
57501
  var import_yaml2 = __toESM(require_dist(), 1);
57354
57502
  init_src();
57355
57503
  import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
57356
- import { basename, join as join16, resolve as resolve5 } from "node:path";
57504
+ import { basename as basename2, join as join16, resolve as resolve5 } from "node:path";
57357
57505
  var KINDS = ["typecheck", "lint", "build", "test"];
57358
57506
  async function readOptional(file2) {
57359
57507
  try {
@@ -57498,7 +57646,7 @@ async function draftPlanForExisting(repoDir, opts = {}) {
57498
57646
  } catch {
57499
57647
  }
57500
57648
  }
57501
- const name2 = (opts.name ?? pkgName ?? basename(root)).slice(0, 100);
57649
+ const name2 = (opts.name ?? pkgName ?? basename2(root)).slice(0, 100);
57502
57650
  const milestone = opts.milestoneId ?? "M1";
57503
57651
  const allowedPaths = opts.allowedPaths ?? ["."];
57504
57652
  const tasks = [];
@@ -57696,7 +57844,7 @@ async function importSpecKit(repoDir) {
57696
57844
  const constitution = await findConstitution(root);
57697
57845
  const parsedConstitution = constitution ? parseConstitution(constitution.text) : void 0;
57698
57846
  const firstInput = /\*\*Input\*\*:\s*User description:\s*"(.*)"/.exec(features[0]?.specText ?? "")?.[1];
57699
- const name2 = (parsedConstitution?.name ?? basename2(root)).slice(0, 100);
57847
+ const name2 = (parsedConstitution?.name ?? basename3(root)).slice(0, 100);
57700
57848
  const goal = (parsedConstitution?.goal ?? firstInput ?? `Deliver ${name2}.`).slice(0, 2e3);
57701
57849
  const multi = features.length > 1;
57702
57850
  const counts2 = /* @__PURE__ */ new Map();
@@ -59069,7 +59217,7 @@ var contextCommand = defineCommand({
59069
59217
  init_src();
59070
59218
  init_zod();
59071
59219
  import { existsSync as existsSync4, readFileSync as readFileSync7 } from "node:fs";
59072
- import { basename as basename3, resolve as resolve7 } from "node:path";
59220
+ import { basename as basename4, resolve as resolve7 } from "node:path";
59073
59221
  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
59222
  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
59223
  var ECOSYSTEM_FLAG = { name: "ecosystem", type: "string", enum: DOCS_ECOSYSTEMS, default: "npm", description: "Where the library is published" };
@@ -59181,7 +59329,7 @@ function readLockfiles(paths) {
59181
59329
  const files = paths.length > 0 ? paths : DEFAULT_LOCKFILES.filter((name2) => existsSync4(resolve7(name2)));
59182
59330
  if (files.length === 0) throw new UsageError("no lockfile found in this directory", { hint: "overlane lib pins --project <id> --lockfile pnpm-lock.yaml" });
59183
59331
  return files.map((file2) => {
59184
- const kind = LOCKFILES.find(([pattern]) => pattern.test(basename3(file2)))?.[1];
59332
+ const kind = LOCKFILES.find(([pattern]) => pattern.test(basename4(file2)))?.[1];
59185
59333
  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
59334
  try {
59187
59335
  return { kind, content: readFileSync7(resolve7(file2), "utf8") };
@@ -59277,7 +59425,7 @@ var libAddCommand = defineCommand({
59277
59425
  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
59426
  const pages = files.map((file2) => {
59279
59427
  try {
59280
- return { title: basename3(file2), text: readFileSync7(resolve7(file2), "utf8") };
59428
+ return { title: basename4(file2), text: readFileSync7(resolve7(file2), "utf8") };
59281
59429
  } catch {
59282
59430
  throw new UsageError(`cannot read ${file2}`);
59283
59431
  }
@@ -59353,7 +59501,7 @@ async function post(deps, base4, path, body2) {
59353
59501
  return { status: response.status, json: json2 };
59354
59502
  }
59355
59503
  function sleep(ms) {
59356
- return new Promise((resolve13) => setTimeout(resolve13, ms));
59504
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
59357
59505
  }
59358
59506
  async function deviceLogin(deps, service, options) {
59359
59507
  const started = await post(deps, service, "/auth/device", {});
@@ -60951,6 +61099,7 @@ var loopCommands = [loopListCommand, loopNewCommand, loopSetCommand, loopFireCom
60951
61099
  // ../cli/src/commands/review.ts
60952
61100
  init_src();
60953
61101
  import { randomUUID as randomUUID7 } from "node:crypto";
61102
+ import { resolve as resolve9 } from "node:path";
60954
61103
  var common7 = { needsAuth: true, needsNetwork: true };
60955
61104
  var requestId7 = () => `cli-${randomUUID7()}`;
60956
61105
  async function connected3(inv) {
@@ -60969,9 +61118,38 @@ async function repositoryOf(inv) {
60969
61118
  }
60970
61119
  const remote = await inv.deps.exec("git", ["remote", "get-url", "origin"], { cwd: inv.deps.paths.cwd });
60971
61120
  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" });
61121
+ 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
61122
  return `${match[1]}/${match[2]}`;
60974
61123
  }
61124
+ async function diffOf(inv) {
61125
+ const flag = textFlag(inv, "diff");
61126
+ const pull = inv.positionals[0];
61127
+ 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" });
61128
+ let from;
61129
+ let text;
61130
+ if (flag !== void 0) {
61131
+ if (flag === "-") {
61132
+ 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" });
61133
+ from = "standard input";
61134
+ text = await inv.deps.stdin.read();
61135
+ } else {
61136
+ from = flag;
61137
+ text = readText(resolve9(inv.deps.paths.cwd, flag));
61138
+ if (text === null) throw new UsageError(`could not read the diff file ${flag}`, { hint: "git diff > change.patch && overlane review run --diff change.patch" });
61139
+ }
61140
+ } else if (pull === void 0) {
61141
+ if (inv.deps.stdin === void 0 || inv.deps.stdin.isTTY) {
61142
+ 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" });
61143
+ }
61144
+ from = "standard input";
61145
+ text = await inv.deps.stdin.read();
61146
+ } else {
61147
+ return void 0;
61148
+ }
61149
+ 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" });
61150
+ if (text.length > MAX_PATCH_BYTES) throw new UsageError(`the diff is larger than ${MAX_PATCH_BYTES} characters; review it in parts`);
61151
+ return { text, from };
61152
+ }
60975
61153
  function id(inv, what) {
60976
61154
  const value = inv.positionals[0];
60977
61155
  if (value === void 0) throw new UsageError(`${what} needs a finding ID`, { hint: "overlane review findings" });
@@ -60980,22 +61158,39 @@ function id(inv, what) {
60980
61158
  var FINDING_LINE = (finding) => `${finding.status.padEnd(9)} ${finding.severity.padEnd(8)} ${finding.path}:${finding.line} ${finding.rule ?? "see reason"} ${finding.id}`;
60981
61159
  var reviewRunCommand = defineCommand({
60982
61160
  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"],
61161
+ summary: "Review a diff (no repository needed) or a pull request now and report the findings",
61162
+ 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.",
61163
+ args: [{ name: "pull", required: false, description: "A pull request number (omit it to review a diff)" }],
61164
+ flags: [
61165
+ { name: "diff", type: "string", value: "FILE", description: "Review this unified diff (a file, or - for standard input); needs no repository" },
61166
+ { name: "title", type: "string", value: "TEXT", description: "A title for the diff, shown in the summary" },
61167
+ { name: "label", type: "string", value: "NAME", description: "Names the diff so a re-review of the same change merges its findings (default: patch)" },
61168
+ { name: "repo", type: "string", value: "OWNER/NAME", description: "For a pull request number: the GitHub repository (default: the origin remote); not used with --diff" }
61169
+ ],
61170
+ examples: ["overlane review run --diff change.patch", "overlane review run --diff -", "overlane review run 7 --repo acme/app --dry-run"],
60988
61171
  effect: "write",
60989
61172
  ...common7,
60990
- keywords: ["code review", "review pull request", "review pr", "ai review", "check my pr", "findings"],
61173
+ keywords: ["code review", "review diff", "review patch", "review pull request", "review pr", "check my pr", "findings"],
60991
61174
  result: withDryRun(ReviewRunResponse),
60992
61175
  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
61176
  handler: async (inv) => {
61177
+ const diff = await diffOf(inv);
61178
+ if (diff !== void 0) {
61179
+ const title = textFlag(inv, "title");
61180
+ const label = textFlag(inv, "label");
61181
+ const source = { kind: "patch", diff: diff.text, ...title === void 0 ? {} : { title }, ...label === void 0 ? {} : { label } };
61182
+ const patchBody = { requestId: requestId7(), trigger: "manual", source };
61183
+ 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");
61184
+ const sent = await connected3(inv);
61185
+ const patched = await sent.call(ReviewRunResponse, "POST", reviewPaths.runs(sent.tenantId, sent.projectId), patchBody);
61186
+ if (patched.run.status === "partial") say(inv.deps, "Partial review: the token cap was reached. The summary lists what was not covered.");
61187
+ return { data: patched };
61188
+ }
60994
61189
  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" });
61190
+ 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
61191
  const repository = await repositoryOf(inv);
60997
61192
  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");
61193
+ if (inv.dryRun) return planned3(inv, "POST", reviewPaths.runs, body2, "reads the pull request through the GitHub connection and runs the review");
60999
61194
  const { call: call2, tenantId, projectId } = await connected3(inv);
61000
61195
  const result = await call2(ReviewRunResponse, "POST", reviewPaths.runs(tenantId, projectId), body2);
61001
61196
  if (result.run.status === "partial") say(inv.deps, "Partial review: the token cap was reached. The summary lists what was not covered.");
@@ -61106,7 +61301,7 @@ var reviewSettingsCommand = defineCommand({
61106
61301
  var reviewSettingsSetCommand = defineCommand({
61107
61302
  path: ["review", "settings", "set"],
61108
61303
  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.",
61304
+ 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
61305
  flags: [
61111
61306
  { name: "mode", type: "string", enum: ["log_only", "comments"], description: "log_only records findings only; comments posts them" },
61112
61307
  { name: "token-cap", type: "string", value: "N", description: "Most tokens one pull request may use (1,000 to 2,000,000)" },
@@ -61192,7 +61387,7 @@ function rootHelp(specs, version2) {
61192
61387
  const lines = [
61193
61388
  ROOT_FIRST_LINE,
61194
61389
  "",
61195
- `overlane${version2 === "" ? "" : ` ${version2}`} - connect a GitHub project to Overlane, and run its tasks`,
61390
+ `overlane${version2 === "" ? "" : ` ${version2}`} - connect a project to Overlane (no GitHub account needed), and run its tasks`,
61196
61391
  "",
61197
61392
  "Usage: overlane <command> [flags] overlane <command> --help overlane schema <command>",
61198
61393
  "",
@@ -61503,7 +61698,7 @@ init_zod();
61503
61698
  // ../cli/src/connect-result.ts
61504
61699
  init_zod();
61505
61700
  var ConnectResult = external_exports.object({
61506
- project: external_exports.object({ owner: external_exports.string(), name: external_exports.string(), root: external_exports.string() }),
61701
+ 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
61702
  serviceUrl: external_exports.string(),
61508
61703
  tenantId: external_exports.string().optional(),
61509
61704
  projectId: external_exports.string().optional(),
@@ -61648,10 +61843,10 @@ async function disconnect(deps, options) {
61648
61843
  }
61649
61844
 
61650
61845
  // ../cli/src/doctor.ts
61651
- import { resolve as resolve9 } from "node:path";
61846
+ import { resolve as resolve10 } from "node:path";
61652
61847
  init_zod();
61653
61848
  var DoctorResult = external_exports.object({
61654
- project: external_exports.object({ owner: external_exports.string(), name: external_exports.string(), root: external_exports.string() }),
61849
+ 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
61850
  binding: external_exports.enum(["ok", "missing", "invalid"]),
61656
61851
  service: external_exports.string().optional(),
61657
61852
  credentials: external_exports.string().optional(),
@@ -61668,13 +61863,13 @@ async function doctor(deps, options) {
61668
61863
  const root = project.root;
61669
61864
  const binding = readBindingFile(root);
61670
61865
  const owned = readOwned(root);
61671
- const marketplaceRoot2 = resolve9(options.marketplaceRoot ?? owned?.marketplaceRoot ?? deps.paths.defaultMarketplaceRoot);
61866
+ const marketplaceRoot2 = resolve10(options.marketplaceRoot ?? owned?.marketplaceRoot ?? deps.paths.defaultMarketplaceRoot);
61672
61867
  const infos = await detectAgents(deps, options.agents, root);
61673
61868
  let service = "reachable";
61674
61869
  let hasToken = false;
61675
61870
  let credentials;
61676
61871
  let checked2 = false;
61677
- say(deps, `Project: ${project.repository.owner}/${project.repository.name} at ${root}`);
61872
+ say(deps, `Project: ${projectLabel(project)} at ${root}`);
61678
61873
  if (binding.kind === "ok") {
61679
61874
  const { serviceUrl } = binding.binding;
61680
61875
  const token = await findToken(deps, serviceUrl);
@@ -61698,7 +61893,7 @@ async function doctor(deps, options) {
61698
61893
  const installedStates = reports.filter((report2, index) => infos[index]?.installed === true).map((report2) => report2.state);
61699
61894
  const ready = installedStates.length > 0 && installedStates.every((state) => state === "ready");
61700
61895
  const data = {
61701
- project: { owner: project.repository.owner, name: project.repository.name, root },
61896
+ project: projectSummary(project),
61702
61897
  binding: binding.kind,
61703
61898
  ...binding.kind === "ok" ? { service: binding.binding.serviceUrl } : {},
61704
61899
  ...credentials === void 0 ? {} : { credentials },
@@ -61818,7 +62013,7 @@ function newPlan(name2, goal, withCiTask) {
61818
62013
  id: "T001",
61819
62014
  title: "Add CI",
61820
62015
  milestone: "M1",
61821
- outcome: "A GitHub Actions workflow runs the project's install, typecheck and test commands on every push and pull request.",
62016
+ 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
62017
  allowedPaths: [".github/**"],
61823
62018
  acceptance: ["A workflow in .github/workflows runs on push and pull_request"],
61824
62019
  verification: ['test -n "$(ls .github/workflows/*.yml .github/workflows/*.yaml 2>/dev/null)"'],
@@ -61857,7 +62052,8 @@ function schedulerSetup(projectId) {
61857
62052
  }
61858
62053
  async function connectKit(deps, options) {
61859
62054
  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);
62055
+ const project = await detectProject(deps, { name: options.name, provider: options.provider });
62056
+ const { root } = project;
61861
62057
  if (await headCommit(deps, root) === null) throw new CliError("the repository has no commit yet; make an initial commit first");
61862
62058
  const planDir = join22(root, PLAN_DIR);
61863
62059
  const planExists = existsSync6(join22(planDir, "project.md"));
@@ -61869,7 +62065,7 @@ async function connectKit(deps, options) {
61869
62065
  plan3 = await readPlan(root);
61870
62066
  planSource = `${PLAN_DIR}/ already exists; kept as it is`;
61871
62067
  } else if (options.mode === "new") {
61872
- plan3 = newPlan(repository.name, options.goal ?? "", !ciExists);
62068
+ plan3 = newPlan(project.name, options.goal ?? "", !ciExists);
61873
62069
  planSource = "minimal plan from --goal";
61874
62070
  } else if (hasSpecKit(root)) {
61875
62071
  plan3 = await importSpecKit(root);
@@ -61892,7 +62088,7 @@ async function connectKit(deps, options) {
61892
62088
  const touched = [...INSTRUCTION_FILES, CI_FILE];
61893
62089
  const unsaved = await dirty(deps, root, touched);
61894
62090
  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}`);
62091
+ say(deps, `Kit setup (${options.mode}) for ${projectLabel(project)}`);
61896
62092
  say(deps, ` branch: create ${KIT_BRANCH}`);
61897
62093
  say(deps, ` plan: ${planSource} (${plan3.milestones.length} milestone(s), ${plan3.tasks.length} task(s))${planExists ? "" : `, written to ${PLAN_DIR}/`}`);
61898
62094
  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 +62165,7 @@ async function connectKit(deps, options) {
61969
62165
  say(deps, `Run policy set (build-ahead limit ${firstMilestone}).`);
61970
62166
  const synced = await kit.syncPlan(PlanSyncRequest.parse({ requestId: `cli-${randomUUID8()}`, sourceCommit: sha, plan: await readPlan(root) }));
61971
62167
  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);
62168
+ const pr = await openPullRequest(deps, root, project.name);
61973
62169
  say(deps);
61974
62170
  for (const line2 of schedulerSetup(binding.binding.projectId)) say(deps, line2);
61975
62171
  return {
@@ -62015,18 +62211,20 @@ var AGENTS_FLAG = { name: "agents", type: "string", value: "claude,codex", descr
62015
62211
  var ROOT_FLAG = { name: "marketplace-root", type: "string", value: "DIR", description: "Folder holding the built claude/ and codex/ plugin marketplaces" };
62016
62212
  var connectCommand = defineCommand({
62017
62213
  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.",
62214
+ summary: "Connect this project (native Overlane, or your GitHub repository): sign in, bind it, register the plugin; --kit also sets up a plan",
62215
+ 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
62216
  flags: [
62021
62217
  { name: "service", type: "string", value: "URL", description: "Service address (https); default is the hosted service or HARNESS_SERVICE_URL" },
62022
62218
  ROOT_FLAG,
62023
62219
  AGENTS_FLAG,
62024
62220
  { 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
62221
  { name: "yes", type: "boolean", description: "Apply the plan without asking (required when there is no terminal)" },
62222
+ { name: "name", type: "string", value: "NAME", description: "The project name (default: the GitHub repository name, else this folder's name)" },
62223
+ { 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
62224
  { name: "kit", type: "string", enum: ["existing", "new"], description: "Also set up the project kit: plan files, CI, instruction blocks and one pull request" },
62027
62225
  { name: "goal", type: "string", value: "TEXT", description: "The project's goal; required with --kit new" }
62028
62226
  ],
62029
- examples: ["overlane connect --dry-run", "overlane connect --yes", 'overlane connect --kit new --goal "A rundown service" --yes', "overlane connect --kit existing --yes"],
62227
+ 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
62228
  effect: "write",
62031
62229
  needsNetwork: true,
62032
62230
  keywords: ["setup", "install", "bind", "link", "onboard", "register plugin", "bootstrap", "autonomous", "plan", "kit", "get started", "initialise", "enable harness", "ci workflow", "pull request"],
@@ -62037,7 +62235,9 @@ var connectCommand = defineCommand({
62037
62235
  marketplaceRoot: textFlag(inv, "marketplace-root"),
62038
62236
  agents: parseAgentList(textFlag(inv, "agents")),
62039
62237
  dryRun: inv.dryRun,
62040
- yes: boolFlag(inv, "yes")
62238
+ yes: boolFlag(inv, "yes"),
62239
+ name: textFlag(inv, "name"),
62240
+ provider: parseProvider(textFlag(inv, "provider"))
62041
62241
  };
62042
62242
  const kit = textFlag(inv, "kit");
62043
62243
  const goal = textFlag(inv, "goal");