@3lineas/grooveskills 1.3.1 → 1.5.0

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.
@@ -1,5 +1,5 @@
1
1
  // src/domains/detector/project-detector.ts
2
- import { existsSync as existsSync2 } from "fs";
2
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
3
3
  import { join as join2 } from "path";
4
4
 
5
5
  // src/domains/detector/detect-agents.ts
@@ -70,7 +70,8 @@ var SKILL_CATALOG = [
70
70
  name: "GrooveSkills Harness",
71
71
  description: "Lightweight project harness, context memory, and ODD 3-lane task execution (Answer, Task, Spec) for AI coding agents",
72
72
  dependencies: [],
73
- directoryName: "groove-harness"
73
+ directoryName: "groove-harness",
74
+ isCoreHarness: true
74
75
  },
75
76
  {
76
77
  id: "odd-ai",
@@ -173,6 +174,19 @@ var SKILL_CATALOG = [
173
174
  ];
174
175
 
175
176
  // src/domains/detector/project-detector.ts
177
+ function readConfiguredLanguage(targetPath) {
178
+ const configPath = join2(targetPath, ".grooveskills", "config.json");
179
+ if (!existsSync2(configPath)) {
180
+ return void 0;
181
+ }
182
+ try {
183
+ const raw = readFileSync2(configPath, "utf-8");
184
+ const parsed = JSON.parse(raw);
185
+ return typeof parsed.language === "string" ? parsed.language : void 0;
186
+ } catch {
187
+ return void 0;
188
+ }
189
+ }
176
190
  function detectProjectContext(targetPath) {
177
191
  const detectedAgents = detectAgents(targetPath);
178
192
  const { dependencies, exists } = detectDependencies(targetPath);
@@ -193,18 +207,20 @@ function detectProjectContext(targetPath) {
193
207
  }
194
208
  }
195
209
  const harnessExists = existsSync2(join2(targetPath, ".grooveskills", "memory", "context.md"));
210
+ const configuredLanguage = readConfiguredLanguage(targetPath);
196
211
  return {
197
212
  targetPath,
198
213
  detectedDependencies: dependencies,
199
214
  suggestedSkillIds,
200
215
  detectedAgents,
201
216
  packageJsonExists: exists,
202
- harnessExists
217
+ harnessExists,
218
+ configuredLanguage
203
219
  };
204
220
  }
205
221
 
206
222
  // src/domains/ui/ui-orchestrator.ts
207
- import * as p6 from "@clack/prompts";
223
+ import * as p5 from "@clack/prompts";
208
224
  import pc2 from "picocolors";
209
225
 
210
226
  // src/domains/ui/banners.ts
@@ -220,7 +236,8 @@ function renderBanner() {
220
236
  // src/domains/ui/prompt-skills.ts
221
237
  import * as p from "@clack/prompts";
222
238
  async function promptSkills(suggestedSkillIds) {
223
- const options = SKILL_CATALOG.map((skill) => {
239
+ const selectableSkills = SKILL_CATALOG.filter((skill) => !skill.isCoreHarness);
240
+ const options = selectableSkills.map((skill) => {
224
241
  const isSuggested = suggestedSkillIds.includes(skill.id);
225
242
  return {
226
243
  value: skill.id,
@@ -256,19 +273,8 @@ async function promptAgents(detectedAgents) {
256
273
  return selected;
257
274
  }
258
275
 
259
- // src/domains/ui/prompt-harness.ts
260
- import * as p3 from "@clack/prompts";
261
- async function promptHarness(harnessExists) {
262
- const message = harnessExists ? "GrooveSkills Harness is already initialized. Would you like to update agent rules and memory templates?" : "Would you like to initialize the GrooveSkills Harness in .grooveskills/ (project memory, ADR, and 3-lane task execution)?";
263
- const confirm3 = await p3.confirm({
264
- message,
265
- initialValue: true
266
- });
267
- return confirm3;
268
- }
269
-
270
276
  // src/domains/ui/prompt-language.ts
271
- import * as p4 from "@clack/prompts";
277
+ import * as p3 from "@clack/prompts";
272
278
  async function promptLanguage(defaultLanguage = "es") {
273
279
  const options = [
274
280
  { value: "es", label: "Espa\xF1ol (Spanish)", hint: "Recomendado para proyectos en espa\xF1ol" },
@@ -277,7 +283,7 @@ async function promptLanguage(defaultLanguage = "es") {
277
283
  { value: "it", label: "Italiano (Italian)", hint: "Comunicazione in lingua italiana" },
278
284
  { value: "fr", label: "Fran\xE7ais (French)", hint: "Communication en langue fran\xE7aise" }
279
285
  ];
280
- const selected = await p4.select({
286
+ const selected = await p3.select({
281
287
  message: "Which language should AI agents use for user-facing copy and communication?",
282
288
  options,
283
289
  initialValue: defaultLanguage
@@ -286,9 +292,9 @@ async function promptLanguage(defaultLanguage = "es") {
286
292
  }
287
293
 
288
294
  // src/domains/ui/prompt-confirm-overwrite.ts
289
- import * as p5 from "@clack/prompts";
295
+ import * as p4 from "@clack/prompts";
290
296
  async function promptConfirmOverwrite() {
291
- return await p5.confirm({
297
+ return await p4.confirm({
292
298
  message: "Some skills already exist in this project. Would you like to overwrite them with the latest version?",
293
299
  initialValue: true
294
300
  });
@@ -317,10 +323,10 @@ function verifySkillExists(targetPath, skillDirectoryName, agents) {
317
323
  }
318
324
 
319
325
  // src/domains/installer/install-orchestrator.ts
320
- import { join as join13 } from "path";
326
+ import { join as join11 } from "path";
321
327
 
322
- // src/domains/adapters/antigravity.adapter.ts
323
- import { mkdirSync, existsSync as existsSync3 } from "fs";
328
+ // src/domains/adapters/skill-reference-builder.ts
329
+ import { existsSync as existsSync3, lstatSync as lstatSync2, mkdirSync, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync } from "fs";
324
330
  import { join as join5 } from "path";
325
331
 
326
332
  // src/domains/project-store/project-paths.ts
@@ -331,9 +337,6 @@ function getProjectStoreDir(targetPath) {
331
337
  function getProjectSkillsDir(targetPath) {
332
338
  return join4(getProjectStoreDir(targetPath), "skills");
333
339
  }
334
- function getProjectCursorRulesDir(targetPath) {
335
- return join4(getProjectStoreDir(targetPath), "cursor-rules");
336
- }
337
340
  function getProjectMemoryDir(targetPath) {
338
341
  return join4(getProjectStoreDir(targetPath), "memory");
339
342
  }
@@ -344,13 +347,26 @@ function getProjectConfigPath(targetPath) {
344
347
  return join4(getProjectStoreDir(targetPath), "config.json");
345
348
  }
346
349
 
347
- // src/domains/adapters/link-helper.ts
348
- import { lstatSync as lstatSync2, unlinkSync, rmSync, symlinkSync } from "fs";
349
- import { dirname, relative } from "path";
350
- function removeExistingLinkPath(path) {
350
+ // src/domains/adapters/skill-reference-builder.ts
351
+ function removeExistingPathSafely(path) {
352
+ const fileExists = existsSync3(path);
353
+ if (!fileExists) {
354
+ try {
355
+ const lstat = lstatSync2(path);
356
+ if (lstat.isSymbolicLink()) {
357
+ unlinkSync(path);
358
+ }
359
+ } catch {
360
+ }
361
+ return;
362
+ }
351
363
  try {
352
364
  const lstat = lstatSync2(path);
353
- if (lstat.isDirectory() && !lstat.isSymbolicLink()) {
365
+ if (lstat.isSymbolicLink()) {
366
+ unlinkSync(path);
367
+ return;
368
+ }
369
+ if (lstat.isDirectory()) {
354
370
  rmSync(path, { recursive: true, force: true });
355
371
  return;
356
372
  }
@@ -358,11 +374,71 @@ function removeExistingLinkPath(path) {
358
374
  } catch {
359
375
  }
360
376
  }
361
- function createOrReplaceSymlink(target, linkPath, type) {
362
- removeExistingLinkPath(linkPath);
363
- const linkDir = dirname(linkPath);
364
- const relativeTarget = relative(linkDir, target);
365
- symlinkSync(relativeTarget, linkPath, type);
377
+ function extractSkillDescription(canonicalSkillMdPath, fallback) {
378
+ if (!existsSync3(canonicalSkillMdPath)) {
379
+ return fallback;
380
+ }
381
+ try {
382
+ const content = readFileSync3(canonicalSkillMdPath, "utf-8");
383
+ const match = content.match(/^description:\s*(.+)$/m);
384
+ const hasMatchedDesc = Boolean(match && match[1]);
385
+ if (hasMatchedDesc && match?.[1]) {
386
+ return match[1].trim();
387
+ }
388
+ } catch {
389
+ }
390
+ return fallback;
391
+ }
392
+ function writeAgentSkillReference(targetPath, agentRelativeSkillsDir, skill) {
393
+ const agentSkillFolder = join5(targetPath, agentRelativeSkillsDir, skill.directoryName);
394
+ removeExistingPathSafely(agentSkillFolder);
395
+ mkdirSync(agentSkillFolder, { recursive: true });
396
+ const canonicalSkillMd = join5(getProjectSkillsDir(targetPath), skill.directoryName, "SKILL.md");
397
+ const description = extractSkillDescription(canonicalSkillMd, skill.description);
398
+ const referenceContent = `---
399
+ name: ${skill.id}
400
+ description: ${description}
401
+ ---
402
+
403
+ # ${skill.name} \u2014 Skill Reference
404
+
405
+ Canonical skill specification stored in \`.grooveskills/\`.
406
+
407
+ - **Specification**: [\`.grooveskills/skills/${skill.directoryName}/SKILL.md\`](../../../.grooveskills/skills/${skill.directoryName}/SKILL.md)
408
+ - **References & Templates**: \`.grooveskills/skills/${skill.directoryName}/\`
409
+
410
+ > **Instruction**: Read \`.grooveskills/skills/${skill.directoryName}/SKILL.md\` before executing tasks matching this skill.
411
+ `;
412
+ const targetFile = join5(agentSkillFolder, "SKILL.md");
413
+ writeFileSync(targetFile, referenceContent, "utf-8");
414
+ return targetFile;
415
+ }
416
+ function writeCursorRuleReference(targetPath, cursorRelativeRulesDir, skill) {
417
+ const rulesDir = join5(targetPath, cursorRelativeRulesDir);
418
+ if (!existsSync3(rulesDir)) {
419
+ mkdirSync(rulesDir, { recursive: true });
420
+ }
421
+ const targetFile = join5(rulesDir, `${skill.id}.mdc`);
422
+ removeExistingPathSafely(targetFile);
423
+ const canonicalSkillMd = join5(getProjectSkillsDir(targetPath), skill.directoryName, "SKILL.md");
424
+ const description = extractSkillDescription(canonicalSkillMd, skill.description);
425
+ const referenceContent = `---
426
+ description: ${description}
427
+ globs: ["**/*"]
428
+ alwaysApply: false
429
+ ---
430
+
431
+ # ${skill.name} \u2014 Rule Reference
432
+
433
+ Canonical rule specification stored in \`.grooveskills/\`.
434
+
435
+ - **Specification**: \`.grooveskills/skills/${skill.directoryName}/SKILL.md\`
436
+ - **References & Templates**: \`.grooveskills/skills/${skill.directoryName}/\`
437
+
438
+ > **Instruction**: Read \`.grooveskills/skills/${skill.directoryName}/SKILL.md\` before executing tasks matching this rule.
439
+ `;
440
+ writeFileSync(targetFile, referenceContent, "utf-8");
441
+ return targetFile;
366
442
  }
367
443
 
368
444
  // src/domains/adapters/antigravity.adapter.ts
@@ -371,101 +447,70 @@ var AntigravityAdapter = class {
371
447
  name = "Antigravity";
372
448
  targetRelativeDir = ".agents/skills";
373
449
  async installSkill(targetPath, skill, _skillSourceDir) {
374
- const parentDir = join5(targetPath, this.targetRelativeDir);
375
- if (!existsSync3(parentDir)) {
376
- mkdirSync(parentDir, { recursive: true });
377
- }
378
- const destination = join5(parentDir, skill.directoryName);
379
- const projectSkillDir = join5(getProjectSkillsDir(targetPath), skill.directoryName);
380
- createOrReplaceSymlink(projectSkillDir, destination, "dir");
381
- return [destination];
450
+ const file = writeAgentSkillReference(targetPath, this.targetRelativeDir, skill);
451
+ return [file];
382
452
  }
383
453
  };
384
454
 
385
455
  // src/domains/adapters/claude.adapter.ts
386
- import { mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
387
- import { join as join6 } from "path";
388
456
  var ClaudeAdapter = class {
389
457
  id = "claude";
390
458
  name = "Claude Code";
391
459
  targetRelativeDir = ".claude/skills";
392
460
  async installSkill(targetPath, skill, _skillSourceDir) {
393
- const parentDir = join6(targetPath, this.targetRelativeDir);
394
- if (!existsSync4(parentDir)) {
395
- mkdirSync2(parentDir, { recursive: true });
396
- }
397
- const destination = join6(parentDir, skill.directoryName);
398
- const projectSkillDir = join6(getProjectSkillsDir(targetPath), skill.directoryName);
399
- createOrReplaceSymlink(projectSkillDir, destination, "dir");
400
- return [destination];
461
+ const file = writeAgentSkillReference(targetPath, this.targetRelativeDir, skill);
462
+ return [file];
401
463
  }
402
464
  };
403
465
 
404
466
  // src/domains/adapters/cursor.adapter.ts
405
- import { mkdirSync as mkdirSync3, existsSync as existsSync5 } from "fs";
406
- import { join as join7 } from "path";
407
467
  var CursorAdapter = class {
408
468
  id = "cursor";
409
469
  name = "Cursor";
410
470
  targetRelativeDir = ".cursor/rules";
411
471
  async installSkill(targetPath, skill, _skillSourceDir) {
412
- const rulesDir = join7(targetPath, this.targetRelativeDir);
413
- if (!existsSync5(rulesDir)) {
414
- mkdirSync3(rulesDir, { recursive: true });
415
- }
416
- const filename = `${skill.id}.mdc`;
417
- const destination = join7(rulesDir, filename);
418
- const projectRuleFile = join7(getProjectCursorRulesDir(targetPath), filename);
419
- createOrReplaceSymlink(projectRuleFile, destination, "file");
420
- return [destination];
472
+ const file = writeCursorRuleReference(targetPath, this.targetRelativeDir, skill);
473
+ return [file];
421
474
  }
422
475
  };
423
476
 
424
477
  // src/domains/adapters/gemini.adapter.ts
425
- import { mkdirSync as mkdirSync4, existsSync as existsSync6 } from "fs";
426
- import { join as join8 } from "path";
427
478
  var GeminiAdapter = class {
428
479
  id = "gemini";
429
480
  name = "Gemini Code Assist";
430
481
  targetRelativeDir = ".gemini/skills";
431
482
  async installSkill(targetPath, skill, _skillSourceDir) {
432
- const parentDir = join8(targetPath, this.targetRelativeDir);
433
- if (!existsSync6(parentDir)) {
434
- mkdirSync4(parentDir, { recursive: true });
435
- }
436
- const destination = join8(parentDir, skill.directoryName);
437
- const projectSkillDir = join8(getProjectSkillsDir(targetPath), skill.directoryName);
438
- createOrReplaceSymlink(projectSkillDir, destination, "dir");
439
- return [destination];
483
+ const file = writeAgentSkillReference(targetPath, this.targetRelativeDir, skill);
484
+ return [file];
440
485
  }
441
486
  };
442
487
 
443
488
  // src/domains/project-store/sync-project-store.ts
444
- import { cpSync, mkdirSync as mkdirSync5, existsSync as existsSync8, writeFileSync, readFileSync as readFileSync2 } from "fs";
445
- import { join as join10 } from "path";
489
+ import { cpSync, existsSync as existsSync5, mkdirSync as mkdirSync2, rmSync as rmSync2 } from "fs";
490
+ import { join as join7 } from "path";
446
491
 
447
492
  // src/domains/installer/resolve-skills-source.ts
448
493
  import { fileURLToPath } from "url";
449
- import { dirname as dirname2, resolve, join as join9 } from "path";
450
- import { existsSync as existsSync7 } from "fs";
494
+ import { dirname, resolve, join as join6 } from "path";
495
+ import { existsSync as existsSync4 } from "fs";
451
496
  function resolveSkillsSourceRoot() {
452
497
  const currentFilePath = fileURLToPath(import.meta.url);
453
- const currentDir = dirname2(currentFilePath);
498
+ const currentDir = dirname(currentFilePath);
454
499
  const candidateFromDist = resolve(currentDir, "../skills");
455
- if (existsSync7(candidateFromDist)) {
500
+ if (existsSync4(candidateFromDist)) {
456
501
  return candidateFromDist;
457
502
  }
458
503
  const candidateFromSrc = resolve(currentDir, "../../../skills");
459
- if (existsSync7(candidateFromSrc)) {
504
+ if (existsSync4(candidateFromSrc)) {
460
505
  return candidateFromSrc;
461
506
  }
462
507
  let searchDir = currentDir;
463
508
  for (let i = 0; i < 5; i++) {
464
- const candidate = join9(searchDir, "skills");
465
- if (existsSync7(candidate)) {
509
+ const candidate = join6(searchDir, "skills");
510
+ if (existsSync4(candidate)) {
466
511
  return candidate;
467
512
  }
468
- const parent = dirname2(searchDir);
513
+ const parent = dirname(searchDir);
469
514
  if (parent === searchDir) {
470
515
  break;
471
516
  }
@@ -477,51 +522,35 @@ function resolveSkillsSourceRoot() {
477
522
  }
478
523
 
479
524
  // src/domains/project-store/sync-project-store.ts
480
- function syncProjectStore(targetPath, selectedSkillIds, selectedAgents) {
525
+ function syncProjectStore(targetPath, selectedSkillIds, _selectedAgents) {
481
526
  const bundledSkillsDir = resolveSkillsSourceRoot();
482
527
  const projectSkillsDir = getProjectSkillsDir(targetPath);
483
- const projectCursorRulesDir = getProjectCursorRulesDir(targetPath);
484
- if (!existsSync8(projectSkillsDir)) {
485
- mkdirSync5(projectSkillsDir, { recursive: true });
528
+ if (!existsSync5(projectSkillsDir)) {
529
+ mkdirSync2(projectSkillsDir, { recursive: true });
486
530
  }
487
- const needsCursorRules = selectedAgents.includes("cursor");
488
- if (needsCursorRules && !existsSync8(projectCursorRulesDir)) {
489
- mkdirSync5(projectCursorRulesDir, { recursive: true });
531
+ const legacyCursorRules = join7(targetPath, ".grooveskills", "cursor-rules");
532
+ if (existsSync5(legacyCursorRules)) {
533
+ try {
534
+ rmSync2(legacyCursorRules, { recursive: true, force: true });
535
+ } catch {
536
+ }
490
537
  }
491
538
  for (const skillId of selectedSkillIds) {
492
539
  const skill = SKILL_CATALOG.find((item) => item.id === skillId);
493
540
  if (!skill) {
494
541
  continue;
495
542
  }
496
- const sourceSkillDir = join10(bundledSkillsDir, skill.directoryName);
497
- const destSkillDir = join10(projectSkillsDir, skill.directoryName);
498
- if (existsSync8(sourceSkillDir)) {
543
+ const sourceSkillDir = join7(bundledSkillsDir, skill.directoryName);
544
+ const destSkillDir = join7(projectSkillsDir, skill.directoryName);
545
+ if (existsSync5(sourceSkillDir)) {
499
546
  cpSync(sourceSkillDir, destSkillDir, { recursive: true });
500
547
  }
501
- if (!needsCursorRules) {
502
- continue;
503
- }
504
- const skillMdPath = join10(destSkillDir, "SKILL.md");
505
- if (!existsSync8(skillMdPath)) {
506
- continue;
507
- }
508
- const content = readFileSync2(skillMdPath, "utf-8");
509
- const mdcHeader = `---
510
- description: ${skill.description}
511
- globs: ["**/*"]
512
- alwaysApply: false
513
- ---
514
-
515
- `;
516
- const cleanedBody = content.replace(/^---[\s\S]*?---\s*/, "");
517
- const targetMdc = join10(projectCursorRulesDir, `${skill.id}.mdc`);
518
- writeFileSync(targetMdc, `${mdcHeader}${cleanedBody}`, "utf-8");
519
548
  }
520
549
  }
521
550
 
522
551
  // src/domains/harness/install-harness.ts
523
- import { existsSync as existsSync10, mkdirSync as mkdirSync6, writeFileSync as writeFileSync3 } from "fs";
524
- import { join as join12 } from "path";
552
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
553
+ import { join as join10 } from "path";
525
554
 
526
555
  // src/domains/harness/harness-languages.ts
527
556
  var SUPPORTED_LANGUAGES = {
@@ -558,29 +587,59 @@ var SUPPORTED_LANGUAGES = {
558
587
  };
559
588
 
560
589
  // src/domains/harness/harness-templates.ts
561
- function buildContextTemplate(detectedDependencies, language = "es") {
590
+ function buildContextTemplate(detectedDependencies, language = "es", profile) {
562
591
  const depsFormatted = detectedDependencies.length > 0 ? detectedDependencies.map((d) => `- \`${d}\``).join("\n") : "- (No external dependencies detected)";
563
592
  const langConfig = SUPPORTED_LANGUAGES[language];
564
- return `# Project Context & Architecture
593
+ const projectName = profile?.projectName ?? "Project";
594
+ const pkgManager = profile?.packageManager ?? "npm";
595
+ const commandLines = [];
596
+ if (profile?.commands) {
597
+ for (const [key, cmd] of Object.entries(profile.commands)) {
598
+ commandLines.push(`- **${key}**: \`${cmd}\``);
599
+ }
600
+ }
601
+ const commandsSection = commandLines.length > 0 ? commandLines.join("\n") : `- Build: Refer to \`package.json\` scripts.
602
+ - Typecheck: Refer to TypeScript configuration.
603
+ - Tests: Refer to test runner configuration.`;
604
+ const aliasLines = [];
605
+ if (profile?.pathAliases) {
606
+ for (const [alias, target] of Object.entries(profile.pathAliases)) {
607
+ aliasLines.push(`- \`${alias}\` -> \`${target}\``);
608
+ }
609
+ }
610
+ const aliasesSection = aliasLines.length > 0 ? `
611
+ ### Path Aliases
612
+ ${aliasLines.join("\n")}
613
+ ` : "";
614
+ const dirLines = [];
615
+ if (profile?.sourceDirectories && profile.sourceDirectories.length > 0) {
616
+ for (const dir of profile.sourceDirectories) {
617
+ dirLines.push(`- \`${dir}/\``);
618
+ }
619
+ }
620
+ const dirsSection = dirLines.length > 0 ? `
621
+ ### Source Modules
622
+ ${dirLines.join("\n")}
623
+ ` : "";
624
+ return `# Project Context & Architecture: ${projectName}
565
625
 
566
626
  This file provides AI agents with instant architectural orientation for this project.
567
627
 
568
628
  ## 1. Stack & Dependencies
629
+ - **Package Manager**: \`${pkgManager}\`
569
630
  ${depsFormatted}
570
631
 
571
632
  ## 2. Directory Structure Conventions
572
633
  - Follow single-responsibility per file (<200 lines).
573
634
  - Maintain direct imports with path aliases; avoid barrel files.
574
635
  - Keep domain boundaries explicit and clean.
575
-
636
+ ${aliasesSection}${dirsSection}
576
637
  ## 3. Communication & User Copy Language
577
638
  - **Configured Language**: ${langConfig.nativeName} (\`${language}\`).
578
639
  - **Policy**: ${langConfig.instruction}
579
640
 
580
641
  ## 4. Essential Commands
581
- - Build: Refer to \`package.json\` scripts.
582
- - Typecheck: Refer to TypeScript configuration.
583
- - Tests: Refer to test runner configuration.
642
+ ${commandsSection}
584
643
  `;
585
644
  }
586
645
  function buildDecisionsTemplate(language = "es") {
@@ -595,6 +654,35 @@ An append-only log of significant technical and architectural choices.
595
654
  | ${now} | Adopt GrooveSkills Harness | Initialized \`.grooveskills/\` control plane with ODD | Clean, encapsulated agent memory, 3-lane ODD flow, and ${langConfig.nativeName} copy standard |
596
655
  `;
597
656
  }
657
+ function buildOnboardingTaskTemplate(projectName = "Project") {
658
+ const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
659
+ return `---
660
+ status: pending
661
+ createdAt: ${now}
662
+ ---
663
+
664
+ # 00 \u2014 Initial Project Onboarding & Architecture Exploration: ${projectName}
665
+
666
+ ## Outcome Hypothesis
667
+ By scanning dependencies, entry points, configuration manifests, and module layout, the AI agent will gain a verified architectural understanding of \`${projectName}\`, proven by filling out \`.grooveskills/memory/context.md\` and validating the essential build/typecheck commands.
668
+
669
+ ## Scope
670
+ - In scope: Inspect project manifests, entry points, directory conventions, and script execution.
671
+ - Out of scope: Refactoring business logic or modifying functional code.
672
+
673
+ ## Checklist
674
+ - [ ] Verify package manager and essential scripts (\`build\`, \`test\`, \`typecheck\`).
675
+ - [ ] Map high-level module architecture and data flow in \`.grooveskills/memory/context.md\`.
676
+ - [ ] Verify test runner or static checks pass cleanly.
677
+ - [ ] Switch status to \`completed\` once project context is fully verified.
678
+
679
+ ## Evidence
680
+ - Observed command runs and outputs during the initial onboarding pass.
681
+
682
+ ## Next
683
+ - Once onboarding is marked completed, proceed with domain tasks following the 3-lane ODD protocol.
684
+ `;
685
+ }
598
686
  function buildTaskTemplate() {
599
687
  return `---
600
688
  status: in-progress
@@ -630,6 +718,7 @@ function buildAgentHarnessBlock(language = "es") {
630
718
  This project uses the **GrooveSkills Harness** located in \`.grooveskills/\`.
631
719
 
632
720
  ## 1. Three-Lane ODD Protocol
721
+ - **Onboarding Check**: If \`.grooveskills/memory/tasks/00-onboarding.md\` has \`status: pending\`, complete its checklist to enrich \`context.md\` and set its status to \`completed\`.
633
722
  - **Authorize & Explore**: Follow the 7-step ODD protocol (Authorize, Explore, Resolve, Classify, Track & Hypothesize, Execute, Verify).
634
723
  - **Lane 1 (Answer)**: Explanations, audits, or questions. Read-only; write zero code.
635
724
  - **Lane 2 (Task)**: Direct implementation. Declare Outcome Hypothesis and checklist in \`.grooveskills/memory/tasks/<slug>.md\`. Only check off tasks with observed evidence under \`Evidence\`.
@@ -646,19 +735,162 @@ This project uses the **GrooveSkills Harness** located in \`.grooveskills/\`.
646
735
  <!-- grooveskills:harness:end -->`;
647
736
  }
648
737
 
738
+ // src/domains/harness/scan-project-onboarding.ts
739
+ import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
740
+ import { basename, join as join8 } from "path";
741
+ function detectProjectName(targetPath) {
742
+ const packageJsonPath = join8(targetPath, "package.json");
743
+ if (existsSync6(packageJsonPath)) {
744
+ try {
745
+ const raw = readFileSync4(packageJsonPath, "utf-8");
746
+ const parsed = JSON.parse(raw);
747
+ if (typeof parsed.name === "string" && parsed.name.trim().length > 0) {
748
+ return parsed.name.trim();
749
+ }
750
+ } catch {
751
+ }
752
+ }
753
+ const cargoPath = join8(targetPath, "Cargo.toml");
754
+ if (existsSync6(cargoPath)) {
755
+ try {
756
+ const cargoRaw = readFileSync4(cargoPath, "utf-8");
757
+ const nameMatch = cargoRaw.match(/name\s*=\s*"([^"]+)"/);
758
+ if (nameMatch?.[1]) {
759
+ return nameMatch[1];
760
+ }
761
+ } catch {
762
+ }
763
+ }
764
+ const pyprojectPath = join8(targetPath, "pyproject.toml");
765
+ if (existsSync6(pyprojectPath)) {
766
+ try {
767
+ const pyRaw = readFileSync4(pyprojectPath, "utf-8");
768
+ const pyMatch = pyRaw.match(/name\s*=\s*"([^"]+)"/);
769
+ if (pyMatch?.[1]) {
770
+ return pyMatch[1];
771
+ }
772
+ } catch {
773
+ }
774
+ }
775
+ return basename(targetPath) || "project";
776
+ }
777
+ function detectPackageManager(targetPath) {
778
+ if (existsSync6(join8(targetPath, "pnpm-lock.yaml"))) {
779
+ return "pnpm";
780
+ }
781
+ if (existsSync6(join8(targetPath, "bun.lockb")) || existsSync6(join8(targetPath, "bun.lock"))) {
782
+ return "bun";
783
+ }
784
+ if (existsSync6(join8(targetPath, "yarn.lock"))) {
785
+ return "yarn";
786
+ }
787
+ if (existsSync6(join8(targetPath, "package-lock.json"))) {
788
+ return "npm";
789
+ }
790
+ if (existsSync6(join8(targetPath, "Cargo.lock")) || existsSync6(join8(targetPath, "Cargo.toml"))) {
791
+ return "cargo";
792
+ }
793
+ if (existsSync6(join8(targetPath, "uv.lock"))) {
794
+ return "uv";
795
+ }
796
+ if (existsSync6(join8(targetPath, "poetry.lock"))) {
797
+ return "poetry";
798
+ }
799
+ return "npm";
800
+ }
801
+ function detectCommands(targetPath, pkgManager) {
802
+ const packageJsonPath = join8(targetPath, "package.json");
803
+ if (!existsSync6(packageJsonPath)) {
804
+ return {};
805
+ }
806
+ try {
807
+ const raw = readFileSync4(packageJsonPath, "utf-8");
808
+ const parsed = JSON.parse(raw);
809
+ const scripts = parsed.scripts ?? {};
810
+ const commands = {};
811
+ const runner = pkgManager === "npm" ? "npm run" : pkgManager;
812
+ if (scripts.build) {
813
+ commands.build = `${runner} build`;
814
+ }
815
+ if (scripts["check-types"]) {
816
+ commands.typecheck = `${runner} check-types`;
817
+ } else if (scripts.typecheck) {
818
+ commands.typecheck = `${runner} typecheck`;
819
+ } else if (scripts.tsc) {
820
+ commands.typecheck = `${runner} tsc`;
821
+ }
822
+ if (scripts.test) {
823
+ commands.test = `${runner} test`;
824
+ }
825
+ if (scripts.lint) {
826
+ commands.lint = `${runner} lint`;
827
+ }
828
+ if (scripts.dev) {
829
+ commands.dev = `${runner} dev`;
830
+ }
831
+ return commands;
832
+ } catch {
833
+ return {};
834
+ }
835
+ }
836
+ function detectPathAliases(targetPath) {
837
+ const tsconfigPath = join8(targetPath, "tsconfig.json");
838
+ if (!existsSync6(tsconfigPath)) {
839
+ return {};
840
+ }
841
+ try {
842
+ const raw = readFileSync4(tsconfigPath, "utf-8");
843
+ const parsed = JSON.parse(raw);
844
+ const paths = parsed.compilerOptions?.paths ?? {};
845
+ const aliases = {};
846
+ for (const [key, targets] of Object.entries(paths)) {
847
+ if (Array.isArray(targets) && typeof targets[0] === "string") {
848
+ aliases[key] = targets[0];
849
+ }
850
+ }
851
+ return aliases;
852
+ } catch {
853
+ return {};
854
+ }
855
+ }
856
+ function detectSourceDirectories(targetPath) {
857
+ const srcPath = join8(targetPath, "src");
858
+ const scanTarget = existsSync6(srcPath) ? srcPath : targetPath;
859
+ try {
860
+ const entries = readdirSync2(scanTarget, { withFileTypes: true });
861
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => !name.startsWith(".") && name !== "node_modules" && name !== "dist");
862
+ } catch {
863
+ return [];
864
+ }
865
+ }
866
+ function scanProjectOnboarding(targetPath) {
867
+ const projectName = detectProjectName(targetPath);
868
+ const packageManager = detectPackageManager(targetPath);
869
+ const commands = detectCommands(targetPath, packageManager);
870
+ const pathAliases = detectPathAliases(targetPath);
871
+ const sourceDirectories = detectSourceDirectories(targetPath);
872
+ return {
873
+ projectName,
874
+ packageManager,
875
+ commands,
876
+ pathAliases,
877
+ sourceDirectories
878
+ };
879
+ }
880
+
649
881
  // src/domains/harness/upsert-agent-instructions.ts
650
- import { existsSync as existsSync9, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
651
- import { join as join11 } from "path";
882
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
883
+ import { join as join9 } from "path";
652
884
  var START_MARKER = "<!-- grooveskills:harness:start -->";
653
885
  var END_MARKER = "<!-- grooveskills:harness:end -->";
654
886
  function applyHarnessBlock(filePath, language = "es") {
655
887
  const block = buildAgentHarnessBlock(language);
656
- if (!existsSync9(filePath)) {
888
+ if (!existsSync7(filePath)) {
657
889
  writeFileSync2(filePath, `${block}
658
890
  `, "utf-8");
659
891
  return;
660
892
  }
661
- const existingContent = readFileSync3(filePath, "utf-8");
893
+ const existingContent = readFileSync5(filePath, "utf-8");
662
894
  if (existingContent.includes(START_MARKER) && existingContent.includes(END_MARKER)) {
663
895
  const regex = new RegExp(`${START_MARKER}[\\s\\S]*?${END_MARKER}`, "g");
664
896
  const updated = existingContent.replace(regex, block);
@@ -671,11 +903,11 @@ function applyHarnessBlock(filePath, language = "es") {
671
903
  }
672
904
  function upsertAgentInstructions(targetPath, selectedAgents, language = "es") {
673
905
  const updatedFiles = [];
674
- const agentsMdPath = join11(targetPath, "AGENTS.md");
906
+ const agentsMdPath = join9(targetPath, "AGENTS.md");
675
907
  applyHarnessBlock(agentsMdPath, language);
676
908
  updatedFiles.push(agentsMdPath);
677
909
  if (selectedAgents.includes("claude")) {
678
- const claudeMdPath = join11(targetPath, "CLAUDE.md");
910
+ const claudeMdPath = join9(targetPath, "CLAUDE.md");
679
911
  applyHarnessBlock(claudeMdPath, language);
680
912
  updatedFiles.push(claudeMdPath);
681
913
  }
@@ -687,43 +919,62 @@ function installHarness(options) {
687
919
  const memoryDir = getProjectMemoryDir(options.targetPath);
688
920
  const tasksDir = getProjectTasksDir(options.targetPath);
689
921
  const language = options.language ?? "es";
690
- if (!existsSync10(tasksDir)) {
691
- mkdirSync6(tasksDir, { recursive: true });
922
+ const forceOnboarding = Boolean(options.forceOnboarding);
923
+ if (!existsSync8(tasksDir)) {
924
+ mkdirSync3(tasksDir, { recursive: true });
692
925
  }
693
926
  const createdFiles = [];
694
- const contextPath = join12(memoryDir, "context.md");
695
- if (!existsSync10(contextPath)) {
696
- writeFileSync3(contextPath, buildContextTemplate(options.detectedDependencies, language), "utf-8");
927
+ const contextPath = join10(memoryDir, "context.md");
928
+ const shouldWriteContext = !existsSync8(contextPath) || forceOnboarding;
929
+ if (shouldWriteContext) {
930
+ const profile = scanProjectOnboarding(options.targetPath);
931
+ const contextContent = buildContextTemplate(
932
+ options.detectedDependencies,
933
+ language,
934
+ profile
935
+ );
936
+ writeFileSync3(contextPath, contextContent, "utf-8");
697
937
  createdFiles.push(contextPath);
938
+ const onboardingTaskPath = join10(tasksDir, "00-onboarding.md");
939
+ writeFileSync3(
940
+ onboardingTaskPath,
941
+ buildOnboardingTaskTemplate(profile.projectName),
942
+ "utf-8"
943
+ );
944
+ createdFiles.push(onboardingTaskPath);
698
945
  }
699
- const decisionsPath = join12(memoryDir, "decisions.md");
700
- if (!existsSync10(decisionsPath)) {
946
+ const decisionsPath = join10(memoryDir, "decisions.md");
947
+ if (!existsSync8(decisionsPath)) {
701
948
  writeFileSync3(decisionsPath, buildDecisionsTemplate(language), "utf-8");
702
949
  createdFiles.push(decisionsPath);
703
950
  }
704
- const templateTaskPath = join12(tasksDir, "_template.md");
705
- if (!existsSync10(templateTaskPath)) {
951
+ const templateTaskPath = join10(tasksDir, "_template.md");
952
+ if (!existsSync8(templateTaskPath)) {
706
953
  writeFileSync3(templateTaskPath, buildTaskTemplate(), "utf-8");
707
954
  createdFiles.push(templateTaskPath);
708
955
  }
709
- const instructions = upsertAgentInstructions(options.targetPath, options.selectedAgents, language);
956
+ const instructions = upsertAgentInstructions(
957
+ options.targetPath,
958
+ options.selectedAgents,
959
+ language
960
+ );
710
961
  createdFiles.push(...instructions);
711
962
  return createdFiles;
712
963
  }
713
964
 
714
965
  // src/domains/harness/write-project-config.ts
715
- import { existsSync as existsSync11, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
966
+ import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
716
967
  function readExistingConfig(configPath) {
717
968
  const fallback = {
718
969
  skills: [],
719
970
  agents: [],
720
971
  harness: false
721
972
  };
722
- if (!existsSync11(configPath)) {
973
+ if (!existsSync9(configPath)) {
723
974
  return fallback;
724
975
  }
725
976
  try {
726
- const raw = readFileSync4(configPath, "utf-8");
977
+ const raw = readFileSync6(configPath, "utf-8");
727
978
  const parsed = JSON.parse(raw);
728
979
  return {
729
980
  skills: Array.isArray(parsed.skills) ? parsed.skills : [],
@@ -764,10 +1015,10 @@ var ADAPTER_REGISTRY = {
764
1015
  };
765
1016
  async function installSkills(options) {
766
1017
  const skillsToInstall = [...options.selectedSkillIds];
767
- if (options.enableHarness && !skillsToInstall.includes("groove-harness")) {
1018
+ if (!skillsToInstall.includes("groove-harness")) {
768
1019
  skillsToInstall.push("groove-harness");
769
1020
  }
770
- if (options.enableHarness && !skillsToInstall.includes("odd-ai")) {
1021
+ if (!skillsToInstall.includes("odd-ai")) {
771
1022
  skillsToInstall.push("odd-ai");
772
1023
  }
773
1024
  syncProjectStore(options.targetPath, skillsToInstall, options.selectedAgents);
@@ -778,7 +1029,7 @@ async function installSkills(options) {
778
1029
  if (!skill) {
779
1030
  continue;
780
1031
  }
781
- const skillSourceDir = join13(projectSkillsDir, skill.directoryName);
1032
+ const skillSourceDir = join11(projectSkillsDir, skill.directoryName);
782
1033
  for (const agentId of options.selectedAgents) {
783
1034
  const adapter = ADAPTER_REGISTRY[agentId];
784
1035
  if (!adapter) {
@@ -788,23 +1039,20 @@ async function installSkills(options) {
788
1039
  createdFiles.push(...files);
789
1040
  }
790
1041
  }
791
- let harnessInitialized = false;
792
- if (options.enableHarness) {
793
- const harnessFiles = installHarness({
794
- targetPath: options.targetPath,
795
- selectedAgents: options.selectedAgents,
796
- selectedSkillIds: skillsToInstall,
797
- detectedDependencies: options.detectedDependencies || [],
798
- language: options.language
799
- });
800
- createdFiles.push(...harnessFiles);
801
- harnessInitialized = true;
802
- }
1042
+ const harnessFiles = installHarness({
1043
+ targetPath: options.targetPath,
1044
+ selectedAgents: options.selectedAgents,
1045
+ selectedSkillIds: skillsToInstall,
1046
+ detectedDependencies: options.detectedDependencies || [],
1047
+ language: options.language,
1048
+ forceOnboarding: options.forceOnboarding
1049
+ });
1050
+ createdFiles.push(...harnessFiles);
803
1051
  const configPath = writeProjectConfig(
804
1052
  options.targetPath,
805
1053
  skillsToInstall,
806
1054
  options.selectedAgents,
807
- Boolean(options.enableHarness),
1055
+ true,
808
1056
  options.language
809
1057
  );
810
1058
  createdFiles.push(configPath);
@@ -812,19 +1060,19 @@ async function installSkills(options) {
812
1060
  installedSkills: skillsToInstall,
813
1061
  configuredAgents: options.selectedAgents,
814
1062
  createdFiles,
815
- harnessInitialized,
1063
+ harnessInitialized: true,
816
1064
  language: options.language
817
1065
  };
818
1066
  }
819
1067
 
820
1068
  // src/domains/ui/ui-orchestrator.ts
821
- async function resolveLanguageSelection(harnessEnabled) {
822
- if (!harnessEnabled) {
823
- return "es";
1069
+ async function resolveLanguageSelection(harnessExists, configuredLanguage, forceOnboarding) {
1070
+ if (harnessExists && !forceOnboarding) {
1071
+ return configuredLanguage ?? "es";
824
1072
  }
825
- const langChoice = await promptLanguage("es");
826
- if (p6.isCancel(langChoice)) {
827
- p6.cancel("Installation cancelled. Have a wonderful day!");
1073
+ const langChoice = await promptLanguage(configuredLanguage ?? "es");
1074
+ if (p5.isCancel(langChoice)) {
1075
+ p5.cancel("Installation cancelled. Have a wonderful day!");
828
1076
  process.exit(0);
829
1077
  }
830
1078
  return langChoice;
@@ -837,65 +1085,66 @@ async function resolveOverwriteConfirmation(targetPath, selectedSkills, selected
837
1085
  if (!anyExists) {
838
1086
  return true;
839
1087
  }
840
- const confirm3 = await promptConfirmOverwrite();
841
- if (p6.isCancel(confirm3) || !confirm3) {
842
- p6.cancel("Installation stopped to protect existing skills.");
1088
+ const confirm2 = await promptConfirmOverwrite();
1089
+ if (p5.isCancel(confirm2) || !confirm2) {
1090
+ p5.cancel("Installation stopped to protect existing skills.");
843
1091
  process.exit(0);
844
1092
  }
845
- return Boolean(confirm3);
1093
+ return Boolean(confirm2);
846
1094
  }
847
- async function runInteractiveUi(context) {
1095
+ async function runInteractiveUi(context, forceOnboarding = false) {
848
1096
  console.log(renderBanner());
849
- p6.intro(pc2.magenta("Welcome to GrooveSkills! Let's tailor your AI agents with clean architectural standards."));
1097
+ p5.intro(pc2.magenta("Welcome to GrooveSkills! Let's tailor your AI agents with clean architectural standards."));
850
1098
  if (context.detectedDependencies.length > 0) {
851
- p6.note(
1099
+ const harnessInfo = context.harnessExists && !forceOnboarding ? pc2.green(`Active (.grooveskills/memory, lang: ${context.configuredLanguage ?? "es"})`) : pc2.cyan("Will be initialized");
1100
+ p5.note(
852
1101
  `Detected dependencies: ${context.detectedDependencies.map((d) => pc2.bold(d)).join(", ")}
853
- Active AI folders: ${context.detectedAgents.map((a) => pc2.green(a)).join(", ") || "None (will be created)"}`,
1102
+ Active AI folders: ${context.detectedAgents.map((a) => pc2.green(a)).join(", ") || "None (will be created)"}
1103
+ GrooveSkills Harness: ${harnessInfo}`,
854
1104
  "Project Environment"
855
1105
  );
856
1106
  }
857
1107
  const selectedSkills = await promptSkills(context.suggestedSkillIds);
858
- if (p6.isCancel(selectedSkills)) {
859
- p6.cancel("Installation cancelled. Have a wonderful day!");
1108
+ if (p5.isCancel(selectedSkills)) {
1109
+ p5.cancel("Installation cancelled. Have a wonderful day!");
860
1110
  process.exit(0);
861
1111
  }
862
1112
  const selectedAgents = await promptAgents(context.detectedAgents);
863
- if (p6.isCancel(selectedAgents)) {
864
- p6.cancel("Installation cancelled. Have a wonderful day!");
865
- process.exit(0);
866
- }
867
- const harnessChoice = await promptHarness(context.harnessExists);
868
- if (p6.isCancel(harnessChoice)) {
869
- p6.cancel("Installation cancelled. Have a wonderful day!");
1113
+ if (p5.isCancel(selectedAgents)) {
1114
+ p5.cancel("Installation cancelled. Have a wonderful day!");
870
1115
  process.exit(0);
871
1116
  }
872
- const harnessEnabled = Boolean(harnessChoice);
873
- const selectedLanguage = await resolveLanguageSelection(harnessEnabled);
1117
+ const selectedLanguage = await resolveLanguageSelection(
1118
+ context.harnessExists,
1119
+ context.configuredLanguage,
1120
+ forceOnboarding
1121
+ );
874
1122
  const forceOverwrite = await resolveOverwriteConfirmation(
875
1123
  context.targetPath,
876
1124
  selectedSkills,
877
1125
  selectedAgents
878
1126
  );
879
- const s = p6.spinner();
1127
+ const s = p5.spinner();
880
1128
  s.start("Installing and adapting skills across your configured AI agents...");
881
1129
  const result = await installSkills({
882
1130
  targetPath: context.targetPath,
883
1131
  selectedSkillIds: selectedSkills,
884
1132
  selectedAgents,
885
1133
  forceOverwrite,
886
- enableHarness: harnessEnabled,
1134
+ enableHarness: true,
887
1135
  detectedDependencies: context.detectedDependencies,
888
- language: selectedLanguage
1136
+ language: selectedLanguage,
1137
+ forceOnboarding
889
1138
  });
890
1139
  s.stop(pc2.green("All skills and harness have been successfully configured!"));
891
- const harnessStatus = result.harnessInitialized ? pc2.green(`Initialized in .grooveskills/ (Language: ${selectedLanguage})`) : pc2.dim("Skipped");
892
- p6.note(
1140
+ const harnessStatus = result.harnessInitialized ? pc2.green(`Initialized in .grooveskills/ (Language: ${selectedLanguage})`) : pc2.cyan(`Preserved in .grooveskills/ (Language: ${selectedLanguage})`);
1141
+ p5.note(
893
1142
  `Configured skills: ${result.installedSkills.map((s2) => pc2.bold(s2)).join(", ")}
894
1143
  Target agents: ${result.configuredAgents.map((a) => pc2.cyan(a)).join(", ")}
895
1144
  GrooveSkills Harness: ${harnessStatus}`,
896
1145
  "Installation Summary"
897
1146
  );
898
- p6.outro(pc2.green("Your AI programming pair is now empowered with your team's architectural habits! \u{1F680}"));
1147
+ p5.outro(pc2.green("Your AI programming pair is now empowered with your team's architectural habits! \u{1F680}"));
899
1148
  }
900
1149
 
901
1150
  // src/main.ts
@@ -905,22 +1154,25 @@ async function runGrooveSkills(options = {}) {
905
1154
  const hasSkills = options.skills && options.skills.length > 0;
906
1155
  const hasAgents = options.agents && options.agents.length > 0;
907
1156
  const isDirectHarness = Boolean(options.harness) && hasAgents;
908
- if (hasSkills && hasAgents || isDirectHarness) {
1157
+ const isDirectInit = Boolean(options.forceOnboarding) && hasAgents;
1158
+ if (hasSkills && hasAgents || isDirectHarness || isDirectInit) {
1159
+ const language = options.language ?? context.configuredLanguage ?? "es";
909
1160
  await installSkills({
910
1161
  targetPath,
911
1162
  selectedSkillIds: options.skills || [],
912
1163
  selectedAgents: options.agents || [],
913
1164
  forceOverwrite: Boolean(options.yes),
914
- enableHarness: options.harness,
1165
+ enableHarness: true,
915
1166
  detectedDependencies: context.detectedDependencies,
916
- language: options.language
1167
+ language,
1168
+ forceOnboarding: options.forceOnboarding
917
1169
  });
918
1170
  return;
919
1171
  }
920
- await runInteractiveUi(context);
1172
+ await runInteractiveUi(context, Boolean(options.forceOnboarding));
921
1173
  }
922
1174
 
923
1175
  export {
924
1176
  runGrooveSkills
925
1177
  };
926
- //# sourceMappingURL=chunk-M7ZPBGQE.js.map
1178
+ //# sourceMappingURL=chunk-PLMYUKGW.js.map