@tsuzuku/arise 0.2.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/README.md +125 -0
- package/arise.schema.json +130 -0
- package/bin/cli.js +8 -0
- package/index.js +37 -0
- package/lib/cli.js +129 -0
- package/lib/config.js +229 -0
- package/lib/context.js +113 -0
- package/lib/git.js +306 -0
- package/lib/herdr.js +217 -0
- package/lib/layout.js +88 -0
- package/lib/lifecycle/create.js +131 -0
- package/lib/lifecycle/nuke.js +218 -0
- package/lib/skill.js +200 -0
- package/package.json +42 -0
- package/presets/generic.js +33 -0
- package/presets/index.js +39 -0
- package/presets/laravel.js +115 -0
- package/presets/node.js +50 -0
- package/skills/arise/SKILL.md +86 -0
- package/types.d.ts +157 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
name: 'generic',
|
|
6
|
+
|
|
7
|
+
detect(cwd) {
|
|
8
|
+
return true; // Fallback preset
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
repo: {
|
|
12
|
+
defaultBaseBranch: 'main',
|
|
13
|
+
protectedBranches: ['main', 'master', 'develop', 'prod', 'staging', 'production'],
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
workspace: {
|
|
17
|
+
labelPrefix: '',
|
|
18
|
+
defaultFocus: 'agy',
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
layout: [
|
|
22
|
+
{ id: 'vim', title: 'vim', cmd: 'vim .', position: 'root' },
|
|
23
|
+
{ id: 'shell', title: 'shell', cmd: null, split: 'right', from: 'vim' },
|
|
24
|
+
{ id: 'agy', title: 'agy', cmd: 'agy', split: 'down', from: 'shell', focus: true, isAgent: true },
|
|
25
|
+
],
|
|
26
|
+
|
|
27
|
+
hooks: {
|
|
28
|
+
async onScaffold(ctx) {
|
|
29
|
+
// Copy .env from root if available
|
|
30
|
+
ctx.copyFromRoot('.env', '.env');
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
package/presets/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const nodePreset = require('./node');
|
|
2
|
+
const laravelPreset = require('./laravel');
|
|
3
|
+
const genericPreset = require('./generic');
|
|
4
|
+
|
|
5
|
+
const builtInPresets = [
|
|
6
|
+
laravelPreset, // Check Laravel/PHP before generic
|
|
7
|
+
nodePreset, // Check Node before generic
|
|
8
|
+
genericPreset, // Catch-all fallback
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
function getPreset(name) {
|
|
12
|
+
if (!name) return null;
|
|
13
|
+
const normalized = name.toLowerCase().trim();
|
|
14
|
+
if (normalized === 'php' || normalized === 'laravel' || normalized === 'api' || normalized === 'be') {
|
|
15
|
+
return laravelPreset;
|
|
16
|
+
}
|
|
17
|
+
if (normalized === 'node' || normalized === 'js' || normalized === 'ts' || normalized === 'fe' || normalized === 'react') {
|
|
18
|
+
return nodePreset;
|
|
19
|
+
}
|
|
20
|
+
if (normalized === 'generic' || normalized === 'default') {
|
|
21
|
+
return genericPreset;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function detectPreset(cwd = process.cwd()) {
|
|
27
|
+
for (const preset of builtInPresets) {
|
|
28
|
+
if (typeof preset.detect === 'function' && preset.detect(cwd)) {
|
|
29
|
+
return preset;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return genericPreset;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
getPreset,
|
|
37
|
+
detectPreset,
|
|
38
|
+
builtInPresets,
|
|
39
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const git = require('../lib/git');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
name: 'laravel',
|
|
7
|
+
|
|
8
|
+
detect(cwd) {
|
|
9
|
+
return fs.existsSync(path.join(cwd, 'artisan')) || fs.existsSync(path.join(cwd, 'composer.json'));
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
repo: {
|
|
13
|
+
defaultBaseBranch: 'main',
|
|
14
|
+
protectedBranches: ['staging', 'prod', 'master', 'main', 'develop'],
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
workspace: {
|
|
18
|
+
labelPrefix: '',
|
|
19
|
+
defaultFocus: 'agy',
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
layout: [
|
|
23
|
+
{ id: 'vim', title: 'vim', cmd: 'vim .', position: 'root' },
|
|
24
|
+
{ id: 'logs', title: 'logs', cmd: 'tail -f storage/logs/laravel.log', split: 'right', from: 'vim' },
|
|
25
|
+
{ id: 'shell', title: 'shell', cmd: null, split: 'down', from: 'vim' },
|
|
26
|
+
{ id: 'agy', title: 'agy', cmd: 'agy', split: 'down', from: 'logs', focus: true, isAgent: true },
|
|
27
|
+
],
|
|
28
|
+
|
|
29
|
+
hooks: {
|
|
30
|
+
async onSyncPrimary(ctx) {
|
|
31
|
+
git.syncPrimaryBranch({
|
|
32
|
+
branch: ctx.branch,
|
|
33
|
+
worktreePath: ctx.worktreePath,
|
|
34
|
+
repoDir: ctx.repoRoot,
|
|
35
|
+
bareRepo: ctx.bareRepo,
|
|
36
|
+
protectedBranches: ['staging', 'prod', 'master', 'main', 'develop'],
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
async onScaffold(ctx) {
|
|
41
|
+
// 1. Environment (.env) Setup
|
|
42
|
+
console.log('==> Ensuring .env file...');
|
|
43
|
+
const rootEnv = ctx.repoRoot ? path.join(ctx.repoRoot, '.env') : null;
|
|
44
|
+
const targetEnv = path.join(ctx.worktreePath, '.env');
|
|
45
|
+
|
|
46
|
+
if (!fs.existsSync(targetEnv)) {
|
|
47
|
+
if (ctx.config.scaffold && ctx.config.scaffold.envSource && fs.existsSync(ctx.config.scaffold.envSource)) {
|
|
48
|
+
ctx.copyFile(ctx.config.scaffold.envSource, targetEnv);
|
|
49
|
+
} else if (rootEnv && fs.existsSync(rootEnv)) {
|
|
50
|
+
ctx.copyFile(rootEnv, targetEnv);
|
|
51
|
+
} else {
|
|
52
|
+
console.warn('==> No .env source found to copy.');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. Dependencies & Initialization
|
|
57
|
+
console.log('==> Initializing repository (permissions, composer, etc.)...');
|
|
58
|
+
try {
|
|
59
|
+
const installCmd = (ctx.config.scaffold && ctx.config.scaffold.install !== undefined)
|
|
60
|
+
? ctx.config.scaffold.install
|
|
61
|
+
: 'composer install --no-interaction';
|
|
62
|
+
|
|
63
|
+
if (installCmd) {
|
|
64
|
+
console.log(`Running dependency installation: "${installCmd}" in "${ctx.worktreePath}"...`);
|
|
65
|
+
ctx.exec(installCmd);
|
|
66
|
+
} else {
|
|
67
|
+
console.log('Skipping composer installation (scaffold.install is disabled).');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const permissionsScript = `
|
|
71
|
+
mkdir -p storage/logs
|
|
72
|
+
chmod 777 storage/logs
|
|
73
|
+
touch storage/logs/laravel.log
|
|
74
|
+
chmod 666 storage/logs/laravel.log
|
|
75
|
+
mkdir -p storage/framework/sessions
|
|
76
|
+
chmod o+w storage/framework/sessions
|
|
77
|
+
mkdir -p storage/framework/data
|
|
78
|
+
chmod o+w storage/framework/data
|
|
79
|
+
mkdir -p storage/framework/cache/data
|
|
80
|
+
chmod 777 storage/framework/cache/data
|
|
81
|
+
mkdir -p bootstrap/cache
|
|
82
|
+
chmod 777 bootstrap/cache
|
|
83
|
+
mkdir -p storage/temp
|
|
84
|
+
chmod 777 storage/temp
|
|
85
|
+
if [ -d .githooks ]; then git config core.hooksPath .githooks; fi
|
|
86
|
+
`;
|
|
87
|
+
ctx.exec(permissionsScript);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.warn(`==> Warning during repository initialization: ${err.message}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 3. Update Web Server Symlink if configured
|
|
93
|
+
const symlinkPath = ctx.config.scaffold && ctx.config.scaffold.symlink;
|
|
94
|
+
if (symlinkPath) {
|
|
95
|
+
ctx.setSymlink(symlinkPath, ctx.worktreePath);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
async onPreNuke(ctx) {
|
|
100
|
+
const symlinkPath = ctx.config.scaffold && ctx.config.scaffold.symlink;
|
|
101
|
+
if (symlinkPath && fs.existsSync(symlinkPath)) {
|
|
102
|
+
try {
|
|
103
|
+
const lstat = fs.lstatSync(symlinkPath);
|
|
104
|
+
if (lstat.isSymbolicLink()) {
|
|
105
|
+
const currentTarget = fs.realpathSync(symlinkPath);
|
|
106
|
+
if (path.resolve(currentTarget) === path.resolve(ctx.worktreePath)) {
|
|
107
|
+
console.log(`==> Unlinking active web symlink "${symlinkPath}" pointing to nuked worktree...`);
|
|
108
|
+
fs.unlinkSync(symlinkPath);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (e) {}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
package/presets/node.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
name: 'node',
|
|
6
|
+
|
|
7
|
+
detect(cwd) {
|
|
8
|
+
return fs.existsSync(path.join(cwd, 'package.json'));
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
repo: {
|
|
12
|
+
defaultBaseBranch: 'develop',
|
|
13
|
+
protectedBranches: ['main', 'master', 'develop', 'prod', 'staging', 'production'],
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
workspace: {
|
|
17
|
+
labelPrefix: '',
|
|
18
|
+
defaultFocus: 'agy',
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
layout: [
|
|
22
|
+
{ id: 'vim', title: 'vim', cmd: 'vim .', position: 'root' },
|
|
23
|
+
{ id: 'server', title: 'npm server', cmd: 'npm run dev', split: 'right', from: 'vim' },
|
|
24
|
+
{ id: 'shell', title: 'shell', cmd: null, split: 'down', from: 'vim' },
|
|
25
|
+
{ id: 'agy', title: 'agy', cmd: 'agy', split: 'down', from: 'server', focus: true, isAgent: true },
|
|
26
|
+
],
|
|
27
|
+
|
|
28
|
+
hooks: {
|
|
29
|
+
async onScaffold(ctx) {
|
|
30
|
+
// 1. Copy .env from root if available
|
|
31
|
+
ctx.copyFromRoot('.env', '.env');
|
|
32
|
+
|
|
33
|
+
// 2. Install dependencies
|
|
34
|
+
const installCmd = (ctx.config.scaffold && ctx.config.scaffold.install !== undefined)
|
|
35
|
+
? ctx.config.scaffold.install
|
|
36
|
+
: 'npm install';
|
|
37
|
+
|
|
38
|
+
if (installCmd) {
|
|
39
|
+
console.log(`Running dependency installation: "${installCmd}" in "${ctx.worktreePath}"...`);
|
|
40
|
+
try {
|
|
41
|
+
ctx.exec(installCmd);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.warn(`Warning: Dependency installation exited with an error: ${err.message}`);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
console.log('Skipping dependency installation (scaffold.install is disabled).');
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: arise
|
|
3
|
+
description: User guide, CLI reference, and command executor for the `arise` utility (Git worktree and Herdr workspace orchestrator). Activate this skill whenever the user asks questions about how to use arise, how worktree orchestration works, how to configure `.ariserc.json` or `.worktreerc.json`, or asks the assistant to create, switch to, or nuke/clean up Git worktrees and Herdr workspaces on their behalf.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Arise Operator & Assistant Guide
|
|
7
|
+
|
|
8
|
+
Use this skill to answer questions about `arise` and run worktree management commands on the user's behalf.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. CLI Quick Reference & Cheatsheet
|
|
13
|
+
|
|
14
|
+
### Creating Worktrees
|
|
15
|
+
```bash
|
|
16
|
+
# Create or open a worktree for a branch (auto-detects preset, boots Herdr workspace)
|
|
17
|
+
arise --branch <branch-name>
|
|
18
|
+
|
|
19
|
+
# Create worktree based off a specific base branch (e.g. develop, prod, main)
|
|
20
|
+
arise --branch <branch-name> --base <base-branch>
|
|
21
|
+
|
|
22
|
+
# Custom directory name or workspace name
|
|
23
|
+
arise -b <branch-name> -d <dir-name> -w <workspace-name>
|
|
24
|
+
|
|
25
|
+
# Explicit preset or pane focus ('agy', 'vim', 'logs', 'server', 'shell')
|
|
26
|
+
arise -b <branch-name> --preset laravel --focus agy
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Nuking / Teardown
|
|
30
|
+
```bash
|
|
31
|
+
# Nuke active worktree (when run inside a worktree directory)
|
|
32
|
+
arise --nuke
|
|
33
|
+
|
|
34
|
+
# Nuke specific worktree by branch or directory name
|
|
35
|
+
arise --nuke <branch-or-dir>
|
|
36
|
+
|
|
37
|
+
# Remove directory only (keep local and remote git branches)
|
|
38
|
+
arise --nuke <target> --dir-only
|
|
39
|
+
|
|
40
|
+
# Delete local branch and directory, but keep remote branch on origin
|
|
41
|
+
arise --nuke <target> --keep-remote
|
|
42
|
+
|
|
43
|
+
# Force removal even if uncommitted changes exist
|
|
44
|
+
arise --nuke <target> --force
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 2. Configuration (`.ariserc.json` / `.worktreerc.json` / `arise.config.js`)
|
|
50
|
+
|
|
51
|
+
Projects can configure custom topology, bare repos, and layouts via `.ariserc.json` or `.worktreerc.json` in the repository root or base directory:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"preset": "laravel",
|
|
56
|
+
"repo": {
|
|
57
|
+
"bareRepo": "/path/to/bare.git",
|
|
58
|
+
"worktreesBase": "/path/to/worktrees",
|
|
59
|
+
"defaultBaseBranch": "develop",
|
|
60
|
+
"protectedBranches": ["main", "master", "develop", "prod", "staging"]
|
|
61
|
+
},
|
|
62
|
+
"workspace": {
|
|
63
|
+
"labelPrefix": "[API] ",
|
|
64
|
+
"defaultFocus": "agy"
|
|
65
|
+
},
|
|
66
|
+
"scaffold": {
|
|
67
|
+
"envSource": "/path/to/shared/.env",
|
|
68
|
+
"symlink": "/path/to/webserver/symlink",
|
|
69
|
+
"install": "composer install --no-interaction"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 3. How to Assist the User
|
|
77
|
+
|
|
78
|
+
### When the User Asks Questions:
|
|
79
|
+
1. Consult the CLI options and configuration schema above.
|
|
80
|
+
2. If working inside a repository with local documentation or `.ariserc.json` / `.worktreerc.json`, inspect those files.
|
|
81
|
+
3. Provide clear explanations with executable CLI examples and config snippets.
|
|
82
|
+
|
|
83
|
+
### When the User Asks You to Perform an Action:
|
|
84
|
+
1. Formulate the appropriate `arise` CLI command.
|
|
85
|
+
2. Execute the command on behalf of the user using the available command runner.
|
|
86
|
+
3. Confirm the status of the created or nuked worktree and Herdr workspace.
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arise - Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Provides strict structural contracts for presets, configuration,
|
|
5
|
+
* declarative layouts, execution context, and lifecycle hooks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface CliFlags {
|
|
9
|
+
isCleanup: boolean;
|
|
10
|
+
cleanupTarget: string | null;
|
|
11
|
+
dirOnly: boolean;
|
|
12
|
+
keepRemote: boolean;
|
|
13
|
+
force: boolean;
|
|
14
|
+
yes: boolean;
|
|
15
|
+
branch: string | null;
|
|
16
|
+
dirname: string | null;
|
|
17
|
+
workspaceName: string | null;
|
|
18
|
+
source: string | null;
|
|
19
|
+
presetName: string | null;
|
|
20
|
+
agent: string | null;
|
|
21
|
+
focusTarget: string | null;
|
|
22
|
+
installSkill: boolean;
|
|
23
|
+
skillScope: 'global' | 'local' | null;
|
|
24
|
+
showHelp: boolean;
|
|
25
|
+
showVersion: boolean;
|
|
26
|
+
rawArgs: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type SplitDirection = 'right' | 'down';
|
|
30
|
+
|
|
31
|
+
export interface PaneDefinition {
|
|
32
|
+
/** Unique ID for the pane within this layout */
|
|
33
|
+
id: string;
|
|
34
|
+
/** Display title for the pane in Herdr */
|
|
35
|
+
title: string;
|
|
36
|
+
/** Command to execute upon creation (or null for empty shell) */
|
|
37
|
+
cmd: string | null;
|
|
38
|
+
/** Position if this is the root pane ('root') */
|
|
39
|
+
position?: 'root';
|
|
40
|
+
/** ID of parent pane from which to split */
|
|
41
|
+
from?: string;
|
|
42
|
+
/** Direction to split ('right' | 'down') */
|
|
43
|
+
split?: SplitDirection;
|
|
44
|
+
/** Whether to focus this pane by default */
|
|
45
|
+
focus?: boolean;
|
|
46
|
+
/** Whether this pane is designated as the AI CLI agent pane */
|
|
47
|
+
isAgent?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface RepoConfig {
|
|
51
|
+
/** Path to bare repository (if using bare git topology) */
|
|
52
|
+
bareRepo?: string | null;
|
|
53
|
+
/** Base directory where worktrees should be placed */
|
|
54
|
+
worktreesBase?: string | null;
|
|
55
|
+
/** Default base branch to branch off (e.g. 'develop', 'prod', 'main') */
|
|
56
|
+
defaultBaseBranch?: string;
|
|
57
|
+
/** Array of branch names protected against deletion */
|
|
58
|
+
protectedBranches?: string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface WorkspaceConfig {
|
|
62
|
+
/** Prefix added to Herdr workspace labels (e.g. '[BE] ') */
|
|
63
|
+
labelPrefix?: string;
|
|
64
|
+
/** CLI AI agent to run in the workspace pane ('agy', 'claude', 'aider', 'copilot', 'none', etc.) */
|
|
65
|
+
agent?: string | { cmd: string; title?: string; [key: string]: any } | null;
|
|
66
|
+
/** Default pane to focus ('agent', 'agy', 'claude', 'vim', 'logs', 'server', 'shell') */
|
|
67
|
+
defaultFocus?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ScaffoldConfig {
|
|
71
|
+
/** Path to environment file (.env) to copy */
|
|
72
|
+
envSource?: string | null;
|
|
73
|
+
/** Target symlink path to point to the active worktree (e.g. '/var/www/my-app') */
|
|
74
|
+
symlink?: string | null;
|
|
75
|
+
/** Command to run to install dependencies upon creation, or false/null to skip installation */
|
|
76
|
+
install?: string | boolean | null;
|
|
77
|
+
[key: string]: any;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ExecutionContext {
|
|
81
|
+
/** Target worktree absolute directory */
|
|
82
|
+
worktreePath: string;
|
|
83
|
+
/** Repository root directory */
|
|
84
|
+
repoRoot: string | null;
|
|
85
|
+
/** Bare repo directory (if applicable) */
|
|
86
|
+
bareRepo: string | null;
|
|
87
|
+
/** Target branch name */
|
|
88
|
+
branch: string;
|
|
89
|
+
/** Base source branch */
|
|
90
|
+
source: string;
|
|
91
|
+
/** Parsed CLI flags */
|
|
92
|
+
flags: CliFlags;
|
|
93
|
+
/** Active preset */
|
|
94
|
+
preset: Preset;
|
|
95
|
+
/** Merged configuration */
|
|
96
|
+
config: WorktreeConfig;
|
|
97
|
+
|
|
98
|
+
log(msg: string): void;
|
|
99
|
+
warn(msg: string): void;
|
|
100
|
+
error(msg: string): void;
|
|
101
|
+
|
|
102
|
+
/** Execute a shell command synchronously */
|
|
103
|
+
exec(command: string, options?: import('child_process').ExecSyncOptions): Buffer | string;
|
|
104
|
+
/** Spawn a process synchronously with stdio inherit */
|
|
105
|
+
spawn(command: string, args?: string[], options?: import('child_process').SpawnSyncOptions): import('child_process').SpawnSyncReturns<Buffer>;
|
|
106
|
+
/** Copy file from src to dst */
|
|
107
|
+
copyFile(src: string, dst: string): boolean;
|
|
108
|
+
/** Copy file from repository root to worktree destination */
|
|
109
|
+
copyFromRoot(relativeSrc: string, relativeDst?: string): boolean;
|
|
110
|
+
/** Safely create or replace a symlink */
|
|
111
|
+
setSymlink(symlinkPath: string, target?: string): boolean;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface PresetHooks {
|
|
115
|
+
/** Called to sync/reset primary branches before creation */
|
|
116
|
+
onSyncPrimary?(ctx: ExecutionContext): Promise<void> | void;
|
|
117
|
+
/** Called to scaffold environment, dependencies, and permissions */
|
|
118
|
+
onScaffold?(ctx: ExecutionContext): Promise<void> | void;
|
|
119
|
+
/** Called before deleting worktree and closing workspaces */
|
|
120
|
+
onPreNuke?(ctx: ExecutionContext): Promise<void> | void;
|
|
121
|
+
/** Called after all worktree and branch deletions complete */
|
|
122
|
+
onPostNuke?(ctx: ExecutionContext): Promise<void> | void;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface Preset {
|
|
126
|
+
/** Unique name of the preset ('node', 'laravel', 'generic') */
|
|
127
|
+
name: string;
|
|
128
|
+
/** Detection rule to determine if this preset applies to a directory */
|
|
129
|
+
detect?(cwd: string): boolean;
|
|
130
|
+
/** Repository defaults */
|
|
131
|
+
repo?: RepoConfig;
|
|
132
|
+
/** Workspace defaults */
|
|
133
|
+
workspace?: WorkspaceConfig;
|
|
134
|
+
/** Declarative terminal layout */
|
|
135
|
+
layout?: PaneDefinition[];
|
|
136
|
+
/** Scaffolding defaults */
|
|
137
|
+
scaffold?: ScaffoldConfig;
|
|
138
|
+
/** Lifecycle hook implementations */
|
|
139
|
+
hooks?: PresetHooks;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface WorktreeConfig {
|
|
143
|
+
/** Name of preset or preset object */
|
|
144
|
+
preset?: string | Preset;
|
|
145
|
+
/** Repository configuration */
|
|
146
|
+
repo: RepoConfig;
|
|
147
|
+
/** Workspace configuration */
|
|
148
|
+
workspace: WorkspaceConfig;
|
|
149
|
+
/** Declarative terminal layout */
|
|
150
|
+
layout: PaneDefinition[];
|
|
151
|
+
/** Scaffolding configuration */
|
|
152
|
+
scaffold: ScaffoldConfig;
|
|
153
|
+
/** Lifecycle hook overrides */
|
|
154
|
+
hooks: PresetHooks;
|
|
155
|
+
/** Path to config file that was loaded (if any) */
|
|
156
|
+
configFile?: string | null;
|
|
157
|
+
}
|