@lumenflow/core 1.0.0 → 1.3.2
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/arg-parser.d.ts +6 -0
- package/dist/arg-parser.js +57 -1
- package/dist/backlog-generator.js +1 -1
- package/dist/backlog-sync-validator.js +3 -3
- package/dist/branch-check.d.ts +21 -0
- package/dist/branch-check.js +77 -0
- package/dist/cli/is-agent-branch.d.ts +11 -0
- package/dist/cli/is-agent-branch.js +15 -0
- package/dist/code-paths-overlap.js +2 -2
- package/dist/error-handler.d.ts +1 -0
- package/dist/error-handler.js +4 -1
- package/dist/git-adapter.d.ts +23 -0
- package/dist/git-adapter.js +38 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -0
- package/dist/lane-checker.d.ts +36 -3
- package/dist/lane-checker.js +128 -17
- package/dist/lane-inference.js +3 -4
- package/dist/lumenflow-config-schema.d.ts +125 -0
- package/dist/lumenflow-config-schema.js +76 -0
- package/dist/lumenflow-home.d.ts +130 -0
- package/dist/lumenflow-home.js +208 -0
- package/dist/manual-test-validator.js +1 -1
- package/dist/orchestration-rules.d.ts +1 -1
- package/dist/orchestration-rules.js +2 -2
- package/dist/orphan-detector.d.ts +16 -0
- package/dist/orphan-detector.js +24 -0
- package/dist/path-classifiers.d.ts +1 -1
- package/dist/path-classifiers.js +1 -1
- package/dist/rebase-artifact-cleanup.d.ts +17 -0
- package/dist/rebase-artifact-cleanup.js +49 -8
- package/dist/spawn-strategy.d.ts +53 -0
- package/dist/spawn-strategy.js +106 -0
- package/dist/spec-branch-helpers.d.ts +118 -0
- package/dist/spec-branch-helpers.js +192 -0
- package/dist/stamp-utils.d.ts +10 -0
- package/dist/stamp-utils.js +17 -19
- package/dist/token-counter.js +2 -2
- package/dist/wu-consistency-checker.d.ts +2 -0
- package/dist/wu-consistency-checker.js +40 -6
- package/dist/wu-constants.d.ts +98 -3
- package/dist/wu-constants.js +108 -3
- package/dist/wu-create-validators.d.ts +40 -2
- package/dist/wu-create-validators.js +76 -2
- package/dist/wu-done-branch-only.js +9 -0
- package/dist/wu-done-branch-utils.d.ts +10 -0
- package/dist/wu-done-branch-utils.js +31 -0
- package/dist/wu-done-cleanup.d.ts +8 -0
- package/dist/wu-done-cleanup.js +122 -0
- package/dist/wu-done-docs-generate.d.ts +73 -0
- package/dist/wu-done-docs-generate.js +108 -0
- package/dist/wu-done-docs-only.d.ts +20 -0
- package/dist/wu-done-docs-only.js +65 -0
- package/dist/wu-done-errors.d.ts +17 -0
- package/dist/wu-done-errors.js +24 -0
- package/dist/wu-done-inputs.d.ts +12 -0
- package/dist/wu-done-inputs.js +51 -0
- package/dist/wu-done-metadata.d.ts +100 -0
- package/dist/wu-done-metadata.js +193 -0
- package/dist/wu-done-paths.d.ts +69 -0
- package/dist/wu-done-paths.js +237 -0
- package/dist/wu-done-preflight.d.ts +48 -0
- package/dist/wu-done-preflight.js +185 -0
- package/dist/wu-done-validation.d.ts +82 -0
- package/dist/wu-done-validation.js +340 -0
- package/dist/wu-done-validators.d.ts +13 -409
- package/dist/wu-done-validators.js +9 -1225
- package/dist/wu-done-worktree.d.ts +0 -1
- package/dist/wu-done-worktree.js +24 -30
- package/dist/wu-schema.js +4 -4
- package/dist/wu-spawn-skills.d.ts +19 -0
- package/dist/wu-spawn-skills.js +148 -0
- package/dist/wu-spawn.d.ts +17 -4
- package/dist/wu-spawn.js +113 -177
- package/dist/wu-validation.d.ts +1 -0
- package/dist/wu-validation.js +21 -1
- package/dist/wu-validator.d.ts +51 -0
- package/dist/wu-validator.js +108 -0
- package/package.json +12 -8
|
@@ -132,7 +132,6 @@ export declare function checkMergeConflicts(branch: any): Promise<void>;
|
|
|
132
132
|
* @throws {Error} When code_paths defined but files not modified in commits
|
|
133
133
|
*/
|
|
134
134
|
export declare function checkEmptyMerge(branch: any, doc?: any): Promise<void>;
|
|
135
|
-
export declare function isBranchAlreadyMerged(branch: any): Promise<boolean>;
|
|
136
135
|
/**
|
|
137
136
|
* Merge lane branch to main with exponential backoff retry (WU-1747)
|
|
138
137
|
*
|
package/dist/wu-done-worktree.js
CHANGED
|
@@ -28,12 +28,16 @@ import { BRANCHES, REMOTES, THRESHOLDS, LOG_PREFIX, EMOJI, COMMIT_FORMATS, BOX,
|
|
|
28
28
|
import { RECOVERY, REBASE, PREFLIGHT, MERGE } from './wu-done-messages.js';
|
|
29
29
|
import { getDriftLevel, DRIFT_LEVELS } from './branch-drift.js';
|
|
30
30
|
import { createError, ErrorCodes } from './error-handler.js';
|
|
31
|
+
import { createRecoveryError, createValidationError } from './wu-done-errors.js';
|
|
31
32
|
import { validateDoneWU, validateAndNormalizeWUYAML } from './wu-schema.js';
|
|
32
33
|
import { assertTransition } from './state-machine.js';
|
|
33
34
|
import { detectZombieState, resetWorktreeYAMLForRecovery, getRecoveryAttemptCount, incrementRecoveryAttempt, clearRecoveryAttempts, shouldEscalateToManualIntervention, MAX_RECOVERY_ATTEMPTS, } from './wu-recovery.js';
|
|
34
35
|
import { isPRModeEnabled, createPR, printPRCreatedMessage } from './wu-done-pr.js';
|
|
36
|
+
import { isBranchAlreadyMerged } from './wu-done-branch-utils.js';
|
|
35
37
|
// WU-1371: Import rebase artifact cleanup functions
|
|
36
38
|
import { detectRebasedArtifacts, cleanupRebasedArtifacts } from './rebase-artifact-cleanup.js';
|
|
39
|
+
// WU-1061: Import docs regeneration utilities
|
|
40
|
+
import { maybeRegenerateAndStageDocs } from './wu-done-docs-generate.js';
|
|
37
41
|
import { WUTransaction, createTransactionSnapshot, restoreFromSnapshot } from './wu-transaction.js';
|
|
38
42
|
// WU-1506: Import backlog invariant repair
|
|
39
43
|
// WU-1574: Removed repairBacklogInvariants - no longer needed with state store architecture
|
|
@@ -113,7 +117,7 @@ export async function executeWorktreeCompletion(context) {
|
|
|
113
117
|
console.log(`${BOX.SIDE} Or reset the recovery counter:`);
|
|
114
118
|
console.log(`${BOX.SIDE} rm .beacon/recovery/${id}.recovery`);
|
|
115
119
|
console.log(BOX.BOT);
|
|
116
|
-
throw
|
|
120
|
+
throw createRecoveryError(`Recovery loop detected for ${id} after ${attemptCount} attempts. Manual intervention required.`, { wuId: id, attemptCount, maxAttempts: MAX_RECOVERY_ATTEMPTS });
|
|
117
121
|
}
|
|
118
122
|
// Increment attempt counter before trying recovery
|
|
119
123
|
const newAttemptCount = incrementRecoveryAttempt(id);
|
|
@@ -184,7 +188,7 @@ export async function executeWorktreeCompletion(context) {
|
|
|
184
188
|
// This catches schema issues early and auto-fixes normalizable problems
|
|
185
189
|
const normalizeResult = validateAndNormalizeWUYAML(docForUpdate);
|
|
186
190
|
if (!normalizeResult.valid) {
|
|
187
|
-
throw
|
|
191
|
+
throw createValidationError(`WU YAML validation failed:\n - ${normalizeResult.errors.join('\n - ')}\n\nNext step: Fix the validation errors in ${workingWUPath} and rerun wu:done`, { wuId: id });
|
|
188
192
|
}
|
|
189
193
|
// WU-1811: If normalizations were applied, write back to YAML file
|
|
190
194
|
if (normalizeResult.wasNormalized) {
|
|
@@ -197,7 +201,7 @@ export async function executeWorktreeCompletion(context) {
|
|
|
197
201
|
// Validate done-specific completeness (uses normalized data)
|
|
198
202
|
const completenessResult = validateDoneWU(normalizeResult.normalized);
|
|
199
203
|
if (!completenessResult.valid) {
|
|
200
|
-
throw
|
|
204
|
+
throw createValidationError(`Cannot mark WU as done - spec incomplete:\n ${completenessResult.errors.join('\n ')}\n\nNext step: Update ${workingWUPath} to meet completion requirements and rerun wu:done`, { wuId: id });
|
|
201
205
|
}
|
|
202
206
|
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} All validations passed`);
|
|
203
207
|
// ======================================================================
|
|
@@ -252,13 +256,23 @@ export async function executeWorktreeCompletion(context) {
|
|
|
252
256
|
stampPath: workingStampPath,
|
|
253
257
|
});
|
|
254
258
|
if (!postMutationResult.valid) {
|
|
255
|
-
throw
|
|
259
|
+
throw createValidationError(`Post-mutation validation failed:\n ${postMutationResult.errors.join('\n ')}`, { wuId: id, errors: postMutationResult.errors });
|
|
256
260
|
}
|
|
257
261
|
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Post-mutation validation passed (WU-1617)`);
|
|
258
262
|
// ======================================================================
|
|
259
263
|
// PHASE 4: GIT OPERATIONS (stage, format, commit)
|
|
260
264
|
// Files are now written - proceed with git operations
|
|
261
265
|
// ======================================================================
|
|
266
|
+
// ======================================================================
|
|
267
|
+
// WU-1061: Regenerate docs if doc-source files changed
|
|
268
|
+
// This runs BEFORE stageAndFormatMetadata to include doc outputs
|
|
269
|
+
// in the single atomic commit
|
|
270
|
+
// Uses main as base to detect changes introduced by this WU
|
|
271
|
+
// ======================================================================
|
|
272
|
+
await maybeRegenerateAndStageDocs({
|
|
273
|
+
baseBranch: BRANCHES.MAIN,
|
|
274
|
+
repoRoot: worktreePath,
|
|
275
|
+
});
|
|
262
276
|
// Stage and format files
|
|
263
277
|
await stageAndFormatMetadata({
|
|
264
278
|
id,
|
|
@@ -930,7 +944,12 @@ export async function checkEmptyMerge(branch, doc = null) {
|
|
|
930
944
|
const missingCodePaths = codePaths.filter((codePath) => !modifiedFiles.some((modified) => modified.includes(codePath) || codePath.includes(modified)));
|
|
931
945
|
if (missingCodePaths.length > 0) {
|
|
932
946
|
// BLOCK: code_paths defined but files not modified
|
|
933
|
-
throw
|
|
947
|
+
throw createValidationError(PREFLIGHT.CODE_PATHS_NOT_MODIFIED(missingCodePaths), {
|
|
948
|
+
branch,
|
|
949
|
+
codePaths,
|
|
950
|
+
missingCodePaths,
|
|
951
|
+
modifiedFiles,
|
|
952
|
+
});
|
|
934
953
|
}
|
|
935
954
|
// All code_paths files were modified
|
|
936
955
|
console.log(PREFLIGHT.CODE_PATHS_VERIFIED);
|
|
@@ -951,31 +970,6 @@ export async function checkEmptyMerge(branch, doc = null) {
|
|
|
951
970
|
console.warn(`${LOG_PREFIX.DONE} Warning: Could not check for empty merge: ${e.message}`);
|
|
952
971
|
}
|
|
953
972
|
}
|
|
954
|
-
/**
|
|
955
|
-
* Check if branch is already merged to main
|
|
956
|
-
*
|
|
957
|
-
* @param {string} branch - Lane branch name
|
|
958
|
-
* @returns {Promise<boolean>} Whether branch is already merged
|
|
959
|
-
*/
|
|
960
|
-
/** @constant {number} SHA_SHORT_LENGTH - Length of shortened git SHA hashes for display */
|
|
961
|
-
const SHA_SHORT_LENGTH = 8;
|
|
962
|
-
export async function isBranchAlreadyMerged(branch) {
|
|
963
|
-
const gitAdapter = getGitForCwd();
|
|
964
|
-
try {
|
|
965
|
-
const branchTip = (await gitAdapter.getCommitHash(branch)).trim();
|
|
966
|
-
const mergeBase = (await gitAdapter.mergeBase(BRANCHES.MAIN, branch)).trim();
|
|
967
|
-
const mainHead = (await gitAdapter.getCommitHash(BRANCHES.MAIN)).trim();
|
|
968
|
-
if (branchTip === mergeBase) {
|
|
969
|
-
console.log(PREFLIGHT.BRANCH_INFO(branch, branchTip.substring(0, SHA_SHORT_LENGTH), mergeBase.substring(0, SHA_SHORT_LENGTH), mainHead.substring(0, SHA_SHORT_LENGTH)));
|
|
970
|
-
return true;
|
|
971
|
-
}
|
|
972
|
-
return false;
|
|
973
|
-
}
|
|
974
|
-
catch (e) {
|
|
975
|
-
console.warn(`${LOG_PREFIX.DONE} Warning: Could not check if branch is merged: ${e.message}`);
|
|
976
|
-
return false;
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
973
|
async function isMainAncestorOfBranch(gitAdapter, branch) {
|
|
980
974
|
try {
|
|
981
975
|
await gitAdapter.raw([GIT_COMMANDS.MERGE_BASE, GIT_FLAGS.IS_ANCESTOR, BRANCHES.MAIN, branch]);
|
package/dist/wu-schema.js
CHANGED
|
@@ -109,9 +109,7 @@ const normalizedMultilineString = z.string().transform((s) => s.replace(/\\n/g,
|
|
|
109
109
|
*
|
|
110
110
|
* WU-1750: After normalization, paths should be clean. This catches any edge cases.
|
|
111
111
|
*/
|
|
112
|
-
const filePathItem = z
|
|
113
|
-
.string()
|
|
114
|
-
.refine((s) => !s.includes('\n') && !s.includes('\\n'), {
|
|
112
|
+
const filePathItem = z.string().refine((s) => !s.includes('\n') && !s.includes('\\n'), {
|
|
115
113
|
message: 'File path cannot contain newlines - split into separate array items',
|
|
116
114
|
});
|
|
117
115
|
/**
|
|
@@ -828,10 +826,12 @@ export function validateWUCompleteness(wu) {
|
|
|
828
826
|
warnings.push(`${wu.id}: Missing 'tests.manual' field. Add manual verification steps for acceptance criteria.`);
|
|
829
827
|
}
|
|
830
828
|
// Check for spec_refs (features should link to plans/specs)
|
|
829
|
+
// WU-1062: Accepts both repo-relative paths (docs/04-operations/plans/) and
|
|
830
|
+
// external paths (~/.lumenflow/plans/, $LUMENFLOW_HOME/plans/, lumenflow://plans/)
|
|
831
831
|
if (type === 'feature') {
|
|
832
832
|
const hasSpecRefs = wu.spec_refs && wu.spec_refs.length > 0;
|
|
833
833
|
if (!hasSpecRefs) {
|
|
834
|
-
warnings.push(`${wu.id}: Missing 'spec_refs' field. Link to plan file
|
|
834
|
+
warnings.push(`${wu.id}: Missing 'spec_refs' field. Link to plan file (docs/04-operations/plans/, lumenflow://plans/, or ~/.lumenflow/plans/) for traceability.`);
|
|
835
835
|
}
|
|
836
836
|
}
|
|
837
837
|
return { warnings };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ClientConfig } from './lumenflow-config-schema.js';
|
|
2
|
+
interface ClientContext {
|
|
3
|
+
name: string;
|
|
4
|
+
config?: ClientConfig;
|
|
5
|
+
}
|
|
6
|
+
export declare function resolveClientConfig(config: any, clientName: any): any;
|
|
7
|
+
export declare function resolveSkillsPaths(config: any, clientName: any): {
|
|
8
|
+
clientConfig: any;
|
|
9
|
+
configuredSkillsDir: any;
|
|
10
|
+
configuredAgentsDir: any;
|
|
11
|
+
skillsDir: any;
|
|
12
|
+
agentsDir: any;
|
|
13
|
+
configuredSkillsMissing: boolean;
|
|
14
|
+
configuredAgentsMissing: boolean;
|
|
15
|
+
};
|
|
16
|
+
export declare function generateSkillsCatalogGuidance(config: any, clientName: any): string;
|
|
17
|
+
export declare function generateClientSkillsGuidance(clientContext: ClientContext): string;
|
|
18
|
+
export declare function generateSkillsSelectionSection(doc: any, config: any, clientName: any): string;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
const KNOWN_SKILLS_DIRS = [
|
|
3
|
+
'.lumenflow/skills',
|
|
4
|
+
'.claude/skills',
|
|
5
|
+
'.codex/skills',
|
|
6
|
+
'.gemini/skills',
|
|
7
|
+
];
|
|
8
|
+
const KNOWN_AGENTS_DIRS = [
|
|
9
|
+
'.lumenflow/agents',
|
|
10
|
+
'.claude/agents',
|
|
11
|
+
'.codex/agents',
|
|
12
|
+
'.gemini/agents',
|
|
13
|
+
];
|
|
14
|
+
const SECTION = {
|
|
15
|
+
skillsSelection: '## Skills Selection',
|
|
16
|
+
skillsCatalog: '### Skills Catalog',
|
|
17
|
+
softPolicy: '### Soft Policy (baselines for this WU)',
|
|
18
|
+
additionalSkills: '### Additional Skills (load if needed)',
|
|
19
|
+
gracefulDegradation: '### Graceful Degradation',
|
|
20
|
+
clientSkills: '### Client Skills Guidance',
|
|
21
|
+
};
|
|
22
|
+
const MESSAGES = {
|
|
23
|
+
skillsIntro: '**IMPORTANT**: Before starting work, select and load relevant skills.',
|
|
24
|
+
catalogMissing: 'No skills directories configured or found. Set `directories.skillsDir` or `agents.clients.<client>.skillsDir` in .lumenflow.config.yaml.',
|
|
25
|
+
baselineFallback: '- Load baseline skills: `/skill wu-lifecycle`, `/skill tdd-workflow` (for features)\n- Continue with implementation using Mandatory Standards below',
|
|
26
|
+
};
|
|
27
|
+
const CONTEXT_HINTS = {
|
|
28
|
+
wuLifecycle: '- `wu-lifecycle` — ALL WUs need workflow automation',
|
|
29
|
+
worktreeDiscipline: '- `worktree-discipline` — ALL WUs need path safety',
|
|
30
|
+
tddWorkflow: '- `tdd-workflow` — TDD is mandatory for feature/enhancement WUs',
|
|
31
|
+
bugClassification: '- `bug-classification` — Bug severity assessment',
|
|
32
|
+
lumenflowGates: '- `lumenflow-gates` — Tooling often affects gates',
|
|
33
|
+
beaconCompliance: '- `beacon-compliance` — Intelligence lane requires Beacon validation',
|
|
34
|
+
promptManagement: '- `prompt-management` — For prompt template work',
|
|
35
|
+
frontendDesign: '- `frontend-design` — For UI component work',
|
|
36
|
+
};
|
|
37
|
+
const ADDITIONAL_SKILLS_TABLE = `| Skill | Use When |
|
|
38
|
+
|-------|----------|
|
|
39
|
+
| lumenflow-gates | Gates fail, debugging format/lint/typecheck errors |
|
|
40
|
+
| bug-classification | Bug discovered mid-WU, need priority classification |
|
|
41
|
+
| beacon-compliance | Code touches LLM, prompts, classification |
|
|
42
|
+
| prompt-management | Working with prompt templates, golden datasets |
|
|
43
|
+
| frontend-design | Building UI components, pages |
|
|
44
|
+
| initiative-management | Multi-phase projects, INIT-XXX coordination |
|
|
45
|
+
| multi-agent-coordination | Spawning sub-agents, parallel WU work |
|
|
46
|
+
| orchestration | Agent coordination, mandatory agent checks |
|
|
47
|
+
| ops-maintenance | Metrics, validation, health checks |`;
|
|
48
|
+
export function resolveClientConfig(config, clientName) {
|
|
49
|
+
const clients = config?.agents?.clients || {};
|
|
50
|
+
if (!clientName)
|
|
51
|
+
return undefined;
|
|
52
|
+
if (clients[clientName])
|
|
53
|
+
return clients[clientName];
|
|
54
|
+
const matchKey = Object.keys(clients).find((key) => key.toLowerCase() === clientName.toLowerCase());
|
|
55
|
+
return matchKey ? clients[matchKey] : undefined;
|
|
56
|
+
}
|
|
57
|
+
function uniqueNonEmpty(values) {
|
|
58
|
+
const seen = new Set();
|
|
59
|
+
const result = [];
|
|
60
|
+
for (const value of values) {
|
|
61
|
+
if (!value)
|
|
62
|
+
continue;
|
|
63
|
+
if (seen.has(value))
|
|
64
|
+
continue;
|
|
65
|
+
seen.add(value);
|
|
66
|
+
result.push(value);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
export function resolveSkillsPaths(config, clientName) {
|
|
71
|
+
const clientConfig = resolveClientConfig(config, clientName);
|
|
72
|
+
const configuredSkillsDir = clientConfig?.skillsDir || config?.directories?.skillsDir;
|
|
73
|
+
const configuredAgentsDir = config?.directories?.agentsDir;
|
|
74
|
+
const skillsCandidates = uniqueNonEmpty([configuredSkillsDir, ...KNOWN_SKILLS_DIRS]);
|
|
75
|
+
const agentsCandidates = uniqueNonEmpty([configuredAgentsDir, ...KNOWN_AGENTS_DIRS]);
|
|
76
|
+
const skillsDir = skillsCandidates.find((candidate) => existsSync(candidate));
|
|
77
|
+
const agentsDir = agentsCandidates.find((candidate) => existsSync(candidate));
|
|
78
|
+
const configuredSkillsMissing = Boolean(configuredSkillsDir && !existsSync(configuredSkillsDir));
|
|
79
|
+
const configuredAgentsMissing = Boolean(configuredAgentsDir && !existsSync(configuredAgentsDir));
|
|
80
|
+
return {
|
|
81
|
+
clientConfig,
|
|
82
|
+
configuredSkillsDir,
|
|
83
|
+
configuredAgentsDir,
|
|
84
|
+
skillsDir,
|
|
85
|
+
agentsDir,
|
|
86
|
+
configuredSkillsMissing,
|
|
87
|
+
configuredAgentsMissing,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export function generateSkillsCatalogGuidance(config, clientName) {
|
|
91
|
+
const resolution = resolveSkillsPaths(config, clientName);
|
|
92
|
+
const lines = [];
|
|
93
|
+
if (resolution.skillsDir) {
|
|
94
|
+
lines.push(`- Check \`${resolution.skillsDir}\` for available skills.`);
|
|
95
|
+
}
|
|
96
|
+
if (resolution.agentsDir) {
|
|
97
|
+
lines.push(`- Check \`${resolution.agentsDir}\` for agent configs (optional).`);
|
|
98
|
+
}
|
|
99
|
+
if (lines.length > 0) {
|
|
100
|
+
return `${SECTION.skillsCatalog}\n\n${lines.join('\n')}\n`;
|
|
101
|
+
}
|
|
102
|
+
const configuredHint = resolution.configuredSkillsDir
|
|
103
|
+
? `Configured skillsDir \`${resolution.configuredSkillsDir}\` was not found. `
|
|
104
|
+
: '';
|
|
105
|
+
const clientHint = clientName
|
|
106
|
+
? `agents.clients.${clientName}.skillsDir`
|
|
107
|
+
: 'agents.clients.<client>.skillsDir';
|
|
108
|
+
return `${SECTION.skillsCatalog}\n\n${configuredHint}No skills directories configured or found. Set \`directories.skillsDir\` or \`${clientHint}\` in .lumenflow.config.yaml.\n`;
|
|
109
|
+
}
|
|
110
|
+
export function generateClientSkillsGuidance(clientContext) {
|
|
111
|
+
const skills = clientContext?.config?.skills;
|
|
112
|
+
if (!skills ||
|
|
113
|
+
(!skills.instructions && (!skills.recommended || skills.recommended.length === 0))) {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
const instructions = skills.instructions ? `${skills.instructions.trim()}\n\n` : '';
|
|
117
|
+
const recommended = skills.recommended && skills.recommended.length > 0
|
|
118
|
+
? `Recommended skills:\n${skills.recommended.map((s) => `- \`${s}\``).join('\n')}\n`
|
|
119
|
+
: '';
|
|
120
|
+
return `${SECTION.clientSkills} (${clientContext.name})\n\n${instructions}${recommended}`;
|
|
121
|
+
}
|
|
122
|
+
export function generateSkillsSelectionSection(doc, config, clientName) {
|
|
123
|
+
const lane = doc.lane || '';
|
|
124
|
+
const type = doc.type || 'feature';
|
|
125
|
+
const laneParent = lane.split(':')[0].trim();
|
|
126
|
+
const contextHints = [];
|
|
127
|
+
contextHints.push(CONTEXT_HINTS.wuLifecycle);
|
|
128
|
+
contextHints.push(CONTEXT_HINTS.worktreeDiscipline);
|
|
129
|
+
if (type === 'feature' || type === 'enhancement') {
|
|
130
|
+
contextHints.push(CONTEXT_HINTS.tddWorkflow);
|
|
131
|
+
}
|
|
132
|
+
if (type === 'bug') {
|
|
133
|
+
contextHints.push(CONTEXT_HINTS.bugClassification);
|
|
134
|
+
}
|
|
135
|
+
if (laneParent === 'Operations' && lane.includes('Tooling')) {
|
|
136
|
+
contextHints.push(CONTEXT_HINTS.lumenflowGates);
|
|
137
|
+
}
|
|
138
|
+
if (laneParent === 'Intelligence') {
|
|
139
|
+
contextHints.push(CONTEXT_HINTS.beaconCompliance);
|
|
140
|
+
contextHints.push(CONTEXT_HINTS.promptManagement);
|
|
141
|
+
}
|
|
142
|
+
if (laneParent === 'Experience') {
|
|
143
|
+
contextHints.push(CONTEXT_HINTS.frontendDesign);
|
|
144
|
+
}
|
|
145
|
+
const softPolicySection = `${SECTION.softPolicy}\n\nBased on WU context, consider loading:\n\n${contextHints.join('\n')}\n\n`;
|
|
146
|
+
const catalogGuidance = generateSkillsCatalogGuidance(config, clientName);
|
|
147
|
+
return `${SECTION.skillsSelection}\n\n${MESSAGES.skillsIntro}\n\n${catalogGuidance}${softPolicySection}${SECTION.additionalSkills}\n\n${ADDITIONAL_SKILLS_TABLE}\n\n${SECTION.gracefulDegradation}\n\nIf the skill catalogue is missing or invalid:\n${MESSAGES.baselineFallback}\n`;
|
|
148
|
+
}
|
package/dist/wu-spawn.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Output:
|
|
13
13
|
* A complete Task tool invocation block with:
|
|
14
|
-
* - Context loading preamble (CLAUDE
|
|
14
|
+
* - Context loading preamble (.claude/CLAUDE.md, README, lumenflow, WU YAML)
|
|
15
15
|
* - WU details and acceptance criteria
|
|
16
16
|
* - Skills Selection section (sub-agent reads catalogue and selects at runtime)
|
|
17
17
|
* - Mandatory agent advisory
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
* Codex Mode:
|
|
26
26
|
* When --codex is used, outputs a Codex/GPT-friendly Markdown prompt (no antml/XML escaping).
|
|
27
27
|
*
|
|
28
|
-
* @see {@link
|
|
28
|
+
* @see {@link docs/04-operations/_frameworks/lumenflow/agent/onboarding/agent-invocation-guide.md} - Context loading templates
|
|
29
29
|
*/
|
|
30
|
+
import type { ClientConfig, LumenFlowConfig } from './lumenflow-config-schema.js';
|
|
30
31
|
/**
|
|
31
32
|
* Generate effort scaling rules section (WU-1986)
|
|
32
33
|
*
|
|
@@ -119,19 +120,31 @@ export declare function generateWorktreePathGuidance(worktreePath: any): string;
|
|
|
119
120
|
* @returns {string} Action section content
|
|
120
121
|
*/
|
|
121
122
|
export declare function generateActionSection(doc: any, id: any): string;
|
|
123
|
+
interface ClientContext {
|
|
124
|
+
name: string;
|
|
125
|
+
config?: ClientConfig;
|
|
126
|
+
}
|
|
127
|
+
interface SpawnOptions {
|
|
128
|
+
thinking?: boolean;
|
|
129
|
+
noThinking?: boolean;
|
|
130
|
+
budget?: string;
|
|
131
|
+
client?: ClientContext;
|
|
132
|
+
config?: LumenFlowConfig;
|
|
133
|
+
}
|
|
122
134
|
/**
|
|
123
135
|
* Generate the complete Task tool invocation
|
|
124
136
|
*
|
|
125
137
|
* @param {object} doc - WU YAML document
|
|
126
138
|
* @param {string} id - WU ID
|
|
139
|
+
* @param {SpawnStrategy} strategy - Client strategy
|
|
127
140
|
* @param {object} [options={}] - Thinking mode options
|
|
128
141
|
* @param {boolean} [options.thinking] - Whether extended thinking is enabled
|
|
129
142
|
* @param {boolean} [options.noThinking] - Whether thinking is explicitly disabled
|
|
130
143
|
* @param {string} [options.budget] - Token budget for thinking
|
|
131
144
|
* @returns {string} Complete Task tool invocation
|
|
132
145
|
*/
|
|
133
|
-
export declare function generateTaskInvocation(doc: any, id: any, options?:
|
|
134
|
-
export declare function generateCodexPrompt(doc: any, id: any, options?:
|
|
146
|
+
export declare function generateTaskInvocation(doc: any, id: any, strategy: any, options?: SpawnOptions): string;
|
|
147
|
+
export declare function generateCodexPrompt(doc: any, id: any, strategy: any, options?: SpawnOptions): string;
|
|
135
148
|
/**
|
|
136
149
|
* WU-1603: Check if a lane is currently occupied by another WU
|
|
137
150
|
*
|