cortex-agents 4.0.1 → 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/cli.js CHANGED
@@ -4,10 +4,10 @@ import * as path from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  import prompts from "prompts";
6
6
  import { PRIMARY_AGENTS, SUBAGENTS, ALL_AGENTS, DISABLED_BUILTIN_AGENTS, STALE_AGENT_FILES, getPrimaryChoices, getSubagentChoices, } from "./registry.js";
7
- const VERSION = "4.0.0";
8
7
  const PLUGIN_NAME = "cortex-agents";
9
8
  const __filename = fileURLToPath(import.meta.url);
10
9
  const __dirname = path.dirname(__filename);
10
+ const VERSION = JSON.parse(fs.readFileSync(path.resolve(__dirname, "..", "package.json"), "utf-8")).version;
11
11
  // The .opencode directory shipped with the package (adjacent to dist/)
12
12
  const PACKAGE_OPENCODE_DIR = path.resolve(__dirname, "..", ".opencode");
13
13
  // ─── Config Helpers ──────────────────────────────────────────────────────────
@@ -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;AA6CH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;CA+I7B,CAAC"}
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: args.scope ?? "unknown",
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: ${args.scope ?? "unknown"}`);
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("");
@@ -1 +1 @@
1
- {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/tools/repl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0BH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;CAwGf,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"}
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"}
@@ -73,6 +73,7 @@ export const init = tool({
73
73
  iterations: [],
74
74
  }));
75
75
  const state = {
76
+ version: 1,
76
77
  planFilename,
77
78
  startedAt: new Date().toISOString(),
78
79
  buildCommand: finalBuild,
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/tools/session.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;CAuFf,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;CA8Df,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;CAuBf,CAAC"}
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"}
@@ -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
  },
@@ -1 +1 @@
1
- {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"AA+EA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;CA0OnB,CAAC"}
1
+ {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"AAgFA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;CAyPnB,CAAC"}
@@ -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 all changes ──────────────────────────────────
166
+ // ── 6. Stage changes safely ─────────────────────────────
166
167
  try {
167
- await git(cwd, "add", "-A");
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;AAwHD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAsE7E"}
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
- /auth/i,
37
+ // Auth & security — match directory boundaries, not arbitrary substrings
38
+ /\bauth[/\-._]/i,
39
+ /\/auth\b/i,
39
40
  /login/i,
40
- /session/i,
41
+ /\/session\b/i,
41
42
  /password/i,
42
- /token/i,
43
- /crypto/i,
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
- /checkout/i,
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
- /query/i,
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
- /cache/i,
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,
@@ -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
  *
@@ -1 +1 @@
1
- {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/utils/repl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/utils/repl.ts"],"names":[],"mappings":"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"}
@@ -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 = "npm run build";
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 = "npm test";
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 = "npm run lint";
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortex-agents",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
4
4
  "description": "Supercharge OpenCode with structured workflows, intelligent agents, and automated development practices",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",