@opengsd/gsd-core 1.7.0-rc.3 → 1.7.0-rc.5
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +20 -0
- package/README.ja-JP.md +4 -3
- package/README.ko-KR.md +4 -3
- package/README.md +4 -3
- package/README.pt-BR.md +4 -3
- package/README.zh-CN.md +4 -3
- package/agents/gsd-doc-classifier.md +105 -0
- package/agents/gsd-doc-synthesizer.md +61 -0
- package/agents/gsd-ui-checker.md +28 -0
- package/bin/install.js +652 -466
- package/commands/gsd/map-codebase.md +4 -4
- package/commands/gsd/ns-project.md +2 -1
- package/commands/gsd/onboard.md +46 -0
- package/gsd-core/bin/gsd-tools.cjs +87 -3
- package/gsd-core/bin/lib/api-coverage.cjs +466 -0
- package/gsd-core/bin/lib/audit.cjs +6 -3
- package/gsd-core/bin/lib/capability-loader.cjs +11 -9
- package/gsd-core/bin/lib/capability-registry.cjs +741 -62
- package/gsd-core/bin/lib/capability-state.cjs +117 -18
- package/gsd-core/bin/lib/capability-validator.cjs +1 -1
- package/gsd-core/bin/lib/capability-writer.cjs +21 -2
- package/gsd-core/bin/lib/check-command-router.cjs +242 -3
- package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +136 -0
- package/gsd-core/bin/lib/claude-orchestration.cjs +404 -0
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/command-aliases.cjs +8 -0
- package/gsd-core/bin/lib/commands.cjs +7 -5
- package/gsd-core/bin/lib/config-loader.cjs +1 -0
- package/gsd-core/bin/lib/config.cjs +96 -0
- package/gsd-core/bin/lib/core-utils.cjs +4 -1
- package/gsd-core/bin/lib/host-integration-adapters/cline-sdk-binding.cjs +234 -0
- package/gsd-core/bin/lib/host-integration-adapters/imperative-hook-bus.cjs +145 -0
- package/gsd-core/bin/lib/host-integration.cjs +16 -0
- package/gsd-core/bin/lib/init-command-router.cjs +4 -0
- package/gsd-core/bin/lib/init.cjs +99 -99
- package/gsd-core/bin/lib/install-effort-resolver.cjs +213 -0
- package/gsd-core/bin/lib/install-engine.cjs +159 -16
- package/gsd-core/bin/lib/install-profiles.cjs +2 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +75 -18
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +50 -11
- package/gsd-core/bin/lib/milestone.cjs +3 -3
- package/gsd-core/bin/lib/model-resolver.cjs +69 -4
- package/gsd-core/bin/lib/normalize-test-command.cjs +187 -0
- package/gsd-core/bin/lib/onboard-projection.cjs +309 -0
- package/gsd-core/bin/lib/phase-id.cjs +132 -3
- package/gsd-core/bin/lib/phase.cjs +78 -16
- package/gsd-core/bin/lib/planning-workspace.cjs +17 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +5 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +21 -30
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +9 -9
- package/gsd-core/bin/lib/roadmap.cjs +42 -56
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +13 -6
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +17 -10
- package/gsd-core/bin/lib/runtime-homes.cjs +8 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +33 -25
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/spec-section.cjs +111 -0
- package/gsd-core/bin/lib/state-transition.cjs +1 -1
- package/gsd-core/bin/lib/state.cjs +24 -24
- package/gsd-core/bin/lib/surface.cjs +81 -30
- package/gsd-core/bin/lib/uat.cjs +4 -1
- package/gsd-core/bin/lib/validate.cjs +15 -6
- package/gsd-core/bin/lib/verify.cjs +33 -37
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
- package/gsd-core/bin/shared/model-catalog.json +11 -6
- package/gsd-core/references/api-coverage.md +104 -0
- package/gsd-core/references/gsd-run-resolver.md +8 -0
- package/gsd-core/references/model-profiles.md +2 -2
- package/gsd-core/references/planning-config.md +2 -0
- package/gsd-core/references/specless-probe-fallback.md +172 -0
- package/gsd-core/templates/config.json +2 -1
- package/gsd-core/templates/project.md +1 -1
- package/gsd-core/workflows/audit-fix.md +9 -1
- package/gsd-core/workflows/code-review-fix.md +7 -3
- package/gsd-core/workflows/code-review.md +4 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -1
- package/gsd-core/workflows/do.md +4 -3
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +8 -4
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +42 -0
- package/gsd-core/workflows/execute-phase.md +1 -25
- package/gsd-core/workflows/help/modes/brief.md +2 -1
- package/gsd-core/workflows/help/modes/default.md +2 -1
- package/gsd-core/workflows/help/modes/full.md +11 -1
- package/gsd-core/workflows/help/modes/topic.md +1 -1
- package/gsd-core/workflows/onboard.md +277 -0
- package/gsd-core/workflows/plan-phase.md +31 -2
- package/gsd-core/workflows/quick.md +22 -2
- package/gsd-core/workflows/review.md +59 -13
- package/gsd-core/workflows/settings-advanced.md +5 -5
- package/gsd-core/workflows/settings.md +2 -2
- package/gsd-core/workflows/verify-phase.md +3 -2
- package/gsd-core/workflows/verify-work.md +38 -0
- package/hooks/dist/gsd-cursor-pre-tool.js +76 -0
- package/hooks/dist/gsd-cursor-stop.js +48 -0
- package/hooks/dist/gsd-cursor-subagent-start.js +50 -0
- package/hooks/dist/gsd-cursor-subagent-stop.js +40 -0
- package/hooks/dist/managed-hooks-registry.cjs +4 -0
- package/hooks/gsd-cursor-pre-tool.js +76 -0
- package/hooks/gsd-cursor-stop.js +48 -0
- package/hooks/gsd-cursor-subagent-start.js +50 -0
- package/hooks/gsd-cursor-subagent-stop.js +40 -0
- package/hooks/managed-hooks-registry.cjs +4 -0
- package/package.json +2 -1
- package/scripts/build-hooks.js +5 -1
- package/scripts/gen-golden-install-parity-zcode.cjs +77 -0
- package/scripts/lint-phase-id-drift.cjs +150 -0
- package/scripts/run-tests.cjs +26 -4
- package/scripts/sync-runtime-launcher.cjs +20 -2
- package/skills/gsd-map-codebase/SKILL.md +3 -3
- package/skills/gsd-ns-project/SKILL.md +1 -0
- package/skills/gsd-onboard/SKILL.md +46 -0
|
@@ -54,15 +54,18 @@ const { checkAgentsInstalled } = agentInstallCheck;
|
|
|
54
54
|
const gitBaseBranch = require("./git-base-branch.cjs");
|
|
55
55
|
const { gitWorktreeInfoInternal } = gitBaseBranch;
|
|
56
56
|
const resolution_cjs_1 = require("./resolution.cjs");
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- onboard-projection.cjs is an export= CommonJS module
|
|
58
|
+
const onboardProjection = require("./onboard-projection.cjs");
|
|
59
|
+
const { REQUIRED_CODEBASE_MAP_FILES, buildOnboardProjection, hasCodeFilesInternal, hasPackageFileInternal, listCodebaseMapFiles, } = onboardProjection;
|
|
57
60
|
const { output, error } = io;
|
|
58
61
|
const { loadConfig, loadConfigResolved } = configLoader;
|
|
59
62
|
const { resolveModelInternal, resolveGranularityInternal, assertValidGranularityOverride } = modelResolver;
|
|
60
63
|
const { findPhaseInternal } = phaseLocator;
|
|
61
64
|
const { getRoadmapPhaseInternal, getMilestoneInfo, getMilestonePhaseFilter, stripShippedMilestones, extractCurrentMilestone, } = roadmapParser;
|
|
62
65
|
const { pathExistsInternal, generateSlugInternal, toPosixPath } = coreUtils;
|
|
63
|
-
const { normalizePhaseName, phaseTokenMatches, stripProjectCodePrefix } = phaseId;
|
|
66
|
+
const { escapeRegex, normalizePhaseName, phaseTokenMatches, stripProjectCodePrefix, PHASE_NUMBER_TOKEN_SOURCE } = phaseId;
|
|
64
67
|
const { pruneOrphanedWorktrees } = worktreeSafety;
|
|
65
|
-
const { planningPaths, planningDir, planningRoot, getActiveWorkstream, findContextMdIn, } = planningWorkspace;
|
|
68
|
+
const { planningPaths, planningDir, planningRoot, listAvailableWorkstreams, getActiveWorkstream, findContextMdIn, } = planningWorkspace;
|
|
66
69
|
const { determinePhaseStatus } = commandsMod;
|
|
67
70
|
const { extractFrontmatter } = frontmatterMod;
|
|
68
71
|
const { readVerificationStatus } = verificationMod;
|
|
@@ -71,6 +74,35 @@ const { evaluateUatPassed } = uatPredicateMod;
|
|
|
71
74
|
void stripShippedMilestones;
|
|
72
75
|
// Accept all bold/colon variants of the Requirements header (#2769)
|
|
73
76
|
const REQUIREMENTS_HEADER_RE = /^\*\*Requirements:?\*\*[^\S\n]*:?[^\S\n]*([^\n]*)$/m;
|
|
77
|
+
// #2056: normalizePhaseName() strips ANY [A-Z][A-Z0-9_]*- prefix as a project
|
|
78
|
+
// code (e.g. 'MEM-01' → '01'), so a foreign-prefixed workstream/task id would
|
|
79
|
+
// collapse to its numeric suffix and resolve to an unrelated numeric phase via
|
|
80
|
+
// the dir/roadmap fallback. init plan-phase must require EXACT prefixed
|
|
81
|
+
// evidence — a phase dir whose token literally IS the prefixed query, or a
|
|
82
|
+
// roadmap entry literally headed with it — before accepting such a match. The
|
|
83
|
+
// configured project_code's own prefix (e.g. LKML-01 under project_code: LKML)
|
|
84
|
+
// is never foreign and always passes through.
|
|
85
|
+
function parsePhasePrefix(phase) {
|
|
86
|
+
const match = String(phase).match(/^([A-Z][A-Z0-9_]*)-(?=\d)/i);
|
|
87
|
+
return match ? match[1] : null;
|
|
88
|
+
}
|
|
89
|
+
function isForeignPrefixedPhaseQuery(phase, projectCode) {
|
|
90
|
+
const prefix = parsePhasePrefix(phase);
|
|
91
|
+
if (!prefix)
|
|
92
|
+
return false;
|
|
93
|
+
const configured = typeof projectCode === 'string' ? projectCode.trim() : '';
|
|
94
|
+
return !configured || prefix.toUpperCase() !== configured.toUpperCase();
|
|
95
|
+
}
|
|
96
|
+
function phaseInfoMatchesExactPrefix(phaseInfo, phase) {
|
|
97
|
+
const num = phaseInfo?.['phase_number'];
|
|
98
|
+
const numStr = typeof num === 'string' ? num : (typeof num === 'number' ? String(num) : '');
|
|
99
|
+
return numStr.toUpperCase() === phase.toUpperCase();
|
|
100
|
+
}
|
|
101
|
+
function roadmapPhaseMatchesExactPrefix(roadmapPhase, phase) {
|
|
102
|
+
const sectionRaw = roadmapPhase?.['section'];
|
|
103
|
+
const section = typeof sectionRaw === 'string' ? sectionRaw : '';
|
|
104
|
+
return new RegExp(`^#{2,4}\\s*Phase\\s+${escapeRegex(phase)}(?:\\b|\\s|:)`, 'i').test(section);
|
|
105
|
+
}
|
|
74
106
|
function listPhaseSummaryFiles(phaseDir) {
|
|
75
107
|
return scanPhasePlans(phaseDir)['summaryFiles'];
|
|
76
108
|
}
|
|
@@ -329,8 +361,18 @@ function cmdInitPlanPhase(cwd, phase, raw, options = {}) {
|
|
|
329
361
|
error('phase required for init plan-phase');
|
|
330
362
|
}
|
|
331
363
|
const config = loadConfig(cwd);
|
|
364
|
+
const foreignPrefixedPhase = isForeignPrefixedPhaseQuery(phase, config.project_code);
|
|
332
365
|
let phaseInfo = findPhaseInternal(cwd, phase);
|
|
333
|
-
|
|
366
|
+
// #2056: a foreign-prefixed query must only match a phase whose token literally
|
|
367
|
+
// IS the prefixed query (e.g. a real 'MEM-01-*' dir); otherwise the numeric
|
|
368
|
+
// fallback ('MEM-01' → '01') would resolve to the unrelated numeric phase.
|
|
369
|
+
if (foreignPrefixedPhase && !phaseInfoMatchesExactPrefix(phaseInfo, phase)) {
|
|
370
|
+
phaseInfo = null;
|
|
371
|
+
}
|
|
372
|
+
let roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
|
|
373
|
+
if (foreignPrefixedPhase && !roadmapPhaseMatchesExactPrefix(roadmapPhase, phase)) {
|
|
374
|
+
roadmapPhase = null;
|
|
375
|
+
}
|
|
334
376
|
if (phaseInfo?.['archived'] && roadmapPhase?.['found']) {
|
|
335
377
|
phaseInfo = null;
|
|
336
378
|
}
|
|
@@ -479,84 +521,23 @@ function cmdInitNewProject(cwd, raw) {
|
|
|
479
521
|
const hasFirecrawl = !!(process.env['FIRECRAWL_API_KEY'] || node_fs_1.default.existsSync(firecrawlKeyFile));
|
|
480
522
|
const exaKeyFile = node_path_1.default.join(homedir, '.gsd', 'exa_api_key');
|
|
481
523
|
const hasExaSearch = !!(process.env['EXA_API_KEY'] || node_fs_1.default.existsSync(exaKeyFile));
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
'.kt', '.kts',
|
|
488
|
-
'.c', '.cpp', '.h',
|
|
489
|
-
'.cs',
|
|
490
|
-
'.rb',
|
|
491
|
-
'.php',
|
|
492
|
-
'.dart',
|
|
493
|
-
'.m', '.mm',
|
|
494
|
-
'.scala',
|
|
495
|
-
'.groovy',
|
|
496
|
-
'.lua',
|
|
497
|
-
'.r', '.R',
|
|
498
|
-
'.zig',
|
|
499
|
-
'.ex', '.exs',
|
|
500
|
-
'.clj',
|
|
501
|
-
]);
|
|
502
|
-
const skipDirs = new Set([
|
|
503
|
-
'node_modules', '.git', '.planning', '.claude', '.codex',
|
|
504
|
-
'__pycache__', 'target', 'dist', 'build',
|
|
505
|
-
]);
|
|
506
|
-
function findCodeFiles(dir, depth) {
|
|
507
|
-
if (depth > 3)
|
|
508
|
-
return false;
|
|
509
|
-
let entries;
|
|
510
|
-
try {
|
|
511
|
-
entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
512
|
-
}
|
|
513
|
-
catch {
|
|
514
|
-
return false;
|
|
515
|
-
}
|
|
516
|
-
for (const entry of entries) {
|
|
517
|
-
if (entry.isFile() && codeExtensions.has(node_path_1.default.extname(entry.name)))
|
|
518
|
-
return true;
|
|
519
|
-
if (entry.isDirectory() && !skipDirs.has(entry.name)) {
|
|
520
|
-
if (findCodeFiles(node_path_1.default.join(dir, entry.name), depth + 1))
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
return false;
|
|
525
|
-
}
|
|
526
|
-
hasCode = findCodeFiles(cwd, 0);
|
|
527
|
-
}
|
|
528
|
-
catch {
|
|
529
|
-
/* intentionally empty — best-effort detection */
|
|
530
|
-
}
|
|
531
|
-
hasPackageFile =
|
|
532
|
-
pathExistsInternal(cwd, 'package.json') ||
|
|
533
|
-
pathExistsInternal(cwd, 'requirements.txt') ||
|
|
534
|
-
pathExistsInternal(cwd, 'Cargo.toml') ||
|
|
535
|
-
pathExistsInternal(cwd, 'go.mod') ||
|
|
536
|
-
pathExistsInternal(cwd, 'Package.swift') ||
|
|
537
|
-
pathExistsInternal(cwd, 'build.gradle') ||
|
|
538
|
-
pathExistsInternal(cwd, 'build.gradle.kts') ||
|
|
539
|
-
pathExistsInternal(cwd, 'pom.xml') ||
|
|
540
|
-
pathExistsInternal(cwd, 'Gemfile') ||
|
|
541
|
-
pathExistsInternal(cwd, 'composer.json') ||
|
|
542
|
-
pathExistsInternal(cwd, 'pubspec.yaml') ||
|
|
543
|
-
pathExistsInternal(cwd, 'CMakeLists.txt') ||
|
|
544
|
-
pathExistsInternal(cwd, 'Makefile') ||
|
|
545
|
-
pathExistsInternal(cwd, 'build.zig') ||
|
|
546
|
-
pathExistsInternal(cwd, 'mix.exs') ||
|
|
547
|
-
pathExistsInternal(cwd, 'project.clj');
|
|
524
|
+
const hasCode = hasCodeFilesInternal(cwd);
|
|
525
|
+
const hasPackageFile = hasPackageFileInternal(cwd);
|
|
526
|
+
const isBrownfield = hasCode || hasPackageFile;
|
|
527
|
+
const codebaseMapFiles = listCodebaseMapFiles(cwd);
|
|
528
|
+
const hasCodebaseMap = codebaseMapFiles.length === REQUIRED_CODEBASE_MAP_FILES.length;
|
|
548
529
|
const result = {
|
|
549
530
|
researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
|
|
550
531
|
synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
|
|
551
532
|
roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
|
|
552
533
|
commit_docs: config.commit_docs,
|
|
553
534
|
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
|
554
|
-
has_codebase_map:
|
|
535
|
+
has_codebase_map: hasCodebaseMap,
|
|
555
536
|
planning_exists: pathExistsInternal(cwd, '.planning'),
|
|
556
537
|
has_existing_code: hasCode,
|
|
557
538
|
has_package_file: hasPackageFile,
|
|
558
|
-
is_brownfield:
|
|
559
|
-
needs_codebase_map:
|
|
539
|
+
is_brownfield: isBrownfield,
|
|
540
|
+
needs_codebase_map: isBrownfield && !hasCodebaseMap,
|
|
560
541
|
...getInitGitState(cwd),
|
|
561
542
|
brave_search_available: hasBraveSearch,
|
|
562
543
|
firecrawl_available: hasFirecrawl,
|
|
@@ -631,6 +612,9 @@ function cmdInitQuick(cwd, description, raw) {
|
|
|
631
612
|
executor_model: resolveModelInternal(cwd, 'gsd-executor'),
|
|
632
613
|
checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
|
|
633
614
|
verifier_model: resolveModelInternal(cwd, 'gsd-verifier'),
|
|
615
|
+
// #2072: the quick review step spawns gsd-code-reviewer; resolve its own model
|
|
616
|
+
// so model_overrides / models.verification apply (was reusing executor_model).
|
|
617
|
+
reviewer_model: resolveModelInternal(cwd, 'gsd-code-reviewer'),
|
|
634
618
|
commit_docs: config.commit_docs,
|
|
635
619
|
branch_name: quickBranchName,
|
|
636
620
|
quick_id: quickId,
|
|
@@ -656,6 +640,19 @@ function cmdInitIngestDocs(cwd, raw) {
|
|
|
656
640
|
};
|
|
657
641
|
output(withProjectRoot(cwd, result), raw);
|
|
658
642
|
}
|
|
643
|
+
function cmdInitOnboard(cwd, raw, options = {}) {
|
|
644
|
+
const config = loadConfig(cwd);
|
|
645
|
+
const workflowConfig = (config.workflow ?? {});
|
|
646
|
+
const result = {
|
|
647
|
+
...buildOnboardProjection(cwd, {
|
|
648
|
+
commitDocs: !!config.commit_docs,
|
|
649
|
+
fast: options['fast'] === true,
|
|
650
|
+
textMode: options['text'] === true || !!config.text_mode || !!workflowConfig['text_mode'],
|
|
651
|
+
}),
|
|
652
|
+
...getInitGitState(cwd),
|
|
653
|
+
};
|
|
654
|
+
output(withProjectRoot(cwd, result), raw);
|
|
655
|
+
}
|
|
659
656
|
function cmdInitResume(cwd, raw) {
|
|
660
657
|
const config = loadConfig(cwd);
|
|
661
658
|
let interruptedAgentId = null;
|
|
@@ -919,8 +916,8 @@ function cmdInitMilestoneOp(cwd, raw) {
|
|
|
919
916
|
const roadmapPath = node_path_1.default.join(planningDir(cwd), 'ROADMAP.md');
|
|
920
917
|
const roadmapRaw = node_fs_1.default.readFileSync(roadmapPath, 'utf-8');
|
|
921
918
|
const currentSection = extractCurrentMilestone(roadmapRaw, cwd);
|
|
922
|
-
// #1729: `(?:\s*\([^)\n]
|
|
923
|
-
const phasePattern =
|
|
919
|
+
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
920
|
+
const phasePattern = new RegExp(`#{2,4}\\s*Phase\\s+(${PHASE_NUMBER_TOKEN_SOURCE})(?:\\s*\\([^)\\n]{0,200}\\))?\\s*:`, 'gi');
|
|
924
921
|
let m;
|
|
925
922
|
while ((m = phasePattern.exec(currentSection)) !== null) {
|
|
926
923
|
if (/^999(?:\.|$)/.test(m[1]))
|
|
@@ -941,7 +938,7 @@ function cmdInitMilestoneOp(cwd, raw) {
|
|
|
941
938
|
for (const e of entries) {
|
|
942
939
|
if (!e.isDirectory())
|
|
943
940
|
continue;
|
|
944
|
-
const m = stripProjectCodePrefix(e.name).match(
|
|
941
|
+
const m = stripProjectCodePrefix(e.name).match(new RegExp(`^(${PHASE_NUMBER_TOKEN_SOURCE})`));
|
|
945
942
|
if (!m)
|
|
946
943
|
continue;
|
|
947
944
|
diskPhaseDirs.set(canonicalizePhase(m[1]), e.name);
|
|
@@ -1069,13 +1066,13 @@ function cmdInitManager(cwd, raw) {
|
|
|
1069
1066
|
}
|
|
1070
1067
|
})();
|
|
1071
1068
|
const _checkboxStates = new Map();
|
|
1072
|
-
const _cbPattern =
|
|
1069
|
+
const _cbPattern = new RegExp(`-\\s*\\[(x| )\\]\\s*.*Phase\\s+(${PHASE_NUMBER_TOKEN_SOURCE})[:\\s]`, 'gi');
|
|
1073
1070
|
let _cbMatch;
|
|
1074
1071
|
while ((_cbMatch = _cbPattern.exec(content)) !== null) {
|
|
1075
1072
|
_checkboxStates.set(_cbMatch[2], _cbMatch[1].toLowerCase() === 'x');
|
|
1076
1073
|
}
|
|
1077
|
-
// #1729: `(?:\s*\([^)\n]
|
|
1078
|
-
const phasePattern =
|
|
1074
|
+
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
1075
|
+
const phasePattern = new RegExp(`#{2,4}\\s*Phase\\s+(${PHASE_NUMBER_TOKEN_SOURCE})(?:\\s*\\([^)\\n]{0,200}\\))?\\s*:\\s*([^\\n]+)`, 'gi');
|
|
1079
1076
|
const phases = [];
|
|
1080
1077
|
let match;
|
|
1081
1078
|
while ((match = phasePattern.exec(content)) !== null) {
|
|
@@ -1193,7 +1190,7 @@ function cmdInitManager(cwd, raw) {
|
|
|
1193
1190
|
.filter((p) => p['phase_complete'] === true)
|
|
1194
1191
|
.map((p) => normalizePhaseNumber(p['number'])));
|
|
1195
1192
|
const phaseMap = new Map(phases.map((p) => [normalizePhaseNumber(p['number']), p]));
|
|
1196
|
-
const _allCompletedPattern =
|
|
1193
|
+
const _allCompletedPattern = new RegExp(`-\\s*\\[x\\]\\s*.*Phase\\s+(${PHASE_NUMBER_TOKEN_SOURCE})[:\\s]`, 'gi');
|
|
1197
1194
|
let _allMatch;
|
|
1198
1195
|
while ((_allMatch = _allCompletedPattern.exec(rawContent)) !== null) {
|
|
1199
1196
|
const phaseNum = normalizePhaseNumber(_allMatch[1]);
|
|
@@ -1225,7 +1222,7 @@ function cmdInitManager(cwd, raw) {
|
|
|
1225
1222
|
phase['deps_satisfied'] = true;
|
|
1226
1223
|
}
|
|
1227
1224
|
else {
|
|
1228
|
-
const depNums = phase['depends_on'].match(
|
|
1225
|
+
const depNums = phase['depends_on'].match(new RegExp(`${PHASE_NUMBER_TOKEN_SOURCE}`, 'gi')) || [];
|
|
1229
1226
|
phase['deps_satisfied'] = depNums.every((n) => completedNums.has(normalizePhaseNumber(n)));
|
|
1230
1227
|
phase['dep_phases'] = depNums;
|
|
1231
1228
|
}
|
|
@@ -1364,18 +1361,7 @@ function cmdInitProgress(cwd, raw) {
|
|
|
1364
1361
|
// reporting a stale root milestone. Require an explicit workstream instead.
|
|
1365
1362
|
// Mirror planningDir's resolution (GSD_WORKSTREAM env > stored active pointer) so
|
|
1366
1363
|
// an explicit --ws (which sets GSD_WORKSTREAM) satisfies the check.
|
|
1367
|
-
const
|
|
1368
|
-
let _availableWorkstreams = [];
|
|
1369
|
-
try {
|
|
1370
|
-
_availableWorkstreams = node_fs_1.default
|
|
1371
|
-
.readdirSync(_wsRoot, { withFileTypes: true })
|
|
1372
|
-
.filter((e) => e.isDirectory())
|
|
1373
|
-
.map((e) => e.name)
|
|
1374
|
-
.sort();
|
|
1375
|
-
}
|
|
1376
|
-
catch {
|
|
1377
|
-
/* no workstreams dir → flat mode */
|
|
1378
|
-
}
|
|
1364
|
+
const _availableWorkstreams = listAvailableWorkstreams(cwd);
|
|
1379
1365
|
const _resolvedWorkstream = process.env['GSD_WORKSTREAM'] || getActiveWorkstream(cwd);
|
|
1380
1366
|
if (_availableWorkstreams.length > 0 && !_resolvedWorkstream) {
|
|
1381
1367
|
error(`init.progress requires a workstream in workstream mode — no active workstream is set, so root STATE.md (likely stale) would be reported. ` +
|
|
@@ -1391,14 +1377,14 @@ function cmdInitProgress(cwd, raw) {
|
|
|
1391
1377
|
const roadmapCheckboxStates = new Map();
|
|
1392
1378
|
try {
|
|
1393
1379
|
const roadmapContent = extractCurrentMilestone(node_fs_1.default.readFileSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md'), 'utf-8'), cwd);
|
|
1394
|
-
// #1729: `(?:\s*\([^)\n]
|
|
1395
|
-
const headingPattern =
|
|
1380
|
+
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
1381
|
+
const headingPattern = new RegExp(`#{2,4}\\s*Phase\\s+(${PHASE_NUMBER_TOKEN_SOURCE})(?:\\s*\\([^)\\n]{0,200}\\))?\\s*:\\s*([^\\n]+)`, 'gi');
|
|
1396
1382
|
let hm;
|
|
1397
1383
|
while ((hm = headingPattern.exec(roadmapContent)) !== null) {
|
|
1398
1384
|
roadmapPhaseNums.add(hm[1]);
|
|
1399
1385
|
roadmapPhaseNames.set(hm[1], hm[2].replace(/\(INSERTED\)/i, '').trim());
|
|
1400
1386
|
}
|
|
1401
|
-
const cbPattern =
|
|
1387
|
+
const cbPattern = new RegExp(`-\\s*\\[(x| )\\]\\s*.*Phase\\s+(${PHASE_NUMBER_TOKEN_SOURCE})[:\\s]`, 'gi');
|
|
1402
1388
|
let cbm;
|
|
1403
1389
|
while ((cbm = cbPattern.exec(roadmapContent)) !== null) {
|
|
1404
1390
|
roadmapCheckboxStates.set(cbm[2], cbm[1].toLowerCase() === 'x');
|
|
@@ -1416,14 +1402,14 @@ function cmdInitProgress(cwd, raw) {
|
|
|
1416
1402
|
.map((e) => e.name)
|
|
1417
1403
|
.filter(isDirInMilestone)
|
|
1418
1404
|
.sort((a, b) => {
|
|
1419
|
-
const pa = a.match(
|
|
1420
|
-
const pb = b.match(
|
|
1405
|
+
const pa = a.match(new RegExp(`^(${PHASE_NUMBER_TOKEN_SOURCE})`, 'i'));
|
|
1406
|
+
const pb = b.match(new RegExp(`^(${PHASE_NUMBER_TOKEN_SOURCE})`, 'i'));
|
|
1421
1407
|
if (!pa || !pb)
|
|
1422
1408
|
return a.localeCompare(b);
|
|
1423
1409
|
return parseInt(pa[1], 10) - parseInt(pb[1], 10);
|
|
1424
1410
|
});
|
|
1425
1411
|
for (const dir of dirs) {
|
|
1426
|
-
const dirMatch = dir.match(
|
|
1412
|
+
const dirMatch = dir.match(new RegExp(`^(${PHASE_NUMBER_TOKEN_SOURCE})-?(.*)`, 'i'));
|
|
1427
1413
|
const phaseNumber = dirMatch ? dirMatch[1] : dir;
|
|
1428
1414
|
const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
|
|
1429
1415
|
seenPhaseNums.add(phaseNumber.replace(/^0+/, '') || '0');
|
|
@@ -1915,11 +1901,24 @@ function buildSkillManifest(cwd, skillsDir = null) {
|
|
|
1915
1901
|
kind: 'skills',
|
|
1916
1902
|
},
|
|
1917
1903
|
{
|
|
1918
|
-
|
|
1904
|
+
// ADR-1239 upgrade 3 (#2088): Codex's canonical skill root is
|
|
1905
|
+
// $HOME/.agents/skills (per codex core-skills loader.rs), resolved via
|
|
1906
|
+
// the skills-kind `home` override in getGlobalSkillsBase.
|
|
1907
|
+
root: '~/.agents/skills',
|
|
1919
1908
|
path: (0, runtime_homes_cjs_1.getGlobalSkillsBase)('codex'),
|
|
1920
1909
|
scope: 'global',
|
|
1921
1910
|
kind: 'skills',
|
|
1922
1911
|
},
|
|
1912
|
+
{
|
|
1913
|
+
// Codex's deprecated fallback skill root ($CODEX_HOME/skills). Kept as a
|
|
1914
|
+
// discovery-only legacy root so pre-move installs remain inventoried;
|
|
1915
|
+
// GSD no longer installs here (#2088).
|
|
1916
|
+
root: '~/.codex/skills',
|
|
1917
|
+
path: node_path_1.default.join((0, runtime_homes_cjs_1.getGlobalConfigDir)('codex'), 'skills'),
|
|
1918
|
+
scope: 'global',
|
|
1919
|
+
kind: 'skills',
|
|
1920
|
+
deprecated: true,
|
|
1921
|
+
},
|
|
1923
1922
|
{
|
|
1924
1923
|
root: '.claude/gsd-core/skills',
|
|
1925
1924
|
path: node_path_1.default.join(node_os_1.default.homedir(), '.claude', 'gsd-core', 'skills'),
|
|
@@ -2099,6 +2098,7 @@ module.exports = {
|
|
|
2099
2098
|
cmdInitNewMilestone,
|
|
2100
2099
|
cmdInitQuick,
|
|
2101
2100
|
cmdInitIngestDocs,
|
|
2101
|
+
cmdInitOnboard,
|
|
2102
2102
|
cmdInitResume,
|
|
2103
2103
|
cmdInitVerifyWork,
|
|
2104
2104
|
cmdInitPhaseOp,
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* install-effort-resolver — install-time effort resolution (#443), extracted from
|
|
7
|
+
* the package-root `bin/install.js` (#2071).
|
|
8
|
+
*
|
|
9
|
+
* `gsd-tools effort sync` (src/commands.cts `cmdEffortSync`) must mirror what the
|
|
10
|
+
* installer writes — home `~/.gsd/defaults.json` merged with the project's
|
|
11
|
+
* `.planning/config.json` — which the runtime resolver (`resolveEffortInternal`
|
|
12
|
+
* via `loadConfig`) does NOT do. It previously reached those two functions via
|
|
13
|
+
* `require('../../../bin/install.js')`, but the installer never copies the
|
|
14
|
+
* package-root `bin/install.js` into a runtime home, so `effort sync` crashed with
|
|
15
|
+
* MODULE_NOT_FOUND in every installed runtime (#2071). Moving the logic here — a
|
|
16
|
+
* `src/*.cts` module compiled into the shipped `gsd-core/bin/lib/` tree — lets both
|
|
17
|
+
* the installer AND `effort sync` require it from a location that is always present,
|
|
18
|
+
* keeping a single source of truth (no duplication / drift).
|
|
19
|
+
*
|
|
20
|
+
* Pure with respect to config: `readGsdEffectiveEffortConfig` performs the config
|
|
21
|
+
* reads; `resolveInstallTimeEffort` is pure given a pre-merged effort object.
|
|
22
|
+
*/
|
|
23
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
24
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
25
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- model-resolver.cjs is an export= CommonJS module
|
|
27
|
+
const modelResolver = require("./model-resolver.cjs");
|
|
28
|
+
const { EFFORT_SET: GSD_EFFORT_SET } = modelResolver;
|
|
29
|
+
/**
|
|
30
|
+
* #2517 — Read a single GSD config file (defaults.json or per-project
|
|
31
|
+
* config.json) into a plain object, returning null on missing/empty files
|
|
32
|
+
* and warning to stderr on JSON parse failures so silent corruption can't
|
|
33
|
+
* mask broken configs (review finding #5).
|
|
34
|
+
*/
|
|
35
|
+
function _readGsdConfigFile(absPath, label) {
|
|
36
|
+
if (!node_fs_1.default.existsSync(absPath))
|
|
37
|
+
return null;
|
|
38
|
+
let raw;
|
|
39
|
+
try {
|
|
40
|
+
raw = node_fs_1.default.readFileSync(absPath, 'utf-8');
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
process.stderr.write(`gsd: warning — could not read ${label} (${absPath}): ${err.message}\n`);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(raw);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
process.stderr.write(`gsd: warning — invalid JSON in ${label} (${absPath}): ${err.message}\n`);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// #443 — model-catalog and config-defaults.manifest.json exports needed only
|
|
55
|
+
// by effort-resolution code paths (resolveInstallTimeEffort /
|
|
56
|
+
// generateCodexAgentToml / Claude .md effort injection). Loaded lazily the
|
|
57
|
+
// first time they are needed so that requiring this module in test contexts that
|
|
58
|
+
// never trigger an install does NOT produce module-load-time side effects (the
|
|
59
|
+
// manifest read + hard throw) that could alter subprocess exit codes or stderr.
|
|
60
|
+
let _gsdEffortCatalogCache = null;
|
|
61
|
+
function _getGsdEffortCatalog() {
|
|
62
|
+
if (_gsdEffortCatalogCache)
|
|
63
|
+
return _gsdEffortCatalogCache;
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- model-catalog.cjs is an export= CommonJS module
|
|
65
|
+
const { AGENT_DEFAULT_TIERS, renderEffortForRuntime } = require('./model-catalog.cjs');
|
|
66
|
+
// This module lives in gsd-core/bin/lib/, so the shared manifest is one level
|
|
67
|
+
// up in gsd-core/bin/shared/ (bin/lib → bin → shared). (In bin/install.js this
|
|
68
|
+
// path was `.., gsd-core, bin, shared` relative to the package-root bin/.)
|
|
69
|
+
const manifestPath = node_path_1.default.join(__dirname, '..', 'shared', 'config-defaults.manifest.json');
|
|
70
|
+
let manifestData;
|
|
71
|
+
try {
|
|
72
|
+
manifestData = JSON.parse(node_fs_1.default.readFileSync(manifestPath, 'utf-8'));
|
|
73
|
+
}
|
|
74
|
+
catch (_err) {
|
|
75
|
+
// Fail loudly — a missing manifest is a broken install, not a soft degradation.
|
|
76
|
+
throw new Error(`gsd install: cannot load config-defaults.manifest.json at ${manifestPath}: ${_err.message}`);
|
|
77
|
+
}
|
|
78
|
+
const tierDefaults = (manifestData.effort &&
|
|
79
|
+
manifestData.effort.routing_tier_defaults &&
|
|
80
|
+
typeof manifestData.effort.routing_tier_defaults === 'object' &&
|
|
81
|
+
!Array.isArray(manifestData.effort.routing_tier_defaults))
|
|
82
|
+
? manifestData.effort.routing_tier_defaults
|
|
83
|
+
: { light: 'low', standard: 'high', heavy: 'xhigh' }; // guard: unreachable if manifest is valid
|
|
84
|
+
const effortDefault = (manifestData.effort && typeof manifestData.effort.default === 'string')
|
|
85
|
+
? manifestData.effort.default
|
|
86
|
+
: 'high'; // guard: unreachable if manifest is valid
|
|
87
|
+
_gsdEffortCatalogCache = {
|
|
88
|
+
AGENT_DEFAULT_TIERS,
|
|
89
|
+
renderEffortForRuntime,
|
|
90
|
+
EFFORT_MANIFEST_TIER_DEFAULTS: tierDefaults,
|
|
91
|
+
EFFORT_MANIFEST_DEFAULT: effortDefault,
|
|
92
|
+
};
|
|
93
|
+
return _gsdEffortCatalogCache;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* #443 — Read the merged `effort` config block for install-time effort resolution.
|
|
97
|
+
*
|
|
98
|
+
* Probes the same config sources as readGsdRuntimeProfileResolver (per-project
|
|
99
|
+
* `.planning/config.json` wins over `~/.gsd/defaults.json`) but extracts the
|
|
100
|
+
* `effort` object instead of the model-profile fields.
|
|
101
|
+
*
|
|
102
|
+
* Returns the merged `effort` object or null when neither source defines one.
|
|
103
|
+
* The caller can pass this to resolveInstallTimeEffort() which is pure and
|
|
104
|
+
* requires no filesystem access beyond what this helper already performs.
|
|
105
|
+
*
|
|
106
|
+
* @param targetDir Runtime install root (walks up to find .planning/).
|
|
107
|
+
*/
|
|
108
|
+
function readGsdEffectiveEffortConfig(targetDir = null) {
|
|
109
|
+
const homeDefaults = _readGsdConfigFile(node_path_1.default.join(node_os_1.default.homedir(), '.gsd', 'defaults.json'), '~/.gsd/defaults.json');
|
|
110
|
+
let projectConfig = null;
|
|
111
|
+
if (targetDir) {
|
|
112
|
+
let probeDir = node_path_1.default.resolve(targetDir);
|
|
113
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
114
|
+
const candidate = node_path_1.default.join(probeDir, '.planning', 'config.json');
|
|
115
|
+
if (node_fs_1.default.existsSync(candidate)) {
|
|
116
|
+
projectConfig = _readGsdConfigFile(candidate, '.planning/config.json');
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
const parent = node_path_1.default.dirname(probeDir);
|
|
120
|
+
if (parent === probeDir)
|
|
121
|
+
break;
|
|
122
|
+
probeDir = parent;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const homeEffort = (homeDefaults && homeDefaults.effort && typeof homeDefaults.effort === 'object' && !Array.isArray(homeDefaults.effort))
|
|
126
|
+
? homeDefaults.effort
|
|
127
|
+
: null;
|
|
128
|
+
const projectEffort = (projectConfig && projectConfig.effort && typeof projectConfig.effort === 'object' && !Array.isArray(projectConfig.effort))
|
|
129
|
+
? projectConfig.effort
|
|
130
|
+
: null;
|
|
131
|
+
if (!homeEffort && !projectEffort)
|
|
132
|
+
return null;
|
|
133
|
+
// Per-project wins on conflict within each sub-field. Merge field-by-field so
|
|
134
|
+
// a project config that only sets agent_overrides still inherits global
|
|
135
|
+
// routing_tier_defaults and default.
|
|
136
|
+
return {
|
|
137
|
+
...(homeEffort || {}),
|
|
138
|
+
...(projectEffort || {}),
|
|
139
|
+
// Deep-merge agent_overrides (project wins per-key)
|
|
140
|
+
agent_overrides: {
|
|
141
|
+
...((homeEffort && homeEffort.agent_overrides) || {}),
|
|
142
|
+
...((projectEffort && projectEffort.agent_overrides) || {}),
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* #443 — Resolve install-time effort for a given agent, using the same
|
|
148
|
+
* precedence chain as resolveEffortInternal() in core.cjs, but operating
|
|
149
|
+
* on a pre-loaded effortCfg object (no loadConfig side-effects at install).
|
|
150
|
+
*
|
|
151
|
+
* Precedence (mirrors resolveEffortInternal):
|
|
152
|
+
* 1. effortCfg.agent_overrides[agentName]
|
|
153
|
+
* 2. effortCfg.routing_tier_defaults[agentTier] (if effortCfg present)
|
|
154
|
+
* — OR manifest tier defaults when effortCfg is null
|
|
155
|
+
* 3. effortCfg.default
|
|
156
|
+
* 4. 'high' (hardcoded fallback)
|
|
157
|
+
*
|
|
158
|
+
* @param effortCfg Result of readGsdEffectiveEffortConfig().
|
|
159
|
+
* @param agentName e.g. 'gsd-planner'
|
|
160
|
+
* @returns Universal effort string (low/medium/high/xhigh/max/minimal)
|
|
161
|
+
*/
|
|
162
|
+
function resolveInstallTimeEffort(effortCfg, agentName) {
|
|
163
|
+
// Validates each candidate against the canonical EFFORT_SET (sourced once
|
|
164
|
+
// from model-resolver.cjs) before accepting it, mirroring resolveEffortInternal
|
|
165
|
+
// exactly. Invalid values fall through to the next precedence layer; final
|
|
166
|
+
// fallback 'high'.
|
|
167
|
+
// Step 1: agent_overrides
|
|
168
|
+
if (effortCfg) {
|
|
169
|
+
const ao = effortCfg.agent_overrides;
|
|
170
|
+
if (ao && typeof ao === 'object' && !Array.isArray(ao)) {
|
|
171
|
+
const v = ao[agentName];
|
|
172
|
+
if (typeof v === 'string' && GSD_EFFORT_SET.has(v))
|
|
173
|
+
return v;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Step 2: routing_tier_defaults keyed by the agent's catalog tier
|
|
177
|
+
const { AGENT_DEFAULT_TIERS, EFFORT_MANIFEST_TIER_DEFAULTS, EFFORT_MANIFEST_DEFAULT } = _getGsdEffortCatalog();
|
|
178
|
+
const agentTier = AGENT_DEFAULT_TIERS[agentName];
|
|
179
|
+
if (agentTier) {
|
|
180
|
+
if (effortCfg && effortCfg.routing_tier_defaults &&
|
|
181
|
+
typeof effortCfg.routing_tier_defaults === 'object' &&
|
|
182
|
+
!Array.isArray(effortCfg.routing_tier_defaults)) {
|
|
183
|
+
const v = effortCfg.routing_tier_defaults[agentTier];
|
|
184
|
+
if (typeof v === 'string' && GSD_EFFORT_SET.has(v))
|
|
185
|
+
return v;
|
|
186
|
+
}
|
|
187
|
+
else if (!effortCfg) {
|
|
188
|
+
// No effort config — use manifest tier defaults
|
|
189
|
+
const v = EFFORT_MANIFEST_TIER_DEFAULTS[agentTier];
|
|
190
|
+
if (typeof v === 'string' && GSD_EFFORT_SET.has(v))
|
|
191
|
+
return v;
|
|
192
|
+
}
|
|
193
|
+
// effortCfg exists but has no routing_tier_defaults — fall through
|
|
194
|
+
}
|
|
195
|
+
// Step 3: effort.default
|
|
196
|
+
if (effortCfg) {
|
|
197
|
+
const d = effortCfg.default;
|
|
198
|
+
if (typeof d === 'string' && GSD_EFFORT_SET.has(d))
|
|
199
|
+
return d;
|
|
200
|
+
}
|
|
201
|
+
// Step 4: manifest default (sourced from config-defaults.manifest.json effort.default)
|
|
202
|
+
// If even the manifest default is invalid, fall back to 'high'.
|
|
203
|
+
if (typeof EFFORT_MANIFEST_DEFAULT === 'string' && GSD_EFFORT_SET.has(EFFORT_MANIFEST_DEFAULT)) {
|
|
204
|
+
return EFFORT_MANIFEST_DEFAULT;
|
|
205
|
+
}
|
|
206
|
+
return 'high';
|
|
207
|
+
}
|
|
208
|
+
module.exports = {
|
|
209
|
+
readGsdEffectiveEffortConfig,
|
|
210
|
+
resolveInstallTimeEffort,
|
|
211
|
+
_getGsdEffortCatalog,
|
|
212
|
+
_readGsdConfigFile,
|
|
213
|
+
};
|