@teambit/ci 1.0.637 → 1.0.638

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.
@@ -39,9 +39,12 @@ class CiSyncCmd {
39
39
  // `[lane]: [string]` rather than `[string?]`: `CLIArgs` does not admit an undefined-carrying tuple.
40
40
  // The argument is genuinely optional at runtime, hence the `|| undefined` below.
41
41
  async report([lane], options) {
42
- this.logger.console('\n\n');
43
- this.logger.console('Initializing sync command');
44
42
  if (!this.workspace) throw new (_workspace().OutsideWorkspaceError)();
43
+ // --init prints its own report; the banner only frames a reconcile run.
44
+ if (!options.init) {
45
+ this.logger.console('\n\n');
46
+ this.logger.console('Initializing sync command');
47
+ }
45
48
  return this.ci.sync({
46
49
  lane: lane || undefined,
47
50
  branch: options.branch,
@@ -1 +1 @@
1
- {"version":3,"names":["_workspace","data","require","_defineProperty","e","r","t","_toPropertyKey","Object","defineProperty","value","enumerable","configurable","writable","i","_toPrimitive","Symbol","toPrimitive","call","TypeError","String","Number","CiSyncCmd","constructor","workspace","logger","ci","name","description","report","lane","options","console","OutsideWorkspaceError","sync","undefined","branch","all","main","dryRun","init","exports"],"sources":["sync.cmd.ts"],"sourcesContent":["import type { Command, CommandOptions } from '@teambit/cli';\nimport type { Logger } from '@teambit/logger';\nimport { OutsideWorkspaceError, type Workspace } from '@teambit/workspace';\nimport type { CiMain } from '../ci.main.runtime';\n\ntype Options = { branch?: string; all?: boolean; main?: boolean; dryRun?: boolean; init?: boolean };\n\nexport class CiSyncCmd implements Command {\n name = 'sync [lane]';\n arguments = [\n {\n name: 'lane',\n description:\n 'the lane to reconcile: either a lane name (hosted on the workspace\\'s defaultScope) or a scope-qualified lane id, \"other-org.other-scope/my-lane\", for a lane hosted on another scope. Only the lane\\'s defaultScope components are mirrored; components from other scopes stay on the lane as package dependencies',\n },\n ];\n description = 'Reconciles Bit lanes and the main scope with git branches and pull requests.';\n extendedDescription = `Stateless reconciler: compares each mapped lane's remote head against the state the branch itself records, and converges — importing lane changes onto the branch, exporting dev commits to the lane, or opening/closing PRs. That state comes from bit's own data: the .bitmap committed on the branch, which records the lane the branch mirrors and the exact version of every component on it. The \"chore(bit-sync)\" subject, \"Bit-Lane-Head\" trailer and \"[bit-sync]\" marker on sync commits are annotations for humans and triggers; the only decision that consults one is branch deletion, which additionally requires the marker to prove the reconciler wrote the branch tip. The main scope is reconciled by checking the workspace out to its latest exported versions and proposing the result as a sync PR. Triggers (webhook, push, cron) only decide when it runs, never what it does. Safe to re-run at any time; converged state is a no-op. A lane carrying components from other scopes (a cross-scope lane) is reconciled over its defaultScope slice only: foreign components are never written into this repository — the branch consumes them as package dependencies at their lane versions, and only their own scopes' repositories can mirror their sources. A lane with no defaultScope components has nothing to mirror here: enumerated runs skip it and stay green, an explicitly named one is refused, and a mirrored lane whose defaultScope components all left it is halted for a human. Configure mapping under \\`\"teambit.git/ci\": { \"sync\": { ... } }\\` in workspace.jsonc.`;\n group = 'collaborate';\n\n /**\n * Changing any user-facing text on this command requires regenerating the CLI reference (the\n * `generate-cli-reference*` npm scripts), or the `check_generated_reference` CI job fails. The\n * scripts invoke whatever `bit` is on PATH — put `<repo>/bin/bit.js` first — and a local workspace\n * may register extra commands, so inspect the generated diff and keep only the text that changed.\n */\n options: CommandOptions = [\n [\n '',\n 'branch <branch>',\n 'Resolve the lane from this git branch name using the sync mapping config (cannot be combined with --all)',\n ],\n [\n '',\n 'all',\n 'Reconcile every mapped lane plus the main scope (the default when no target is given; cannot be combined with a lane argument, --branch or --main)',\n ],\n [\n '',\n 'main',\n 'Reconcile only the main scope against the default branch, opening a sync PR on drift (conflicts resolve in favour of the scope)',\n ],\n [\n '',\n 'dry-run',\n 'Print the planned action per target. Nothing is pushed and no pull request is created or modified; the working tree is still written and then restored, so a dirty tree is refused rather than discarded',\n ],\n [\n '',\n 'init',\n 'One-command onboarding: scaffold .github/workflows/bit-sync.yml + bit-release.yml (with this repository\\'s actual default branch substituted), add the `\"teambit.git/ci\": { \"sync\": {} }` config block to workspace.jsonc if absent, and print the remaining manual-steps checklist (secrets + bit.cloud webhook). Writes nothing else and never overwrites an existing workflow file. Cannot be combined with a lane argument or any other flag.',\n ],\n ];\n\n constructor(\n private workspace: Workspace,\n private logger: Logger,\n private ci: CiMain\n ) {}\n\n // `[lane]: [string]` rather than `[string?]`: `CLIArgs` does not admit an undefined-carrying tuple.\n // The argument is genuinely optional at runtime, hence the `|| undefined` below.\n async report([lane]: [string], options: Options) {\n this.logger.console('\\n\\n');\n this.logger.console('Initializing sync command');\n if (!this.workspace) throw new OutsideWorkspaceError();\n\n return this.ci.sync({\n lane: lane || undefined,\n branch: options.branch,\n all: options.all,\n main: options.main,\n dryRun: options.dryRun,\n init: options.init,\n });\n }\n}\n"],"mappings":";;;;;;AAEA,SAAAA,WAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,UAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAA2E,SAAAE,gBAAAC,CAAA,EAAAC,CAAA,EAAAC,CAAA,YAAAD,CAAA,GAAAE,cAAA,CAAAF,CAAA,MAAAD,CAAA,GAAAI,MAAA,CAAAC,cAAA,CAAAL,CAAA,EAAAC,CAAA,IAAAK,KAAA,EAAAJ,CAAA,EAAAK,UAAA,MAAAC,YAAA,MAAAC,QAAA,UAAAT,CAAA,CAAAC,CAAA,IAAAC,CAAA,EAAAF,CAAA;AAAA,SAAAG,eAAAD,CAAA,QAAAQ,CAAA,GAAAC,YAAA,CAAAT,CAAA,uCAAAQ,CAAA,GAAAA,CAAA,GAAAA,CAAA;AAAA,SAAAC,aAAAT,CAAA,EAAAD,CAAA,2BAAAC,CAAA,KAAAA,CAAA,SAAAA,CAAA,MAAAF,CAAA,GAAAE,CAAA,CAAAU,MAAA,CAAAC,WAAA,kBAAAb,CAAA,QAAAU,CAAA,GAAAV,CAAA,CAAAc,IAAA,CAAAZ,CAAA,EAAAD,CAAA,uCAAAS,CAAA,SAAAA,CAAA,YAAAK,SAAA,yEAAAd,CAAA,GAAAe,MAAA,GAAAC,MAAA,EAAAf,CAAA;AAKpE,MAAMgB,SAAS,CAAoB;EA+CxCC,WAAWA,CACDC,SAAoB,EACpBC,MAAc,EACdC,EAAU,EAClB;IAAA,KAHQF,SAAoB,GAApBA,SAAoB;IAAA,KACpBC,MAAc,GAAdA,MAAc;IAAA,KACdC,EAAU,GAAVA,EAAU;IAAAvB,eAAA,eAjDb,aAAa;IAAAA,eAAA,oBACR,CACV;MACEwB,IAAI,EAAE,MAAM;MACZC,WAAW,EACT;IACJ,CAAC,CACF;IAAAzB,eAAA,sBACa,8EAA8E;IAAAA,eAAA,8BACtE,mhDAAmhD;IAAAA,eAAA,gBACjiD,aAAa;IAErB;AACF;AACA;AACA;AACA;AACA;IALEA,eAAA,kBAM0B,CACxB,CACE,EAAE,EACF,iBAAiB,EACjB,0GAA0G,CAC3G,EACD,CACE,EAAE,EACF,KAAK,EACL,oJAAoJ,CACrJ,EACD,CACE,EAAE,EACF,MAAM,EACN,iIAAiI,CAClI,EACD,CACE,EAAE,EACF,SAAS,EACT,0MAA0M,CAC3M,EACD,CACE,EAAE,EACF,MAAM,EACN,mbAAmb,CACpb,CACF;EAME;;EAEH;EACA;EACA,MAAM0B,MAAMA,CAAC,CAACC,IAAI,CAAW,EAAEC,OAAgB,EAAE;IAC/C,IAAI,CAACN,MAAM,CAACO,OAAO,CAAC,MAAM,CAAC;IAC3B,IAAI,CAACP,MAAM,CAACO,OAAO,CAAC,2BAA2B,CAAC;IAChD,IAAI,CAAC,IAAI,CAACR,SAAS,EAAE,MAAM,KAAIS,kCAAqB,EAAC,CAAC;IAEtD,OAAO,IAAI,CAACP,EAAE,CAACQ,IAAI,CAAC;MAClBJ,IAAI,EAAEA,IAAI,IAAIK,SAAS;MACvBC,MAAM,EAAEL,OAAO,CAACK,MAAM;MACtBC,GAAG,EAAEN,OAAO,CAACM,GAAG;MAChBC,IAAI,EAAEP,OAAO,CAACO,IAAI;MAClBC,MAAM,EAAER,OAAO,CAACQ,MAAM;MACtBC,IAAI,EAAET,OAAO,CAACS;IAChB,CAAC,CAAC;EACJ;AACF;AAACC,OAAA,CAAAnB,SAAA,GAAAA,SAAA","ignoreList":[]}
1
+ {"version":3,"names":["_workspace","data","require","_defineProperty","e","r","t","_toPropertyKey","Object","defineProperty","value","enumerable","configurable","writable","i","_toPrimitive","Symbol","toPrimitive","call","TypeError","String","Number","CiSyncCmd","constructor","workspace","logger","ci","name","description","report","lane","options","OutsideWorkspaceError","init","console","sync","undefined","branch","all","main","dryRun","exports"],"sources":["sync.cmd.ts"],"sourcesContent":["import type { Command, CommandOptions } from '@teambit/cli';\nimport type { Logger } from '@teambit/logger';\nimport { OutsideWorkspaceError, type Workspace } from '@teambit/workspace';\nimport type { CiMain } from '../ci.main.runtime';\n\ntype Options = { branch?: string; all?: boolean; main?: boolean; dryRun?: boolean; init?: boolean };\n\nexport class CiSyncCmd implements Command {\n name = 'sync [lane]';\n arguments = [\n {\n name: 'lane',\n description:\n 'the lane to reconcile: either a lane name (hosted on the workspace\\'s defaultScope) or a scope-qualified lane id, \"other-org.other-scope/my-lane\", for a lane hosted on another scope. Only the lane\\'s defaultScope components are mirrored; components from other scopes stay on the lane as package dependencies',\n },\n ];\n description = 'Reconciles Bit lanes and the main scope with git branches and pull requests.';\n extendedDescription = `Stateless reconciler: compares each mapped lane's remote head against the state the branch itself records, and converges — importing lane changes onto the branch, exporting dev commits to the lane, or opening/closing PRs. That state comes from bit's own data: the .bitmap committed on the branch, which records the lane the branch mirrors and the exact version of every component on it. The \"chore(bit-sync)\" subject, \"Bit-Lane-Head\" trailer and \"[bit-sync]\" marker on sync commits are annotations for humans and triggers; the only decision that consults one is branch deletion, which additionally requires the marker to prove the reconciler wrote the branch tip. The main scope is reconciled by checking the workspace out to its latest exported versions and proposing the result as a sync PR. Triggers (webhook, push, cron) only decide when it runs, never what it does. Safe to re-run at any time; converged state is a no-op. A lane carrying components from other scopes (a cross-scope lane) is reconciled over its defaultScope slice only: foreign components are never written into this repository — the branch consumes them as package dependencies at their lane versions, and only their own scopes' repositories can mirror their sources. A lane with no defaultScope components has nothing to mirror here: enumerated runs skip it and stay green, an explicitly named one is refused, and a mirrored lane whose defaultScope components all left it is halted for a human. Configure mapping under \\`\"teambit.git/ci\": { \"sync\": { ... } }\\` in workspace.jsonc.`;\n group = 'collaborate';\n\n /**\n * Changing any user-facing text on this command requires regenerating the CLI reference (the\n * `generate-cli-reference*` npm scripts), or the `check_generated_reference` CI job fails. The\n * scripts invoke whatever `bit` is on PATH — put `<repo>/bin/bit.js` first — and a local workspace\n * may register extra commands, so inspect the generated diff and keep only the text that changed.\n */\n options: CommandOptions = [\n [\n '',\n 'branch <branch>',\n 'Resolve the lane from this git branch name using the sync mapping config (cannot be combined with --all)',\n ],\n [\n '',\n 'all',\n 'Reconcile every mapped lane plus the main scope (the default when no target is given; cannot be combined with a lane argument, --branch or --main)',\n ],\n [\n '',\n 'main',\n 'Reconcile only the main scope against the default branch, opening a sync PR on drift (conflicts resolve in favour of the scope)',\n ],\n [\n '',\n 'dry-run',\n 'Print the planned action per target. Nothing is pushed and no pull request is created or modified; the working tree is still written and then restored, so a dirty tree is refused rather than discarded',\n ],\n [\n '',\n 'init',\n 'One-command onboarding: scaffold .github/workflows/bit-sync.yml + bit-release.yml (with this repository\\'s actual default branch substituted), add the `\"teambit.git/ci\": { \"sync\": {} }` config block to workspace.jsonc if absent, and print the remaining manual-steps checklist (secrets + bit.cloud webhook). Writes nothing else and never overwrites an existing workflow file. Cannot be combined with a lane argument or any other flag.',\n ],\n ];\n\n constructor(\n private workspace: Workspace,\n private logger: Logger,\n private ci: CiMain\n ) {}\n\n // `[lane]: [string]` rather than `[string?]`: `CLIArgs` does not admit an undefined-carrying tuple.\n // The argument is genuinely optional at runtime, hence the `|| undefined` below.\n async report([lane]: [string], options: Options) {\n if (!this.workspace) throw new OutsideWorkspaceError();\n // --init prints its own report; the banner only frames a reconcile run.\n if (!options.init) {\n this.logger.console('\\n\\n');\n this.logger.console('Initializing sync command');\n }\n\n return this.ci.sync({\n lane: lane || undefined,\n branch: options.branch,\n all: options.all,\n main: options.main,\n dryRun: options.dryRun,\n init: options.init,\n });\n }\n}\n"],"mappings":";;;;;;AAEA,SAAAA,WAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,UAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAA2E,SAAAE,gBAAAC,CAAA,EAAAC,CAAA,EAAAC,CAAA,YAAAD,CAAA,GAAAE,cAAA,CAAAF,CAAA,MAAAD,CAAA,GAAAI,MAAA,CAAAC,cAAA,CAAAL,CAAA,EAAAC,CAAA,IAAAK,KAAA,EAAAJ,CAAA,EAAAK,UAAA,MAAAC,YAAA,MAAAC,QAAA,UAAAT,CAAA,CAAAC,CAAA,IAAAC,CAAA,EAAAF,CAAA;AAAA,SAAAG,eAAAD,CAAA,QAAAQ,CAAA,GAAAC,YAAA,CAAAT,CAAA,uCAAAQ,CAAA,GAAAA,CAAA,GAAAA,CAAA;AAAA,SAAAC,aAAAT,CAAA,EAAAD,CAAA,2BAAAC,CAAA,KAAAA,CAAA,SAAAA,CAAA,MAAAF,CAAA,GAAAE,CAAA,CAAAU,MAAA,CAAAC,WAAA,kBAAAb,CAAA,QAAAU,CAAA,GAAAV,CAAA,CAAAc,IAAA,CAAAZ,CAAA,EAAAD,CAAA,uCAAAS,CAAA,SAAAA,CAAA,YAAAK,SAAA,yEAAAd,CAAA,GAAAe,MAAA,GAAAC,MAAA,EAAAf,CAAA;AAKpE,MAAMgB,SAAS,CAAoB;EA+CxCC,WAAWA,CACDC,SAAoB,EACpBC,MAAc,EACdC,EAAU,EAClB;IAAA,KAHQF,SAAoB,GAApBA,SAAoB;IAAA,KACpBC,MAAc,GAAdA,MAAc;IAAA,KACdC,EAAU,GAAVA,EAAU;IAAAvB,eAAA,eAjDb,aAAa;IAAAA,eAAA,oBACR,CACV;MACEwB,IAAI,EAAE,MAAM;MACZC,WAAW,EACT;IACJ,CAAC,CACF;IAAAzB,eAAA,sBACa,8EAA8E;IAAAA,eAAA,8BACtE,mhDAAmhD;IAAAA,eAAA,gBACjiD,aAAa;IAErB;AACF;AACA;AACA;AACA;AACA;IALEA,eAAA,kBAM0B,CACxB,CACE,EAAE,EACF,iBAAiB,EACjB,0GAA0G,CAC3G,EACD,CACE,EAAE,EACF,KAAK,EACL,oJAAoJ,CACrJ,EACD,CACE,EAAE,EACF,MAAM,EACN,iIAAiI,CAClI,EACD,CACE,EAAE,EACF,SAAS,EACT,0MAA0M,CAC3M,EACD,CACE,EAAE,EACF,MAAM,EACN,mbAAmb,CACpb,CACF;EAME;;EAEH;EACA;EACA,MAAM0B,MAAMA,CAAC,CAACC,IAAI,CAAW,EAAEC,OAAgB,EAAE;IAC/C,IAAI,CAAC,IAAI,CAACP,SAAS,EAAE,MAAM,KAAIQ,kCAAqB,EAAC,CAAC;IACtD;IACA,IAAI,CAACD,OAAO,CAACE,IAAI,EAAE;MACjB,IAAI,CAACR,MAAM,CAACS,OAAO,CAAC,MAAM,CAAC;MAC3B,IAAI,CAACT,MAAM,CAACS,OAAO,CAAC,2BAA2B,CAAC;IAClD;IAEA,OAAO,IAAI,CAACR,EAAE,CAACS,IAAI,CAAC;MAClBL,IAAI,EAAEA,IAAI,IAAIM,SAAS;MACvBC,MAAM,EAAEN,OAAO,CAACM,MAAM;MACtBC,GAAG,EAAEP,OAAO,CAACO,GAAG;MAChBC,IAAI,EAAER,OAAO,CAACQ,IAAI;MAClBC,MAAM,EAAET,OAAO,CAACS,MAAM;MACtBP,IAAI,EAAEF,OAAO,CAACE;IAChB,CAAC,CAAC;EACJ;AACF;AAACQ,OAAA,CAAAnB,SAAA,GAAAA,SAAA","ignoreList":[]}
@@ -1,5 +1,5 @@
1
1
  ;
2
- import * as overview_0 from '/home/circleci/Library/Caches/Bit/capsules/8891be5ad/teambit.git_ci@1.0.637/dist/ci.docs.mdx';
2
+ import * as overview_0 from '/home/circleci/Library/Caches/Bit/capsules/8891be5ad/teambit.git_ci@1.0.638/dist/ci.docs.mdx';
3
3
 
4
4
  export const compositions = [];
5
5
  export const overview = [overview_0];
@@ -3,26 +3,30 @@
3
3
  *
4
4
  * TEMPLATE SOURCE OF TRUTH: `BIT_SYNC_WORKFLOW_RAW` / `BIT_RELEASE_WORKFLOW_RAW` are byte-for-byte
5
5
  * copies of the canonical templates in the `bit-git-sync` action workspace
6
- * (git-sync/git-sync/workflows/templates/) and MUST be kept in sync with them. The ONLY departure is
7
- * the two `DEFAULT_BRANCH_MARKER` substitution points; everything else — CHANGE-ME comments, the
8
- * placeholder action ref, `bit-sync/main` config defaults — stays untouched.
6
+ * (git-sync/git-sync/workflows/templates/) and MUST be kept in sync with them. The ONLY departures
7
+ * are the two `DEFAULT_BRANCH_MARKER` substitution points and, for a workspace below the repository
8
+ * root, the `WS_DIR_MARKER` line; everything else — CHANGE-ME comments, the placeholder action ref,
9
+ * `bit-sync/main` config defaults — stays untouched.
9
10
  */
10
11
  /** Where `scaffoldWorkflowFiles` writes each file, relative to the workspace root. */
11
12
  export declare const WORKFLOW_RELATIVE_PATHS: {
12
13
  readonly sync: string;
13
14
  readonly release: string;
14
15
  };
15
- /** Render `bit-sync.yml` with the repository's actual default branch substituted. */
16
- export declare function renderBitSyncWorkflow(defaultBranch: string): string;
17
- /** Render `bit-release.yml` with the repository's actual default branch substituted. */
18
- export declare function renderBitReleaseWorkflow(defaultBranch: string): string;
16
+ /** Render `bit-sync.yml` with the repository's actual default branch, and `ws-dir` for a nested workspace. */
17
+ export declare function renderBitSyncWorkflow(defaultBranch: string, wsDir?: string): string;
18
+ /** Render `bit-release.yml` with the repository's actual default branch, and `ws-dir` for a nested workspace. */
19
+ export declare function renderBitReleaseWorkflow(defaultBranch: string, wsDir?: string): string;
19
20
  export interface ScaffoldFileOutcome {
20
21
  /** relative to the workspace root, e.g. `.github/workflows/bit-sync.yml` */
21
22
  relativePath: string;
22
23
  status: 'written' | 'skipped';
23
24
  }
24
- /** Scaffold both workflow files under `workspaceDir`. Never overwrites; creates `.github/workflows/` as needed. */
25
- export declare function scaffoldWorkflowFiles(workspaceDir: string, defaultBranch: string): ScaffoldFileOutcome[];
25
+ /**
26
+ * Scaffold both workflow files under `workspaceDir` (the repository root). `wsDir` is the bit workspace
27
+ * relative to it, when the workspace is a subdirectory. Never overwrites; creates `.github/workflows/`.
28
+ */
29
+ export declare function scaffoldWorkflowFiles(workspaceDir: string, defaultBranch: string, wsDir?: string): ScaffoldFileOutcome[];
26
30
  export interface OwnerRepo {
27
31
  owner: string;
28
32
  repo: string;
@@ -35,8 +39,81 @@ export interface OwnerRepo {
35
39
  * two never disagree.
36
40
  */
37
41
  export declare function deriveOwnerRepo(remoteUrl: string | undefined): OwnerRepo | undefined;
42
+ export interface InitReportInput {
43
+ /** the workspace's default scope, the one this repository mirrors */
44
+ scopeId?: string;
45
+ /** derived from the `origin` remote; undefined when there is none, or it isn't a recognized GitHub host */
46
+ ownerRepo?: OwnerRepo;
47
+ /** the raw `origin` URL, to name a remote that exists but isn't recognized as GitHub */
48
+ originUrl?: string;
49
+ defaultBranch: string;
50
+ /** true when the remote didn't name its default branch and `defaultBranch` is a guess */
51
+ defaultBranchGuessed?: boolean;
52
+ /**
53
+ * The repository root as seen from where the user stands (`.` when they stand in it). The workflows
54
+ * live there, so the first commit and `gh repo create --source` must name it.
55
+ */
56
+ repoRootFromCwd?: string;
57
+ /**
58
+ * false when the repository has no commit yet. The first commit then takes the whole workspace;
59
+ * after that, the commit takes only the files `--init` touched, never unrelated local changes.
60
+ */
61
+ repoHasCommits?: boolean;
62
+ /** false when the workspace is not in a git repository yet: step 1 then starts with `git init` */
63
+ inGitRepo?: boolean;
64
+ /** scaffolded workflow files, with the path to show (relative to where the user stands) */
65
+ files: Array<ScaffoldFileOutcome & {
66
+ displayPath: string;
67
+ }>;
68
+ /** workspace.jsonc, as seen from where the user stands */
69
+ configDisplayPath?: string;
70
+ /** whether `--init` added the sync block to workspace.jsonc, or found one already there */
71
+ configAdded: boolean;
72
+ /**
73
+ * Of the workflow files and workspace.jsonc, the ones git shows as new or changed, as displayed.
74
+ * Omitted: stage them all. Empty: nothing is left to commit (a re-run after the commit).
75
+ */
76
+ toStage?: string[];
77
+ /**
78
+ * Of those files, the untracked ones `.gitignore` matches, also before the first commit. `git add`
79
+ * refuses them by name and `git add -A` skips them.
80
+ */
81
+ ignored?: string[];
82
+ }
83
+ /**
84
+ * A remote that is a path on this machine (a bare repository, a `file://` URL), not a server. It has
85
+ * no host to suggest as a GitHub Enterprise Server. Git's own rule: a URL has a scheme, or is scp-like
86
+ * (`host:path`, with no slash before the first colon); anything else is a path, `remote.git` included.
87
+ */
88
+ export declare function isLocalPathRemote(remoteUrl: string): boolean;
89
+ /**
90
+ * The remote URL without the credentials a URL can carry (`https://user:token@host/...`), so the
91
+ * report never prints a token. An http(s) user name can itself be a token, so all of it goes; other
92
+ * schemes keep the user name (`ssh://git@host`) and lose only a password.
93
+ */
94
+ export declare function redactRemoteUrl(remoteUrl: string): string;
95
+ /** `value` with each control character written as `\xNN`, so printing it cannot move or restyle the terminal. */
96
+ export declare function escapeControlChars(value: string): string;
97
+ /**
98
+ * Quote a value for a POSIX shell, so a command the report prints runs as shown when pasted. Plain
99
+ * names stay unquoted for readability; anything else is single-quoted. A git-valid branch such as
100
+ * `$(id)` must not run as a command substitution.
101
+ */
102
+ export declare function shellQuote(value: string): string;
103
+ /**
104
+ * The default branch `--init` writes into the workflows: the one the remote names, else a guess. The
105
+ * guess is the checked-out branch only when it is `main` or `master`: a feature branch in the branch
106
+ * filters would exclude itself from sync and point releases at the wrong base.
107
+ */
108
+ export declare function chooseInitDefaultBranch(detected: string | undefined, current: string | undefined): string;
109
+ /**
110
+ * The `GITHUB_SERVER_URL` to suggest for a remote bit doesn't recognize: an http(s) remote's own origin,
111
+ * port included, else https on the remote's host (an ssh port is not the web server's).
112
+ */
113
+ export declare function suggestedServerUrl(remoteUrl: string): string;
38
114
  /**
39
- * The manual-steps checklist `bit ci sync --init` prints: everything the command itself cannot do
40
- * (secrets live in GitHub settings; the webhook lives on bit.cloud).
115
+ * The report `bit ci sync --init` prints: what it changed, then the steps that need a person, as
116
+ * commands to paste. Short by design; the setup guide carries the details. Commands are printed only
117
+ * for a resolved repository: a placeholder would not run when pasted.
41
118
  */
42
- export declare function renderInitChecklist(ownerRepo: OwnerRepo | undefined): string;
119
+ export declare function renderInitReport(input: InitReportInput): string;
@@ -4,11 +4,17 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.WORKFLOW_RELATIVE_PATHS = void 0;
7
+ exports.chooseInitDefaultBranch = chooseInitDefaultBranch;
7
8
  exports.deriveOwnerRepo = deriveOwnerRepo;
9
+ exports.escapeControlChars = escapeControlChars;
10
+ exports.isLocalPathRemote = isLocalPathRemote;
11
+ exports.redactRemoteUrl = redactRemoteUrl;
8
12
  exports.renderBitReleaseWorkflow = renderBitReleaseWorkflow;
9
13
  exports.renderBitSyncWorkflow = renderBitSyncWorkflow;
10
- exports.renderInitChecklist = renderInitChecklist;
14
+ exports.renderInitReport = renderInitReport;
11
15
  exports.scaffoldWorkflowFiles = scaffoldWorkflowFiles;
16
+ exports.shellQuote = shellQuote;
17
+ exports.suggestedServerUrl = suggestedServerUrl;
12
18
  function _fs() {
13
19
  const data = _interopRequireDefault(require("fs"));
14
20
  _fs = function () {
@@ -16,6 +22,20 @@ function _fs() {
16
22
  };
17
23
  return data;
18
24
  }
25
+ function _chalk() {
26
+ const data = _interopRequireDefault(require("chalk"));
27
+ _chalk = function () {
28
+ return data;
29
+ };
30
+ return data;
31
+ }
32
+ function _cli() {
33
+ const data = require("@teambit/cli");
34
+ _cli = function () {
35
+ return data;
36
+ };
37
+ return data;
38
+ }
19
39
  function _path() {
20
40
  const data = _interopRequireDefault(require("path"));
21
41
  _path = function () {
@@ -36,9 +56,10 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
36
56
  *
37
57
  * TEMPLATE SOURCE OF TRUTH: `BIT_SYNC_WORKFLOW_RAW` / `BIT_RELEASE_WORKFLOW_RAW` are byte-for-byte
38
58
  * copies of the canonical templates in the `bit-git-sync` action workspace
39
- * (git-sync/git-sync/workflows/templates/) and MUST be kept in sync with them. The ONLY departure is
40
- * the two `DEFAULT_BRANCH_MARKER` substitution points; everything else — CHANGE-ME comments, the
41
- * placeholder action ref, `bit-sync/main` config defaults — stays untouched.
59
+ * (git-sync/git-sync/workflows/templates/) and MUST be kept in sync with them. The ONLY departures
60
+ * are the two `DEFAULT_BRANCH_MARKER` substitution points and, for a workspace below the repository
61
+ * root, the `WS_DIR_MARKER` line; everything else — CHANGE-ME comments, the placeholder action ref,
62
+ * `bit-sync/main` config defaults — stays untouched.
42
63
  */
43
64
 
44
65
  /** Where `scaffoldWorkflowFiles` writes each file, relative to the workspace root. */
@@ -258,14 +279,29 @@ function substituteDefaultBranch(raw, marker, defaultBranch) {
258
279
  return raw.replace(marker, () => substitutedMarker);
259
280
  }
260
281
 
261
- /** Render `bit-sync.yml` with the repository's actual default branch substituted. */
262
- function renderBitSyncWorkflow(defaultBranch) {
263
- return substituteDefaultBranch(BIT_SYNC_WORKFLOW_RAW, DEFAULT_BRANCH_MARKER.sync, defaultBranch);
282
+ /** The commented-out `ws-dir` input, once in each template. */
283
+ const WS_DIR_MARKER = '# ws-dir: packages/my-workspace';
284
+
285
+ /**
286
+ * Set the action's `ws-dir` input when the workspace is below the repository root (`wsDir` is the
287
+ * workspace directory relative to the root, `/`-separated). At the root, the line stays commented out.
288
+ */
289
+ function substituteWsDir(raw, wsDir) {
290
+ if (!wsDir || wsDir === '.') return raw;
291
+ if (!raw.includes(WS_DIR_MARKER)) {
292
+ throw new Error(`init-scaffold: expected marker "${WS_DIR_MARKER}" not found in its workflow template`);
293
+ }
294
+ return raw.replace(WS_DIR_MARKER, () => `ws-dir: ${yamlSingleQuoted(wsDir)}`);
264
295
  }
265
296
 
266
- /** Render `bit-release.yml` with the repository's actual default branch substituted. */
267
- function renderBitReleaseWorkflow(defaultBranch) {
268
- return substituteDefaultBranch(BIT_RELEASE_WORKFLOW_RAW, DEFAULT_BRANCH_MARKER.release, defaultBranch);
297
+ /** Render `bit-sync.yml` with the repository's actual default branch, and `ws-dir` for a nested workspace. */
298
+ function renderBitSyncWorkflow(defaultBranch, wsDir) {
299
+ return substituteWsDir(substituteDefaultBranch(BIT_SYNC_WORKFLOW_RAW, DEFAULT_BRANCH_MARKER.sync, defaultBranch), wsDir);
300
+ }
301
+
302
+ /** Render `bit-release.yml` with the repository's actual default branch, and `ws-dir` for a nested workspace. */
303
+ function renderBitReleaseWorkflow(defaultBranch, wsDir) {
304
+ return substituteWsDir(substituteDefaultBranch(BIT_RELEASE_WORKFLOW_RAW, DEFAULT_BRANCH_MARKER.release, defaultBranch), wsDir);
269
305
  }
270
306
  // Never overwrites an existing file — `--init` must be safe to re-run after hand-edits.
271
307
  function writeIfAbsent(workspaceDir, relativePath, content) {
@@ -286,9 +322,12 @@ function writeIfAbsent(workspaceDir, relativePath, content) {
286
322
  };
287
323
  }
288
324
 
289
- /** Scaffold both workflow files under `workspaceDir`. Never overwrites; creates `.github/workflows/` as needed. */
290
- function scaffoldWorkflowFiles(workspaceDir, defaultBranch) {
291
- return [writeIfAbsent(workspaceDir, WORKFLOW_RELATIVE_PATHS.sync, renderBitSyncWorkflow(defaultBranch)), writeIfAbsent(workspaceDir, WORKFLOW_RELATIVE_PATHS.release, renderBitReleaseWorkflow(defaultBranch))];
325
+ /**
326
+ * Scaffold both workflow files under `workspaceDir` (the repository root). `wsDir` is the bit workspace
327
+ * relative to it, when the workspace is a subdirectory. Never overwrites; creates `.github/workflows/`.
328
+ */
329
+ function scaffoldWorkflowFiles(workspaceDir, defaultBranch, wsDir) {
330
+ return [writeIfAbsent(workspaceDir, WORKFLOW_RELATIVE_PATHS.sync, renderBitSyncWorkflow(defaultBranch, wsDir)), writeIfAbsent(workspaceDir, WORKFLOW_RELATIVE_PATHS.release, renderBitReleaseWorkflow(defaultBranch, wsDir))];
292
331
  }
293
332
  /**
294
333
  * Derive `{owner, repo}` from the `origin` remote when it is a parseable GitHub remote, else
@@ -311,19 +350,167 @@ function deriveOwnerRepo(remoteUrl) {
311
350
 
312
351
  /**
313
352
  * The bit.cloud custom webhook payload template, verified byte-perfect against a live delivery.
314
- * Lane vs. main export is discriminated by whether `laneId` is empty.
353
+ * Lane vs. main export is discriminated by whether `laneId` is empty. Used on GitHub Enterprise
354
+ * Server, where the webhook posts straight to the repository's `dispatches` API with a token.
315
355
  */
316
356
  const WEBHOOK_PAYLOAD_TEMPLATE = '{"event_type":"bit-export","client_payload":{"laneId":"{{laneId}}","componentIds":"{{componentIds}}","owner":"{{owner}}","actor":"{{username}}"}}';
317
357
 
318
358
  /**
319
- * The manual-steps checklist `bit ci sync --init` prints: everything the command itself cannot do
320
- * (secrets live in GitHub settings; the webhook lives on bit.cloud).
359
+ * On github.com, instant Bit -> Git goes through the hosted relay: the `bit-git-sync` GitHub App lets
360
+ * it send `repository_dispatch` to the repositories it is installed on, and its setup page hands out
361
+ * one webhook URL per repository. No personal token is involved.
362
+ */
363
+ const BIT_GIT_SYNC_APP_URL = 'https://github.com/apps/bit-git-sync';
364
+ const WEBHOOK_RELAY_SETUP_URL = 'https://webhook-relay-gggmal.r2.composed.app/setup';
365
+ const SETUP_GUIDE_URL = 'https://github.com/teambit/acme-modular-store#set-it-up-for-your-own-scope';
366
+
367
+ /** What each scaffolded file does, in the words the report shows next to it. */
368
+ const FILE_PURPOSE = {
369
+ [WORKFLOW_RELATIVE_PATHS.sync]: 'syncs lanes and branches: on export, on push, and every 30 minutes',
370
+ [WORKFLOW_RELATIVE_PATHS.release]: 'releases the scope when a pull request merges'
371
+ };
372
+ /**
373
+ * A remote that is a path on this machine (a bare repository, a `file://` URL), not a server. It has
374
+ * no host to suggest as a GitHub Enterprise Server. Git's own rule: a URL has a scheme, or is scp-like
375
+ * (`host:path`, with no slash before the first colon); anything else is a path, `remote.git` included.
376
+ */
377
+ function isLocalPathRemote(remoteUrl) {
378
+ const url = remoteUrl.trim();
379
+ if (/^file:\/\//i.test(url)) return true;
380
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(url)) return false;
381
+ // a Windows drive (`C:\repos`) looks scp-like to the next check
382
+ if (/^[a-z]:[/\\]/i.test(url)) return true;
383
+ return !/^[^/\\]+:/.test(url);
384
+ }
385
+
386
+ /**
387
+ * The remote URL without the credentials a URL can carry (`https://user:token@host/...`), so the
388
+ * report never prints a token. An http(s) user name can itself be a token, so all of it goes; other
389
+ * schemes keep the user name (`ssh://git@host`) and lose only a password.
390
+ */
391
+ function redactRemoteUrl(remoteUrl) {
392
+ const url = remoteUrl.trim();
393
+ if (/^https?:\/\//i.test(url)) return url.replace(/^(https?:\/\/)[^@/]*@/i, '$1');
394
+ return url.replace(/^([a-z][a-z0-9+.-]*:\/\/[^:@/]*):[^@/]*@/i, '$1@');
395
+ }
396
+
397
+ /** `value` with each control character written as `\xNN`, so printing it cannot move or restyle the terminal. */
398
+ function escapeControlChars(value) {
399
+ // eslint-disable-next-line no-control-regex
400
+ return value.replace(/[\u0000-\u001f\u007f-\u009f]/g, c => `\\x${c.charCodeAt(0).toString(16).padStart(2, '0')}`);
401
+ }
402
+
403
+ /**
404
+ * Quote a value for a POSIX shell, so a command the report prints runs as shown when pasted. Plain
405
+ * names stay unquoted for readability; anything else is single-quoted. A git-valid branch such as
406
+ * `$(id)` must not run as a command substitution.
407
+ */
408
+ function shellQuote(value) {
409
+ return /^[\w./@:+-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
410
+ }
411
+
412
+ /**
413
+ * The default branch `--init` writes into the workflows: the one the remote names, else a guess. The
414
+ * guess is the checked-out branch only when it is `main` or `master`: a feature branch in the branch
415
+ * filters would exclude itself from sync and point releases at the wrong base.
321
416
  */
322
- function renderInitChecklist(ownerRepo) {
323
- const repoSegment = ownerRepo ? `${ownerRepo.owner}/${ownerRepo.repo}` : '<owner>/<repo>';
324
- const api = (0, _githubClient().gitHubApiUrl)(ownerRepo?.host);
325
- const dispatchUrl = `${'error' in api ? '<GitHub API URL>' : api.url}/repos/${repoSegment}/dispatches`;
326
- return ['', 'Remaining manual steps (bit ci sync --init only scaffolds files -- these need a human):', '', '1. Secrets -- add in the repository (or org) Settings > Secrets and variables > Actions:', ' - BIT_CONFIG_ACCESS_TOKEN (required): a bit.cloud service-account token with export rights on', " this scope. This account must also be exempt from the org's", ' change-request/merge block -- it is the only identity that merges lanes.', ' - BIT_SYNC_GH_TOKEN (optional): a GitHub PAT or App token. Without it, sync pushes/PRs use the', ' default GITHUB_TOKEN, which does NOT trigger downstream workflow runs (loop-safe, but the', ' sync PR then gets no CI checks).', '', '2. Permissions -- both scaffolded workflows already declare `contents: write` and', ' `pull-requests: write`. Nothing to change unless an org-wide policy overrides workflow-level', ' permissions (e.g. a default of "Read repository contents permission" for the GITHUB_TOKEN).', '', '3. bit.cloud webhook -- create ONE webhook (org Settings > Webhooks) on the "Components > Export', ' succeeded" event:', ` URL: ${dispatchUrl}`, ...('error' in api ? [` (${api.error})`] : []), ' Headers: Authorization: Bearer <PAT>', ' Accept: application/vnd.github+json', ' Custom payload template:', ` ${WEBHOOK_PAYLOAD_TEMPLATE}`, ' WARNING: create this webhook fresh -- editing an existing webhook drops its custom headers', ' (known bit.cloud platform bug, verified 2026-07-29). If the URL, headers or template need to', ' change later, delete the webhook and create a new one rather than editing it.', '', '4. Checkout depth -- both scaffolded workflows already check out with `fetch-depth: 0`. This is', ' required: the reconciler reads full git history, and a shallow (--depth=1) clone fails sync', ' safely but uselessly (HALTED, no writes). Keep `fetch-depth: 0` if you customize the workflow.', ' Narrowing the REFSPEC is fine, though -- a single-branch clone is supported, because every', ' fetch sync performs names +refs/heads/*:refs/remotes/origin/* explicitly.', ''].join('\n');
417
+ function chooseInitDefaultBranch(detected, current) {
418
+ if (detected) return detected;
419
+ return current === 'main' || current === 'master' ? current : 'main';
420
+ }
421
+
422
+ /**
423
+ * The `GITHUB_SERVER_URL` to suggest for a remote bit doesn't recognize: an http(s) remote's own origin,
424
+ * port included, else https on the remote's host (an ssh port is not the web server's).
425
+ */
426
+ function suggestedServerUrl(remoteUrl) {
427
+ if (/^https?:\/\//i.test(remoteUrl.trim())) {
428
+ try {
429
+ return new URL(remoteUrl.trim()).origin;
430
+ } catch {
431
+ // fall through to the host
432
+ }
433
+ }
434
+ return `https://${(0, _githubClient().remoteHost)(remoteUrl) ?? '<your-server>'}`;
435
+ }
436
+
437
+ /**
438
+ * The report `bit ci sync --init` prints: what it changed, then the steps that need a person, as
439
+ * commands to paste. Short by design; the setup guide carries the details. Commands are printed only
440
+ * for a resolved repository: a placeholder would not run when pasted.
441
+ */
442
+ function renderInitReport(input) {
443
+ const {
444
+ ownerRepo,
445
+ defaultBranch
446
+ } = input;
447
+ const scope = input.scopeId ?? '<scope>';
448
+ // An origin that isn't recognized is most often a GitHub Enterprise Server the shell doesn't know about.
449
+ const redactedOrigin = !ownerRepo && input.originUrl ? redactRemoteUrl(input.originUrl) : undefined;
450
+ // Shown, so made inert: a control character (a newline, a terminal escape) must not reach the terminal.
451
+ const unrecognizedOrigin = redactedOrigin && escapeControlChars(redactedOrigin);
452
+ // Suggest a server only for a remote that names a host: a local path has none, and a URL with a
453
+ // control character in it has no trustworthy one.
454
+ const serverHost = redactedOrigin && redactedOrigin === unrecognizedOrigin && !isLocalPathRemote(redactedOrigin) ? (0, _githubClient().remoteHost)(redactedOrigin) : undefined;
455
+ const repoRootFromCwd = input.repoRootFromCwd || '.';
456
+ const configDisplayPath = input.configDisplayPath || 'workspace.jsonc';
457
+ const target = ownerRepo ? _chalk().default.cyan(ownerRepo.host === 'github.com' ? `${ownerRepo.owner}/${ownerRepo.repo}` : `${ownerRepo.host}/${ownerRepo.owner}/${ownerRepo.repo}`) : unrecognizedOrigin ? `origin ${unrecognizedOrigin}` : 'no GitHub remote yet';
458
+ const header = [`${(0, _cli().successSymbol)()} ${(0, _cli().formatTitle)('Scaffolded bit ci sync')} for ${_chalk().default.cyan(scope)}, mirrored to ${target} ${(0, _cli().formatHint)(`(default branch: ${defaultBranch})`)}`];
459
+ if (input.defaultBranchGuessed) {
460
+ const why = input.originUrl ? "the remote didn't name its default branch" : 'no remote names the default branch';
461
+ header.push((0, _cli().formatWarningSummary)(`${why}, so the workflows use "${defaultBranch}". If that's wrong,\n` + ` edit the branch filters in both workflow files.`));
462
+ }
463
+ if (serverHost && unrecognizedOrigin) {
464
+ header.push((0, _cli().formatWarningSummary)("origin isn't a GitHub remote bit recognizes. For GitHub Enterprise Server, run:"));
465
+ header.push(` ${_chalk().default.cyan(`GITHUB_SERVER_URL=${shellQuote(suggestedServerUrl(unrecognizedOrigin))} bit ci sync --init`)}`);
466
+ }
467
+ const width = Math.max(...input.files.map(f => f.displayPath.length), configDisplayPath.length) + 2;
468
+ const fileItem = (displayPath, note) => (0, _cli().formatItem)(`${displayPath.padEnd(width)}${(0, _cli().formatHint)(note)}`);
469
+ const files = [...input.files.map(file => fileItem(file.displayPath, file.status === 'written' ? FILE_PURPOSE[file.relativePath] ?? '' : 'already exists, left unchanged')), fileItem(configDisplayPath, input.configAdded ? 'added "teambit.git/ci": { "sync": {} }' : 'already configures sync, left unchanged')];
470
+ const step = (n, title, who, body) => [`${(0, _cli().formatTitle)(`${n}. ${title}`)} ${(0, _cli().formatHint)(`(${who})`)}`, ...body.map(line => ` ${line}`)].join('\n');
471
+ const cmd = text => _chalk().default.cyan(text);
472
+ // Stage and commit exactly what git shows as new or changed among the files `--init` handles, so
473
+ // unrelated local changes stay out: a re-run still stages files that were never committed, and a
474
+ // file already committed is not named. The first commit of a new repository is the exception: it
475
+ // must carry the whole workspace. `:/` stages from the repository root, where the workflows are,
476
+ // when the workspace is a subdirectory.
477
+ const firstCommit = input.repoHasCommits === false;
478
+ const toStage = firstCommit ? [] : input.toStage ?? [...input.files.map(f => f.displayPath), configDisplayPath];
479
+ const ignored = input.ignored ?? [];
480
+ const quoted = paths => paths.map(shellQuote).join(' ');
481
+ const stage = [...(firstCommit ? [cmd(repoRootFromCwd === '.' ? 'git add -A' : 'git add -A :/')] : []), ...(toStage.length ? [cmd(`git add -- ${quoted(toStage)}`)] : []),
482
+ // `git add` skips or refuses a path that .gitignore matches, and GitHub runs only committed workflows
483
+ ...(ignored.length ? [cmd(`git add -f -- ${quoted(ignored)}`), (0, _cli().formatHint)('.gitignore matches these; -f adds them anyway')] : [])];
484
+ // Commit and push are separate: on a re-run nothing may be left to commit, and the push must still run.
485
+ // Naming the paths keeps changes the user staged before out of the commit.
486
+ // `-b`: without init.defaultBranch, a bare `git init` makes `master`, a branch the workflows ignore
487
+ const gitInit = `git init -b ${shellQuote(defaultBranch)}${repoRootFromCwd === '.' ? '' : ` ${shellQuote(repoRootFromCwd)}`}`;
488
+ const toCommit = [...toStage, ...ignored];
489
+ const nothingToCommit = !firstCommit && !toCommit.length;
490
+ const commitMessage = `git commit -m ${shellQuote(`Mirror ${scope}`)}`;
491
+ const commit = [...(input.inGitRepo === false ? [cmd(gitInit)] : []), ...stage, ...(nothingToCommit ? [(0, _cli().formatHint)('nothing to commit: these files are already committed')] : firstCommit ? [cmd(commitMessage)] :
492
+ // the paths go on a continuation line, as in the permissions command, to keep lines short
493
+ [cmd(`${commitMessage} -- \\`), cmd(` ${quoted(toCommit)}`)])];
494
+ const steps = [];
495
+ if (!ownerRepo) {
496
+ steps.push(unrecognizedOrigin ? step(1, 'Push it', 'you', [...commit, cmd('git push -u origin HEAD')]) : step(1, 'Create the repository and push it', 'you', [...commit, cmd(`gh repo create --private --source ${shellQuote(repoRootFromCwd)} --remote origin --push`), (0, _cli().formatHint)('names the repository after its root folder; add OWNER/NAME after "create" to choose')]), step(2, 'Run bit ci sync --init again', 'you', ['Once origin is a GitHub remote bit recognizes, it prints the secret, permission and webhook', 'steps for your repository as commands.']));
497
+ } else {
498
+ const onGitHubCom = ownerRepo.host === 'github.com';
499
+ const repo = `${ownerRepo.owner}/${ownerRepo.repo}`;
500
+ // gh takes HOST/OWNER/REPO, or --hostname, for an enterprise server
501
+ const ghRepo = shellQuote(onGitHubCom ? repo : `${ownerRepo.host}/${repo}`);
502
+ const ghApi = onGitHubCom ? 'gh api' : `gh api --hostname ${shellQuote(ownerRepo.host)}`;
503
+ steps.push(step(1, 'Push it', 'you', [...commit, cmd('git push -u origin HEAD')]), step(2, 'Let the workflows publish to bit.cloud and open pull requests', 'repository admin', [cmd(`gh secret set BIT_CONFIG_ACCESS_TOKEN -R ${ghRepo}`), (0, _cli().formatHint)(`a bit.cloud access token with Write permission on ${scope}. If your organization`), (0, _cli().formatHint)("requires change requests, exempt the token's account: it is the one that merges lanes."), cmd(`${ghApi} -X PUT ${shellQuote(`repos/${repo}/actions/permissions/workflow`)} \\`), cmd(' -f default_workflow_permissions=write -F can_approve_pull_request_reviews=true'), (0, _cli().formatHint)('turns on "Read and write permissions" and "Allow GitHub Actions to create and approve pull requests".'), (0, _cli().formatHint)('If they are greyed out in the settings, an organization owner must allow them first.'), cmd(`gh secret set BIT_SYNC_GH_TOKEN -R ${ghRepo}`), (0, _cli().formatHint)('optional: a GitHub token, so the pushes the sync makes start your other workflows (CI checks)')]));
504
+ if (onGitHubCom) {
505
+ steps.push(step(3, 'Make Bit -> Git instant', 'organization admin, optional', [`Install ${_chalk().default.cyan(BIT_GIT_SYNC_APP_URL)} on ${repo}.`, `Copy the repository's webhook URL from ${_chalk().default.cyan(WEBHOOK_RELAY_SETUP_URL)}`, `and add it to ${scope} on bit.cloud as an "Export succeeded" webhook.`]));
506
+ } else {
507
+ const api = (0, _githubClient().gitHubApiUrl)(ownerRepo.host);
508
+ const dispatchUrl = `${'error' in api ? '<GitHub API URL>' : api.url}/repos/${repo}/dispatches`;
509
+ steps.push(step(3, 'Make Bit -> Git instant', 'optional', [`On bit.cloud, add an "Export succeeded" webhook to ${scope}:`, ` URL ${_chalk().default.cyan(dispatchUrl)}`, ...('error' in api ? [_chalk().default.yellow(` (${api.error})`)] : []), ' Headers Authorization: Bearer <token with access to this repository>', ' Accept: application/vnd.github+json', ` Payload ${WEBHOOK_PAYLOAD_TEMPLATE}`, (0, _cli().formatHint)('Create it fresh: editing a bit.cloud webhook drops its custom headers.')]));
510
+ }
511
+ }
512
+ const footer = ownerRepo ? `After step 2 the sync runs on pushes to feature branches and every 30 minutes; step 3 adds instant Bit -> Git.\nGuide: ${SETUP_GUIDE_URL}` : `Guide: ${SETUP_GUIDE_URL}`;
513
+ return (0, _cli().joinSections)([header.join('\n'), files.join('\n'), [(0, _cli().formatTitle)(`Next: ${steps.length} steps to go live`), '', steps.join('\n\n')].join('\n'), (0, _cli().formatHint)(footer)]);
327
514
  }
328
515
 
329
516
  //# sourceMappingURL=init-scaffold.js.map