hub-launch 1.16.0 → 1.18.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.
- package/CHANGELOG.md +14 -0
- package/README.md +102 -2
- package/dist/commands/init.d.ts +61 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +125 -114
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/instructions.d.ts +17 -0
- package/dist/commands/instructions.d.ts.map +1 -0
- package/dist/commands/instructions.js +51 -0
- package/dist/commands/instructions.js.map +1 -0
- package/dist/commands/launch.d.ts +21 -0
- package/dist/commands/launch.d.ts.map +1 -1
- package/dist/commands/launch.js +61 -0
- package/dist/commands/launch.js.map +1 -1
- package/dist/commands/script.d.ts +28 -0
- package/dist/commands/script.d.ts.map +1 -0
- package/dist/commands/script.js +69 -0
- package/dist/commands/script.js.map +1 -0
- package/dist/commands/session-hook.d.ts +26 -0
- package/dist/commands/session-hook.d.ts.map +1 -0
- package/dist/commands/session-hook.js +146 -0
- package/dist/commands/session-hook.js.map +1 -0
- package/dist/index.js +22 -1
- package/dist/index.js.map +1 -1
- package/dist/scripts/fix-commit.d.ts +2 -0
- package/dist/scripts/fix-commit.d.ts.map +1 -0
- package/dist/scripts/fix-commit.js +125 -0
- package/dist/scripts/fix-commit.js.map +1 -0
- package/dist/scripts/fix-setup.d.ts +2 -0
- package/dist/scripts/fix-setup.d.ts.map +1 -0
- package/dist/scripts/fix-setup.js +161 -0
- package/dist/scripts/fix-setup.js.map +1 -0
- package/dist/scripts/launch-run.d.ts +14 -0
- package/dist/scripts/launch-run.d.ts.map +1 -0
- package/dist/scripts/launch-run.js +117 -0
- package/dist/scripts/launch-run.js.map +1 -0
- package/dist/scripts/lib/exec.d.ts +48 -0
- package/dist/scripts/lib/exec.d.ts.map +1 -0
- package/dist/scripts/lib/exec.js +61 -0
- package/dist/scripts/lib/exec.js.map +1 -0
- package/dist/scripts/lib/io.d.ts +48 -0
- package/dist/scripts/lib/io.d.ts.map +1 -0
- package/dist/scripts/lib/io.js +72 -0
- package/dist/scripts/lib/io.js.map +1 -0
- package/dist/scripts/lib/read-config.d.ts +26 -0
- package/dist/scripts/lib/read-config.d.ts.map +1 -0
- package/dist/scripts/lib/read-config.js +65 -0
- package/dist/scripts/lib/read-config.js.map +1 -0
- package/dist/scripts/merge-local.d.ts +2 -0
- package/dist/scripts/merge-local.d.ts.map +1 -0
- package/dist/scripts/merge-local.js +146 -0
- package/dist/scripts/merge-local.js.map +1 -0
- package/dist/scripts/merge-remote.d.ts +12 -0
- package/dist/scripts/merge-remote.d.ts.map +1 -0
- package/dist/scripts/merge-remote.js +71 -0
- package/dist/scripts/merge-remote.js.map +1 -0
- package/dist/scripts/schedule-manage.d.ts +2 -0
- package/dist/scripts/schedule-manage.d.ts.map +1 -0
- package/dist/scripts/schedule-manage.js +151 -0
- package/dist/scripts/schedule-manage.js.map +1 -0
- package/dist/scripts/schedule-run.d.ts +2 -0
- package/dist/scripts/schedule-run.d.ts.map +1 -0
- package/dist/scripts/schedule-run.js +146 -0
- package/dist/scripts/schedule-run.js.map +1 -0
- package/dist/scripts/verify-gather.d.ts +2 -0
- package/dist/scripts/verify-gather.d.ts.map +1 -0
- package/dist/scripts/verify-gather.js +206 -0
- package/dist/scripts/verify-gather.js.map +1 -0
- package/dist/scripts/verify-post.d.ts +12 -0
- package/dist/scripts/verify-post.d.ts.map +1 -0
- package/dist/scripts/verify-post.js +91 -0
- package/dist/scripts/verify-post.js.map +1 -0
- package/dist/templates/planning-instructions.md +7 -7
- package/dist/templates/skill-creation-instructions.md +2 -2
- package/dist/templates/skills/hula-confirm/SKILL.md +3 -3
- package/dist/templates/skills/hula-fix/SKILL.md +3 -3
- package/dist/templates/skills/hula-help/SKILL.md +117 -0
- package/dist/templates/skills/hula-launch/SKILL.md +14 -8
- package/dist/templates/skills/hula-merge/SKILL.md +2 -2
- package/dist/templates/skills/hula-plan/SKILL.md +5 -5
- package/dist/templates/skills/hula-schedule/SKILL.md +16 -16
- package/dist/templates/skills/hula-verify/SKILL.md +32 -33
- package/dist/types/config.schema.d.ts +235 -0
- package/dist/types/config.schema.d.ts.map +1 -1
- package/dist/types/config.schema.js +66 -0
- package/dist/types/config.schema.js.map +1 -1
- package/dist/utils/client-session.d.ts +2 -2
- package/dist/utils/client-session.js +2 -2
- package/package.json +6 -5
- package/scripts/postinstall.mjs +102 -0
- package/dist/templates/scripts/hula-fix-commit.sh +0 -114
- package/dist/templates/scripts/hula-fix-setup.sh +0 -152
- package/dist/templates/scripts/hula-launch-run.sh +0 -140
- package/dist/templates/scripts/hula-merge-local.sh +0 -138
- package/dist/templates/scripts/hula-merge-remote.sh +0 -94
- package/dist/templates/scripts/hula-read-config.sh +0 -38
- package/dist/templates/scripts/hula-schedule-manage.sh +0 -159
- package/dist/templates/scripts/hula-schedule-run.sh +0 -148
- package/dist/templates/scripts/hula-session-hook.sh +0 -68
- package/dist/templates/scripts/hula-verify-gather.sh +0 -135
- package/dist/templates/scripts/hula-verify-post.sh +0 -84
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.18.0] - 2026-07-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Verify reports now auto-post to the PR by default; use `--no-post` to restore the old confirm-before-posting behavior.
|
|
15
|
+
- Added a `hula-help` Agent Skill for interactive onboarding and reference guidance.
|
|
16
|
+
- Moved `hula-verify`'s tmp writes from OS `/tmp` to a repo-local, gitignored `.hublaunch/tmp/` directory (#325).
|
|
17
|
+
|
|
18
|
+
## [1.17.0] - 2026-07-23
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `hula launch` now supports per-pipeline-step model and iteration-cap overrides via a `steps` block in `.hublaunch/hublaunch.config.js` (hula-server PR #442), plus a `--skip-regression` flag to force-skip regression tests for a single launch. Conflicting `bugfix.model`/`mergeConflict.model` values, or `regression.skip` combined with the legacy `--regression` flag, are rejected locally before any network call.
|
|
23
|
+
|
|
10
24
|
## [1.16.0] - 2026-07-17
|
|
11
25
|
|
|
12
26
|
### Fixed
|
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ That's the whole fundamental workflow.
|
|
|
40
40
|
- 🖥️ **Client Agnostic** — based on skills that can be adapted to most agent harnesses
|
|
41
41
|
- 🔔 **Notifications** - you can configure an endpoint for notifications about progress. For instance, a slack channel.
|
|
42
42
|
- 📋 **Logging** - run `hula-info` for progress in the container. Also pushes several documents within each PR showing logging.
|
|
43
|
+
- 🧭 **Guided Help** — run `/hula-help` anytime for an interactive walkthrough of setup, the workflow, and any command or skill
|
|
43
44
|
- 🖥️ **Dashboard** — track all your active plans at [https://www.hublaunch.site/dashboard](https://www.hublaunch.site/dashboard)
|
|
44
45
|
- 🔒 **Safe** - tokens are maintained by you locally in your config file, and on our server securely protected and removed when no longer needed.
|
|
45
46
|
|
|
@@ -82,8 +83,9 @@ After upgrading the CLI:
|
|
|
82
83
|
npm install -g hub-launch@latest # or: pnpm add -g hub-launch
|
|
83
84
|
```
|
|
84
85
|
|
|
85
|
-
re-run `hula init` inside each project to refresh the bundled Agent Skills
|
|
86
|
-
|
|
86
|
+
re-run `hula init` inside each project to refresh the bundled Agent Skills and
|
|
87
|
+
config scaffolding (workflow scripts and instruction docs now ship with the
|
|
88
|
+
package, so they update automatically with the CLI):
|
|
87
89
|
|
|
88
90
|
```bash
|
|
89
91
|
cd <your-project>
|
|
@@ -149,9 +151,41 @@ Top-level commands:
|
|
|
149
151
|
| `hula merge` | — | Merge PR and clean up |
|
|
150
152
|
| `hula launch` | — | Trigger AI coding session on hula-project server |
|
|
151
153
|
| `hula schedule` | — | Trigger or schedule an execute-action (e.g. `--built-in harden`) |
|
|
154
|
+
| `hula script <name>` | — | Run a bundled cross-platform workflow script (used by the Agent Skills) |
|
|
155
|
+
| `hula instructions <name>` | — | Print a bundled instruction doc (`planning`, `proceed`, `skill-creation`) |
|
|
156
|
+
| `hula session-hook` | — | Claude Code PreToolUse hook that captures launch-session provenance |
|
|
152
157
|
|
|
153
158
|
Run `hula <command> --help` for details, or see the full [Commands Reference](./docs/commands.md).
|
|
154
159
|
|
|
160
|
+
### Cross-platform, low-footprint tooling
|
|
161
|
+
|
|
162
|
+
The workflow scripts and instruction documents that power the Agent Skills ship
|
|
163
|
+
**inside the `hula` package** as cross-platform Node — they are no longer copied
|
|
164
|
+
into your repo, and they need **no `bash` and no `jq`**, so they run identically
|
|
165
|
+
on macOS, Linux, and Windows. `hula init` therefore does not write
|
|
166
|
+
`.github/scripts/*.sh` or `.hublaunch/*-instructions.md`.
|
|
167
|
+
|
|
168
|
+
Skills invoke them via the global bin:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Run a bundled workflow script (cross-platform, no bash/jq)
|
|
172
|
+
hula script merge-local -- 42 ".hula-worktrees/issue-42" "fix(#42): message"
|
|
173
|
+
|
|
174
|
+
# Print a bundled instruction document
|
|
175
|
+
hula instructions planning
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Migration:** upgrading from an older version? Existing
|
|
179
|
+
`.github/scripts/hula-*.sh` and `.hublaunch/*-instructions.md` keep working, but
|
|
180
|
+
are now obsolete and safe to delete — `hula init` prints a reminder listing them
|
|
181
|
+
(it never deletes anything).
|
|
182
|
+
|
|
183
|
+
**Claude Code commands:** the `/hula-*` commands are available as a Claude Code
|
|
184
|
+
plugin so they load globally, so `hula init` no longer writes `.claude/commands/*`
|
|
185
|
+
symlinks by default. Prefer repo-local command files instead? Run
|
|
186
|
+
`hula init --with-claude-commands`. The committed `.agents/skills/` directory
|
|
187
|
+
(read by GitHub Copilot, Cursor, Codex, and 30+ tools) is unchanged.
|
|
188
|
+
|
|
155
189
|
## `hula launch` and Resume
|
|
156
190
|
|
|
157
191
|
`hula launch` submits a job to the hula-project server, which runs an AI coding agent (Claude Code) through a fixed 9-step pipeline:
|
|
@@ -281,6 +315,72 @@ variables, and includes them in the request to the server. Notes:
|
|
|
281
315
|
- Only forward variables your tests actually need; treat anything you list as
|
|
282
316
|
leaving your machine.
|
|
283
317
|
|
|
318
|
+
### Configuring per-step model & iteration overrides
|
|
319
|
+
|
|
320
|
+
`hula launch` runs your plan through a fixed 9-step server-side pipeline. By
|
|
321
|
+
default every step uses the server's built-in model, loop-iteration cap, and
|
|
322
|
+
skip behavior. To override those per step for your project, add a `steps` block
|
|
323
|
+
to `.hublaunch/hublaunch.config.js` (config-file only — this is a persistent
|
|
324
|
+
project setting, not a per-launch flag):
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
export const config = {
|
|
328
|
+
// ...
|
|
329
|
+
steps: {
|
|
330
|
+
implementation: { model: "opus" },
|
|
331
|
+
lintfix: { model: "haiku", maxIterations: 2 },
|
|
332
|
+
regression: { skip: true },
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Each of the 9 keys maps to a pipeline step. All fields are optional; omit a step
|
|
338
|
+
(or the whole `steps` block) to keep the server default:
|
|
339
|
+
|
|
340
|
+
| Step key | `model` | `maxIterations` | `skip` | Other |
|
|
341
|
+
| ---------------- | :-----: | :-------------: | :----: | ----- |
|
|
342
|
+
| `implementation` | ✅ | | | |
|
|
343
|
+
| `findBugs` | ✅ | ✅ (1–20) | | `diffMaxLines` (≥1), `excludeRegex` (string) |
|
|
344
|
+
| `bugfix` | ✅ | | | |
|
|
345
|
+
| `lintfix` | ✅ | ✅ (1–20) | | |
|
|
346
|
+
| `build` | ✅ | ✅ (1–20) | | |
|
|
347
|
+
| `regression` | | | ✅ | |
|
|
348
|
+
| `mergeConflict` | ✅ | | | |
|
|
349
|
+
| `summary` | ✅ | ✅ (1–20) | | |
|
|
350
|
+
| `verify` | ✅ | ✅ (1–20) | ✅ | |
|
|
351
|
+
|
|
352
|
+
`model` values are free-form strings passed straight through to the server
|
|
353
|
+
(`claude --model <value>`); no allowlist is enforced. Values are validated at
|
|
354
|
+
config-load time — an out-of-range `maxIterations`, a non-boolean `skip`, or an
|
|
355
|
+
empty `model` string fails immediately with a clear error.
|
|
356
|
+
|
|
357
|
+
#### `--skip-regression`
|
|
358
|
+
|
|
359
|
+
As a per-launch counterpart to the config `steps.regression.skip`, `hula launch`
|
|
360
|
+
accepts a `--skip-regression` flag that force-skips the regression-tests step for
|
|
361
|
+
that one invocation (it wins over whatever `steps.regression.skip` is set to in
|
|
362
|
+
config):
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
# Skip regression tests for a single launch
|
|
366
|
+
hula launch feature-auth .hublaunch/plans/my-plan.md --skip-regression
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
#### Conflict rules (validated locally before any network call)
|
|
370
|
+
|
|
371
|
+
Two combinations are rejected client-side — `hula launch` exits `1` immediately
|
|
372
|
+
with the same message the server would return, so misconfigurations fail fast:
|
|
373
|
+
|
|
374
|
+
- **`bugfix.model` ≠ `mergeConflict.model`** — both map to the same
|
|
375
|
+
`RALPH_BUGFIX_MODEL` env var on the server, so they cannot be set to different
|
|
376
|
+
values:
|
|
377
|
+
`bugfix.model and mergeConflict.model both map to RALPH_BUGFIX_MODEL and cannot conflict`
|
|
378
|
+
- **`regression.skip: true` combined with the legacy `--regression` flag** — one
|
|
379
|
+
forces the step off, the other forces it on. This also covers passing both
|
|
380
|
+
`--skip-regression` and `--regression`, and a config `steps.regression.skip:
|
|
381
|
+
true` combined with a one-off `--regression`:
|
|
382
|
+
`regression.skip and the legacy regression flag are contradictory`
|
|
383
|
+
|
|
284
384
|
## `hula schedule`
|
|
285
385
|
|
|
286
386
|
`hula schedule` triggers a built-in or custom execute-action (e.g. the `harden` security audit) on the hula-project server, which provisions a sandbox to run it and opens a PR / plan / feedback as the outcome.
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import type { Config } from '../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Idempotently append a `.gitignore` entry with its own comment header, if
|
|
5
|
+
* `marker` isn't already present in `content`. Pure/sync so the append logic is
|
|
6
|
+
* unit-testable without touching the filesystem.
|
|
7
|
+
*/
|
|
8
|
+
export declare function appendGitignoreEntry(content: string, marker: string, comment: string, entry: string): string;
|
|
3
9
|
/**
|
|
4
10
|
* Keys whose **actual runtime value** is written by the config template below.
|
|
5
11
|
* A key belongs here if and only if emitting it a second time would duplicate
|
|
@@ -40,7 +46,62 @@ export declare function initCommand(program: Command, _config: Config): void;
|
|
|
40
46
|
* Generate hook templates based on authentication provider
|
|
41
47
|
*/
|
|
42
48
|
export declare function generateHookTemplates(projectRoot: string, authProvider: string): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Ensure the `.hublaunch/skills/` action-file directory exists.
|
|
51
|
+
*
|
|
52
|
+
* The planning/proceed/skill-creation instruction documents are no longer
|
|
53
|
+
* copied into the consumer repo — they ship inside the `hula` package and are
|
|
54
|
+
* read at runtime via `hula instructions <planning|proceed|skill-creation>`.
|
|
55
|
+
* This keeps the project footprint to genuinely project-specific files.
|
|
56
|
+
*
|
|
57
|
+
* Only the `.hublaunch/skills/` directory (user-authored /hula-schedule action
|
|
58
|
+
* files) is created here; files committed there persist (it is not gitignored).
|
|
59
|
+
*/
|
|
60
|
+
export declare function initializeSkillsActionDir(projectRoot: string): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Initialize Agent Skills for AI-assisted hula workflows.
|
|
63
|
+
*
|
|
64
|
+
* Single source of truth: .agents/skills/<name>/SKILL.md (Agent Skills spec).
|
|
65
|
+
*
|
|
66
|
+
* Each harness gets a reference to that canonical file:
|
|
67
|
+
* - GitHub Copilot, Cursor, Codex, and other Agent Skills-compatible tools
|
|
68
|
+
* read directly from .agents/skills/<name>/SKILL.md.
|
|
69
|
+
* - Claude Code reads from .claude/commands/<name>.md, which is created as
|
|
70
|
+
* a symlink pointing into .agents/skills/ (relative path so it works after
|
|
71
|
+
* cloning on any machine). No content is duplicated.
|
|
72
|
+
*
|
|
73
|
+
* Because the symlinks are named <name>.md (not SKILL.md) and live under
|
|
74
|
+
* .claude/commands/ (not .agents/skills/), GitHub Copilot's Agent Skills
|
|
75
|
+
* scanner does not pick them up, so no duplicate commands appear.
|
|
76
|
+
*
|
|
77
|
+
* Any existing .claude/skills/ directory is removed on init to clean up
|
|
78
|
+
* legacy installations that previously wrote full files there.
|
|
79
|
+
*
|
|
80
|
+
* Agent Skills standard: https://agentskills.io/specification
|
|
81
|
+
*/
|
|
82
|
+
export declare function initializeAgentSkills(projectRoot: string, withClaudeCommands: boolean): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Detect tool-owned files from earlier hula versions that are now obsolete and
|
|
85
|
+
* print a non-destructive notice. `hula init` no longer generates
|
|
86
|
+
* `.github/scripts/hula-*.sh` or `.hublaunch/*-instructions.md` — those scripts
|
|
87
|
+
* and instruction docs ship inside the `hula` package now (run via
|
|
88
|
+
* `hula script <name>` / `hula instructions <name>`). Pre-existing copies are
|
|
89
|
+
* left untouched (they still work) but can be safely deleted.
|
|
90
|
+
*/
|
|
91
|
+
export declare function noticeObsoleteFiles(projectRoot: string): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Register the hula session hook in the consumer repo's .claude/settings.json.
|
|
94
|
+
*
|
|
95
|
+
* Adds a PreToolUse/Bash hook entry that captures the Claude Code session id
|
|
96
|
+
* of the chat session running /hula-launch (clientSessionId provenance —
|
|
97
|
+
* hula-server PR #419). Unlike initVsCodeAutoApproval's single-key overwrite,
|
|
98
|
+
* hooks live in a NESTED ARRAY (`hooks.PreToolUse[]`) that users may already
|
|
99
|
+
* populate, so this merges: it preserves every existing hook and appends ours
|
|
100
|
+
* only when absent (idempotent by the command string).
|
|
101
|
+
*/
|
|
102
|
+
export declare function initClaudeSessionHook(projectRoot: string): Promise<void>;
|
|
43
103
|
export declare function executeInit(options?: {
|
|
44
104
|
force?: boolean;
|
|
105
|
+
withClaudeCommands?: boolean;
|
|
45
106
|
}): Promise<void>;
|
|
46
107
|
//# sourceMappingURL=init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAahD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAahD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,MAAM,CAIR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,qBAAqB,aAmBhC,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAe9E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAuBnE;AA0bD;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAyED;;;;;;;;;;GAUG;AACH,wBAAsB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,OAAO,GAC1B,OAAO,CAAC,IAAI,CAAC,CAmEf;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC5E;AAwED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD9E;AAsCD,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GAAG,OAAO,CAAC,IAAI,CAAC,CA4iBhB"}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeFile, readFile, mkdir, copyFile,
|
|
1
|
+
import { writeFile, readFile, readdir, mkdir, copyFile, rm, symlink, } from 'fs/promises';
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
3
|
import { join, relative, isAbsolute } from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
@@ -10,6 +10,17 @@ import { DEFAULT_CONFIG } from '../types/config.schema.js';
|
|
|
10
10
|
import { checkGhVersion } from '../utils/github-cli.js';
|
|
11
11
|
import { parseExistingConfig, mergeConfigs, CONFIG_PARSE_FAILED_PREFIX, } from '../utils/config-parser.js';
|
|
12
12
|
import { getCliVersion } from '../utils/version.js';
|
|
13
|
+
/**
|
|
14
|
+
* Idempotently append a `.gitignore` entry with its own comment header, if
|
|
15
|
+
* `marker` isn't already present in `content`. Pure/sync so the append logic is
|
|
16
|
+
* unit-testable without touching the filesystem.
|
|
17
|
+
*/
|
|
18
|
+
export function appendGitignoreEntry(content, marker, comment, entry) {
|
|
19
|
+
if (content.includes(marker))
|
|
20
|
+
return content;
|
|
21
|
+
const prefix = content.length === 0 || content.endsWith('\n') ? '' : '\n';
|
|
22
|
+
return `${content}${prefix}\n${comment}\n${entry}\n`;
|
|
23
|
+
}
|
|
13
24
|
/**
|
|
14
25
|
* Keys whose **actual runtime value** is written by the config template below.
|
|
15
26
|
* A key belongs here if and only if emitting it a second time would duplicate
|
|
@@ -45,6 +56,7 @@ export const TEMPLATE_EMITTED_KEYS = new Set([
|
|
|
45
56
|
'hooks',
|
|
46
57
|
'worktreeBasePath',
|
|
47
58
|
'envVars',
|
|
59
|
+
'steps',
|
|
48
60
|
]);
|
|
49
61
|
/**
|
|
50
62
|
* Build the `// Preserved custom settings` block for any keys present in the
|
|
@@ -75,6 +87,7 @@ export function initCommand(program, _config) {
|
|
|
75
87
|
.command('init')
|
|
76
88
|
.description('Initialize HubLaunch configuration (interactive)')
|
|
77
89
|
.option('--force', 'Overwrite existing configuration')
|
|
90
|
+
.option('--with-claude-commands', 'Also write repo-local .claude/commands/* symlinks (default: use the global hula Claude Code plugin instead)')
|
|
78
91
|
.action(async (options) => {
|
|
79
92
|
try {
|
|
80
93
|
await executeInit(options);
|
|
@@ -605,43 +618,20 @@ const AGENT_SKILLS = [
|
|
|
605
618
|
{ templateDir: 'hula-schedule', skillName: 'hula-schedule' },
|
|
606
619
|
{ templateDir: 'hula-upload', skillName: 'hula-upload' },
|
|
607
620
|
{ templateDir: 'hula-info', skillName: 'hula-info' },
|
|
621
|
+
{ templateDir: 'hula-help', skillName: 'hula-help' },
|
|
608
622
|
];
|
|
609
623
|
/**
|
|
610
|
-
*
|
|
611
|
-
*
|
|
624
|
+
* Ensure the `.hublaunch/skills/` action-file directory exists.
|
|
625
|
+
*
|
|
626
|
+
* The planning/proceed/skill-creation instruction documents are no longer
|
|
627
|
+
* copied into the consumer repo — they ship inside the `hula` package and are
|
|
628
|
+
* read at runtime via `hula instructions <planning|proceed|skill-creation>`.
|
|
629
|
+
* This keeps the project footprint to genuinely project-specific files.
|
|
630
|
+
*
|
|
631
|
+
* Only the `.hublaunch/skills/` directory (user-authored /hula-schedule action
|
|
632
|
+
* files) is created here; files committed there persist (it is not gitignored).
|
|
612
633
|
*/
|
|
613
|
-
async function
|
|
614
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
615
|
-
const __dirname = dirname(__filename);
|
|
616
|
-
const templatesSourceDir = join(__dirname, '..', 'templates');
|
|
617
|
-
const instructionsTemplatePath = join(templatesSourceDir, 'planning-instructions.md');
|
|
618
|
-
const instructionsDestPath = join(projectRoot, '.hublaunch', 'planning-instructions.md');
|
|
619
|
-
if (!existsSync(instructionsDestPath) || overridePlanningInstructions) {
|
|
620
|
-
await copyFile(instructionsTemplatePath, instructionsDestPath);
|
|
621
|
-
logger.success('Updated: .hublaunch/planning-instructions.md');
|
|
622
|
-
}
|
|
623
|
-
else {
|
|
624
|
-
logger.info('Keeping existing planning instructions');
|
|
625
|
-
}
|
|
626
|
-
const proceedInstructionsTemplatePath = join(templatesSourceDir, 'proceed-instructions.md');
|
|
627
|
-
const proceedInstructionsDestPath = join(projectRoot, '.hublaunch', 'proceed-instructions.md');
|
|
628
|
-
if (!existsSync(proceedInstructionsDestPath) || overrideProceedInstructions) {
|
|
629
|
-
await copyFile(proceedInstructionsTemplatePath, proceedInstructionsDestPath);
|
|
630
|
-
logger.success('Updated: .hublaunch/proceed-instructions.md');
|
|
631
|
-
}
|
|
632
|
-
else {
|
|
633
|
-
logger.info('Keeping existing proceed instructions');
|
|
634
|
-
}
|
|
635
|
-
// Skill-creation instructions are read by the /hula-schedule skill at runtime
|
|
636
|
-
// (parallel to how /hula-plan reads planning-instructions.md). They are
|
|
637
|
-
// deterministic tooling, so always refresh them with the latest template.
|
|
638
|
-
const skillCreationTemplatePath = join(templatesSourceDir, 'skill-creation-instructions.md');
|
|
639
|
-
const skillCreationDestPath = join(projectRoot, '.hublaunch', 'skill-creation-instructions.md');
|
|
640
|
-
await copyFile(skillCreationTemplatePath, skillCreationDestPath);
|
|
641
|
-
logger.success('Updated: .hublaunch/skill-creation-instructions.md');
|
|
642
|
-
// Ensure the action-file directory used by the /hula-schedule skill exists.
|
|
643
|
-
// Files committed here persist (it is not gitignored). Seed a .gitkeep so the
|
|
644
|
-
// empty directory survives in git until the first action file is created.
|
|
634
|
+
export async function initializeSkillsActionDir(projectRoot) {
|
|
645
635
|
const skillsDir = join(projectRoot, '.hublaunch', 'skills');
|
|
646
636
|
await mkdir(skillsDir, { recursive: true });
|
|
647
637
|
const gitkeepPath = join(skillsDir, '.gitkeep');
|
|
@@ -671,16 +661,20 @@ async function initializePlanningInstructions(projectRoot, overridePlanningInstr
|
|
|
671
661
|
*
|
|
672
662
|
* Agent Skills standard: https://agentskills.io/specification
|
|
673
663
|
*/
|
|
674
|
-
async function initializeAgentSkills(projectRoot) {
|
|
664
|
+
export async function initializeAgentSkills(projectRoot, withClaudeCommands) {
|
|
675
665
|
const __filename = fileURLToPath(import.meta.url);
|
|
676
666
|
const __dirname = dirname(__filename);
|
|
677
667
|
const skillsSourceDir = join(__dirname, '..', 'templates', 'skills');
|
|
678
668
|
// Canonical location — single source of truth.
|
|
679
669
|
const agentsSkillsDir = join(projectRoot, '.agents', 'skills');
|
|
680
670
|
await mkdir(agentsSkillsDir, { recursive: true });
|
|
681
|
-
// Claude Code reads from .claude/commands
|
|
671
|
+
// Claude Code reads from .claude/commands/ — only when the opt-in flag asks
|
|
672
|
+
// for repo-local commands. By default the /hula-* commands come from the hula
|
|
673
|
+
// Claude Code plugin (installed globally), so no symlinks are written.
|
|
682
674
|
const claudeCommandsDir = join(projectRoot, '.claude', 'commands');
|
|
683
|
-
|
|
675
|
+
if (withClaudeCommands) {
|
|
676
|
+
await mkdir(claudeCommandsDir, { recursive: true });
|
|
677
|
+
}
|
|
684
678
|
// Remove .claude/skills/ if it exists — legacy path that caused duplicates.
|
|
685
679
|
const claudeSkillsDir = join(projectRoot, '.claude', 'skills');
|
|
686
680
|
try {
|
|
@@ -695,63 +689,66 @@ async function initializeAgentSkills(projectRoot) {
|
|
|
695
689
|
const agentsDestDir = join(agentsSkillsDir, skillName);
|
|
696
690
|
await mkdir(agentsDestDir, { recursive: true });
|
|
697
691
|
await copyFile(srcSkillMd, join(agentsDestDir, 'SKILL.md'));
|
|
698
|
-
//
|
|
699
|
-
// Relative path so
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
692
|
+
// Optionally create a symlink in .claude/commands/ pointing back to the
|
|
693
|
+
// canonical file. Relative path so it works after cloning on any machine.
|
|
694
|
+
if (withClaudeCommands) {
|
|
695
|
+
const symlinkPath = join(claudeCommandsDir, `${skillName}.md`);
|
|
696
|
+
const symlinkTarget = join('..', '..', '.agents', 'skills', skillName, 'SKILL.md');
|
|
697
|
+
// Remove any existing file/symlink before (re-)creating.
|
|
698
|
+
await rm(symlinkPath, { force: true });
|
|
699
|
+
await symlink(symlinkTarget, symlinkPath);
|
|
700
|
+
}
|
|
705
701
|
logger.success(`Updated skill: ${skillName}`);
|
|
706
702
|
}
|
|
707
703
|
logger.blank();
|
|
708
704
|
logger.info('🎉 Agent Skills installed — works with Claude Code, GitHub Copilot, Codex, and 30+ AI tools');
|
|
709
705
|
logger.info('💡 Invoke with /hula-plan, /hula-fix, /hula-create, etc. (note: hyphens, not dots)');
|
|
706
|
+
if (withClaudeCommands) {
|
|
707
|
+
logger.info('🔗 Repo-local Claude Code commands written to .claude/commands/ (--with-claude-commands).');
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
logger.info('📦 For Claude Code, /hula-* commands are installed globally to ~/.claude/commands/ when hula is installed/built — no per-project files needed.');
|
|
711
|
+
logger.info(' If they are missing, reinstall hula (or run its postinstall), or use `hula init --with-claude-commands` for repo-local command files.');
|
|
712
|
+
}
|
|
710
713
|
}
|
|
711
714
|
/**
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
'hula-fix-setup.sh',
|
|
719
|
-
'hula-fix-commit.sh',
|
|
720
|
-
'hula-verify-gather.sh',
|
|
721
|
-
'hula-verify-post.sh',
|
|
722
|
-
'hula-merge-local.sh',
|
|
723
|
-
'hula-merge-remote.sh',
|
|
724
|
-
'hula-launch-run.sh',
|
|
725
|
-
// No new auto-approve rule needed: the VSCODE_AUTO_APPROVE_SETTINGS pattern
|
|
726
|
-
// `^bash \.github/scripts/hula-` already matches hula-schedule-run.sh and
|
|
727
|
-
// hula-schedule-manage.sh.
|
|
728
|
-
'hula-schedule-run.sh',
|
|
729
|
-
'hula-schedule-manage.sh',
|
|
730
|
-
// Claude Code PreToolUse hook that captures the launching chat session id
|
|
731
|
-
// (clientSessionId provenance — hula-server PR #419). Registered in the
|
|
732
|
-
// consumer's .claude/settings.json by initClaudeSessionHook().
|
|
733
|
-
'hula-session-hook.sh',
|
|
734
|
-
];
|
|
735
|
-
/**
|
|
736
|
-
* Initialize bundled shell scripts for chat participant workflows.
|
|
737
|
-
* Copies scripts from src/templates/scripts/ to .github/scripts/ in the target project.
|
|
738
|
-
* These scripts bundle multiple terminal commands into single invocations,
|
|
739
|
-
* reducing VS Code terminal approval popups from ~28 to ~7 per workflow cycle.
|
|
715
|
+
* Detect tool-owned files from earlier hula versions that are now obsolete and
|
|
716
|
+
* print a non-destructive notice. `hula init` no longer generates
|
|
717
|
+
* `.github/scripts/hula-*.sh` or `.hublaunch/*-instructions.md` — those scripts
|
|
718
|
+
* and instruction docs ship inside the `hula` package now (run via
|
|
719
|
+
* `hula script <name>` / `hula instructions <name>`). Pre-existing copies are
|
|
720
|
+
* left untouched (they still work) but can be safely deleted.
|
|
740
721
|
*/
|
|
741
|
-
async function
|
|
742
|
-
const
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
722
|
+
export async function noticeObsoleteFiles(projectRoot) {
|
|
723
|
+
const obsolete = [];
|
|
724
|
+
const scriptsDir = join(projectRoot, '.github', 'scripts');
|
|
725
|
+
if (existsSync(scriptsDir)) {
|
|
726
|
+
try {
|
|
727
|
+
const entries = await readdir(scriptsDir);
|
|
728
|
+
if (entries.some((f) => f.startsWith('hula-') && f.endsWith('.sh'))) {
|
|
729
|
+
obsolete.push('.github/scripts/hula-*.sh');
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
catch {
|
|
733
|
+
// Unreadable dir — skip the notice rather than fail init.
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
for (const name of [
|
|
737
|
+
'planning-instructions.md',
|
|
738
|
+
'proceed-instructions.md',
|
|
739
|
+
'skill-creation-instructions.md',
|
|
740
|
+
]) {
|
|
741
|
+
if (existsSync(join(projectRoot, '.hublaunch', name))) {
|
|
742
|
+
obsolete.push(`.hublaunch/${name}`);
|
|
743
|
+
break;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (obsolete.length > 0) {
|
|
747
|
+
logger.blank();
|
|
748
|
+
logger.info('ℹ️ These hula files are now obsolete and safe to delete (scripts & instructions ship with the hula package):');
|
|
749
|
+
for (const f of obsolete) {
|
|
750
|
+
logger.listItem(f, 1);
|
|
751
|
+
}
|
|
755
752
|
}
|
|
756
753
|
}
|
|
757
754
|
/**
|
|
@@ -770,8 +767,6 @@ const VSCODE_AUTO_APPROVE_SETTINGS = {
|
|
|
770
767
|
'/^gh (issue view|pr list|pr view|pr diff|repo view)\\b/': true,
|
|
771
768
|
// GitHub CLI write commands used by hula workflows
|
|
772
769
|
'/^gh pr (comment|merge)\\b/': true,
|
|
773
|
-
// Hula bash scripts deployed to .github/scripts/
|
|
774
|
-
'/^bash \\.github\\/scripts\\/hula-/': true,
|
|
775
770
|
// Common safe commands
|
|
776
771
|
'/^(ls|cat|head|tail|wc|echo|mkdir|rm -f|cd|pwd)\\b/': true,
|
|
777
772
|
};
|
|
@@ -807,10 +802,10 @@ async function initVsCodeAutoApproval(projectRoot) {
|
|
|
807
802
|
await writeFile(settingsPath, content, 'utf-8');
|
|
808
803
|
logger.success('VS Code auto-approval configured: .vscode/settings.json');
|
|
809
804
|
}
|
|
810
|
-
/** The hook command registered in .claude/settings.json
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
const CLAUDE_SESSION_HOOK_COMMAND = '
|
|
805
|
+
/** The hook command registered in .claude/settings.json. Runs the global
|
|
806
|
+
* `hula` bin (cross-platform, no bash/jq) instead of a project-local shell
|
|
807
|
+
* script, so no file is written into the consumer repo. */
|
|
808
|
+
const CLAUDE_SESSION_HOOK_COMMAND = 'hula session-hook';
|
|
814
809
|
/**
|
|
815
810
|
* Register the hula session hook in the consumer repo's .claude/settings.json.
|
|
816
811
|
*
|
|
@@ -821,7 +816,7 @@ const CLAUDE_SESSION_HOOK_COMMAND = 'bash .github/scripts/hula-session-hook.sh';
|
|
|
821
816
|
* populate, so this merges: it preserves every existing hook and appends ours
|
|
822
817
|
* only when absent (idempotent by the command string).
|
|
823
818
|
*/
|
|
824
|
-
async function initClaudeSessionHook(projectRoot) {
|
|
819
|
+
export async function initClaudeSessionHook(projectRoot) {
|
|
825
820
|
const claudeDir = join(projectRoot, '.claude');
|
|
826
821
|
const settingsPath = join(claudeDir, 'settings.json');
|
|
827
822
|
await mkdir(claudeDir, { recursive: true });
|
|
@@ -1118,6 +1113,12 @@ export async function executeInit(options) {
|
|
|
1118
1113
|
envVarsLine =
|
|
1119
1114
|
'\n // envVars: ["TEST_USER_EMAIL", "API_KEY"], // Environment variables to forward to container (read from .env)';
|
|
1120
1115
|
}
|
|
1116
|
+
// Per-pipeline-step model/iteration overrides (hula-server PR #442). Rendered
|
|
1117
|
+
// as a real value when preserved across re-init, otherwise a commented example.
|
|
1118
|
+
const stepsDocsUrl = 'https://github.com/NoStackApp/hub-launch#configuring-per-step-model--iteration-overrides';
|
|
1119
|
+
const stepsLine = finalConfig.steps
|
|
1120
|
+
? `\n steps: ${JSON.stringify(finalConfig.steps)}, // Per-pipeline-step model/iteration overrides. Keys/fields/ranges: ${stepsDocsUrl}`
|
|
1121
|
+
: `\n // steps: { implementation: { model: "opus" }, regression: { skip: true } }, // Per-pipeline-step model/iteration overrides. Keys/fields/ranges: ${stepsDocsUrl}`;
|
|
1121
1122
|
const configContent = `export const config = {${versionLine}
|
|
1122
1123
|
// API Configuration${apiKeyLine}${anthropicKeyLine}${daytonaKeyLine}${daytonaTierLine}${containerResourcesLine}${updateNotificationUrlLine}${updateNotificationNameTagLine}${usageTierLine}
|
|
1123
1124
|
|
|
@@ -1132,7 +1133,7 @@ export async function executeInit(options) {
|
|
|
1132
1133
|
|
|
1133
1134
|
// Worktree base path (used by /hula-fix, /hula-merge, /hula-upload)
|
|
1134
1135
|
worktreeBasePath: "${(finalConfig.worktreeBasePath || '.hula-worktrees').replace(/\\/g, '\\\\').replace(/"/g, '\\"')}",
|
|
1135
|
-
${envVarsLine}${buildPreservedSection(finalConfig)}
|
|
1136
|
+
${envVarsLine}${stepsLine}${buildPreservedSection(finalConfig)}
|
|
1136
1137
|
};
|
|
1137
1138
|
`;
|
|
1138
1139
|
// Create directory if it doesn't exist
|
|
@@ -1168,22 +1169,30 @@ ${envVarsLine}${buildPreservedSection(finalConfig)}
|
|
|
1168
1169
|
if (existsSync(gitignorePath)) {
|
|
1169
1170
|
gitignoreContent = await import('fs/promises').then((fs) => fs.readFile(gitignorePath, 'utf-8'));
|
|
1170
1171
|
}
|
|
1172
|
+
const originalGitignoreContent = gitignoreContent;
|
|
1171
1173
|
// Check if hublaunch.config.js is already in .gitignore
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
? '# HubLaunch configuration\nhublaunch.config.js\n'
|
|
1176
|
-
: '\n# HubLaunch configuration\nhublaunch.config.js\n';
|
|
1177
|
-
gitignoreContent += newEntry;
|
|
1178
|
-
await import('fs/promises').then((fs) => fs.writeFile(gitignorePath, gitignoreContent, 'utf-8'));
|
|
1174
|
+
const beforeConfig = gitignoreContent;
|
|
1175
|
+
gitignoreContent = appendGitignoreEntry(gitignoreContent, 'hublaunch.config.js', '# HubLaunch configuration', 'hublaunch.config.js');
|
|
1176
|
+
if (gitignoreContent !== beforeConfig) {
|
|
1179
1177
|
logger.success('✨ Added hublaunch.config.js to .gitignore');
|
|
1180
1178
|
}
|
|
1181
1179
|
// Check if worktree base path is already in .gitignore (skip absolute paths — they're outside the repo)
|
|
1182
|
-
if (!isAbsolute(worktreeBasePath)
|
|
1183
|
-
|
|
1184
|
-
gitignoreContent
|
|
1180
|
+
if (!isAbsolute(worktreeBasePath)) {
|
|
1181
|
+
const beforeWorktree = gitignoreContent;
|
|
1182
|
+
gitignoreContent = appendGitignoreEntry(gitignoreContent, worktreeBasePath, '# HubLaunch worktrees', `${worktreeBasePath}/`);
|
|
1183
|
+
if (gitignoreContent !== beforeWorktree) {
|
|
1184
|
+
logger.success(`✨ Added ${worktreeBasePath}/ to .gitignore`);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
// Ignore the repo-local scratch dir hula-verify writes its report/diff/
|
|
1188
|
+
// comment files into.
|
|
1189
|
+
const beforeTmp = gitignoreContent;
|
|
1190
|
+
gitignoreContent = appendGitignoreEntry(gitignoreContent, '.hublaunch/tmp', '# HubLaunch verify report/diff scratch files', '.hublaunch/tmp/');
|
|
1191
|
+
if (gitignoreContent !== beforeTmp) {
|
|
1192
|
+
logger.success('✨ Added .hublaunch/tmp/ to .gitignore');
|
|
1193
|
+
}
|
|
1194
|
+
if (gitignoreContent !== originalGitignoreContent) {
|
|
1185
1195
|
await import('fs/promises').then((fs) => fs.writeFile(gitignorePath, gitignoreContent, 'utf-8'));
|
|
1186
|
-
logger.success(`✨ Added ${worktreeBasePath}/ to .gitignore`);
|
|
1187
1196
|
}
|
|
1188
1197
|
// Warn if .agents/skills is in .gitignore — it must be committed so all
|
|
1189
1198
|
// team members get GitHub Copilot and Claude Code support.
|
|
@@ -1232,18 +1241,16 @@ ${envVarsLine}${buildPreservedSection(finalConfig)}
|
|
|
1232
1241
|
logger.blank();
|
|
1233
1242
|
logger.info('Generating templates directory structure...');
|
|
1234
1243
|
await generateTemplatesStructure(repoRoot);
|
|
1235
|
-
//
|
|
1244
|
+
// Ensure the .hublaunch/skills/ action-file directory exists. Instruction
|
|
1245
|
+
// documents are no longer copied here — skills read them from the package via
|
|
1246
|
+
// `hula instructions <name>`.
|
|
1236
1247
|
logger.blank();
|
|
1237
|
-
logger.info('
|
|
1238
|
-
await
|
|
1248
|
+
logger.info('Ensuring .hublaunch/skills/ action directory...');
|
|
1249
|
+
await initializeSkillsActionDir(repoRoot);
|
|
1239
1250
|
// Initialize Agent Skills for AI-assisted planning (works with Copilot, Claude Code, and others)
|
|
1240
1251
|
logger.blank();
|
|
1241
1252
|
logger.info('Setting up Agent Skills for AI-assisted planning...');
|
|
1242
|
-
await initializeAgentSkills(repoRoot);
|
|
1243
|
-
// Initialize bundled shell scripts for chat participant workflows
|
|
1244
|
-
logger.blank();
|
|
1245
|
-
logger.info('Setting up bundled shell scripts for chat workflows...');
|
|
1246
|
-
await initializeScriptFiles(repoRoot);
|
|
1253
|
+
await initializeAgentSkills(repoRoot, options?.withClaudeCommands ?? false);
|
|
1247
1254
|
// Register the Claude Code session hook (clientSessionId provenance)
|
|
1248
1255
|
logger.blank();
|
|
1249
1256
|
logger.info('Registering Claude Code session hook...');
|
|
@@ -1254,6 +1261,8 @@ ${envVarsLine}${buildPreservedSection(finalConfig)}
|
|
|
1254
1261
|
logger.info('Configuring VS Code auto-approval for hula agent commands...');
|
|
1255
1262
|
await initVsCodeAutoApproval(repoRoot);
|
|
1256
1263
|
}
|
|
1264
|
+
// Non-destructive migration notice for repos initialized by an older hula.
|
|
1265
|
+
await noticeObsoleteFiles(repoRoot);
|
|
1257
1266
|
logger.blank();
|
|
1258
1267
|
logger.blank();
|
|
1259
1268
|
logger.info('Next steps:');
|
|
@@ -1263,6 +1272,7 @@ ${envVarsLine}${buildPreservedSection(finalConfig)}
|
|
|
1263
1272
|
logger.listItem('📝 Edit .hublaunch/hublaunch.config.js to customize (each field is documented inline):', 1);
|
|
1264
1273
|
logger.listItem('daytonaTier, containerResources — sandbox sizing', 2);
|
|
1265
1274
|
logger.listItem('teamMembers, envVars — project specifics', 2);
|
|
1275
|
+
logger.listItem('steps — per-pipeline-step model & iteration overrides', 2);
|
|
1266
1276
|
logger.listItem('updateNotificationUrl, updateNotificationNameTag — Slack notifications', 2);
|
|
1267
1277
|
// Show credential setup instructions based on selected services
|
|
1268
1278
|
if (authProvider !== 'none') {
|
|
@@ -1278,6 +1288,7 @@ ${envVarsLine}${buildPreservedSection(finalConfig)}
|
|
|
1278
1288
|
logger.listItem("Run 'hublaunch create' to create your first issue", 1);
|
|
1279
1289
|
logger.blank();
|
|
1280
1290
|
logger.info('💡 Or use the Agent Skills slash commands in any AI chat:');
|
|
1291
|
+
logger.info(' - /hula-help [topic] - Interactive guide: getting started, workflow, commands, config');
|
|
1281
1292
|
logger.info(' - /hula-plan <description> - Generate implementation plan');
|
|
1282
1293
|
logger.info(' - /hula-confirm - Validate and refine the plan');
|
|
1283
1294
|
logger.info(' - /hula-upload - Upload plan to origin/main');
|