hub-launch 1.27.0 → 1.29.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 +12 -0
- package/README.md +2 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +2 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/launch.d.ts +6 -0
- package/dist/commands/launch.d.ts.map +1 -1
- package/dist/commands/launch.js +47 -54
- package/dist/commands/launch.js.map +1 -1
- package/dist/commands/schedule.d.ts.map +1 -1
- package/dist/commands/schedule.js +20 -2
- package/dist/commands/schedule.js.map +1 -1
- package/dist/commands/upload.d.ts +10 -0
- package/dist/commands/upload.d.ts.map +1 -1
- package/dist/commands/upload.js +58 -2
- package/dist/commands/upload.js.map +1 -1
- package/dist/services/git/FilePublishService.d.ts +7 -0
- package/dist/services/git/FilePublishService.d.ts.map +1 -1
- package/dist/services/git/FilePublishService.js +10 -4
- package/dist/services/git/FilePublishService.js.map +1 -1
- package/dist/services/plan/PlanBranchService.d.ts +38 -0
- package/dist/services/plan/PlanBranchService.d.ts.map +1 -0
- package/dist/services/plan/PlanBranchService.js +95 -0
- package/dist/services/plan/PlanBranchService.js.map +1 -0
- package/dist/templates/proceed-instructions.md +3 -2
- package/dist/templates/skills/hula-help/SKILL.md +1 -1
- package/dist/templates/skills/hula-launch/SKILL.md +2 -2
- package/dist/templates/skills/hula-plan/SKILL.md +18 -2
- package/dist/templates/skills/hula-research/SKILL.md +162 -0
- package/dist/templates/skills/hula-upload/SKILL.md +2 -2
- package/dist/utils/validators.d.ts +8 -0
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/utils/validators.js +10 -0
- package/dist/utils/validators.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.mjs +1 -0
|
@@ -115,8 +115,11 @@ export class FilePublishService {
|
|
|
115
115
|
* commit (with `commitMessage`) if it produced changes, push to the branch,
|
|
116
116
|
* and always remove the worktree afterward.
|
|
117
117
|
*/
|
|
118
|
-
async withWorktree(type, branch, commitMessage, operation) {
|
|
118
|
+
async withWorktree(type, branch, commitMessage, operation, createFromRef) {
|
|
119
119
|
this.validateBranch(branch);
|
|
120
|
+
if (createFromRef !== undefined) {
|
|
121
|
+
this.validateBranch(createFromRef);
|
|
122
|
+
}
|
|
120
123
|
const worktreeBasePath = await this.resolveWorktreeBasePath();
|
|
121
124
|
const repoInfo = await getRepoInfo(this.cwd);
|
|
122
125
|
const worktreeService = new WorktreeService({
|
|
@@ -129,7 +132,7 @@ export class FilePublishService {
|
|
|
129
132
|
const worktreePath = worktreeService.getWorktreeDir(type, identifier);
|
|
130
133
|
let worktreeCreated = false;
|
|
131
134
|
try {
|
|
132
|
-
await worktreeService.createWorktreeAt(worktreePath, `origin/${branch}`, true);
|
|
135
|
+
await worktreeService.createWorktreeAt(worktreePath, createFromRef ?? `origin/${branch}`, true);
|
|
133
136
|
worktreeCreated = true;
|
|
134
137
|
operation(worktreePath);
|
|
135
138
|
const hasChanges = await worktreeService.hasChangesAt(worktreePath);
|
|
@@ -149,7 +152,10 @@ export class FilePublishService {
|
|
|
149
152
|
let lastError;
|
|
150
153
|
for (let attempt = 1; attempt <= MAX_PUSH_ATTEMPTS; attempt++) {
|
|
151
154
|
try {
|
|
152
|
-
|
|
155
|
+
// Fully-qualified destination so the push also CREATES the branch on
|
|
156
|
+
// origin when it does not exist yet (an unqualified `HEAD:<branch>`
|
|
157
|
+
// is rejected for a nonexistent destination ref).
|
|
158
|
+
await worktreeService.pushAt(worktreePath, `HEAD:refs/heads/${branch}`);
|
|
153
159
|
lastError = undefined;
|
|
154
160
|
break; // pushed successfully
|
|
155
161
|
}
|
|
@@ -206,7 +212,7 @@ export class FilePublishService {
|
|
|
206
212
|
const filePath = join(worktreePath, relativePath);
|
|
207
213
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
208
214
|
writeFileSync(filePath, content, 'utf-8');
|
|
209
|
-
});
|
|
215
|
+
}, opts?.createFromRef);
|
|
210
216
|
}
|
|
211
217
|
/**
|
|
212
218
|
* Delete a file from the target branch.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilePublishService.js","sourceRoot":"","sources":["../../../src/services/git/FilePublishService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD;;;GAGG;AACH,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B;;;;GAIG;AACH,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B;;;;;GAKG;AACH,MAAM,eAAe,GAAG;IACtB,iBAAiB;IACjB,0BAA0B;IAC1B,mBAAmB;IACnB,aAAa;IACb,kBAAkB;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAChC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC;
|
|
1
|
+
{"version":3,"file":"FilePublishService.js","sourceRoot":"","sources":["../../../src/services/git/FilePublishService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Config } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Outcome of {@link ensurePlanBranch}.
|
|
4
|
+
*/
|
|
5
|
+
export interface EnsurePlanBranchResult {
|
|
6
|
+
/** The git branch name the plan lives on (sanitized issue name). */
|
|
7
|
+
branch: string;
|
|
8
|
+
/** True when the branch was created on origin by this call. */
|
|
9
|
+
created: boolean;
|
|
10
|
+
/** True when the plan file on the branch was written/refreshed by this call. */
|
|
11
|
+
updated: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Thrown when the plan file cannot be found anywhere — not on disk, not on
|
|
15
|
+
* the feature branch, not on the base branch. Callers translate this into the
|
|
16
|
+
* historical "Plan not found locally or on origin/main" error handling.
|
|
17
|
+
*/
|
|
18
|
+
export declare class PlanNotFoundError extends Error {
|
|
19
|
+
constructor(planPath: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Ensure the feature branch for `issueName` exists on origin and carries the
|
|
23
|
+
* current plan file — the core of the plan-branch flow.
|
|
24
|
+
*
|
|
25
|
+
* - Branch missing on origin → create it from `origin/<uploadBranch ?? main>`
|
|
26
|
+
* with the plan committed (one worktree publish, one push).
|
|
27
|
+
* - Branch exists but the plan file on it is missing or stale → publish the
|
|
28
|
+
* fresh content to the branch.
|
|
29
|
+
* - Branch exists with identical content → no-op.
|
|
30
|
+
*
|
|
31
|
+
* This runs BEFORE the beforeLaunch hook in `hula launch`, so hooks (e.g.
|
|
32
|
+
* Vercel branch-scoped env vars) can rely on the git branch existing on the
|
|
33
|
+
* remote. It is also invoked at plan time via `hula upload --branch`.
|
|
34
|
+
*
|
|
35
|
+
* @throws PlanNotFoundError when the plan content cannot be resolved anywhere.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ensurePlanBranch(config: Config, planPath: string, issueName: string, repoRoot?: string): Promise<EnsurePlanBranchResult>;
|
|
38
|
+
//# sourceMappingURL=PlanBranchService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlanBranchService.d.ts","sourceRoot":"","sources":["../../../src/services/plan/PlanBranchService.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAMnD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,QAAQ,EAAE,MAAM;CAI7B;AAmCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,sBAAsB,CAAC,CAsDjC"}
|
|
@@ -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
|
|
382
|
-
2. **
|
|
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` —
|
|
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`
|
|
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:
|
|
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
|
|
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.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hula-research
|
|
3
|
+
description: Research a codebase and present a clear, digestible R&D report. Use when the user wants to understand how the code works, get an architecture overview, or investigate a specific area, feature, or subsystem.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
argument-hint: "[topic or area to focus on — omit for a whole-codebase overview]"
|
|
6
|
+
allowed-tools: Bash Read
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are an expert software researcher for the HubLaunch workflow. Your job is to go through the code, do the R&D, and present the user a report that is **easy to absorb yet complete on the things that matter**.
|
|
10
|
+
|
|
11
|
+
## Golden rules
|
|
12
|
+
|
|
13
|
+
1. **Read-only.** This is research, not implementation. **Never edit, create, move, or delete any file**, and never run commands that change state (no `git commit`, `git checkout`, `npm install`, writes, etc.). Only read and search.
|
|
14
|
+
2. **Digestible first, deep second.** Lead with a short summary the user can read in 30 seconds. Put detail below it, structured so the reader can stop early. Do not dump everything you found.
|
|
15
|
+
3. **Ground every claim in the code.** Reference real files and line numbers (e.g. `src/services/git/GitService.ts:58`). If you are inferring rather than confirming, say so.
|
|
16
|
+
4. **One simple diagram, when it helps.** Use a plain ASCII/box-and-arrow diagram — **never Mermaid** or any other rendered diagram syntax. Keep it small enough to read at a glance.
|
|
17
|
+
|
|
18
|
+
## Input
|
|
19
|
+
|
|
20
|
+
Research request: $ARGUMENTS
|
|
21
|
+
|
|
22
|
+
### Scope detection
|
|
23
|
+
|
|
24
|
+
- **If an argument is provided** (a topic, area, feature, file, or question — e.g. `/hula-research the launch pipeline` or `/hula-research how auth tokens flow`): scope the research to that topic. Go **deeper** on it; ignore unrelated parts of the codebase except where they connect.
|
|
25
|
+
- **If no argument is provided**: produce a **whole-codebase architecture overview** — breadth over depth. Cover what the project is, its major pieces, and how they fit together.
|
|
26
|
+
|
|
27
|
+
If the argument is genuinely ambiguous (could mean two very different things), ask **one** short clarifying question, then proceed.
|
|
28
|
+
|
|
29
|
+
## Research workflow
|
|
30
|
+
|
|
31
|
+
Do this analysis **before** writing the report. Work efficiently — you do not need to read every file, but you must not guess at the important ones.
|
|
32
|
+
|
|
33
|
+
1. **Orient.** Read the entry points and the map of the project: `package.json` (scripts, bin, deps), `README.md`, `tsconfig.json`, top-level `src/` layout, and any CLAUDE.md / docs. Establish what the project *is* and how it runs.
|
|
34
|
+
2. **Map the structure.** Identify the major directories and what each is responsible for (commands, services, types, config, templates, utils, etc.). Note the naming conventions and patterns in use.
|
|
35
|
+
3. **Trace the important paths.** For the chosen scope, follow the real flow: entry point → command → service(s) → external calls → output. Read the type definitions that describe the data shapes. Follow imports to understand how pieces connect.
|
|
36
|
+
4. **Find the load-bearing pieces.** Identify the files, services, or abstractions that the rest of the code depends on most. These deserve the most attention in the report.
|
|
37
|
+
5. **Note the rough edges.** Spot anything worth flagging: complexity hot spots, duplication, TODO/FIXME markers, tight coupling, missing tests, or surprising design choices. Be honest but fair.
|
|
38
|
+
|
|
39
|
+
Use whatever read-only search and file tools the harness provides (codebase/semantic search, file reads, `grep`, `git log`/`git blame` for history). Prefer reading source over assuming.
|
|
40
|
+
|
|
41
|
+
## Report format
|
|
42
|
+
|
|
43
|
+
Present the report **in chat** (do not write it to a file). Use this layered structure so the reader can stop reading whenever they have enough:
|
|
44
|
+
|
|
45
|
+
```markdown
|
|
46
|
+
# 🔬 Research: <topic, or "Codebase Overview">
|
|
47
|
+
|
|
48
|
+
## TL;DR
|
|
49
|
+
<2–4 sentences. What this is, and the single most important thing to understand. A busy reader should be able to stop here.>
|
|
50
|
+
|
|
51
|
+
## Key Findings
|
|
52
|
+
- <3–7 punchy bullets — the things that actually matter. Each ties to a concrete place in the code.>
|
|
53
|
+
|
|
54
|
+
## How it fits together
|
|
55
|
+
<One ASCII diagram (see guidelines below) + 2–4 sentences walking through it.>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then, **below the summary**, include the deeper material. Put each deep section inside a collapsible block so the report stays scannable (fall back to plain `###` headings if the harness doesn't render `<details>`):
|
|
59
|
+
|
|
60
|
+
```markdown
|
|
61
|
+
<details>
|
|
62
|
+
<summary><b>Components & responsibilities</b></summary>
|
|
63
|
+
|
|
64
|
+
- **<Component>** (`path`) — what it does, who calls it, what it depends on.
|
|
65
|
+
- ...
|
|
66
|
+
</details>
|
|
67
|
+
|
|
68
|
+
<details>
|
|
69
|
+
<summary><b>Data & control flow</b></summary>
|
|
70
|
+
|
|
71
|
+
<Step-by-step of the key path, with file:line references.>
|
|
72
|
+
</details>
|
|
73
|
+
|
|
74
|
+
<details>
|
|
75
|
+
<summary><b>Patterns & conventions</b></summary>
|
|
76
|
+
|
|
77
|
+
<Naming, structure, error handling, config, testing patterns worth knowing before touching the code.>
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
<details>
|
|
81
|
+
<summary><b>Key files to know</b></summary>
|
|
82
|
+
|
|
83
|
+
| File | Why it matters |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `src/...` | ... |
|
|
86
|
+
</details>
|
|
87
|
+
|
|
88
|
+
<details>
|
|
89
|
+
<summary><b>Risks, gaps & open questions</b></summary>
|
|
90
|
+
|
|
91
|
+
- ⚠️ <complexity / coupling / missing tests / tech debt>
|
|
92
|
+
- ❓ <anything you could not determine from the code>
|
|
93
|
+
</details>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
End with a short pointer block (not collapsed):
|
|
97
|
+
|
|
98
|
+
```markdown
|
|
99
|
+
## Where to dig next
|
|
100
|
+
- To change X, start at `src/...`
|
|
101
|
+
- Related area worth a follow-up `/hula-research <topic>`: ...
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Scale the report to the scope: a **topic-focused** request should go deep on that topic; a **whole-codebase overview** should stay broad and keep each section short. Never let the deep sections bury the TL;DR and Key Findings.
|
|
105
|
+
|
|
106
|
+
## ASCII diagram guidelines
|
|
107
|
+
|
|
108
|
+
Include **one** diagram when it clarifies structure or flow (most reports benefit from one; skip it only if it would add nothing). Rules:
|
|
109
|
+
|
|
110
|
+
- **ASCII only — no Mermaid, no PlantUML, no image syntax.** It must render as plain text in any chat.
|
|
111
|
+
- Keep it small: a handful of boxes and arrows, not a wall of ASCII art.
|
|
112
|
+
- Use boxes for components and arrows (`──▶`, `│`, `▼`) for flow or dependency direction.
|
|
113
|
+
- Label arrows when the relationship isn't obvious.
|
|
114
|
+
|
|
115
|
+
Example (a flow diagram):
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
User
|
|
119
|
+
│ /hula-launch <branch>
|
|
120
|
+
▼
|
|
121
|
+
┌─────────────┐ reads ┌──────────────────┐
|
|
122
|
+
│ launch.ts │ ───────────▶ │ hublaunch.config│
|
|
123
|
+
└──────┬──────┘ └──────────────────┘
|
|
124
|
+
│ POST job
|
|
125
|
+
▼
|
|
126
|
+
┌──────────────────┐ runs ┌───────────────────┐
|
|
127
|
+
│ HulaApiClient │ ──────▶ │ hula-project server│
|
|
128
|
+
└──────────────────┘ │ (Claude Code in │
|
|
129
|
+
│ cloud container) │
|
|
130
|
+
└─────────┬─────────┘
|
|
131
|
+
│ opens
|
|
132
|
+
▼
|
|
133
|
+
GitHub PR
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Example (a layered/module diagram):
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
┌──────────────────────────────────────────────┐
|
|
140
|
+
│ commands/ (CLI surface: create, launch …) │
|
|
141
|
+
└───────────────┬──────────────────────────────┘
|
|
142
|
+
│ calls
|
|
143
|
+
▼
|
|
144
|
+
┌──────────────────────────────────────────────┐
|
|
145
|
+
│ services/ (github, git, api, logs, …) │
|
|
146
|
+
└───────────────┬──────────────────────────────┘
|
|
147
|
+
│ uses
|
|
148
|
+
▼
|
|
149
|
+
┌──────────────────────────────────────────────┐
|
|
150
|
+
│ utils/ • types/ • config/ (shared core) │
|
|
151
|
+
└──────────────────────────────────────────────┘
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Quality bar
|
|
155
|
+
|
|
156
|
+
- ✅ Scope correctly detected (topic-focused vs. whole-codebase overview)
|
|
157
|
+
- ✅ TL;DR + Key Findings let a reader grasp the gist in under a minute
|
|
158
|
+
- ✅ All important aspects covered, deeper detail available but not overwhelming
|
|
159
|
+
- ✅ One clear ASCII diagram (never Mermaid) when it helps
|
|
160
|
+
- ✅ Claims grounded in real `file:line` references; inferences labeled as such
|
|
161
|
+
- ✅ Honest about risks, gaps, and what couldn't be determined
|
|
162
|
+
- ✅ **Nothing was modified** — read-only throughout
|
|
@@ -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
|
|
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
|
|
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"}
|
package/dist/utils/validators.js
CHANGED
|
@@ -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