peaks-loop 4.0.23 → 4.0.25
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.
- package/CHANGELOG.md +59 -0
- package/dist/cli/commands/_register.js +2 -1
- package/dist/cli/commands/best-practice-scan-command.d.ts +36 -0
- package/dist/cli/commands/best-practice-scan-command.js +118 -0
- package/dist/cli/commands/codegraph-commands.d.ts +10 -0
- package/dist/cli/commands/codegraph-commands.js +18 -4
- package/dist/cli/commands/request-commands.js +21 -9
- package/dist/services/best-practice/language-detector.d.ts +7 -0
- package/dist/services/best-practice/language-detector.js +96 -0
- package/dist/services/best-practice/output-formatter.d.ts +41 -0
- package/dist/services/best-practice/output-formatter.js +116 -0
- package/dist/services/best-practice/scan-orchestrator.d.ts +39 -0
- package/dist/services/best-practice/scan-orchestrator.js +85 -0
- package/dist/services/context/collector.d.ts +5 -12
- package/dist/services/context/context-builder.d.ts +12 -20
- package/dist/services/context/context-builder.js +1 -1
- package/dist/services/context/context-schema.d.ts +51 -364
- package/dist/services/context/context-schema.js +3 -3
- package/dist/services/crystallization/crystallization-service.d.ts +2 -12
- package/dist/services/crystallization/crystallization-service.js +3 -9
- package/dist/services/crystallization/crystallization-types.d.ts +45 -153
- package/dist/services/crystallization/crystallization-types.js +17 -11
- package/dist/services/crystallization/evidence-brief-builder.d.ts +12 -112
- package/dist/services/evolution/evolution-types.d.ts +83 -497
- package/dist/services/evolution/evolution-types.js +6 -10
- package/dist/services/fixture/fixture-sanitize-service.d.ts +10 -36
- package/dist/services/fixture/fixture-sanitize-service.js +1 -1
- package/dist/services/job/job-progress-store.d.ts +1 -17
- package/dist/services/job/job-progress-store.js +2 -2
- package/dist/services/job/job-types.d.ts +63 -370
- package/dist/services/job/job-types.js +46 -11
- package/dist/services/loop/loop-bee-relation-types.d.ts +20 -32
- package/dist/services/loop/loop-bee-relation-types.js +2 -2
- package/dist/services/loop/loop-release-types.d.ts +31 -110
- package/dist/services/migrate-skill-name/schema.d.ts +3 -19
- package/dist/services/migrate-skill-name/schema.js +4 -4
- package/dist/services/observability/observability-service.d.ts +21 -19
- package/dist/services/observability/observability-service.js +1 -1
- package/dist/services/prd/best-practice-auto-trigger.d.ts +61 -0
- package/dist/services/prd/best-practice-auto-trigger.js +126 -0
- package/dist/services/rd/types.d.ts +25 -194
- package/dist/services/sediment/json-schema.d.ts +39 -224
- package/dist/services/sediment/json-schema.js +2 -2
- package/dist/services/session/binding-store.d.ts +5 -47
- package/dist/services/session/binding-store.js +1 -1
- package/dist/services/share/bundle-types.d.ts +12 -180
- package/dist/services/share/bundle-types.js +15 -9
- package/dist/services/share/run-state-contract.d.ts +8 -25
- package/dist/services/skill/skill-search-service.d.ts +26 -46
- package/dist/services/skill/skill-search-service.js +2 -2
- package/dist/services/skills/hooks-settings-service.d.ts +9 -0
- package/dist/services/skills/hooks-settings-service.js +31 -1
- package/dist/services/skills/skill-presence-service.d.ts +24 -0
- package/dist/services/skills/skill-presence-service.js +33 -0
- package/package.json +8 -8
- package/schemas/context.schema.json +17 -8
- package/skills/bee/peaks-prd/SKILL.md +17 -0
- package/skills/bee/peaks-rd/SKILL.md +7 -0
- package/skills/bee/peaks-rd/references/frontend-acl-mapper.md +29 -0
- package/skills/peaks-code/SKILL.md +28 -1
- package/skills/peaks-code/references/codegraph-orchestration.md +7 -1
- package/skills/peaks-code/references/skill-presence-and-title.md +3 -3
|
@@ -8,12 +8,32 @@ export const SliceStateSchema = z
|
|
|
8
8
|
commitSha: z.string().optional(), // required when status=done
|
|
9
9
|
finishedAt: z.string().datetime().optional(),
|
|
10
10
|
failureReason: z.string().optional(), // required when status=failed
|
|
11
|
-
repairCycles: z.number().int().
|
|
11
|
+
repairCycles: z.number().int().gte(0).default(0),
|
|
12
12
|
blockedReason: z.string().optional(), // required when status=blocked
|
|
13
13
|
})
|
|
14
|
-
.
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
.superRefine((v, ctx) => {
|
|
15
|
+
if (v.status === 'done' && !(v.commitSha && v.commitSha.length >= 7)) {
|
|
16
|
+
ctx.addIssue({
|
|
17
|
+
code: 'custom',
|
|
18
|
+
path: ['commitSha'],
|
|
19
|
+
message: 'commitSha required (≥7 hex) when status=done',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (v.status === 'failed' && !(v.failureReason && v.failureReason.length >= 1)) {
|
|
23
|
+
ctx.addIssue({
|
|
24
|
+
code: 'custom',
|
|
25
|
+
path: ['failureReason'],
|
|
26
|
+
message: 'failureReason required when status=failed',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (v.status === 'blocked' && !(v.blockedReason && v.blockedReason.length >= 1)) {
|
|
30
|
+
ctx.addIssue({
|
|
31
|
+
code: 'custom',
|
|
32
|
+
path: ['blockedReason'],
|
|
33
|
+
message: 'blockedReason required when status=blocked',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
17
37
|
export const JobStateSchema = z.object({
|
|
18
38
|
jobId: z.string(),
|
|
19
39
|
sessionId: z.string(),
|
|
@@ -22,8 +42,8 @@ export const JobStateSchema = z.object({
|
|
|
22
42
|
parallelismHint: z.enum(['serial', 'llm-decides']).default('llm-decides'),
|
|
23
43
|
exitPolicy: z.enum(['strict', 'best-effort']).default('strict'),
|
|
24
44
|
mainLoopStrategy: z.enum(['single', 'rotating']).default('rotating'),
|
|
25
|
-
rotateEvery: z.number().int().
|
|
26
|
-
mainSessionCycle: z.number().int().
|
|
45
|
+
rotateEvery: z.number().int().gt(0).default(3),
|
|
46
|
+
mainSessionCycle: z.number().int().gte(0).default(0),
|
|
27
47
|
mainLoopOverride: z
|
|
28
48
|
.object({
|
|
29
49
|
from: z.literal('rotating'),
|
|
@@ -37,8 +57,8 @@ export const JobStateSchema = z.object({
|
|
|
37
57
|
export const ResourceSnapshotSchema = z.object({
|
|
38
58
|
capturedAt: z.string().datetime(),
|
|
39
59
|
cpuPercent: z.number().min(0).max(100),
|
|
40
|
-
memMb: z.number().
|
|
41
|
-
diskMb: z.number().
|
|
60
|
+
memMb: z.number().gte(0),
|
|
61
|
+
diskMb: z.number().gte(0),
|
|
42
62
|
contextRatio: z.number().min(0).max(1),
|
|
43
63
|
});
|
|
44
64
|
export const JobStatusSummarySchema = z.object({
|
|
@@ -62,7 +82,7 @@ export const JobInitInputSchema = z.object({
|
|
|
62
82
|
parallelismHint: z.enum(['serial', 'llm-decides']).default('llm-decides'),
|
|
63
83
|
exitPolicy: z.enum(['strict', 'best-effort']).default('strict'),
|
|
64
84
|
mainLoopStrategy: z.enum(['single', 'rotating']).default('rotating'),
|
|
65
|
-
rotateEvery: z.number().int().
|
|
85
|
+
rotateEvery: z.number().int().gt(0).default(3),
|
|
66
86
|
project: z.string(),
|
|
67
87
|
json: z.boolean().default(true),
|
|
68
88
|
});
|
|
@@ -76,8 +96,23 @@ export const JobCheckpointInputSchema = z
|
|
|
76
96
|
project: z.string(),
|
|
77
97
|
json: z.boolean().default(true),
|
|
78
98
|
})
|
|
79
|
-
.
|
|
80
|
-
|
|
99
|
+
.superRefine((v, ctx) => {
|
|
100
|
+
if (v.state === 'done' && !(v.commitSha && v.commitSha.length >= 7)) {
|
|
101
|
+
ctx.addIssue({
|
|
102
|
+
code: 'custom',
|
|
103
|
+
path: ['commitSha'],
|
|
104
|
+
message: 'commitSha required (≥7 hex) when state=done',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if ((v.state === 'failed' || v.state === 'skipped') &&
|
|
108
|
+
!(v.reason && v.reason.length >= 3)) {
|
|
109
|
+
ctx.addIssue({
|
|
110
|
+
code: 'custom',
|
|
111
|
+
path: ['reason'],
|
|
112
|
+
message: 'reason required (≥3 chars) when state=failed|skipped',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
81
116
|
export const JobBlockInputSchema = z.object({
|
|
82
117
|
jobId: z.string(),
|
|
83
118
|
sliceId: z.string(),
|
|
@@ -27,7 +27,12 @@ import { z } from "zod";
|
|
|
27
27
|
* - `created_at` is server-stamped from the system clock; the input
|
|
28
28
|
* schema does not let clients supply it (would be a backdate hole).
|
|
29
29
|
*/
|
|
30
|
-
export declare const LoopBeeRelationRoleSchema: z.ZodEnum<
|
|
30
|
+
export declare const LoopBeeRelationRoleSchema: z.ZodEnum<{
|
|
31
|
+
main: "main";
|
|
32
|
+
candidate: "candidate";
|
|
33
|
+
retired: "retired";
|
|
34
|
+
supporting: "supporting";
|
|
35
|
+
}>;
|
|
31
36
|
export type LoopBeeRelationRole = z.infer<typeof LoopBeeRelationRoleSchema>;
|
|
32
37
|
export declare const LOOP_BEE_RELATION_ROLES: readonly LoopBeeRelationRole[];
|
|
33
38
|
/**
|
|
@@ -44,19 +49,14 @@ export declare const LOOP_BEE_RELATION_ROLES: readonly LoopBeeRelationRole[];
|
|
|
44
49
|
export declare const LoopBeeRelationInputSchema: z.ZodObject<{
|
|
45
50
|
loop_release_id: z.ZodString;
|
|
46
51
|
bee_release_id: z.ZodNumber;
|
|
47
|
-
role: z.ZodEnum<
|
|
52
|
+
role: z.ZodEnum<{
|
|
53
|
+
main: "main";
|
|
54
|
+
candidate: "candidate";
|
|
55
|
+
retired: "retired";
|
|
56
|
+
supporting: "supporting";
|
|
57
|
+
}>;
|
|
48
58
|
reason: z.ZodString;
|
|
49
|
-
},
|
|
50
|
-
bee_release_id: number;
|
|
51
|
-
loop_release_id: string;
|
|
52
|
-
role: "main" | "candidate" | "retired" | "supporting";
|
|
53
|
-
reason: string;
|
|
54
|
-
}, {
|
|
55
|
-
bee_release_id: number;
|
|
56
|
-
loop_release_id: string;
|
|
57
|
-
role: "main" | "candidate" | "retired" | "supporting";
|
|
58
|
-
reason: string;
|
|
59
|
-
}>;
|
|
59
|
+
}, z.core.$strip>;
|
|
60
60
|
export type LoopBeeRelationInput = z.input<typeof LoopBeeRelationInputSchema>;
|
|
61
61
|
/**
|
|
62
62
|
* Full Zod schema for a LoopBeeRelation row as persisted. Differs from
|
|
@@ -72,29 +72,17 @@ export type LoopBeeRelationInput = z.input<typeof LoopBeeRelationInputSchema>;
|
|
|
72
72
|
export declare const LoopBeeRelationSchema: z.ZodObject<{
|
|
73
73
|
loop_release_id: z.ZodString;
|
|
74
74
|
bee_release_id: z.ZodNumber;
|
|
75
|
-
role: z.ZodEnum<
|
|
75
|
+
role: z.ZodEnum<{
|
|
76
|
+
main: "main";
|
|
77
|
+
candidate: "candidate";
|
|
78
|
+
retired: "retired";
|
|
79
|
+
supporting: "supporting";
|
|
80
|
+
}>;
|
|
76
81
|
reason: z.ZodString;
|
|
77
|
-
} & {
|
|
78
82
|
id: z.ZodNumber;
|
|
79
83
|
schema_version: z.ZodDefault<z.ZodLiteral<"peaks.loop-bee-relation/1">>;
|
|
80
84
|
created_at: z.ZodString;
|
|
81
|
-
},
|
|
82
|
-
schema_version: "peaks.loop-bee-relation/1";
|
|
83
|
-
id: number;
|
|
84
|
-
created_at: string;
|
|
85
|
-
bee_release_id: number;
|
|
86
|
-
loop_release_id: string;
|
|
87
|
-
role: "main" | "candidate" | "retired" | "supporting";
|
|
88
|
-
reason: string;
|
|
89
|
-
}, {
|
|
90
|
-
id: number;
|
|
91
|
-
created_at: string;
|
|
92
|
-
bee_release_id: number;
|
|
93
|
-
loop_release_id: string;
|
|
94
|
-
role: "main" | "candidate" | "retired" | "supporting";
|
|
95
|
-
reason: string;
|
|
96
|
-
schema_version?: "peaks.loop-bee-relation/1" | undefined;
|
|
97
|
-
}>;
|
|
85
|
+
}, z.core.$strip>;
|
|
98
86
|
export type LoopBeeRelation = z.infer<typeof LoopBeeRelationSchema>;
|
|
99
87
|
/**
|
|
100
88
|
* Convenience: strict-parse an unknown payload into a LoopBeeRelation
|
|
@@ -61,7 +61,7 @@ export const LoopBeeRelationInputSchema = z.object({
|
|
|
61
61
|
bee_release_id: z
|
|
62
62
|
.number()
|
|
63
63
|
.int()
|
|
64
|
-
.
|
|
64
|
+
.gt(0)
|
|
65
65
|
.max(2 ** 31 - 1, "bee_release_id out of 32-bit range"),
|
|
66
66
|
role: LoopBeeRelationRoleSchema,
|
|
67
67
|
reason: z
|
|
@@ -82,7 +82,7 @@ export const LoopBeeRelationInputSchema = z.object({
|
|
|
82
82
|
* read paths.
|
|
83
83
|
*/
|
|
84
84
|
export const LoopBeeRelationSchema = LoopBeeRelationInputSchema.extend({
|
|
85
|
-
id: z.number().int().
|
|
85
|
+
id: z.number().int().gt(0),
|
|
86
86
|
schema_version: z
|
|
87
87
|
.literal("peaks.loop-bee-relation/1")
|
|
88
88
|
.default("peaks.loop-bee-relation/1"),
|
|
@@ -40,7 +40,11 @@ import { z } from "zod";
|
|
|
40
40
|
* `"peaks.bundle/1"` per the spec §7A.2 contract — no other
|
|
41
41
|
* value is accepted in this schema version.
|
|
42
42
|
*/
|
|
43
|
-
export declare const LoopReleaseLifecycleStatusSchema: z.ZodEnum<
|
|
43
|
+
export declare const LoopReleaseLifecycleStatusSchema: z.ZodEnum<{
|
|
44
|
+
candidate: "candidate";
|
|
45
|
+
stable: "stable";
|
|
46
|
+
retired: "retired";
|
|
47
|
+
}>;
|
|
44
48
|
export type LoopReleaseLifecycleStatus = z.infer<typeof LoopReleaseLifecycleStatusSchema>;
|
|
45
49
|
/**
|
|
46
50
|
* The M3 share / desktop extension fields, listed for code-search /
|
|
@@ -65,20 +69,10 @@ export declare const LOOP_RELEASE_M3_FIELDS: readonly ["shareable", "share_exclu
|
|
|
65
69
|
*/
|
|
66
70
|
export declare const LoopReleaseM3ExtensionSchema: z.ZodObject<{
|
|
67
71
|
shareable: z.ZodDefault<z.ZodBoolean>;
|
|
68
|
-
share_excluded_paths: z.ZodDefault<z.ZodArray<z.ZodString
|
|
72
|
+
share_excluded_paths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
69
73
|
desktop_visible: z.ZodDefault<z.ZodBoolean>;
|
|
70
74
|
export_bundle_format: z.ZodDefault<z.ZodLiteral<"peaks.bundle/1">>;
|
|
71
|
-
},
|
|
72
|
-
shareable: boolean;
|
|
73
|
-
share_excluded_paths: string[];
|
|
74
|
-
desktop_visible: boolean;
|
|
75
|
-
export_bundle_format: "peaks.bundle/1";
|
|
76
|
-
}, {
|
|
77
|
-
shareable?: boolean | undefined;
|
|
78
|
-
share_excluded_paths?: string[] | undefined;
|
|
79
|
-
desktop_visible?: boolean | undefined;
|
|
80
|
-
export_bundle_format?: "peaks.bundle/1" | undefined;
|
|
81
|
-
}>;
|
|
75
|
+
}, z.core.$strip>;
|
|
82
76
|
/** Convenience type for the M3 share / desktop subset. */
|
|
83
77
|
export type LoopReleaseM3Extension = z.infer<typeof LoopReleaseM3ExtensionSchema>;
|
|
84
78
|
/**
|
|
@@ -92,60 +86,25 @@ export declare const LoopReleaseInputSchema: z.ZodObject<{
|
|
|
92
86
|
name: z.ZodString;
|
|
93
87
|
scenario: z.ZodString;
|
|
94
88
|
trigger_policy: z.ZodString;
|
|
95
|
-
success_criteria: z.ZodArray<z.ZodString
|
|
89
|
+
success_criteria: z.ZodArray<z.ZodString>;
|
|
96
90
|
interaction_policy: z.ZodString;
|
|
97
91
|
feedback_policy: z.ZodString;
|
|
98
92
|
evolution_policy: z.ZodString;
|
|
99
|
-
evaluator_policy: z.ZodArray<z.ZodString
|
|
100
|
-
linked_bees: z.ZodDefault<z.ZodArray<z.ZodString
|
|
101
|
-
run_history: z.ZodDefault<z.ZodArray<z.ZodString
|
|
102
|
-
crystallization_evidence: z.ZodDefault<z.ZodArray<z.ZodString
|
|
103
|
-
lifecycle_status: z.ZodEnum<
|
|
93
|
+
evaluator_policy: z.ZodArray<z.ZodString>;
|
|
94
|
+
linked_bees: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
95
|
+
run_history: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
96
|
+
crystallization_evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
97
|
+
lifecycle_status: z.ZodEnum<{
|
|
98
|
+
candidate: "candidate";
|
|
99
|
+
stable: "stable";
|
|
100
|
+
retired: "retired";
|
|
101
|
+
}>;
|
|
104
102
|
version: z.ZodString;
|
|
105
|
-
} & {
|
|
106
103
|
shareable: z.ZodDefault<z.ZodBoolean>;
|
|
107
|
-
share_excluded_paths: z.ZodDefault<z.ZodArray<z.ZodString
|
|
104
|
+
share_excluded_paths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
108
105
|
desktop_visible: z.ZodDefault<z.ZodBoolean>;
|
|
109
106
|
export_bundle_format: z.ZodDefault<z.ZodLiteral<"peaks.bundle/1">>;
|
|
110
|
-
},
|
|
111
|
-
version: string;
|
|
112
|
-
name: string;
|
|
113
|
-
lifecycle_status: "candidate" | "stable" | "retired";
|
|
114
|
-
id: string;
|
|
115
|
-
shareable: boolean;
|
|
116
|
-
share_excluded_paths: string[];
|
|
117
|
-
desktop_visible: boolean;
|
|
118
|
-
export_bundle_format: "peaks.bundle/1";
|
|
119
|
-
scenario: string;
|
|
120
|
-
trigger_policy: string;
|
|
121
|
-
success_criteria: string[];
|
|
122
|
-
interaction_policy: string;
|
|
123
|
-
feedback_policy: string;
|
|
124
|
-
evolution_policy: string;
|
|
125
|
-
evaluator_policy: string[];
|
|
126
|
-
linked_bees: string[];
|
|
127
|
-
run_history: string[];
|
|
128
|
-
crystallization_evidence: string[];
|
|
129
|
-
}, {
|
|
130
|
-
version: string;
|
|
131
|
-
name: string;
|
|
132
|
-
lifecycle_status: "candidate" | "stable" | "retired";
|
|
133
|
-
id: string;
|
|
134
|
-
scenario: string;
|
|
135
|
-
trigger_policy: string;
|
|
136
|
-
success_criteria: string[];
|
|
137
|
-
interaction_policy: string;
|
|
138
|
-
feedback_policy: string;
|
|
139
|
-
evolution_policy: string;
|
|
140
|
-
evaluator_policy: string[];
|
|
141
|
-
shareable?: boolean | undefined;
|
|
142
|
-
share_excluded_paths?: string[] | undefined;
|
|
143
|
-
desktop_visible?: boolean | undefined;
|
|
144
|
-
export_bundle_format?: "peaks.bundle/1" | undefined;
|
|
145
|
-
linked_bees?: string[] | undefined;
|
|
146
|
-
run_history?: string[] | undefined;
|
|
147
|
-
crystallization_evidence?: string[] | undefined;
|
|
148
|
-
}>;
|
|
107
|
+
}, z.core.$strip>;
|
|
149
108
|
/**
|
|
150
109
|
* `LoopReleaseInput` is the *input* shape clients supply: defaulted
|
|
151
110
|
* fields (linked_bees / run_history / crystallization_evidence) are
|
|
@@ -170,64 +129,26 @@ export declare const LoopReleaseSchema: z.ZodObject<{
|
|
|
170
129
|
name: z.ZodString;
|
|
171
130
|
scenario: z.ZodString;
|
|
172
131
|
trigger_policy: z.ZodString;
|
|
173
|
-
success_criteria: z.ZodArray<z.ZodString
|
|
132
|
+
success_criteria: z.ZodArray<z.ZodString>;
|
|
174
133
|
interaction_policy: z.ZodString;
|
|
175
134
|
feedback_policy: z.ZodString;
|
|
176
135
|
evolution_policy: z.ZodString;
|
|
177
|
-
evaluator_policy: z.ZodArray<z.ZodString
|
|
178
|
-
linked_bees: z.ZodDefault<z.ZodArray<z.ZodString
|
|
179
|
-
run_history: z.ZodDefault<z.ZodArray<z.ZodString
|
|
180
|
-
crystallization_evidence: z.ZodDefault<z.ZodArray<z.ZodString
|
|
181
|
-
lifecycle_status: z.ZodEnum<
|
|
136
|
+
evaluator_policy: z.ZodArray<z.ZodString>;
|
|
137
|
+
linked_bees: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
138
|
+
run_history: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
139
|
+
crystallization_evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
140
|
+
lifecycle_status: z.ZodEnum<{
|
|
141
|
+
candidate: "candidate";
|
|
142
|
+
stable: "stable";
|
|
143
|
+
retired: "retired";
|
|
144
|
+
}>;
|
|
182
145
|
version: z.ZodString;
|
|
183
|
-
} & {
|
|
184
146
|
shareable: z.ZodDefault<z.ZodBoolean>;
|
|
185
|
-
share_excluded_paths: z.ZodDefault<z.ZodArray<z.ZodString
|
|
147
|
+
share_excluded_paths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
186
148
|
desktop_visible: z.ZodDefault<z.ZodBoolean>;
|
|
187
149
|
export_bundle_format: z.ZodDefault<z.ZodLiteral<"peaks.bundle/1">>;
|
|
188
|
-
} & {
|
|
189
150
|
schema_version: z.ZodDefault<z.ZodLiteral<"peaks.loop/1">>;
|
|
190
|
-
},
|
|
191
|
-
schema_version: "peaks.loop/1";
|
|
192
|
-
version: string;
|
|
193
|
-
name: string;
|
|
194
|
-
lifecycle_status: "candidate" | "stable" | "retired";
|
|
195
|
-
id: string;
|
|
196
|
-
shareable: boolean;
|
|
197
|
-
share_excluded_paths: string[];
|
|
198
|
-
desktop_visible: boolean;
|
|
199
|
-
export_bundle_format: "peaks.bundle/1";
|
|
200
|
-
scenario: string;
|
|
201
|
-
trigger_policy: string;
|
|
202
|
-
success_criteria: string[];
|
|
203
|
-
interaction_policy: string;
|
|
204
|
-
feedback_policy: string;
|
|
205
|
-
evolution_policy: string;
|
|
206
|
-
evaluator_policy: string[];
|
|
207
|
-
linked_bees: string[];
|
|
208
|
-
run_history: string[];
|
|
209
|
-
crystallization_evidence: string[];
|
|
210
|
-
}, {
|
|
211
|
-
version: string;
|
|
212
|
-
name: string;
|
|
213
|
-
lifecycle_status: "candidate" | "stable" | "retired";
|
|
214
|
-
id: string;
|
|
215
|
-
scenario: string;
|
|
216
|
-
trigger_policy: string;
|
|
217
|
-
success_criteria: string[];
|
|
218
|
-
interaction_policy: string;
|
|
219
|
-
feedback_policy: string;
|
|
220
|
-
evolution_policy: string;
|
|
221
|
-
evaluator_policy: string[];
|
|
222
|
-
schema_version?: "peaks.loop/1" | undefined;
|
|
223
|
-
shareable?: boolean | undefined;
|
|
224
|
-
share_excluded_paths?: string[] | undefined;
|
|
225
|
-
desktop_visible?: boolean | undefined;
|
|
226
|
-
export_bundle_format?: "peaks.bundle/1" | undefined;
|
|
227
|
-
linked_bees?: string[] | undefined;
|
|
228
|
-
run_history?: string[] | undefined;
|
|
229
|
-
crystallization_evidence?: string[] | undefined;
|
|
230
|
-
}>;
|
|
151
|
+
}, z.core.$strip>;
|
|
231
152
|
export type LoopRelease = z.infer<typeof LoopReleaseSchema>;
|
|
232
153
|
/**
|
|
233
154
|
* Convenience: strict-parse an unknown payload into a LoopRelease row.
|
|
@@ -20,23 +20,7 @@ export declare const MigrateResultSchema: z.ZodObject<{
|
|
|
20
20
|
modifiedFiles: z.ZodNumber;
|
|
21
21
|
keyValueReplacements: z.ZodNumber;
|
|
22
22
|
stringReplacements: z.ZodNumber;
|
|
23
|
-
skipped: z.ZodArray<z.ZodString
|
|
24
|
-
errors: z.ZodArray<z.ZodString
|
|
25
|
-
},
|
|
26
|
-
skipped: string[];
|
|
27
|
-
ok: boolean;
|
|
28
|
-
scannedFiles: number;
|
|
29
|
-
modifiedFiles: number;
|
|
30
|
-
keyValueReplacements: number;
|
|
31
|
-
stringReplacements: number;
|
|
32
|
-
errors: string[];
|
|
33
|
-
}, {
|
|
34
|
-
skipped: string[];
|
|
35
|
-
ok: boolean;
|
|
36
|
-
scannedFiles: number;
|
|
37
|
-
modifiedFiles: number;
|
|
38
|
-
keyValueReplacements: number;
|
|
39
|
-
stringReplacements: number;
|
|
40
|
-
errors: string[];
|
|
41
|
-
}>;
|
|
23
|
+
skipped: z.ZodArray<z.ZodString>;
|
|
24
|
+
errors: z.ZodArray<z.ZodString>;
|
|
25
|
+
}, z.core.$strip>;
|
|
42
26
|
export type MigrateResult = z.infer<typeof MigrateResultSchema>;
|
|
@@ -16,10 +16,10 @@ import { z } from 'zod';
|
|
|
16
16
|
*/
|
|
17
17
|
export const MigrateResultSchema = z.object({
|
|
18
18
|
ok: z.boolean(),
|
|
19
|
-
scannedFiles: z.number().int().
|
|
20
|
-
modifiedFiles: z.number().int().
|
|
21
|
-
keyValueReplacements: z.number().int().
|
|
22
|
-
stringReplacements: z.number().int().
|
|
19
|
+
scannedFiles: z.number().int().gte(0),
|
|
20
|
+
modifiedFiles: z.number().int().gte(0),
|
|
21
|
+
keyValueReplacements: z.number().int().gte(0),
|
|
22
|
+
stringReplacements: z.number().int().gte(0),
|
|
23
23
|
skipped: z.array(z.string()),
|
|
24
24
|
errors: z.array(z.string()),
|
|
25
25
|
});
|
|
@@ -28,27 +28,29 @@ export declare const ObservabilityEventSchema: z.ZodObject<{
|
|
|
28
28
|
schemaVersion: z.ZodLiteral<1>;
|
|
29
29
|
ts: z.ZodString;
|
|
30
30
|
sessionId: z.ZodString;
|
|
31
|
-
category: z.ZodEnum<
|
|
31
|
+
category: z.ZodEnum<{
|
|
32
|
+
dispatch: "dispatch";
|
|
33
|
+
"slice-transition": "slice-transition";
|
|
34
|
+
checkpoint: "checkpoint";
|
|
35
|
+
"mode-gate": "mode-gate";
|
|
36
|
+
"context-trigger": "context-trigger";
|
|
37
|
+
"post-compact": "post-compact";
|
|
38
|
+
cycle: "cycle";
|
|
39
|
+
"token-usage": "token-usage";
|
|
40
|
+
"monotonic-trigger": "monotonic-trigger";
|
|
41
|
+
lease: "lease";
|
|
42
|
+
}>;
|
|
32
43
|
sliceRid: z.ZodOptional<z.ZodString>;
|
|
33
|
-
role: z.ZodOptional<z.ZodEnum<
|
|
44
|
+
role: z.ZodOptional<z.ZodEnum<{
|
|
45
|
+
qa: "qa";
|
|
46
|
+
rd: "rd";
|
|
47
|
+
"code-reviewer": "code-reviewer";
|
|
48
|
+
"karpathy-reviewer": "karpathy-reviewer";
|
|
49
|
+
"peaks-security-audit": "peaks-security-audit";
|
|
50
|
+
"peaks-perf-audit": "peaks-perf-audit";
|
|
51
|
+
}>>;
|
|
34
52
|
detail: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
35
|
-
},
|
|
36
|
-
schemaVersion: 1;
|
|
37
|
-
sessionId: string;
|
|
38
|
-
detail: Record<string, unknown>;
|
|
39
|
-
ts: string;
|
|
40
|
-
category: "dispatch" | "slice-transition" | "checkpoint" | "mode-gate" | "context-trigger" | "post-compact" | "cycle" | "token-usage" | "monotonic-trigger" | "lease";
|
|
41
|
-
role?: "qa" | "rd" | "code-reviewer" | "karpathy-reviewer" | "peaks-security-audit" | "peaks-perf-audit" | undefined;
|
|
42
|
-
sliceRid?: string | undefined;
|
|
43
|
-
}, {
|
|
44
|
-
schemaVersion: 1;
|
|
45
|
-
sessionId: string;
|
|
46
|
-
detail: Record<string, unknown>;
|
|
47
|
-
ts: string;
|
|
48
|
-
category: "dispatch" | "slice-transition" | "checkpoint" | "mode-gate" | "context-trigger" | "post-compact" | "cycle" | "token-usage" | "monotonic-trigger" | "lease";
|
|
49
|
-
role?: "qa" | "rd" | "code-reviewer" | "karpathy-reviewer" | "peaks-security-audit" | "peaks-perf-audit" | undefined;
|
|
50
|
-
sliceRid?: string | undefined;
|
|
51
|
-
}>;
|
|
53
|
+
}, z.core.$strip>;
|
|
52
54
|
export type ObservabilityEvent = z.infer<typeof ObservabilityEventSchema>;
|
|
53
55
|
export type EmitOptions = {
|
|
54
56
|
/** Absolute path to the project root (where `.peaks/_runtime/` lives). */
|
|
@@ -61,7 +61,7 @@ export const ObservabilityEventSchema = z.object({
|
|
|
61
61
|
category: z.enum(OBSERVABILITY_CATEGORIES),
|
|
62
62
|
sliceRid: z.string().min(1).optional(),
|
|
63
63
|
role: z.enum(OBSERVABILITY_SUBAGENT_ROLES).optional(),
|
|
64
|
-
detail: z.record(z.unknown())
|
|
64
|
+
detail: z.record(z.string(), z.unknown())
|
|
65
65
|
});
|
|
66
66
|
/**
|
|
67
67
|
* Append a single observability event to the session's JSONL metrics
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice 2026-08-12 best-practice-scan — auto-trigger post-step (Slice F).
|
|
3
|
+
*
|
|
4
|
+
* When peaks-prd's request artifact transitions to `handed-off`, this helper
|
|
5
|
+
* extracts the `businessGoal` (first non-empty bullet under `## Goals` of the
|
|
6
|
+
* PRD body) and fires `peaks best-practice-scan --project <root> --intent "<goal>"`
|
|
7
|
+
* as a fire-and-forget post-step. The PRD → handed-off transition is the
|
|
8
|
+
* canonical moment when "businessGoal transitions to complete" (the prd state
|
|
9
|
+
* machine's terminal state).
|
|
10
|
+
*
|
|
11
|
+
* Failure modes (all non-fatal — the prd → handed-off transition MUST NOT
|
|
12
|
+
* block on BPS issues):
|
|
13
|
+
* - Empty businessGoal → status: 'skipped-empty-goal' (no spawn)
|
|
14
|
+
* - Artifact missing → status: 'skipped-artifact-missing'
|
|
15
|
+
* - Peaks binary missing → status: 'skipped-artifact-missing'
|
|
16
|
+
* - Spawn 'error' event → status: 'failed' (logged, not thrown)
|
|
17
|
+
* - Spawn event timeout (5 s) → status: 'failed' (logged, not thrown)
|
|
18
|
+
* - Spawn 'spawn' event → status: 'triggered' (resolved; child detached)
|
|
19
|
+
*
|
|
20
|
+
* Karpathy §1 (Think Before Coding): extracted from the QA verdict
|
|
21
|
+
* `verdict-rid-best-practice-scan-qa-ship.md` AC-1 PARTIAL finding. The
|
|
22
|
+
* `prd:handed-off` transition in `src/cli/commands/request-commands.ts`
|
|
23
|
+
* is the canonical hook point — peaks-prd's contract in
|
|
24
|
+
* `skills/bee/peaks-prd/SKILL.md` §"Step 2.5 sub-step" mandates this firing
|
|
25
|
+
* BEFORE peaks-rd takes over.
|
|
26
|
+
*
|
|
27
|
+
* Karpathy §2 (Simplicity First): single spawn, no retry, no async queue.
|
|
28
|
+
* Karpathy §3 (Surgical Changes): one new file, no other source files
|
|
29
|
+
* touched (the call site wiring in request-commands.ts is the only other
|
|
30
|
+
* edit; that is the "Pattern A: inline post-step" from the dispatch spec).
|
|
31
|
+
*/
|
|
32
|
+
export type BestPracticeTriggerStatus = 'triggered' | 'skipped-empty-goal' | 'skipped-artifact-missing' | 'failed';
|
|
33
|
+
export type BestPracticeTriggerResult = {
|
|
34
|
+
readonly status: BestPracticeTriggerStatus;
|
|
35
|
+
readonly businessGoal?: string;
|
|
36
|
+
readonly pid?: number;
|
|
37
|
+
readonly reason?: string;
|
|
38
|
+
};
|
|
39
|
+
/** Extract the first non-empty bullet from the `## Goals` section of a PRD
|
|
40
|
+
* body. Falls back to the `raw input (sanitized):` line at the top when
|
|
41
|
+
* the Goals section is missing or empty. Returns null when no goal can
|
|
42
|
+
* be derived (caller should treat as `skipped-empty-goal`).
|
|
43
|
+
*
|
|
44
|
+
* Pure function — exported separately so unit tests can target the
|
|
45
|
+
* extraction logic without spawning child processes. */
|
|
46
|
+
export declare function extractBusinessGoal(prdBody: string): string | null;
|
|
47
|
+
/** Fire-and-forget: invoke `peaks best-practice-scan --project <root>
|
|
48
|
+
* --intent "<businessGoal>"`. Never throws — always resolves with a
|
|
49
|
+
* BestPracticeTriggerResult envelope. The child is detached via `unref()`
|
|
50
|
+
* on the 'spawn' event so the parent process is not blocked waiting for
|
|
51
|
+
* the BPS scan to finish (the scan itself sleeps ~100 ms in the v1
|
|
52
|
+
* Context7 stub).
|
|
53
|
+
*
|
|
54
|
+
* `PEAKS_BEST_PRACTICE_STDIN` is forced to empty so the BPS catch-gate
|
|
55
|
+
* auto-accepts the recommended option — auto-trigger is non-interactive
|
|
56
|
+
* by design (no user at the prompt when prd → handed-off fires). */
|
|
57
|
+
export declare function triggerBestPracticeScan(opts: {
|
|
58
|
+
readonly projectRoot: string;
|
|
59
|
+
readonly sessionId: string;
|
|
60
|
+
readonly requestId: string;
|
|
61
|
+
}): Promise<BestPracticeTriggerResult>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice 2026-08-12 best-practice-scan — auto-trigger post-step (Slice F).
|
|
3
|
+
*
|
|
4
|
+
* When peaks-prd's request artifact transitions to `handed-off`, this helper
|
|
5
|
+
* extracts the `businessGoal` (first non-empty bullet under `## Goals` of the
|
|
6
|
+
* PRD body) and fires `peaks best-practice-scan --project <root> --intent "<goal>"`
|
|
7
|
+
* as a fire-and-forget post-step. The PRD → handed-off transition is the
|
|
8
|
+
* canonical moment when "businessGoal transitions to complete" (the prd state
|
|
9
|
+
* machine's terminal state).
|
|
10
|
+
*
|
|
11
|
+
* Failure modes (all non-fatal — the prd → handed-off transition MUST NOT
|
|
12
|
+
* block on BPS issues):
|
|
13
|
+
* - Empty businessGoal → status: 'skipped-empty-goal' (no spawn)
|
|
14
|
+
* - Artifact missing → status: 'skipped-artifact-missing'
|
|
15
|
+
* - Peaks binary missing → status: 'skipped-artifact-missing'
|
|
16
|
+
* - Spawn 'error' event → status: 'failed' (logged, not thrown)
|
|
17
|
+
* - Spawn event timeout (5 s) → status: 'failed' (logged, not thrown)
|
|
18
|
+
* - Spawn 'spawn' event → status: 'triggered' (resolved; child detached)
|
|
19
|
+
*
|
|
20
|
+
* Karpathy §1 (Think Before Coding): extracted from the QA verdict
|
|
21
|
+
* `verdict-rid-best-practice-scan-qa-ship.md` AC-1 PARTIAL finding. The
|
|
22
|
+
* `prd:handed-off` transition in `src/cli/commands/request-commands.ts`
|
|
23
|
+
* is the canonical hook point — peaks-prd's contract in
|
|
24
|
+
* `skills/bee/peaks-prd/SKILL.md` §"Step 2.5 sub-step" mandates this firing
|
|
25
|
+
* BEFORE peaks-rd takes over.
|
|
26
|
+
*
|
|
27
|
+
* Karpathy §2 (Simplicity First): single spawn, no retry, no async queue.
|
|
28
|
+
* Karpathy §3 (Surgical Changes): one new file, no other source files
|
|
29
|
+
* touched (the call site wiring in request-commands.ts is the only other
|
|
30
|
+
* edit; that is the "Pattern A: inline post-step" from the dispatch spec).
|
|
31
|
+
*/
|
|
32
|
+
import { spawn } from 'node:child_process';
|
|
33
|
+
import { existsSync } from 'node:fs';
|
|
34
|
+
import { join } from 'node:path';
|
|
35
|
+
import { showRequestArtifact } from '../artifacts/request-artifact-service.js';
|
|
36
|
+
/** Extract the first non-empty bullet from the `## Goals` section of a PRD
|
|
37
|
+
* body. Falls back to the `raw input (sanitized):` line at the top when
|
|
38
|
+
* the Goals section is missing or empty. Returns null when no goal can
|
|
39
|
+
* be derived (caller should treat as `skipped-empty-goal`).
|
|
40
|
+
*
|
|
41
|
+
* Pure function — exported separately so unit tests can target the
|
|
42
|
+
* extraction logic without spawning child processes. */
|
|
43
|
+
export function extractBusinessGoal(prdBody) {
|
|
44
|
+
const goalsMatch = /##\s+Goals\s*\n([\s\S]*?)(?=\n##\s|\n#\s|\Z)/.exec(prdBody);
|
|
45
|
+
if (goalsMatch !== null && goalsMatch[1] !== undefined) {
|
|
46
|
+
for (const raw of goalsMatch[1].split(/\r?\n/)) {
|
|
47
|
+
const line = raw.replace(/^[\s>*\-]+/, '').trim();
|
|
48
|
+
if (line.length > 0 && line !== '...')
|
|
49
|
+
return line;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const rawInputMatch = /^- raw input \(sanitized\):\s*(.+)$/m.exec(prdBody);
|
|
53
|
+
if (rawInputMatch !== null && rawInputMatch[1] !== undefined) {
|
|
54
|
+
const line = rawInputMatch[1].trim();
|
|
55
|
+
if (line.length > 0 && line !== '...')
|
|
56
|
+
return line;
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/** Fire-and-forget: invoke `peaks best-practice-scan --project <root>
|
|
61
|
+
* --intent "<businessGoal>"`. Never throws — always resolves with a
|
|
62
|
+
* BestPracticeTriggerResult envelope. The child is detached via `unref()`
|
|
63
|
+
* on the 'spawn' event so the parent process is not blocked waiting for
|
|
64
|
+
* the BPS scan to finish (the scan itself sleeps ~100 ms in the v1
|
|
65
|
+
* Context7 stub).
|
|
66
|
+
*
|
|
67
|
+
* `PEAKS_BEST_PRACTICE_STDIN` is forced to empty so the BPS catch-gate
|
|
68
|
+
* auto-accepts the recommended option — auto-trigger is non-interactive
|
|
69
|
+
* by design (no user at the prompt when prd → handed-off fires). */
|
|
70
|
+
export async function triggerBestPracticeScan(opts) {
|
|
71
|
+
const artifact = await showRequestArtifact({
|
|
72
|
+
projectRoot: opts.projectRoot,
|
|
73
|
+
role: 'prd',
|
|
74
|
+
requestId: opts.requestId,
|
|
75
|
+
sessionId: opts.sessionId
|
|
76
|
+
});
|
|
77
|
+
if (artifact === null) {
|
|
78
|
+
return { status: 'skipped-artifact-missing' };
|
|
79
|
+
}
|
|
80
|
+
const businessGoal = extractBusinessGoal(artifact.content);
|
|
81
|
+
if (businessGoal === null) {
|
|
82
|
+
return { status: 'skipped-empty-goal' };
|
|
83
|
+
}
|
|
84
|
+
const peaksBin = join(opts.projectRoot, 'bin', 'peaks.js');
|
|
85
|
+
if (!existsSync(peaksBin)) {
|
|
86
|
+
return { status: 'skipped-artifact-missing', reason: `peaks binary not found at ${peaksBin}` };
|
|
87
|
+
}
|
|
88
|
+
return await new Promise((resolveTrigger) => {
|
|
89
|
+
let resolved = false;
|
|
90
|
+
const resolveOnce = (result) => {
|
|
91
|
+
if (resolved)
|
|
92
|
+
return;
|
|
93
|
+
resolved = true;
|
|
94
|
+
resolveTrigger(result);
|
|
95
|
+
};
|
|
96
|
+
const child = spawn(process.execPath, [
|
|
97
|
+
peaksBin,
|
|
98
|
+
'best-practice-scan',
|
|
99
|
+
'--project',
|
|
100
|
+
opts.projectRoot,
|
|
101
|
+
'--intent',
|
|
102
|
+
businessGoal,
|
|
103
|
+
'--json'
|
|
104
|
+
], {
|
|
105
|
+
cwd: opts.projectRoot,
|
|
106
|
+
stdio: 'ignore',
|
|
107
|
+
detached: true,
|
|
108
|
+
env: { ...process.env, PEAKS_BEST_PRACTICE_STDIN: '' }
|
|
109
|
+
});
|
|
110
|
+
child.once('error', (err) => {
|
|
111
|
+
resolveOnce({ status: 'failed', businessGoal, reason: err.message });
|
|
112
|
+
});
|
|
113
|
+
child.once('spawn', () => {
|
|
114
|
+
if (typeof child.unref === 'function')
|
|
115
|
+
child.unref();
|
|
116
|
+
resolveOnce({
|
|
117
|
+
status: 'triggered',
|
|
118
|
+
businessGoal,
|
|
119
|
+
pid: typeof child.pid === 'number' ? child.pid : -1
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
setTimeout(() => {
|
|
123
|
+
resolveOnce({ status: 'failed', businessGoal, reason: 'spawn event timeout (5s)' });
|
|
124
|
+
}, 5_000).unref();
|
|
125
|
+
});
|
|
126
|
+
}
|