vibe-coding-master 0.3.23 → 0.3.25

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.
@@ -9,13 +9,8 @@ export function createTaskService(deps) {
9
9
  const config = await deps.projectService.loadConfig(repoRoot);
10
10
  const taskStoreRoot = deps.projectService.getProjectDataRoot(repoRoot);
11
11
  const taskPath = getTaskPath(taskStoreRoot, input.taskSlug);
12
- const shouldCreateWorktree = input.createWorktree !== false;
13
- const taskBranch = shouldCreateWorktree
14
- ? `feature/${input.taskSlug}`
15
- : await deps.git.getCurrentBranch(repoRoot);
16
- const worktreePath = shouldCreateWorktree
17
- ? getTaskWorktreePath(repoRoot, input.taskSlug)
18
- : undefined;
12
+ const taskBranch = `feature/${input.taskSlug}`;
13
+ const worktreePath = getTaskWorktreePath(repoRoot, input.taskSlug);
19
14
  if (await deps.fs.pathExists(taskPath)) {
20
15
  throw new VcmError({
21
16
  code: "TASK_EXISTS",
@@ -31,7 +26,7 @@ export function createTaskService(deps) {
31
26
  hint: "Apply VCM Harness first so .gitignore contains the VCM managed block."
32
27
  });
33
28
  }
34
- if (shouldCreateWorktree && !(await deps.git.isIgnored(repoRoot, ".claude/worktrees/.probe"))) {
29
+ if (!(await deps.git.isIgnored(repoRoot, ".claude/worktrees/.probe"))) {
35
30
  throw new VcmError({
36
31
  code: "VCM_WORKTREES_NOT_IGNORED",
37
32
  message: ".claude/worktrees/ is not ignored by Git.",
@@ -39,53 +34,39 @@ export function createTaskService(deps) {
39
34
  hint: "Apply VCM Harness first so .gitignore ignores Claude-compatible task worktrees."
40
35
  });
41
36
  }
42
- if (!shouldCreateWorktree) {
43
- const activeInlineTask = await findActiveInlineTask(deps.fs, taskStoreRoot);
44
- if (activeInlineTask) {
45
- throw new VcmError({
46
- code: "INLINE_TASK_EXISTS",
47
- message: `An inline task already exists: ${activeInlineTask.taskSlug}`,
48
- statusCode: 409,
49
- hint: "Close the existing inline task first, or enable Create worktree and branch for this task."
50
- });
51
- }
37
+ if (await deps.git.branchExists(repoRoot, taskBranch)) {
38
+ throw new VcmError({
39
+ code: "TASK_BRANCH_EXISTS",
40
+ message: `Task branch already exists: ${taskBranch}`,
41
+ statusCode: 409,
42
+ hint: "Choose a different task name or clean up the existing branch."
43
+ });
44
+ }
45
+ if (await deps.fs.pathExists(worktreePath)) {
46
+ throw new VcmError({
47
+ code: "TASK_WORKTREE_EXISTS",
48
+ message: `Task worktree already exists: ${worktreePath}`,
49
+ statusCode: 409,
50
+ hint: "Choose a different task name or clean up the existing worktree."
51
+ });
52
52
  }
53
- if (shouldCreateWorktree && worktreePath) {
54
- if (await deps.git.branchExists(repoRoot, taskBranch)) {
55
- throw new VcmError({
56
- code: "TASK_BRANCH_EXISTS",
57
- message: `Task branch already exists: ${taskBranch}`,
58
- statusCode: 409,
59
- hint: "Choose a different task name or clean up the existing branch."
60
- });
61
- }
62
- if (await deps.fs.pathExists(worktreePath)) {
63
- throw new VcmError({
64
- code: "TASK_WORKTREE_EXISTS",
65
- message: `Task worktree already exists: ${worktreePath}`,
66
- statusCode: 409,
67
- hint: "Choose a different task name or clean up the existing worktree."
68
- });
69
- }
70
- const baseStatus = await deps.git.getStatusPorcelain(repoRoot);
71
- if (baseStatus.trim()) {
72
- throw new VcmError({
73
- code: "BASE_REPO_DIRTY",
74
- message: "The connected repository has uncommitted changes.",
75
- statusCode: 409,
76
- hint: "Commit, stash, or discard base repository changes before creating a task worktree."
77
- });
78
- }
79
- await deps.fs.ensureDir(path.dirname(worktreePath));
80
- await deps.git.createWorktree({
81
- repoRoot,
82
- branch: taskBranch,
83
- worktreePath,
84
- baseRef: "HEAD"
53
+ const baseStatus = await deps.git.getStatusPorcelain(repoRoot);
54
+ if (baseStatus.trim()) {
55
+ throw new VcmError({
56
+ code: "BASE_REPO_DIRTY",
57
+ message: "The connected repository has uncommitted changes.",
58
+ statusCode: 409,
59
+ hint: "Commit, stash, or discard base repository changes before creating a task worktree."
85
60
  });
86
61
  }
87
62
  const timestamp = now();
88
- const taskRepoRoot = worktreePath ?? repoRoot;
63
+ await deps.fs.ensureDir(path.dirname(worktreePath));
64
+ await deps.git.createWorktree({
65
+ repoRoot,
66
+ branch: taskBranch,
67
+ worktreePath,
68
+ baseRef: "HEAD"
69
+ });
89
70
  const task = {
90
71
  version: 1,
91
72
  taskSlug: input.taskSlug,
@@ -100,14 +81,14 @@ export function createTaskService(deps) {
100
81
  specPath: input.specPath,
101
82
  cleanupStatus: "active"
102
83
  };
103
- await ensureTaskRuntimeStateDirs(deps.fs, taskRepoRoot, config.stateRoot);
84
+ await ensureTaskRuntimeStateDirs(deps.fs, worktreePath, config.stateRoot);
104
85
  await deps.artifactService.ensureHandoffStructure({
105
- repoRoot: taskRepoRoot,
86
+ repoRoot: worktreePath,
106
87
  taskSlug: input.taskSlug,
107
88
  handoffDir: task.handoffDir
108
89
  });
109
90
  await deps.artifactService.createArtifactTemplates({
110
- repoRoot: taskRepoRoot,
91
+ repoRoot: worktreePath,
111
92
  taskSlug: input.taskSlug,
112
93
  handoffDir: task.handoffDir,
113
94
  branch: task.branch
@@ -123,7 +104,7 @@ export function createTaskService(deps) {
123
104
  const entries = await deps.fs.readDir(tasksDir);
124
105
  const tasks = [];
125
106
  for (const entry of entries.filter((candidate) => candidate.endsWith(".json"))) {
126
- tasks.push(normalizeTaskRecord(await deps.fs.readJson(path.join(tasksDir, entry))));
107
+ tasks.push(await deps.fs.readJson(path.join(tasksDir, entry)));
127
108
  }
128
109
  return tasks.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
129
110
  },
@@ -137,7 +118,7 @@ export function createTaskService(deps) {
137
118
  statusCode: 404
138
119
  });
139
120
  }
140
- return normalizeTaskRecord(await deps.fs.readJson(taskPath));
121
+ return deps.fs.readJson(taskPath);
141
122
  },
142
123
  async saveTask(repoRoot, task) {
143
124
  await deps.fs.writeJsonAtomic(getTaskPath(deps.projectService.getProjectDataRoot(repoRoot), task.taskSlug), task);
@@ -167,15 +148,9 @@ export function createTaskService(deps) {
167
148
  const statePaths = getTaskStatePaths(deps.projectService.getProjectDataRoot(repoRoot), taskRepoRoot, config.stateRoot, config.handoffRoot, taskSlug);
168
149
  const removedStatePaths = [];
169
150
  const cleanedAt = now();
170
- if (task.worktreePath) {
171
- assertTaskWorktreePath(repoRoot, task.worktreePath);
172
- await deps.git.removeWorktree(repoRoot, task.worktreePath, { force: options.force ?? true });
173
- }
174
- let deletedBranch;
175
- if (task.worktreePath && (options.deleteBranch ?? true)) {
176
- await deps.git.deleteBranch(repoRoot, task.branch, { force: options.forceDeleteBranch ?? true });
177
- deletedBranch = task.branch;
178
- }
151
+ assertTaskWorktreePath(repoRoot, task.worktreePath);
152
+ await deps.git.removeWorktree(repoRoot, task.worktreePath, { force: options.force ?? true });
153
+ await deps.git.deleteBranch(repoRoot, task.branch, { force: options.forceDeleteBranch ?? true });
179
154
  for (const statePath of statePaths) {
180
155
  await deps.fs.removePath(statePath, { recursive: true, force: true });
181
156
  removedStatePaths.push(statePath);
@@ -184,14 +159,14 @@ export function createTaskService(deps) {
184
159
  taskSlug,
185
160
  removedWorktreePath: task.worktreePath,
186
161
  removedStatePaths,
187
- deletedBranch,
162
+ deletedBranch: task.branch,
188
163
  cleanedAt
189
164
  };
190
165
  }
191
166
  };
192
167
  }
193
168
  export function getTaskRuntimeRepoRoot(task) {
194
- return task.worktreePath ?? task.repoRoot;
169
+ return task.worktreePath;
195
170
  }
196
171
  function getTaskPath(taskStoreRoot, taskSlug) {
197
172
  return path.join(taskStoreRoot, "tasks", `${taskSlug}.json`);
@@ -206,49 +181,6 @@ async function ensureTaskRuntimeStateDirs(fs, taskRepoRoot, stateRoot) {
206
181
  await fs.ensureDir(path.join(taskRepoRoot, stateRoot, "translation"));
207
182
  await fs.ensureDir(path.join(taskRepoRoot, stateRoot, "codex-reviews"));
208
183
  }
209
- async function findActiveInlineTask(fs, taskStoreRoot) {
210
- const tasksDir = path.join(taskStoreRoot, "tasks");
211
- if (!(await fs.pathExists(tasksDir))) {
212
- return undefined;
213
- }
214
- const entries = await fs.readDir(tasksDir);
215
- for (const entry of entries.filter((candidate) => candidate.endsWith(".json"))) {
216
- const task = normalizeTaskRecord(await fs.readJson(path.join(tasksDir, entry)));
217
- if (!task.worktreePath && task.cleanupStatus !== "cleaned") {
218
- return task;
219
- }
220
- }
221
- return undefined;
222
- }
223
- function normalizeTaskRecord(input) {
224
- return {
225
- version: 1,
226
- taskSlug: input.taskSlug ?? "",
227
- title: input.title,
228
- createdAt: input.createdAt ?? "",
229
- updatedAt: input.updatedAt ?? input.createdAt ?? "",
230
- repoRoot: input.repoRoot ?? "",
231
- worktreePath: input.worktreePath,
232
- branch: input.branch ?? "",
233
- handoffDir: input.handoffDir ?? ".ai/vcm/handoffs",
234
- status: normalizeTaskStatus(input.status),
235
- specPath: input.specPath,
236
- cleanupStatus: input.cleanupStatus,
237
- cleanedAt: input.cleanedAt
238
- };
239
- }
240
- function normalizeTaskStatus(value) {
241
- if (value === "created" || value === "running" || value === "stopped") {
242
- return value;
243
- }
244
- if (value === undefined || value === null) {
245
- return "created";
246
- }
247
- if (value === "planning") {
248
- return "created";
249
- }
250
- return "stopped";
251
- }
252
184
  function getTaskStatePaths(taskStoreRoot, taskRepoRoot, stateRoot, handoffRoot, taskSlug) {
253
185
  return [
254
186
  getTaskPath(taskStoreRoot, taskSlug),
@@ -35,10 +35,19 @@ export function renderProjectManagerHarnessRules() {
35
35
  ### Dispatch
36
36
 
37
37
  - Use the \`vcm-route-message\` skill for every role dispatch, question, result, blocker, or finding.
38
- - Route messages contain PM-owned routing context only: target role, user request summary, known user constraints, source of truth, required next gate, skipped gates when applicable, required handoff inputs, expected artifact, stop conditions, and confirmed worktree information.
38
+ - Formal route messages contain PM-owned routing context only: target role, user request summary, known user constraints, source of truth, required next gate, skipped gates when applicable, required handoff inputs, expected artifact, stop conditions, and confirmed worktree information.
39
39
  - Do not write technical design into route messages; ask architect to determine architecture, file scope, public contracts, behavior/contract proof points, docs impact, and Replan triggers.
40
40
  - For coder or reviewer messages, reference existing handoff artifacts instead of making new technical judgments.
41
41
 
42
+ ### Simple User Relay
43
+
44
+ When forwarding a user's answer, clarification, or small preference update to an active role, use a lightweight relay message.
45
+
46
+ PM may lightly rewrite the user's words to:
47
+ - clarify pronouns or references from the current context
48
+ - translate the user's intent into clear role-facing language
49
+ - state whether this is confirmation, rejection, preference, or a small constraint
50
+
42
51
  ### Phased Tasks
43
52
 
44
53
  - When architect provides a phased plan, dispatch only one phase at a time.
@@ -33,6 +33,12 @@ If the same route file already contains a not-yet-delivered message, update that
33
33
 
34
34
  ## Message Format
35
35
 
36
+ Use the smallest body that is complete. Include artifact refs instead of copying long documents.
37
+
38
+ For simple user relay, use a lightweight body instead of the formal dispatch format.
39
+
40
+ For formal dispatch, blocker, finding, review, or gate routing, use:
41
+
36
42
  \`\`\`md
37
43
  ---
38
44
  type: task
@@ -54,9 +60,9 @@ Expected next action:
54
60
  ...
55
61
  \`\`\`
56
62
 
57
- Use the smallest body that is complete. Include artifact refs instead of copying long documents.
63
+ ## Formal Body Content
58
64
 
59
- ## Required Body Content
65
+ Formal messages should include:
60
66
 
61
67
  - why this message exists
62
68
  - what the target role should do or what result is being reported