peaks-cli 1.0.11 → 1.0.13

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 (94) hide show
  1. package/bin/peaks.js +0 -0
  2. package/dist/src/cli/commands/core-artifact-commands.js +23 -0
  3. package/dist/src/cli/commands/mcp-commands.d.ts +3 -0
  4. package/dist/src/cli/commands/mcp-commands.js +144 -0
  5. package/dist/src/cli/commands/openspec-commands.d.ts +3 -0
  6. package/dist/src/cli/commands/openspec-commands.js +169 -0
  7. package/dist/src/cli/commands/project-commands.d.ts +3 -0
  8. package/dist/src/cli/commands/project-commands.js +37 -0
  9. package/dist/src/cli/commands/request-commands.d.ts +3 -0
  10. package/dist/src/cli/commands/request-commands.js +140 -0
  11. package/dist/src/cli/commands/understand-commands.d.ts +3 -0
  12. package/dist/src/cli/commands/understand-commands.js +78 -0
  13. package/dist/src/cli/program.js +10 -0
  14. package/dist/src/services/artifacts/request-artifact-service.d.ts +58 -0
  15. package/dist/src/services/artifacts/request-artifact-service.js +432 -0
  16. package/dist/src/services/dashboard/project-dashboard-service.d.ts +64 -0
  17. package/dist/src/services/dashboard/project-dashboard-service.js +112 -0
  18. package/dist/src/services/doctor/doctor-service.d.ts +7 -0
  19. package/dist/src/services/doctor/doctor-service.js +139 -0
  20. package/dist/src/services/mcp/mcp-apply-service.d.ts +31 -0
  21. package/dist/src/services/mcp/mcp-apply-service.js +112 -0
  22. package/dist/src/services/mcp/mcp-call-service.d.ts +17 -0
  23. package/dist/src/services/mcp/mcp-call-service.js +34 -0
  24. package/dist/src/services/mcp/mcp-client-service.d.ts +14 -0
  25. package/dist/src/services/mcp/mcp-client-service.js +49 -0
  26. package/dist/src/services/mcp/mcp-install-registry.d.ts +11 -0
  27. package/dist/src/services/mcp/mcp-install-registry.js +38 -0
  28. package/dist/src/services/mcp/mcp-plan-service.d.ts +29 -0
  29. package/dist/src/services/mcp/mcp-plan-service.js +109 -0
  30. package/dist/src/services/mcp/mcp-protocol.d.ts +24 -0
  31. package/dist/src/services/mcp/mcp-protocol.js +41 -0
  32. package/dist/src/services/mcp/mcp-scan-service.d.ts +8 -0
  33. package/dist/src/services/mcp/mcp-scan-service.js +214 -0
  34. package/dist/src/services/mcp/mcp-stdio-transport.d.ts +10 -0
  35. package/dist/src/services/mcp/mcp-stdio-transport.js +50 -0
  36. package/dist/src/services/mcp/mcp-types.d.ts +31 -0
  37. package/dist/src/services/mcp/mcp-types.js +1 -0
  38. package/dist/src/services/openspec/openspec-archive-service.d.ts +12 -0
  39. package/dist/src/services/openspec/openspec-archive-service.js +28 -0
  40. package/dist/src/services/openspec/openspec-bridge-service.d.ts +16 -0
  41. package/dist/src/services/openspec/openspec-bridge-service.js +76 -0
  42. package/dist/src/services/openspec/openspec-render-service.d.ts +38 -0
  43. package/dist/src/services/openspec/openspec-render-service.js +130 -0
  44. package/dist/src/services/openspec/openspec-scan-service.d.ts +6 -0
  45. package/dist/src/services/openspec/openspec-scan-service.js +123 -0
  46. package/dist/src/services/openspec/openspec-types.d.ts +39 -0
  47. package/dist/src/services/openspec/openspec-types.js +1 -0
  48. package/dist/src/services/openspec/openspec-validate-service.d.ts +27 -0
  49. package/dist/src/services/openspec/openspec-validate-service.js +77 -0
  50. package/dist/src/services/recommendations/capability-seed-items.js +1 -0
  51. package/dist/src/services/skills/skill-runbook-service.d.ts +11 -0
  52. package/dist/src/services/skills/skill-runbook-service.js +60 -0
  53. package/dist/src/services/standards/project-standards-service.js +4 -9
  54. package/dist/src/services/understand/understand-scan-service.d.ts +28 -0
  55. package/dist/src/services/understand/understand-scan-service.js +157 -0
  56. package/dist/src/services/understand/understand-types.d.ts +24 -0
  57. package/dist/src/services/understand/understand-types.js +1 -0
  58. package/dist/src/shared/json-schema-mini.d.ts +10 -0
  59. package/dist/src/shared/json-schema-mini.js +113 -0
  60. package/dist/src/shared/paths.d.ts +1 -1
  61. package/dist/src/shared/paths.js +9 -1
  62. package/dist/src/shared/version.d.ts +1 -1
  63. package/dist/src/shared/version.js +1 -1
  64. package/package.json +1 -6
  65. package/schemas/doctor-report.schema.json +34 -0
  66. package/schemas/mcp-apply-result.schema.json +46 -0
  67. package/schemas/mcp-install-plan.schema.json +71 -0
  68. package/schemas/mcp-install-spec.schema.json +29 -0
  69. package/schemas/mcp-server.schema.json +29 -0
  70. package/schemas/openspec-change-summary.schema.json +68 -0
  71. package/schemas/openspec-render-request.schema.json +61 -0
  72. package/schemas/openspec-validation-result.schema.json +36 -0
  73. package/skills/peaks-prd/SKILL.md +59 -8
  74. package/skills/peaks-prd/references/artifact-per-request.md +78 -0
  75. package/skills/peaks-prd/references/workflow.md +7 -5
  76. package/skills/peaks-qa/SKILL.md +73 -7
  77. package/skills/peaks-qa/references/artifact-contracts.md +1 -1
  78. package/skills/peaks-qa/references/artifact-per-request.md +83 -0
  79. package/skills/peaks-qa/references/openspec-validation-gate.md +55 -0
  80. package/skills/peaks-qa/references/regression-gates.md +1 -1
  81. package/skills/peaks-rd/SKILL.md +94 -7
  82. package/skills/peaks-rd/references/artifact-per-request.md +90 -0
  83. package/skills/peaks-rd/references/openspec-mcp-cli.md +65 -0
  84. package/skills/peaks-sc/SKILL.md +44 -0
  85. package/skills/peaks-sc/references/openspec-commit-boundaries.md +33 -0
  86. package/skills/peaks-solo/SKILL.md +87 -4
  87. package/skills/peaks-solo/references/browser-workflow.md +114 -0
  88. package/skills/peaks-solo/references/external-skill-invocation.md +70 -0
  89. package/skills/peaks-solo/references/openspec-mcp-workflow.md +53 -0
  90. package/skills/peaks-solo/references/workflow.md +1 -1
  91. package/skills/peaks-txt/SKILL.md +42 -0
  92. package/skills/peaks-ui/SKILL.md +57 -33
  93. package/skills/peaks-ui/references/artifact-per-request.md +71 -0
  94. package/skills/peaks-ui/references/workflow.md +8 -11
@@ -0,0 +1,113 @@
1
+ function joinPath(parent, segment) {
2
+ if (parent === '/') {
3
+ return `/${segment}`;
4
+ }
5
+ return `${parent}/${segment}`;
6
+ }
7
+ function typeOf(value) {
8
+ if (value === null) {
9
+ return 'null';
10
+ }
11
+ if (Array.isArray(value)) {
12
+ return 'array';
13
+ }
14
+ if (Number.isInteger(value)) {
15
+ return 'integer';
16
+ }
17
+ return typeof value;
18
+ }
19
+ function matchesType(value, expected) {
20
+ if (expected === 'integer') {
21
+ return typeof value === 'number' && Number.isFinite(value) && Number.isInteger(value);
22
+ }
23
+ if (expected === 'number') {
24
+ return typeof value === 'number' && Number.isFinite(value);
25
+ }
26
+ if (expected === 'array') {
27
+ return Array.isArray(value);
28
+ }
29
+ if (expected === 'null') {
30
+ return value === null;
31
+ }
32
+ if (expected === 'object') {
33
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
34
+ }
35
+ return typeof value === expected;
36
+ }
37
+ function validateNode(value, schema, path, errors) {
38
+ if (Array.isArray(schema.oneOf)) {
39
+ const branches = schema.oneOf;
40
+ const branchErrors = [];
41
+ let matched = false;
42
+ for (const branch of branches) {
43
+ const sink = [];
44
+ validateNode(value, branch, path, sink);
45
+ if (sink.length === 0) {
46
+ matched = true;
47
+ break;
48
+ }
49
+ branchErrors.push(sink);
50
+ }
51
+ if (!matched) {
52
+ const detail = branchErrors.map((sink) => sink.map((issue) => issue.message).join(' / ')).join(' | ');
53
+ errors.push({ path, message: `does not match any oneOf branch (${detail})` });
54
+ }
55
+ return;
56
+ }
57
+ const expectedType = typeof schema.type === 'string' ? schema.type : null;
58
+ if (expectedType !== null && !matchesType(value, expectedType)) {
59
+ errors.push({ path, message: `expected type ${expectedType}, got ${typeOf(value)}` });
60
+ return;
61
+ }
62
+ if (typeof value === 'string') {
63
+ if (typeof schema.minLength === 'number' && value.length < schema.minLength) {
64
+ errors.push({ path, message: `string shorter than minLength ${schema.minLength}` });
65
+ }
66
+ if (typeof schema.pattern === 'string' && !new RegExp(schema.pattern).test(value)) {
67
+ errors.push({ path, message: `string does not match pattern ${schema.pattern}` });
68
+ }
69
+ if (Array.isArray(schema.enum) && !schema.enum.includes(value)) {
70
+ errors.push({ path, message: `value ${JSON.stringify(value)} is not in enum` });
71
+ }
72
+ return;
73
+ }
74
+ if (typeof value === 'number') {
75
+ if (typeof schema.minimum === 'number' && value < schema.minimum) {
76
+ errors.push({ path, message: `number below minimum ${schema.minimum}` });
77
+ }
78
+ return;
79
+ }
80
+ if (Array.isArray(value)) {
81
+ if (schema.items !== undefined) {
82
+ const itemSchema = schema.items;
83
+ value.forEach((entry, index) => {
84
+ validateNode(entry, itemSchema, joinPath(path, index), errors);
85
+ });
86
+ }
87
+ return;
88
+ }
89
+ if (value !== null && typeof value === 'object') {
90
+ const record = value;
91
+ if (Array.isArray(schema.required)) {
92
+ for (const key of schema.required) {
93
+ if (!Object.prototype.hasOwnProperty.call(record, key)) {
94
+ errors.push({ path, message: `missing required property: ${key}` });
95
+ }
96
+ }
97
+ }
98
+ const properties = schema.properties;
99
+ if (properties !== null && typeof properties === 'object' && !Array.isArray(properties)) {
100
+ const propertyMap = properties;
101
+ for (const [key, child] of Object.entries(propertyMap)) {
102
+ if (Object.prototype.hasOwnProperty.call(record, key)) {
103
+ validateNode(record[key], child, joinPath(path, key), errors);
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ export function validateAgainstSchema(value, schema) {
110
+ const errors = [];
111
+ validateNode(value, schema, '/', errors);
112
+ return { valid: errors.length === 0, errors };
113
+ }
@@ -3,4 +3,4 @@ export declare const skillsDir: string;
3
3
  export declare const schemasDir: string;
4
4
  export declare const templatesDir: string;
5
5
  export declare const requiredSkillNames: readonly ["peaks-solo", "peaks-prd", "peaks-ui", "peaks-rd", "peaks-qa", "peaks-sc", "peaks-txt"];
6
- export declare const requiredSchemaFiles: readonly ["artifact-manifest.schema.json", "context-capsule.schema.json", "approval-record.schema.json", "change-impact.schema.json", "refactor-slice-spec.schema.json", "artifact-retention-report.schema.json", "capability-source.schema.json", "capability-item.schema.json", "capability-availability.schema.json", "recommendation-plan.schema.json", "artifact-workspace.schema.json"];
6
+ export declare const requiredSchemaFiles: readonly ["artifact-manifest.schema.json", "context-capsule.schema.json", "approval-record.schema.json", "change-impact.schema.json", "refactor-slice-spec.schema.json", "artifact-retention-report.schema.json", "capability-source.schema.json", "capability-item.schema.json", "capability-availability.schema.json", "recommendation-plan.schema.json", "artifact-workspace.schema.json", "mcp-server.schema.json", "mcp-install-spec.schema.json", "mcp-install-plan.schema.json", "mcp-apply-result.schema.json", "openspec-change-summary.schema.json", "openspec-render-request.schema.json", "openspec-validation-result.schema.json", "doctor-report.schema.json"];
@@ -36,5 +36,13 @@ export const requiredSchemaFiles = [
36
36
  'capability-item.schema.json',
37
37
  'capability-availability.schema.json',
38
38
  'recommendation-plan.schema.json',
39
- 'artifact-workspace.schema.json'
39
+ 'artifact-workspace.schema.json',
40
+ 'mcp-server.schema.json',
41
+ 'mcp-install-spec.schema.json',
42
+ 'mcp-install-plan.schema.json',
43
+ 'mcp-apply-result.schema.json',
44
+ 'openspec-change-summary.schema.json',
45
+ 'openspec-render-request.schema.json',
46
+ 'openspec-validation-result.schema.json',
47
+ 'doctor-report.schema.json'
40
48
  ];
@@ -1 +1 @@
1
- export declare const CLI_VERSION = "1.0.11";
1
+ export declare const CLI_VERSION = "1.0.13";
@@ -1 +1 @@
1
- export const CLI_VERSION = "1.0.11";
1
+ export const CLI_VERSION = "1.0.13";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peaks-cli",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Peaks CLI and short skill family for Claude Code automation.",
5
5
  "author": "SquabbyZ",
6
6
  "license": "MIT",
@@ -35,7 +35,6 @@
35
35
  "dev:watch": "node ./scripts/watch.mjs",
36
36
  "test": "vitest run",
37
37
  "test:coverage": "vitest run --coverage",
38
- "lint": "eslint eslint.config.js \"bin/**/*.js\" \"scripts/**/*.mjs\" \"src/**/*.ts\" \"tests/**/*.ts\" vitest.config.ts",
39
38
  "typecheck": "tsc -p tsconfig.json --noEmit"
40
39
  },
41
40
  "engines": {
@@ -47,14 +46,10 @@
47
46
  "shadcn": "4.7.0"
48
47
  },
49
48
  "devDependencies": {
50
- "@eslint/js": "^10.0.1",
51
49
  "@types/node": "^22.10.2",
52
50
  "@vitest/coverage-v8": "^2.1.8",
53
- "eslint": "^10.4.0",
54
- "globals": "^17.6.0",
55
51
  "tsx": "^4.19.2",
56
52
  "typescript": "^5.7.2",
57
- "typescript-eslint": "^8.59.4",
58
53
  "vitest": "^2.1.8"
59
54
  }
60
55
  }
@@ -0,0 +1,34 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Peaks Doctor Report",
4
+ "description": "The envelope emitted by `peaks doctor --json` (data field). Each check.id uses a `<prefix>:<target>` form so callers can route follow-up actions per category.",
5
+ "type": "object",
6
+ "required": ["checks", "summary"],
7
+ "properties": {
8
+ "checks": {
9
+ "type": "array",
10
+ "items": {
11
+ "type": "object",
12
+ "required": ["id", "ok", "message"],
13
+ "properties": {
14
+ "id": {
15
+ "type": "string",
16
+ "pattern": "^(skill|skill-name|skill-parse|skill-runbook|skill-apply-note|schema|config|doctor-self|capability):[A-Za-z0-9][A-Za-z0-9._-]*$",
17
+ "description": "Stable check id. Known prefixes: skill:<name> (required skill present), skill-name:<dir> (directory matches declared name), skill-parse:<dir> (skill metadata parsed), skill-runbook:<name> (Default runbook section exists), skill-apply-note:<name> (destructive --apply lines carry an authorization/--dry-run note), schema:<file> (schema file exists and is valid JSON), config:<scope> (optional config locations), doctor-self:<topic> (doctor validates its own output against this schema), capability:<name> (third-party capability is resolvable at the pinned version)."
18
+ },
19
+ "ok": { "type": "boolean" },
20
+ "message": { "type": "string", "minLength": 1 }
21
+ }
22
+ }
23
+ },
24
+ "summary": {
25
+ "type": "object",
26
+ "required": ["ok", "passed", "failed"],
27
+ "properties": {
28
+ "ok": { "type": "boolean" },
29
+ "passed": { "type": "integer", "minimum": 0 },
30
+ "failed": { "type": "integer", "minimum": 0 }
31
+ }
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Peaks MCP Apply Result",
4
+ "type": "object",
5
+ "required": ["capabilityId", "action", "backup", "written", "envCheck"],
6
+ "properties": {
7
+ "capabilityId": { "type": "string", "minLength": 1 },
8
+ "action": {
9
+ "type": "string",
10
+ "enum": ["add", "update", "claimed", "noop"],
11
+ "description": "claimed is returned when an existing non-peaks-managed entry was overwritten with --claim."
12
+ },
13
+ "backup": {
14
+ "type": "object",
15
+ "required": ["path", "skipped"],
16
+ "properties": {
17
+ "path": {
18
+ "oneOf": [
19
+ { "type": "null" },
20
+ { "type": "string", "minLength": 1 }
21
+ ],
22
+ "description": "Absolute path to the backup settings.json copy. Null when no prior settings existed or skipped is true."
23
+ },
24
+ "skipped": {
25
+ "type": "boolean",
26
+ "description": "True when action was noop and no write occurred."
27
+ }
28
+ }
29
+ },
30
+ "written": {
31
+ "type": "object",
32
+ "required": ["settingsPath", "managedMarkerPath"],
33
+ "properties": {
34
+ "settingsPath": { "type": "string", "minLength": 1 },
35
+ "managedMarkerPath": { "type": "string", "minLength": 1 }
36
+ }
37
+ },
38
+ "envCheck": {
39
+ "type": "object",
40
+ "required": ["missing"],
41
+ "properties": {
42
+ "missing": { "type": "array", "items": { "type": "string" } }
43
+ }
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,71 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Peaks MCP Install Plan",
4
+ "type": "object",
5
+ "required": ["capabilityId", "action", "spec", "current", "envCheck", "diff", "nextActions"],
6
+ "properties": {
7
+ "capabilityId": { "type": "string", "minLength": 1 },
8
+ "action": {
9
+ "type": "string",
10
+ "enum": ["add", "update", "noop", "conflict", "unknown-capability"]
11
+ },
12
+ "spec": {
13
+ "oneOf": [
14
+ { "type": "null" },
15
+ { "$ref": "mcp-install-spec.schema.json" }
16
+ ]
17
+ },
18
+ "current": {
19
+ "oneOf": [
20
+ { "type": "null" },
21
+ { "$ref": "mcp-server.schema.json" }
22
+ ]
23
+ },
24
+ "envCheck": {
25
+ "type": "object",
26
+ "required": ["missing"],
27
+ "properties": {
28
+ "missing": {
29
+ "type": "array",
30
+ "items": { "type": "string" },
31
+ "description": "Env var keys that are not set or are empty."
32
+ }
33
+ }
34
+ },
35
+ "diff": {
36
+ "oneOf": [
37
+ { "type": "null" },
38
+ {
39
+ "type": "object",
40
+ "properties": {
41
+ "command": {
42
+ "type": "object",
43
+ "required": ["before", "after"],
44
+ "properties": {
45
+ "before": { "type": "string" },
46
+ "after": { "type": "string" }
47
+ }
48
+ },
49
+ "args": {
50
+ "type": "object",
51
+ "required": ["before", "after"],
52
+ "properties": {
53
+ "before": { "type": "array", "items": { "type": "string" } },
54
+ "after": { "type": "array", "items": { "type": "string" } }
55
+ }
56
+ },
57
+ "envKeys": {
58
+ "type": "object",
59
+ "required": ["before", "after"],
60
+ "properties": {
61
+ "before": { "type": "array", "items": { "type": "string" } },
62
+ "after": { "type": "array", "items": { "type": "string" } }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ ]
68
+ },
69
+ "nextActions": { "type": "array", "items": { "type": "string" } }
70
+ }
71
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Peaks MCP Install Spec",
4
+ "type": "object",
5
+ "required": ["capabilityId", "name", "scope", "command", "args", "envKeys"],
6
+ "properties": {
7
+ "capabilityId": {
8
+ "type": "string",
9
+ "minLength": 1,
10
+ "description": "Capability id from the Peaks capability map (e.g. context7.docs-lookup)."
11
+ },
12
+ "name": {
13
+ "type": "string",
14
+ "minLength": 1,
15
+ "description": "Server key written into .claude/settings.json mcpServers."
16
+ },
17
+ "scope": {
18
+ "type": "string",
19
+ "enum": ["global", "project"]
20
+ },
21
+ "command": { "type": "string", "minLength": 1 },
22
+ "args": { "type": "array", "items": { "type": "string" } },
23
+ "envKeys": {
24
+ "type": "array",
25
+ "items": { "type": "string" },
26
+ "description": "Required env var names. Values are sourced from process.env at runtime and written as ${VAR} placeholders into settings.json."
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Peaks MCP Server Config",
4
+ "type": "object",
5
+ "required": ["name", "command", "args", "envKeys", "source", "scope"],
6
+ "properties": {
7
+ "name": { "type": "string", "minLength": 1 },
8
+ "command": { "type": "string", "minLength": 1 },
9
+ "args": { "type": "array", "items": { "type": "string" } },
10
+ "envKeys": {
11
+ "type": "array",
12
+ "items": { "type": "string" },
13
+ "description": "Names of env vars referenced by the server config. Values are never stored here."
14
+ },
15
+ "source": {
16
+ "type": "string",
17
+ "enum": ["peaks", "cc-switch", "user", "plugin", "unknown"]
18
+ },
19
+ "scope": {
20
+ "type": "string",
21
+ "enum": ["global", "project", "plugin"]
22
+ },
23
+ "pluginName": {
24
+ "type": "string",
25
+ "minLength": 1,
26
+ "description": "Plugin id (e.g. playwright@claude-plugins-official) when source is plugin."
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Peaks OpenSpec Change Summary",
4
+ "type": "object",
5
+ "required": ["id", "paths", "specs", "taskProgress"],
6
+ "properties": {
7
+ "id": {
8
+ "type": "string",
9
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$",
10
+ "description": "OpenSpec change directory name under openspec/changes/."
11
+ },
12
+ "paths": {
13
+ "type": "object",
14
+ "required": ["root", "proposal", "tasks", "design"],
15
+ "properties": {
16
+ "root": { "type": "string", "minLength": 1 },
17
+ "proposal": {
18
+ "oneOf": [
19
+ { "type": "null" },
20
+ { "type": "string", "minLength": 1 }
21
+ ]
22
+ },
23
+ "tasks": {
24
+ "oneOf": [
25
+ { "type": "null" },
26
+ { "type": "string", "minLength": 1 }
27
+ ]
28
+ },
29
+ "design": {
30
+ "oneOf": [
31
+ { "type": "null" },
32
+ { "type": "string", "minLength": 1 }
33
+ ]
34
+ }
35
+ }
36
+ },
37
+ "specs": {
38
+ "type": "array",
39
+ "items": { "type": "string" },
40
+ "description": "Capability names found under specs/<capability>/spec.md."
41
+ },
42
+ "taskProgress": {
43
+ "oneOf": [
44
+ { "type": "null" },
45
+ {
46
+ "type": "object",
47
+ "required": ["totalTodo", "doneTodo", "sections"],
48
+ "properties": {
49
+ "totalTodo": { "type": "integer", "minimum": 0 },
50
+ "doneTodo": { "type": "integer", "minimum": 0 },
51
+ "sections": {
52
+ "type": "array",
53
+ "items": {
54
+ "type": "object",
55
+ "required": ["heading", "total", "done"],
56
+ "properties": {
57
+ "heading": { "type": "string", "minLength": 1 },
58
+ "total": { "type": "integer", "minimum": 0 },
59
+ "done": { "type": "integer", "minimum": 0 }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ ]
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Peaks OpenSpec Render Request",
4
+ "type": "object",
5
+ "required": ["changeId", "why", "whatChanges", "acceptanceCriteria"],
6
+ "properties": {
7
+ "changeId": {
8
+ "type": "string",
9
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$",
10
+ "description": "Safe directory name under openspec/changes/. Path traversal sequences are rejected."
11
+ },
12
+ "why": {
13
+ "type": "string",
14
+ "description": "Plain markdown content for the ## Why section. May be empty (rendered as _None_)."
15
+ },
16
+ "whatChanges": {
17
+ "type": "array",
18
+ "items": { "type": "string", "minLength": 1 },
19
+ "description": "Bullet items for the ## What Changes section. Empty array renders as _None_ but is a soft warning."
20
+ },
21
+ "acceptanceCriteria": {
22
+ "type": "array",
23
+ "items": { "type": "string", "minLength": 1 },
24
+ "description": "Bullet items for ## Acceptance Criteria. Empty array renders as _None_ but is a hard validation error."
25
+ },
26
+ "outOfScope": {
27
+ "type": "array",
28
+ "items": { "type": "string", "minLength": 1 }
29
+ },
30
+ "dependencies": {
31
+ "type": "array",
32
+ "items": { "type": "string", "minLength": 1 }
33
+ },
34
+ "risks": {
35
+ "type": "array",
36
+ "items": { "type": "string", "minLength": 1 }
37
+ },
38
+ "tasks": {
39
+ "type": "array",
40
+ "items": {
41
+ "type": "object",
42
+ "required": ["heading", "todos"],
43
+ "properties": {
44
+ "heading": { "type": "string", "minLength": 1 },
45
+ "todos": {
46
+ "type": "array",
47
+ "items": { "type": "string", "minLength": 1 }
48
+ },
49
+ "doneItems": {
50
+ "type": "array",
51
+ "items": { "type": "string", "minLength": 1 }
52
+ }
53
+ }
54
+ }
55
+ },
56
+ "design": {
57
+ "type": "string",
58
+ "description": "Raw markdown body for design.md. Passthrough; not parsed by Peaks."
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Peaks OpenSpec Validation Result",
4
+ "type": "object",
5
+ "required": ["changeId", "valid", "source", "issues"],
6
+ "properties": {
7
+ "changeId": {
8
+ "type": "string",
9
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$"
10
+ },
11
+ "valid": { "type": "boolean" },
12
+ "source": {
13
+ "type": "string",
14
+ "enum": ["internal", "openspec-cli"]
15
+ },
16
+ "issues": {
17
+ "type": "array",
18
+ "items": {
19
+ "type": "object",
20
+ "required": ["level", "rule", "message"],
21
+ "properties": {
22
+ "level": { "type": "string", "enum": ["error", "warning"] },
23
+ "rule": {
24
+ "type": "string",
25
+ "description": "Stable rule id. Internal rules: proposal-exists, what-changes-non-empty, acceptance-non-empty, why-non-empty, change-id-format, openspec-cli-failed, openspec-cli-unavailable."
26
+ },
27
+ "message": { "type": "string", "minLength": 1 }
28
+ }
29
+ }
30
+ },
31
+ "cliOutput": {
32
+ "type": "string",
33
+ "description": "Combined stdout+stderr from the external openspec CLI. Only set when source is openspec-cli."
34
+ }
35
+ }
36
+ }