@openweave/weave-skills 1.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -0
  3. package/dist/config-loader.d.ts +52 -0
  4. package/dist/config-loader.d.ts.map +1 -0
  5. package/dist/config-loader.js +123 -0
  6. package/dist/config-loader.js.map +1 -0
  7. package/dist/index.d.ts +12 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +14 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/skill-registry.d.ts +96 -0
  12. package/dist/skill-registry.d.ts.map +1 -0
  13. package/dist/skill-registry.js +218 -0
  14. package/dist/skill-registry.js.map +1 -0
  15. package/dist/skills/auto-fix.d.ts +35 -0
  16. package/dist/skills/auto-fix.d.ts.map +1 -0
  17. package/dist/skills/auto-fix.js +121 -0
  18. package/dist/skills/auto-fix.js.map +1 -0
  19. package/dist/skills/cli-interactive.d.ts +60 -0
  20. package/dist/skills/cli-interactive.d.ts.map +1 -0
  21. package/dist/skills/cli-interactive.js +264 -0
  22. package/dist/skills/cli-interactive.js.map +1 -0
  23. package/dist/skills/code-review.d.ts +39 -0
  24. package/dist/skills/code-review.d.ts.map +1 -0
  25. package/dist/skills/code-review.js +204 -0
  26. package/dist/skills/code-review.js.map +1 -0
  27. package/dist/skills/commit-composer.d.ts +51 -0
  28. package/dist/skills/commit-composer.d.ts.map +1 -0
  29. package/dist/skills/commit-composer.js +223 -0
  30. package/dist/skills/commit-composer.js.map +1 -0
  31. package/dist/skills/container-advisor.d.ts +43 -0
  32. package/dist/skills/container-advisor.d.ts.map +1 -0
  33. package/dist/skills/container-advisor.js +274 -0
  34. package/dist/skills/container-advisor.js.map +1 -0
  35. package/dist/skills/context-memory.d.ts +44 -0
  36. package/dist/skills/context-memory.d.ts.map +1 -0
  37. package/dist/skills/context-memory.js +160 -0
  38. package/dist/skills/context-memory.js.map +1 -0
  39. package/dist/skills/dep-audit.d.ts +55 -0
  40. package/dist/skills/dep-audit.d.ts.map +1 -0
  41. package/dist/skills/dep-audit.js +248 -0
  42. package/dist/skills/dep-audit.js.map +1 -0
  43. package/dist/skills/deploy-provision.d.ts +47 -0
  44. package/dist/skills/deploy-provision.d.ts.map +1 -0
  45. package/dist/skills/deploy-provision.js +270 -0
  46. package/dist/skills/deploy-provision.js.map +1 -0
  47. package/dist/skills/docs-gen.d.ts +36 -0
  48. package/dist/skills/docs-gen.d.ts.map +1 -0
  49. package/dist/skills/docs-gen.js +187 -0
  50. package/dist/skills/docs-gen.js.map +1 -0
  51. package/dist/skills/index.d.ts +19 -0
  52. package/dist/skills/index.d.ts.map +1 -0
  53. package/dist/skills/index.js +55 -0
  54. package/dist/skills/index.js.map +1 -0
  55. package/dist/skills/multi-repo.d.ts +50 -0
  56. package/dist/skills/multi-repo.d.ts.map +1 -0
  57. package/dist/skills/multi-repo.js +175 -0
  58. package/dist/skills/multi-repo.js.map +1 -0
  59. package/dist/skills/onboarding.d.ts +48 -0
  60. package/dist/skills/onboarding.d.ts.map +1 -0
  61. package/dist/skills/onboarding.js +245 -0
  62. package/dist/skills/onboarding.js.map +1 -0
  63. package/dist/skills/perf-profile.d.ts +36 -0
  64. package/dist/skills/perf-profile.d.ts.map +1 -0
  65. package/dist/skills/perf-profile.js +179 -0
  66. package/dist/skills/perf-profile.js.map +1 -0
  67. package/dist/skills/pipeline-aware.d.ts +33 -0
  68. package/dist/skills/pipeline-aware.d.ts.map +1 -0
  69. package/dist/skills/pipeline-aware.js +226 -0
  70. package/dist/skills/pipeline-aware.js.map +1 -0
  71. package/dist/skills/refactor.d.ts +33 -0
  72. package/dist/skills/refactor.d.ts.map +1 -0
  73. package/dist/skills/refactor.js +210 -0
  74. package/dist/skills/refactor.js.map +1 -0
  75. package/dist/skills/test-gen.d.ts +36 -0
  76. package/dist/skills/test-gen.d.ts.map +1 -0
  77. package/dist/skills/test-gen.js +154 -0
  78. package/dist/skills/test-gen.js.map +1 -0
  79. package/dist/types.d.ts +133 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +8 -0
  82. package/dist/types.js.map +1 -0
  83. package/package.json +39 -0
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Skill: commit-composer
3
+ *
4
+ * Analyses `git diff --staged` and proposes a Conventional Commits message.
5
+ * No LLM required — pure pattern-matching on diff hunks.
6
+ *
7
+ * Conventional format: <type>(<scope>): <description>
8
+ * [optional body]
9
+ * [optional footer: BREAKING CHANGE: ...]
10
+ *
11
+ * Types detected: feat, fix, docs, style, refactor, test, chore, perf, ci, build
12
+ *
13
+ * Input (via SkillContext.graph):
14
+ * - `ctx.graph['diff']` — staged diff string (injectable for tests)
15
+ * - `ctx.graph['stagedFiles']` — string[] (overrides ctx.git?.stagedFiles)
16
+ *
17
+ * Output data:
18
+ * - CommitComposerResult
19
+ */
20
+ import { execSync } from 'node:child_process';
21
+ export function parseDiffStats(diff) {
22
+ const additions = (diff.match(/^\+[^+]/gm) ?? []).length;
23
+ const deletions = (diff.match(/^-[^-]/gm) ?? []).length;
24
+ const filesChanged = [];
25
+ for (const m of diff.matchAll(/^(?:---|\+\+\+) (?:a\/|b\/)?(.+)$/gm)) {
26
+ const f = m[1].trim();
27
+ if (f !== '/dev/null' && !filesChanged.includes(f)) {
28
+ filesChanged.push(f);
29
+ }
30
+ }
31
+ return { additions, deletions, filesChanged };
32
+ }
33
+ export function detectScope(files) {
34
+ if (files.length === 0)
35
+ return null;
36
+ // pnpm workspace package scope
37
+ const pkgMatch = files[0].match(/^(?:packages|apps)\/([^/]+)\//);
38
+ if (pkgMatch) {
39
+ const pkg = pkgMatch[1];
40
+ // strip weave- prefix for brevity
41
+ return pkg.replace(/^weave-/, '');
42
+ }
43
+ // top-level directory scope
44
+ const topDir = files[0].split('/')[0];
45
+ if (topDir && topDir !== files[0])
46
+ return topDir;
47
+ return null;
48
+ }
49
+ const TYPE_RULES = [
50
+ {
51
+ type: 'test',
52
+ patterns: [/\.test\.[tj]sx?$/, /\.spec\.[tj]sx?$/, /__tests__\//],
53
+ },
54
+ {
55
+ type: 'docs',
56
+ patterns: [/\.md$/, /docs\//],
57
+ },
58
+ {
59
+ type: 'ci',
60
+ patterns: [/\.github\//, /\.gitlab-ci\.yml/, /ci\//],
61
+ },
62
+ {
63
+ type: 'build',
64
+ patterns: [/tsconfig/, /package\.json$/, /vite\.config/, /webpack/, /rollup/],
65
+ },
66
+ {
67
+ type: 'style',
68
+ patterns: [/\.css$/, /\.scss$/, /\.less$/, /\.svg$/, /\.png$/],
69
+ },
70
+ {
71
+ type: 'chore',
72
+ patterns: [/\.gitignore$/, /\.npmrc$/, /\.env/, /pnpm-lock/],
73
+ },
74
+ ];
75
+ export function detectType(files, diff) {
76
+ // If all files match a specific type, use it
77
+ for (const rule of TYPE_RULES) {
78
+ if (files.length > 0 && files.every((f) => rule.patterns.some((p) => p.test(f)))) {
79
+ return rule.type;
80
+ }
81
+ }
82
+ // Check diff content for semantic clues
83
+ const addedLines = diff
84
+ .split('\n')
85
+ .filter((l) => l.startsWith('+') && !l.startsWith('+++'))
86
+ .join('\n');
87
+ const isFeature = /\bexport\s+(function|class|const|interface|type)\b/.test(addedLines) ||
88
+ /\bnew\s+\w+\s*\(/.test(addedLines);
89
+ const isFix = /\b(fix|bug|error|exception|catch|throw)\b/i.test(addedLines) ||
90
+ /\b(null|undefined)\s*\?\?/.test(addedLines);
91
+ const isRefactor = /\bextract|rename|move|reorganize|simplify\b/i.test(addedLines);
92
+ const isPerf = /\bcache|memoize|debounce|throttle|optimize\b/i.test(addedLines);
93
+ if (isPerf)
94
+ return 'perf';
95
+ if (isFix)
96
+ return 'fix';
97
+ if (isRefactor)
98
+ return 'refactor';
99
+ if (isFeature)
100
+ return 'feat';
101
+ return 'chore';
102
+ }
103
+ export function detectBreakingChange(diff) {
104
+ const removedLines = diff
105
+ .split('\n')
106
+ .filter((l) => l.startsWith('-') && !l.startsWith('---'))
107
+ .join('\n');
108
+ // Removed exports = potentially breaking
109
+ if (/^-\s*export\s+(function|class|const|interface|type)\s+\w+/m.test(removedLines)) {
110
+ return { breaking: true, note: 'Removed public export — downstream consumers may break' };
111
+ }
112
+ // Removed function parameters
113
+ if (/^-.*function\s+\w+\s*\([^)]+\)/m.test(removedLines)) {
114
+ return { breaking: true, note: 'Changed function signature' };
115
+ }
116
+ // BREAKING CHANGE in commit note markers already in diff
117
+ if (/BREAKING[\s_-]CHANGE/i.test(diff)) {
118
+ return { breaking: true, note: 'Breaking change marked in source' };
119
+ }
120
+ return { breaking: false, note: null };
121
+ }
122
+ export function buildDescription(type, _scope, _stats, files) {
123
+ const mainFile = files[0] ?? 'codebase';
124
+ const base = mainFile.replace(/^.*\//, '').replace(/\.[tj]sx?$/, '');
125
+ const descriptions = {
126
+ feat: `add ${base}`,
127
+ fix: `resolve issue in ${base}`,
128
+ docs: `update documentation`,
129
+ style: `apply style changes`,
130
+ refactor: `refactor ${base}`,
131
+ test: `add tests for ${base}`,
132
+ chore: `update project config`,
133
+ perf: `improve performance of ${base}`,
134
+ ci: `update CI/CD configuration`,
135
+ build: `update build configuration`,
136
+ };
137
+ return descriptions[type];
138
+ }
139
+ // ---------------------------------------------------------------------------
140
+ // Skill
141
+ // ---------------------------------------------------------------------------
142
+ export const commitComposerSkill = {
143
+ id: 'commit-composer',
144
+ name: 'Commit Message Composer',
145
+ description: 'Analyses staged git diff and proposes a Conventional Commits message with type, scope and description.',
146
+ version: '1.0.0',
147
+ enabled: true,
148
+ tags: ['git', 'dx', 'commit'],
149
+ async execute(ctx) {
150
+ const graph = (ctx.graph ?? {});
151
+ // --- Get diff ---
152
+ let diff = '';
153
+ if (typeof graph['diff'] === 'string') {
154
+ diff = graph['diff'];
155
+ }
156
+ else {
157
+ try {
158
+ diff = execSync('git diff --staged', {
159
+ cwd: ctx.projectRoot,
160
+ encoding: 'utf8',
161
+ timeout: 10_000,
162
+ });
163
+ }
164
+ catch {
165
+ return {
166
+ success: false,
167
+ output: 'Failed to read staged diff — is this a git repository with staged changes?',
168
+ error: 'git diff --staged failed',
169
+ };
170
+ }
171
+ }
172
+ if (!diff.trim()) {
173
+ return {
174
+ success: false,
175
+ output: 'No staged changes found. Stage files with `git add` before composing a commit.',
176
+ error: 'empty diff',
177
+ };
178
+ }
179
+ const stats = parseDiffStats(diff);
180
+ // --- File list ---
181
+ const stagedFiles = Array.isArray(graph['stagedFiles'])
182
+ ? graph['stagedFiles']
183
+ : (ctx.git?.stagedFiles ?? stats.filesChanged);
184
+ const type = detectType(stagedFiles, diff);
185
+ const scope = detectScope(stagedFiles);
186
+ const description = buildDescription(type, scope, stats, stagedFiles);
187
+ const { breaking, note } = detectBreakingChange(diff);
188
+ // Build message
189
+ const header = scope
190
+ ? `${type}(${scope}): ${description}`
191
+ : `${type}: ${description}`;
192
+ const bodyLines = [];
193
+ if (stats.filesChanged.length > 1) {
194
+ bodyLines.push(`Changed ${stats.filesChanged.length} files (+${stats.additions}/-${stats.deletions} lines)`);
195
+ }
196
+ if (breaking && note) {
197
+ bodyLines.push('', `BREAKING CHANGE: ${note}`);
198
+ }
199
+ const suggestedMessage = bodyLines.length > 0
200
+ ? `${header}\n\n${bodyLines.join('\n')}`
201
+ : header;
202
+ const result = {
203
+ suggestedMessage,
204
+ type,
205
+ scope,
206
+ description,
207
+ breakingChange: breaking,
208
+ breakingChangeNote: note,
209
+ changedFiles: stagedFiles,
210
+ stats: {
211
+ additions: stats.additions,
212
+ deletions: stats.deletions,
213
+ filesChanged: stats.filesChanged.length,
214
+ },
215
+ };
216
+ return {
217
+ success: true,
218
+ output: `Suggested commit: "${header}"${breaking ? ' ⚠️ BREAKING CHANGE' : ''}`,
219
+ data: result,
220
+ };
221
+ },
222
+ };
223
+ //# sourceMappingURL=commit-composer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-composer.js","sourceRoot":"","sources":["../../src/skills/commit-composer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Skill: container-advisor
3
+ *
4
+ * Audits Dockerfile(s) against a best-practice checklist and produces a
5
+ * structured report with pass/fail per check plus remediation snippets.
6
+ *
7
+ * Checks:
8
+ * 1. Multi-stage build — at least 2 FROM instructions
9
+ * 2. Non-root user — USER instruction present (not root/0)
10
+ * 3. HEALTHCHECK — HEALTHCHECK instruction defined
11
+ * 4. Pinned base image — FROM uses a tag other than "latest" or no-tag
12
+ * 5. Minimal COPY scope — no bare `COPY . .` (copies entire context)
13
+ * 6. No sudo usage — RUN sudo ... is a smell
14
+ * 7. No secrets in ENV — ENV key=value with secret-like name
15
+ * 8. Explicit WORKDIR — WORKDIR instruction set before COPY/RUN
16
+ * 9. No `apt-get upgrade` — unpinned system upgrade → non-reproducible
17
+ * 10. Combined RUN layers — multiple consecutive RUN instructions (layer bloat)
18
+ *
19
+ * Input options (ctx.graph):
20
+ * - `dockerfileContent` {string} — inject Dockerfile text (tests)
21
+ * - `dockerfilePath` {string} — path relative to projectRoot
22
+ */
23
+ import type { SkillModule } from '../types.js';
24
+ export type CheckStatus = 'pass' | 'fail' | 'warn' | 'skip';
25
+ export interface DockerCheck {
26
+ id: string;
27
+ title: string;
28
+ status: CheckStatus;
29
+ severity: 'error' | 'warning' | 'info';
30
+ details: string;
31
+ remediation: string;
32
+ }
33
+ export interface ContainerReport {
34
+ dockerfilePath: string;
35
+ checks: DockerCheck[];
36
+ score: number;
37
+ errors: number;
38
+ warnings: number;
39
+ summary: string;
40
+ }
41
+ export declare function auditDockerfile(content: string, filePath?: string): ContainerReport;
42
+ export declare const containerAdvisorSkill: SkillModule;
43
+ //# sourceMappingURL=container-advisor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-advisor.d.ts","sourceRoot":"","sources":["../../src/skills/container-advisor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,aAAa,CAAC;AAM1E,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AA2LD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAe,GAAG,eAAe,CAgCzF;AAMD,eAAO,MAAM,qBAAqB,EAAE,WAoDnC,CAAC"}
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Skill: container-advisor
3
+ *
4
+ * Audits Dockerfile(s) against a best-practice checklist and produces a
5
+ * structured report with pass/fail per check plus remediation snippets.
6
+ *
7
+ * Checks:
8
+ * 1. Multi-stage build — at least 2 FROM instructions
9
+ * 2. Non-root user — USER instruction present (not root/0)
10
+ * 3. HEALTHCHECK — HEALTHCHECK instruction defined
11
+ * 4. Pinned base image — FROM uses a tag other than "latest" or no-tag
12
+ * 5. Minimal COPY scope — no bare `COPY . .` (copies entire context)
13
+ * 6. No sudo usage — RUN sudo ... is a smell
14
+ * 7. No secrets in ENV — ENV key=value with secret-like name
15
+ * 8. Explicit WORKDIR — WORKDIR instruction set before COPY/RUN
16
+ * 9. No `apt-get upgrade` — unpinned system upgrade → non-reproducible
17
+ * 10. Combined RUN layers — multiple consecutive RUN instructions (layer bloat)
18
+ *
19
+ * Input options (ctx.graph):
20
+ * - `dockerfileContent` {string} — inject Dockerfile text (tests)
21
+ * - `dockerfilePath` {string} — path relative to projectRoot
22
+ */
23
+ import { existsSync, readFileSync } from 'node:fs';
24
+ import { join } from 'node:path';
25
+ // ---------------------------------------------------------------------------
26
+ // Individual check implementations
27
+ // ---------------------------------------------------------------------------
28
+ function checkMultiStage(lines) {
29
+ const fromCount = lines.filter((l) => /^FROM\s+/i.test(l.trim())).length;
30
+ return fromCount >= 2 ? 'pass' : 'fail';
31
+ }
32
+ function checkNonRootUser(lines) {
33
+ const userLine = lines.find((l) => /^USER\s+/i.test(l.trim()));
34
+ if (!userLine)
35
+ return 'fail';
36
+ const val = userLine.replace(/^USER\s+/i, '').trim().toLowerCase();
37
+ if (val === 'root' || val === '0')
38
+ return 'fail';
39
+ return 'pass';
40
+ }
41
+ function checkHealthcheck(lines) {
42
+ return lines.some((l) => /^HEALTHCHECK\s+/i.test(l.trim())) ? 'pass' : 'warn';
43
+ }
44
+ function checkPinnedBase(lines) {
45
+ const froms = lines.filter((l) => /^FROM\s+/i.test(l.trim()));
46
+ for (const from of froms) {
47
+ const image = from.replace(/^FROM\s+/i, '').split(/\s+/)[0];
48
+ if (image === 'scratch')
49
+ continue; // scratch is fine
50
+ if (!image.includes(':'))
51
+ return 'fail'; // no tag at all
52
+ if (image.endsWith(':latest'))
53
+ return 'fail'; // latest is unpinned
54
+ }
55
+ return 'pass';
56
+ }
57
+ function checkCopyScope(lines) {
58
+ // Bare "COPY . ." or "COPY . /" copies entire context
59
+ return lines.some((l) => /^COPY\s+\.\s+[./]/i.test(l.trim())) ? 'warn' : 'pass';
60
+ }
61
+ function checkNoSudo(lines) {
62
+ return lines.some((l) => /^RUN\b.+\bsudo\b/i.test(l.trim())) ? 'warn' : 'pass';
63
+ }
64
+ function checkNoSecretsInEnv(lines) {
65
+ const SECRET_KEYS = /\b(password|passwd|secret|api_?key|token|private_?key|auth)\s*=/i;
66
+ return lines.some((l) => /^ENV\s+/i.test(l.trim()) && SECRET_KEYS.test(l)) ? 'fail' : 'pass';
67
+ }
68
+ function checkWorkdir(lines) {
69
+ const instrs = lines.map((l) => l.trim()).filter((l) => /^(COPY|RUN|WORKDIR)\s+/i.test(l));
70
+ // WORKDIR should come before first COPY or RUN
71
+ const firstCopyRun = instrs.findIndex((l) => /^(COPY|RUN)\s+/i.test(l));
72
+ const firstWorkdir = instrs.findIndex((l) => /^WORKDIR\s+/i.test(l));
73
+ if (firstWorkdir === -1)
74
+ return 'fail';
75
+ if (firstCopyRun === -1)
76
+ return 'pass';
77
+ return firstWorkdir < firstCopyRun ? 'pass' : 'warn';
78
+ }
79
+ function checkNoAptUpgrade(lines) {
80
+ return lines.some((l) => /apt-get\s+upgrade\b/i.test(l)) ? 'warn' : 'pass';
81
+ }
82
+ function checkRunLayers(lines) {
83
+ let consecutive = 0;
84
+ let maxConsecutive = 0;
85
+ for (const l of lines) {
86
+ if (/^RUN\s+/i.test(l.trim())) {
87
+ consecutive++;
88
+ maxConsecutive = Math.max(maxConsecutive, consecutive);
89
+ }
90
+ else if (l.trim().length > 0 && !l.trim().startsWith('#')) {
91
+ consecutive = 0;
92
+ }
93
+ }
94
+ return maxConsecutive >= 3 ? 'warn' : 'pass';
95
+ }
96
+ const CHECKS = [
97
+ {
98
+ id: 'multi-stage',
99
+ title: 'Multi-stage build',
100
+ severity: 'error',
101
+ run: checkMultiStage,
102
+ failDetails: 'Only one FROM instruction found — single-stage build ships build tools to production.',
103
+ warnDetails: '',
104
+ remediation: 'Split into builder and final stages:\n FROM node:22-alpine AS builder\n RUN npm ci && npm run build\n FROM node:22-alpine\n COPY --from=builder /app/dist ./dist',
105
+ },
106
+ {
107
+ id: 'non-root-user',
108
+ title: 'Non-root USER',
109
+ severity: 'error',
110
+ run: checkNonRootUser,
111
+ failDetails: 'Container runs as root — a container escape would grant host root access.',
112
+ warnDetails: '',
113
+ remediation: 'Add before CMD/ENTRYPOINT:\n RUN addgroup -S appgroup && adduser -S appuser -G appgroup\n USER appuser',
114
+ },
115
+ {
116
+ id: 'healthcheck',
117
+ title: 'HEALTHCHECK defined',
118
+ severity: 'warning',
119
+ run: checkHealthcheck,
120
+ failDetails: '',
121
+ warnDetails: 'No HEALTHCHECK instruction — orchestrators (Docker Swarm, ECS) cannot detect unhealthy containers.',
122
+ remediation: 'Add:\n HEALTHCHECK --interval=30s --timeout=5s --retries=3 \\\n CMD wget -qO- http://localhost:3000/health || exit 1',
123
+ },
124
+ {
125
+ id: 'pinned-base',
126
+ title: 'Pinned base image version',
127
+ severity: 'error',
128
+ run: checkPinnedBase,
129
+ failDetails: 'Base image uses `:latest` or has no tag — builds are not reproducible.',
130
+ warnDetails: '',
131
+ remediation: 'Use a specific digest or version tag:\n FROM node:22.12.0-alpine3.21',
132
+ },
133
+ {
134
+ id: 'copy-scope',
135
+ title: 'Scoped COPY (no `COPY . .`)',
136
+ severity: 'warning',
137
+ run: checkCopyScope,
138
+ failDetails: '',
139
+ warnDetails: '`COPY . .` copies the entire build context including secrets, .git, node_modules.',
140
+ remediation: 'Use a .dockerignore and copy only what the image needs:\n COPY package.json pnpm-lock.yaml ./\n COPY src/ ./src/',
141
+ },
142
+ {
143
+ id: 'no-sudo',
144
+ title: 'No sudo in RUN',
145
+ severity: 'warning',
146
+ run: checkNoSudo,
147
+ failDetails: '',
148
+ warnDetails: '`sudo` in RUN layers is a smell — the build user should already have required permissions.',
149
+ remediation: 'Grant permissions during image build or switch USER instead of using sudo at runtime.',
150
+ },
151
+ {
152
+ id: 'no-secrets-env',
153
+ title: 'No secrets in ENV',
154
+ severity: 'error',
155
+ run: checkNoSecretsInEnv,
156
+ failDetails: 'Secret-like key found in ENV instruction — secrets baked into layers are extractable via `docker history`.',
157
+ warnDetails: '',
158
+ remediation: 'Pass secrets at runtime via environment variables or Docker secrets:\n docker run -e API_KEY=$API_KEY myimage',
159
+ },
160
+ {
161
+ id: 'explicit-workdir',
162
+ title: 'WORKDIR set before COPY/RUN',
163
+ severity: 'warning',
164
+ run: checkWorkdir,
165
+ failDetails: 'No WORKDIR set — files are placed in root (/) by default.',
166
+ warnDetails: 'WORKDIR defined after COPY/RUN — early instructions run in an unexpected directory.',
167
+ remediation: 'Set WORKDIR early:\n WORKDIR /app',
168
+ },
169
+ {
170
+ id: 'no-apt-upgrade',
171
+ title: 'No `apt-get upgrade`',
172
+ severity: 'warning',
173
+ run: checkNoAptUpgrade,
174
+ failDetails: '',
175
+ warnDetails: '`apt-get upgrade` upgrades all packages to unspecified versions — breaks reproducibility.',
176
+ remediation: 'Pin specific package versions or use a freshly pulled base image instead.',
177
+ },
178
+ {
179
+ id: 'run-layers',
180
+ title: 'Minimal RUN layers',
181
+ severity: 'warning',
182
+ run: checkRunLayers,
183
+ failDetails: '',
184
+ warnDetails: '3+ consecutive RUN instructions detected — each adds a layer that increases image size.',
185
+ remediation: 'Chain RUN instructions with &&:\n RUN npm ci \\\n && npm run build \\\n && rm -rf node_modules',
186
+ },
187
+ ];
188
+ // ---------------------------------------------------------------------------
189
+ // Main audit function
190
+ // ---------------------------------------------------------------------------
191
+ export function auditDockerfile(content, filePath = 'Dockerfile') {
192
+ const lines = content.split('\n');
193
+ const checks = [];
194
+ for (const def of CHECKS) {
195
+ const status = def.run(lines);
196
+ let details = '';
197
+ if (status === 'fail')
198
+ details = def.failDetails;
199
+ else if (status === 'warn')
200
+ details = def.warnDetails;
201
+ checks.push({
202
+ id: def.id,
203
+ title: def.title,
204
+ status,
205
+ severity: def.severity,
206
+ details,
207
+ remediation: status !== 'pass' ? def.remediation : '',
208
+ });
209
+ }
210
+ const errors = checks.filter((c) => c.status === 'fail' && c.severity === 'error').length;
211
+ const warnings = checks.filter((c) => (c.status === 'fail' || c.status === 'warn') && c.severity === 'warning').length;
212
+ const passed = checks.filter((c) => c.status === 'pass').length;
213
+ const score = Math.round((passed / checks.length) * 100);
214
+ const summary = errors > 0
215
+ ? `❌ ${errors} error(s), ${warnings} warning(s) — score: ${score}/100`
216
+ : warnings > 0
217
+ ? `⚠️ ${warnings} warning(s) — score: ${score}/100`
218
+ : `✅ All checks passed — score: ${score}/100`;
219
+ return { dockerfilePath: filePath, checks, score, errors, warnings, summary };
220
+ }
221
+ // ---------------------------------------------------------------------------
222
+ // Skill
223
+ // ---------------------------------------------------------------------------
224
+ export const containerAdvisorSkill = {
225
+ id: 'container-advisor',
226
+ name: 'Container Advisor',
227
+ description: 'Audits Dockerfiles against 10 best-practice checks (multi-stage, non-root, HEALTHCHECK, pinned base, etc.)',
228
+ version: '1.0.0',
229
+ enabled: false,
230
+ tags: ['devops', 'docker'],
231
+ async execute(ctx) {
232
+ const opts = ctx.graph ?? {};
233
+ let content = '';
234
+ let filePath = 'Dockerfile';
235
+ if (typeof opts['dockerfileContent'] === 'string') {
236
+ content = opts['dockerfileContent'];
237
+ }
238
+ else {
239
+ const rel = typeof opts['dockerfilePath'] === 'string' ? opts['dockerfilePath'] : 'Dockerfile';
240
+ filePath = join(ctx.projectRoot, rel);
241
+ if (!existsSync(filePath)) {
242
+ return {
243
+ success: false,
244
+ output: `❌ Dockerfile not found at ${filePath}`,
245
+ error: 'dockerfile not found',
246
+ };
247
+ }
248
+ content = readFileSync(filePath, 'utf-8');
249
+ }
250
+ const report = auditDockerfile(content, filePath);
251
+ const lines = [
252
+ `🐳 Container Advisor — ${report.dockerfilePath}`,
253
+ ` ${report.summary}`,
254
+ '',
255
+ ];
256
+ for (const c of report.checks) {
257
+ const icon = c.status === 'pass' ? '✅' : c.status === 'fail' ? '❌' : '⚠️ ';
258
+ lines.push(` ${icon} ${c.title}`);
259
+ if (c.details)
260
+ lines.push(` ${c.details}`);
261
+ if (c.remediation) {
262
+ lines.push(` 💡 Remediation:`);
263
+ for (const rl of c.remediation.split('\n'))
264
+ lines.push(` ${rl}`);
265
+ }
266
+ }
267
+ return {
268
+ success: report.errors === 0,
269
+ output: lines.join('\n'),
270
+ data: report,
271
+ };
272
+ },
273
+ };
274
+ //# sourceMappingURL=container-advisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-advisor.js","sourceRoot":"","sources":["../../src/skills/container-advisor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Skill: context-memory
3
+ *
4
+ * Persists architectural decisions, team agreements and agent reasoning sessions
5
+ * into the WeaveGraph knowledge graph for long-term cross-session memory.
6
+ *
7
+ * Actions:
8
+ * - save — persist a new memory entry as a graph node
9
+ * - load — retrieve entries by id or tag
10
+ * - list — list all persisted memory entries (optionally filtered by type/tag)
11
+ *
12
+ * Input (via SkillContext.graph):
13
+ * - `ctx.graph['action']` — 'save' | 'load' | 'list' (default: 'list')
14
+ * - `ctx.graph['entry']` — MemoryEntry (required for 'save')
15
+ * - `ctx.graph['query']` — string keyword for 'load'
16
+ * - `ctx.graph['store']` — Record<string,MemoryEntry> injectable in-memory store for tests
17
+ *
18
+ * Output data:
19
+ * - ContextMemoryResult
20
+ */
21
+ import type { SkillModule } from '../types.js';
22
+ export type MemoryEntryType = 'decision' | 'agreement' | 'reasoning' | 'constraint' | 'pattern' | 'note';
23
+ export interface MemoryEntry {
24
+ id: string;
25
+ type: MemoryEntryType;
26
+ title: string;
27
+ content: string;
28
+ tags: string[];
29
+ createdAt: string;
30
+ sessionId?: string;
31
+ }
32
+ export interface ContextMemoryResult {
33
+ action: 'save' | 'load' | 'list';
34
+ saved?: MemoryEntry;
35
+ entries: MemoryEntry[];
36
+ total: number;
37
+ query?: string;
38
+ }
39
+ export declare function generateId(entry: Omit<MemoryEntry, 'id'>): string;
40
+ export declare function matchesQuery(entry: MemoryEntry, query: string): boolean;
41
+ export declare function saveEntry(store: Map<string, MemoryEntry>, raw: Partial<MemoryEntry>, sessionId?: string): MemoryEntry;
42
+ export declare function listEntries(store: Map<string, MemoryEntry>, query?: string, type?: MemoryEntryType): MemoryEntry[];
43
+ export declare const contextMemorySkill: SkillModule;
44
+ //# sourceMappingURL=context-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-memory.d.ts","sourceRoot":"","sources":["../../src/skills/context-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,aAAa,CAAC;AAM1E,MAAM,MAAM,eAAe,GACvB,UAAU,GACV,WAAW,GACX,WAAW,GACX,YAAY,GACZ,SAAS,GACT,MAAM,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AASD,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,MAAM,CAOjE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAQvE;AAED,wBAAgB,SAAS,CACvB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EAC/B,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,WAAW,CAgBb;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EAC/B,KAAK,CAAC,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,eAAe,GACrB,WAAW,EAAE,CAKf;AAsBD,eAAO,MAAM,kBAAkB,EAAE,WAiGhC,CAAC"}