@captain_z/zsk 1.8.3 → 1.8.4
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/dist/commands/add-flow.d.ts +3 -7
- package/dist/commands/add-flow.js +7 -59
- package/dist/commands/add-flow.js.map +1 -1
- package/dist/commands/add.js +25 -104
- package/dist/commands/add.js.map +1 -1
- package/dist/core/prepare-sync.d.ts +2 -31
- package/dist/core/prepare-sync.js +96 -128
- package/dist/core/prepare-sync.js.map +1 -1
- package/dist/core/profile-bundle-installation.d.ts +55 -0
- package/dist/core/profile-bundle-installation.js +170 -0
- package/dist/core/profile-bundle-installation.js.map +1 -0
- package/dist/core/source-snapshot-adapters.d.ts +59 -0
- package/dist/core/source-snapshot-adapters.js +82 -0
- package/dist/core/source-snapshot-adapters.js.map +1 -0
- package/dist/core/staffing-plan.js +52 -18
- package/dist/core/staffing-plan.js.map +1 -1
- package/dist/core/stage-clarity-verification.d.ts +31 -0
- package/dist/core/stage-clarity-verification.js +313 -0
- package/dist/core/stage-clarity-verification.js.map +1 -0
- package/dist/core/stage-quality-artifacts.d.ts +15 -0
- package/dist/core/stage-quality-artifacts.js +421 -0
- package/dist/core/stage-quality-artifacts.js.map +1 -0
- package/dist/core/stage-quality-contracts.d.ts +86 -0
- package/dist/core/stage-quality-contracts.js +2 -0
- package/dist/core/stage-quality-contracts.js.map +1 -0
- package/dist/core/stage-quality-criteria.d.ts +9 -0
- package/dist/core/stage-quality-criteria.js +323 -0
- package/dist/core/stage-quality-criteria.js.map +1 -0
- package/dist/core/stage-quality-rendering.d.ts +13 -0
- package/dist/core/stage-quality-rendering.js +122 -0
- package/dist/core/stage-quality-rendering.js.map +1 -0
- package/dist/core/stage-quality.d.ts +4 -59
- package/dist/core/stage-quality.js +39 -791
- package/dist/core/stage-quality.js.map +1 -1
- package/package.json +2 -2
- package/templates/module/frontend-module/design.md +10 -0
- package/templates/module/frontend-module/proposal.md +8 -0
- package/templates/module/frontend-module/spec.md +7 -0
- package/templates/project-init/.zsk/config.yaml +33 -0
- package/templates/project-init/.zsk/docs/PROJECT-CONFIG.md +43 -0
- package/templates/project-init/.zsk/docs/SYSTEM-SPEC.md +22 -2
- package/templates/project-init/.zsk/raws/index.md +16 -0
- package/templates/project-init/.zsk/raws/prepare/design/index.md +18 -0
- package/templates/project-init/.zsk/raws/prepare/index.md +33 -0
- package/templates/project-init/.zsk/raws/prepare/ux/index.md +19 -0
- package/templates/project-init/.zsk/roles.yaml +3 -3
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
3
|
+
import { expandCapabilityFilters, hasCapabilityFilter, } from "./capabilities.js";
|
|
4
|
+
import { install, skillRelPath } from "./installer.js";
|
|
5
|
+
import { buildManifest, sha256File, } from "./manifest.js";
|
|
6
|
+
import { loadSkill } from "./skills.js";
|
|
7
|
+
export const DEFAULT_PROFILE_BUNDLE = "zsk-sdlc";
|
|
8
|
+
export async function installProfileBundle(plan) {
|
|
9
|
+
return install(plan);
|
|
10
|
+
}
|
|
11
|
+
export function isProfileBundleMaintenanceRun(args) {
|
|
12
|
+
return args.targetProvided && args.hasManifest && !args.hasExplicitPicks;
|
|
13
|
+
}
|
|
14
|
+
export function resolveProfileInstallMode(args) {
|
|
15
|
+
if (!args.hasManifest)
|
|
16
|
+
return "new";
|
|
17
|
+
if (args.hasExplicitPicks)
|
|
18
|
+
return "append";
|
|
19
|
+
return args.requestedAction ?? "exit";
|
|
20
|
+
}
|
|
21
|
+
export function buildProfileBundleOptions(bundles) {
|
|
22
|
+
return profileBundleEntries(bundles)
|
|
23
|
+
.map(([name, bundle]) => ({
|
|
24
|
+
value: name,
|
|
25
|
+
label: bundle.label || name,
|
|
26
|
+
hint: buildProfileBundleSummary(bundle.skills),
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
export function resolveProfileBundleChoices(selectedBundleNames, bundles, availableSkills) {
|
|
30
|
+
const skills = uniqueStrings(selectedBundleNames.flatMap((name) => {
|
|
31
|
+
const bundle = bundles[name];
|
|
32
|
+
return bundle ? profileBundleToAvailableSkills(bundle, availableSkills) : [];
|
|
33
|
+
}));
|
|
34
|
+
return {
|
|
35
|
+
skills,
|
|
36
|
+
bundle: selectedBundleNames.length === 1
|
|
37
|
+
? inferProfileBundleName(selectedBundleNames[0] ?? null, skills, bundles, availableSkills)
|
|
38
|
+
: null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function resolveCapabilityProfileSelection(filters, availableSkills) {
|
|
42
|
+
const matched = expandCapabilityFilters(filters.skill ?? [], availableSkills);
|
|
43
|
+
if (!hasCapabilityFilter(filters))
|
|
44
|
+
return null;
|
|
45
|
+
return { skills: matched, bundle: null };
|
|
46
|
+
}
|
|
47
|
+
export function resolveProfileBundlePatternSelection(args) {
|
|
48
|
+
const { bundles, availableSkills, bundlePatterns, skillPatterns } = args;
|
|
49
|
+
const matched = expandCapabilityFilters(skillPatterns, availableSkills);
|
|
50
|
+
const selected = uniqueStrings([
|
|
51
|
+
...bundlePatterns.flatMap((name) => {
|
|
52
|
+
const bundle = bundles[name];
|
|
53
|
+
return bundle ? profileBundleToAvailableSkills(bundle, availableSkills) : [];
|
|
54
|
+
}),
|
|
55
|
+
...matched,
|
|
56
|
+
]);
|
|
57
|
+
return {
|
|
58
|
+
skills: selected,
|
|
59
|
+
bundle: bundlePatterns.length === 1
|
|
60
|
+
? inferProfileBundleName(bundlePatterns[0] ?? null, selected, bundles, availableSkills)
|
|
61
|
+
: null,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function inferProfileBundleName(selectedBundleName, selectedSkills, bundles, availableSkills) {
|
|
65
|
+
if (!selectedBundleName)
|
|
66
|
+
return null;
|
|
67
|
+
const bundle = bundles[selectedBundleName];
|
|
68
|
+
if (!bundle)
|
|
69
|
+
return null;
|
|
70
|
+
const expected = profileBundleToAvailableSkills(bundle, availableSkills);
|
|
71
|
+
return sameMembers(selectedSkills, expected) ? selectedBundleName : null;
|
|
72
|
+
}
|
|
73
|
+
export function profileBundleToAvailableSkills(bundle, availableSkills) {
|
|
74
|
+
const set = new Set(availableSkills);
|
|
75
|
+
return bundle.skills.filter((skill) => set.has(skill));
|
|
76
|
+
}
|
|
77
|
+
export function inferProfileBundleInstallLayout(targetPath, format) {
|
|
78
|
+
if (format === "claude-plugin")
|
|
79
|
+
return "claude-plugin";
|
|
80
|
+
if (format === "flat")
|
|
81
|
+
return "flat";
|
|
82
|
+
const base = basename(targetPath);
|
|
83
|
+
return base === ".claude-plugin" || base === "claude-plugin"
|
|
84
|
+
? "claude-plugin"
|
|
85
|
+
: "flat";
|
|
86
|
+
}
|
|
87
|
+
export async function buildProfileBundleManifestRecords(skillNames, targetPath, layout, zskVersion) {
|
|
88
|
+
const out = [];
|
|
89
|
+
for (const name of skillNames) {
|
|
90
|
+
try {
|
|
91
|
+
const skill = await loadSkill(name);
|
|
92
|
+
const relPath = skillRelPath(skill, layout);
|
|
93
|
+
const buf = await readFile(join(targetPath, relPath));
|
|
94
|
+
const skillRoot = dirname(relPath);
|
|
95
|
+
out.push({
|
|
96
|
+
name,
|
|
97
|
+
version: zskVersion,
|
|
98
|
+
sha256: sha256File(buf),
|
|
99
|
+
relPath,
|
|
100
|
+
files: await buildOwnedFileRecords(targetPath, skillRoot),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// The skill may have been skipped by conflict policy; omit it from the manifest.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
export function buildProfileBundleManifest(params) {
|
|
110
|
+
return buildManifest(params);
|
|
111
|
+
}
|
|
112
|
+
export function mergeProfileBundleManifestSkills(existing, fresh, currentInstallableNames) {
|
|
113
|
+
const map = new Map();
|
|
114
|
+
for (const entry of existing) {
|
|
115
|
+
if (currentInstallableNames.has(entry.name))
|
|
116
|
+
map.set(entry.name, entry);
|
|
117
|
+
}
|
|
118
|
+
for (const entry of fresh)
|
|
119
|
+
map.set(entry.name, entry);
|
|
120
|
+
return [...map.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
121
|
+
}
|
|
122
|
+
function profileBundleEntries(bundles) {
|
|
123
|
+
return Object.entries(bundles)
|
|
124
|
+
.filter(([, bundle]) => bundle.skills.length > 0)
|
|
125
|
+
.sort(([leftName], [rightName]) => {
|
|
126
|
+
if (leftName === DEFAULT_PROFILE_BUNDLE)
|
|
127
|
+
return -1;
|
|
128
|
+
if (rightName === DEFAULT_PROFILE_BUNDLE)
|
|
129
|
+
return 1;
|
|
130
|
+
return leftName.localeCompare(rightName);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function buildProfileBundleSummary(skills) {
|
|
134
|
+
const preview = skills.slice(0, 3).join(", ");
|
|
135
|
+
const suffix = skills.length > 3 ? ", ..." : "";
|
|
136
|
+
return `${skills.length} 个 · ${preview}${suffix}`;
|
|
137
|
+
}
|
|
138
|
+
async function buildOwnedFileRecords(targetPath, skillRoot) {
|
|
139
|
+
const absRoot = join(targetPath, skillRoot);
|
|
140
|
+
const files = await walkFiles(absRoot);
|
|
141
|
+
const records = await Promise.all(files.map(async (absPath) => ({
|
|
142
|
+
relPath: relative(targetPath, absPath),
|
|
143
|
+
sha256: sha256File(await readFile(absPath)),
|
|
144
|
+
})));
|
|
145
|
+
return records.sort((left, right) => left.relPath.localeCompare(right.relPath));
|
|
146
|
+
}
|
|
147
|
+
async function walkFiles(dir) {
|
|
148
|
+
const out = [];
|
|
149
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
150
|
+
for (const entry of entries) {
|
|
151
|
+
const path = join(dir, entry.name);
|
|
152
|
+
if (entry.isDirectory()) {
|
|
153
|
+
out.push(...(await walkFiles(path)));
|
|
154
|
+
}
|
|
155
|
+
else if (entry.isFile()) {
|
|
156
|
+
out.push(path);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
function sameMembers(left, right) {
|
|
162
|
+
if (left.length !== right.length)
|
|
163
|
+
return false;
|
|
164
|
+
const rightSet = new Set(right);
|
|
165
|
+
return left.every((value) => rightSet.has(value));
|
|
166
|
+
}
|
|
167
|
+
function uniqueStrings(values) {
|
|
168
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=profile-bundle-installation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-bundle-installation.js","sourceRoot":"","sources":["../../src/core/profile-bundle-installation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type ProjectConfig, type SourceConfig, type SourceEntry } from "./config.js";
|
|
2
|
+
import { type OriginInference } from "./origin-detection.js";
|
|
3
|
+
export type PrepareSyncOptions = {
|
|
4
|
+
source?: string;
|
|
5
|
+
all?: boolean;
|
|
6
|
+
allowNetwork?: boolean;
|
|
7
|
+
authState?: string;
|
|
8
|
+
authProfile?: string;
|
|
9
|
+
browser?: boolean;
|
|
10
|
+
dryRun?: boolean;
|
|
11
|
+
runId?: string;
|
|
12
|
+
};
|
|
13
|
+
export type PrepareSyncStatus = "materialized" | "metadata-only" | "blocked-auth" | "source-gap" | "skipped" | "failed";
|
|
14
|
+
export type PrepareSyncResult = {
|
|
15
|
+
envelopeVersion?: 1;
|
|
16
|
+
sourceKey: string;
|
|
17
|
+
sourcePath: string;
|
|
18
|
+
rawLane?: string;
|
|
19
|
+
provider?: string;
|
|
20
|
+
adapter?: string;
|
|
21
|
+
strategy: string;
|
|
22
|
+
status: PrepareSyncStatus;
|
|
23
|
+
origin?: string;
|
|
24
|
+
resolvedOrigin?: string;
|
|
25
|
+
contentType?: string;
|
|
26
|
+
snapshot?: string;
|
|
27
|
+
snapshotHash?: string;
|
|
28
|
+
previousSnapshotHash?: string;
|
|
29
|
+
metadata?: Record<string, unknown>;
|
|
30
|
+
changed: boolean;
|
|
31
|
+
reason: string;
|
|
32
|
+
validation: Record<string, "pass" | "fail" | "skipped">;
|
|
33
|
+
};
|
|
34
|
+
export type PrepareSyncBase = Omit<PrepareSyncResult, "strategy" | "status" | "changed" | "reason" | "validation">;
|
|
35
|
+
export type SourceSnapshotProviderAdapter = "confluence" | "jira" | "gitlab" | "design-source";
|
|
36
|
+
export type SourceSnapshotContext = {
|
|
37
|
+
target: string;
|
|
38
|
+
config: ProjectConfig;
|
|
39
|
+
entry: SourceEntry;
|
|
40
|
+
source: SourceConfig;
|
|
41
|
+
origin: OriginInference;
|
|
42
|
+
opts: PrepareSyncOptions;
|
|
43
|
+
snapshot: string;
|
|
44
|
+
snapshotPath: string;
|
|
45
|
+
previousSnapshotHash?: string;
|
|
46
|
+
base: PrepareSyncBase;
|
|
47
|
+
};
|
|
48
|
+
export type SourceSnapshotAdapterHandlers = {
|
|
49
|
+
dryRun: (context: SourceSnapshotContext) => Promise<PrepareSyncResult> | PrepareSyncResult;
|
|
50
|
+
local: (context: SourceSnapshotContext) => Promise<PrepareSyncResult>;
|
|
51
|
+
provider: (context: SourceSnapshotContext, adapter: SourceSnapshotProviderAdapter) => Promise<PrepareSyncResult | null>;
|
|
52
|
+
repository: (context: SourceSnapshotContext) => Promise<PrepareSyncResult>;
|
|
53
|
+
url: (context: SourceSnapshotContext) => Promise<PrepareSyncResult>;
|
|
54
|
+
providerManaged: (context: SourceSnapshotContext) => Promise<PrepareSyncResult> | PrepareSyncResult;
|
|
55
|
+
};
|
|
56
|
+
export declare function createSourceSnapshotContext(target: string, config: ProjectConfig, entry: SourceEntry, opts: PrepareSyncOptions, previousSnapshotHashFor: (snapshotPath: string) => Promise<string | undefined>): Promise<SourceSnapshotContext>;
|
|
57
|
+
export declare function acquireSourceSnapshot(context: SourceSnapshotContext, handlers: SourceSnapshotAdapterHandlers): Promise<PrepareSyncResult>;
|
|
58
|
+
export declare function selectSourceSnapshotProviderAdapter(source: SourceConfig, origin: OriginInference): SourceSnapshotProviderAdapter | undefined;
|
|
59
|
+
export declare function chooseSourceSnapshotStrategy(method: string): string;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { resolveSourceSnapshot, } from "./config.js";
|
|
3
|
+
import { inferSourceOrigin } from "./origin-detection.js";
|
|
4
|
+
export async function createSourceSnapshotContext(target, config, entry, opts, previousSnapshotHashFor) {
|
|
5
|
+
const source = entry.source;
|
|
6
|
+
const origin = inferSourceOrigin(source);
|
|
7
|
+
const snapshot = resolveSourceSnapshot(config, entry);
|
|
8
|
+
const snapshotPath = resolve(target, snapshot);
|
|
9
|
+
const previousSnapshotHash = await previousSnapshotHashFor(snapshotPath);
|
|
10
|
+
const base = {
|
|
11
|
+
envelopeVersion: 1,
|
|
12
|
+
sourceKey: entry.id,
|
|
13
|
+
sourcePath: entry.path,
|
|
14
|
+
rawLane: entry.rawLane,
|
|
15
|
+
provider: origin.provider,
|
|
16
|
+
origin: origin.ref,
|
|
17
|
+
snapshot,
|
|
18
|
+
previousSnapshotHash,
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
target,
|
|
22
|
+
config,
|
|
23
|
+
entry,
|
|
24
|
+
source,
|
|
25
|
+
origin,
|
|
26
|
+
opts,
|
|
27
|
+
snapshot,
|
|
28
|
+
snapshotPath,
|
|
29
|
+
previousSnapshotHash,
|
|
30
|
+
base,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export async function acquireSourceSnapshot(context, handlers) {
|
|
34
|
+
if (context.opts.dryRun)
|
|
35
|
+
return handlers.dryRun(context);
|
|
36
|
+
if (context.origin.method === "local")
|
|
37
|
+
return handlers.local(context);
|
|
38
|
+
const providerAdapter = selectSourceSnapshotProviderAdapter(context.source, context.origin);
|
|
39
|
+
if (providerAdapter) {
|
|
40
|
+
const result = await handlers.provider(context, providerAdapter);
|
|
41
|
+
if (result)
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
if (context.origin.method === "repository")
|
|
45
|
+
return handlers.repository(context);
|
|
46
|
+
if (context.origin.method === "url")
|
|
47
|
+
return handlers.url(context);
|
|
48
|
+
return handlers.providerManaged(context);
|
|
49
|
+
}
|
|
50
|
+
export function selectSourceSnapshotProviderAdapter(source, origin) {
|
|
51
|
+
const keys = [
|
|
52
|
+
origin.provider,
|
|
53
|
+
origin.kind,
|
|
54
|
+
source.origin?.provider,
|
|
55
|
+
source.origin?.kind,
|
|
56
|
+
source.kind,
|
|
57
|
+
source.type,
|
|
58
|
+
].map((value) => normalizeAdapterKey(typeof value === "string" ? value : undefined));
|
|
59
|
+
if (keys.some((value) => value.includes("confluence")))
|
|
60
|
+
return "confluence";
|
|
61
|
+
if (keys.some((value) => value.includes("jira")))
|
|
62
|
+
return "jira";
|
|
63
|
+
if (keys.some((value) => value.includes("gitlab")))
|
|
64
|
+
return "gitlab";
|
|
65
|
+
if (keys.some((value) => ["figma", "modao", "mastergo", "design", "design-asset", "design-source"].includes(value))) {
|
|
66
|
+
return "design-source";
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
export function chooseSourceSnapshotStrategy(method) {
|
|
71
|
+
if (method === "local")
|
|
72
|
+
return "local-copy-structured-markdown";
|
|
73
|
+
if (method === "repository")
|
|
74
|
+
return "repository-metadata-only";
|
|
75
|
+
if (method === "url")
|
|
76
|
+
return "playwright-auth-or-direct-fetch";
|
|
77
|
+
return "confirm-acquisition-method";
|
|
78
|
+
}
|
|
79
|
+
function normalizeAdapterKey(value) {
|
|
80
|
+
return value?.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") ?? "";
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=source-snapshot-adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-snapshot-adapters.js","sourceRoot":"","sources":["../../src/core/source-snapshot-adapters.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,7 @@ const PREPROPOSAL_ROLE_NAMES = [
|
|
|
17
17
|
"planner",
|
|
18
18
|
"ux-specialist",
|
|
19
19
|
"design-specialist",
|
|
20
|
+
"frontend-engineer",
|
|
20
21
|
"architect",
|
|
21
22
|
"qa-engineer",
|
|
22
23
|
"researcher",
|
|
@@ -69,14 +70,14 @@ const BUILTIN_ROLE_POOL = {
|
|
|
69
70
|
}),
|
|
70
71
|
rolePoolEntry("frontend-engineer", {
|
|
71
72
|
subagentType: "executor",
|
|
72
|
-
stages: ["design"],
|
|
73
|
+
stages: ["preproposal", "design"],
|
|
73
74
|
lanes: ["frontend", "web", "client", "mobile"],
|
|
74
75
|
activation: "when frontend implementation, routing, state, or UI integration is in scope",
|
|
75
76
|
reason: "map UI implementation, routing, state, and component integration risk",
|
|
76
77
|
}),
|
|
77
78
|
rolePoolEntry("design-specialist", {
|
|
78
79
|
subagentType: "designer",
|
|
79
|
-
stages: ["prepare", "preproposal"
|
|
80
|
+
stages: ["prepare", "preproposal"],
|
|
80
81
|
lanes: ["design", "ui", "visual"],
|
|
81
82
|
activation: "when design, UI, visual, prototype, or asset sources are configured",
|
|
82
83
|
reason: "inspect design assets, screens, visual states, and design-source gaps",
|
|
@@ -173,10 +174,12 @@ const ROLE_CONTRACTS = {
|
|
|
173
174
|
".zsk/evidence/{scope}/{run}/integration-summary.md",
|
|
174
175
|
".zsk/raws/manifest.json when prepare snapshots change",
|
|
175
176
|
".zsk/raws/manifest.json and .zsk/raws/index.md when preproposal raw resources change",
|
|
177
|
+
".zsk/raws/prepare/product/{topic}/intake-clarity.md when running preproposal",
|
|
176
178
|
".zsk/evidence/preproposal/{run}/readiness-review.md when running preproposal",
|
|
177
179
|
],
|
|
178
180
|
evidenceRequired: [
|
|
179
181
|
"integrated lane status with pass/blocker/waived reason for each role",
|
|
182
|
+
"source-discoverable questions answered before user clarification when running preproposal",
|
|
180
183
|
"confirmation that shared/global artifacts were updated only after lane validation",
|
|
181
184
|
],
|
|
182
185
|
forbiddenDecisions: [
|
|
@@ -190,10 +193,11 @@ const ROLE_CONTRACTS = {
|
|
|
190
193
|
doesNotOwn: ["backend implementation details", "technical feasibility signoff without architect/engineer evidence"],
|
|
191
194
|
outputs: [
|
|
192
195
|
".zsk/evidence/{scope}/{run}/product-source-report.md",
|
|
196
|
+
".zsk/raws/prepare/product/{topic}/intake-clarity.md when running preproposal",
|
|
193
197
|
".zsk/raws/prepare/product/{topic}/product-brief.md when running preproposal",
|
|
194
198
|
".zsk/evidence/preproposal/{run}/checkpoint-product-review.md when running preproposal",
|
|
195
199
|
],
|
|
196
|
-
evidenceRequired: ["requirement/source IDs or paths behind each product claim", "open requirement gaps and acceptance risks", "product checkpoint verdict before roadmap/decomposition when running preproposal"],
|
|
200
|
+
evidenceRequired: ["requirement/source IDs or paths behind each product claim", "accepted clarifications, inferred assumptions, and one blocking question when running preproposal", "open requirement gaps and acceptance risks", "product checkpoint verdict before roadmap/decomposition when running preproposal"],
|
|
197
201
|
forbiddenDecisions: ["Do not rewrite technical design or implementation ownership.", "Do not turn weak/inferred evidence into accepted requirements."],
|
|
198
202
|
stopCondition: "Product facts, gaps, and acceptance risks are explicit and handed to lead-integrator.",
|
|
199
203
|
},
|
|
@@ -229,33 +233,36 @@ const ROLE_CONTRACTS = {
|
|
|
229
233
|
stopCondition: "Backend facts and gaps are reported with source references and no shared artifact edits pending.",
|
|
230
234
|
},
|
|
231
235
|
"frontend-engineer": {
|
|
232
|
-
owns: ["UI implementation, routing, state, component integration, and frontend framework constraints"],
|
|
236
|
+
owns: ["UI implementation, routing, state, page/module-to-code component mapping, component integration, and frontend framework constraints"],
|
|
233
237
|
doesNotOwn: ["source-of-truth product decisions", "backend/API correctness signoff"],
|
|
234
238
|
outputs: [".zsk/evidence/{scope}/{run}/frontend-impact-report.md"],
|
|
235
|
-
evidenceRequired: ["component/route/state file references", "UI implementation risks and validation hooks"],
|
|
239
|
+
evidenceRequired: ["component/route/state file references", "page/module-to-code mapping coverage", "UI implementation risks and validation hooks"],
|
|
236
240
|
forbiddenDecisions: ["Do not reinterpret acceptance criteria without product-owner handoff.", "Do not approve API behavior without backend evidence."],
|
|
237
241
|
stopCondition: "Frontend impact and validation needs are clear for lead-integrator.",
|
|
238
242
|
},
|
|
239
243
|
"design-specialist": {
|
|
240
|
-
owns: ["design assets, visual constraints, screen/state inventory, and design snapshot validation"],
|
|
244
|
+
owns: ["design assets, visual constraints, screen/state inventory, provider source maps, and design snapshot validation"],
|
|
241
245
|
doesNotOwn: ["backend/API correctness", "final product scope acceptance"],
|
|
242
246
|
outputs: [
|
|
243
247
|
".zsk/evidence/{scope}/{run}/design-asset-report.md",
|
|
244
248
|
".zsk/raws/prepare/design/{topic}/design-source-needs.md when running preproposal",
|
|
249
|
+
".zsk/raws/prepare/design/{topic}/design-source-map.md when provider-backed design sources are used",
|
|
245
250
|
],
|
|
246
|
-
evidenceRequired: ["design/prototype source references", "screen/state map and missing asset list"],
|
|
251
|
+
evidenceRequired: ["design/prototype source references", "screen/state map, provider source coverage, and missing asset list"],
|
|
247
252
|
forbiddenDecisions: ["Do not infer implementation truth from design assets.", "Do not store auth state or exported private assets outside declared scope."],
|
|
248
253
|
stopCondition: "Design assets are mapped or blocked with provider/auth evidence.",
|
|
249
254
|
},
|
|
250
255
|
"ux-specialist": {
|
|
251
|
-
owns: ["user flows, interaction constraints, usability risks, and UX source validation"],
|
|
256
|
+
owns: ["user flows, interaction handoff, interaction constraints, usability risks, and UX source validation"],
|
|
252
257
|
doesNotOwn: ["backend/API correctness", "business priority decisions"],
|
|
253
258
|
outputs: [
|
|
254
259
|
".zsk/evidence/{scope}/{run}/ux-source-report.md",
|
|
255
260
|
".zsk/raws/prepare/ux/{topic}/ux-readiness.md when running preproposal",
|
|
261
|
+
".zsk/raws/prepare/ux/{topic}/interaction-handoff.md when UI, UX, or design-source interaction is triggered",
|
|
256
262
|
".zsk/evidence/preproposal/{run}/checkpoint-ux-review.md when running preproposal",
|
|
263
|
+
".zsk/evidence/preproposal/{run}/checkpoint-interaction-review.md when interaction handoff is triggered",
|
|
257
264
|
],
|
|
258
|
-
evidenceRequired: ["flow/source references", "usability risks and unresolved interaction questions"],
|
|
265
|
+
evidenceRequired: ["flow/source references", "AI brief draft status", "page/module interaction detail coverage", "interaction/state/a11y coverage", "usability risks and unresolved interaction questions"],
|
|
259
266
|
forbiddenDecisions: ["Do not approve product scope or technical design alone.", "Do not resolve UX/product conflicts silently."],
|
|
260
267
|
stopCondition: "UX facts, questions, and risks are ready for lead integration.",
|
|
261
268
|
},
|
|
@@ -464,7 +471,7 @@ function seedFromRolePool(role, entries, overrides = {}) {
|
|
|
464
471
|
reason: overrides.reason ?? role.reason ?? `configured ${role.role} role`,
|
|
465
472
|
entries,
|
|
466
473
|
activation: overrides.activation ?? role.activation,
|
|
467
|
-
extraInputs: role.extraInputs,
|
|
474
|
+
extraInputs: unique([...(role.extraInputs ?? []), ...(overrides.extraInputs ?? [])]),
|
|
468
475
|
writeScope: unique([...(role.writeScope ?? []), ...(overrides.writeScope ?? [])]),
|
|
469
476
|
outputs: unique([...(role.outputs ?? []), ...(overrides.outputs ?? [])]),
|
|
470
477
|
evidenceRequired: unique([...(role.evidenceRequired ?? []), ...(overrides.evidenceRequired ?? [])]),
|
|
@@ -559,7 +566,7 @@ export function buildStaffingPlan(target, config, opts = {}, rolePool = BUILTIN_
|
|
|
559
566
|
const reviewMode = reviewModeForReviewTarget(reviewTarget);
|
|
560
567
|
const timeoutPolicy = packetTimeoutPolicyFromConfig(config);
|
|
561
568
|
const entries = flattenProjectSources(config.sources);
|
|
562
|
-
const seeds = seedRoles(stage, skill, entries, rolePool, reviewMode);
|
|
569
|
+
const seeds = seedRoles(stage, skill, entries, rolePool, reviewMode, opts.module);
|
|
563
570
|
const orchestration = buildOrchestrationPlan(surface, stage, entries, seeds, config);
|
|
564
571
|
const roles = seeds.map((seed) => buildRole(seed, stage, skill, orchestration, config));
|
|
565
572
|
const dir = resolve(target, getWorkspacePath(config, "evidenceRoot"), "dispatch", runId);
|
|
@@ -660,7 +667,7 @@ function markPacketStale(packet, now) {
|
|
|
660
667
|
blocker: "No heartbeat was recorded before the packet deadline; route this lane through leader-sequential fallback or re-emit with a new packet.",
|
|
661
668
|
};
|
|
662
669
|
}
|
|
663
|
-
function seedRoles(stage, skill, entries, rolePool, reviewMode) {
|
|
670
|
+
function seedRoles(stage, skill, entries, rolePool, reviewMode, module) {
|
|
664
671
|
const seeds = new Map();
|
|
665
672
|
const poolRoles = Object.values(rolePool.roles);
|
|
666
673
|
for (const role of poolRoles) {
|
|
@@ -706,13 +713,26 @@ function seedRoles(stage, skill, entries, rolePool, reviewMode) {
|
|
|
706
713
|
}
|
|
707
714
|
}
|
|
708
715
|
if (stage === "preproposal" || skill === "preproposal") {
|
|
716
|
+
const topic = module ?? "{topic}";
|
|
717
|
+
const moduleInputs = module
|
|
718
|
+
? [
|
|
719
|
+
`.zsk/modules/${module}/module.yaml`,
|
|
720
|
+
`.zsk/modules/${module}/CONTEXT.md`,
|
|
721
|
+
`.zsk/modules/${module}/proposal.md when present`,
|
|
722
|
+
`.zsk/modules/${module}/spec.md when present`,
|
|
723
|
+
`.zsk/modules/${module}/design.md when present`,
|
|
724
|
+
`.zsk/modules/${module}/tasks.md when present`,
|
|
725
|
+
]
|
|
726
|
+
: [];
|
|
709
727
|
for (const roleName of PREPROPOSAL_ROLE_NAMES) {
|
|
710
728
|
const role = rolePool.roles[roleName];
|
|
711
729
|
if (!role)
|
|
712
730
|
continue;
|
|
713
731
|
addSeed(seeds, seedFromRolePool(role, [], {
|
|
714
732
|
activation: "required for preproposal product/roadmap/UX/readiness checkpoint coverage",
|
|
715
|
-
reason:
|
|
733
|
+
reason: module
|
|
734
|
+
? role.reason || `produce and review module-scoped preproposal raw resources for ${module} before formal proposal`
|
|
735
|
+
: role.reason || "produce and review preproposal raw resources before formal proposal",
|
|
716
736
|
writeScope: [
|
|
717
737
|
".zsk/raws/prepare/product/**",
|
|
718
738
|
".zsk/raws/prepare/ux/**",
|
|
@@ -723,23 +743,37 @@ function seedRoles(stage, skill, entries, rolePool, reviewMode) {
|
|
|
723
743
|
...role.writeScope,
|
|
724
744
|
],
|
|
725
745
|
outputs: [
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
746
|
+
`.zsk/raws/prepare/product/${topic}/intake-clarity.md`,
|
|
747
|
+
`.zsk/raws/prepare/product/${topic}/product-brief.md`,
|
|
748
|
+
`.zsk/raws/prepare/product/${topic}/roadmap.md`,
|
|
749
|
+
`.zsk/raws/prepare/ux/${topic}/ux-readiness.md`,
|
|
750
|
+
`.zsk/raws/prepare/ux/${topic}/interaction-handoff.md when UI/UX/design-source interaction is triggered`,
|
|
751
|
+
`.zsk/raws/prepare/design/${topic}/design-source-needs.md`,
|
|
752
|
+
`.zsk/raws/prepare/design/${topic}/design-source-map.md when provider-backed design sources are used`,
|
|
730
753
|
".zsk/evidence/preproposal/{run}/checkpoint-*.md",
|
|
731
754
|
".zsk/evidence/preproposal/{run}/readiness-review.md",
|
|
732
755
|
...role.outputs,
|
|
733
756
|
],
|
|
734
757
|
evidenceRequired: [
|
|
758
|
+
...(module ? [
|
|
759
|
+
`module target is fixed to ${module}; module docs and raw sources are challenged before widening scope`,
|
|
760
|
+
`interaction handoff and design-source map use ${module} as the default raw topic unless a narrower page/topic is justified`,
|
|
761
|
+
] : []),
|
|
762
|
+
"source-discoverable questions answered before user clarification",
|
|
763
|
+
"accepted clarifications, inferred assumptions, and one blocking question are separated",
|
|
735
764
|
"product checkpoint passes before roadmap/decomposition",
|
|
736
765
|
"roadmap/decomposition checkpoint passes before UX/design-readiness",
|
|
766
|
+
"AI brief drafts and candidate code component mapping exist for source-backed page/module interaction details before asking humans to fill gaps",
|
|
767
|
+
"interaction handoff separates sourced provider facts from accepted decisions, assumptions, and missing page/module interaction details when triggered",
|
|
737
768
|
"UX/design-readiness checkpoint passes before readiness handoff",
|
|
738
769
|
"final readiness review passes or blocks with owner, missing input, impact, and next action",
|
|
739
770
|
...role.evidenceRequired,
|
|
740
771
|
],
|
|
772
|
+
...(moduleInputs.length > 0 ? { extraInputs: moduleInputs } : {}),
|
|
741
773
|
contract: {
|
|
742
|
-
owns:
|
|
774
|
+
owns: module
|
|
775
|
+
? [`preproposal lane facts, source gaps, checkpoint evidence, and readiness handoff for module ${module}`]
|
|
776
|
+
: ["preproposal lane facts, source gaps, checkpoint evidence, and readiness handoff for this role"],
|
|
743
777
|
doesNotOwn: ["formal module proposal/spec/design/task artifacts", "formal test cases", "implementation edits"],
|
|
744
778
|
forbiddenDecisions: ["Do not skip checkpoint order.", "Do not treat scenario seeds as formal post-design test cases."],
|
|
745
779
|
stopCondition: "Preproposal lane output is reviewable, or blockers are recorded for the checkpoint owner.",
|