@open-product-primer/cli 2.9.0 → 2.10.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.
@@ -48,7 +48,7 @@ function initCommand() {
48
48
  return new commander_1.Command('init')
49
49
  .description('Initialize oprim in the current repository')
50
50
  .option('--name <name>', 'project name (defaults to directory name)')
51
- .option('--agent <name>', 'AI agent to install skills for (repeatable; supported: claude, cursor, codex, gemini, poolside, vibe, qwen, kimi)', (val, prev) => [...prev, val], [])
51
+ .option('--agent <name>', 'AI agent to install skills for (repeatable; supported: claude, cursor, codex, gemini, poolside, vibe, qwen, kimi, dsh)', (val, prev) => [...prev, val], [])
52
52
  .action(async (opts) => {
53
53
  const projectRoot = process.cwd();
54
54
  const projectName = opts.name ?? path.basename(projectRoot);
@@ -90,6 +90,8 @@ function detectAvailableAgents(projectRoot) {
90
90
  detected.push('qwen');
91
91
  if (fs.existsSync(path.join(projectRoot, '.kimi')))
92
92
  detected.push('kimi');
93
+ if (fs.existsSync(path.join(projectRoot, '.dsh')))
94
+ detected.push('dsh');
93
95
  return detected;
94
96
  }
95
97
  function writeAgentsToConfig(agents, projectRoot) {
@@ -1,4 +1,4 @@
1
- export type Agent = 'claude' | 'cursor' | 'codex' | 'gemini' | 'poolside' | 'vibe' | 'qwen' | 'kimi';
1
+ export type Agent = 'claude' | 'cursor' | 'codex' | 'gemini' | 'poolside' | 'vibe' | 'qwen' | 'kimi' | 'dsh';
2
2
  export declare const SUPPORTED_AGENTS: readonly Agent[];
3
3
  export declare function promptFrameworkSelection(projectRoot: string): Promise<string>;
4
4
  export declare function resolveSpecFramework(projectRoot: string): string;
@@ -13,6 +13,7 @@ export declare const POOLSIDE_SKILLS: Record<string, string>;
13
13
  export declare const VIBE_SKILLS: Record<string, string>;
14
14
  export declare const QWEN_SKILLS: Record<string, string>;
15
15
  export declare const KIMI_SKILLS: Record<string, string>;
16
+ export declare const DSH_SKILLS: Record<string, string>;
16
17
  export declare const CURSOR_SKILLS: Record<string, string>;
17
18
  export declare const CURSOR_COMMANDS: Record<string, string>;
18
19
  export declare function specAuthoringSkill(): string;
@@ -23,3 +24,4 @@ export declare function poolsideInstructions(): string;
23
24
  export declare function vibeInstructions(): string;
24
25
  export declare function qwenInstructions(): string;
25
26
  export declare function kimiInstructions(): string;
27
+ export declare function dshInstructions(): string;
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.CURSOR_COMMANDS = exports.CURSOR_SKILLS = exports.KIMI_SKILLS = exports.QWEN_SKILLS = exports.VIBE_SKILLS = exports.POOLSIDE_SKILLS = exports.CLAUDE_COMMANDS = exports.CLAUDE_SKILLS = exports.OPRIM_CONTEXT_SKILL_STEP = exports.SUPPORTED_AGENTS = void 0;
39
+ exports.CURSOR_COMMANDS = exports.CURSOR_SKILLS = exports.DSH_SKILLS = exports.KIMI_SKILLS = exports.QWEN_SKILLS = exports.VIBE_SKILLS = exports.POOLSIDE_SKILLS = exports.CLAUDE_COMMANDS = exports.CLAUDE_SKILLS = exports.OPRIM_CONTEXT_SKILL_STEP = exports.SUPPORTED_AGENTS = void 0;
40
40
  exports.promptFrameworkSelection = promptFrameworkSelection;
41
41
  exports.resolveSpecFramework = resolveSpecFramework;
42
42
  exports.promptAgentSelection = promptAgentSelection;
@@ -51,6 +51,7 @@ exports.poolsideInstructions = poolsideInstructions;
51
51
  exports.vibeInstructions = vibeInstructions;
52
52
  exports.qwenInstructions = qwenInstructions;
53
53
  exports.kimiInstructions = kimiInstructions;
54
+ exports.dshInstructions = dshInstructions;
54
55
  const path = __importStar(require("path"));
55
56
  const fs = __importStar(require("fs"));
56
57
  const chalk_1 = __importDefault(require("chalk"));
@@ -68,6 +69,7 @@ exports.SUPPORTED_AGENTS = [
68
69
  'vibe',
69
70
  'qwen',
70
71
  'kimi',
72
+ 'dsh',
71
73
  ];
72
74
  // oprim/config.yaml (via integrations.spec_framework) is the source of truth for the
73
75
  // selected speccing framework; .claude/hooks/config.json is checked only as a fallback for
@@ -139,6 +141,7 @@ async function promptAgentSelection(projectRoot) {
139
141
  { name: 'Mistral Vibe', value: 'vibe', checked: detected.includes('vibe') },
140
142
  { name: 'Qwen Code', value: 'qwen', checked: detected.includes('qwen') },
141
143
  { name: 'Kimi CLI', value: 'kimi', checked: detected.includes('kimi') },
144
+ { name: 'DeepSeek Harness', value: 'dsh', checked: detected.includes('dsh') },
142
145
  ],
143
146
  });
144
147
  }
@@ -360,6 +363,37 @@ function installAgentSkills(agent, projectRoot, framework = 'openspec', pdrSurfa
360
363
  console.log(chalk_1.default.dim(' .qwen/ created — Qwen Code will discover these files automatically.'));
361
364
  }
362
365
  }
366
+ else if (agent === 'dsh') {
367
+ const dshDir = path.join(projectRoot, '.dsh');
368
+ const dirCreated = !fs.existsSync(dshDir);
369
+ const skillsBase = path.join(dshDir, 'skills');
370
+ for (const id of POOLSIDE_SKILL_WORKFLOW_IDS) {
371
+ const schema = (0, workflow_schema_1.loadWorkflowSchema)(id, projectRoot);
372
+ if (!schema.dsh.skill || !schema.skillName)
373
+ continue;
374
+ (0, scaffold_1.writeFile)(path.join(skillsBase, schema.skillName, 'SKILL.md'), (0, workflow_renderer_1.renderSkillBody)(id, projectRoot));
375
+ console.log(chalk_1.default.green('✓') + ` .dsh/skills/${schema.skillName}/SKILL.md`);
376
+ }
377
+ const dshSpecSkillPath = path.join(skillsBase, 'oprim-spec', 'SKILL.md');
378
+ if (framework === 'native') {
379
+ (0, scaffold_1.writeFile)(dshSpecSkillPath, (0, workflow_renderer_1.renderSkillBody)('spec-authoring', projectRoot));
380
+ console.log(chalk_1.default.green('✓') + ' .dsh/skills/oprim-spec/SKILL.md');
381
+ }
382
+ else if (fs.existsSync(dshSpecSkillPath)) {
383
+ fs.unlinkSync(dshSpecSkillPath);
384
+ try {
385
+ fs.rmdirSync(path.dirname(dshSpecSkillPath));
386
+ }
387
+ catch { /* not empty or already gone */ }
388
+ console.log(chalk_1.default.dim(' removed .dsh/skills/oprim-spec/SKILL.md'));
389
+ }
390
+ const agentsFile = path.join(projectRoot, 'AGENTS.md');
391
+ writeAgentInstructionFile(agentsFile, dshInstructions());
392
+ console.log(chalk_1.default.green('✓') + ' AGENTS.md (oprim section written)');
393
+ if (dirCreated) {
394
+ console.log(chalk_1.default.dim(' .dsh/ created — DeepSeek Harness will discover these files automatically.'));
395
+ }
396
+ }
363
397
  else if (agent === 'kimi') {
364
398
  // Kimi CLI is a split-path install: .kimi/ is the detection signal, but skills are
365
399
  // discovered from a project-root .skills/ directory, not .kimi/skills/ — see
@@ -573,6 +607,10 @@ exports.KIMI_SKILLS = Object.fromEntries(POOLSIDE_SKILL_WORKFLOW_IDS.map((id) =>
573
607
  const schema = (0, workflow_schema_1.loadWorkflowSchema)(id);
574
608
  return [schema.skillName, (0, workflow_renderer_1.renderSkillBody)(id)];
575
609
  }));
610
+ exports.DSH_SKILLS = Object.fromEntries(POOLSIDE_SKILL_WORKFLOW_IDS.map((id) => {
611
+ const schema = (0, workflow_schema_1.loadWorkflowSchema)(id);
612
+ return [schema.skillName, (0, workflow_renderer_1.renderSkillBody)(id)];
613
+ }));
576
614
  exports.CURSOR_SKILLS = Object.fromEntries(CURSOR_SKILL_WORKFLOW_IDS.map((id) => {
577
615
  const schema = (0, workflow_schema_1.loadWorkflowSchema)(id);
578
616
  return [schema.skillName, (0, workflow_renderer_1.renderSkillBody)(id)];
@@ -773,3 +811,6 @@ function qwenInstructions() {
773
811
  function kimiInstructions() {
774
812
  return (0, workflow_renderer_1.renderAgentInstructions)();
775
813
  }
814
+ function dshInstructions() {
815
+ return (0, workflow_renderer_1.renderAgentInstructions)();
816
+ }
@@ -22,6 +22,9 @@ export interface WorkflowSchema {
22
22
  kimi: {
23
23
  skill: boolean;
24
24
  };
25
+ dsh: {
26
+ skill: boolean;
27
+ };
25
28
  inline: boolean;
26
29
  variants: string[] | null;
27
30
  }
@@ -68,12 +68,14 @@ function parseSchema(raw, filePath) {
68
68
  const claude = requireField(obj, 'claude', filePath);
69
69
  const cursor = requireField(obj, 'cursor', filePath);
70
70
  const poolside = requireField(obj, 'poolside', filePath);
71
- // vibe/qwen/kimi are optional and mirror poolside by default — see mistral-vibe-agent-support,
72
- // qwen-code-agent-support, and kimi-cli-agent-support specs. This keeps existing bundled/forked
73
- // schemas (none declare a `vibe:`/`qwen:`/`kimi:` key) working unchanged.
71
+ // vibe/qwen/kimi/dsh are optional and mirror poolside by default — see mistral-vibe-agent-support,
72
+ // qwen-code-agent-support, kimi-cli-agent-support, and deepseek-harness-agent-support specs. This
73
+ // keeps existing bundled/forked schemas (none declare a `vibe:`/`qwen:`/`kimi:`/`dsh:` key) working
74
+ // unchanged.
74
75
  const vibe = obj.vibe ?? poolside;
75
76
  const qwen = obj.qwen ?? poolside;
76
77
  const kimi = obj.kimi ?? poolside;
78
+ const dsh = obj.dsh ?? poolside;
77
79
  requireField(obj, 'inline', filePath);
78
80
  return {
79
81
  id: obj.id,
@@ -87,6 +89,7 @@ function parseSchema(raw, filePath) {
87
89
  vibe: { skill: Boolean(vibe.skill) },
88
90
  qwen: { skill: Boolean(qwen.skill) },
89
91
  kimi: { skill: Boolean(kimi.skill) },
92
+ dsh: { skill: Boolean(dsh.skill) },
90
93
  inline: Boolean(obj.inline),
91
94
  variants: obj.variants ?? null,
92
95
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-product-primer/cli",
3
- "version": "2.9.0",
3
+ "version": "2.10.0",
4
4
  "description": "Open Product Primer CLI — product decisions, sequencing, and KPI tracking for repositories",
5
5
  "keywords": [
6
6
  "product",