ralphctl 0.4.2 → 0.4.4
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-DVPVHENV.mjs} +7 -7
- package/dist/{add-GX7P7XTT.mjs → add-YVXM34RP.mjs} +6 -5
- package/dist/{chunk-GL7MKLLS.mjs → chunk-ACRMBVEE.mjs} +458 -181
- package/dist/{chunk-NUYQK5MN.mjs → chunk-BSB4EDGR.mjs} +2 -2
- package/dist/{chunk-YCDUVPRT.mjs → chunk-CBMFRQ4Y.mjs} +5 -73
- package/dist/{chunk-3QBEBKMZ.mjs → chunk-FNAAA32W.mjs} +7 -7
- package/dist/{chunk-JOQO4HMM.mjs → chunk-GQ2WFKBN.mjs} +11 -11
- package/dist/{chunk-TKPTT2UG.mjs → chunk-OFILN7QL.mjs} +798 -1023
- package/dist/{chunk-7JLZQICD.mjs → chunk-OGEXYSFS.mjs} +7 -7
- package/dist/{chunk-D2YGPLIV.mjs → chunk-PYZEQ2VK.mjs} +214 -9
- package/dist/{chunk-57UWLHRH.mjs → chunk-VAZ3LJBI.mjs} +12 -1
- package/dist/{chunk-CTP2A436.mjs → chunk-WDMLPXOD.mjs} +11 -4
- package/dist/{chunk-FKMKOWLA.mjs → chunk-XN2UIHBY.mjs} +84 -3
- package/dist/chunk-ZLWSPLWI.mjs +1117 -0
- package/dist/cli.mjs +72 -21
- package/dist/create-Z635FQKO.mjs +15 -0
- package/dist/{handle-BBAZJ44Y.mjs → handle-23EFF3BE.mjs} +1 -1
- package/dist/{mount-ISHZM36X.mjs → mount-VEV3TESX.mjs} +1702 -1202
- package/dist/{project-2IE7VWDB.mjs → project-DQHF4ISP.mjs} +3 -3
- package/dist/prompts/check-script-discover.md +69 -0
- package/dist/prompts/repo-onboard.md +111 -0
- package/dist/prompts/sprint-feedback.md +4 -0
- package/dist/prompts/task-evaluation.md +44 -2
- package/dist/prompts/task-execution.md +5 -0
- package/dist/{resolver-EOE5WUMV.mjs → resolver-OVPYVW6Q.mjs} +4 -4
- package/dist/{sprint-OGOFEJJH.mjs → sprint-4E26AB5F.mjs} +4 -4
- package/dist/start-2WH4BTDB.mjs +19 -0
- package/package.json +6 -6
- package/dist/create-7WFSCMP4.mjs +0 -15
- package/dist/start-76JKJQIH.mjs +0 -17
|
@@ -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-GQ2WFKBN.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-BSB4EDGR.mjs";
|
|
17
17
|
import {
|
|
18
18
|
getCurrentSprintOrThrow
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-CBMFRQ4Y.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-XN2UIHBY.mjs";
|
|
33
33
|
import {
|
|
34
34
|
ensureError,
|
|
35
35
|
wrapAsync
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
import {
|
|
38
38
|
IOError,
|
|
39
39
|
SprintStatusError
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-VAZ3LJBI.mjs";
|
|
41
41
|
|
|
42
42
|
// src/integration/cli/commands/ticket/add.ts
|
|
43
43
|
import { Result as Result2 } from "typescript-result";
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
ProviderAiSessionAdapter,
|
|
4
|
+
SignalParser,
|
|
5
|
+
buildCheckScriptDiscoverPrompt
|
|
6
|
+
} from "./chunk-ZLWSPLWI.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-BSB4EDGR.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-XN2UIHBY.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-WDMLPXOD.mjs";
|
|
33
39
|
import {
|
|
34
40
|
IOError,
|
|
35
|
-
ProjectExistsError
|
|
36
|
-
|
|
41
|
+
ProjectExistsError,
|
|
42
|
+
ValidationError
|
|
43
|
+
} from "./chunk-VAZ3LJBI.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
|
};
|
|
@@ -145,6 +145,16 @@ var BranchPreflightError = class extends DomainError {
|
|
|
145
145
|
this.expectedBranch = expectedBranch;
|
|
146
146
|
}
|
|
147
147
|
};
|
|
148
|
+
var ExecutionAlreadyRunningError = class extends DomainError {
|
|
149
|
+
code = "EXECUTION_ALREADY_RUNNING";
|
|
150
|
+
projectName;
|
|
151
|
+
existingExecutionId;
|
|
152
|
+
constructor(projectName, existingExecutionId) {
|
|
153
|
+
super(`An execution is already running for project '${projectName}' (id: ${existingExecutionId}).`);
|
|
154
|
+
this.projectName = projectName;
|
|
155
|
+
this.existingExecutionId = existingExecutionId;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
148
158
|
|
|
149
159
|
export {
|
|
150
160
|
DomainError,
|
|
@@ -164,5 +174,6 @@ export {
|
|
|
164
174
|
DependencyCycleError,
|
|
165
175
|
IssueFetchError,
|
|
166
176
|
StepError,
|
|
167
|
-
BranchPreflightError
|
|
177
|
+
BranchPreflightError,
|
|
178
|
+
ExecutionAlreadyRunningError
|
|
168
179
|
};
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
IOError,
|
|
4
4
|
StorageError,
|
|
5
5
|
ValidationError
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VAZ3LJBI.mjs";
|
|
7
7
|
|
|
8
8
|
// src/integration/persistence/paths.ts
|
|
9
9
|
import { isAbsolute, join, resolve, sep } from "path";
|
|
@@ -191,10 +191,11 @@ async function readTextFile(filePath) {
|
|
|
191
191
|
// src/domain/models.ts
|
|
192
192
|
import { z } from "zod";
|
|
193
193
|
var SprintStatusSchema = z.enum(["draft", "active", "closed"]);
|
|
194
|
-
var TaskStatusSchema = z.enum(["todo", "in_progress", "done"]);
|
|
194
|
+
var TaskStatusSchema = z.enum(["todo", "in_progress", "done", "cancelled"]);
|
|
195
195
|
var RequirementStatusSchema = z.enum(["pending", "approved"]);
|
|
196
196
|
var EvaluationStatusSchema = z.enum(["passed", "failed", "malformed", "plateau"]);
|
|
197
197
|
var IdSchema = z.string().min(1);
|
|
198
|
+
var CURRENT_ONBOARDING_VERSION = 1;
|
|
198
199
|
var RepositorySchema = z.object({
|
|
199
200
|
id: IdSchema,
|
|
200
201
|
// UUID8, stable across renames
|
|
@@ -204,8 +205,12 @@ var RepositorySchema = z.object({
|
|
|
204
205
|
// Absolute path
|
|
205
206
|
checkScript: z.string().optional(),
|
|
206
207
|
// e.g., "pnpm install && pnpm typecheck && pnpm lint && pnpm test"
|
|
207
|
-
checkTimeout: z.number().positive().optional()
|
|
208
|
+
checkTimeout: z.number().positive().optional(),
|
|
208
209
|
// Per-repo timeout in ms (overrides RALPHCTL_SETUP_TIMEOUT_MS)
|
|
210
|
+
// Stamped by `project onboard` on success. Absence means the repo was never
|
|
211
|
+
// onboarded; `doctor` surfaces a hint. A value < CURRENT_ONBOARDING_VERSION
|
|
212
|
+
// means the contract has drifted and re-onboarding is recommended.
|
|
213
|
+
onboardingVersion: z.number().int().nonnegative().optional()
|
|
209
214
|
});
|
|
210
215
|
var ProjectSchema = z.object({
|
|
211
216
|
id: IdSchema,
|
|
@@ -290,7 +295,8 @@ var ConfigSchema = z.object({
|
|
|
290
295
|
currentSprint: z.string().nullable().default(null),
|
|
291
296
|
aiProvider: AiProviderSchema.nullable().default(null),
|
|
292
297
|
editor: z.string().nullable().default(null),
|
|
293
|
-
evaluationIterations: z.number().int().min(0).optional()
|
|
298
|
+
evaluationIterations: z.number().int().min(0).optional(),
|
|
299
|
+
aiCheckScriptDiscovery: z.boolean().optional()
|
|
294
300
|
});
|
|
295
301
|
function getRequirementsOutputJsonSchema() {
|
|
296
302
|
return JSON.stringify(z.toJSONSchema(RefinedRequirementsSchema), null, 2);
|
|
@@ -342,6 +348,7 @@ export {
|
|
|
342
348
|
SprintStatusSchema,
|
|
343
349
|
TaskStatusSchema,
|
|
344
350
|
RequirementStatusSchema,
|
|
351
|
+
CURRENT_ONBOARDING_VERSION,
|
|
345
352
|
ProjectsSchema,
|
|
346
353
|
TasksSchema,
|
|
347
354
|
ImportTasksSchema,
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
unwrapOrThrow
|
|
4
|
+
} from "./chunk-IWXBJD2D.mjs";
|
|
5
|
+
import {
|
|
6
|
+
ConfigSchema,
|
|
7
|
+
fileExists,
|
|
8
|
+
getConfigPath,
|
|
9
|
+
readValidatedJson,
|
|
10
|
+
writeValidatedJson
|
|
11
|
+
} from "./chunk-WDMLPXOD.mjs";
|
|
2
12
|
|
|
3
13
|
// src/integration/ui/theme/theme.ts
|
|
4
14
|
import { bold, cyan, gray, green, red, yellow } from "colorette";
|
|
@@ -295,11 +305,17 @@ function labelValue(label, value, labelWidth = DETAIL_LABEL_WIDTH) {
|
|
|
295
305
|
}
|
|
296
306
|
function formatTaskStatus(status) {
|
|
297
307
|
const e = getStatusEmoji(status);
|
|
298
|
-
const labels = {
|
|
308
|
+
const labels = {
|
|
309
|
+
todo: "To Do",
|
|
310
|
+
in_progress: "In Progress",
|
|
311
|
+
done: "Done",
|
|
312
|
+
cancelled: "Cancelled"
|
|
313
|
+
};
|
|
299
314
|
const statusColors = {
|
|
300
315
|
todo: colors.muted,
|
|
301
316
|
in_progress: colors.warning,
|
|
302
|
-
done: colors.success
|
|
317
|
+
done: colors.success,
|
|
318
|
+
cancelled: colors.muted
|
|
303
319
|
};
|
|
304
320
|
return (statusColors[status] ?? colors.muted)(`${e} ${labels[status] ?? status}`);
|
|
305
321
|
}
|
|
@@ -467,6 +483,60 @@ function renderTable(columns, rows, options = {}) {
|
|
|
467
483
|
return result.join("\n");
|
|
468
484
|
}
|
|
469
485
|
|
|
486
|
+
// src/integration/persistence/config.ts
|
|
487
|
+
var DEFAULT_EVALUATION_ITERATIONS = 1;
|
|
488
|
+
var DEFAULT_CONFIG = {
|
|
489
|
+
currentSprint: null,
|
|
490
|
+
aiProvider: null,
|
|
491
|
+
editor: null
|
|
492
|
+
};
|
|
493
|
+
async function getConfig() {
|
|
494
|
+
const configPath = getConfigPath();
|
|
495
|
+
if (!await fileExists(configPath)) {
|
|
496
|
+
return DEFAULT_CONFIG;
|
|
497
|
+
}
|
|
498
|
+
return unwrapOrThrow(await readValidatedJson(configPath, ConfigSchema));
|
|
499
|
+
}
|
|
500
|
+
async function saveConfig(config) {
|
|
501
|
+
unwrapOrThrow(await writeValidatedJson(getConfigPath(), config, ConfigSchema));
|
|
502
|
+
}
|
|
503
|
+
async function getCurrentSprint() {
|
|
504
|
+
const config = await getConfig();
|
|
505
|
+
return config.currentSprint;
|
|
506
|
+
}
|
|
507
|
+
async function setCurrentSprint(sprintId) {
|
|
508
|
+
const config = await getConfig();
|
|
509
|
+
config.currentSprint = sprintId;
|
|
510
|
+
await saveConfig(config);
|
|
511
|
+
}
|
|
512
|
+
async function getAiProvider() {
|
|
513
|
+
const config = await getConfig();
|
|
514
|
+
return config.aiProvider ?? null;
|
|
515
|
+
}
|
|
516
|
+
async function setAiProvider(provider) {
|
|
517
|
+
const config = await getConfig();
|
|
518
|
+
config.aiProvider = provider;
|
|
519
|
+
await saveConfig(config);
|
|
520
|
+
}
|
|
521
|
+
async function getEditor() {
|
|
522
|
+
const config = await getConfig();
|
|
523
|
+
return config.editor ?? null;
|
|
524
|
+
}
|
|
525
|
+
async function setEditor(editor) {
|
|
526
|
+
const config = await getConfig();
|
|
527
|
+
config.editor = editor;
|
|
528
|
+
await saveConfig(config);
|
|
529
|
+
}
|
|
530
|
+
async function getEvaluationIterations() {
|
|
531
|
+
const config = await getConfig();
|
|
532
|
+
return config.evaluationIterations ?? DEFAULT_EVALUATION_ITERATIONS;
|
|
533
|
+
}
|
|
534
|
+
async function setEvaluationIterations(iterations) {
|
|
535
|
+
const config = await getConfig();
|
|
536
|
+
config.evaluationIterations = iterations;
|
|
537
|
+
await saveConfig(config);
|
|
538
|
+
}
|
|
539
|
+
|
|
470
540
|
export {
|
|
471
541
|
emoji,
|
|
472
542
|
colors,
|
|
@@ -491,6 +561,7 @@ export {
|
|
|
491
561
|
showRandomQuote,
|
|
492
562
|
printCountSummary,
|
|
493
563
|
printBanner,
|
|
564
|
+
isTTY,
|
|
494
565
|
terminalBell,
|
|
495
566
|
createSpinner,
|
|
496
567
|
field,
|
|
@@ -504,5 +575,15 @@ export {
|
|
|
504
575
|
horizontalLine,
|
|
505
576
|
renderCard,
|
|
506
577
|
progressBar,
|
|
507
|
-
renderTable
|
|
578
|
+
renderTable,
|
|
579
|
+
getConfig,
|
|
580
|
+
saveConfig,
|
|
581
|
+
getCurrentSprint,
|
|
582
|
+
setCurrentSprint,
|
|
583
|
+
getAiProvider,
|
|
584
|
+
setAiProvider,
|
|
585
|
+
getEditor,
|
|
586
|
+
setEditor,
|
|
587
|
+
getEvaluationIterations,
|
|
588
|
+
setEvaluationIterations
|
|
508
589
|
};
|