kodu 1.1.21 → 2.0.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.
Files changed (129) hide show
  1. package/AGENTS.md +36 -68
  2. package/README.md +97 -96
  3. package/dist/package.json +1 -2
  4. package/dist/src/app.module.js +0 -8
  5. package/dist/src/app.module.js.map +1 -1
  6. package/dist/src/commands/init/init.command.d.ts +2 -9
  7. package/dist/src/commands/init/init.command.js +15 -241
  8. package/dist/src/commands/init/init.command.js.map +1 -1
  9. package/dist/src/commands/pack/pack.command.d.ts +9 -0
  10. package/dist/src/commands/pack/pack.command.js +72 -3
  11. package/dist/src/commands/pack/pack.command.js.map +1 -1
  12. package/dist/src/core/config/config.schema.d.ts +0 -46
  13. package/dist/src/core/config/config.schema.js +1 -51
  14. package/dist/src/core/config/config.schema.js.map +1 -1
  15. package/dist/src/core/config/config.service.js +2 -2
  16. package/dist/src/core/config/config.service.js.map +1 -1
  17. package/dist/src/core/config/prompt.service.d.ts +1 -4
  18. package/dist/src/core/config/prompt.service.js +4 -17
  19. package/dist/src/core/config/prompt.service.js.map +1 -1
  20. package/dist/src/core/file-system/fs.service.d.ts +1 -0
  21. package/dist/src/core/file-system/fs.service.js +4 -1
  22. package/dist/src/core/file-system/fs.service.js.map +1 -1
  23. package/dist/src/shared/constants.d.ts +0 -4
  24. package/dist/src/shared/constants.js +1 -5
  25. package/dist/src/shared/constants.js.map +1 -1
  26. package/dist/src/shared/git/git.module.js +0 -2
  27. package/dist/src/shared/git/git.module.js.map +1 -1
  28. package/dist/src/shared/git/git.service.d.ts +0 -8
  29. package/dist/src/shared/git/git.service.js +2 -34
  30. package/dist/src/shared/git/git.service.js.map +1 -1
  31. package/dist/src/shared/tokenizer/tokenizer.module.js +0 -2
  32. package/dist/src/shared/tokenizer/tokenizer.module.js.map +1 -1
  33. package/dist/src/shared/tokenizer/tokenizer.service.d.ts +0 -6
  34. package/dist/src/shared/tokenizer/tokenizer.service.js +8 -38
  35. package/dist/src/shared/tokenizer/tokenizer.service.js.map +1 -1
  36. package/dist/tsconfig.build.tsbuildinfo +1 -1
  37. package/kodu.schema.json +0 -139
  38. package/package.json +1 -2
  39. package/skills/kodu-ops/SKILL.md +184 -0
  40. package/src/app.module.ts +0 -8
  41. package/src/commands/init/init.command.ts +15 -310
  42. package/src/commands/pack/pack.command.ts +66 -3
  43. package/src/core/config/config.schema.ts +1 -68
  44. package/src/core/config/config.service.ts +2 -2
  45. package/src/core/config/prompt.service.ts +4 -26
  46. package/src/core/file-system/fs.service.ts +7 -1
  47. package/src/shared/constants.ts +0 -4
  48. package/src/shared/git/git.module.ts +0 -2
  49. package/src/shared/git/git.service.ts +1 -33
  50. package/src/shared/tokenizer/tokenizer.module.ts +0 -2
  51. package/src/shared/tokenizer/tokenizer.service.ts +9 -39
  52. package/.kodu/prompts/.keep +0 -0
  53. package/.kodu/prompts/commit.md +0 -9
  54. package/.kodu/prompts/pack.md +0 -7
  55. package/.kodu/prompts/review-bug.md +0 -6
  56. package/.kodu/prompts/review-security.md +0 -6
  57. package/.kodu/prompts/review-style.md +0 -6
  58. package/.opencode/command/openspec-apply.md +0 -24
  59. package/.opencode/command/openspec-archive.md +0 -27
  60. package/.opencode/command/openspec-proposal.md +0 -29
  61. package/.opencode/skills/kodu-ops/SKILL.md +0 -60
  62. package/dist/src/commands/commit/commit.command.d.ts +0 -18
  63. package/dist/src/commands/commit/commit.command.js +0 -149
  64. package/dist/src/commands/commit/commit.command.js.map +0 -1
  65. package/dist/src/commands/commit/commit.module.d.ts +0 -2
  66. package/dist/src/commands/commit/commit.module.js +0 -25
  67. package/dist/src/commands/commit/commit.module.js.map +0 -1
  68. package/dist/src/commands/ops/ops.command.d.ts +0 -4
  69. package/dist/src/commands/ops/ops.command.js +0 -39
  70. package/dist/src/commands/ops/ops.command.js.map +0 -1
  71. package/dist/src/commands/ops/ops.module.d.ts +0 -2
  72. package/dist/src/commands/ops/ops.module.js +0 -33
  73. package/dist/src/commands/ops/ops.module.js.map +0 -1
  74. package/dist/src/commands/ops/ops.types.d.ts +0 -13
  75. package/dist/src/commands/ops/ops.types.js +0 -12
  76. package/dist/src/commands/ops/ops.types.js.map +0 -1
  77. package/dist/src/commands/ops/ops.utils.d.ts +0 -13
  78. package/dist/src/commands/ops/ops.utils.js +0 -121
  79. package/dist/src/commands/ops/ops.utils.js.map +0 -1
  80. package/dist/src/commands/ops/subcommands/ops-env.command.d.ts +0 -24
  81. package/dist/src/commands/ops/subcommands/ops-env.command.js +0 -156
  82. package/dist/src/commands/ops/subcommands/ops-env.command.js.map +0 -1
  83. package/dist/src/commands/ops/subcommands/ops-routes.command.d.ts +0 -22
  84. package/dist/src/commands/ops/subcommands/ops-routes.command.js +0 -203
  85. package/dist/src/commands/ops/subcommands/ops-routes.command.js.map +0 -1
  86. package/dist/src/commands/ops/subcommands/ops-service.command.d.ts +0 -22
  87. package/dist/src/commands/ops/subcommands/ops-service.command.js +0 -169
  88. package/dist/src/commands/ops/subcommands/ops-service.command.js.map +0 -1
  89. package/dist/src/commands/ops/subcommands/ops-sysinfo.command.d.ts +0 -14
  90. package/dist/src/commands/ops/subcommands/ops-sysinfo.command.js +0 -75
  91. package/dist/src/commands/ops/subcommands/ops-sysinfo.command.js.map +0 -1
  92. package/dist/src/commands/review/review.command.d.ts +0 -26
  93. package/dist/src/commands/review/review.command.js +0 -205
  94. package/dist/src/commands/review/review.command.js.map +0 -1
  95. package/dist/src/commands/review/review.module.d.ts +0 -2
  96. package/dist/src/commands/review/review.module.js +0 -26
  97. package/dist/src/commands/review/review.module.js.map +0 -1
  98. package/dist/src/core/config/default-prompts.d.ts +0 -9
  99. package/dist/src/core/config/default-prompts.js +0 -49
  100. package/dist/src/core/config/default-prompts.js.map +0 -1
  101. package/dist/src/shared/ai/ai.module.d.ts +0 -2
  102. package/dist/src/shared/ai/ai.module.js +0 -23
  103. package/dist/src/shared/ai/ai.module.js.map +0 -1
  104. package/dist/src/shared/ai/ai.service.d.ts +0 -22
  105. package/dist/src/shared/ai/ai.service.js +0 -164
  106. package/dist/src/shared/ai/ai.service.js.map +0 -1
  107. package/dist/src/shared/ssh/ssh.module.d.ts +0 -2
  108. package/dist/src/shared/ssh/ssh.module.js +0 -21
  109. package/dist/src/shared/ssh/ssh.module.js.map +0 -1
  110. package/dist/src/shared/ssh/ssh.service.d.ts +0 -11
  111. package/dist/src/shared/ssh/ssh.service.js +0 -53
  112. package/dist/src/shared/ssh/ssh.service.js.map +0 -1
  113. package/src/commands/commit/commit.command.ts +0 -139
  114. package/src/commands/commit/commit.module.ts +0 -12
  115. package/src/commands/ops/ops.command.ts +0 -30
  116. package/src/commands/ops/ops.module.ts +0 -20
  117. package/src/commands/ops/ops.types.ts +0 -24
  118. package/src/commands/ops/ops.utils.ts +0 -160
  119. package/src/commands/ops/subcommands/ops-env.command.ts +0 -165
  120. package/src/commands/ops/subcommands/ops-routes.command.ts +0 -221
  121. package/src/commands/ops/subcommands/ops-service.command.ts +0 -190
  122. package/src/commands/ops/subcommands/ops-sysinfo.command.ts +0 -77
  123. package/src/commands/review/review.command.ts +0 -199
  124. package/src/commands/review/review.module.ts +0 -13
  125. package/src/core/config/default-prompts.ts +0 -53
  126. package/src/shared/ai/ai.module.ts +0 -10
  127. package/src/shared/ai/ai.service.ts +0 -216
  128. package/src/shared/ssh/ssh.module.ts +0 -8
  129. package/src/shared/ssh/ssh.service.ts +0 -61
@@ -1,216 +0,0 @@
1
- import { Agent } from '@mastra/core/agent';
2
- import { Injectable } from '@nestjs/common';
3
- import { ConfigService } from '../../core/config/config.service';
4
- import {
5
- DEFAULT_COMMIT_PROMPT,
6
- DEFAULT_REVIEW_PROMPTS,
7
- replacePromptVariables,
8
- STANDARD_REVIEW_MODES,
9
- } from '../../core/config/default-prompts';
10
- import { PromptService } from '../../core/config/prompt.service';
11
- import { DEFAULT_COMMIT_TOKENS, DEFAULT_REVIEW_TOKENS } from '../constants';
12
-
13
- export type ReviewMode = string;
14
-
15
- type ModelSettings = Record<string, unknown> & {
16
- maxOutputTokens?: number;
17
- };
18
-
19
- @Injectable()
20
- export class AiService {
21
- constructor(
22
- private readonly configService: ConfigService,
23
- private readonly promptService: PromptService,
24
- ) {}
25
-
26
- async reviewDiff(diff: string, mode: ReviewMode): Promise<{ text: string }> {
27
- const agent = this.createAgent(
28
- 'kodu-review-agent',
29
- 'AI Reviewer for staged git diff. Be concise.',
30
- );
31
-
32
- const userPrompt = await this.buildReviewPrompt(diff, mode);
33
-
34
- const modelSettings = this.getModelSettingsForCommand('review');
35
- const output = await agent.generate(userPrompt, { modelSettings });
36
- return { text: output.text.trim() };
37
- }
38
-
39
- async generateCommitMessage(diff: string): Promise<string> {
40
- const agent = this.createAgent(
41
- 'kodu-commit-agent',
42
- 'Generate a concise Conventional Commit message. Only output the message string.',
43
- );
44
-
45
- const prompt = await this.buildCommitPrompt(diff);
46
- const modelSettings = this.getModelSettingsForCommand('commit');
47
- const output = await agent.generate(prompt, { modelSettings });
48
-
49
- const raw = output.text.trim();
50
- const cleaned = this.cleanCommitMessage(raw);
51
-
52
- if (!cleaned) {
53
- throw new Error('AI did not return a valid commit message.');
54
- }
55
-
56
- return cleaned;
57
- }
58
-
59
- getAvailableReviewModes(): string[] {
60
- const config = this.configService.getConfig();
61
- const standardModes = [...STANDARD_REVIEW_MODES];
62
- const customModes = config.prompts?.review
63
- ? Object.keys(config.prompts.review)
64
- : [];
65
-
66
- return Array.from(new Set([...standardModes, ...customModes]));
67
- }
68
-
69
- hasApiKey(): boolean {
70
- const config = this.configService.getConfig();
71
- if (!config.llm) {
72
- return false;
73
- }
74
- const envName = config.llm.apiKeyEnv ?? 'OPENAI_API_KEY';
75
- const value = process.env[envName];
76
- return Boolean(value);
77
- }
78
-
79
- getApiKeyEnvName(): string {
80
- const config = this.configService.getConfig();
81
- return config.llm?.apiKeyEnv ?? 'OPENAI_API_KEY';
82
- }
83
-
84
- private createAgent(id: string, instructions: string): Agent {
85
- const apiKey = this.getApiKey();
86
- const modelId = this.getModelId();
87
-
88
- return new Agent({
89
- id,
90
- name: id,
91
- instructions,
92
- model: {
93
- id: modelId as `${string}/${string}`,
94
- apiKey,
95
- },
96
- maxRetries: 1,
97
- });
98
- }
99
-
100
- private async buildReviewPrompt(
101
- diff: string,
102
- mode: ReviewMode,
103
- ): Promise<string> {
104
- const config = this.configService.getConfig();
105
-
106
- const customPrompt = config.prompts?.review?.[mode];
107
- if (customPrompt) {
108
- return this.promptService.load(customPrompt, { diff, mode });
109
- }
110
-
111
- if (
112
- STANDARD_REVIEW_MODES.includes(
113
- mode as (typeof STANDARD_REVIEW_MODES)[number],
114
- )
115
- ) {
116
- const defaultPrompt =
117
- DEFAULT_REVIEW_PROMPTS[mode as keyof typeof DEFAULT_REVIEW_PROMPTS];
118
- return replacePromptVariables(defaultPrompt, { diff, mode });
119
- }
120
-
121
- return replacePromptVariables(DEFAULT_REVIEW_PROMPTS.bug, { diff, mode });
122
- }
123
-
124
- private async buildCommitPrompt(diff: string): Promise<string> {
125
- const config = this.configService.getConfig();
126
- const customPrompt = config.prompts?.commit;
127
-
128
- if (customPrompt) {
129
- return this.promptService.load(customPrompt, { diff });
130
- }
131
-
132
- return replacePromptVariables(DEFAULT_COMMIT_PROMPT, { diff });
133
- }
134
-
135
- private getApiKey(): string {
136
- const config = this.configService.getConfig();
137
- if (!config.llm) {
138
- throw new Error(
139
- 'LLM configuration not found. Add llm section to kodu.json',
140
- );
141
- }
142
- const envName = config.llm.apiKeyEnv ?? 'OPENAI_API_KEY';
143
- const value = process.env[envName];
144
-
145
- if (!value) {
146
- throw new Error(`API key not found: set ${envName} in environment.`);
147
- }
148
-
149
- return value;
150
- }
151
-
152
- private getModelId(): string {
153
- const config = this.configService.getConfig();
154
- if (!config.llm) {
155
- throw new Error(
156
- 'LLM configuration not found. Add llm section to kodu.json',
157
- );
158
- }
159
- const model = config.llm.model;
160
-
161
- // Model should already be in provider/model format, but validate
162
- if (!model.includes('/')) {
163
- throw new Error(
164
- `Invalid model format: "${model}". Expected format "provider/model-name" (e.g., "openai/gpt-4o")`,
165
- );
166
- }
167
-
168
- return model;
169
- }
170
-
171
- private getModelSettingsForCommand(
172
- command: 'commit' | 'review',
173
- ): ModelSettings {
174
- const config = this.configService.getConfig();
175
- const commands = config.llm?.commands;
176
- const defaultMax =
177
- command === 'commit' ? DEFAULT_COMMIT_TOKENS : DEFAULT_REVIEW_TOKENS;
178
- const base: ModelSettings = { maxOutputTokens: defaultMax };
179
-
180
- if (!commands) {
181
- return base;
182
- }
183
-
184
- const override = commands[command];
185
- const settings = override?.modelSettings as ModelSettings | undefined;
186
-
187
- if (!settings) {
188
- return base;
189
- }
190
-
191
- return {
192
- ...settings,
193
- maxOutputTokens: settings.maxOutputTokens ?? defaultMax,
194
- };
195
- }
196
-
197
- private cleanCommitMessage(text: string): string {
198
- const unfenced = text.replace(/^```[a-zA-Z]*\s*/g, '').replace(/```$/g, '');
199
- const lines = unfenced
200
- .split('\n')
201
- .map((line) => line.trim())
202
- .filter((line) => line.length > 0);
203
-
204
- if (lines.length === 0) {
205
- return '';
206
- }
207
-
208
- const first = lines[0]
209
- .replace(/^"|"$/g, '')
210
- .replace(/^'|'$/g, '')
211
- .replace(/^Commit message:?\s*/i, '')
212
- .trim();
213
-
214
- return first;
215
- }
216
- }
@@ -1,8 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { SshService } from './ssh.service';
3
-
4
- @Module({
5
- providers: [SshService],
6
- exports: [SshService],
7
- })
8
- export class SshModule {}
@@ -1,61 +0,0 @@
1
- import { Injectable } from '@nestjs/common';
2
- import { execa } from 'execa';
3
- import type { ServerConfig } from '../../core/config/config.schema';
4
-
5
- export type SshResult = {
6
- success: boolean;
7
- stdout: string;
8
- stderr: string;
9
- exitCode: number;
10
- error?: string;
11
- };
12
-
13
- @Injectable()
14
- export class SshService {
15
- async execute(
16
- serverConfig: ServerConfig,
17
- command: string,
18
- ): Promise<SshResult> {
19
- const args = [
20
- '-i',
21
- serverConfig.sshKeyPath,
22
- '-p',
23
- String(serverConfig.port ?? 22),
24
- '-o',
25
- 'StrictHostKeyChecking=no',
26
- '-o',
27
- 'ConnectTimeout=10',
28
- `${serverConfig.user}@${serverConfig.host}`,
29
- command,
30
- ];
31
-
32
- try {
33
- const { stdout, stderr, exitCode } = await execa('ssh', args, {
34
- env: serverConfig.env,
35
- });
36
-
37
- return {
38
- success: (exitCode ?? 0) === 0,
39
- stdout,
40
- stderr,
41
- exitCode: exitCode ?? 0,
42
- };
43
- } catch (error) {
44
- const failure = error as {
45
- stdout?: string;
46
- stderr?: string;
47
- exitCode?: number;
48
- shortMessage?: string;
49
- message?: string;
50
- };
51
-
52
- return {
53
- success: false,
54
- stdout: failure.stdout ?? '',
55
- stderr: failure.stderr ?? '',
56
- exitCode: failure.exitCode ?? -1,
57
- error: failure.shortMessage ?? failure.message ?? 'Unknown SSH error',
58
- };
59
- }
60
- }
61
- }