hub-launch 1.26.0 → 1.28.0

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +1 -1
  3. package/dist/commands/init.d.ts +6 -6
  4. package/dist/commands/init.d.ts.map +1 -1
  5. package/dist/commands/init.js +171 -16
  6. package/dist/commands/init.js.map +1 -1
  7. package/dist/commands/launch.d.ts +6 -0
  8. package/dist/commands/launch.d.ts.map +1 -1
  9. package/dist/commands/launch.js +47 -54
  10. package/dist/commands/launch.js.map +1 -1
  11. package/dist/commands/upload.d.ts +10 -0
  12. package/dist/commands/upload.d.ts.map +1 -1
  13. package/dist/commands/upload.js +58 -2
  14. package/dist/commands/upload.js.map +1 -1
  15. package/dist/services/git/FilePublishService.d.ts +7 -0
  16. package/dist/services/git/FilePublishService.d.ts.map +1 -1
  17. package/dist/services/git/FilePublishService.js +10 -4
  18. package/dist/services/git/FilePublishService.js.map +1 -1
  19. package/dist/services/plan/PlanBranchService.d.ts +38 -0
  20. package/dist/services/plan/PlanBranchService.d.ts.map +1 -0
  21. package/dist/services/plan/PlanBranchService.js +95 -0
  22. package/dist/services/plan/PlanBranchService.js.map +1 -0
  23. package/dist/templates/proceed-instructions.md +3 -2
  24. package/dist/templates/skills/hula-help/SKILL.md +1 -1
  25. package/dist/templates/skills/hula-launch/SKILL.md +2 -2
  26. package/dist/templates/skills/hula-plan/SKILL.md +18 -2
  27. package/dist/templates/skills/hula-upload/SKILL.md +2 -2
  28. package/dist/utils/validators.d.ts +8 -0
  29. package/dist/utils/validators.d.ts.map +1 -1
  30. package/dist/utils/validators.js +10 -0
  31. package/dist/utils/validators.js.map +1 -1
  32. package/package.json +9 -1
@@ -0,0 +1,95 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { isAbsolute, join } from 'path';
3
+ import { sanitizePlanName } from '../../utils/validators.js';
4
+ import { GitService } from '../git/GitService.js';
5
+ import { FilePublishService } from '../git/FilePublishService.js';
6
+ import { PlanService } from './PlanService.js';
7
+ /**
8
+ * Thrown when the plan file cannot be found anywhere — not on disk, not on
9
+ * the feature branch, not on the base branch. Callers translate this into the
10
+ * historical "Plan not found locally or on origin/main" error handling.
11
+ */
12
+ export class PlanNotFoundError extends Error {
13
+ constructor(planPath) {
14
+ super(`Plan not found locally or on any git ref: ${planPath}`);
15
+ this.name = 'PlanNotFoundError';
16
+ }
17
+ }
18
+ /**
19
+ * Resolve the plan's content, preferring the freshest source:
20
+ * 1. the working tree (where /hula-plan writes and validation edits it)
21
+ * 2. the feature branch on origin (plan-branch flow, plan already pushed)
22
+ * 3. the base branch on origin, then local base (legacy plans, relaunches)
23
+ *
24
+ * Returns `null` when the plan exists nowhere.
25
+ */
26
+ async function resolvePlanContent(gitService, relativePath, planFsPath, branch, branchOnOrigin, baseBranch) {
27
+ if (existsSync(planFsPath)) {
28
+ return readFileSync(planFsPath, 'utf-8');
29
+ }
30
+ if (branchOnOrigin &&
31
+ (await gitService.fileExistsOnRef(`origin/${branch}`, relativePath))) {
32
+ return gitService.showFile(`origin/${branch}`, relativePath);
33
+ }
34
+ for (const ref of [`origin/${baseBranch}`, baseBranch]) {
35
+ if (await gitService.fileExistsOnRef(ref, relativePath)) {
36
+ return gitService.showFile(ref, relativePath);
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ /**
42
+ * Ensure the feature branch for `issueName` exists on origin and carries the
43
+ * current plan file — the core of the plan-branch flow.
44
+ *
45
+ * - Branch missing on origin → create it from `origin/<uploadBranch ?? main>`
46
+ * with the plan committed (one worktree publish, one push).
47
+ * - Branch exists but the plan file on it is missing or stale → publish the
48
+ * fresh content to the branch.
49
+ * - Branch exists with identical content → no-op.
50
+ *
51
+ * This runs BEFORE the beforeLaunch hook in `hula launch`, so hooks (e.g.
52
+ * Vercel branch-scoped env vars) can rely on the git branch existing on the
53
+ * remote. It is also invoked at plan time via `hula upload --branch`.
54
+ *
55
+ * @throws PlanNotFoundError when the plan content cannot be resolved anywhere.
56
+ */
57
+ export async function ensurePlanBranch(config, planPath, issueName, repoRoot) {
58
+ const branch = sanitizePlanName(issueName);
59
+ const baseBranch = config.uploadBranch ?? 'main';
60
+ const gitService = new GitService(repoRoot);
61
+ const planService = new PlanService(config.planPath);
62
+ const relativePath = planService.getRelativePath(planPath);
63
+ const planFsPath = isAbsolute(planPath) || !repoRoot ? planPath : join(repoRoot, planPath);
64
+ // One fetch up front so every origin/<ref> read below is current.
65
+ await gitService.fetch('origin');
66
+ const branchOnOrigin = await gitService.remoteBranchExists(branch);
67
+ const content = await resolvePlanContent(gitService, relativePath, planFsPath, branch, branchOnOrigin, baseBranch);
68
+ if (content === null) {
69
+ throw new PlanNotFoundError(planPath);
70
+ }
71
+ if (branchOnOrigin) {
72
+ // Skip the publish when the branch already holds this exact content.
73
+ // `git show` output matches committed bytes, so string equality is exact.
74
+ if (await gitService.fileExistsOnRef(`origin/${branch}`, relativePath)) {
75
+ const onBranch = await gitService.showFile(`origin/${branch}`, relativePath);
76
+ if (onBranch === content) {
77
+ return { branch, created: false, updated: false };
78
+ }
79
+ }
80
+ const publisher = new FilePublishService(config, repoRoot);
81
+ await publisher.publishFile(relativePath, content, {
82
+ commitMessage: 'chore: update plan via hula',
83
+ branch,
84
+ });
85
+ return { branch, created: false, updated: true };
86
+ }
87
+ const publisher = new FilePublishService(config, repoRoot);
88
+ await publisher.publishFile(relativePath, content, {
89
+ commitMessage: 'chore: create plan branch via hula',
90
+ branch,
91
+ createFromRef: `origin/${baseBranch}`,
92
+ });
93
+ return { branch, created: true, updated: true };
94
+ }
95
+ //# sourceMappingURL=PlanBranchService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlanBranchService.js","sourceRoot":"","sources":["../../../src/services/plan/PlanBranchService.ts"],"names":[],"mappings":"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"}
@@ -378,8 +378,9 @@ After the Completion Format block is printed, offer to launch the plan for the u
378
378
 
379
379
  Determine `<issueName>` before asking the question:
380
380
 
381
- 1. **Look for a name the user specified** anywhere in this conversatione.g. "use the branch name `foo`", "call the issue `bar`", or a name passed in the original `/hula-plan` arguments. If more than one was mentioned, **the most recent wins**. Use that name verbatim (kebab-case it if needed).
382
- 2. **Otherwise derive the default from the plan file's basename** (the subfolder is never part of the name):
381
+ 1. **Look for a plan-branch created earlier in this session**a `<!-- hula-branch: <name> -->` comment in the chat history (emitted by `/hula-plan` when it created the feature branch at plan time). If present, that name is the default: the branch already exists on origin with the plan on it.
382
+ 2. **Look for a name the user specified** anywhere in this conversation — e.g. "use the branch name `foo`", "call the issue `bar`", or a name passed in the original `/hula-plan` arguments. If more than one was mentioned, **the most recent wins**, and a user-specified name overrides the plan-branch default. Use that name verbatim (kebab-case it if needed). (Launching under a different name than the plan branch is fine `hula launch` creates the new branch automatically; the unused plan branch can be deleted later.)
383
+ 3. **Otherwise derive the default from the plan file's basename** (the subfolder is never part of the name):
383
384
  - Strip the leading timestamp prefix matching `YYYY-MM-DD-HH:MM-` and the trailing `.md`.
384
385
  - The remaining text is the title slug (e.g. `auto-launch-offer-after-plan`).
385
386
  - If the slug is **longer than 3 words**, shorten it to the 2–3 most distinctive words (e.g. `auto-launch-offer-after-plan` → `auto-launch`). Otherwise keep it as-is.
@@ -86,7 +86,7 @@ Read `README.md`'s "Quick Start" and "Requirements" sections (and the "Core Work
86
86
  Read the "Core Workflow" section of `README.md` live. Explain each step in plain language — one at a time if the user wants depth, or as a compact list if they want the overview:
87
87
 
88
88
  - `/hula-plan <description>` — writes a plan file to `.hublaunch/plans/`, validates it automatically.
89
- - `/hula-upload` — syncs the plan to `origin/main` (usually automatic as part of `/hula-launch`, rarely needed standalone).
89
+ - `/hula-upload` — publishes the plan to its feature branch (`hula upload --branch <name>`) or to `origin/main` (usually automatic as part of `/hula-plan` and `/hula-launch`, rarely needed standalone).
90
90
  - `/hula-launch <name>` — creates the GitHub issue, runs the AI coding session in an isolated cloud container, opens a PR.
91
91
  - `/hula-verify` — checks the PR against the plan's acceptance criteria.
92
92
  - `/hula-fix <instructions>` — addresses gaps found by verify, or anything else you want changed on the PR branch.
@@ -153,6 +153,6 @@ The `cliOutput` already contains the per-repo roster, ✓/✗ summary, and any r
153
153
 
154
154
  ## Important Notes
155
155
 
156
- - Do NOT call the `Read` tool to check if the plan file exists. The `hula launch` CLI validates file existence (locally and on `origin/main`) and reports errors clearly.
157
- - Do NOT run `hula upload` separately. `hula launch` handles upload automatically.
156
+ - Do NOT call the `Read` tool to check if the plan file exists. The `hula launch` CLI validates file existence (locally, on the plan's feature branch, and on `origin/main`) and reports errors clearly.
157
+ - Do NOT run `hula upload` separately. `hula launch` publishes the plan to its feature branch automatically (creating the branch from the base branch if `/hula-plan` didn't already, and refreshing it after validation edits or a rename).
158
158
  - This command is typically run after `/hula-plan` and `/hula-confirm`.
@@ -122,17 +122,33 @@ The plan should be immediately actionable by a developer familiar with the codeb
122
122
 
123
123
  **⚠️ NEVER create plan files in the project root directory.** The plan file MUST always be inside the `.hublaunch/plans/` directory (or a subfolder of it). If you cannot read the config file, use the default path `.hublaunch/plans/`.
124
124
 
125
- ### Step 2: Output the Plan Path and Next Steps
125
+ ### Step 2: Create the Plan Branch
126
+
127
+ Right after saving the plan file, create the feature branch on origin with the plan committed to it. This is the **plan-branch flow**: the git branch exists from plan time onward, so branch-scoped infrastructure (Vercel Preview env vars, per-branch databases, beforeLaunch hooks) can rely on it well before the launch.
128
+
129
+ 1. **Resolve `<issueName>`** using the same rules as the Launch Offer's "Resolve the issue name" step in `hula instructions proceed`: a name the user specified anywhere in this conversation wins (most recent first); otherwise derive the default from the plan file's basename (strip the `YYYY-MM-DD-HH:MM-` prefix and `.md`, shorten a >3-word slug to its 2–3 most distinctive words, always kebab-case).
130
+ 2. **Create the branch** by running:
131
+
132
+ `hula upload <planPath> --branch <issueName>`
133
+
134
+ This creates branch `<issueName>` (sanitized) on origin from the base branch with the plan file committed, or refreshes the plan on the branch if it already exists.
135
+ 3. If the command fails (e.g. no network, no push permission), print a warning and continue — `hula launch` re-runs the same step as a safety net at launch time, so a plan-time failure is not fatal.
136
+
137
+ ### Step 3: Output the Plan Path and Next Steps
126
138
 
127
139
  **Output Format:**
128
140
 
129
141
  ```
130
142
  ✅ Plan created: `.hublaunch/plans/2025-12-29-14:30-feature-name.md`
143
+ 🌿 Branch created: `feature-name` (plan pushed to origin)
131
144
  <!-- hula-plan: .hublaunch/plans/2025-12-29-14:30-feature-name.md -->
145
+ <!-- hula-branch: feature-name -->
132
146
 
133
147
  📋 **Proceeding to validation now…**
134
148
  ```
135
149
 
150
+ (Substitute the actual resolved `<issueName>` in the branch line and the `hula-branch` comment. If branch creation failed in Step 2, replace the 🌿 line with `⚠️ Branch creation deferred to launch time` and omit the `hula-branch` comment.)
151
+
136
152
  Now proceed directly to plan validation **without waiting for the user**. The plan file was just created in this session — the path is already known.
137
153
 
138
154
  Read `hula instructions proceed` and execute the full validation workflow against the plan at `<path>` (substitute `<path>` with the actual plan file path you just created, e.g. `.hublaunch/plans/2025-12-29-14:30-feature-name.md`).
@@ -156,4 +172,4 @@ Read `hula instructions proceed` and execute the full validation workflow agains
156
172
  5. If `--test` and/or `--handoff <username>` were also present in `$ARGUMENTS`, pass them through to the launch — same as the Launch Offer's reply table does for a manual reply containing those flags.
157
173
  - **Without `--autoLaunch`**, behavior is completely unchanged: ask and wait as today.
158
174
 
159
- **Note:** The plan is saved locally. When you run `/hula-launch`, the plan is automatically synced to `origin/main` before the GitHub issue is created and the implementation begins — no separate upload step needed. Because validation ends with the Launch Offer, an affirmative reply runs the `/hula-launch` workflow for the user automatically; they can also decline and run `/hula-launch` themselves later. `/hula-confirm` remains available as a standalone command for re-validation at any time. If `--autoLaunch` was passed to `/hula-plan`, the launch runs automatically once validation completes — no reply needed.
175
+ **Note:** The plan is saved locally AND pushed to its feature branch on origin (Step 2). When you run `/hula-launch`, the plan branch is re-synced automatically (covering validation edits and renames) before the GitHub issue is created and the implementation begins — no separate upload step needed. Because validation ends with the Launch Offer, an affirmative reply runs the `/hula-launch` workflow for the user automatically; they can also decline and run `/hula-launch` themselves later. `/hula-confirm` remains available as a standalone command for re-validation at any time. If `--autoLaunch` was passed to `/hula-plan`, the launch runs automatically once validation completes — no reply needed.
@@ -29,7 +29,7 @@ Your job is to:
29
29
  ```
30
30
  ℹ️ Upload is no longer a separate step.
31
31
 
32
- `hula launch` automatically uploads the plan to `origin/main` before starting the job.
32
+ `hula launch` automatically publishes the plan to its feature branch before starting the job (creating the branch from the base branch if `/hula-plan` didn't already).
33
33
 
34
34
  **Next Step:** Run `/hula-launch <branch-name>` to upload and launch in one step.
35
35
 
@@ -84,7 +84,7 @@ Display this message to the user:
84
84
  ```
85
85
  ℹ️ Upload is no longer a separate step.
86
86
 
87
- `hula launch` automatically uploads the plan to `origin/main` before starting the job.
87
+ `hula launch` automatically publishes the plan to its feature branch before starting the job (creating the branch from the base branch if `/hula-plan` didn't already).
88
88
 
89
89
  **Next Step:** Run `/hula-launch <branch-name>` to upload and launch in one step.
90
90
 
@@ -25,6 +25,14 @@ export declare function parseIssueNumber(value: string | number): number | null;
25
25
  * Validate email address
26
26
  */
27
27
  export declare function isValidEmail(email: string): boolean;
28
+ /**
29
+ * Sanitize an issue/tracking name into the git branch name used for its run.
30
+ * MUST stay byte-identical to `sanitizePlanName` in hula-server's
31
+ * `packages/shared/src/utils.ts` — the server derives the sandbox branch from
32
+ * the same issueName, so both sides have to resolve the SAME branch name for
33
+ * the plan-branch flow to hand off correctly.
34
+ */
35
+ export declare function sanitizePlanName(name: string): string;
28
36
  /**
29
37
  * Sanitize filename
30
38
  */
@@ -1 +1 @@
1
- {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/utils/validators.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAElE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG/D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO/C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAUtE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMzD"}
1
+ {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/utils/validators.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAElE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG/D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO/C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAUtE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMzD"}
@@ -51,6 +51,16 @@ export function isValidEmail(email) {
51
51
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
52
52
  return emailRegex.test(email);
53
53
  }
54
+ /**
55
+ * Sanitize an issue/tracking name into the git branch name used for its run.
56
+ * MUST stay byte-identical to `sanitizePlanName` in hula-server's
57
+ * `packages/shared/src/utils.ts` — the server derives the sandbox branch from
58
+ * the same issueName, so both sides have to resolve the SAME branch name for
59
+ * the plan-branch flow to hand off correctly.
60
+ */
61
+ export function sanitizePlanName(name) {
62
+ return name.replace(/[^a-zA-Z0-9_-]/g, "_");
63
+ }
54
64
  /**
55
65
  * Sanitize filename
56
66
  */
@@ -1 +1 @@
1
- {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/utils/validators.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,8DAA8D;IAC9D,OAAO,+CAA+C,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAsB;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,CAAC;IAED,6BAA6B;IAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAElC,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,UAAU,GAAG,4BAA4B,CAAC;IAChD,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,QAAQ;SACZ,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC,wBAAwB;SAC/D,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,8BAA8B;SACnD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,4BAA4B;SAChD,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,kCAAkC;AAC9D,CAAC"}
1
+ {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/utils/validators.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,8DAA8D;IAC9D,OAAO,+CAA+C,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAsB;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,CAAC;IAED,6BAA6B;IAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAElC,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,UAAU,GAAG,4BAA4B,CAAC;IAChD,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,QAAQ;SACZ,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC,wBAAwB;SAC/D,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,8BAA8B;SACnD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,4BAA4B;SAChD,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,kCAAkC;AAC9D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hub-launch",
3
- "version": "1.26.0",
3
+ "version": "1.28.0",
4
4
  "description": "GitHub Issue and PR automation CLI tool with plugin/hook system for project-specific customizations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -75,5 +75,13 @@
75
75
  "engines": {
76
76
  "node": ">=18.0.0"
77
77
  },
78
+ "overrides": {
79
+ "core-js": "^3.23.3"
80
+ },
81
+ "pnpm": {
82
+ "overrides": {
83
+ "core-js": "^3.23.3"
84
+ }
85
+ },
78
86
  "packageManager": "pnpm@9.1.1+sha512.14e915759c11f77eac07faba4d019c193ec8637229e62ec99eefb7cf3c3b75c64447882b7c485142451ee3a6b408059cdfb7b7fa0341b975f12d0f7629c71195"
79
87
  }