cortex-agents 4.0.2 → 4.0.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/dist/tools/quality-gate.d.ts +2 -0
- package/dist/tools/quality-gate.d.ts.map +1 -1
- package/dist/tools/quality-gate.js +14 -3
- package/dist/tools/repl.d.ts.map +1 -1
- package/dist/tools/repl.js +1 -0
- package/dist/tools/session.d.ts.map +1 -1
- package/dist/tools/session.js +36 -1
- package/dist/tools/task.d.ts.map +1 -1
- package/dist/tools/task.js +15 -2
- package/dist/utils/change-scope.d.ts.map +1 -1
- package/dist/utils/change-scope.js +9 -14
- package/dist/utils/repl.d.ts +9 -0
- package/dist/utils/repl.d.ts.map +1 -1
- package/dist/utils/repl.js +36 -6
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ export declare const qualityGateSummary: {
|
|
|
8
8
|
description: string;
|
|
9
9
|
args: {
|
|
10
10
|
scope: import("zod").ZodOptional<import("zod").ZodString>;
|
|
11
|
+
changedFiles: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
11
12
|
testing: import("zod").ZodOptional<import("zod").ZodString>;
|
|
12
13
|
security: import("zod").ZodOptional<import("zod").ZodString>;
|
|
13
14
|
audit: import("zod").ZodOptional<import("zod").ZodString>;
|
|
@@ -17,6 +18,7 @@ export declare const qualityGateSummary: {
|
|
|
17
18
|
};
|
|
18
19
|
execute(args: {
|
|
19
20
|
scope?: string | undefined;
|
|
21
|
+
changedFiles?: string[] | undefined;
|
|
20
22
|
testing?: string | undefined;
|
|
21
23
|
security?: string | undefined;
|
|
22
24
|
audit?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quality-gate.d.ts","sourceRoot":"","sources":["../../src/tools/quality-gate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"quality-gate.d.ts","sourceRoot":"","sources":["../../src/tools/quality-gate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8CH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;CA0J7B,CAAC"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { tool } from "@opencode-ai/plugin";
|
|
8
8
|
import * as fs from "fs";
|
|
9
9
|
import * as path from "path";
|
|
10
|
+
import { classifyChangeScope } from "../utils/change-scope.js";
|
|
10
11
|
const CORTEX_DIR = ".cortex";
|
|
11
12
|
const QUALITY_GATE_FILE = "quality-gate.json";
|
|
12
13
|
// ─── Severity ordering ───────────────────────────────────────────────────────
|
|
@@ -27,7 +28,11 @@ export const qualityGateSummary = tool({
|
|
|
27
28
|
scope: tool.schema
|
|
28
29
|
.string()
|
|
29
30
|
.optional()
|
|
30
|
-
.describe("Change scope classification: trivial, low, standard, high"),
|
|
31
|
+
.describe("Change scope classification: trivial, low, standard, high. If changedFiles is provided, this is auto-classified and this field is ignored."),
|
|
32
|
+
changedFiles: tool.schema
|
|
33
|
+
.array(tool.schema.string())
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Array of changed file paths. When provided, scope is auto-classified using classifyChangeScope."),
|
|
31
36
|
testing: tool.schema
|
|
32
37
|
.string()
|
|
33
38
|
.optional()
|
|
@@ -56,6 +61,12 @@ export const qualityGateSummary = tool({
|
|
|
56
61
|
async execute(args, context) {
|
|
57
62
|
const cwd = context.worktree;
|
|
58
63
|
const reports = [];
|
|
64
|
+
// Auto-classify scope from changed files if provided
|
|
65
|
+
let resolvedScope = args.scope ?? "unknown";
|
|
66
|
+
if (args.changedFiles && args.changedFiles.length > 0) {
|
|
67
|
+
const classification = classifyChangeScope(args.changedFiles);
|
|
68
|
+
resolvedScope = classification.scope;
|
|
69
|
+
}
|
|
59
70
|
// Parse each provided report
|
|
60
71
|
const agentEntries = [
|
|
61
72
|
["testing", args.testing],
|
|
@@ -93,7 +104,7 @@ export const qualityGateSummary = tool({
|
|
|
93
104
|
// Build state for persistence
|
|
94
105
|
const state = {
|
|
95
106
|
timestamp: new Date().toISOString(),
|
|
96
|
-
scope:
|
|
107
|
+
scope: resolvedScope,
|
|
97
108
|
reports,
|
|
98
109
|
recommendation,
|
|
99
110
|
};
|
|
@@ -104,7 +115,7 @@ export const qualityGateSummary = tool({
|
|
|
104
115
|
lines.push(`\u2713 Quality Gate Summary`);
|
|
105
116
|
lines.push("");
|
|
106
117
|
lines.push(`**Recommendation: ${recommendation}**`);
|
|
107
|
-
lines.push(`Scope: ${
|
|
118
|
+
lines.push(`Scope: ${resolvedScope}`);
|
|
108
119
|
lines.push(`Agents: ${reports.map((r) => r.agent).join(", ")}`);
|
|
109
120
|
lines.push(`Total findings: ${allFindings.length}`);
|
|
110
121
|
lines.push("");
|
package/dist/tools/repl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/tools/repl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0BH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/tools/repl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0BH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;CAyGf,CAAC;AAIH,eAAO,MAAM,MAAM;;;;CA0BjB,CAAC;AAIH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;CAwCjB,CAAC;AAkFH,eAAO,MAAM,MAAM;;;;CA+CjB,CAAC;AAIH,eAAO,MAAM,OAAO;;;;CAclB,CAAC"}
|
package/dist/tools/repl.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/tools/session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/tools/session.ts"],"names":[],"mappings":"AA4DA,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;CA2Ff,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;CA8Df,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;CAuBf,CAAC"}
|
package/dist/tools/session.js
CHANGED
|
@@ -2,8 +2,40 @@ import { tool } from "@opencode-ai/plugin";
|
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { git } from "../utils/shell.js";
|
|
5
|
+
import { readCortexConfig } from "../utils/repl.js";
|
|
5
6
|
const CORTEX_DIR = ".cortex";
|
|
6
7
|
const SESSIONS_DIR = "sessions";
|
|
8
|
+
/**
|
|
9
|
+
* Delete session files older than the configured retention period.
|
|
10
|
+
*/
|
|
11
|
+
function cleanExpiredSessions(worktree) {
|
|
12
|
+
const config = readCortexConfig(worktree);
|
|
13
|
+
const retentionDays = config.sessionRetentionDays;
|
|
14
|
+
if (!retentionDays || retentionDays <= 0)
|
|
15
|
+
return 0;
|
|
16
|
+
const sessionsPath = path.join(worktree, CORTEX_DIR, SESSIONS_DIR);
|
|
17
|
+
if (!fs.existsSync(sessionsPath))
|
|
18
|
+
return 0;
|
|
19
|
+
const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
|
|
20
|
+
let deleted = 0;
|
|
21
|
+
for (const file of fs.readdirSync(sessionsPath)) {
|
|
22
|
+
if (!file.endsWith(".md"))
|
|
23
|
+
continue;
|
|
24
|
+
// Session filenames start with YYYY-MM-DD — parse the date prefix
|
|
25
|
+
const dateStr = file.substring(0, 10);
|
|
26
|
+
const fileDate = new Date(dateStr);
|
|
27
|
+
if (!isNaN(fileDate.getTime()) && fileDate.getTime() < cutoff) {
|
|
28
|
+
try {
|
|
29
|
+
fs.unlinkSync(path.join(sessionsPath, file));
|
|
30
|
+
deleted++;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Ignore deletion errors
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return deleted;
|
|
38
|
+
}
|
|
7
39
|
function getDatePrefix() {
|
|
8
40
|
const now = new Date();
|
|
9
41
|
return now.toISOString().split("T")[0]; // YYYY-MM-DD
|
|
@@ -90,12 +122,15 @@ See: \`.cortex/plans/${relatedPlan}\`
|
|
|
90
122
|
}
|
|
91
123
|
// Write file
|
|
92
124
|
fs.writeFileSync(filepath, content);
|
|
125
|
+
// Clean up expired sessions based on retention config
|
|
126
|
+
const cleaned = cleanExpiredSessions(context.worktree);
|
|
127
|
+
const cleanedMsg = cleaned > 0 ? `\nCleaned up ${cleaned} expired session(s).` : "";
|
|
93
128
|
return `✓ Session summary saved
|
|
94
129
|
|
|
95
130
|
File: ${filename}
|
|
96
131
|
Branch: ${currentBranch}
|
|
97
132
|
Decisions recorded: ${decisions.length}
|
|
98
|
-
${filesChanged ? `Files tracked: ${filesChanged.length}` : ""}
|
|
133
|
+
${filesChanged ? `Files tracked: ${filesChanged.length}` : ""}${cleanedMsg}
|
|
99
134
|
|
|
100
135
|
Session summaries are stored in .cortex/sessions/ and gitignored by default.`;
|
|
101
136
|
},
|
package/dist/tools/task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"AAgFA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;CAyPnB,CAAC"}
|
package/dist/tools/task.js
CHANGED
|
@@ -5,6 +5,7 @@ import { detectWorktreeInfo } from "../utils/worktree-detect.js";
|
|
|
5
5
|
import { findPlanContent, extractPlanSections, extractIssueRefs, buildPrBodyFromPlan, } from "../utils/plan-extract.js";
|
|
6
6
|
import { git, gh } from "../utils/shell.js";
|
|
7
7
|
import { checkGhAvailability } from "../utils/github.js";
|
|
8
|
+
const CORTEX_DIR = ".cortex";
|
|
8
9
|
const PROTECTED_BRANCHES = ["main", "master", "develop", "production", "staging"];
|
|
9
10
|
const DOCS_DIR = "docs";
|
|
10
11
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
@@ -162,9 +163,21 @@ Create a feature/bugfix branch first with branch_create or worktree_create.`;
|
|
|
162
163
|
else {
|
|
163
164
|
output.push(`Documentation: ${docsCheck.count} doc(s) found`);
|
|
164
165
|
}
|
|
165
|
-
// ── 6. Stage
|
|
166
|
+
// ── 6. Stage changes safely ─────────────────────────────
|
|
166
167
|
try {
|
|
167
|
-
|
|
168
|
+
// Stage tracked file changes (safe — won't pick up new untracked files)
|
|
169
|
+
await git(cwd, "add", "-u");
|
|
170
|
+
// Stage .cortex/ directory explicitly (plans, state, etc.)
|
|
171
|
+
const cortexPath = path.join(cwd, CORTEX_DIR);
|
|
172
|
+
if (fs.existsSync(cortexPath)) {
|
|
173
|
+
await git(cwd, "add", CORTEX_DIR);
|
|
174
|
+
}
|
|
175
|
+
// Warn about untracked files that won't be staged
|
|
176
|
+
const { stdout: untrackedOut } = await git(cwd, "ls-files", "--others", "--exclude-standard");
|
|
177
|
+
const untrackedFiles = untrackedOut.trim().split("\n").filter(Boolean);
|
|
178
|
+
if (untrackedFiles.length > 0) {
|
|
179
|
+
warnings.push(`${untrackedFiles.length} untracked file(s) not staged: ${untrackedFiles.slice(0, 5).join(", ")}${untrackedFiles.length > 5 ? ` (and ${untrackedFiles.length - 5} more)` : ""}. Stage them manually with \`git add <file>\` if needed.`);
|
|
180
|
+
}
|
|
168
181
|
}
|
|
169
182
|
catch (error) {
|
|
170
183
|
return `✗ Error staging changes: ${error.message || error}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-scope.d.ts","sourceRoot":"","sources":["../../src/utils/change-scope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,KAAK,EAAE,WAAW,CAAC;IACnB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"change-scope.d.ts","sourceRoot":"","sources":["../../src/utils/change-scope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,KAAK,EAAE,WAAW,CAAC;IACnB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;CACrB;AAmHD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAsE7E"}
|
|
@@ -34,13 +34,14 @@ const LOW_RISK_PATTERNS = [
|
|
|
34
34
|
];
|
|
35
35
|
/** Patterns that indicate high-risk changes — auth, payments, infra, security */
|
|
36
36
|
const HIGH_RISK_PATTERNS = [
|
|
37
|
-
// Auth & security
|
|
38
|
-
/
|
|
37
|
+
// Auth & security — match directory boundaries, not arbitrary substrings
|
|
38
|
+
/\bauth[/\-._]/i,
|
|
39
|
+
/\/auth\b/i,
|
|
39
40
|
/login/i,
|
|
40
|
-
|
|
41
|
+
/\/session\b/i,
|
|
41
42
|
/password/i,
|
|
42
|
-
/
|
|
43
|
-
/
|
|
43
|
+
/\/tokens?\b/i,
|
|
44
|
+
/\bcrypto[/\-._]/i,
|
|
44
45
|
/encrypt/i,
|
|
45
46
|
/permission/i,
|
|
46
47
|
/rbac/i,
|
|
@@ -51,7 +52,7 @@ const HIGH_RISK_PATTERNS = [
|
|
|
51
52
|
/payment/i,
|
|
52
53
|
/billing/i,
|
|
53
54
|
/stripe/i,
|
|
54
|
-
|
|
55
|
+
/\/checkout\b/i,
|
|
55
56
|
// Infrastructure & deployment
|
|
56
57
|
/Dockerfile/i,
|
|
57
58
|
/docker-compose/i,
|
|
@@ -93,21 +94,15 @@ const DEVOPS_PATTERNS = [
|
|
|
93
94
|
];
|
|
94
95
|
/** Patterns that indicate performance-sensitive changes */
|
|
95
96
|
const PERF_PATTERNS = [
|
|
96
|
-
/
|
|
97
|
+
/\/queries?\b/i,
|
|
97
98
|
/database/i,
|
|
98
99
|
/migration/i,
|
|
99
100
|
/\.sql$/i,
|
|
100
101
|
/prisma/i,
|
|
101
102
|
/drizzle/i,
|
|
102
103
|
/repository/i,
|
|
103
|
-
|
|
104
|
-
/render/i,
|
|
105
|
-
/component/i,
|
|
106
|
-
/hook/i,
|
|
104
|
+
/\/cache[/\-._]/i,
|
|
107
105
|
/algorithm/i,
|
|
108
|
-
/sort/i,
|
|
109
|
-
/search/i,
|
|
110
|
-
/index/i,
|
|
111
106
|
/worker/i,
|
|
112
107
|
/stream/i,
|
|
113
108
|
/batch/i,
|
package/dist/utils/repl.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export interface ReplTask {
|
|
|
35
35
|
completedAt?: string;
|
|
36
36
|
}
|
|
37
37
|
export interface ReplState {
|
|
38
|
+
/** Schema version for migration support */
|
|
39
|
+
version: number;
|
|
38
40
|
/** Source plan filename */
|
|
39
41
|
planFilename: string;
|
|
40
42
|
/** ISO timestamp when the loop started */
|
|
@@ -57,6 +59,8 @@ export interface ReplState {
|
|
|
57
59
|
export interface CortexConfig {
|
|
58
60
|
/** Max retries per task before escalating to user */
|
|
59
61
|
maxRetries?: number;
|
|
62
|
+
/** Session retention in days */
|
|
63
|
+
sessionRetentionDays?: number;
|
|
60
64
|
}
|
|
61
65
|
export interface CommandDetection {
|
|
62
66
|
buildCommand: string | null;
|
|
@@ -86,6 +90,11 @@ export declare function parseTasksFromPlan(planContent: string): string[];
|
|
|
86
90
|
* Returns structured tasks including `- AC:` lines found under each checkbox item.
|
|
87
91
|
*/
|
|
88
92
|
export declare function parseTasksWithAC(planContent: string): ParsedTask[];
|
|
93
|
+
/**
|
|
94
|
+
* Detect the package manager from lockfiles.
|
|
95
|
+
* Priority: bun > pnpm > yarn > npm (fallback)
|
|
96
|
+
*/
|
|
97
|
+
export declare function detectPackageManager(cwd: string): "bun" | "pnpm" | "yarn" | "npm";
|
|
89
98
|
/**
|
|
90
99
|
* Auto-detect build, test, and lint commands from project configuration files.
|
|
91
100
|
*
|
package/dist/utils/repl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/utils/repl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/utils/repl.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/repl.js
CHANGED
|
@@ -13,6 +13,7 @@ import * as path from "path";
|
|
|
13
13
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
14
14
|
const CORTEX_DIR = ".cortex";
|
|
15
15
|
const REPL_STATE_FILE = "repl-state.json";
|
|
16
|
+
const REPL_STATE_VERSION = 1;
|
|
16
17
|
/**
|
|
17
18
|
* Parse plan tasks from plan markdown content.
|
|
18
19
|
*
|
|
@@ -89,6 +90,23 @@ function extractTasksSection(content) {
|
|
|
89
90
|
return sectionLines.length > 0 ? sectionLines.join("\n") : null;
|
|
90
91
|
}
|
|
91
92
|
// ─── Command Auto-Detection ──────────────────────────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* Detect the package manager from lockfiles.
|
|
95
|
+
* Priority: bun > pnpm > yarn > npm (fallback)
|
|
96
|
+
*/
|
|
97
|
+
export function detectPackageManager(cwd) {
|
|
98
|
+
if (fs.existsSync(path.join(cwd, "bun.lockb")) ||
|
|
99
|
+
fs.existsSync(path.join(cwd, "bun.lock"))) {
|
|
100
|
+
return "bun";
|
|
101
|
+
}
|
|
102
|
+
if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) {
|
|
103
|
+
return "pnpm";
|
|
104
|
+
}
|
|
105
|
+
if (fs.existsSync(path.join(cwd, "yarn.lock"))) {
|
|
106
|
+
return "yarn";
|
|
107
|
+
}
|
|
108
|
+
return "npm";
|
|
109
|
+
}
|
|
92
110
|
/**
|
|
93
111
|
* Auto-detect build, test, and lint commands from project configuration files.
|
|
94
112
|
*
|
|
@@ -116,30 +134,32 @@ export async function detectCommands(cwd) {
|
|
|
116
134
|
const scripts = pkg.scripts || {};
|
|
117
135
|
const devDeps = pkg.devDependencies || {};
|
|
118
136
|
const deps = pkg.dependencies || {};
|
|
137
|
+
// Detect package manager from lockfiles
|
|
138
|
+
const pm = detectPackageManager(cwd);
|
|
119
139
|
// Build command
|
|
120
140
|
if (scripts.build) {
|
|
121
|
-
result.buildCommand = "
|
|
141
|
+
result.buildCommand = pm === "yarn" ? "yarn build" : `${pm} run build`;
|
|
122
142
|
}
|
|
123
143
|
// Test command — prefer specific runner detection
|
|
124
144
|
if (devDeps.vitest || deps.vitest) {
|
|
125
|
-
result.testCommand = "npx vitest run";
|
|
145
|
+
result.testCommand = pm === "bun" ? "bun vitest run" : "npx vitest run";
|
|
126
146
|
result.framework = "vitest";
|
|
127
147
|
}
|
|
128
148
|
else if (devDeps.jest || deps.jest) {
|
|
129
|
-
result.testCommand = "npx jest";
|
|
149
|
+
result.testCommand = pm === "bun" ? "bun jest" : "npx jest";
|
|
130
150
|
result.framework = "jest";
|
|
131
151
|
}
|
|
132
152
|
else if (devDeps.mocha || deps.mocha) {
|
|
133
|
-
result.testCommand = "npx mocha";
|
|
153
|
+
result.testCommand = pm === "bun" ? "bun mocha" : "npx mocha";
|
|
134
154
|
result.framework = "mocha";
|
|
135
155
|
}
|
|
136
156
|
else if (scripts.test && scripts.test !== 'echo "Error: no test specified" && exit 1') {
|
|
137
|
-
result.testCommand = "
|
|
157
|
+
result.testCommand = pm === "yarn" ? "yarn test" : `${pm} test`;
|
|
138
158
|
result.framework = "npm-test";
|
|
139
159
|
}
|
|
140
160
|
// Lint command
|
|
141
161
|
if (scripts.lint) {
|
|
142
|
-
result.lintCommand = "
|
|
162
|
+
result.lintCommand = pm === "yarn" ? "yarn lint" : `${pm} run lint`;
|
|
143
163
|
}
|
|
144
164
|
result.detected = !!(result.buildCommand || result.testCommand);
|
|
145
165
|
if (result.detected)
|
|
@@ -238,8 +258,10 @@ export function readCortexConfig(cwd) {
|
|
|
238
258
|
const raw = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
239
259
|
if (typeof raw !== "object" || raw === null)
|
|
240
260
|
return {};
|
|
261
|
+
const sessions = typeof raw.sessions === "object" && raw.sessions !== null ? raw.sessions : {};
|
|
241
262
|
return {
|
|
242
263
|
maxRetries: typeof raw.maxRetries === "number" ? raw.maxRetries : undefined,
|
|
264
|
+
sessionRetentionDays: typeof sessions.retention === "number" ? sessions.retention : undefined,
|
|
243
265
|
};
|
|
244
266
|
}
|
|
245
267
|
catch {
|
|
@@ -273,6 +295,14 @@ export function readReplState(cwd) {
|
|
|
273
295
|
!Array.isArray(raw.tasks)) {
|
|
274
296
|
return null;
|
|
275
297
|
}
|
|
298
|
+
// Migrate from v0 (no version field) to v1
|
|
299
|
+
if (typeof raw.version !== "number") {
|
|
300
|
+
raw.version = REPL_STATE_VERSION;
|
|
301
|
+
}
|
|
302
|
+
// Reject state from a newer version we don't understand
|
|
303
|
+
if (raw.version > REPL_STATE_VERSION) {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
276
306
|
// Backward compatibility: ensure all tasks have acceptanceCriteria
|
|
277
307
|
for (const task of raw.tasks) {
|
|
278
308
|
if (!Array.isArray(task.acceptanceCriteria)) {
|
package/package.json
CHANGED