@opengsd/gsd-pi 1.8.1-dev.897b3c90 → 1.9.0-dev.5c1a3ff2
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/README.md +10 -8
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -8
- package/dist/resources/extensions/gsd/auto-prompts.js +90 -17
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +31 -5
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -24
- package/dist/resources/extensions/gsd/constants.js +12 -13
- package/dist/resources/extensions/gsd/context-masker.js +97 -21
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +22 -0
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +3 -6
- package/dist/resources/extensions/gsd/git-service.js +19 -7
- package/dist/resources/extensions/gsd/guided-flow.js +9 -3
- package/dist/resources/extensions/gsd/markdown-renderer.js +2 -12
- package/dist/resources/extensions/gsd/md-importer.js +5 -6
- package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
- package/dist/resources/extensions/gsd/model-router.js +11 -0
- package/dist/resources/extensions/gsd/paths.js +51 -10
- package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
- package/dist/resources/extensions/gsd/preferences-types.js +5 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
- package/dist/resources/extensions/gsd/preferences.js +17 -0
- package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
- package/dist/resources/extensions/gsd/skill-activation.js +17 -3
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +12 -5
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
- package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
- package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
- package/dist/resources/extensions/gsd/workspace.js +2 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +6 -6
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.js +1 -0
- package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/package.json +1 -1
- package/packages/mcp-server/README.md +7 -2
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +5 -5
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +59 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +53 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +6 -1
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -7
- package/src/resources/extensions/gsd/auto-prompts.ts +104 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -10
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -29
- package/src/resources/extensions/gsd/constants.ts +14 -13
- package/src/resources/extensions/gsd/context-masker.ts +98 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +22 -0
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +3 -5
- package/src/resources/extensions/gsd/git-service.ts +19 -6
- package/src/resources/extensions/gsd/guided-flow.ts +9 -2
- package/src/resources/extensions/gsd/markdown-renderer.ts +2 -14
- package/src/resources/extensions/gsd/md-importer.ts +5 -5
- package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
- package/src/resources/extensions/gsd/model-router.ts +12 -0
- package/src/resources/extensions/gsd/paths.ts +58 -10
- package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
- package/src/resources/extensions/gsd/preferences.ts +25 -0
- package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
- package/src/resources/extensions/gsd/skill-activation.ts +17 -3
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +76 -1
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
- package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
- package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -5
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
- package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
- package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
- package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
- package/src/resources/extensions/gsd/workspace.ts +2 -1
- /package/dist/web/standalone/.next/static/{TezjdjSHBVRRr54XjAvte → 6YWV7VAPg-jqjfPswrKZb}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{TezjdjSHBVRRr54XjAvte → 6YWV7VAPg-jqjfPswrKZb}/_ssgManifest.js +0 -0
|
@@ -9,7 +9,8 @@ import { isAbsolute } from "node:path";
|
|
|
9
9
|
import { VALID_BRANCH_NAME } from "./git-service.js";
|
|
10
10
|
import { normalizeStringArray } from "../shared/format-utils.js";
|
|
11
11
|
import { getGateIdsForTurn } from "./gate-registry.js";
|
|
12
|
-
import { KNOWN_PREFERENCE_KEYS, KNOWN_UNIT_LABELS, GSD_MODEL_PHASE_KEYS, SKILL_ACTIONS, } from "./preferences-types.js";
|
|
12
|
+
import { KNOWN_PREFERENCE_KEYS, KNOWN_UNIT_LABELS, CONFIGURABLE_PLANNING_SUBAGENT_UNITS, GSD_MODEL_PHASE_KEYS, SKILL_ACTIONS, } from "./preferences-types.js";
|
|
13
|
+
import { ALLOWED_PLANNING_DISPATCH_AGENTS, allowedPlanningDispatchAgentsList, } from "./planning-subagent-registry.js";
|
|
13
14
|
const VALID_TOKEN_PROFILES = new Set(["budget", "balanced", "quality", "burn-max"]);
|
|
14
15
|
const VALID_THINKING_LEVELS = new Set([
|
|
15
16
|
"off",
|
|
@@ -727,6 +728,52 @@ export function validatePreferences(preferences) {
|
|
|
727
728
|
validated.pre_dispatch_hooks = validPreHooks;
|
|
728
729
|
}
|
|
729
730
|
}
|
|
731
|
+
// ─── Planning Subagents ─────────────────────────────────────────────────
|
|
732
|
+
if (preferences.planning_subagents !== undefined) {
|
|
733
|
+
if (!preferences.planning_subagents ||
|
|
734
|
+
typeof preferences.planning_subagents !== "object" ||
|
|
735
|
+
Array.isArray(preferences.planning_subagents)) {
|
|
736
|
+
errors.push("planning_subagents must be an object keyed by planning unit type");
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
const validUnits = new Set(CONFIGURABLE_PLANNING_SUBAGENT_UNITS);
|
|
740
|
+
const validPlanningSubagents = {};
|
|
741
|
+
for (const [unitType, rawConfig] of Object.entries(preferences.planning_subagents)) {
|
|
742
|
+
if (!validUnits.has(unitType)) {
|
|
743
|
+
errors.push(`planning_subagents unknown or unsupported unit "${unitType}" — supported units: ` +
|
|
744
|
+
`${CONFIGURABLE_PLANNING_SUBAGENT_UNITS.join(", ")}`);
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
748
|
+
errors.push(`planning_subagents.${unitType} must be an object with an allowed array`);
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
const allowed = normalizeStringArray(rawConfig.allowed);
|
|
752
|
+
if (allowed.length === 0) {
|
|
753
|
+
errors.push(`planning_subagents.${unitType}.allowed must include at least one read-only planning specialist`);
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
const sanitizedAllowed = [];
|
|
757
|
+
for (const agentId of allowed) {
|
|
758
|
+
if (!ALLOWED_PLANNING_DISPATCH_AGENTS.has(agentId)) {
|
|
759
|
+
errors.push(`planning_subagents.${unitType}.allowed includes "${agentId}", which is not classified as a ` +
|
|
760
|
+
`read-only planning specialist. Allowed agents: ${allowedPlanningDispatchAgentsList()}`);
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
sanitizedAllowed.push(agentId);
|
|
764
|
+
}
|
|
765
|
+
const dedupedAllowed = Array.from(new Set(sanitizedAllowed));
|
|
766
|
+
if (dedupedAllowed.length > 0) {
|
|
767
|
+
validPlanningSubagents[unitType] = {
|
|
768
|
+
allowed: dedupedAllowed,
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
if (Object.keys(validPlanningSubagents).length > 0) {
|
|
773
|
+
validated.planning_subagents = validPlanningSubagents;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
730
777
|
// ─── Dynamic Routing ─────────────────────────────────────────────────
|
|
731
778
|
if (preferences.dynamic_routing !== undefined) {
|
|
732
779
|
if (typeof preferences.dynamic_routing === "object" && preferences.dynamic_routing !== null) {
|
|
@@ -635,6 +635,7 @@ function mergePreferences(base, override) {
|
|
|
635
635
|
: undefined,
|
|
636
636
|
post_unit_hooks: mergePostUnitHooks(base.post_unit_hooks, override.post_unit_hooks),
|
|
637
637
|
pre_dispatch_hooks: mergePreDispatchHooks(base.pre_dispatch_hooks, override.pre_dispatch_hooks),
|
|
638
|
+
planning_subagents: mergePlanningSubagents(base.planning_subagents, override.planning_subagents),
|
|
638
639
|
dynamic_routing: (base.dynamic_routing || override.dynamic_routing)
|
|
639
640
|
? { ...(base.dynamic_routing ?? {}), ...(override.dynamic_routing ?? {}) }
|
|
640
641
|
: undefined,
|
|
@@ -752,6 +753,22 @@ function mergePreDispatchHooks(base, override) {
|
|
|
752
753
|
}
|
|
753
754
|
return merged.length > 0 ? merged : undefined;
|
|
754
755
|
}
|
|
756
|
+
function mergePlanningSubagents(base, override) {
|
|
757
|
+
if (!base && !override)
|
|
758
|
+
return undefined;
|
|
759
|
+
const merged = {};
|
|
760
|
+
const unitTypes = new Set([
|
|
761
|
+
...Object.keys(base ?? {}),
|
|
762
|
+
...Object.keys(override ?? {}),
|
|
763
|
+
]);
|
|
764
|
+
for (const unitType of unitTypes) {
|
|
765
|
+
const allowed = mergeStringLists(base?.[unitType]?.allowed, override?.[unitType]?.allowed);
|
|
766
|
+
if (allowed?.length) {
|
|
767
|
+
merged[unitType] = { allowed };
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
771
|
+
}
|
|
755
772
|
// ─── System Prompt Rendering ──────────────────────────────────────────────────
|
|
756
773
|
export function renderPreferencesForSystemPrompt(preferences, resolutions, options) {
|
|
757
774
|
const validated = validatePreferences(preferences);
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
* Provider Payload Policy - ordered shaping of provider request payloads.
|
|
3
3
|
*
|
|
4
4
|
* The order is intentional:
|
|
5
|
-
* 1.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* 1. superseded GSD context injections (memory/guided/forensics) are removed,
|
|
6
|
+
* keeping only the latest, for every mode,
|
|
7
|
+
* 2. observation budgeting masks old tool results in auto-mode,
|
|
8
|
+
* 3. display truncation caps tool-result text for every mode,
|
|
9
|
+
* 4. the protected Source Context Block is appended after truncation,
|
|
10
|
+
* 5. supported models receive the configured service tier.
|
|
9
11
|
*/
|
|
10
|
-
import { createObservationMask, createResponsesInputObservationMask, truncateContextResultMessages, truncateResponsesInputResultItems, } from "./context-masker.js";
|
|
12
|
+
import { createObservationMask, createResponsesInputObservationMask, filterSupersededContextInjections, filterSupersededResponsesContextInjections, truncateContextResultMessages, truncateResponsesInputResultItems, } from "./context-masker.js";
|
|
11
13
|
import { getSourceObservationStore, isAutoActive } from "./auto-runtime-state.js";
|
|
12
14
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
13
15
|
import { getEffectiveServiceTier, supportsServiceTier } from "./service-tier.js";
|
|
@@ -42,9 +44,18 @@ export function applyProviderPayloadPolicy({ payload, modelId, deps: overrides,
|
|
|
42
44
|
}
|
|
43
45
|
function applyContextManagement(payload, deps) {
|
|
44
46
|
const config = deps.loadContextManagementConfig();
|
|
47
|
+
applyContextInjectionFilter(payload);
|
|
45
48
|
applyObservationBudget(payload, config, deps.isAutoActive());
|
|
46
49
|
applyDisplayTruncation(payload, config);
|
|
47
50
|
}
|
|
51
|
+
function applyContextInjectionFilter(payload) {
|
|
52
|
+
if (Array.isArray(payload.messages)) {
|
|
53
|
+
payload.messages = filterSupersededContextInjections(payload.messages);
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(payload.input)) {
|
|
56
|
+
payload.input = filterSupersededResponsesContextInjections(payload.input);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
48
59
|
function applyObservationBudget(payload, config, autoActive) {
|
|
49
60
|
if (!autoActive || config?.observation_masking === false)
|
|
50
61
|
return;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
7
7
|
*/
|
|
8
8
|
const DESTRUCTIVE_PATTERNS = [
|
|
9
|
-
{ pattern: /\brm\s+(
|
|
9
|
+
{ pattern: /\brm\s+((?:-(?!-)[^\s]*[rR][^\s]*|--recursive)\s+|.*\s+(?:-(?!-)[^\s]*[rR][^\s]*|--recursive)(?:\s|$))/, label: "recursive delete" },
|
|
10
10
|
{ pattern: /\bgit\s+push\s+.*--force/, label: "force push" },
|
|
11
11
|
{ pattern: /\bgit\s+push\s+-f\b/, label: "force push" },
|
|
12
12
|
{ pattern: /\bgit\s+reset\s+--hard/, label: "hard reset" },
|
|
@@ -104,11 +104,24 @@ function resolvePreferredSkillNames(prefs, visibleSkills, contextTokens, base) {
|
|
|
104
104
|
/** Skill names must be lowercase alphanumeric with hyphens — reject anything else
|
|
105
105
|
* to prevent prompt injection via crafted directory names. */
|
|
106
106
|
const SAFE_SKILL_NAME = /^[a-z0-9][a-z0-9-]*$/;
|
|
107
|
-
function
|
|
107
|
+
function escapeXml(str) {
|
|
108
|
+
return str
|
|
109
|
+
.replace(/&/g, "&")
|
|
110
|
+
.replace(/</g, "<")
|
|
111
|
+
.replace(/>/g, ">")
|
|
112
|
+
.replace(/"/g, """)
|
|
113
|
+
.replace(/'/g, "'");
|
|
114
|
+
}
|
|
115
|
+
function formatSkillActivationBlock(skillNames, skillPaths) {
|
|
108
116
|
const safe = skillNames.filter(name => SAFE_SKILL_NAME.test(name));
|
|
109
117
|
if (safe.length === 0)
|
|
110
118
|
return "";
|
|
111
|
-
const reads = safe.map(name =>
|
|
119
|
+
const reads = safe.map(name => {
|
|
120
|
+
const path = skillPaths.get(name);
|
|
121
|
+
if (path)
|
|
122
|
+
return `Read the skill file at \`${escapeXml(path)}\``;
|
|
123
|
+
return `Find '${name}' in <available_skills>, copy its <location> value, and pass that exact path to read`;
|
|
124
|
+
}).join(". ");
|
|
112
125
|
return `<skill_activation>${reads}.</skill_activation>`;
|
|
113
126
|
}
|
|
114
127
|
/**
|
|
@@ -149,6 +162,7 @@ export function buildSkillActivationBlock(params) {
|
|
|
149
162
|
const visibleSkills = loaded;
|
|
150
163
|
const manifestScopedSkills = filterSkillsByManifest(visibleSkills, params.unitType);
|
|
151
164
|
const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
|
|
165
|
+
const installedSkillPaths = new Map(visibleSkills.map(skill => [normalizeSkillReference(skill.name), skill.filePath]));
|
|
152
166
|
warnIfManifestHasMissingSkills(params.unitType, installedNames);
|
|
153
167
|
const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
|
|
154
168
|
const matched = new Set();
|
|
@@ -196,7 +210,7 @@ export function buildSkillActivationBlock(params) {
|
|
|
196
210
|
const ordered = [...matched]
|
|
197
211
|
.filter(name => installedNames.has(name) && !avoided.has(name))
|
|
198
212
|
.sort();
|
|
199
|
-
const activationBlock = formatSkillActivationBlock(ordered);
|
|
213
|
+
const activationBlock = formatSkillActivationBlock(ordered, installedSkillPaths);
|
|
200
214
|
// Omit recommendations when the system catalog is manifest-scoped for this
|
|
201
215
|
// unit — skill names are already listed in <available_skills>.
|
|
202
216
|
let recommendationsBlock = "";
|
|
@@ -92,6 +92,11 @@ remote_questions:
|
|
|
92
92
|
uat_dispatch:
|
|
93
93
|
post_unit_hooks: []
|
|
94
94
|
pre_dispatch_hooks: []
|
|
95
|
+
# planning_subagents:
|
|
96
|
+
# plan-milestone:
|
|
97
|
+
# allowed: [scout, planner, security]
|
|
98
|
+
# plan-slice:
|
|
99
|
+
# allowed: [scout, planner, reviewer, security]
|
|
95
100
|
# language:
|
|
96
101
|
# experimental:
|
|
97
102
|
# rtk: false
|
|
@@ -15,7 +15,7 @@ import { isClosedStatus } from "../status-guards.js";
|
|
|
15
15
|
import { transaction, insertMilestone, insertSlice, insertTask, insertVerificationEvidence, getMilestone, getSlice, getTask, updateTaskStatus, deleteVerificationEvidence, saveGateResult, getPendingGatesForTurn, getUnresolvedBlockingReworkFindingsForTask, getBlockingReworkFindingsForTask, applyReworkResolutions, } from "../gsd-db.js";
|
|
16
16
|
import { getWorkflowDatabasePath, ensureWorkflowDbAtPath } from "../db-workspace.js";
|
|
17
17
|
import { getGatesForTurn } from "../gate-registry.js";
|
|
18
|
-
import { gsdProjectionRoot, clearPathCache, resolveMilestonePath, resolveSlicePath } from "../paths.js";
|
|
18
|
+
import { buildFlatTaskFileName, buildTaskFileName, gsdProjectionRoot, clearPathCache, legacyMilestonesDir, resolveMilestonePath, resolveSlicePath, } from "../paths.js";
|
|
19
19
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
20
20
|
import { checkOwnership, taskUnitKey } from "../unit-ownership.js";
|
|
21
21
|
import { saveFile, clearParseCache } from "../files.js";
|
|
@@ -34,13 +34,20 @@ function taskSummaryPath(basePath, milestoneId, sliceId, taskId) {
|
|
|
34
34
|
// a legacy layout and breaks all subsequent path resolution for the session.
|
|
35
35
|
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId);
|
|
36
36
|
const phaseDir = resolveMilestonePath(basePath, milestoneId);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
38
|
+
const isLegacy = phaseDir
|
|
39
|
+
? phaseDir.startsWith(legacyBase + "/") || phaseDir.startsWith(legacyBase + "\\")
|
|
40
|
+
: false;
|
|
41
|
+
if (isLegacy && phaseDir) {
|
|
42
|
+
// Legacy layout: the slice has its own slices/SID/ subdir → tasks/ subdir.
|
|
43
|
+
const legacySlicePath = slicePath && slicePath !== phaseDir
|
|
44
|
+
? slicePath
|
|
45
|
+
: join(phaseDir, "slices", sliceId);
|
|
46
|
+
return join(legacySlicePath, "tasks", buildTaskFileName(taskId, "SUMMARY"));
|
|
40
47
|
}
|
|
41
48
|
if (phaseDir) {
|
|
42
49
|
// Flat-phase: task summaries go in the phase dir (no tasks/ subdir)
|
|
43
|
-
return join(phaseDir,
|
|
50
|
+
return join(phaseDir, buildFlatTaskFileName(sliceId, taskId, "SUMMARY"));
|
|
44
51
|
}
|
|
45
52
|
// Fallback: legacy hardcoded path (milestone/slice dir not on disk yet)
|
|
46
53
|
return join(gsdProjectionRoot(basePath), "milestones", milestoneId, "slices", sliceId, "tasks", `${taskId}-SUMMARY.md`);
|
|
@@ -16,7 +16,7 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
16
16
|
import { debugLog } from "../debug-logger.js";
|
|
17
17
|
import { existsSync, unlinkSync } from "node:fs";
|
|
18
18
|
import { join } from "node:path";
|
|
19
|
-
import { resolveMilestonePath, resolveSlicePath, resolveTasksDir, clearPathCache } from "../paths.js";
|
|
19
|
+
import { buildFlatTaskFileName, buildTaskFileName, legacyMilestonesDir, resolveMilestonePath, resolveSlicePath, resolveTasksDir, clearPathCache, } from "../paths.js";
|
|
20
20
|
export async function handleReopenMilestone(params, basePath) {
|
|
21
21
|
// ── Validate required fields ────────────────────────────────────────────
|
|
22
22
|
if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
|
|
@@ -41,6 +41,8 @@ export async function handleReopenMilestone(params, basePath) {
|
|
|
41
41
|
// auto-corrects entities back to "complete", making reopen a no-op (#3161).
|
|
42
42
|
try {
|
|
43
43
|
const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
|
|
44
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
45
|
+
const isLegacy = !!milestoneDir && (milestoneDir.startsWith(legacyBase + "/") || milestoneDir.startsWith(legacyBase + "\\"));
|
|
44
46
|
if (milestoneDir) {
|
|
45
47
|
const milestoneSummary = join(milestoneDir, `${params.milestoneId}-SUMMARY.md`);
|
|
46
48
|
if (existsSync(milestoneSummary))
|
|
@@ -58,10 +60,17 @@ export async function handleReopenMilestone(params, basePath) {
|
|
|
58
60
|
unlinkSync(sliceUat);
|
|
59
61
|
}
|
|
60
62
|
const tasksDir = resolveTasksDir(basePath, params.milestoneId, slice.id);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
const tasks = getSliceTasks(params.milestoneId, slice.id);
|
|
64
|
+
for (const task of tasks) {
|
|
65
|
+
const taskSummaries = isLegacy
|
|
66
|
+
? (tasksDir ? [join(tasksDir, buildTaskFileName(task.id, "SUMMARY"))] : [])
|
|
67
|
+
: milestoneDir
|
|
68
|
+
? [
|
|
69
|
+
join(milestoneDir, buildFlatTaskFileName(slice.id, task.id, "SUMMARY")),
|
|
70
|
+
join(milestoneDir, buildTaskFileName(task.id, "SUMMARY")),
|
|
71
|
+
]
|
|
72
|
+
: [];
|
|
73
|
+
for (const taskSummary of taskSummaries) {
|
|
65
74
|
if (existsSync(taskSummary))
|
|
66
75
|
unlinkSync(taskSummary);
|
|
67
76
|
}
|
|
@@ -22,7 +22,7 @@ import { appendEvent } from "../workflow-events.js";
|
|
|
22
22
|
import { logWarning } from "../workflow-logger.js";
|
|
23
23
|
import { existsSync, unlinkSync } from "node:fs";
|
|
24
24
|
import { join } from "node:path";
|
|
25
|
-
import { resolveTasksDir, resolveSlicePath, clearPathCache } from "../paths.js";
|
|
25
|
+
import { buildFlatTaskFileName, buildTaskFileName, legacyMilestonesDir, resolveMilestonePath, resolveTasksDir, resolveSlicePath, clearPathCache, } from "../paths.js";
|
|
26
26
|
export async function handleReopenSlice(params, basePath) {
|
|
27
27
|
// ── Validate required fields ────────────────────────────────────────────
|
|
28
28
|
if (!params.sliceId || typeof params.sliceId !== "string" || params.sliceId.trim() === "") {
|
|
@@ -52,11 +52,21 @@ export async function handleReopenSlice(params, basePath) {
|
|
|
52
52
|
// Without this, the DB-filesystem reconciler sees SUMMARY.md files and
|
|
53
53
|
// auto-corrects tasks back to "complete", making reopen a no-op (#3161).
|
|
54
54
|
try {
|
|
55
|
+
const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
|
|
56
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
57
|
+
const isLegacy = !!milestoneDir && (milestoneDir.startsWith(legacyBase + "/") || milestoneDir.startsWith(legacyBase + "\\"));
|
|
55
58
|
const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
const tasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
60
|
+
for (const task of tasks) {
|
|
61
|
+
const summaryPaths = isLegacy
|
|
62
|
+
? (tasksDir ? [join(tasksDir, buildTaskFileName(task.id, "SUMMARY"))] : [])
|
|
63
|
+
: milestoneDir
|
|
64
|
+
? [
|
|
65
|
+
join(milestoneDir, buildFlatTaskFileName(params.sliceId, task.id, "SUMMARY")),
|
|
66
|
+
join(milestoneDir, buildTaskFileName(task.id, "SUMMARY")),
|
|
67
|
+
]
|
|
68
|
+
: [];
|
|
69
|
+
for (const summaryPath of summaryPaths) {
|
|
60
70
|
if (existsSync(summaryPath))
|
|
61
71
|
unlinkSync(summaryPath);
|
|
62
72
|
}
|
|
@@ -17,8 +17,8 @@ import { appendEvent } from "../workflow-events.js";
|
|
|
17
17
|
import { logWarning } from "../workflow-logger.js";
|
|
18
18
|
import { writeReopenReason } from "../reopen-reason.js";
|
|
19
19
|
import { existsSync, unlinkSync } from "node:fs";
|
|
20
|
-
import { join
|
|
21
|
-
import { resolveTasksDir, resolveSlicePath, clearPathCache } from "../paths.js";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { buildFlatTaskFileName, buildTaskFileName, legacyMilestonesDir, resolveMilestonePath, resolveTasksDir, resolveSlicePath, clearPathCache, } from "../paths.js";
|
|
22
22
|
export async function handleReopenTask(params, basePath) {
|
|
23
23
|
// ── Validate required fields ────────────────────────────────────────────
|
|
24
24
|
if (!params.taskId || typeof params.taskId !== "string" || params.taskId.trim() === "") {
|
|
@@ -76,14 +76,20 @@ export async function handleReopenTask(params, basePath) {
|
|
|
76
76
|
// summary cleanup into tasks/ (#1208).
|
|
77
77
|
try {
|
|
78
78
|
const slicePath = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
const milestonePath = resolveMilestonePath(basePath, params.milestoneId);
|
|
80
|
+
if (milestonePath) {
|
|
81
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
82
|
+
const isLegacy = milestonePath.startsWith(legacyBase + "/") || milestonePath.startsWith(legacyBase + "\\");
|
|
83
|
+
const summaryPaths = isLegacy
|
|
84
|
+
? [join(resolveTasksDir(basePath, params.milestoneId, params.sliceId) ?? slicePath ?? join(milestonePath, "slices", params.sliceId, "tasks"), buildTaskFileName(params.taskId, "SUMMARY"))]
|
|
85
|
+
: [
|
|
86
|
+
join(milestonePath, buildFlatTaskFileName(params.sliceId, params.taskId, "SUMMARY")),
|
|
87
|
+
join(milestonePath, buildTaskFileName(params.taskId, "SUMMARY")),
|
|
88
|
+
];
|
|
89
|
+
for (const summaryPath of summaryPaths) {
|
|
90
|
+
if (existsSync(summaryPath))
|
|
91
|
+
unlinkSync(summaryPath);
|
|
92
|
+
}
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
95
|
catch (cleanupErr) {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
// owned by the unit, not in the composer. Reviews must enforce this — it
|
|
37
37
|
// is the difference between an orchestrator and a runaway DSL.
|
|
38
38
|
import { resolveManifest, } from "./unit-context-manifest.js";
|
|
39
|
+
import { resolveEffectivePlanningToolsPolicy } from "./planning-subagent-policy.js";
|
|
39
40
|
import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
|
|
40
41
|
/**
|
|
41
42
|
* Produce the inlined-context portion of a unit's system prompt by
|
|
@@ -148,11 +149,32 @@ const TOOL_SURFACE_GUIDANCE_BY_UNIT = {
|
|
|
148
149
|
"validate-milestone": "Dispatch reviewer subagents in parallel, then persist the verdict via `gsd_validate_milestone`. Do not query `.gsd/gsd.db` directly — use `gsd_milestone_status` and inlined context.",
|
|
149
150
|
"complete-milestone": "Persist completion only through `gsd_complete_milestone` after verification passes. Do not query `.gsd/gsd.db` directly. Do not write `.gsd/PROJECT.md` or `.gsd/REQUIREMENTS.md` by hand — use `gsd_summary_save` and `gsd_requirement_update`.",
|
|
150
151
|
"replan-slice": "Persist replans through `gsd_replan_slice` only. Do not edit `PLAN.md` or task plans directly.",
|
|
151
|
-
"plan-slice": "Persist planning through `gsd_plan_slice` only. Dispatch subagents only to **scout** or **planner** for reconnaissance — not implementation agents. Do not edit user source files outside `.gsd/**`.",
|
|
152
|
-
"refine-slice": "Persist refinements through `gsd_plan_slice` only. Dispatch subagents only to **scout** or **planner**. Do not edit user source files outside `.gsd/**`.",
|
|
153
|
-
"plan-milestone": "Persist milestone planning through `gsd_plan_milestone` / `gsd_plan_slice`. Do not edit user source files outside `.gsd/**`.",
|
|
154
152
|
"research-slice": "Dispatch subagents only to **scout** or **planner** for reconnaissance. Do not edit user source files outside `.gsd/**`.",
|
|
155
153
|
};
|
|
154
|
+
function formatAllowedAgents(agents) {
|
|
155
|
+
return agents.map((agent) => `**${agent}**`).join(", ");
|
|
156
|
+
}
|
|
157
|
+
function guidanceForUnitToolsPolicy(unitType, policy) {
|
|
158
|
+
if (unitType === "plan-slice") {
|
|
159
|
+
const dispatch = policy.mode === "planning-dispatch"
|
|
160
|
+
? ` Dispatch subagents only to ${formatAllowedAgents(policy.allowedSubagents)} for reconnaissance — not implementation agents.`
|
|
161
|
+
: " Do not dispatch subagents.";
|
|
162
|
+
return `Persist planning through \`gsd_plan_slice\` only.${dispatch} Do not edit user source files outside \`.gsd/**\`.`;
|
|
163
|
+
}
|
|
164
|
+
if (unitType === "refine-slice") {
|
|
165
|
+
const dispatch = policy.mode === "planning-dispatch"
|
|
166
|
+
? ` Dispatch subagents only to ${formatAllowedAgents(policy.allowedSubagents)}.`
|
|
167
|
+
: " Do not dispatch subagents.";
|
|
168
|
+
return `Persist refinements through \`gsd_plan_slice\` only.${dispatch} Do not edit user source files outside \`.gsd/**\`.`;
|
|
169
|
+
}
|
|
170
|
+
if (unitType === "plan-milestone") {
|
|
171
|
+
const dispatch = policy.mode === "planning-dispatch"
|
|
172
|
+
? ` Dispatch subagents only to ${formatAllowedAgents(policy.allowedSubagents)}.`
|
|
173
|
+
: "";
|
|
174
|
+
return `Persist milestone planning through \`gsd_plan_milestone\` / \`gsd_plan_slice\`.${dispatch} Do not edit user source files outside \`.gsd/**\`.`;
|
|
175
|
+
}
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
156
178
|
function guidanceForToolsPolicy(policy) {
|
|
157
179
|
switch (policy.mode) {
|
|
158
180
|
case "planning":
|
|
@@ -191,8 +213,9 @@ export function composeToolSurfaceInstructions(unitType, opts) {
|
|
|
191
213
|
const manifest = resolveManifest(unitType);
|
|
192
214
|
if (!manifest)
|
|
193
215
|
return "";
|
|
194
|
-
const
|
|
195
|
-
const
|
|
216
|
+
const effectiveTools = resolveEffectivePlanningToolsPolicy(unitType, manifest.tools, opts.basePath) ?? manifest.tools;
|
|
217
|
+
const unitGuidance = guidanceForUnitToolsPolicy(unitType, effectiveTools) ?? TOOL_SURFACE_GUIDANCE_BY_UNIT[unitType];
|
|
218
|
+
const policyGuidance = unitGuidance ? null : guidanceForToolsPolicy(effectiveTools);
|
|
196
219
|
const forbiddenLine = formatForbiddenWorkflowToolsLine(unitType, unitGuidance);
|
|
197
220
|
const parts = [unitGuidance, policyGuidance, forbiddenLine].filter((part) => typeof part === "string" && part.length > 0);
|
|
198
221
|
if (parts.length === 0)
|
|
@@ -13,7 +13,7 @@ import { isClosedStatus } from "./status-guards.js";
|
|
|
13
13
|
import { deriveState } from "./state.js";
|
|
14
14
|
import { renderPlanFromDb, renderRoadmapFromDb } from "./markdown-renderer.js";
|
|
15
15
|
import { readManifest } from "./workflow-manifest.js";
|
|
16
|
-
import { gsdRoot, resolveMilestoneFile, resolveSliceFile, resolveTaskFile,
|
|
16
|
+
import { gsdRoot, resolveMilestoneFile, resolveSliceFile, resolveTaskFile, targetTaskFile } from "./paths.js";
|
|
17
17
|
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
18
18
|
/**
|
|
19
19
|
* Strip a leading ID prefix (e.g. "M001: " or "S04: ") from a title
|
|
@@ -276,8 +276,7 @@ export function renderSummaryProjection(basePath, milestoneId, sliceId, taskId)
|
|
|
276
276
|
return;
|
|
277
277
|
const evidenceRows = getVerificationEvidence(milestoneId, sliceId, taskId);
|
|
278
278
|
const content = renderSummaryContent(taskRow, sliceId, milestoneId, evidenceRows);
|
|
279
|
-
const summaryPath =
|
|
280
|
-
?? join(basePath, relTaskFile(basePath, milestoneId, sliceId, taskId, "SUMMARY", getMilestone(milestoneId)?.title));
|
|
279
|
+
const summaryPath = targetTaskFile(basePath, milestoneId, sliceId, taskId, "SUMMARY", getMilestone(milestoneId)?.title);
|
|
281
280
|
mkdirSync(dirname(summaryPath), { recursive: true });
|
|
282
281
|
atomicWriteSync(summaryPath, content);
|
|
283
282
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { resolveGsdPathContract, resolveMilestoneFile, resolveMilestonePath, targetMilestoneFile, normalizeRealPath, } from "./paths.js";
|
|
4
4
|
import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
5
|
+
import { milestoneMetaPath } from "./git-service.js";
|
|
5
6
|
function tryRealpath(p) {
|
|
6
7
|
return normalizeRealPath(p);
|
|
7
8
|
}
|
|
@@ -63,7 +64,7 @@ export function scopeMilestone(workspace, milestoneId) {
|
|
|
63
64
|
stateFile: () => join(gsd, "STATE.md"),
|
|
64
65
|
dbPath: () => contract.projectDb,
|
|
65
66
|
milestoneDir: () => scopeMilestoneDir(basePath, milestoneId),
|
|
66
|
-
metaJson: () =>
|
|
67
|
+
metaJson: () => milestoneMetaPath(basePath, milestoneId),
|
|
67
68
|
});
|
|
68
69
|
return scope;
|
|
69
70
|
}
|