@jskit-ai/jskit-cli 0.2.78 → 0.2.80
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/package.json +5 -5
- package/src/server/appBlueprint.js +126 -0
- package/src/server/cliRuntime/mutationWhen.js +16 -0
- package/src/server/cliRuntime/packageInstallFlow.js +43 -5
- package/src/server/commandHandlers/blueprint.js +151 -0
- package/src/server/commandHandlers/session.js +237 -0
- package/src/server/commandHandlers/show/renderPackageText.js +11 -2
- package/src/server/core/argParser.js +2 -2
- package/src/server/core/commandCatalog.js +83 -0
- package/src/server/core/createCommandHandlers.js +7 -1
- package/src/server/index.js +2 -0
- package/src/server/sessionRuntime/constants.js +296 -0
- package/src/server/sessionRuntime/io.js +97 -0
- package/src/server/sessionRuntime/paths.js +165 -0
- package/src/server/sessionRuntime/preconditions.js +372 -0
- package/src/server/sessionRuntime/promptRenderer.js +41 -0
- package/src/server/sessionRuntime/prompts/app_blueprint.md +28 -0
- package/src/server/sessionRuntime/prompts/doctor_failure.md +15 -0
- package/src/server/sessionRuntime/prompts/final_comment.md +8 -0
- package/src/server/sessionRuntime/prompts/implement_issue.md +25 -0
- package/src/server/sessionRuntime/prompts/new_issue.md +13 -0
- package/src/server/sessionRuntime/prompts/pr_failure.md +15 -0
- package/src/server/sessionRuntime/prompts/review_changes.md +22 -0
- package/src/server/sessionRuntime/prompts/user_check.md +9 -0
- package/src/server/sessionRuntime/responses.js +315 -0
- package/src/server/sessionRuntime.js +927 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import {
|
|
2
|
+
access,
|
|
3
|
+
appendFile,
|
|
4
|
+
mkdir,
|
|
5
|
+
stat
|
|
6
|
+
} from "node:fs/promises";
|
|
7
|
+
import { constants as fsConstants } from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import {
|
|
10
|
+
SESSION_STATE_RELATIVE_PATH
|
|
11
|
+
} from "./constants.js";
|
|
12
|
+
import {
|
|
13
|
+
createError,
|
|
14
|
+
createPrecondition
|
|
15
|
+
} from "./responses.js";
|
|
16
|
+
import {
|
|
17
|
+
readTextIfExists,
|
|
18
|
+
readTrimmedFile,
|
|
19
|
+
runCommand,
|
|
20
|
+
runGit
|
|
21
|
+
} from "./io.js";
|
|
22
|
+
import {
|
|
23
|
+
resolveExistingSessionRoot
|
|
24
|
+
} from "./paths.js";
|
|
25
|
+
|
|
26
|
+
async function assertTargetRootWritable(targetRoot) {
|
|
27
|
+
try {
|
|
28
|
+
await access(targetRoot, fsConstants.R_OK | fsConstants.W_OK);
|
|
29
|
+
return {
|
|
30
|
+
ok: true,
|
|
31
|
+
precondition: createPrecondition({
|
|
32
|
+
id: "target_root_writable",
|
|
33
|
+
ok: true,
|
|
34
|
+
message: "Target root exists and is readable/writable."
|
|
35
|
+
})
|
|
36
|
+
};
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
error: createError({
|
|
41
|
+
code: "target_root_not_writable",
|
|
42
|
+
message: `Target root is not readable/writable: ${error?.message || error}`,
|
|
43
|
+
repairCommand: `test -w ${targetRoot}`
|
|
44
|
+
}),
|
|
45
|
+
precondition: createPrecondition({
|
|
46
|
+
id: "target_root_writable",
|
|
47
|
+
ok: false,
|
|
48
|
+
message: "Target root exists and is readable/writable."
|
|
49
|
+
})
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function resolveGitCommonDirectory(targetRoot) {
|
|
55
|
+
const result = await runGit(targetRoot, ["rev-parse", "--git-common-dir"]);
|
|
56
|
+
if (!result.ok || !result.stdout) {
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
return path.resolve(targetRoot, result.stdout);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function assertGitRepository(targetRoot) {
|
|
63
|
+
const result = await runGit(targetRoot, ["rev-parse", "--is-inside-work-tree"]);
|
|
64
|
+
if (result.ok && result.stdout === "true") {
|
|
65
|
+
return {
|
|
66
|
+
ok: true,
|
|
67
|
+
precondition: createPrecondition({
|
|
68
|
+
id: "git_repository",
|
|
69
|
+
ok: true,
|
|
70
|
+
message: "Target root is inside a git work tree."
|
|
71
|
+
})
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
ok: false,
|
|
76
|
+
error: createError({
|
|
77
|
+
code: "git_repository_missing",
|
|
78
|
+
message: "Target root is not inside a git work tree.",
|
|
79
|
+
repairCommand: "git init"
|
|
80
|
+
}),
|
|
81
|
+
precondition: createPrecondition({
|
|
82
|
+
id: "git_repository",
|
|
83
|
+
ok: false,
|
|
84
|
+
message: "Target root is inside a git work tree."
|
|
85
|
+
})
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function assertGitCurrentBranch(targetRoot) {
|
|
90
|
+
const [branchResult, headResult] = await Promise.all([
|
|
91
|
+
runGit(targetRoot, ["branch", "--show-current"]),
|
|
92
|
+
runGit(targetRoot, ["rev-parse", "--verify", "HEAD"])
|
|
93
|
+
]);
|
|
94
|
+
if (branchResult.ok && branchResult.stdout && headResult.ok) {
|
|
95
|
+
return {
|
|
96
|
+
ok: true,
|
|
97
|
+
precondition: createPrecondition({
|
|
98
|
+
id: "git_current_branch",
|
|
99
|
+
ok: true,
|
|
100
|
+
message: "Target repository has a named current branch with an initial commit."
|
|
101
|
+
})
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
ok: false,
|
|
106
|
+
error: createError({
|
|
107
|
+
code: "git_current_branch_missing",
|
|
108
|
+
message: "Target repository does not have a named current branch with an initial commit.",
|
|
109
|
+
repairCommand: "git checkout -b main && git add . && git commit -m \"Initial commit\""
|
|
110
|
+
}),
|
|
111
|
+
precondition: createPrecondition({
|
|
112
|
+
id: "git_current_branch",
|
|
113
|
+
ok: false,
|
|
114
|
+
message: "Target repository has a named current branch with an initial commit."
|
|
115
|
+
})
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function assertGhAuth(targetRoot) {
|
|
120
|
+
const result = await runCommand("gh", ["auth", "status"], {
|
|
121
|
+
cwd: targetRoot,
|
|
122
|
+
timeout: 15000
|
|
123
|
+
});
|
|
124
|
+
if (result.ok) {
|
|
125
|
+
return {
|
|
126
|
+
ok: true,
|
|
127
|
+
precondition: createPrecondition({
|
|
128
|
+
id: "github_auth",
|
|
129
|
+
ok: true,
|
|
130
|
+
message: "GitHub CLI is authenticated."
|
|
131
|
+
})
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
ok: false,
|
|
136
|
+
error: createError({
|
|
137
|
+
code: "github_auth_missing",
|
|
138
|
+
message: "GitHub CLI is not authenticated.",
|
|
139
|
+
repairCommand: "gh auth login"
|
|
140
|
+
}),
|
|
141
|
+
precondition: createPrecondition({
|
|
142
|
+
id: "github_auth",
|
|
143
|
+
ok: false,
|
|
144
|
+
message: "GitHub CLI is authenticated."
|
|
145
|
+
})
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function assertGithubOrigin(targetRoot) {
|
|
150
|
+
const result = await runGit(targetRoot, ["remote", "get-url", "origin"]);
|
|
151
|
+
if (result.ok && /github\.com[:/]/u.test(result.stdout)) {
|
|
152
|
+
return {
|
|
153
|
+
ok: true,
|
|
154
|
+
precondition: createPrecondition({
|
|
155
|
+
id: "github_origin",
|
|
156
|
+
ok: true,
|
|
157
|
+
message: "Origin remote points at GitHub."
|
|
158
|
+
})
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
ok: false,
|
|
163
|
+
error: createError({
|
|
164
|
+
code: "github_origin_missing",
|
|
165
|
+
message: "Origin remote is missing or is not a GitHub remote.",
|
|
166
|
+
repairCommand: "git remote add origin https://github.com/<owner>/<repo>.git"
|
|
167
|
+
}),
|
|
168
|
+
precondition: createPrecondition({
|
|
169
|
+
id: "github_origin",
|
|
170
|
+
ok: false,
|
|
171
|
+
message: "Origin remote points at GitHub."
|
|
172
|
+
})
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function applyPreconditions(paths, checks = []) {
|
|
177
|
+
const preconditions = [];
|
|
178
|
+
for (const check of checks) {
|
|
179
|
+
const result = await check();
|
|
180
|
+
if (result?.precondition) {
|
|
181
|
+
preconditions.push(result.precondition);
|
|
182
|
+
}
|
|
183
|
+
if (result?.ok !== true) {
|
|
184
|
+
return {
|
|
185
|
+
ok: false,
|
|
186
|
+
error: result.error,
|
|
187
|
+
preconditions
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
void paths;
|
|
192
|
+
return {
|
|
193
|
+
ok: true,
|
|
194
|
+
preconditions
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function ensureStudioGitExclude(targetRoot) {
|
|
199
|
+
const gitCommonDirectory = await resolveGitCommonDirectory(targetRoot);
|
|
200
|
+
if (!gitCommonDirectory) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const excludePath = path.join(gitCommonDirectory, "info", "exclude");
|
|
204
|
+
await mkdir(path.dirname(excludePath), { recursive: true });
|
|
205
|
+
const current = await readTextIfExists(excludePath);
|
|
206
|
+
const lines = current.split(/\r?\n/u).map((line) => line.trim());
|
|
207
|
+
if (!lines.includes(`${SESSION_STATE_RELATIVE_PATH}/`)) {
|
|
208
|
+
await appendFile(excludePath, `${current.endsWith("\n") || current.length === 0 ? "" : "\n"}${SESSION_STATE_RELATIVE_PATH}/\n`, "utf8");
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function assertSessionExists(paths) {
|
|
213
|
+
const existing = await resolveExistingSessionRoot(paths);
|
|
214
|
+
if (existing.root) {
|
|
215
|
+
return {
|
|
216
|
+
ok: true,
|
|
217
|
+
precondition: createPrecondition({
|
|
218
|
+
id: "session_exists",
|
|
219
|
+
ok: true,
|
|
220
|
+
message: "Session state directory exists."
|
|
221
|
+
})
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
ok: false,
|
|
226
|
+
error: createError({
|
|
227
|
+
code: "session_missing",
|
|
228
|
+
message: `Session does not exist: ${paths.sessionId}`,
|
|
229
|
+
repairCommand: "jskit session create"
|
|
230
|
+
}),
|
|
231
|
+
precondition: createPrecondition({
|
|
232
|
+
id: "session_exists",
|
|
233
|
+
ok: false,
|
|
234
|
+
message: "Session state directory exists."
|
|
235
|
+
})
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function assertIssueArtifacts(paths) {
|
|
240
|
+
const [issueText, issueUrl] = await Promise.all([
|
|
241
|
+
readTrimmedFile(path.join(paths.sessionRoot, "issue.md")),
|
|
242
|
+
readTrimmedFile(path.join(paths.sessionRoot, "issue_url"))
|
|
243
|
+
]);
|
|
244
|
+
if (issueText && issueUrl) {
|
|
245
|
+
return {
|
|
246
|
+
ok: true,
|
|
247
|
+
precondition: createPrecondition({
|
|
248
|
+
id: "issue_artifacts",
|
|
249
|
+
ok: true,
|
|
250
|
+
message: "Issue text and GitHub issue URL exist."
|
|
251
|
+
})
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
ok: false,
|
|
256
|
+
error: createError({
|
|
257
|
+
code: "issue_artifacts_missing",
|
|
258
|
+
message: "Issue text and GitHub issue URL are required.",
|
|
259
|
+
repairCommand: `jskit session ${paths.sessionId} step`
|
|
260
|
+
}),
|
|
261
|
+
precondition: createPrecondition({
|
|
262
|
+
id: "issue_artifacts",
|
|
263
|
+
ok: false,
|
|
264
|
+
message: "Issue text and GitHub issue URL exist."
|
|
265
|
+
})
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function assertIssueTextExists(paths) {
|
|
270
|
+
const issueText = await readTrimmedFile(path.join(paths.sessionRoot, "issue.md"));
|
|
271
|
+
if (issueText) {
|
|
272
|
+
return {
|
|
273
|
+
ok: true,
|
|
274
|
+
precondition: createPrecondition({
|
|
275
|
+
id: "issue_text_exists",
|
|
276
|
+
ok: true,
|
|
277
|
+
message: "Issue text exists."
|
|
278
|
+
})
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
ok: false,
|
|
283
|
+
error: createError({
|
|
284
|
+
code: "issue_text_missing",
|
|
285
|
+
message: "Cannot create a GitHub issue before issue.md exists.",
|
|
286
|
+
repairCommand: `jskit session ${paths.sessionId} step --issue -`
|
|
287
|
+
}),
|
|
288
|
+
precondition: createPrecondition({
|
|
289
|
+
id: "issue_text_exists",
|
|
290
|
+
ok: false,
|
|
291
|
+
message: "Issue text exists."
|
|
292
|
+
})
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function hasWorktree(paths) {
|
|
297
|
+
try {
|
|
298
|
+
const stats = await stat(paths.worktree);
|
|
299
|
+
return stats.isDirectory();
|
|
300
|
+
} catch {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function assertWorktreeExists(paths) {
|
|
306
|
+
if (await hasWorktree(paths)) {
|
|
307
|
+
return {
|
|
308
|
+
ok: true,
|
|
309
|
+
precondition: createPrecondition({
|
|
310
|
+
id: "worktree_exists",
|
|
311
|
+
ok: true,
|
|
312
|
+
message: "Session worktree exists."
|
|
313
|
+
})
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
ok: false,
|
|
318
|
+
error: createError({
|
|
319
|
+
code: "worktree_missing",
|
|
320
|
+
message: "Session worktree does not exist.",
|
|
321
|
+
repairCommand: `jskit session ${paths.sessionId} step`
|
|
322
|
+
}),
|
|
323
|
+
precondition: createPrecondition({
|
|
324
|
+
id: "worktree_exists",
|
|
325
|
+
ok: false,
|
|
326
|
+
message: "Session worktree exists."
|
|
327
|
+
})
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async function assertPrUrlExists(paths) {
|
|
332
|
+
const prUrl = await readTrimmedFile(path.join(paths.sessionRoot, "pr_url"));
|
|
333
|
+
if (prUrl) {
|
|
334
|
+
return {
|
|
335
|
+
ok: true,
|
|
336
|
+
precondition: createPrecondition({
|
|
337
|
+
id: "pr_url_exists",
|
|
338
|
+
ok: true,
|
|
339
|
+
message: "PR URL exists."
|
|
340
|
+
})
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
ok: false,
|
|
345
|
+
error: createError({
|
|
346
|
+
code: "pr_url_missing",
|
|
347
|
+
message: "Cannot merge before pr_url exists.",
|
|
348
|
+
repairCommand: `jskit session ${paths.sessionId} step`
|
|
349
|
+
}),
|
|
350
|
+
precondition: createPrecondition({
|
|
351
|
+
id: "pr_url_exists",
|
|
352
|
+
ok: false,
|
|
353
|
+
message: "PR URL exists."
|
|
354
|
+
})
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export {
|
|
359
|
+
applyPreconditions,
|
|
360
|
+
assertGhAuth,
|
|
361
|
+
assertGitCurrentBranch,
|
|
362
|
+
assertGitRepository,
|
|
363
|
+
assertGithubOrigin,
|
|
364
|
+
assertIssueArtifacts,
|
|
365
|
+
assertIssueTextExists,
|
|
366
|
+
assertPrUrlExists,
|
|
367
|
+
assertSessionExists,
|
|
368
|
+
assertTargetRootWritable,
|
|
369
|
+
assertWorktreeExists,
|
|
370
|
+
ensureStudioGitExclude,
|
|
371
|
+
hasWorktree
|
|
372
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
PROMPT_DIRECTORY,
|
|
4
|
+
SESSION_STATE_RELATIVE_PATH
|
|
5
|
+
} from "./constants.js";
|
|
6
|
+
import {
|
|
7
|
+
fileExists,
|
|
8
|
+
normalizeText,
|
|
9
|
+
readTextIfExists
|
|
10
|
+
} from "./io.js";
|
|
11
|
+
|
|
12
|
+
async function readPromptTemplate(targetRoot, name) {
|
|
13
|
+
const normalizedName = normalizeText(name);
|
|
14
|
+
const overridePath = path.join(targetRoot, SESSION_STATE_RELATIVE_PATH, "prompts", normalizedName);
|
|
15
|
+
if (await fileExists(overridePath)) {
|
|
16
|
+
return readTextIfExists(overridePath);
|
|
17
|
+
}
|
|
18
|
+
return readTextIfExists(path.join(PROMPT_DIRECTORY, normalizedName));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function renderTemplate(source, values = {}) {
|
|
22
|
+
return String(source || "").replace(/\{\{\s*([A-Za-z0-9_]+)\s*\}\}/gu, (_match, key) => {
|
|
23
|
+
return String(values[key] ?? "");
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function renderPrompt(paths, templateName, values = {}) {
|
|
28
|
+
const template = await readPromptTemplate(paths.targetRoot, templateName);
|
|
29
|
+
return renderTemplate(template, {
|
|
30
|
+
branch: paths.branch,
|
|
31
|
+
session_id: paths.sessionId,
|
|
32
|
+
worktree: paths.worktree,
|
|
33
|
+
...values
|
|
34
|
+
}).trim();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export {
|
|
38
|
+
readPromptTemplate,
|
|
39
|
+
renderPrompt,
|
|
40
|
+
renderTemplate
|
|
41
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Create a durable JSKIT app blueprint from this app brief.
|
|
2
|
+
|
|
3
|
+
App brief:
|
|
4
|
+
|
|
5
|
+
{{app_brief}}
|
|
6
|
+
|
|
7
|
+
Produce a concise but useful app-level blueprint. It must describe product intent, not implementation steps for the current issue.
|
|
8
|
+
|
|
9
|
+
Cover:
|
|
10
|
+
|
|
11
|
+
- App purpose and what the app will do in general.
|
|
12
|
+
- Primary users and actors.
|
|
13
|
+
- Type of multihoming or tenancy: none, personal, workspaces, or another explicit model from the brief.
|
|
14
|
+
- The role of each surface: app, admin, console, settings, public, workspace, or any app-specific surface from the brief.
|
|
15
|
+
- Global view of the main product areas and navigation destinations.
|
|
16
|
+
- Key domain concepts and data objects, without inventing database schemas unless the brief clearly requires them.
|
|
17
|
+
- Important non-goals and constraints.
|
|
18
|
+
- First useful screen and what it should show.
|
|
19
|
+
- Settings, admin, and operator expectations when relevant.
|
|
20
|
+
|
|
21
|
+
If the brief is ambiguous, state the assumption in the blueprint instead of asking questions.
|
|
22
|
+
|
|
23
|
+
When the blueprint is ready, output only the final markdown surrounded by these exact markers:
|
|
24
|
+
|
|
25
|
+
[app_blueprint]
|
|
26
|
+
# App Blueprint
|
|
27
|
+
...
|
|
28
|
+
[/app_blueprint]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
The JSKIT session doctor or verification step failed.
|
|
2
|
+
|
|
3
|
+
Session:
|
|
4
|
+
|
|
5
|
+
{{session_id}}
|
|
6
|
+
|
|
7
|
+
Worktree:
|
|
8
|
+
|
|
9
|
+
{{worktree}}
|
|
10
|
+
|
|
11
|
+
Failure output:
|
|
12
|
+
|
|
13
|
+
{{doctor_output}}
|
|
14
|
+
|
|
15
|
+
Fix the root cause in this worktree. Do not push, open a PR, merge, or remove the worktree. When the fix is ready, report changed files and verification, then the user will rerun the JSKIT session step.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Work only in this session worktree:
|
|
2
|
+
|
|
3
|
+
{{worktree}}
|
|
4
|
+
|
|
5
|
+
Branch:
|
|
6
|
+
|
|
7
|
+
{{branch}}
|
|
8
|
+
|
|
9
|
+
Issue URL:
|
|
10
|
+
|
|
11
|
+
{{issue_url}}
|
|
12
|
+
|
|
13
|
+
Issue:
|
|
14
|
+
|
|
15
|
+
{{issue_text}}
|
|
16
|
+
|
|
17
|
+
Instructions:
|
|
18
|
+
|
|
19
|
+
- Keep changes scoped to this issue.
|
|
20
|
+
- Do not touch unrelated files.
|
|
21
|
+
- Prefer existing JSKIT package/runtime seams before adding local helpers.
|
|
22
|
+
- Ask the user when blocked by product or architecture ambiguity.
|
|
23
|
+
- Run relevant checks before reporting completion.
|
|
24
|
+
- Do not push, open a PR, merge, or remove the worktree unless JSKIT Studio explicitly instructs it.
|
|
25
|
+
- Report changed files and verification when the implementation is ready.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Create a GitHub issue from this user request:
|
|
2
|
+
|
|
3
|
+
{{user_input}}
|
|
4
|
+
|
|
5
|
+
Ask clarifying questions if the request is not specific enough to produce a useful implementation issue.
|
|
6
|
+
|
|
7
|
+
When the issue text is ready, output only the final issue body surrounded by these exact markers:
|
|
8
|
+
|
|
9
|
+
[issue_text]
|
|
10
|
+
<issue title and body>
|
|
11
|
+
[/issue_text]
|
|
12
|
+
|
|
13
|
+
The issue should be concrete, scoped, and implementation-ready. Include acceptance criteria when they are useful.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
The JSKIT session PR operation failed.
|
|
2
|
+
|
|
3
|
+
Session:
|
|
4
|
+
|
|
5
|
+
{{session_id}}
|
|
6
|
+
|
|
7
|
+
Worktree:
|
|
8
|
+
|
|
9
|
+
{{worktree}}
|
|
10
|
+
|
|
11
|
+
Failure output:
|
|
12
|
+
|
|
13
|
+
{{doctor_output}}
|
|
14
|
+
|
|
15
|
+
Diagnose the failure and fix only what is required in this worktree. Do not push, open a PR, merge, or remove the worktree unless JSKIT Studio explicitly instructs it.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Review pass {{review_pass}} for session {{session_id}}.
|
|
2
|
+
|
|
3
|
+
{{review_pass_note}}
|
|
4
|
+
|
|
5
|
+
Changed files from the latest commit:
|
|
6
|
+
|
|
7
|
+
{{changed_files}}
|
|
8
|
+
|
|
9
|
+
Check through the changed code and see if the changes are done without problems:
|
|
10
|
+
|
|
11
|
+
- slop
|
|
12
|
+
- repeated code
|
|
13
|
+
- ownership issues
|
|
14
|
+
- repeated helpers
|
|
15
|
+
- fragmented functions
|
|
16
|
+
- unnecessary complications
|
|
17
|
+
- tricky code
|
|
18
|
+
- missing tests
|
|
19
|
+
- weak verification
|
|
20
|
+
- JSKIT convention violations
|
|
21
|
+
|
|
22
|
+
Once you are done, provide a list ordered by priority, with a proposal on how to fix each important issue. If there are no important findings, say so explicitly and list any residual risk.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
User check {{review_pass}} for session {{session_id}}.
|
|
2
|
+
|
|
3
|
+
The code should already be built or runnable according to the implementation instructions.
|
|
4
|
+
|
|
5
|
+
Ask the user to test the changed behavior in the app and report whether it works as intended.
|
|
6
|
+
|
|
7
|
+
If the user finds a problem, diagnose it and fix it in this worktree. If the behavior works, tell the user to run:
|
|
8
|
+
|
|
9
|
+
jskit session {{session_id}} step --user-check passed
|