kodu 2.1.2 → 2.2.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 (122) hide show
  1. package/AGENTS.md +23 -1
  2. package/__tests__/core/registry/registry.service.test.ts +82 -0
  3. package/__tests__/shared/runbook/runbook.service.test.ts +104 -0
  4. package/dist/package.json +1 -1
  5. package/dist/src/app.module.js +6 -0
  6. package/dist/src/app.module.js.map +1 -1
  7. package/dist/src/commands/init/init.command.d.ts +1 -0
  8. package/dist/src/commands/init/init.command.js +34 -1
  9. package/dist/src/commands/init/init.command.js.map +1 -1
  10. package/dist/src/commands/ops/ops-add.command.d.ts +18 -0
  11. package/dist/src/commands/ops/ops-add.command.js +102 -0
  12. package/dist/src/commands/ops/ops-add.command.js.map +1 -0
  13. package/dist/src/commands/ops/ops-init.command.d.ts +22 -0
  14. package/dist/src/commands/ops/ops-init.command.js +130 -0
  15. package/dist/src/commands/ops/ops-init.command.js.map +1 -0
  16. package/dist/src/commands/ops/ops-list.command.d.ts +12 -0
  17. package/dist/src/commands/ops/ops-list.command.js +73 -0
  18. package/dist/src/commands/ops/ops-list.command.js.map +1 -0
  19. package/dist/src/commands/ops/ops-path.command.d.ts +9 -0
  20. package/dist/src/commands/ops/ops-path.command.js +52 -0
  21. package/dist/src/commands/ops/ops-path.command.js.map +1 -0
  22. package/dist/src/commands/ops/ops-runbook.command.d.ts +12 -0
  23. package/dist/src/commands/ops/ops-runbook.command.js +81 -0
  24. package/dist/src/commands/ops/ops-runbook.command.js.map +1 -0
  25. package/dist/src/commands/ops/ops-status.command.d.ts +11 -0
  26. package/dist/src/commands/ops/ops-status.command.js +62 -0
  27. package/dist/src/commands/ops/ops-status.command.js.map +1 -0
  28. package/dist/src/commands/ops/ops-use.command.d.ts +12 -0
  29. package/dist/src/commands/ops/ops-use.command.js +76 -0
  30. package/dist/src/commands/ops/ops-use.command.js.map +1 -0
  31. package/dist/src/commands/ops/ops.command.d.ts +7 -0
  32. package/dist/src/commands/ops/ops.command.js +56 -0
  33. package/dist/src/commands/ops/ops.command.js.map +1 -0
  34. package/dist/src/commands/ops/ops.helpers.d.ts +2 -0
  35. package/dist/src/commands/ops/ops.helpers.js +11 -0
  36. package/dist/src/commands/ops/ops.helpers.js.map +1 -0
  37. package/dist/src/commands/ops/ops.module.d.ts +2 -0
  38. package/dist/src/commands/ops/ops.module.js +36 -0
  39. package/dist/src/commands/ops/ops.module.js.map +1 -0
  40. package/dist/src/core/registry/registry.module.d.ts +2 -0
  41. package/dist/src/core/registry/registry.module.js +22 -0
  42. package/dist/src/core/registry/registry.module.js.map +1 -0
  43. package/dist/src/core/registry/registry.schema.d.ts +24 -0
  44. package/dist/src/core/registry/registry.schema.js +21 -0
  45. package/dist/src/core/registry/registry.schema.js.map +1 -0
  46. package/dist/src/core/registry/registry.service.d.ts +16 -0
  47. package/dist/src/core/registry/registry.service.js +91 -0
  48. package/dist/src/core/registry/registry.service.js.map +1 -0
  49. package/dist/src/shared/runbook/runbook.module.d.ts +2 -0
  50. package/dist/src/shared/runbook/runbook.module.js +22 -0
  51. package/dist/src/shared/runbook/runbook.module.js.map +1 -0
  52. package/dist/src/shared/runbook/runbook.service.d.ts +20 -0
  53. package/dist/src/shared/runbook/runbook.service.js +118 -0
  54. package/dist/src/shared/runbook/runbook.service.js.map +1 -0
  55. package/dist/src/shared/runbook/runbook.templates.d.ts +6 -0
  56. package/dist/src/shared/runbook/runbook.templates.js +49 -0
  57. package/dist/src/shared/runbook/runbook.templates.js.map +1 -0
  58. package/dist/tsconfig.build.tsbuildinfo +1 -1
  59. package/package.json +1 -1
  60. package/registry.schema.json +39 -0
  61. package/scripts/generate-json-schema.ts +14 -5
  62. package/skills/ac/SKILL.md +239 -0
  63. package/skills/al/SKILL.md +98 -0
  64. package/skills/audit/SKILL.md +205 -0
  65. package/skills/audit/audit-baseline-template.yml +188 -0
  66. package/skills/audit/runtime-detect.md +64 -0
  67. package/skills/audit/stacks/_generic.md +41 -0
  68. package/skills/audit/stacks/_registry.md +47 -0
  69. package/skills/audit/stacks/go.md +66 -0
  70. package/skills/audit/stacks/java.md +44 -0
  71. package/skills/audit/stacks/node.md +57 -0
  72. package/skills/audit/stacks/python.md +45 -0
  73. package/skills/audit/stacks/rust.md +44 -0
  74. package/skills/audit-api-contracts/SKILL.md +201 -0
  75. package/skills/audit-architecture/SKILL.md +200 -0
  76. package/skills/audit-bugs/SKILL.md +226 -0
  77. package/skills/audit-concurrency/SKILL.md +197 -0
  78. package/skills/audit-deployment/SKILL.md +218 -0
  79. package/skills/audit-docs/SKILL.md +209 -0
  80. package/skills/audit-errors/SKILL.md +216 -0
  81. package/skills/audit-logging/SKILL.md +197 -0
  82. package/skills/audit-matrix/SKILL.md +245 -0
  83. package/skills/audit-meta/SKILL.md +120 -0
  84. package/skills/audit-naming/SKILL.md +200 -0
  85. package/skills/audit-owasp/SKILL.md +223 -0
  86. package/skills/audit-performance/SKILL.md +199 -0
  87. package/skills/audit-reinvention/SKILL.md +214 -0
  88. package/skills/audit-secrets/SKILL.md +198 -0
  89. package/skills/audit-tests/SKILL.md +210 -0
  90. package/skills/audit-validation/SKILL.md +206 -0
  91. package/skills/audit-verify/SKILL.md +139 -0
  92. package/skills/audit-yagni/SKILL.md +188 -0
  93. package/skills/doc-gen/SKILL.md +490 -0
  94. package/skills/doc-gen/scripts/doc_gen.py +911 -0
  95. package/skills/generate-project-docs/SKILL.md +380 -0
  96. package/skills/implement-project/SKILL.md +409 -0
  97. package/skills/litefront-prototype/SKILL.md +484 -0
  98. package/skills/ops/SKILL.md +94 -0
  99. package/skills/post-call-task-builder/SKILL.md +419 -0
  100. package/skills/skills-best-practices/SKILL.md +415 -0
  101. package/skills/start/SKILL.md +319 -0
  102. package/skills/tech-blueprint/SKILL.md +890 -0
  103. package/skills/tech-blueprint/scripts/blueprint_validator.py +417 -0
  104. package/src/app.module.ts +6 -0
  105. package/src/commands/init/init.command.ts +43 -1
  106. package/src/commands/ops/ops-add.command.ts +83 -0
  107. package/src/commands/ops/ops-init.command.ts +125 -0
  108. package/src/commands/ops/ops-list.command.ts +57 -0
  109. package/src/commands/ops/ops-path.command.ts +38 -0
  110. package/src/commands/ops/ops-runbook.command.ts +74 -0
  111. package/src/commands/ops/ops-status.command.ts +47 -0
  112. package/src/commands/ops/ops-use.command.ts +76 -0
  113. package/src/commands/ops/ops.command.ts +42 -0
  114. package/src/commands/ops/ops.helpers.ts +20 -0
  115. package/src/commands/ops/ops.module.ts +23 -0
  116. package/src/core/registry/registry.module.ts +9 -0
  117. package/src/core/registry/registry.schema.ts +46 -0
  118. package/src/core/registry/registry.service.ts +128 -0
  119. package/src/shared/runbook/runbook.module.ts +9 -0
  120. package/src/shared/runbook/runbook.service.ts +164 -0
  121. package/src/shared/runbook/runbook.templates.ts +66 -0
  122. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectConfigSchema = exports.registrySchema = exports.projectEntrySchema = exports.DEFAULT_STANDS = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.DEFAULT_STANDS = ['local', 'dev', 'stage', 'prod'];
6
+ exports.projectEntrySchema = zod_1.z.object({
7
+ path: zod_1.z.string().min(1),
8
+ repo: zod_1.z.string().optional(),
9
+ stands: zod_1.z.array(zod_1.z.string()).default([...exports.DEFAULT_STANDS]),
10
+ });
11
+ exports.registrySchema = zod_1.z.object({
12
+ $schema: zod_1.z.string().optional(),
13
+ projects: zod_1.z.record(zod_1.z.string(), exports.projectEntrySchema).default({}),
14
+ });
15
+ exports.projectConfigSchema = zod_1.z.object({
16
+ $schema: zod_1.z.string().optional(),
17
+ project: zod_1.z.string().min(1),
18
+ activeStand: zod_1.z.string().default('local'),
19
+ stands: zod_1.z.array(zod_1.z.string()).default([...exports.DEFAULT_STANDS]),
20
+ });
21
+ //# sourceMappingURL=registry.schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.schema.js","sourceRoot":"","sources":["../../../../src/core/registry/registry.schema.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAMX,QAAA,cAAc,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAU,CAAC;AAG5D,QAAA,kBAAkB,GAAG,OAAC,CAAC,MAAM,CAAC;IAEzC,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEvB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE3B,MAAM,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,sBAAc,CAAC,CAAC;CACzD,CAAC,CAAC;AAQU,QAAA,cAAc,GAAG,OAAC,CAAC,MAAM,CAAC;IACrC,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,0BAAkB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAC/D,CAAC,CAAC;AAQU,QAAA,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE9B,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1B,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAExC,MAAM,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,sBAAc,CAAC,CAAC;CACzD,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { type ProjectEntry, type Registry } from './registry.schema';
2
+ export declare class RegistryService {
3
+ private readonly dir;
4
+ private readonly file;
5
+ getFilePath(): string;
6
+ load(): Promise<Registry>;
7
+ save(registry: Registry): Promise<void>;
8
+ list(): Promise<Registry['projects']>;
9
+ get(name: string): Promise<ProjectEntry | undefined>;
10
+ has(name: string): Promise<boolean>;
11
+ add(name: string, entry: ProjectEntry, options?: {
12
+ overwrite?: boolean;
13
+ }): Promise<void>;
14
+ update(name: string, patch: Partial<ProjectEntry>): Promise<ProjectEntry>;
15
+ remove(name: string): Promise<void>;
16
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RegistryService = void 0;
13
+ const node_fs_1 = require("node:fs");
14
+ const node_os_1 = __importDefault(require("node:os"));
15
+ const node_path_1 = __importDefault(require("node:path"));
16
+ const common_1 = require("@nestjs/common");
17
+ const registry_schema_1 = require("./registry.schema");
18
+ let RegistryService = class RegistryService {
19
+ dir = node_path_1.default.join(process.env.XDG_CONFIG_HOME?.trim() || node_path_1.default.join(node_os_1.default.homedir(), '.config'), 'kodu');
20
+ file = node_path_1.default.join(this.dir, 'registry.json');
21
+ getFilePath() {
22
+ return this.file;
23
+ }
24
+ async load() {
25
+ let raw;
26
+ try {
27
+ const content = await node_fs_1.promises.readFile(this.file, 'utf8');
28
+ raw = JSON.parse(content);
29
+ }
30
+ catch (error) {
31
+ if (error.code === 'ENOENT') {
32
+ return registry_schema_1.registrySchema.parse({});
33
+ }
34
+ throw new Error(`Не удалось прочитать реестр ${this.file}: ${error.message}`);
35
+ }
36
+ const parsed = registry_schema_1.registrySchema.safeParse(raw);
37
+ if (!parsed.success) {
38
+ const issues = parsed.error.issues
39
+ .map((issue) => `- ${issue.path.join('.') || '(root)'}: ${issue.message}`)
40
+ .join('\n');
41
+ throw new Error(`Реестр ${this.file} невалиден:\n${issues}`);
42
+ }
43
+ return parsed.data;
44
+ }
45
+ async save(registry) {
46
+ const validated = registry_schema_1.registrySchema.parse(registry);
47
+ await node_fs_1.promises.mkdir(this.dir, { recursive: true });
48
+ await node_fs_1.promises.writeFile(this.file, `${JSON.stringify(validated, null, 2)}\n`, 'utf8');
49
+ }
50
+ async list() {
51
+ return (await this.load()).projects;
52
+ }
53
+ async get(name) {
54
+ return (await this.load()).projects[name];
55
+ }
56
+ async has(name) {
57
+ return Boolean(await this.get(name));
58
+ }
59
+ async add(name, entry, options = {}) {
60
+ const registry = await this.load();
61
+ if (registry.projects[name] && !options.overwrite) {
62
+ throw new Error(`Проект с именем "${name}" уже есть в реестре. Выбери другое имя или обнови существующий проект.`);
63
+ }
64
+ registry.projects[name] = entry;
65
+ await this.save(registry);
66
+ }
67
+ async update(name, patch) {
68
+ const registry = await this.load();
69
+ const existing = registry.projects[name];
70
+ if (!existing) {
71
+ throw new Error(`Проект "${name}" не найден в реестре.`);
72
+ }
73
+ const next = { ...existing, ...patch };
74
+ registry.projects[name] = next;
75
+ await this.save(registry);
76
+ return next;
77
+ }
78
+ async remove(name) {
79
+ const registry = await this.load();
80
+ if (!registry.projects[name]) {
81
+ throw new Error(`Проект "${name}" не найден в реестре.`);
82
+ }
83
+ delete registry.projects[name];
84
+ await this.save(registry);
85
+ }
86
+ };
87
+ exports.RegistryService = RegistryService;
88
+ exports.RegistryService = RegistryService = __decorate([
89
+ (0, common_1.Injectable)()
90
+ ], RegistryService);
91
+ //# sourceMappingURL=registry.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.service.js","sourceRoot":"","sources":["../../../../src/core/registry/registry.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare class RunbookModule {
2
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.RunbookModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const runbook_service_1 = require("./runbook.service");
12
+ let RunbookModule = class RunbookModule {
13
+ };
14
+ exports.RunbookModule = RunbookModule;
15
+ exports.RunbookModule = RunbookModule = __decorate([
16
+ (0, common_1.Global)(),
17
+ (0, common_1.Module)({
18
+ providers: [runbook_service_1.RunbookService],
19
+ exports: [runbook_service_1.RunbookService],
20
+ })
21
+ ], RunbookModule);
22
+ //# sourceMappingURL=runbook.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runbook.module.js","sourceRoot":"","sources":["../../../../src/shared/runbook/runbook.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAgD;AAChD,uDAAmD;AAO5C,IAAM,aAAa,GAAnB,MAAM,aAAa;CAAG,CAAA;AAAhB,sCAAa;wBAAb,aAAa;IALzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,gCAAc,CAAC;QAC3B,OAAO,EAAE,CAAC,gCAAc,CAAC;KAC1B,CAAC;GACW,aAAa,CAAG"}
@@ -0,0 +1,20 @@
1
+ import { type ProjectConfig } from '../../core/registry/registry.schema';
2
+ import { type DetectedStack } from './runbook.templates';
3
+ export type GitignoreResult = 'created' | 'added' | 'present' | 'no-git';
4
+ export declare class RunbookService {
5
+ dirPath(root?: string): string;
6
+ configPath(root?: string): string;
7
+ runbookPath(root?: string): string;
8
+ exists(root?: string): Promise<boolean>;
9
+ readConfig(root?: string): Promise<ProjectConfig>;
10
+ writeConfig(config: ProjectConfig, root?: string): Promise<void>;
11
+ readRunbook(root?: string): Promise<string>;
12
+ scaffold(options: {
13
+ project: string;
14
+ stands: string[];
15
+ activeStand: string;
16
+ }, root?: string): Promise<void>;
17
+ detectStack(root?: string): Promise<DetectedStack>;
18
+ ensureGitignore(root?: string): Promise<GitignoreResult>;
19
+ private pathExists;
20
+ }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RunbookService = void 0;
13
+ const node_fs_1 = require("node:fs");
14
+ const node_path_1 = __importDefault(require("node:path"));
15
+ const common_1 = require("@nestjs/common");
16
+ const registry_schema_1 = require("../../core/registry/registry.schema");
17
+ const runbook_templates_1 = require("./runbook.templates");
18
+ const RUNBOOK_DIR = '.runbook';
19
+ const GITIGNORE_ENTRY = '/.runbook/';
20
+ const GITIGNORE_EQUIVALENTS = new Set([
21
+ '/.runbook/',
22
+ '/.runbook',
23
+ '.runbook/',
24
+ '.runbook',
25
+ ]);
26
+ let RunbookService = class RunbookService {
27
+ dirPath(root = process.cwd()) {
28
+ return node_path_1.default.join(root, RUNBOOK_DIR);
29
+ }
30
+ configPath(root = process.cwd()) {
31
+ return node_path_1.default.join(root, RUNBOOK_DIR, 'config.json');
32
+ }
33
+ runbookPath(root = process.cwd()) {
34
+ return node_path_1.default.join(root, RUNBOOK_DIR, 'runbook.md');
35
+ }
36
+ async exists(root = process.cwd()) {
37
+ return this.pathExists(this.configPath(root));
38
+ }
39
+ async readConfig(root = process.cwd()) {
40
+ const content = await node_fs_1.promises.readFile(this.configPath(root), 'utf8');
41
+ return registry_schema_1.projectConfigSchema.parse(JSON.parse(content));
42
+ }
43
+ async writeConfig(config, root = process.cwd()) {
44
+ const validated = registry_schema_1.projectConfigSchema.parse(config);
45
+ await node_fs_1.promises.mkdir(this.dirPath(root), { recursive: true });
46
+ await node_fs_1.promises.writeFile(this.configPath(root), `${JSON.stringify(validated, null, 2)}\n`, 'utf8');
47
+ }
48
+ async readRunbook(root = process.cwd()) {
49
+ return node_fs_1.promises.readFile(this.runbookPath(root), 'utf8');
50
+ }
51
+ async scaffold(options, root = process.cwd()) {
52
+ await node_fs_1.promises.mkdir(this.dirPath(root), { recursive: true });
53
+ await this.writeConfig({
54
+ project: options.project,
55
+ activeStand: options.activeStand,
56
+ stands: options.stands,
57
+ }, root);
58
+ if (!(await this.pathExists(this.runbookPath(root)))) {
59
+ const detected = await this.detectStack(root);
60
+ const markdown = (0, runbook_templates_1.renderRunbook)(options.project, options.stands, detected);
61
+ await node_fs_1.promises.writeFile(this.runbookPath(root), markdown, 'utf8');
62
+ }
63
+ }
64
+ async detectStack(root = process.cwd()) {
65
+ const [composeYml, composeYaml, dockerfile, envExample] = await Promise.all([
66
+ this.pathExists(node_path_1.default.join(root, 'docker-compose.yml')),
67
+ this.pathExists(node_path_1.default.join(root, 'docker-compose.yaml')),
68
+ this.pathExists(node_path_1.default.join(root, 'Dockerfile')),
69
+ this.pathExists(node_path_1.default.join(root, '.env.example')),
70
+ ]);
71
+ return {
72
+ compose: composeYml || composeYaml,
73
+ dockerfile,
74
+ envExample,
75
+ };
76
+ }
77
+ async ensureGitignore(root = process.cwd()) {
78
+ if (!(await this.pathExists(node_path_1.default.join(root, '.git')))) {
79
+ return 'no-git';
80
+ }
81
+ const gitignorePath = node_path_1.default.join(root, '.gitignore');
82
+ let content = '';
83
+ let fileExists = true;
84
+ try {
85
+ content = await node_fs_1.promises.readFile(gitignorePath, 'utf8');
86
+ }
87
+ catch {
88
+ fileExists = false;
89
+ }
90
+ const alreadyIgnored = content
91
+ .split(/\r?\n/)
92
+ .map((line) => line.trim())
93
+ .some((line) => GITIGNORE_EQUIVALENTS.has(line));
94
+ if (alreadyIgnored) {
95
+ return 'present';
96
+ }
97
+ const trimmed = content.trimEnd();
98
+ const next = trimmed.length > 0
99
+ ? `${trimmed}\n${GITIGNORE_ENTRY}\n`
100
+ : `${GITIGNORE_ENTRY}\n`;
101
+ await node_fs_1.promises.writeFile(gitignorePath, next, 'utf8');
102
+ return fileExists ? 'added' : 'created';
103
+ }
104
+ async pathExists(target) {
105
+ try {
106
+ await node_fs_1.promises.access(target);
107
+ return true;
108
+ }
109
+ catch {
110
+ return false;
111
+ }
112
+ }
113
+ };
114
+ exports.RunbookService = RunbookService;
115
+ exports.RunbookService = RunbookService = __decorate([
116
+ (0, common_1.Injectable)()
117
+ ], RunbookService);
118
+ //# sourceMappingURL=runbook.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runbook.service.js","sourceRoot":"","sources":["../../../../src/shared/runbook/runbook.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type DetectedStack = {
2
+ compose: boolean;
3
+ dockerfile: boolean;
4
+ envExample: boolean;
5
+ };
6
+ export declare function renderRunbook(project: string, stands: string[], detected: DetectedStack): string;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderRunbook = renderRunbook;
4
+ const STAND_TITLES = {
5
+ local: 'локальная разработка',
6
+ dev: 'dev-стенд',
7
+ stage: 'stage-стенд',
8
+ prod: 'production (осторожно!)',
9
+ };
10
+ function renderStandSection(stand, detected) {
11
+ const title = STAND_TITLES[stand] ?? stand;
12
+ const startCmd = detected.compose
13
+ ? 'docker compose up -d'
14
+ : '<команда запуска, напр. docker compose up -d>';
15
+ const logsCmd = detected.compose
16
+ ? 'docker compose logs -f'
17
+ : '<команда логов>';
18
+ const envNote = detected.envExample
19
+ ? 'Скопируй `.env.example` → `.env` и заполни значения.'
20
+ : '<откуда взять переменные окружения / секреты>';
21
+ return [
22
+ `## Стенд: ${stand} (${title})`,
23
+ '',
24
+ '- **Где живёт / доступ**: <ssh user@host или localhost>',
25
+ '- **Рабочая директория**: <путь на сервере или локально>',
26
+ '- **Получить код**: `git clone <repo>` (первый раз) / `git pull` (обновить)',
27
+ `- **Запуск**: \`${startCmd}\``,
28
+ `- **Логи**: \`${logsCmd}\``,
29
+ '- **Деплой**: <пошаговые команды деплоя на этот стенд>',
30
+ '- **Откат**: <как откатиться, если что-то пошло не так>',
31
+ `- **Переменные окружения / секреты**: ${envNote}`,
32
+ '',
33
+ ].join('\n');
34
+ }
35
+ function renderRunbook(project, stands, detected) {
36
+ const header = [
37
+ `# Runbook: ${project}`,
38
+ '',
39
+ '> Этот файл описывает, как работать со стендами проекта.',
40
+ '> Он лежит в `.gitignore` и не коммитится — здесь могут быть хосты и пути.',
41
+ '> Заполни плейсхолдеры `<...>` под свою инфраструктуру.',
42
+ '',
43
+ ].join('\n');
44
+ const sections = stands
45
+ .map((stand) => renderStandSection(stand, detected))
46
+ .join('\n');
47
+ return `${header}\n${sections}`;
48
+ }
49
+ //# sourceMappingURL=runbook.templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runbook.templates.js","sourceRoot":"","sources":["../../../../src/shared/runbook/runbook.templates.ts"],"names":[],"mappings":";;AA8CA,sCAmBC;AA1DD,MAAM,YAAY,GAA2B;IAC3C,KAAK,EAAE,sBAAsB;IAC7B,GAAG,EAAE,WAAW;IAChB,KAAK,EAAE,aAAa;IACpB,IAAI,EAAE,yBAAyB;CAChC,CAAC;AAEF,SAAS,kBAAkB,CAAC,KAAa,EAAE,QAAuB;IAChE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;IAE3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO;QAC/B,CAAC,CAAC,sBAAsB;QACxB,CAAC,CAAC,+CAA+C,CAAC;IACpD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO;QAC9B,CAAC,CAAC,wBAAwB;QAC1B,CAAC,CAAC,iBAAiB,CAAC;IACtB,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU;QACjC,CAAC,CAAC,sDAAsD;QACxD,CAAC,CAAC,+CAA+C,CAAC;IAEpD,OAAO;QACL,aAAa,KAAK,KAAK,KAAK,GAAG;QAC/B,EAAE;QACF,yDAAyD;QACzD,0DAA0D;QAC1D,6EAA6E;QAC7E,mBAAmB,QAAQ,IAAI;QAC/B,iBAAiB,OAAO,IAAI;QAC5B,wDAAwD;QACxD,yDAAyD;QACzD,yCAAyC,OAAO,EAAE;QAClD,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAMD,SAAgB,aAAa,CAC3B,OAAe,EACf,MAAgB,EAChB,QAAuB;IAEvB,MAAM,MAAM,GAAG;QACb,cAAc,OAAO,EAAE;QACvB,EAAE;QACF,0DAA0D;QAC1D,4EAA4E;QAC5E,yDAAyD;QACzD,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,QAAQ,GAAG,MAAM;SACpB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;SACnD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,GAAG,MAAM,KAAK,QAAQ,EAAE,CAAC;AAClC,CAAC"}