mrvn-cli 0.2.6 → 0.2.9

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/index.js CHANGED
@@ -333,13 +333,10 @@ var DocumentStore = class {
333
333
  if (!prefix) {
334
334
  throw new Error(`Unknown document type: ${type}`);
335
335
  }
336
- const dirName = this.typeDirs[type];
337
- const dir = path3.join(this.docsDir, dirName);
338
- if (!fs3.existsSync(dir)) return `${prefix}-001`;
339
- const files = fs3.readdirSync(dir).filter((f) => f.endsWith(".md"));
336
+ const pattern = new RegExp(`^${prefix}-(\\d+)$`);
340
337
  let maxNum = 0;
341
- for (const file2 of files) {
342
- const match = file2.match(new RegExp(`^${prefix}-(\\d+)\\.md$`));
338
+ for (const id of this.index.keys()) {
339
+ const match = id.match(pattern);
343
340
  if (match) {
344
341
  maxNum = Math.max(maxNum, parseInt(match[1], 10));
345
342
  }
@@ -500,14 +497,14 @@ function getPersona(idOrShortName) {
500
497
  function listPersonas() {
501
498
  return [...BUILTIN_PERSONAS];
502
499
  }
503
- function resolvePersonaId(input3) {
504
- const persona = getPersona(input3);
500
+ function resolvePersonaId(input4) {
501
+ const persona = getPersona(input4);
505
502
  if (!persona) {
506
503
  const available = BUILTIN_PERSONAS.map(
507
504
  (p) => `${p.shortName} (${p.name})`
508
505
  ).join(", ");
509
506
  throw new Error(
510
- `Unknown persona "${input3}". Available: ${available}`
507
+ `Unknown persona "${input4}". Available: ${available}`
511
508
  );
512
509
  }
513
510
  return persona.id;
@@ -1266,8 +1263,8 @@ function cached(getter) {
1266
1263
  }
1267
1264
  };
1268
1265
  }
1269
- function nullish(input3) {
1270
- return input3 === null || input3 === void 0;
1266
+ function nullish(input4) {
1267
+ return input4 === null || input4 === void 0;
1271
1268
  }
1272
1269
  function cleanRegex(source) {
1273
1270
  const start = source.startsWith("^") ? 1 : 0;
@@ -1361,8 +1358,8 @@ function randomString(length = 10) {
1361
1358
  function esc(str) {
1362
1359
  return JSON.stringify(str);
1363
1360
  }
1364
- function slugify2(input3) {
1365
- return input3.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
1361
+ function slugify2(input4) {
1362
+ return input4.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
1366
1363
  }
1367
1364
  var captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {
1368
1365
  };
@@ -1744,19 +1741,19 @@ function finalizeIssue(iss, ctx, config2) {
1744
1741
  }
1745
1742
  return full;
1746
1743
  }
1747
- function getSizableOrigin(input3) {
1748
- if (input3 instanceof Set)
1744
+ function getSizableOrigin(input4) {
1745
+ if (input4 instanceof Set)
1749
1746
  return "set";
1750
- if (input3 instanceof Map)
1747
+ if (input4 instanceof Map)
1751
1748
  return "map";
1752
- if (input3 instanceof File)
1749
+ if (input4 instanceof File)
1753
1750
  return "file";
1754
1751
  return "unknown";
1755
1752
  }
1756
- function getLengthableOrigin(input3) {
1757
- if (Array.isArray(input3))
1753
+ function getLengthableOrigin(input4) {
1754
+ if (Array.isArray(input4))
1758
1755
  return "array";
1759
- if (typeof input3 === "string")
1756
+ if (typeof input4 === "string")
1760
1757
  return "string";
1761
1758
  return "unknown";
1762
1759
  }
@@ -1782,12 +1779,12 @@ function parsedType(data) {
1782
1779
  return t;
1783
1780
  }
1784
1781
  function issue(...args) {
1785
- const [iss, input3, inst] = args;
1782
+ const [iss, input4, inst] = args;
1786
1783
  if (typeof iss === "string") {
1787
1784
  return {
1788
1785
  message: iss,
1789
1786
  code: "custom",
1790
- input: input3,
1787
+ input: input4,
1791
1788
  inst
1792
1789
  };
1793
1790
  }
@@ -2326,23 +2323,23 @@ var $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberFormat"
2326
2323
  bag.pattern = integer;
2327
2324
  });
2328
2325
  inst._zod.check = (payload) => {
2329
- const input3 = payload.value;
2326
+ const input4 = payload.value;
2330
2327
  if (isInt) {
2331
- if (!Number.isInteger(input3)) {
2328
+ if (!Number.isInteger(input4)) {
2332
2329
  payload.issues.push({
2333
2330
  expected: origin,
2334
2331
  format: def.format,
2335
2332
  code: "invalid_type",
2336
2333
  continue: false,
2337
- input: input3,
2334
+ input: input4,
2338
2335
  inst
2339
2336
  });
2340
2337
  return;
2341
2338
  }
2342
- if (!Number.isSafeInteger(input3)) {
2343
- if (input3 > 0) {
2339
+ if (!Number.isSafeInteger(input4)) {
2340
+ if (input4 > 0) {
2344
2341
  payload.issues.push({
2345
- input: input3,
2342
+ input: input4,
2346
2343
  code: "too_big",
2347
2344
  maximum: Number.MAX_SAFE_INTEGER,
2348
2345
  note: "Integers must be within the safe integer range.",
@@ -2353,7 +2350,7 @@ var $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberFormat"
2353
2350
  });
2354
2351
  } else {
2355
2352
  payload.issues.push({
2356
- input: input3,
2353
+ input: input4,
2357
2354
  code: "too_small",
2358
2355
  minimum: Number.MIN_SAFE_INTEGER,
2359
2356
  note: "Integers must be within the safe integer range.",
@@ -2366,10 +2363,10 @@ var $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberFormat"
2366
2363
  return;
2367
2364
  }
2368
2365
  }
2369
- if (input3 < minimum) {
2366
+ if (input4 < minimum) {
2370
2367
  payload.issues.push({
2371
2368
  origin: "number",
2372
- input: input3,
2369
+ input: input4,
2373
2370
  code: "too_small",
2374
2371
  minimum,
2375
2372
  inclusive: true,
@@ -2377,10 +2374,10 @@ var $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberFormat"
2377
2374
  continue: !def.abort
2378
2375
  });
2379
2376
  }
2380
- if (input3 > maximum) {
2377
+ if (input4 > maximum) {
2381
2378
  payload.issues.push({
2382
2379
  origin: "number",
2383
- input: input3,
2380
+ input: input4,
2384
2381
  code: "too_big",
2385
2382
  maximum,
2386
2383
  inclusive: true,
@@ -2400,11 +2397,11 @@ var $ZodCheckBigIntFormat = /* @__PURE__ */ $constructor("$ZodCheckBigIntFormat"
2400
2397
  bag.maximum = maximum;
2401
2398
  });
2402
2399
  inst._zod.check = (payload) => {
2403
- const input3 = payload.value;
2404
- if (input3 < minimum) {
2400
+ const input4 = payload.value;
2401
+ if (input4 < minimum) {
2405
2402
  payload.issues.push({
2406
2403
  origin: "bigint",
2407
- input: input3,
2404
+ input: input4,
2408
2405
  code: "too_small",
2409
2406
  minimum,
2410
2407
  inclusive: true,
@@ -2412,10 +2409,10 @@ var $ZodCheckBigIntFormat = /* @__PURE__ */ $constructor("$ZodCheckBigIntFormat"
2412
2409
  continue: !def.abort
2413
2410
  });
2414
2411
  }
2415
- if (input3 > maximum) {
2412
+ if (input4 > maximum) {
2416
2413
  payload.issues.push({
2417
2414
  origin: "bigint",
2418
- input: input3,
2415
+ input: input4,
2419
2416
  code: "too_big",
2420
2417
  maximum,
2421
2418
  inclusive: true,
@@ -2438,16 +2435,16 @@ var $ZodCheckMaxSize = /* @__PURE__ */ $constructor("$ZodCheckMaxSize", (inst, d
2438
2435
  inst2._zod.bag.maximum = def.maximum;
2439
2436
  });
2440
2437
  inst._zod.check = (payload) => {
2441
- const input3 = payload.value;
2442
- const size = input3.size;
2438
+ const input4 = payload.value;
2439
+ const size = input4.size;
2443
2440
  if (size <= def.maximum)
2444
2441
  return;
2445
2442
  payload.issues.push({
2446
- origin: getSizableOrigin(input3),
2443
+ origin: getSizableOrigin(input4),
2447
2444
  code: "too_big",
2448
2445
  maximum: def.maximum,
2449
2446
  inclusive: true,
2450
- input: input3,
2447
+ input: input4,
2451
2448
  inst,
2452
2449
  continue: !def.abort
2453
2450
  });
@@ -2466,16 +2463,16 @@ var $ZodCheckMinSize = /* @__PURE__ */ $constructor("$ZodCheckMinSize", (inst, d
2466
2463
  inst2._zod.bag.minimum = def.minimum;
2467
2464
  });
2468
2465
  inst._zod.check = (payload) => {
2469
- const input3 = payload.value;
2470
- const size = input3.size;
2466
+ const input4 = payload.value;
2467
+ const size = input4.size;
2471
2468
  if (size >= def.minimum)
2472
2469
  return;
2473
2470
  payload.issues.push({
2474
- origin: getSizableOrigin(input3),
2471
+ origin: getSizableOrigin(input4),
2475
2472
  code: "too_small",
2476
2473
  minimum: def.minimum,
2477
2474
  inclusive: true,
2478
- input: input3,
2475
+ input: input4,
2479
2476
  inst,
2480
2477
  continue: !def.abort
2481
2478
  });
@@ -2495,13 +2492,13 @@ var $ZodCheckSizeEquals = /* @__PURE__ */ $constructor("$ZodCheckSizeEquals", (i
2495
2492
  bag.size = def.size;
2496
2493
  });
2497
2494
  inst._zod.check = (payload) => {
2498
- const input3 = payload.value;
2499
- const size = input3.size;
2495
+ const input4 = payload.value;
2496
+ const size = input4.size;
2500
2497
  if (size === def.size)
2501
2498
  return;
2502
2499
  const tooBig = size > def.size;
2503
2500
  payload.issues.push({
2504
- origin: getSizableOrigin(input3),
2501
+ origin: getSizableOrigin(input4),
2505
2502
  ...tooBig ? { code: "too_big", maximum: def.size } : { code: "too_small", minimum: def.size },
2506
2503
  inclusive: true,
2507
2504
  exact: true,
@@ -2524,17 +2521,17 @@ var $ZodCheckMaxLength = /* @__PURE__ */ $constructor("$ZodCheckMaxLength", (ins
2524
2521
  inst2._zod.bag.maximum = def.maximum;
2525
2522
  });
2526
2523
  inst._zod.check = (payload) => {
2527
- const input3 = payload.value;
2528
- const length = input3.length;
2524
+ const input4 = payload.value;
2525
+ const length = input4.length;
2529
2526
  if (length <= def.maximum)
2530
2527
  return;
2531
- const origin = getLengthableOrigin(input3);
2528
+ const origin = getLengthableOrigin(input4);
2532
2529
  payload.issues.push({
2533
2530
  origin,
2534
2531
  code: "too_big",
2535
2532
  maximum: def.maximum,
2536
2533
  inclusive: true,
2537
- input: input3,
2534
+ input: input4,
2538
2535
  inst,
2539
2536
  continue: !def.abort
2540
2537
  });
@@ -2553,17 +2550,17 @@ var $ZodCheckMinLength = /* @__PURE__ */ $constructor("$ZodCheckMinLength", (ins
2553
2550
  inst2._zod.bag.minimum = def.minimum;
2554
2551
  });
2555
2552
  inst._zod.check = (payload) => {
2556
- const input3 = payload.value;
2557
- const length = input3.length;
2553
+ const input4 = payload.value;
2554
+ const length = input4.length;
2558
2555
  if (length >= def.minimum)
2559
2556
  return;
2560
- const origin = getLengthableOrigin(input3);
2557
+ const origin = getLengthableOrigin(input4);
2561
2558
  payload.issues.push({
2562
2559
  origin,
2563
2560
  code: "too_small",
2564
2561
  minimum: def.minimum,
2565
2562
  inclusive: true,
2566
- input: input3,
2563
+ input: input4,
2567
2564
  inst,
2568
2565
  continue: !def.abort
2569
2566
  });
@@ -2583,11 +2580,11 @@ var $ZodCheckLengthEquals = /* @__PURE__ */ $constructor("$ZodCheckLengthEquals"
2583
2580
  bag.length = def.length;
2584
2581
  });
2585
2582
  inst._zod.check = (payload) => {
2586
- const input3 = payload.value;
2587
- const length = input3.length;
2583
+ const input4 = payload.value;
2584
+ const length = input4.length;
2588
2585
  if (length === def.length)
2589
2586
  return;
2590
- const origin = getLengthableOrigin(input3);
2587
+ const origin = getLengthableOrigin(input4);
2591
2588
  const tooBig = length > def.length;
2592
2589
  payload.issues.push({
2593
2590
  origin,
@@ -3241,15 +3238,15 @@ var $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => {
3241
3238
  payload.value = Number(payload.value);
3242
3239
  } catch (_) {
3243
3240
  }
3244
- const input3 = payload.value;
3245
- if (typeof input3 === "number" && !Number.isNaN(input3) && Number.isFinite(input3)) {
3241
+ const input4 = payload.value;
3242
+ if (typeof input4 === "number" && !Number.isNaN(input4) && Number.isFinite(input4)) {
3246
3243
  return payload;
3247
3244
  }
3248
- const received = typeof input3 === "number" ? Number.isNaN(input3) ? "NaN" : !Number.isFinite(input3) ? "Infinity" : void 0 : void 0;
3245
+ const received = typeof input4 === "number" ? Number.isNaN(input4) ? "NaN" : !Number.isFinite(input4) ? "Infinity" : void 0 : void 0;
3249
3246
  payload.issues.push({
3250
3247
  expected: "number",
3251
3248
  code: "invalid_type",
3252
- input: input3,
3249
+ input: input4,
3253
3250
  inst,
3254
3251
  ...received ? { received } : {}
3255
3252
  });
@@ -3269,13 +3266,13 @@ var $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
3269
3266
  payload.value = Boolean(payload.value);
3270
3267
  } catch (_) {
3271
3268
  }
3272
- const input3 = payload.value;
3273
- if (typeof input3 === "boolean")
3269
+ const input4 = payload.value;
3270
+ if (typeof input4 === "boolean")
3274
3271
  return payload;
3275
3272
  payload.issues.push({
3276
3273
  expected: "boolean",
3277
3274
  code: "invalid_type",
3278
- input: input3,
3275
+ input: input4,
3279
3276
  inst
3280
3277
  });
3281
3278
  return payload;
@@ -3308,13 +3305,13 @@ var $ZodBigIntFormat = /* @__PURE__ */ $constructor("$ZodBigIntFormat", (inst, d
3308
3305
  var $ZodSymbol = /* @__PURE__ */ $constructor("$ZodSymbol", (inst, def) => {
3309
3306
  $ZodType.init(inst, def);
3310
3307
  inst._zod.parse = (payload, _ctx) => {
3311
- const input3 = payload.value;
3312
- if (typeof input3 === "symbol")
3308
+ const input4 = payload.value;
3309
+ if (typeof input4 === "symbol")
3313
3310
  return payload;
3314
3311
  payload.issues.push({
3315
3312
  expected: "symbol",
3316
3313
  code: "invalid_type",
3317
- input: input3,
3314
+ input: input4,
3318
3315
  inst
3319
3316
  });
3320
3317
  return payload;
@@ -3327,13 +3324,13 @@ var $ZodUndefined = /* @__PURE__ */ $constructor("$ZodUndefined", (inst, def) =>
3327
3324
  inst._zod.optin = "optional";
3328
3325
  inst._zod.optout = "optional";
3329
3326
  inst._zod.parse = (payload, _ctx) => {
3330
- const input3 = payload.value;
3331
- if (typeof input3 === "undefined")
3327
+ const input4 = payload.value;
3328
+ if (typeof input4 === "undefined")
3332
3329
  return payload;
3333
3330
  payload.issues.push({
3334
3331
  expected: "undefined",
3335
3332
  code: "invalid_type",
3336
- input: input3,
3333
+ input: input4,
3337
3334
  inst
3338
3335
  });
3339
3336
  return payload;
@@ -3344,13 +3341,13 @@ var $ZodNull = /* @__PURE__ */ $constructor("$ZodNull", (inst, def) => {
3344
3341
  inst._zod.pattern = _null;
3345
3342
  inst._zod.values = /* @__PURE__ */ new Set([null]);
3346
3343
  inst._zod.parse = (payload, _ctx) => {
3347
- const input3 = payload.value;
3348
- if (input3 === null)
3344
+ const input4 = payload.value;
3345
+ if (input4 === null)
3349
3346
  return payload;
3350
3347
  payload.issues.push({
3351
3348
  expected: "null",
3352
3349
  code: "invalid_type",
3353
- input: input3,
3350
+ input: input4,
3354
3351
  inst
3355
3352
  });
3356
3353
  return payload;
@@ -3379,13 +3376,13 @@ var $ZodNever = /* @__PURE__ */ $constructor("$ZodNever", (inst, def) => {
3379
3376
  var $ZodVoid = /* @__PURE__ */ $constructor("$ZodVoid", (inst, def) => {
3380
3377
  $ZodType.init(inst, def);
3381
3378
  inst._zod.parse = (payload, _ctx) => {
3382
- const input3 = payload.value;
3383
- if (typeof input3 === "undefined")
3379
+ const input4 = payload.value;
3380
+ if (typeof input4 === "undefined")
3384
3381
  return payload;
3385
3382
  payload.issues.push({
3386
3383
  expected: "void",
3387
3384
  code: "invalid_type",
3388
- input: input3,
3385
+ input: input4,
3389
3386
  inst
3390
3387
  });
3391
3388
  return payload;
@@ -3400,15 +3397,15 @@ var $ZodDate = /* @__PURE__ */ $constructor("$ZodDate", (inst, def) => {
3400
3397
  } catch (_err) {
3401
3398
  }
3402
3399
  }
3403
- const input3 = payload.value;
3404
- const isDate = input3 instanceof Date;
3405
- const isValidDate = isDate && !Number.isNaN(input3.getTime());
3400
+ const input4 = payload.value;
3401
+ const isDate = input4 instanceof Date;
3402
+ const isValidDate = isDate && !Number.isNaN(input4.getTime());
3406
3403
  if (isValidDate)
3407
3404
  return payload;
3408
3405
  payload.issues.push({
3409
3406
  expected: "date",
3410
3407
  code: "invalid_type",
3411
- input: input3,
3408
+ input: input4,
3412
3409
  ...isDate ? { received: "Invalid Date" } : {},
3413
3410
  inst
3414
3411
  });
@@ -3424,20 +3421,20 @@ function handleArrayResult(result, final, index) {
3424
3421
  var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
3425
3422
  $ZodType.init(inst, def);
3426
3423
  inst._zod.parse = (payload, ctx) => {
3427
- const input3 = payload.value;
3428
- if (!Array.isArray(input3)) {
3424
+ const input4 = payload.value;
3425
+ if (!Array.isArray(input4)) {
3429
3426
  payload.issues.push({
3430
3427
  expected: "array",
3431
3428
  code: "invalid_type",
3432
- input: input3,
3429
+ input: input4,
3433
3430
  inst
3434
3431
  });
3435
3432
  return payload;
3436
3433
  }
3437
- payload.value = Array(input3.length);
3434
+ payload.value = Array(input4.length);
3438
3435
  const proms = [];
3439
- for (let i = 0; i < input3.length; i++) {
3440
- const item = input3[i];
3436
+ for (let i = 0; i < input4.length; i++) {
3437
+ const item = input4[i];
3441
3438
  const result = def.element._zod.run({
3442
3439
  value: item,
3443
3440
  issues: []
@@ -3454,15 +3451,15 @@ var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
3454
3451
  return payload;
3455
3452
  };
3456
3453
  });
3457
- function handlePropertyResult(result, final, key, input3, isOptionalOut) {
3454
+ function handlePropertyResult(result, final, key, input4, isOptionalOut) {
3458
3455
  if (result.issues.length) {
3459
- if (isOptionalOut && !(key in input3)) {
3456
+ if (isOptionalOut && !(key in input4)) {
3460
3457
  return;
3461
3458
  }
3462
3459
  final.issues.push(...prefixIssues(key, result.issues));
3463
3460
  }
3464
3461
  if (result.value === void 0) {
3465
- if (key in input3) {
3462
+ if (key in input4) {
3466
3463
  final.value[key] = void 0;
3467
3464
  }
3468
3465
  } else {
@@ -3485,31 +3482,31 @@ function normalizeDef(def) {
3485
3482
  optionalKeys: new Set(okeys)
3486
3483
  };
3487
3484
  }
3488
- function handleCatchall(proms, input3, payload, ctx, def, inst) {
3485
+ function handleCatchall(proms, input4, payload, ctx, def, inst) {
3489
3486
  const unrecognized = [];
3490
3487
  const keySet = def.keySet;
3491
3488
  const _catchall = def.catchall._zod;
3492
3489
  const t = _catchall.def.type;
3493
3490
  const isOptionalOut = _catchall.optout === "optional";
3494
- for (const key in input3) {
3491
+ for (const key in input4) {
3495
3492
  if (keySet.has(key))
3496
3493
  continue;
3497
3494
  if (t === "never") {
3498
3495
  unrecognized.push(key);
3499
3496
  continue;
3500
3497
  }
3501
- const r = _catchall.run({ value: input3[key], issues: [] }, ctx);
3498
+ const r = _catchall.run({ value: input4[key], issues: [] }, ctx);
3502
3499
  if (r instanceof Promise) {
3503
- proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input3, isOptionalOut)));
3500
+ proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input4, isOptionalOut)));
3504
3501
  } else {
3505
- handlePropertyResult(r, payload, key, input3, isOptionalOut);
3502
+ handlePropertyResult(r, payload, key, input4, isOptionalOut);
3506
3503
  }
3507
3504
  }
3508
3505
  if (unrecognized.length) {
3509
3506
  payload.issues.push({
3510
3507
  code: "unrecognized_keys",
3511
3508
  keys: unrecognized,
3512
- input: input3,
3509
+ input: input4,
3513
3510
  inst
3514
3511
  });
3515
3512
  }
@@ -3553,12 +3550,12 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
3553
3550
  let value;
3554
3551
  inst._zod.parse = (payload, ctx) => {
3555
3552
  value ?? (value = _normalized.value);
3556
- const input3 = payload.value;
3557
- if (!isObject2(input3)) {
3553
+ const input4 = payload.value;
3554
+ if (!isObject2(input4)) {
3558
3555
  payload.issues.push({
3559
3556
  expected: "object",
3560
3557
  code: "invalid_type",
3561
- input: input3,
3558
+ input: input4,
3562
3559
  inst
3563
3560
  });
3564
3561
  return payload;
@@ -3569,17 +3566,17 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
3569
3566
  for (const key of value.keys) {
3570
3567
  const el = shape[key];
3571
3568
  const isOptionalOut = el._zod.optout === "optional";
3572
- const r = el._zod.run({ value: input3[key], issues: [] }, ctx);
3569
+ const r = el._zod.run({ value: input4[key], issues: [] }, ctx);
3573
3570
  if (r instanceof Promise) {
3574
- proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input3, isOptionalOut)));
3571
+ proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input4, isOptionalOut)));
3575
3572
  } else {
3576
- handlePropertyResult(r, payload, key, input3, isOptionalOut);
3573
+ handlePropertyResult(r, payload, key, input4, isOptionalOut);
3577
3574
  }
3578
3575
  }
3579
3576
  if (!catchall) {
3580
3577
  return proms.length ? Promise.all(proms).then(() => payload) : payload;
3581
3578
  }
3582
- return handleCatchall(proms, input3, payload, ctx, _normalized.value, inst);
3579
+ return handleCatchall(proms, input4, payload, ctx, _normalized.value, inst);
3583
3580
  };
3584
3581
  });
3585
3582
  var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => {
@@ -3660,12 +3657,12 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
3660
3657
  let value;
3661
3658
  inst._zod.parse = (payload, ctx) => {
3662
3659
  value ?? (value = _normalized.value);
3663
- const input3 = payload.value;
3664
- if (!isObject2(input3)) {
3660
+ const input4 = payload.value;
3661
+ if (!isObject2(input4)) {
3665
3662
  payload.issues.push({
3666
3663
  expected: "object",
3667
3664
  code: "invalid_type",
3668
- input: input3,
3665
+ input: input4,
3669
3666
  inst
3670
3667
  });
3671
3668
  return payload;
@@ -3676,7 +3673,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
3676
3673
  payload = fastpass(payload, ctx);
3677
3674
  if (!catchall)
3678
3675
  return payload;
3679
- return handleCatchall([], input3, payload, ctx, value, inst);
3676
+ return handleCatchall([], input4, payload, ctx, value, inst);
3680
3677
  }
3681
3678
  return superParse(payload, ctx);
3682
3679
  };
@@ -3838,17 +3835,17 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
3838
3835
  return map2;
3839
3836
  });
3840
3837
  inst._zod.parse = (payload, ctx) => {
3841
- const input3 = payload.value;
3842
- if (!isObject(input3)) {
3838
+ const input4 = payload.value;
3839
+ if (!isObject(input4)) {
3843
3840
  payload.issues.push({
3844
3841
  code: "invalid_type",
3845
3842
  expected: "object",
3846
- input: input3,
3843
+ input: input4,
3847
3844
  inst
3848
3845
  });
3849
3846
  return payload;
3850
3847
  }
3851
- const opt = disc.value.get(input3?.[def.discriminator]);
3848
+ const opt = disc.value.get(input4?.[def.discriminator]);
3852
3849
  if (opt) {
3853
3850
  return opt._zod.run(payload, ctx);
3854
3851
  }
@@ -3860,7 +3857,7 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
3860
3857
  errors: [],
3861
3858
  note: "No matching discriminator",
3862
3859
  discriminator: def.discriminator,
3863
- input: input3,
3860
+ input: input4,
3864
3861
  path: [def.discriminator],
3865
3862
  inst
3866
3863
  });
@@ -3870,9 +3867,9 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
3870
3867
  var $ZodIntersection = /* @__PURE__ */ $constructor("$ZodIntersection", (inst, def) => {
3871
3868
  $ZodType.init(inst, def);
3872
3869
  inst._zod.parse = (payload, ctx) => {
3873
- const input3 = payload.value;
3874
- const left = def.left._zod.run({ value: input3, issues: [] }, ctx);
3875
- const right = def.right._zod.run({ value: input3, issues: [] }, ctx);
3870
+ const input4 = payload.value;
3871
+ const left = def.left._zod.run({ value: input4, issues: [] }, ctx);
3872
+ const right = def.right._zod.run({ value: input4, issues: [] }, ctx);
3876
3873
  const async = left instanceof Promise || right instanceof Promise;
3877
3874
  if (async) {
3878
3875
  return Promise.all([left, right]).then(([left2, right2]) => {
@@ -3969,10 +3966,10 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
3969
3966
  $ZodType.init(inst, def);
3970
3967
  const items = def.items;
3971
3968
  inst._zod.parse = (payload, ctx) => {
3972
- const input3 = payload.value;
3973
- if (!Array.isArray(input3)) {
3969
+ const input4 = payload.value;
3970
+ if (!Array.isArray(input4)) {
3974
3971
  payload.issues.push({
3975
- input: input3,
3972
+ input: input4,
3976
3973
  inst,
3977
3974
  expected: "tuple",
3978
3975
  code: "invalid_type"
@@ -3984,12 +3981,12 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
3984
3981
  const reversedIndex = [...items].reverse().findIndex((item) => item._zod.optin !== "optional");
3985
3982
  const optStart = reversedIndex === -1 ? 0 : items.length - reversedIndex;
3986
3983
  if (!def.rest) {
3987
- const tooBig = input3.length > items.length;
3988
- const tooSmall = input3.length < optStart - 1;
3984
+ const tooBig = input4.length > items.length;
3985
+ const tooSmall = input4.length < optStart - 1;
3989
3986
  if (tooBig || tooSmall) {
3990
3987
  payload.issues.push({
3991
3988
  ...tooBig ? { code: "too_big", maximum: items.length, inclusive: true } : { code: "too_small", minimum: items.length },
3992
- input: input3,
3989
+ input: input4,
3993
3990
  inst,
3994
3991
  origin: "array"
3995
3992
  });
@@ -3999,12 +3996,12 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
3999
3996
  let i = -1;
4000
3997
  for (const item of items) {
4001
3998
  i++;
4002
- if (i >= input3.length) {
3999
+ if (i >= input4.length) {
4003
4000
  if (i >= optStart)
4004
4001
  continue;
4005
4002
  }
4006
4003
  const result = item._zod.run({
4007
- value: input3[i],
4004
+ value: input4[i],
4008
4005
  issues: []
4009
4006
  }, ctx);
4010
4007
  if (result instanceof Promise) {
@@ -4014,7 +4011,7 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
4014
4011
  }
4015
4012
  }
4016
4013
  if (def.rest) {
4017
- const rest = input3.slice(items.length);
4014
+ const rest = input4.slice(items.length);
4018
4015
  for (const el of rest) {
4019
4016
  i++;
4020
4017
  const result = def.rest._zod.run({
@@ -4042,12 +4039,12 @@ function handleTupleResult(result, final, index) {
4042
4039
  var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
4043
4040
  $ZodType.init(inst, def);
4044
4041
  inst._zod.parse = (payload, ctx) => {
4045
- const input3 = payload.value;
4046
- if (!isPlainObject(input3)) {
4042
+ const input4 = payload.value;
4043
+ if (!isPlainObject(input4)) {
4047
4044
  payload.issues.push({
4048
4045
  expected: "record",
4049
4046
  code: "invalid_type",
4050
- input: input3,
4047
+ input: input4,
4051
4048
  inst
4052
4049
  });
4053
4050
  return payload;
@@ -4060,7 +4057,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
4060
4057
  for (const key of values) {
4061
4058
  if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
4062
4059
  recordKeys.add(typeof key === "number" ? key.toString() : key);
4063
- const result = def.valueType._zod.run({ value: input3[key], issues: [] }, ctx);
4060
+ const result = def.valueType._zod.run({ value: input4[key], issues: [] }, ctx);
4064
4061
  if (result instanceof Promise) {
4065
4062
  proms.push(result.then((result2) => {
4066
4063
  if (result2.issues.length) {
@@ -4077,7 +4074,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
4077
4074
  }
4078
4075
  }
4079
4076
  let unrecognized;
4080
- for (const key in input3) {
4077
+ for (const key in input4) {
4081
4078
  if (!recordKeys.has(key)) {
4082
4079
  unrecognized = unrecognized ?? [];
4083
4080
  unrecognized.push(key);
@@ -4086,14 +4083,14 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
4086
4083
  if (unrecognized && unrecognized.length > 0) {
4087
4084
  payload.issues.push({
4088
4085
  code: "unrecognized_keys",
4089
- input: input3,
4086
+ input: input4,
4090
4087
  inst,
4091
4088
  keys: unrecognized
4092
4089
  });
4093
4090
  }
4094
4091
  } else {
4095
4092
  payload.value = {};
4096
- for (const key of Reflect.ownKeys(input3)) {
4093
+ for (const key of Reflect.ownKeys(input4)) {
4097
4094
  if (key === "__proto__")
4098
4095
  continue;
4099
4096
  let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
@@ -4112,7 +4109,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
4112
4109
  }
4113
4110
  if (keyResult.issues.length) {
4114
4111
  if (def.mode === "loose") {
4115
- payload.value[key] = input3[key];
4112
+ payload.value[key] = input4[key];
4116
4113
  } else {
4117
4114
  payload.issues.push({
4118
4115
  code: "invalid_key",
@@ -4125,7 +4122,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
4125
4122
  }
4126
4123
  continue;
4127
4124
  }
4128
- const result = def.valueType._zod.run({ value: input3[key], issues: [] }, ctx);
4125
+ const result = def.valueType._zod.run({ value: input4[key], issues: [] }, ctx);
4129
4126
  if (result instanceof Promise) {
4130
4127
  proms.push(result.then((result2) => {
4131
4128
  if (result2.issues.length) {
@@ -4150,27 +4147,27 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
4150
4147
  var $ZodMap = /* @__PURE__ */ $constructor("$ZodMap", (inst, def) => {
4151
4148
  $ZodType.init(inst, def);
4152
4149
  inst._zod.parse = (payload, ctx) => {
4153
- const input3 = payload.value;
4154
- if (!(input3 instanceof Map)) {
4150
+ const input4 = payload.value;
4151
+ if (!(input4 instanceof Map)) {
4155
4152
  payload.issues.push({
4156
4153
  expected: "map",
4157
4154
  code: "invalid_type",
4158
- input: input3,
4155
+ input: input4,
4159
4156
  inst
4160
4157
  });
4161
4158
  return payload;
4162
4159
  }
4163
4160
  const proms = [];
4164
4161
  payload.value = /* @__PURE__ */ new Map();
4165
- for (const [key, value] of input3) {
4162
+ for (const [key, value] of input4) {
4166
4163
  const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
4167
4164
  const valueResult = def.valueType._zod.run({ value, issues: [] }, ctx);
4168
4165
  if (keyResult instanceof Promise || valueResult instanceof Promise) {
4169
4166
  proms.push(Promise.all([keyResult, valueResult]).then(([keyResult2, valueResult2]) => {
4170
- handleMapResult(keyResult2, valueResult2, payload, key, input3, inst, ctx);
4167
+ handleMapResult(keyResult2, valueResult2, payload, key, input4, inst, ctx);
4171
4168
  }));
4172
4169
  } else {
4173
- handleMapResult(keyResult, valueResult, payload, key, input3, inst, ctx);
4170
+ handleMapResult(keyResult, valueResult, payload, key, input4, inst, ctx);
4174
4171
  }
4175
4172
  }
4176
4173
  if (proms.length)
@@ -4178,7 +4175,7 @@ var $ZodMap = /* @__PURE__ */ $constructor("$ZodMap", (inst, def) => {
4178
4175
  return payload;
4179
4176
  };
4180
4177
  });
4181
- function handleMapResult(keyResult, valueResult, final, key, input3, inst, ctx) {
4178
+ function handleMapResult(keyResult, valueResult, final, key, input4, inst, ctx) {
4182
4179
  if (keyResult.issues.length) {
4183
4180
  if (propertyKeyTypes.has(typeof key)) {
4184
4181
  final.issues.push(...prefixIssues(key, keyResult.issues));
@@ -4186,7 +4183,7 @@ function handleMapResult(keyResult, valueResult, final, key, input3, inst, ctx)
4186
4183
  final.issues.push({
4187
4184
  code: "invalid_key",
4188
4185
  origin: "map",
4189
- input: input3,
4186
+ input: input4,
4190
4187
  inst,
4191
4188
  issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config()))
4192
4189
  });
@@ -4199,7 +4196,7 @@ function handleMapResult(keyResult, valueResult, final, key, input3, inst, ctx)
4199
4196
  final.issues.push({
4200
4197
  origin: "map",
4201
4198
  code: "invalid_element",
4202
- input: input3,
4199
+ input: input4,
4203
4200
  inst,
4204
4201
  key,
4205
4202
  issues: valueResult.issues.map((iss) => finalizeIssue(iss, ctx, config()))
@@ -4211,10 +4208,10 @@ function handleMapResult(keyResult, valueResult, final, key, input3, inst, ctx)
4211
4208
  var $ZodSet = /* @__PURE__ */ $constructor("$ZodSet", (inst, def) => {
4212
4209
  $ZodType.init(inst, def);
4213
4210
  inst._zod.parse = (payload, ctx) => {
4214
- const input3 = payload.value;
4215
- if (!(input3 instanceof Set)) {
4211
+ const input4 = payload.value;
4212
+ if (!(input4 instanceof Set)) {
4216
4213
  payload.issues.push({
4217
- input: input3,
4214
+ input: input4,
4218
4215
  inst,
4219
4216
  expected: "set",
4220
4217
  code: "invalid_type"
@@ -4223,7 +4220,7 @@ var $ZodSet = /* @__PURE__ */ $constructor("$ZodSet", (inst, def) => {
4223
4220
  }
4224
4221
  const proms = [];
4225
4222
  payload.value = /* @__PURE__ */ new Set();
4226
- for (const item of input3) {
4223
+ for (const item of input4) {
4227
4224
  const result = def.valueType._zod.run({ value: item, issues: [] }, ctx);
4228
4225
  if (result instanceof Promise) {
4229
4226
  proms.push(result.then((result2) => handleSetResult(result2, payload)));
@@ -4248,14 +4245,14 @@ var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
4248
4245
  inst._zod.values = valuesSet;
4249
4246
  inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`);
4250
4247
  inst._zod.parse = (payload, _ctx) => {
4251
- const input3 = payload.value;
4252
- if (valuesSet.has(input3)) {
4248
+ const input4 = payload.value;
4249
+ if (valuesSet.has(input4)) {
4253
4250
  return payload;
4254
4251
  }
4255
4252
  payload.issues.push({
4256
4253
  code: "invalid_value",
4257
4254
  values,
4258
- input: input3,
4255
+ input: input4,
4259
4256
  inst
4260
4257
  });
4261
4258
  return payload;
@@ -4270,14 +4267,14 @@ var $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => {
4270
4267
  inst._zod.values = values;
4271
4268
  inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
4272
4269
  inst._zod.parse = (payload, _ctx) => {
4273
- const input3 = payload.value;
4274
- if (values.has(input3)) {
4270
+ const input4 = payload.value;
4271
+ if (values.has(input4)) {
4275
4272
  return payload;
4276
4273
  }
4277
4274
  payload.issues.push({
4278
4275
  code: "invalid_value",
4279
4276
  values: def.values,
4280
- input: input3,
4277
+ input: input4,
4281
4278
  inst
4282
4279
  });
4283
4280
  return payload;
@@ -4286,13 +4283,13 @@ var $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => {
4286
4283
  var $ZodFile = /* @__PURE__ */ $constructor("$ZodFile", (inst, def) => {
4287
4284
  $ZodType.init(inst, def);
4288
4285
  inst._zod.parse = (payload, _ctx) => {
4289
- const input3 = payload.value;
4290
- if (input3 instanceof File)
4286
+ const input4 = payload.value;
4287
+ if (input4 instanceof File)
4291
4288
  return payload;
4292
4289
  payload.issues.push({
4293
4290
  expected: "file",
4294
4291
  code: "invalid_type",
4295
- input: input3,
4292
+ input: input4,
4296
4293
  inst
4297
4294
  });
4298
4295
  return payload;
@@ -4319,8 +4316,8 @@ var $ZodTransform = /* @__PURE__ */ $constructor("$ZodTransform", (inst, def) =>
4319
4316
  return payload;
4320
4317
  };
4321
4318
  });
4322
- function handleOptionalResult(result, input3) {
4323
- if (result.issues.length && input3 === void 0) {
4319
+ function handleOptionalResult(result, input4) {
4320
+ if (result.issues.length && input4 === void 0) {
4324
4321
  return { issues: [], value: void 0 };
4325
4322
  }
4326
4323
  return result;
@@ -4756,20 +4753,20 @@ var $ZodCustom = /* @__PURE__ */ $constructor("$ZodCustom", (inst, def) => {
4756
4753
  return payload;
4757
4754
  };
4758
4755
  inst._zod.check = (payload) => {
4759
- const input3 = payload.value;
4760
- const r = def.fn(input3);
4756
+ const input4 = payload.value;
4757
+ const r = def.fn(input4);
4761
4758
  if (r instanceof Promise) {
4762
- return r.then((r2) => handleRefineResult(r2, payload, input3, inst));
4759
+ return r.then((r2) => handleRefineResult(r2, payload, input4, inst));
4763
4760
  }
4764
- handleRefineResult(r, payload, input3, inst);
4761
+ handleRefineResult(r, payload, input4, inst);
4765
4762
  return;
4766
4763
  };
4767
4764
  });
4768
- function handleRefineResult(result, payload, input3, inst) {
4765
+ function handleRefineResult(result, payload, input4, inst) {
4769
4766
  if (!result) {
4770
4767
  const _iss = {
4771
4768
  code: "custom",
4772
- input: input3,
4769
+ input: input4,
4773
4770
  inst,
4774
4771
  // incorporates params.error into issue reporting
4775
4772
  path: [...inst._zod.def.path ?? []],
@@ -11079,23 +11076,23 @@ function _overwrite(tx) {
11079
11076
  }
11080
11077
  // @__NO_SIDE_EFFECTS__
11081
11078
  function _normalize(form) {
11082
- return /* @__PURE__ */ _overwrite((input3) => input3.normalize(form));
11079
+ return /* @__PURE__ */ _overwrite((input4) => input4.normalize(form));
11083
11080
  }
11084
11081
  // @__NO_SIDE_EFFECTS__
11085
11082
  function _trim() {
11086
- return /* @__PURE__ */ _overwrite((input3) => input3.trim());
11083
+ return /* @__PURE__ */ _overwrite((input4) => input4.trim());
11087
11084
  }
11088
11085
  // @__NO_SIDE_EFFECTS__
11089
11086
  function _toLowerCase() {
11090
- return /* @__PURE__ */ _overwrite((input3) => input3.toLowerCase());
11087
+ return /* @__PURE__ */ _overwrite((input4) => input4.toLowerCase());
11091
11088
  }
11092
11089
  // @__NO_SIDE_EFFECTS__
11093
11090
  function _toUpperCase() {
11094
- return /* @__PURE__ */ _overwrite((input3) => input3.toUpperCase());
11091
+ return /* @__PURE__ */ _overwrite((input4) => input4.toUpperCase());
11095
11092
  }
11096
11093
  // @__NO_SIDE_EFFECTS__
11097
11094
  function _slugify() {
11098
- return /* @__PURE__ */ _overwrite((input3) => slugify2(input3));
11095
+ return /* @__PURE__ */ _overwrite((input4) => slugify2(input4));
11099
11096
  }
11100
11097
  // @__NO_SIDE_EFFECTS__
11101
11098
  function _array(Class2, element, params) {
@@ -11400,8 +11397,8 @@ function _stringbool(Classes, _params) {
11400
11397
  type: "pipe",
11401
11398
  in: stringSchema,
11402
11399
  out: booleanSchema,
11403
- transform: ((input3, payload) => {
11404
- let data = input3;
11400
+ transform: ((input4, payload) => {
11401
+ let data = input4;
11405
11402
  if (params.case !== "sensitive")
11406
11403
  data = data.toLowerCase();
11407
11404
  if (truthySet.has(data)) {
@@ -11420,8 +11417,8 @@ function _stringbool(Classes, _params) {
11420
11417
  return {};
11421
11418
  }
11422
11419
  }),
11423
- reverseTransform: ((input3, _payload) => {
11424
- if (input3 === true) {
11420
+ reverseTransform: ((input4, _payload) => {
11421
+ if (input4 === true) {
11425
11422
  return truthyArray[0] || "true";
11426
11423
  } else {
11427
11424
  return falsyArray[0] || "false";
@@ -12317,9 +12314,9 @@ var allProcessors = {
12317
12314
  optional: optionalProcessor,
12318
12315
  lazy: lazyProcessor
12319
12316
  };
12320
- function toJSONSchema(input3, params) {
12321
- if ("_idmap" in input3) {
12322
- const registry2 = input3;
12317
+ function toJSONSchema(input4, params) {
12318
+ if ("_idmap" in input4) {
12319
+ const registry2 = input4;
12323
12320
  const ctx2 = initializeContext({ ...params, processors: allProcessors });
12324
12321
  const defs = {};
12325
12322
  for (const entry of registry2._idmap.entries()) {
@@ -12347,9 +12344,9 @@ function toJSONSchema(input3, params) {
12347
12344
  return { schemas };
12348
12345
  }
12349
12346
  const ctx = initializeContext({ ...params, processors: allProcessors });
12350
- process2(input3, ctx);
12351
- extractDefs(ctx, input3);
12352
- return finalize(ctx, input3);
12347
+ process2(input4, ctx);
12348
+ extractDefs(ctx, input4);
12349
+ return finalize(ctx, input4);
12353
12350
  }
12354
12351
 
12355
12352
  // node_modules/zod/v4/core/json-schema-generator.js
@@ -15302,6 +15299,128 @@ function createMeetingTools(store) {
15302
15299
 
15303
15300
  // src/plugins/builtin/tools/reports.ts
15304
15301
  import { tool as tool8 } from "@anthropic-ai/claude-agent-sdk";
15302
+
15303
+ // src/reports/gar/collector.ts
15304
+ function collectGarMetrics(store) {
15305
+ const allActions = store.list({ type: "action" });
15306
+ const openActions = allActions.filter((d) => d.frontmatter.status === "open");
15307
+ const doneActions = allActions.filter((d) => d.frontmatter.status === "done");
15308
+ const allDocs = store.list();
15309
+ const blockedItems = allDocs.filter(
15310
+ (d) => d.frontmatter.tags?.includes("blocked")
15311
+ );
15312
+ const overdueItems = allDocs.filter(
15313
+ (d) => d.frontmatter.tags?.includes("overdue")
15314
+ );
15315
+ const openQuestions = store.list({ type: "question", status: "open" });
15316
+ const riskItems = allDocs.filter(
15317
+ (d) => d.frontmatter.tags?.includes("risk")
15318
+ );
15319
+ const unownedActions = openActions.filter((d) => !d.frontmatter.owner);
15320
+ const total = allActions.length;
15321
+ const done = doneActions.length;
15322
+ const completionPct = total > 0 ? Math.round(done / total * 100) : 100;
15323
+ const scheduleItems = [
15324
+ ...blockedItems,
15325
+ ...overdueItems
15326
+ ].filter(
15327
+ (d, i, arr) => arr.findIndex((x) => x.frontmatter.id === d.frontmatter.id) === i
15328
+ ).map((d) => ({ id: d.frontmatter.id, title: d.frontmatter.title }));
15329
+ const qualityItems = [
15330
+ ...riskItems,
15331
+ ...openQuestions
15332
+ ].filter(
15333
+ (d, i, arr) => arr.findIndex((x) => x.frontmatter.id === d.frontmatter.id) === i
15334
+ ).map((d) => ({ id: d.frontmatter.id, title: d.frontmatter.title }));
15335
+ const resourceItems = unownedActions.map((d) => ({
15336
+ id: d.frontmatter.id,
15337
+ title: d.frontmatter.title
15338
+ }));
15339
+ return {
15340
+ scope: {
15341
+ total,
15342
+ open: openActions.length,
15343
+ done,
15344
+ completionPct
15345
+ },
15346
+ schedule: {
15347
+ blocked: blockedItems.length,
15348
+ overdue: overdueItems.length,
15349
+ items: scheduleItems
15350
+ },
15351
+ quality: {
15352
+ risks: riskItems.length,
15353
+ openQuestions: openQuestions.length,
15354
+ items: qualityItems
15355
+ },
15356
+ resources: {
15357
+ unowned: unownedActions.length,
15358
+ items: resourceItems
15359
+ }
15360
+ };
15361
+ }
15362
+
15363
+ // src/reports/gar/evaluator.ts
15364
+ function worstStatus(statuses) {
15365
+ if (statuses.includes("red")) return "red";
15366
+ if (statuses.includes("amber")) return "amber";
15367
+ return "green";
15368
+ }
15369
+ function evaluateGar(projectName, metrics) {
15370
+ const areas = [];
15371
+ const scopePct = metrics.scope.completionPct;
15372
+ const scopeStatus = scopePct >= 70 ? "green" : scopePct >= 40 ? "amber" : "red";
15373
+ areas.push({
15374
+ name: "Scope",
15375
+ status: scopeStatus,
15376
+ summary: `${scopePct}% complete (${metrics.scope.done}/${metrics.scope.total})`,
15377
+ items: []
15378
+ });
15379
+ const scheduleCount = metrics.schedule.blocked + metrics.schedule.overdue;
15380
+ const scheduleStatus = scheduleCount === 0 ? "green" : scheduleCount <= 2 ? "amber" : "red";
15381
+ const scheduleParts = [];
15382
+ if (metrics.schedule.blocked > 0)
15383
+ scheduleParts.push(`${metrics.schedule.blocked} blocked`);
15384
+ if (metrics.schedule.overdue > 0)
15385
+ scheduleParts.push(`${metrics.schedule.overdue} overdue`);
15386
+ areas.push({
15387
+ name: "Schedule",
15388
+ status: scheduleStatus,
15389
+ summary: scheduleParts.length > 0 ? scheduleParts.join(", ") : "on track",
15390
+ items: metrics.schedule.items
15391
+ });
15392
+ const qualityCount = metrics.quality.risks + metrics.quality.openQuestions;
15393
+ const qualityStatus = qualityCount === 0 ? "green" : qualityCount <= 2 ? "amber" : "red";
15394
+ const qualityParts = [];
15395
+ if (metrics.quality.risks > 0)
15396
+ qualityParts.push(`${metrics.quality.risks} risk(s)`);
15397
+ if (metrics.quality.openQuestions > 0)
15398
+ qualityParts.push(`${metrics.quality.openQuestions} open question(s)`);
15399
+ areas.push({
15400
+ name: "Quality",
15401
+ status: qualityStatus,
15402
+ summary: qualityParts.length > 0 ? qualityParts.join(", ") : "no issues",
15403
+ items: metrics.quality.items
15404
+ });
15405
+ const resourceCount = metrics.resources.unowned;
15406
+ const resourceStatus = resourceCount === 0 ? "green" : resourceCount <= 2 ? "amber" : "red";
15407
+ areas.push({
15408
+ name: "Resources",
15409
+ status: resourceStatus,
15410
+ summary: resourceCount > 0 ? `${resourceCount} unowned action(s)` : "all assigned",
15411
+ items: metrics.resources.items
15412
+ });
15413
+ const overall = worstStatus(areas.map((a) => a.status));
15414
+ return {
15415
+ projectName,
15416
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
15417
+ overall,
15418
+ areas,
15419
+ metrics
15420
+ };
15421
+ }
15422
+
15423
+ // src/plugins/builtin/tools/reports.ts
15305
15424
  function createReportTools(store) {
15306
15425
  return [
15307
15426
  tool8(
@@ -15390,41 +15509,10 @@ function createReportTools(store) {
15390
15509
  "Generate a Green-Amber-Red report with metrics across scope, schedule, quality, and resources",
15391
15510
  {},
15392
15511
  async () => {
15393
- const allActions = store.list({ type: "action" });
15394
- const openActions = allActions.filter((d) => d.frontmatter.status === "open");
15395
- const doneActions = allActions.filter((d) => d.frontmatter.status === "done");
15396
- const allDocs = store.list();
15397
- const blockedItems = allDocs.filter(
15398
- (d) => d.frontmatter.tags?.includes("blocked")
15399
- );
15400
- const overdueItems = allDocs.filter(
15401
- (d) => d.frontmatter.tags?.includes("overdue")
15402
- );
15403
- const openQuestions = store.list({ type: "question", status: "open" });
15404
- const riskItems = allDocs.filter(
15405
- (d) => d.frontmatter.tags?.includes("risk")
15406
- );
15407
- const unownedActions = openActions.filter((d) => !d.frontmatter.owner);
15408
- const areas = {
15409
- scope: {
15410
- total: allActions.length,
15411
- open: openActions.length,
15412
- done: doneActions.length
15413
- },
15414
- schedule: {
15415
- blocked: blockedItems.length,
15416
- overdue: overdueItems.length
15417
- },
15418
- quality: {
15419
- openQuestions: openQuestions.length,
15420
- risks: riskItems.length
15421
- },
15422
- resources: {
15423
- unowned: unownedActions.length
15424
- }
15425
- };
15512
+ const metrics = collectGarMetrics(store);
15513
+ const report = evaluateGar("project", metrics);
15426
15514
  return {
15427
- content: [{ type: "text", text: JSON.stringify({ areas }, null, 2) }]
15515
+ content: [{ type: "text", text: JSON.stringify(report, null, 2) }]
15428
15516
  };
15429
15517
  },
15430
15518
  { annotations: { readOnly: true } }
@@ -17502,9 +17590,492 @@ Be thorough but concise. Focus on actionable insights.`,
17502
17590
  ]
17503
17591
  };
17504
17592
 
17593
+ // src/skills/builtin/jira/tools.ts
17594
+ import { tool as tool19 } from "@anthropic-ai/claude-agent-sdk";
17595
+
17596
+ // src/skills/builtin/jira/client.ts
17597
+ var JiraClient = class {
17598
+ baseUrl;
17599
+ authHeader;
17600
+ constructor(config2) {
17601
+ this.baseUrl = `https://${config2.host}/rest/api/2`;
17602
+ this.authHeader = "Basic " + Buffer.from(`${config2.email}:${config2.apiToken}`).toString("base64");
17603
+ }
17604
+ async request(path18, method = "GET", body) {
17605
+ const url2 = `${this.baseUrl}${path18}`;
17606
+ const headers = {
17607
+ Authorization: this.authHeader,
17608
+ "Content-Type": "application/json",
17609
+ Accept: "application/json"
17610
+ };
17611
+ const response = await fetch(url2, {
17612
+ method,
17613
+ headers,
17614
+ body: body ? JSON.stringify(body) : void 0
17615
+ });
17616
+ if (!response.ok) {
17617
+ const text = await response.text().catch(() => "");
17618
+ throw new Error(
17619
+ `Jira API error ${response.status} ${method} ${path18}: ${text}`
17620
+ );
17621
+ }
17622
+ if (response.status === 204) return void 0;
17623
+ return response.json();
17624
+ }
17625
+ async searchIssues(jql, maxResults = 50) {
17626
+ const params = new URLSearchParams({
17627
+ jql,
17628
+ maxResults: String(maxResults)
17629
+ });
17630
+ return this.request(`/search?${params}`);
17631
+ }
17632
+ async getIssue(key) {
17633
+ return this.request(`/issue/${encodeURIComponent(key)}`);
17634
+ }
17635
+ async createIssue(fields) {
17636
+ return this.request("/issue", "POST", { fields });
17637
+ }
17638
+ async updateIssue(key, fields) {
17639
+ await this.request(
17640
+ `/issue/${encodeURIComponent(key)}`,
17641
+ "PUT",
17642
+ { fields }
17643
+ );
17644
+ }
17645
+ async addComment(key, body) {
17646
+ await this.request(
17647
+ `/issue/${encodeURIComponent(key)}/comment`,
17648
+ "POST",
17649
+ { body }
17650
+ );
17651
+ }
17652
+ };
17653
+ function createJiraClient(jiraUserConfig) {
17654
+ const host = jiraUserConfig?.host ?? process.env.JIRA_HOST;
17655
+ const email3 = jiraUserConfig?.email ?? process.env.JIRA_EMAIL;
17656
+ const apiToken = jiraUserConfig?.apiToken ?? process.env.JIRA_API_TOKEN;
17657
+ if (!host || !email3 || !apiToken) return null;
17658
+ return { client: new JiraClient({ host, email: email3, apiToken }), host };
17659
+ }
17660
+
17661
+ // src/skills/builtin/jira/tools.ts
17662
+ var JIRA_TYPE = "jira-issue";
17663
+ function jiraNotConfiguredError() {
17664
+ return {
17665
+ content: [
17666
+ {
17667
+ type: "text",
17668
+ text: 'Jira is not configured. Run "marvin config jira" or set JIRA_HOST, JIRA_EMAIL, and JIRA_API_TOKEN environment variables.'
17669
+ }
17670
+ ],
17671
+ isError: true
17672
+ };
17673
+ }
17674
+ function mapJiraStatus(jiraStatus) {
17675
+ const lower = jiraStatus.toLowerCase();
17676
+ if (lower === "done" || lower === "closed" || lower === "resolved") return "done";
17677
+ if (lower === "in progress" || lower === "in review") return "in-progress";
17678
+ return "open";
17679
+ }
17680
+ function jiraIssueToFrontmatter(issue2, host, linkedArtifacts) {
17681
+ return {
17682
+ title: issue2.fields.summary,
17683
+ status: mapJiraStatus(issue2.fields.status.name),
17684
+ jiraKey: issue2.key,
17685
+ jiraUrl: `https://${host}/browse/${issue2.key}`,
17686
+ issueType: issue2.fields.issuetype.name,
17687
+ priority: issue2.fields.priority?.name ?? "None",
17688
+ assignee: issue2.fields.assignee?.displayName ?? "",
17689
+ labels: issue2.fields.labels ?? [],
17690
+ linkedArtifacts: linkedArtifacts ?? [],
17691
+ tags: [`jira:${issue2.key}`],
17692
+ lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString()
17693
+ };
17694
+ }
17695
+ function findByJiraKey(store, jiraKey) {
17696
+ const docs = store.list({ type: JIRA_TYPE });
17697
+ return docs.find((d) => d.frontmatter.jiraKey === jiraKey);
17698
+ }
17699
+ function createJiraTools(store) {
17700
+ const jiraUserConfig = loadUserConfig().jira;
17701
+ return [
17702
+ // --- Local read tools ---
17703
+ tool19(
17704
+ "list_jira_issues",
17705
+ "List locally synced Jira issues (JI-xxx documents), optionally filtered by status or Jira key",
17706
+ {
17707
+ status: external_exports.enum(["open", "in-progress", "done"]).optional().describe("Filter by local status"),
17708
+ jiraKey: external_exports.string().optional().describe("Filter by Jira issue key (e.g. 'PROJ-123')")
17709
+ },
17710
+ async (args) => {
17711
+ let docs = store.list({ type: JIRA_TYPE, status: args.status });
17712
+ if (args.jiraKey) {
17713
+ docs = docs.filter((d) => d.frontmatter.jiraKey === args.jiraKey);
17714
+ }
17715
+ const summary = docs.map((d) => ({
17716
+ id: d.frontmatter.id,
17717
+ title: d.frontmatter.title,
17718
+ status: d.frontmatter.status,
17719
+ jiraKey: d.frontmatter.jiraKey,
17720
+ issueType: d.frontmatter.issueType,
17721
+ priority: d.frontmatter.priority,
17722
+ assignee: d.frontmatter.assignee,
17723
+ linkedArtifacts: d.frontmatter.linkedArtifacts
17724
+ }));
17725
+ return {
17726
+ content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
17727
+ };
17728
+ },
17729
+ { annotations: { readOnly: true } }
17730
+ ),
17731
+ tool19(
17732
+ "get_jira_issue",
17733
+ "Get the full content of a locally synced Jira issue by local ID (JI-xxx) or Jira key (PROJ-123)",
17734
+ {
17735
+ id: external_exports.string().describe("Local ID (e.g. 'JI-001') or Jira key (e.g. 'PROJ-123')")
17736
+ },
17737
+ async (args) => {
17738
+ let doc = store.get(args.id);
17739
+ if (!doc) {
17740
+ doc = findByJiraKey(store, args.id);
17741
+ }
17742
+ if (!doc) {
17743
+ return {
17744
+ content: [{ type: "text", text: `Jira issue ${args.id} not found locally` }],
17745
+ isError: true
17746
+ };
17747
+ }
17748
+ return {
17749
+ content: [
17750
+ {
17751
+ type: "text",
17752
+ text: JSON.stringify(
17753
+ { ...doc.frontmatter, content: doc.content },
17754
+ null,
17755
+ 2
17756
+ )
17757
+ }
17758
+ ]
17759
+ };
17760
+ },
17761
+ { annotations: { readOnly: true } }
17762
+ ),
17763
+ // --- Jira → Local tools ---
17764
+ tool19(
17765
+ "pull_jira_issue",
17766
+ "Fetch a single Jira issue by key and create/update a local JI-xxx document",
17767
+ {
17768
+ key: external_exports.string().describe("Jira issue key (e.g. 'PROJ-123')")
17769
+ },
17770
+ async (args) => {
17771
+ const jira = createJiraClient(jiraUserConfig);
17772
+ if (!jira) return jiraNotConfiguredError();
17773
+ const issue2 = await jira.client.getIssue(args.key);
17774
+ const existing = findByJiraKey(store, args.key);
17775
+ if (existing) {
17776
+ const fm2 = jiraIssueToFrontmatter(
17777
+ issue2,
17778
+ jira.host,
17779
+ existing.frontmatter.linkedArtifacts
17780
+ );
17781
+ const doc2 = store.update(
17782
+ existing.frontmatter.id,
17783
+ fm2,
17784
+ issue2.fields.description ?? ""
17785
+ );
17786
+ return {
17787
+ content: [
17788
+ {
17789
+ type: "text",
17790
+ text: `Updated ${doc2.frontmatter.id} from Jira ${args.key}`
17791
+ }
17792
+ ]
17793
+ };
17794
+ }
17795
+ const fm = jiraIssueToFrontmatter(issue2, jira.host);
17796
+ const doc = store.create(
17797
+ JIRA_TYPE,
17798
+ fm,
17799
+ issue2.fields.description ?? ""
17800
+ );
17801
+ return {
17802
+ content: [
17803
+ {
17804
+ type: "text",
17805
+ text: `Created ${doc.frontmatter.id} from Jira ${args.key}`
17806
+ }
17807
+ ]
17808
+ };
17809
+ }
17810
+ ),
17811
+ tool19(
17812
+ "pull_jira_issues_jql",
17813
+ "Bulk fetch Jira issues via JQL query and create/update local JI-xxx documents",
17814
+ {
17815
+ jql: external_exports.string().describe(`JQL query (e.g. 'project = PROJ AND status = "In Progress"')`),
17816
+ maxResults: external_exports.number().optional().describe("Max issues to fetch (default 50)")
17817
+ },
17818
+ async (args) => {
17819
+ const jira = createJiraClient(jiraUserConfig);
17820
+ if (!jira) return jiraNotConfiguredError();
17821
+ const result = await jira.client.searchIssues(args.jql, args.maxResults);
17822
+ const created = [];
17823
+ const updated = [];
17824
+ for (const issue2 of result.issues) {
17825
+ const existing = findByJiraKey(store, issue2.key);
17826
+ if (existing) {
17827
+ const fm = jiraIssueToFrontmatter(
17828
+ issue2,
17829
+ jira.host,
17830
+ existing.frontmatter.linkedArtifacts
17831
+ );
17832
+ store.update(
17833
+ existing.frontmatter.id,
17834
+ fm,
17835
+ issue2.fields.description ?? ""
17836
+ );
17837
+ updated.push(`${existing.frontmatter.id} (${issue2.key})`);
17838
+ } else {
17839
+ const fm = jiraIssueToFrontmatter(issue2, jira.host);
17840
+ const doc = store.create(
17841
+ JIRA_TYPE,
17842
+ fm,
17843
+ issue2.fields.description ?? ""
17844
+ );
17845
+ created.push(`${doc.frontmatter.id} (${issue2.key})`);
17846
+ }
17847
+ }
17848
+ const parts = [
17849
+ `Fetched ${result.issues.length} of ${result.total} matching issues.`
17850
+ ];
17851
+ if (created.length > 0) parts.push(`Created: ${created.join(", ")}`);
17852
+ if (updated.length > 0) parts.push(`Updated: ${updated.join(", ")}`);
17853
+ return {
17854
+ content: [{ type: "text", text: parts.join("\n") }]
17855
+ };
17856
+ }
17857
+ ),
17858
+ // --- Local → Jira tools ---
17859
+ tool19(
17860
+ "push_artifact_to_jira",
17861
+ "Create a Jira issue from any Marvin artifact (D/A/Q/F/E) and create a tracking JI-xxx document",
17862
+ {
17863
+ artifactId: external_exports.string().describe("Marvin artifact ID (e.g. 'D-001', 'F-003', 'E-002')"),
17864
+ projectKey: external_exports.string().describe("Jira project key (e.g. 'PROJ')"),
17865
+ issueType: external_exports.enum(["Story", "Task", "Bug", "Epic"]).optional().describe("Jira issue type (default: 'Task')")
17866
+ },
17867
+ async (args) => {
17868
+ const jira = createJiraClient(jiraUserConfig);
17869
+ if (!jira) return jiraNotConfiguredError();
17870
+ const artifact = store.get(args.artifactId);
17871
+ if (!artifact) {
17872
+ return {
17873
+ content: [
17874
+ { type: "text", text: `Artifact ${args.artifactId} not found` }
17875
+ ],
17876
+ isError: true
17877
+ };
17878
+ }
17879
+ const description = [
17880
+ artifact.content,
17881
+ "",
17882
+ `---`,
17883
+ `Marvin artifact: ${artifact.frontmatter.id} (${artifact.frontmatter.type})`,
17884
+ `Status: ${artifact.frontmatter.status}`
17885
+ ].join("\n");
17886
+ const jiraResult = await jira.client.createIssue({
17887
+ project: { key: args.projectKey },
17888
+ summary: artifact.frontmatter.title,
17889
+ description,
17890
+ issuetype: { name: args.issueType ?? "Task" }
17891
+ });
17892
+ const jiDoc = store.create(
17893
+ JIRA_TYPE,
17894
+ {
17895
+ title: artifact.frontmatter.title,
17896
+ status: "open",
17897
+ jiraKey: jiraResult.key,
17898
+ jiraUrl: `https://${jira.host}/browse/${jiraResult.key}`,
17899
+ issueType: args.issueType ?? "Task",
17900
+ priority: "Medium",
17901
+ assignee: "",
17902
+ labels: [],
17903
+ linkedArtifacts: [args.artifactId],
17904
+ tags: [`jira:${jiraResult.key}`],
17905
+ lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString()
17906
+ },
17907
+ ""
17908
+ );
17909
+ return {
17910
+ content: [
17911
+ {
17912
+ type: "text",
17913
+ text: `Created Jira ${jiraResult.key} from ${args.artifactId}. Tracking locally as ${jiDoc.frontmatter.id}.`
17914
+ }
17915
+ ]
17916
+ };
17917
+ }
17918
+ ),
17919
+ // --- Bidirectional sync ---
17920
+ tool19(
17921
+ "sync_jira_issue",
17922
+ "Bidirectional sync: push local title/description to Jira, pull latest status/assignee/labels back",
17923
+ {
17924
+ id: external_exports.string().describe("Local JI-xxx ID")
17925
+ },
17926
+ async (args) => {
17927
+ const jira = createJiraClient(jiraUserConfig);
17928
+ if (!jira) return jiraNotConfiguredError();
17929
+ const doc = store.get(args.id);
17930
+ if (!doc || doc.frontmatter.type !== JIRA_TYPE) {
17931
+ return {
17932
+ content: [
17933
+ { type: "text", text: `Jira issue ${args.id} not found locally` }
17934
+ ],
17935
+ isError: true
17936
+ };
17937
+ }
17938
+ const jiraKey = doc.frontmatter.jiraKey;
17939
+ await jira.client.updateIssue(jiraKey, {
17940
+ summary: doc.frontmatter.title,
17941
+ description: doc.content || void 0
17942
+ });
17943
+ const issue2 = await jira.client.getIssue(jiraKey);
17944
+ const fm = jiraIssueToFrontmatter(
17945
+ issue2,
17946
+ jira.host,
17947
+ doc.frontmatter.linkedArtifacts
17948
+ );
17949
+ store.update(args.id, fm, issue2.fields.description ?? "");
17950
+ return {
17951
+ content: [
17952
+ {
17953
+ type: "text",
17954
+ text: `Synced ${args.id} \u2194 ${jiraKey}. Status: ${fm.status}, Assignee: ${fm.assignee || "unassigned"}`
17955
+ }
17956
+ ]
17957
+ };
17958
+ }
17959
+ ),
17960
+ // --- Local link tool ---
17961
+ tool19(
17962
+ "link_artifact_to_jira",
17963
+ "Add a Marvin artifact ID to a JI-xxx document's linkedArtifacts field",
17964
+ {
17965
+ jiraIssueId: external_exports.string().describe("Local JI-xxx ID"),
17966
+ artifactId: external_exports.string().describe("Marvin artifact ID to link (e.g. 'D-001', 'F-003')")
17967
+ },
17968
+ async (args) => {
17969
+ const doc = store.get(args.jiraIssueId);
17970
+ if (!doc || doc.frontmatter.type !== JIRA_TYPE) {
17971
+ return {
17972
+ content: [
17973
+ {
17974
+ type: "text",
17975
+ text: `Jira issue ${args.jiraIssueId} not found locally`
17976
+ }
17977
+ ],
17978
+ isError: true
17979
+ };
17980
+ }
17981
+ const artifact = store.get(args.artifactId);
17982
+ if (!artifact) {
17983
+ return {
17984
+ content: [
17985
+ { type: "text", text: `Artifact ${args.artifactId} not found` }
17986
+ ],
17987
+ isError: true
17988
+ };
17989
+ }
17990
+ const linked = doc.frontmatter.linkedArtifacts ?? [];
17991
+ if (linked.includes(args.artifactId)) {
17992
+ return {
17993
+ content: [
17994
+ {
17995
+ type: "text",
17996
+ text: `${args.artifactId} is already linked to ${args.jiraIssueId}`
17997
+ }
17998
+ ]
17999
+ };
18000
+ }
18001
+ store.update(args.jiraIssueId, {
18002
+ linkedArtifacts: [...linked, args.artifactId]
18003
+ });
18004
+ return {
18005
+ content: [
18006
+ {
18007
+ type: "text",
18008
+ text: `Linked ${args.artifactId} to ${args.jiraIssueId}`
18009
+ }
18010
+ ]
18011
+ };
18012
+ }
18013
+ )
18014
+ ];
18015
+ }
18016
+
18017
+ // src/skills/builtin/jira/index.ts
18018
+ var jiraSkill = {
18019
+ id: "jira",
18020
+ name: "Jira Integration",
18021
+ description: "Bidirectional sync between Marvin artifacts and Jira issues",
18022
+ version: "1.0.0",
18023
+ format: "builtin-ts",
18024
+ // No default persona affinity — opt-in via config.yaml skills section
18025
+ documentTypeRegistrations: [
18026
+ { type: "jira-issue", dirName: "jira-issues", idPrefix: "JI" }
18027
+ ],
18028
+ tools: (store) => createJiraTools(store),
18029
+ promptFragments: {
18030
+ "product-owner": `You have the **Jira Integration** skill. You can pull issues from Jira and push Marvin artifacts to Jira.
18031
+
18032
+ **Available tools:**
18033
+ - \`list_jira_issues\` / \`get_jira_issue\` \u2014 browse locally synced Jira issues
18034
+ - \`pull_jira_issue\` / \`pull_jira_issues_jql\` \u2014 import issues from Jira by key or JQL query
18035
+ - \`push_artifact_to_jira\` \u2014 create a Jira issue from a Marvin artifact (decision, feature, etc.)
18036
+ - \`sync_jira_issue\` \u2014 bidirectional sync of a local JI-xxx with Jira
18037
+ - \`link_artifact_to_jira\` \u2014 link a Marvin artifact to an existing JI-xxx
18038
+
18039
+ **As Product Owner, use Jira integration to:**
18040
+ - Pull stakeholder-reported issues for triage and prioritization
18041
+ - Push approved features as Stories for development tracking
18042
+ - Link decisions to Jira issues for audit trail and traceability
18043
+ - Use JQL queries to review backlog status (e.g. \`project = PROJ AND status = "To Do"\`)`,
18044
+ "tech-lead": `You have the **Jira Integration** skill. You can pull issues from Jira and push Marvin artifacts to Jira.
18045
+
18046
+ **Available tools:**
18047
+ - \`list_jira_issues\` / \`get_jira_issue\` \u2014 browse locally synced Jira issues
18048
+ - \`pull_jira_issue\` / \`pull_jira_issues_jql\` \u2014 import issues from Jira by key or JQL query
18049
+ - \`push_artifact_to_jira\` \u2014 create a Jira issue from a Marvin artifact (decision, action, epic, etc.)
18050
+ - \`sync_jira_issue\` \u2014 bidirectional sync of a local JI-xxx with Jira
18051
+ - \`link_artifact_to_jira\` \u2014 link a Marvin artifact to an existing JI-xxx
18052
+
18053
+ **As Tech Lead, use Jira integration to:**
18054
+ - Pull technical issues and bugs for sprint planning and estimation
18055
+ - Push epics and technical decisions to Jira for cross-team visibility
18056
+ - Bidirectional sync to keep local governance and Jira in alignment
18057
+ - Use JQL queries to track technical debt (e.g. \`labels = "tech-debt" AND status != "Done"\`)`,
18058
+ "delivery-manager": `You have the **Jira Integration** skill. You can pull issues from Jira and push Marvin artifacts to Jira.
18059
+
18060
+ **Available tools:**
18061
+ - \`list_jira_issues\` / \`get_jira_issue\` \u2014 browse locally synced Jira issues
18062
+ - \`pull_jira_issue\` / \`pull_jira_issues_jql\` \u2014 import issues from Jira by key or JQL query
18063
+ - \`push_artifact_to_jira\` \u2014 create a Jira issue from a Marvin artifact (decision, action, etc.)
18064
+ - \`sync_jira_issue\` \u2014 bidirectional sync of a local JI-xxx with Jira
18065
+ - \`link_artifact_to_jira\` \u2014 link a Marvin artifact to an existing JI-xxx
18066
+
18067
+ **As Delivery Manager, use Jira integration to:**
18068
+ - Pull sprint issues for tracking progress and blockers
18069
+ - Push actions and decisions to Jira for stakeholder visibility
18070
+ - Use JQL queries for reporting (e.g. \`sprint in openSprints() AND assignee = currentUser()\`)
18071
+ - Sync status between Marvin governance items and Jira issues`
18072
+ }
18073
+ };
18074
+
17505
18075
  // src/skills/registry.ts
17506
18076
  var BUILTIN_SKILLS = {
17507
- "governance-review": governanceReviewSkill
18077
+ "governance-review": governanceReviewSkill,
18078
+ "jira": jiraSkill
17508
18079
  };
17509
18080
  var GOVERNANCE_TOOL_NAMES = [
17510
18081
  "mcp__marvin-governance__list_decisions",
@@ -17653,6 +18224,16 @@ function resolveSkillsForPersona(personaId, skillsConfig, allSkills) {
17653
18224
  }
17654
18225
  return result;
17655
18226
  }
18227
+ function collectSkillRegistrations(skillIds, allSkills) {
18228
+ const registrations = [];
18229
+ for (const id of skillIds) {
18230
+ const skill = allSkills.get(id);
18231
+ if (skill?.documentTypeRegistrations) {
18232
+ registrations.push(...skill.documentTypeRegistrations);
18233
+ }
18234
+ }
18235
+ return registrations;
18236
+ }
17656
18237
  function getSkillTools(skillIds, allSkills, store) {
17657
18238
  const tools = [];
17658
18239
  for (const id of skillIds) {
@@ -17764,16 +18345,17 @@ ${wildcardPrompt}
17764
18345
  async function startSession(options) {
17765
18346
  const { persona, config: config2, marvinDir, projectRoot } = options;
17766
18347
  const plugin = resolvePlugin(config2.project.methodology);
17767
- const registrations = plugin?.documentTypeRegistrations ?? [];
17768
- const store = new DocumentStore(marvinDir, registrations);
18348
+ const pluginRegistrations = plugin?.documentTypeRegistrations ?? [];
18349
+ const allSkills = loadAllSkills(marvinDir);
18350
+ const skillIds = resolveSkillsForPersona(persona.id, config2.project.skills, allSkills);
18351
+ const skillRegistrations = collectSkillRegistrations(skillIds, allSkills);
18352
+ const store = new DocumentStore(marvinDir, [...pluginRegistrations, ...skillRegistrations]);
17769
18353
  const sessionStore = new SessionStore(marvinDir);
17770
18354
  const sourcesDir = path8.join(marvinDir, "sources");
17771
18355
  const hasSourcesDir = fs8.existsSync(sourcesDir);
17772
18356
  const manifest = hasSourcesDir ? new SourceManifestManager(marvinDir) : void 0;
17773
18357
  const pluginTools = plugin ? getPluginTools(plugin, store, marvinDir) : [];
17774
18358
  const pluginPromptFragment = plugin ? getPluginPromptFragment(plugin, persona.id) : void 0;
17775
- const allSkills = loadAllSkills(marvinDir);
17776
- const skillIds = resolveSkillsForPersona(persona.id, config2.project.skills, allSkills);
17777
18359
  const codeSkillTools = getSkillTools(skillIds, allSkills, store);
17778
18360
  const skillAgents = getSkillAgentDefinitions(skillIds, allSkills);
17779
18361
  const skillPromptFragment = getSkillPromptFragment(skillIds, allSkills, persona.id);
@@ -17820,10 +18402,10 @@ Marvin \u2014 ${persona.name}
17820
18402
  });
17821
18403
  try {
17822
18404
  while (true) {
17823
- const input3 = await new Promise((resolve5) => {
18405
+ const input4 = await new Promise((resolve5) => {
17824
18406
  rl.question(chalk.green("\nYou: "), resolve5);
17825
18407
  });
17826
- const trimmed = input3.trim();
18408
+ const trimmed = input4.trim();
17827
18409
  if (trimmed === "exit" || trimmed === "quit") {
17828
18410
  break;
17829
18411
  }
@@ -17970,7 +18552,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
17970
18552
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
17971
18553
 
17972
18554
  // src/skills/action-tools.ts
17973
- import { tool as tool19 } from "@anthropic-ai/claude-agent-sdk";
18555
+ import { tool as tool20 } from "@anthropic-ai/claude-agent-sdk";
17974
18556
 
17975
18557
  // src/skills/action-runner.ts
17976
18558
  import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
@@ -18036,7 +18618,7 @@ function createSkillActionTools(skills, context) {
18036
18618
  if (!skill.actions) continue;
18037
18619
  for (const action of skill.actions) {
18038
18620
  tools.push(
18039
- tool19(
18621
+ tool20(
18040
18622
  `${skill.id}__${action.id}`,
18041
18623
  action.description,
18042
18624
  {
@@ -18128,10 +18710,10 @@ ${lines.join("\n\n")}`;
18128
18710
  }
18129
18711
 
18130
18712
  // src/mcp/persona-tools.ts
18131
- import { tool as tool20 } from "@anthropic-ai/claude-agent-sdk";
18713
+ import { tool as tool21 } from "@anthropic-ai/claude-agent-sdk";
18132
18714
  function createPersonaTools(ctx, marvinDir) {
18133
18715
  return [
18134
- tool20(
18716
+ tool21(
18135
18717
  "set_persona",
18136
18718
  "Set the active persona for this session. Returns full guidance for the selected persona including behavioral rules, allowed document types, and scope. Call this before working to ensure persona-appropriate behavior.",
18137
18719
  {
@@ -18161,7 +18743,7 @@ ${summaries}`
18161
18743
  };
18162
18744
  }
18163
18745
  ),
18164
- tool20(
18746
+ tool21(
18165
18747
  "get_persona_guidance",
18166
18748
  "Get guidance for a persona without changing the active persona. If no persona is specified, lists all available personas with summaries.",
18167
18749
  {
@@ -18614,23 +19196,29 @@ Project: ${project.config.name}
18614
19196
 
18615
19197
  // src/cli/commands/config.ts
18616
19198
  import chalk6 from "chalk";
18617
- import { password } from "@inquirer/prompts";
19199
+ import { input as input2, password } from "@inquirer/prompts";
18618
19200
  async function configCommand(key, value) {
18619
19201
  if (key === "api-key") {
18620
19202
  return setApiKey();
18621
19203
  }
19204
+ if (key === "jira") {
19205
+ return setJira();
19206
+ }
18622
19207
  if (!key) {
18623
19208
  const config2 = loadUserConfig();
18624
19209
  console.log(chalk6.bold("\nUser Configuration:\n"));
18625
19210
  console.log(
18626
- ` API Key: ${config2.apiKey ? chalk6.green("configured") : chalk6.red("not set")}`
19211
+ ` API Key: ${config2.apiKey ? chalk6.green("configured") : chalk6.red("not set")}`
18627
19212
  );
18628
19213
  console.log(
18629
- ` Default Model: ${config2.defaultModel ?? chalk6.dim("(default: claude-sonnet-4-5-20250929)")}`
19214
+ ` Default Model: ${config2.defaultModel ?? chalk6.dim("(default: claude-sonnet-4-5-20250929)")}`
18630
19215
  );
18631
19216
  console.log(
18632
19217
  ` Default Persona: ${config2.defaultPersona ?? chalk6.dim("(default: product-owner)")}`
18633
19218
  );
19219
+ console.log(
19220
+ ` Jira: ${config2.jira?.host ? chalk6.green(`configured (${config2.jira.host})`) : chalk6.red("not set")}`
19221
+ );
18634
19222
  console.log();
18635
19223
  return;
18636
19224
  }
@@ -18663,6 +19251,37 @@ async function configCommand(key, value) {
18663
19251
  }
18664
19252
  }
18665
19253
  }
19254
+ async function setJira() {
19255
+ const host = await input2({
19256
+ message: "Jira host (e.g. mycompany.atlassian.net):"
19257
+ });
19258
+ if (!host.trim()) {
19259
+ console.log(chalk6.red("No host provided."));
19260
+ return;
19261
+ }
19262
+ const email3 = await input2({
19263
+ message: "Jira email:"
19264
+ });
19265
+ if (!email3.trim()) {
19266
+ console.log(chalk6.red("No email provided."));
19267
+ return;
19268
+ }
19269
+ const apiToken = await password({
19270
+ message: "Jira API token:"
19271
+ });
19272
+ if (!apiToken.trim()) {
19273
+ console.log(chalk6.red("No API token provided."));
19274
+ return;
19275
+ }
19276
+ const config2 = loadUserConfig();
19277
+ config2.jira = {
19278
+ host: host.trim(),
19279
+ email: email3.trim(),
19280
+ apiToken: apiToken.trim()
19281
+ };
19282
+ saveUserConfig(config2);
19283
+ console.log(chalk6.green("Jira credentials saved."));
19284
+ }
18666
19285
  async function setApiKey() {
18667
19286
  const apiKey = await password({
18668
19287
  message: "Enter your Anthropic API key:"
@@ -18976,7 +19595,7 @@ ${pending} file${pending === 1 ? "" : "s"} ready to process. Run "marvin ingest
18976
19595
  // src/cli/commands/sync.ts
18977
19596
  import chalk9 from "chalk";
18978
19597
  import ora3 from "ora";
18979
- import { input as input2 } from "@inquirer/prompts";
19598
+ import { input as input3 } from "@inquirer/prompts";
18980
19599
 
18981
19600
  // src/git/repository.ts
18982
19601
  import * as path13 from "path";
@@ -19183,7 +19802,7 @@ async function syncInitCommand(opts) {
19183
19802
  const git = new MarvinGit(project.marvinDir);
19184
19803
  let remote = opts.remote;
19185
19804
  if (!remote) {
19186
- remote = await input2({
19805
+ remote = await input3({
19187
19806
  message: "Remote repository URL (leave blank to skip):"
19188
19807
  }) || void 0;
19189
19808
  }
@@ -19404,20 +20023,23 @@ async function skillsInstallCommand(skillId, options) {
19404
20023
  console.log(chalk10.red("Please specify a persona with --as <persona>."));
19405
20024
  return;
19406
20025
  }
20026
+ const targets = persona === "all" ? listPersonas().map((p) => p.id) : [persona];
19407
20027
  const config2 = loadProjectConfig(project.marvinDir);
19408
20028
  if (!config2.skills) {
19409
20029
  config2.skills = {};
19410
20030
  }
19411
- if (!config2.skills[persona]) {
19412
- config2.skills[persona] = [];
19413
- }
19414
- if (config2.skills[persona].includes(skillId)) {
19415
- console.log(chalk10.yellow(`Skill "${skillId}" is already assigned to ${persona}.`));
19416
- return;
20031
+ for (const target of targets) {
20032
+ if (!config2.skills[target]) {
20033
+ config2.skills[target] = [];
20034
+ }
20035
+ if (config2.skills[target].includes(skillId)) {
20036
+ console.log(chalk10.yellow(`Skill "${skillId}" is already assigned to ${target}.`));
20037
+ continue;
20038
+ }
20039
+ config2.skills[target].push(skillId);
20040
+ console.log(chalk10.green(`Assigned skill "${skillId}" to ${target}.`));
19417
20041
  }
19418
- config2.skills[persona].push(skillId);
19419
20042
  saveProjectConfig(project.marvinDir, config2);
19420
- console.log(chalk10.green(`Assigned skill "${skillId}" to ${persona}.`));
19421
20043
  }
19422
20044
  async function skillsRemoveCommand(skillId, options) {
19423
20045
  const project = loadProject();
@@ -19426,25 +20048,28 @@ async function skillsRemoveCommand(skillId, options) {
19426
20048
  console.log(chalk10.red("Please specify a persona with --as <persona>."));
19427
20049
  return;
19428
20050
  }
20051
+ const targets = persona === "all" ? listPersonas().map((p) => p.id) : [persona];
19429
20052
  const config2 = loadProjectConfig(project.marvinDir);
19430
- if (!config2.skills?.[persona]) {
19431
- console.log(chalk10.yellow(`No skills configured for ${persona}.`));
19432
- return;
19433
- }
19434
- const idx = config2.skills[persona].indexOf(skillId);
19435
- if (idx === -1) {
19436
- console.log(chalk10.yellow(`Skill "${skillId}" is not assigned to ${persona}.`));
19437
- return;
19438
- }
19439
- config2.skills[persona].splice(idx, 1);
19440
- if (config2.skills[persona].length === 0) {
19441
- delete config2.skills[persona];
20053
+ for (const target of targets) {
20054
+ if (!config2.skills?.[target]) {
20055
+ console.log(chalk10.yellow(`No skills configured for ${target}.`));
20056
+ continue;
20057
+ }
20058
+ const idx = config2.skills[target].indexOf(skillId);
20059
+ if (idx === -1) {
20060
+ console.log(chalk10.yellow(`Skill "${skillId}" is not assigned to ${target}.`));
20061
+ continue;
20062
+ }
20063
+ config2.skills[target].splice(idx, 1);
20064
+ if (config2.skills[target].length === 0) {
20065
+ delete config2.skills[target];
20066
+ }
20067
+ console.log(chalk10.green(`Removed skill "${skillId}" from ${target}.`));
19442
20068
  }
19443
- if (Object.keys(config2.skills).length === 0) {
20069
+ if (config2.skills && Object.keys(config2.skills).length === 0) {
19444
20070
  delete config2.skills;
19445
20071
  }
19446
20072
  saveProjectConfig(project.marvinDir, config2);
19447
- console.log(chalk10.green(`Removed skill "${skillId}" from ${persona}.`));
19448
20073
  }
19449
20074
  async function skillsCreateCommand(name) {
19450
20075
  const project = loadProject();
@@ -20691,12 +21316,94 @@ Contribution: ${options.type}`));
20691
21316
  });
20692
21317
  }
20693
21318
 
21319
+ // src/reports/gar/render-ascii.ts
21320
+ import chalk16 from "chalk";
21321
+ var STATUS_DOT = {
21322
+ green: chalk16.green("\u25CF"),
21323
+ amber: chalk16.yellow("\u25CF"),
21324
+ red: chalk16.red("\u25CF")
21325
+ };
21326
+ var STATUS_LABEL = {
21327
+ green: chalk16.green.bold("GREEN"),
21328
+ amber: chalk16.yellow.bold("AMBER"),
21329
+ red: chalk16.red.bold("RED")
21330
+ };
21331
+ var SEPARATOR = chalk16.dim("\u2500".repeat(60));
21332
+ function renderAscii(report) {
21333
+ const lines = [];
21334
+ lines.push("");
21335
+ lines.push(chalk16.bold(` GAR Report \xB7 ${report.projectName}`));
21336
+ lines.push(chalk16.dim(` ${report.generatedAt}`));
21337
+ lines.push("");
21338
+ lines.push(` Overall: ${STATUS_LABEL[report.overall]}`);
21339
+ lines.push("");
21340
+ lines.push(` ${SEPARATOR}`);
21341
+ for (const area of report.areas) {
21342
+ lines.push(` ${STATUS_DOT[area.status]} ${chalk16.bold(area.name.padEnd(12))} ${area.summary}`);
21343
+ for (const item of area.items) {
21344
+ lines.push(` ${chalk16.dim("\u2514")} ${item.id} ${item.title}`);
21345
+ }
21346
+ }
21347
+ lines.push(` ${SEPARATOR}`);
21348
+ lines.push("");
21349
+ return lines.join("\n");
21350
+ }
21351
+
21352
+ // src/reports/gar/render-confluence.ts
21353
+ var EMOJI = {
21354
+ green: ":green_circle:",
21355
+ amber: ":yellow_circle:",
21356
+ red: ":red_circle:"
21357
+ };
21358
+ function renderConfluence(report) {
21359
+ const lines = [];
21360
+ lines.push(`# GAR Report \u2014 ${report.projectName}`);
21361
+ lines.push("");
21362
+ lines.push(`**Date:** ${report.generatedAt}`);
21363
+ lines.push(`**Overall:** ${EMOJI[report.overall]} ${report.overall.toUpperCase()}`);
21364
+ lines.push("");
21365
+ lines.push("| Area | Status | Summary |");
21366
+ lines.push("|------|--------|---------|");
21367
+ for (const area of report.areas) {
21368
+ lines.push(
21369
+ `| ${area.name} | ${EMOJI[area.status]} ${area.status.toUpperCase()} | ${area.summary} |`
21370
+ );
21371
+ }
21372
+ lines.push("");
21373
+ for (const area of report.areas) {
21374
+ if (area.items.length === 0) continue;
21375
+ lines.push(`## ${area.name}`);
21376
+ lines.push("");
21377
+ for (const item of area.items) {
21378
+ lines.push(`- **${item.id}** ${item.title}`);
21379
+ }
21380
+ lines.push("");
21381
+ }
21382
+ return lines.join("\n");
21383
+ }
21384
+
21385
+ // src/cli/commands/report.ts
21386
+ async function garReportCommand(options) {
21387
+ const project = loadProject();
21388
+ const plugin = resolvePlugin(project.config.methodology);
21389
+ const registrations = plugin?.documentTypeRegistrations ?? [];
21390
+ const store = new DocumentStore(project.marvinDir, registrations);
21391
+ const metrics = collectGarMetrics(store);
21392
+ const report = evaluateGar(project.config.name, metrics);
21393
+ const format = options.format ?? "ascii";
21394
+ if (format === "confluence") {
21395
+ console.log(renderConfluence(report));
21396
+ } else {
21397
+ console.log(renderAscii(report));
21398
+ }
21399
+ }
21400
+
20694
21401
  // src/cli/program.ts
20695
21402
  function createProgram() {
20696
21403
  const program = new Command();
20697
21404
  program.name("marvin").description(
20698
21405
  "AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
20699
- ).version("0.2.6");
21406
+ ).version("0.2.9");
20700
21407
  program.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
20701
21408
  await initCommand();
20702
21409
  });
@@ -20766,6 +21473,13 @@ function createProgram() {
20766
21473
  skillsCmd.command("migrate").description("Migrate YAML skill files to SKILL.md directory format").action(async () => {
20767
21474
  await skillsMigrateCommand();
20768
21475
  });
21476
+ const reportCmd = program.command("report").description("Generate project reports");
21477
+ reportCmd.command("gar").description("Generate a Green/Amber/Red status report").option(
21478
+ "--format <format>",
21479
+ "Output format: ascii or confluence (default: ascii)"
21480
+ ).action(async (options) => {
21481
+ await garReportCommand(options);
21482
+ });
20769
21483
  return program;
20770
21484
  }
20771
21485
  export {