ralphctl 0.4.1 → 0.4.3
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 +13 -11
- package/dist/{add-CIM72NE3.mjs → add-MG26JWBP.mjs} +6 -6
- package/dist/{add-GX7P7XTT.mjs → add-ZZYL4BSF.mjs} +5 -4
- package/dist/chunk-2FT37OZX.mjs +1071 -0
- package/dist/{chunk-CTP2A436.mjs → chunk-D2HWXEHH.mjs} +9 -2
- package/dist/{chunk-JOQO4HMM.mjs → chunk-EGUFQNRB.mjs} +10 -10
- package/dist/{chunk-3HJNVQ7N.mjs → chunk-LCY32RW4.mjs} +621 -976
- package/dist/{chunk-NUYQK5MN.mjs → chunk-LDSG7G2T.mjs} +1 -1
- package/dist/{chunk-7JLZQICD.mjs → chunk-MDE6KPJQ.mjs} +6 -6
- package/dist/{chunk-3QBEBKMZ.mjs → chunk-Q4AVHUZL.mjs} +7 -7
- package/dist/{chunk-YCDUVPRT.mjs → chunk-RQGD5WS6.mjs} +4 -72
- package/dist/{chunk-D2YGPLIV.mjs → chunk-TDBEEHTS.mjs} +213 -8
- package/dist/{chunk-SM4GGZSU.mjs → chunk-WOMGKKZY.mjs} +152 -179
- package/dist/{chunk-FKMKOWLA.mjs → chunk-WZTY77GY.mjs} +75 -1
- package/dist/cli.mjs +68 -19
- package/dist/{create-7WFSCMP4.mjs → create-PQK6KKRD.mjs} +5 -5
- package/dist/{handle-BBAZJ44Y.mjs → handle-SYVCFI6Y.mjs} +1 -1
- package/dist/{mount-2N6H5CWA.mjs → mount-2ANLHHQE.mjs} +556 -318
- package/dist/{project-2IE7VWDB.mjs → project-JF47ZWMF.mjs} +2 -2
- package/dist/prompts/check-script-discover.md +69 -0
- package/dist/prompts/ideate-auto.md +26 -1
- package/dist/prompts/ideate.md +5 -1
- package/dist/prompts/plan-auto.md +30 -2
- package/dist/prompts/plan-common-examples.md +82 -0
- package/dist/prompts/plan-common.md +26 -78
- package/dist/prompts/plan-interactive.md +6 -2
- package/dist/prompts/repo-onboard.md +111 -0
- package/dist/prompts/sprint-feedback.md +6 -2
- package/dist/prompts/task-evaluation.md +25 -10
- package/dist/prompts/task-execution.md +13 -13
- package/dist/prompts/ticket-refine.md +4 -0
- package/dist/prompts/validation-checklist.md +4 -0
- package/dist/{resolver-EOE5WUMV.mjs → resolver-PG2DZEBX.mjs} +3 -3
- package/dist/{sprint-OGOFEJJH.mjs → sprint-54DOSIJK.mjs} +3 -3
- package/dist/{start-IUDCXIEA.mjs → start-2SZTBKGF.mjs} +7 -5
- package/package.json +6 -6
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getProjectById
|
|
4
|
-
} from "./chunk-NUYQK5MN.mjs";
|
|
5
2
|
import {
|
|
6
3
|
addTicket,
|
|
7
4
|
fetchIssueFromUrl,
|
|
8
5
|
truncate
|
|
9
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-EGUFQNRB.mjs";
|
|
10
7
|
import {
|
|
11
8
|
EXIT_ERROR,
|
|
12
9
|
exitWithCode
|
|
@@ -14,9 +11,12 @@ import {
|
|
|
14
11
|
import {
|
|
15
12
|
getPrompt
|
|
16
13
|
} from "./chunk-747KW2RW.mjs";
|
|
14
|
+
import {
|
|
15
|
+
getProjectById
|
|
16
|
+
} from "./chunk-LDSG7G2T.mjs";
|
|
17
17
|
import {
|
|
18
18
|
getCurrentSprintOrThrow
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-RQGD5WS6.mjs";
|
|
20
20
|
import {
|
|
21
21
|
createSpinner,
|
|
22
22
|
emoji,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
showError,
|
|
30
30
|
showSuccess,
|
|
31
31
|
showWarning
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-WZTY77GY.mjs";
|
|
33
33
|
import {
|
|
34
34
|
ensureError,
|
|
35
35
|
wrapAsync
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
listProjects
|
|
4
|
-
} from "./chunk-NUYQK5MN.mjs";
|
|
5
2
|
import {
|
|
6
3
|
EXIT_ERROR,
|
|
7
4
|
exitWithCode
|
|
@@ -10,19 +7,22 @@ import {
|
|
|
10
7
|
getPrompt
|
|
11
8
|
} from "./chunk-747KW2RW.mjs";
|
|
12
9
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
listProjects
|
|
11
|
+
} from "./chunk-LDSG7G2T.mjs";
|
|
12
|
+
import {
|
|
13
|
+
createSprint
|
|
14
|
+
} from "./chunk-RQGD5WS6.mjs";
|
|
16
15
|
import {
|
|
17
16
|
emoji,
|
|
18
17
|
field,
|
|
19
18
|
formatSprintStatus,
|
|
20
19
|
icons,
|
|
20
|
+
setCurrentSprint,
|
|
21
21
|
showError,
|
|
22
22
|
showNextStep,
|
|
23
23
|
showRandomQuote,
|
|
24
24
|
showSuccess
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-WZTY77GY.mjs";
|
|
26
26
|
|
|
27
27
|
// src/integration/cli/commands/sprint/create.ts
|
|
28
28
|
async function sprintCreateCommand(options = {}) {
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
getCurrentSprint,
|
|
3
4
|
log
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
unwrapOrThrow
|
|
7
|
-
} from "./chunk-IWXBJD2D.mjs";
|
|
5
|
+
} from "./chunk-WZTY77GY.mjs";
|
|
8
6
|
import {
|
|
9
|
-
ConfigSchema,
|
|
10
7
|
SprintSchema,
|
|
11
8
|
TasksSchema,
|
|
12
9
|
appendToFile,
|
|
@@ -14,7 +11,6 @@ import {
|
|
|
14
11
|
ensureDir,
|
|
15
12
|
fileExists,
|
|
16
13
|
generateSprintId,
|
|
17
|
-
getConfigPath,
|
|
18
14
|
getProgressFilePath,
|
|
19
15
|
getSprintDir,
|
|
20
16
|
getSprintFilePath,
|
|
@@ -25,7 +21,7 @@ import {
|
|
|
25
21
|
readValidatedJson,
|
|
26
22
|
removeDir,
|
|
27
23
|
writeValidatedJson
|
|
28
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-D2HWXEHH.mjs";
|
|
29
25
|
import {
|
|
30
26
|
LockError,
|
|
31
27
|
NoCurrentSprintError,
|
|
@@ -34,60 +30,6 @@ import {
|
|
|
34
30
|
StorageError
|
|
35
31
|
} from "./chunk-57UWLHRH.mjs";
|
|
36
32
|
|
|
37
|
-
// src/integration/persistence/config.ts
|
|
38
|
-
var DEFAULT_EVALUATION_ITERATIONS = 1;
|
|
39
|
-
var DEFAULT_CONFIG = {
|
|
40
|
-
currentSprint: null,
|
|
41
|
-
aiProvider: null,
|
|
42
|
-
editor: null
|
|
43
|
-
};
|
|
44
|
-
async function getConfig() {
|
|
45
|
-
const configPath = getConfigPath();
|
|
46
|
-
if (!await fileExists(configPath)) {
|
|
47
|
-
return DEFAULT_CONFIG;
|
|
48
|
-
}
|
|
49
|
-
return unwrapOrThrow(await readValidatedJson(configPath, ConfigSchema));
|
|
50
|
-
}
|
|
51
|
-
async function saveConfig(config) {
|
|
52
|
-
unwrapOrThrow(await writeValidatedJson(getConfigPath(), config, ConfigSchema));
|
|
53
|
-
}
|
|
54
|
-
async function getCurrentSprint() {
|
|
55
|
-
const config = await getConfig();
|
|
56
|
-
return config.currentSprint;
|
|
57
|
-
}
|
|
58
|
-
async function setCurrentSprint(sprintId) {
|
|
59
|
-
const config = await getConfig();
|
|
60
|
-
config.currentSprint = sprintId;
|
|
61
|
-
await saveConfig(config);
|
|
62
|
-
}
|
|
63
|
-
async function getAiProvider() {
|
|
64
|
-
const config = await getConfig();
|
|
65
|
-
return config.aiProvider ?? null;
|
|
66
|
-
}
|
|
67
|
-
async function setAiProvider(provider) {
|
|
68
|
-
const config = await getConfig();
|
|
69
|
-
config.aiProvider = provider;
|
|
70
|
-
await saveConfig(config);
|
|
71
|
-
}
|
|
72
|
-
async function getEditor() {
|
|
73
|
-
const config = await getConfig();
|
|
74
|
-
return config.editor ?? null;
|
|
75
|
-
}
|
|
76
|
-
async function setEditor(editor) {
|
|
77
|
-
const config = await getConfig();
|
|
78
|
-
config.editor = editor;
|
|
79
|
-
await saveConfig(config);
|
|
80
|
-
}
|
|
81
|
-
async function getEvaluationIterations() {
|
|
82
|
-
const config = await getConfig();
|
|
83
|
-
return config.evaluationIterations ?? DEFAULT_EVALUATION_ITERATIONS;
|
|
84
|
-
}
|
|
85
|
-
async function setEvaluationIterations(iterations) {
|
|
86
|
-
const config = await getConfig();
|
|
87
|
-
config.evaluationIterations = iterations;
|
|
88
|
-
await saveConfig(config);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
33
|
// src/integration/persistence/progress.ts
|
|
92
34
|
import { execSync } from "child_process";
|
|
93
35
|
|
|
@@ -267,7 +209,7 @@ async function getProgress(sprintId) {
|
|
|
267
209
|
const id = await resolveSprintId(sprintId);
|
|
268
210
|
const result = await readTextFile(getProgressFilePath(id));
|
|
269
211
|
if (!result.ok) {
|
|
270
|
-
if (result.error instanceof StorageError && result.error.cause
|
|
212
|
+
if (result.error instanceof StorageError && result.error.cause && "code" in result.error.cause && result.error.cause.code === "ENOENT") {
|
|
271
213
|
return "";
|
|
272
214
|
}
|
|
273
215
|
throw result.error;
|
|
@@ -481,16 +423,6 @@ async function resolveSprintId(sprintId) {
|
|
|
481
423
|
}
|
|
482
424
|
|
|
483
425
|
export {
|
|
484
|
-
getConfig,
|
|
485
|
-
saveConfig,
|
|
486
|
-
getCurrentSprint,
|
|
487
|
-
setCurrentSprint,
|
|
488
|
-
getAiProvider,
|
|
489
|
-
setAiProvider,
|
|
490
|
-
getEditor,
|
|
491
|
-
setEditor,
|
|
492
|
-
getEvaluationIterations,
|
|
493
|
-
setEvaluationIterations,
|
|
494
426
|
withFileLock,
|
|
495
427
|
logProgress,
|
|
496
428
|
getProgress,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
ProviderAiSessionAdapter,
|
|
4
|
+
SignalParser,
|
|
5
|
+
buildCheckScriptDiscoverPrompt
|
|
6
|
+
} from "./chunk-2FT37OZX.mjs";
|
|
5
7
|
import {
|
|
6
8
|
EXIT_ERROR,
|
|
7
9
|
exitWithCode
|
|
@@ -9,11 +11,15 @@ import {
|
|
|
9
11
|
import {
|
|
10
12
|
getPrompt
|
|
11
13
|
} from "./chunk-747KW2RW.mjs";
|
|
14
|
+
import {
|
|
15
|
+
createProject
|
|
16
|
+
} from "./chunk-LDSG7G2T.mjs";
|
|
12
17
|
import {
|
|
13
18
|
createSpinner,
|
|
14
19
|
emoji,
|
|
15
20
|
error,
|
|
16
21
|
field,
|
|
22
|
+
getConfig,
|
|
17
23
|
log,
|
|
18
24
|
muted,
|
|
19
25
|
showError,
|
|
@@ -21,7 +27,7 @@ import {
|
|
|
21
27
|
showSuccess,
|
|
22
28
|
showTip,
|
|
23
29
|
showWarning
|
|
24
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-WZTY77GY.mjs";
|
|
25
31
|
import {
|
|
26
32
|
ensureError,
|
|
27
33
|
wrapAsync
|
|
@@ -29,16 +35,17 @@ import {
|
|
|
29
35
|
import {
|
|
30
36
|
expandTilde,
|
|
31
37
|
validateProjectPath
|
|
32
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-D2HWXEHH.mjs";
|
|
33
39
|
import {
|
|
34
40
|
IOError,
|
|
35
|
-
ProjectExistsError
|
|
41
|
+
ProjectExistsError,
|
|
42
|
+
ValidationError
|
|
36
43
|
} from "./chunk-57UWLHRH.mjs";
|
|
37
44
|
|
|
38
45
|
// src/integration/cli/commands/project/add.ts
|
|
39
46
|
import { existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
40
47
|
import { basename, join as join3, resolve as resolve2 } from "path";
|
|
41
|
-
import { Result as
|
|
48
|
+
import { Result as Result4 } from "typescript-result";
|
|
42
49
|
|
|
43
50
|
// src/integration/ui/prompts/file-browser-impl.ts
|
|
44
51
|
import { readdirSync, statSync } from "fs";
|
|
@@ -328,13 +335,173 @@ function suggestCheckScript(projectPath) {
|
|
|
328
335
|
return parts.length > 0 ? parts.join(" && ") : null;
|
|
329
336
|
}
|
|
330
337
|
|
|
338
|
+
// src/integration/ai/discover-check-script.ts
|
|
339
|
+
var DISCOVERY_TIMEOUT_MS = 3e4;
|
|
340
|
+
async function discoverCheckScriptWithAi(repoPath, aiSession, signalParser) {
|
|
341
|
+
const prompt = buildCheckScriptDiscoverPrompt(repoPath);
|
|
342
|
+
const session = aiSession.spawnHeadless(prompt, { cwd: repoPath });
|
|
343
|
+
const timeout = new Promise((resolve3) => {
|
|
344
|
+
setTimeout(() => {
|
|
345
|
+
resolve3(null);
|
|
346
|
+
}, DISCOVERY_TIMEOUT_MS).unref();
|
|
347
|
+
});
|
|
348
|
+
try {
|
|
349
|
+
const result = await Promise.race([session, timeout]);
|
|
350
|
+
if (!result) return null;
|
|
351
|
+
const signals = signalParser.parseSignals(result.output);
|
|
352
|
+
const discovery = signals.find((s) => s.type === "check-script-discovery");
|
|
353
|
+
return discovery ? discovery.command : null;
|
|
354
|
+
} catch {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/integration/config/schema-provider.ts
|
|
360
|
+
import { Result as Result3 } from "typescript-result";
|
|
361
|
+
|
|
362
|
+
// src/domain/config-schema.ts
|
|
363
|
+
var ConfigSchemaDefinition = {
|
|
364
|
+
currentSprint: {
|
|
365
|
+
key: "currentSprint",
|
|
366
|
+
label: "Current Sprint",
|
|
367
|
+
type: "string",
|
|
368
|
+
default: null,
|
|
369
|
+
description: "Currently active sprint ID (set by `sprint start`, cleared on `sprint close`)",
|
|
370
|
+
validation: (val) => val === null || typeof val === "string" && val.length > 0,
|
|
371
|
+
scope: "global"
|
|
372
|
+
},
|
|
373
|
+
aiProvider: {
|
|
374
|
+
key: "aiProvider",
|
|
375
|
+
label: "AI Provider",
|
|
376
|
+
type: "enum",
|
|
377
|
+
enum: ["claude", "copilot"],
|
|
378
|
+
default: null,
|
|
379
|
+
description: "AI provider for task execution (Claude Code or GitHub Copilot CLI)",
|
|
380
|
+
validation: (val) => val === null || typeof val === "string" && ["claude", "copilot"].includes(val),
|
|
381
|
+
scope: "global"
|
|
382
|
+
},
|
|
383
|
+
evaluationIterations: {
|
|
384
|
+
key: "evaluationIterations",
|
|
385
|
+
label: "Evaluation Iterations",
|
|
386
|
+
type: "integer",
|
|
387
|
+
min: 0,
|
|
388
|
+
max: 10,
|
|
389
|
+
default: 1,
|
|
390
|
+
description: "Number of fix-attempt iterations after initial evaluation; 0 = disabled. Higher values allow more refinement rounds.",
|
|
391
|
+
validation: (val) => typeof val === "number" && Number.isInteger(val) && val >= 0 && val <= 10,
|
|
392
|
+
scope: "sprint"
|
|
393
|
+
},
|
|
394
|
+
aiCheckScriptDiscovery: {
|
|
395
|
+
key: "aiCheckScriptDiscovery",
|
|
396
|
+
label: "AI Check-Script Discovery",
|
|
397
|
+
type: "boolean",
|
|
398
|
+
default: false,
|
|
399
|
+
description: "When static ecosystem detection cannot suggest a check script during `project add`, ask the configured AI provider to inspect the repo and propose one. User approval is always required before saving. Disabled by default \u2014 enable with `ralphctl config set aiCheckScriptDiscovery true`.",
|
|
400
|
+
validation: (val) => typeof val === "boolean",
|
|
401
|
+
scope: "user"
|
|
402
|
+
}
|
|
403
|
+
// Phase 2+ additions can be added here as single schema entries
|
|
404
|
+
// maxTaskTurns: { ... },
|
|
405
|
+
// checkScriptTimeout: { ... },
|
|
406
|
+
};
|
|
407
|
+
function getSchemaEntry(key) {
|
|
408
|
+
return ConfigSchemaDefinition[key];
|
|
409
|
+
}
|
|
410
|
+
function getAllSchemaEntries() {
|
|
411
|
+
return Object.values(ConfigSchemaDefinition);
|
|
412
|
+
}
|
|
413
|
+
function getDefaultValue(key) {
|
|
414
|
+
return ConfigSchemaDefinition[key].default;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/integration/config/schema-provider.ts
|
|
418
|
+
function getAllConfigSchemaEntries() {
|
|
419
|
+
return getAllSchemaEntries();
|
|
420
|
+
}
|
|
421
|
+
function getConfigSchemaEntry(key) {
|
|
422
|
+
return getSchemaEntry(key);
|
|
423
|
+
}
|
|
424
|
+
function getConfigDefaultValue(key) {
|
|
425
|
+
return getDefaultValue(key);
|
|
426
|
+
}
|
|
427
|
+
function validateConfigValue(key, value) {
|
|
428
|
+
if (!(key in ConfigSchemaDefinition)) {
|
|
429
|
+
return Result3.error(new ValidationError(`Unknown config key: ${key}`, key));
|
|
430
|
+
}
|
|
431
|
+
const schemaKey = key;
|
|
432
|
+
const entry = getConfigSchemaEntry(schemaKey);
|
|
433
|
+
if (!entry.validation(value)) {
|
|
434
|
+
let errorMsg = `Invalid value for ${key}`;
|
|
435
|
+
if (entry.type === "enum" && entry.enum) {
|
|
436
|
+
errorMsg += `: must be one of ${entry.enum.join(", ")}`;
|
|
437
|
+
} else if (entry.type === "integer" || entry.type === "number") {
|
|
438
|
+
const constraints = [];
|
|
439
|
+
if (entry.min !== void 0) constraints.push(`min: ${String(entry.min)}`);
|
|
440
|
+
if (entry.max !== void 0) constraints.push(`max: ${String(entry.max)}`);
|
|
441
|
+
if (constraints.length > 0) errorMsg += ` (${constraints.join(", ")})`;
|
|
442
|
+
}
|
|
443
|
+
return Result3.error(new ValidationError(errorMsg, key));
|
|
444
|
+
}
|
|
445
|
+
return Result3.ok(value);
|
|
446
|
+
}
|
|
447
|
+
function parseConfigValue(key, stringValue) {
|
|
448
|
+
if (!(key in ConfigSchemaDefinition)) {
|
|
449
|
+
return Result3.error(new ValidationError(`Unknown config key: ${key}`, key));
|
|
450
|
+
}
|
|
451
|
+
const schemaKey = key;
|
|
452
|
+
const entry = getConfigSchemaEntry(schemaKey);
|
|
453
|
+
let parsedValue;
|
|
454
|
+
try {
|
|
455
|
+
switch (entry.type) {
|
|
456
|
+
case "string":
|
|
457
|
+
parsedValue = stringValue === "null" ? null : stringValue;
|
|
458
|
+
break;
|
|
459
|
+
case "integer":
|
|
460
|
+
parsedValue = stringValue === "null" ? null : Number.parseInt(stringValue, 10);
|
|
461
|
+
if (Number.isNaN(parsedValue)) {
|
|
462
|
+
return Result3.error(new ValidationError(`Expected integer for ${key}, got ${stringValue}`, key));
|
|
463
|
+
}
|
|
464
|
+
break;
|
|
465
|
+
case "number":
|
|
466
|
+
parsedValue = stringValue === "null" ? null : Number.parseFloat(stringValue);
|
|
467
|
+
if (Number.isNaN(parsedValue)) {
|
|
468
|
+
return Result3.error(new ValidationError(`Expected number for ${key}, got ${stringValue}`, key));
|
|
469
|
+
}
|
|
470
|
+
break;
|
|
471
|
+
case "boolean":
|
|
472
|
+
if (stringValue.toLowerCase() === "true" || stringValue === "1") {
|
|
473
|
+
parsedValue = true;
|
|
474
|
+
} else if (stringValue.toLowerCase() === "false" || stringValue === "0") {
|
|
475
|
+
parsedValue = false;
|
|
476
|
+
} else if (stringValue === "null") {
|
|
477
|
+
parsedValue = null;
|
|
478
|
+
} else {
|
|
479
|
+
return Result3.error(new ValidationError(`Expected boolean for ${key}, got ${stringValue}`, key));
|
|
480
|
+
}
|
|
481
|
+
break;
|
|
482
|
+
case "enum":
|
|
483
|
+
if (stringValue === "null") {
|
|
484
|
+
parsedValue = null;
|
|
485
|
+
} else {
|
|
486
|
+
parsedValue = stringValue;
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
} catch (err) {
|
|
491
|
+
return Result3.error(
|
|
492
|
+
new ValidationError(`Failed to parse ${key}: ${err instanceof Error ? err.message : String(err)}`, key)
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
return validateConfigValue(key, parsedValue);
|
|
496
|
+
}
|
|
497
|
+
|
|
331
498
|
// src/integration/cli/commands/project/add.ts
|
|
332
499
|
function validateSlug(slug) {
|
|
333
500
|
return /^[a-z0-9-]+$/.test(slug);
|
|
334
501
|
}
|
|
335
502
|
function isGitRepo2(path) {
|
|
336
503
|
const gitDir = join3(path, ".git");
|
|
337
|
-
const r =
|
|
504
|
+
const r = Result4.try(() => existsSync2(gitDir) && statSync2(gitDir).isDirectory());
|
|
338
505
|
return r.ok ? r.value : false;
|
|
339
506
|
}
|
|
340
507
|
function hasAiInstructions(repoPath) {
|
|
@@ -342,11 +509,12 @@ function hasAiInstructions(repoPath) {
|
|
|
342
509
|
}
|
|
343
510
|
async function addCheckScriptToRepository(repo) {
|
|
344
511
|
let suggested = null;
|
|
345
|
-
const detectR =
|
|
512
|
+
const detectR = Result4.try(() => detectCheckScriptCandidates(repo.path));
|
|
346
513
|
if (detectR.ok && detectR.value) {
|
|
347
514
|
log.success(` Detected: ${detectR.value.typeLabel}`);
|
|
348
515
|
suggested = suggestCheckScript(repo.path);
|
|
349
516
|
}
|
|
517
|
+
suggested ??= await tryAiCheckScriptDiscovery(repo.path);
|
|
350
518
|
const checkInput = await getPrompt().input({
|
|
351
519
|
message: " Check script (optional):",
|
|
352
520
|
default: suggested ?? void 0
|
|
@@ -357,6 +525,35 @@ async function addCheckScriptToRepository(repo) {
|
|
|
357
525
|
checkScript
|
|
358
526
|
};
|
|
359
527
|
}
|
|
528
|
+
async function tryAiCheckScriptDiscovery(repoPath) {
|
|
529
|
+
const config = await getConfig();
|
|
530
|
+
const enabled = config.aiCheckScriptDiscovery ?? getConfigDefaultValue("aiCheckScriptDiscovery");
|
|
531
|
+
if (!enabled) return null;
|
|
532
|
+
if (!config.aiProvider) return null;
|
|
533
|
+
const wantAi = await getPrompt().confirm({
|
|
534
|
+
message: " No ecosystem detected. Ask AI to inspect the repo and suggest a check script?",
|
|
535
|
+
default: true
|
|
536
|
+
});
|
|
537
|
+
if (!wantAi) return null;
|
|
538
|
+
const spinner = createSpinner(" Asking AI to discover check script...").start();
|
|
539
|
+
const aiSession = new ProviderAiSessionAdapter();
|
|
540
|
+
const signalParser = new SignalParser();
|
|
541
|
+
const discoverR = await wrapAsync(async () => {
|
|
542
|
+
await aiSession.ensureReady();
|
|
543
|
+
return discoverCheckScriptWithAi(repoPath, aiSession, signalParser);
|
|
544
|
+
}, ensureError);
|
|
545
|
+
if (!discoverR.ok) {
|
|
546
|
+
spinner.fail("AI discovery unavailable");
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
const suggestion = discoverR.value;
|
|
550
|
+
if (suggestion) {
|
|
551
|
+
spinner.succeed("AI suggestion ready (review before saving)");
|
|
552
|
+
} else {
|
|
553
|
+
spinner.fail("AI returned no suggestion");
|
|
554
|
+
}
|
|
555
|
+
return suggestion;
|
|
556
|
+
}
|
|
360
557
|
async function projectAddCommand(options = {}) {
|
|
361
558
|
let name;
|
|
362
559
|
let displayName;
|
|
@@ -577,6 +774,14 @@ Configuring: ${firstRepo.name ?? basename(firstRepo.path)}`);
|
|
|
577
774
|
export {
|
|
578
775
|
PromptCancelledError,
|
|
579
776
|
escapableSelect,
|
|
777
|
+
detectCheckScriptCandidates,
|
|
778
|
+
suggestCheckScript,
|
|
779
|
+
discoverCheckScriptWithAi,
|
|
780
|
+
getAllSchemaEntries,
|
|
781
|
+
getAllConfigSchemaEntries,
|
|
782
|
+
getConfigDefaultValue,
|
|
783
|
+
validateConfigValue,
|
|
784
|
+
parseConfigValue,
|
|
580
785
|
addCheckScriptToRepository,
|
|
581
786
|
projectAddCommand
|
|
582
787
|
};
|