gsd-pi 2.78.1-dev.84a383f51 → 2.78.1-dev.9d08d820b
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/bundled-resource-path.d.ts +7 -0
- package/dist/bundled-resource-path.js +34 -2
- package/dist/claude-cli-check.js +18 -6
- package/dist/headless-query.js +21 -6
- package/dist/loader.js +2 -3
- package/dist/resource-loader.js +2 -8
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +19 -7
- package/dist/resources/extensions/gsd/auto/phases.js +3 -11
- package/dist/resources/extensions/gsd/auto/session.js +2 -6
- package/dist/resources/extensions/gsd/auto-dashboard.js +3 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +18 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +63 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +30 -13
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -1
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +22 -0
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +84 -2
- package/dist/resources/extensions/gsd/commands-config.js +3 -2
- package/dist/resources/extensions/gsd/commands-extensions.js +46 -3
- package/dist/resources/extensions/gsd/commands-handlers.js +3 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +6 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
- package/dist/resources/extensions/gsd/forensics.js +8 -6
- package/dist/resources/extensions/gsd/guided-flow.js +2 -1
- package/dist/resources/extensions/gsd/home-dir.js +16 -0
- package/dist/resources/extensions/gsd/key-manager.js +2 -1
- package/dist/resources/extensions/gsd/migrate/command.js +3 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +10 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +10 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +29 -4
- package/dist/resources/extensions/gsd/worktree-manager.js +20 -1
- package/dist/resources/extensions/gsd/worktree-resolver.js +4 -13
- package/dist/resources/extensions/gsd/worktree-root.js +124 -0
- package/dist/resources/extensions/gsd/worktree.js +4 -115
- package/dist/resources/extensions/ollama/index.js +15 -2
- package/dist/resources/extensions/ollama/model-capabilities.js +31 -0
- package/dist/resources/extensions/ollama/ollama-client.js +40 -4
- package/dist/resources/extensions/subagent/index.js +324 -178
- 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 +9 -9
- 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 +9 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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/worktree-cli.d.ts +1 -0
- package/dist/worktree-cli.js +9 -3
- package/package.json +1 -3
- package/packages/mcp-server/src/workflow-tools.test.ts +52 -0
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +20 -7
- package/src/resources/extensions/gsd/auto/phases.ts +3 -11
- package/src/resources/extensions/gsd/auto/session.ts +2 -6
- package/src/resources/extensions/gsd/auto-dashboard.ts +3 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +18 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +60 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +44 -12
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +20 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +103 -1
- package/src/resources/extensions/gsd/commands-config.ts +3 -2
- package/src/resources/extensions/gsd/commands-extensions.ts +43 -3
- package/src/resources/extensions/gsd/commands-handlers.ts +3 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +6 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
- package/src/resources/extensions/gsd/forensics.ts +10 -5
- package/src/resources/extensions/gsd/guided-flow.ts +2 -1
- package/src/resources/extensions/gsd/home-dir.ts +19 -0
- package/src/resources/extensions/gsd/journal.ts +4 -1
- package/src/resources/extensions/gsd/key-manager.ts +2 -1
- package/src/resources/extensions/gsd/migrate/command.ts +3 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +10 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +10 -0
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/commands-extensions-version-compare.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/home-dir.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +18 -1
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +17 -1
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +38 -3
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +34 -33
- package/src/resources/extensions/gsd/tests/worktree.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +116 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +36 -4
- package/src/resources/extensions/gsd/worktree-manager.ts +40 -1
- package/src/resources/extensions/gsd/worktree-resolver.ts +4 -14
- package/src/resources/extensions/gsd/worktree-root.ts +144 -0
- package/src/resources/extensions/gsd/worktree.ts +8 -119
- package/src/resources/extensions/ollama/index.ts +16 -2
- package/src/resources/extensions/ollama/model-capabilities.ts +34 -0
- package/src/resources/extensions/ollama/ollama-client.ts +41 -4
- package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +96 -0
- package/src/resources/extensions/ollama/tests/ollama-client-timeout-env.test.ts +147 -0
- package/src/resources/extensions/subagent/index.ts +165 -7
- /package/dist/web/standalone/.next/static/{UF5VF4F1tB0miEtJS7LyX → -Ukk6_YxRd4GY4iUOnRUE}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{UF5VF4F1tB0miEtJS7LyX → -Ukk6_YxRd4GY4iUOnRUE}/_ssgManifest.js +0 -0
|
@@ -111,6 +111,12 @@ export type PreferencesPolicy = "none" | "active-only" | "full";
|
|
|
111
111
|
* Task subagent dispatch denied. Catches the bug class
|
|
112
112
|
* where a discuss-milestone turn modifies user source
|
|
113
113
|
* files (forensics: ~/Github/test-apps/b23, #4934).
|
|
114
|
+
* - "planning-dispatch"
|
|
115
|
+
* — Same read + .gsd/** write + safe-Bash surface as
|
|
116
|
+
* "planning", but permits controlled subagent dispatch
|
|
117
|
+
* only to the agents listed in the ToolsPolicy
|
|
118
|
+
* `allowedSubagents` field. See write-gate.ts for the
|
|
119
|
+
* runtime agent-class enforcement details.
|
|
114
120
|
* - "docs" — Read tools always; writes restricted to .gsd/** AND
|
|
115
121
|
* the explicit `allowedPathGlobs` set; Bash safe-allowlist;
|
|
116
122
|
* no subagents. Reserved for rewrite-docs, which legitimately
|
|
@@ -125,6 +131,7 @@ export type ToolsPolicy =
|
|
|
125
131
|
| { readonly mode: "all" }
|
|
126
132
|
| { readonly mode: "read-only" }
|
|
127
133
|
| { readonly mode: "planning" }
|
|
134
|
+
| { readonly mode: "planning-dispatch"; readonly allowedSubagents: readonly string[] }
|
|
128
135
|
| { readonly mode: "docs"; readonly allowedPathGlobs: readonly string[] };
|
|
129
136
|
|
|
130
137
|
// ─── Computed-artifact registry (#4924 v2 contract) ───────────────────────
|
|
@@ -268,6 +275,18 @@ const COMMON_BUDGET_SMALL = 250_000; // ~65K tokens
|
|
|
268
275
|
|
|
269
276
|
const TOOLS_ALL: ToolsPolicy = { mode: "all" };
|
|
270
277
|
const TOOLS_PLANNING: ToolsPolicy = { mode: "planning" };
|
|
278
|
+
// Like TOOLS_PLANNING but permits dispatch to read-only recon/planning
|
|
279
|
+
// specialists. Runtime-enforced by write-gate.ts before the subagent tool runs.
|
|
280
|
+
const TOOLS_PLANNING_DISPATCH_RECON: ToolsPolicy = {
|
|
281
|
+
mode: "planning-dispatch",
|
|
282
|
+
allowedSubagents: ["scout", "planner"],
|
|
283
|
+
};
|
|
284
|
+
// Like TOOLS_PLANNING_DISPATCH_RECON, but for closeout units that fan out
|
|
285
|
+
// verification work to review-tier specialists.
|
|
286
|
+
const TOOLS_PLANNING_DISPATCH_REVIEW: ToolsPolicy = {
|
|
287
|
+
mode: "planning-dispatch",
|
|
288
|
+
allowedSubagents: ["reviewer", "security", "tester"],
|
|
289
|
+
};
|
|
271
290
|
const TOOLS_DOCS: ToolsPolicy = {
|
|
272
291
|
mode: "docs",
|
|
273
292
|
// Globs are resolved relative to project basePath. The set is intentionally
|
|
@@ -376,7 +395,11 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
376
395
|
memory: "prompt-relevant",
|
|
377
396
|
codebaseMap: false,
|
|
378
397
|
preferences: "active-only",
|
|
379
|
-
|
|
398
|
+
// planning-dispatch: completion is a high-leverage place to fan out to
|
|
399
|
+
// reviewer / security / tester subagents. They read the diff and report
|
|
400
|
+
// findings; they do not write user source. Write isolation to .gsd/ is
|
|
401
|
+
// preserved.
|
|
402
|
+
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
380
403
|
artifacts: {
|
|
381
404
|
// #4780 landed slice-summary as excerpt for this unit; phase 2 of
|
|
382
405
|
// the architecture will read this manifest as the source of truth
|
|
@@ -409,7 +432,10 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
409
432
|
memory: "prompt-relevant",
|
|
410
433
|
codebaseMap: true,
|
|
411
434
|
preferences: "active-only",
|
|
412
|
-
|
|
435
|
+
// planning-dispatch: allows subagent dispatch so the planner can fan out
|
|
436
|
+
// to scout for codebase recon and to planner/decompose-style specialists
|
|
437
|
+
// for sub-decomposition. Write-isolation to .gsd/ is preserved.
|
|
438
|
+
tools: TOOLS_PLANNING_DISPATCH_RECON,
|
|
413
439
|
artifacts: {
|
|
414
440
|
inline: ["roadmap", "slice-research", "dependency-summaries", "requirements", "decisions", "templates"],
|
|
415
441
|
excerpt: [],
|
|
@@ -423,7 +449,10 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
423
449
|
memory: "prompt-relevant",
|
|
424
450
|
codebaseMap: true,
|
|
425
451
|
preferences: "active-only",
|
|
426
|
-
|
|
452
|
+
// See plan-slice — same rationale: dispatch to scout/planner-style
|
|
453
|
+
// specialists during refinement is materially better than re-doing recon
|
|
454
|
+
// inline.
|
|
455
|
+
tools: TOOLS_PLANNING_DISPATCH_RECON,
|
|
427
456
|
artifacts: {
|
|
428
457
|
inline: ["slice-plan", "slice-research", "dependency-summaries", "templates"],
|
|
429
458
|
excerpt: [],
|
|
@@ -451,7 +480,10 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
451
480
|
memory: "prompt-relevant",
|
|
452
481
|
codebaseMap: false,
|
|
453
482
|
preferences: "active-only",
|
|
454
|
-
|
|
483
|
+
// See complete-milestone — same rationale: dispatch to reviewer / security /
|
|
484
|
+
// tester subagents to fan out review work without bloating this unit's
|
|
485
|
+
// context.
|
|
486
|
+
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
455
487
|
artifacts: {
|
|
456
488
|
// Phase 3 migration (#4782): matches today's actual
|
|
457
489
|
// buildCompleteSlicePrompt inlining order. Overrides prepend +
|
|
@@ -39,6 +39,11 @@ import {
|
|
|
39
39
|
nativeWorktreeRemove,
|
|
40
40
|
} from "./native-git-bridge.js";
|
|
41
41
|
import { emitCanonicalRootRedirect } from "./worktree-telemetry.js";
|
|
42
|
+
import {
|
|
43
|
+
isGsdWorktreePath,
|
|
44
|
+
normalizeWorktreePathForCompare,
|
|
45
|
+
resolveWorktreeProjectRoot,
|
|
46
|
+
} from "./worktree-root.js";
|
|
42
47
|
|
|
43
48
|
// ─── Types ─────────────────────────────────────────────────────────────────
|
|
44
49
|
|
|
@@ -75,6 +80,20 @@ function normalizePathForComparison(path: string): string {
|
|
|
75
80
|
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
76
81
|
}
|
|
77
82
|
|
|
83
|
+
function normalizeBasePathForWorktreeOps(basePath: string): string {
|
|
84
|
+
const resolved = resolveWorktreeProjectRoot(basePath);
|
|
85
|
+
if (
|
|
86
|
+
isGsdWorktreePath(basePath) &&
|
|
87
|
+
normalizeWorktreePathForCompare(resolved) === normalizeWorktreePathForCompare(basePath)
|
|
88
|
+
) {
|
|
89
|
+
throw new GSDError(
|
|
90
|
+
GSD_GIT_ERROR,
|
|
91
|
+
`Cannot resolve project root from worktree path: ${basePath}. Run the command from the project root or set GSD_PROJECT_ROOT.`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return resolved;
|
|
95
|
+
}
|
|
96
|
+
|
|
78
97
|
// ─── resolveGitDir ─────────────────────────────────────────────────────────
|
|
79
98
|
|
|
80
99
|
/**
|
|
@@ -106,7 +125,7 @@ export function resolveGitDir(basePath: string): string {
|
|
|
106
125
|
}
|
|
107
126
|
|
|
108
127
|
export function worktreesDir(basePath: string): string {
|
|
109
|
-
return join(basePath, ".gsd", "worktrees");
|
|
128
|
+
return join(resolveWorktreeProjectRoot(basePath), ".gsd", "worktrees");
|
|
110
129
|
}
|
|
111
130
|
|
|
112
131
|
export function worktreePath(basePath: string, name: string): string {
|
|
@@ -195,6 +214,8 @@ export function resolveCanonicalMilestoneRoot(
|
|
|
195
214
|
* @param opts.branch — override the default `worktree/<name>` branch name
|
|
196
215
|
*/
|
|
197
216
|
export function createWorktree(basePath: string, name: string, opts: { branch?: string; startPoint?: string; reuseExistingBranch?: boolean } = {}): WorktreeInfo {
|
|
217
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
218
|
+
|
|
198
219
|
// Validate name: alphanumeric, hyphens, underscores only
|
|
199
220
|
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
200
221
|
throw new GSDError(GSD_PARSE_ERROR, `Invalid worktree name "${name}". Use only letters, numbers, hyphens, and underscores.`);
|
|
@@ -297,6 +318,8 @@ export function createWorktree(basePath: string, name: string, opts: { branch?:
|
|
|
297
318
|
* Uses native worktree list and filters to those under .gsd/worktrees/.
|
|
298
319
|
*/
|
|
299
320
|
export function listWorktrees(basePath: string): WorktreeInfo[] {
|
|
321
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
322
|
+
|
|
300
323
|
const baseVariants = [resolve(basePath)];
|
|
301
324
|
if (existsSync(basePath)) {
|
|
302
325
|
baseVariants.push(realpathSync(basePath));
|
|
@@ -459,6 +482,8 @@ export function removeWorktree(
|
|
|
459
482
|
name: string,
|
|
460
483
|
opts: { deleteBranch?: boolean; force?: boolean; branch?: string } = {},
|
|
461
484
|
): void {
|
|
485
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
486
|
+
|
|
462
487
|
let wtPath = worktreePath(basePath, name);
|
|
463
488
|
const branch = opts.branch ?? worktreeBranchName(name);
|
|
464
489
|
const { deleteBranch = true, force = true } = opts;
|
|
@@ -714,6 +739,8 @@ function parseDiffNameStatus(entries: { status: string; path: string }[]): Workt
|
|
|
714
739
|
* Returns a summary of added, modified, and removed GSD artifacts.
|
|
715
740
|
*/
|
|
716
741
|
export function diffWorktreeGSD(basePath: string, name: string): WorktreeDiffSummary {
|
|
742
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
743
|
+
|
|
717
744
|
const branch = worktreeBranchName(name);
|
|
718
745
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
719
746
|
|
|
@@ -729,6 +756,8 @@ export function diffWorktreeGSD(basePath: string, name: string): WorktreeDiffSum
|
|
|
729
756
|
* content, this correctly returns an empty diff.
|
|
730
757
|
*/
|
|
731
758
|
export function diffWorktreeAll(basePath: string, name: string): WorktreeDiffSummary {
|
|
759
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
760
|
+
|
|
732
761
|
const branch = worktreeBranchName(name);
|
|
733
762
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
734
763
|
|
|
@@ -742,6 +771,8 @@ export function diffWorktreeAll(basePath: string, name: string): WorktreeDiffSum
|
|
|
742
771
|
* Uses direct diff (not merge-base) so the preview matches the actual merge outcome.
|
|
743
772
|
*/
|
|
744
773
|
export function diffWorktreeNumstat(basePath: string, name: string): FileLineStat[] {
|
|
774
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
775
|
+
|
|
745
776
|
const branch = worktreeBranchName(name);
|
|
746
777
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
747
778
|
|
|
@@ -760,6 +791,8 @@ export function diffWorktreeNumstat(basePath: string, name: string): FileLineSta
|
|
|
760
791
|
* Returns the raw unified diff for LLM consumption.
|
|
761
792
|
*/
|
|
762
793
|
export function getWorktreeGSDDiff(basePath: string, name: string): string {
|
|
794
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
795
|
+
|
|
763
796
|
const branch = worktreeBranchName(name);
|
|
764
797
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
765
798
|
|
|
@@ -771,6 +804,8 @@ export function getWorktreeGSDDiff(basePath: string, name: string): string {
|
|
|
771
804
|
* Returns the raw unified diff for LLM consumption.
|
|
772
805
|
*/
|
|
773
806
|
export function getWorktreeCodeDiff(basePath: string, name: string): string {
|
|
807
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
808
|
+
|
|
774
809
|
const branch = worktreeBranchName(name);
|
|
775
810
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
776
811
|
|
|
@@ -781,6 +816,8 @@ export function getWorktreeCodeDiff(basePath: string, name: string): string {
|
|
|
781
816
|
* Get commit log for the worktree branch since it diverged from main.
|
|
782
817
|
*/
|
|
783
818
|
export function getWorktreeLog(basePath: string, name: string): string {
|
|
819
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
820
|
+
|
|
784
821
|
const branch = worktreeBranchName(name);
|
|
785
822
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
786
823
|
|
|
@@ -795,6 +832,8 @@ export function getWorktreeLog(basePath: string, name: string): string {
|
|
|
795
832
|
* Returns the merge commit message.
|
|
796
833
|
*/
|
|
797
834
|
export function mergeWorktreeToMain(basePath: string, name: string, commitMessage: string): string {
|
|
835
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
836
|
+
|
|
798
837
|
const branch = worktreeBranchName(name);
|
|
799
838
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
800
839
|
const current = nativeGetCurrentBranch(basePath);
|
|
@@ -23,6 +23,7 @@ import { emitJournalEvent } from "./journal.js";
|
|
|
23
23
|
import { emitWorktreeCreated, emitWorktreeMerged } from "./worktree-telemetry.js";
|
|
24
24
|
import { getCollapseCadence, getMilestoneResquash, resquashMilestoneOnMain } from "./slice-cadence.js";
|
|
25
25
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
26
|
+
import { resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
26
27
|
|
|
27
28
|
// ─── Dependency Interface ──────────────────────────────────────────────────
|
|
28
29
|
|
|
@@ -84,31 +85,20 @@ export interface NotifyCtx {
|
|
|
84
85
|
|
|
85
86
|
// ─── Path Helpers ──────────────────────────────────────────────────────────
|
|
86
87
|
|
|
87
|
-
/**
|
|
88
|
-
* Worktree marker segment — present in any path produced by worktreePath().
|
|
89
|
-
* Used to strip the worktree suffix and recover the project root (#3729).
|
|
90
|
-
*/
|
|
91
|
-
const WORKTREE_MARKER = "/.gsd/worktrees/";
|
|
92
|
-
|
|
93
88
|
/**
|
|
94
89
|
* Resolve the project root from session path state.
|
|
95
90
|
*
|
|
96
91
|
* Prefers `originalBasePath` (always the project root when set), but falls
|
|
97
92
|
* back to `basePath` when `originalBasePath` is falsy (e.g. fresh AutoSession
|
|
98
93
|
* with default empty string). If `basePath` itself is inside a worktree
|
|
99
|
-
* directory (
|
|
100
|
-
* actual project root
|
|
94
|
+
* directory (including symlink-resolved ~/.gsd/projects/<hash>/worktrees
|
|
95
|
+
* paths), recover the actual project root to prevent double nesting (#3729).
|
|
101
96
|
*/
|
|
102
97
|
export function resolveProjectRoot(
|
|
103
98
|
originalBasePath: string,
|
|
104
99
|
basePath: string,
|
|
105
100
|
): string {
|
|
106
|
-
|
|
107
|
-
const markerIdx = resolved.indexOf(WORKTREE_MARKER);
|
|
108
|
-
if (markerIdx !== -1) {
|
|
109
|
-
resolved = resolved.slice(0, markerIdx);
|
|
110
|
-
}
|
|
111
|
-
return resolved;
|
|
101
|
+
return resolveWorktreeProjectRoot(basePath, originalBasePath);
|
|
112
102
|
}
|
|
113
103
|
|
|
114
104
|
// ─── WorktreeResolver ──────────────────────────────────────────────────────
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
|
|
5
|
+
export interface WorktreeSegment {
|
|
6
|
+
gsdIdx: number;
|
|
7
|
+
afterWorktrees: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function normalizeWorktreePathForCompare(path: string): string {
|
|
11
|
+
let normalized: string;
|
|
12
|
+
try {
|
|
13
|
+
normalized = realpathSync(path);
|
|
14
|
+
} catch {
|
|
15
|
+
normalized = resolve(path);
|
|
16
|
+
}
|
|
17
|
+
const slashed = normalized.replaceAll("\\", "/");
|
|
18
|
+
const trimmed = slashed.replace(/\/+$/, "");
|
|
19
|
+
return process.platform === "win32" ? (trimmed || "/").toLowerCase() : (trimmed || "/");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Find the GSD worktree segment in both direct project layout and the
|
|
24
|
+
* symlink-resolved external-state layout used by ~/.gsd/projects/<hash>.
|
|
25
|
+
*/
|
|
26
|
+
export function findWorktreeSegment(normalizedPath: string): WorktreeSegment | null {
|
|
27
|
+
const directMarker = "/.gsd/worktrees/";
|
|
28
|
+
const directIdx = normalizedPath.indexOf(directMarker);
|
|
29
|
+
if (directIdx !== -1) {
|
|
30
|
+
return { gsdIdx: directIdx, afterWorktrees: directIdx + directMarker.length };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const externalRe = /\/\.gsd\/projects\/[^/]+\/worktrees\//;
|
|
34
|
+
const externalMatch = normalizedPath.match(externalRe);
|
|
35
|
+
if (externalMatch && externalMatch.index !== undefined) {
|
|
36
|
+
return {
|
|
37
|
+
gsdIdx: externalMatch.index,
|
|
38
|
+
afterWorktrees: externalMatch.index + externalMatch[0].length,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function isGsdWorktreePath(path: string): boolean {
|
|
46
|
+
return findWorktreeSegment(path.replaceAll("\\", "/")) !== null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the canonical project root for worktree operations.
|
|
51
|
+
*
|
|
52
|
+
* `originalBasePath` wins when available because session state already knows the
|
|
53
|
+
* root. `GSD_PROJECT_ROOT` is the next strongest signal for worker processes.
|
|
54
|
+
* Otherwise, derive the root from direct `.gsd/worktrees` paths, or recover it
|
|
55
|
+
* from the worktree `.git` file for symlink-resolved ~/.gsd/project paths.
|
|
56
|
+
*/
|
|
57
|
+
export function resolveWorktreeProjectRoot(
|
|
58
|
+
basePath: string,
|
|
59
|
+
originalBasePath?: string | null,
|
|
60
|
+
): string {
|
|
61
|
+
const preferred =
|
|
62
|
+
originalBasePath?.trim() ||
|
|
63
|
+
process.env.GSD_PROJECT_ROOT?.trim() ||
|
|
64
|
+
basePath;
|
|
65
|
+
|
|
66
|
+
return resolveProjectRootFromPath(preferred);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function resolveProjectRootFromPath(path: string): string {
|
|
70
|
+
const normalizedPath = path.replaceAll("\\", "/");
|
|
71
|
+
const segment = findWorktreeSegment(normalizedPath);
|
|
72
|
+
if (!segment) return resolveGitWorkingTreeRoot(path) ?? path;
|
|
73
|
+
|
|
74
|
+
const sepChar = path.includes("\\") ? "\\" : "/";
|
|
75
|
+
const gsdMarker = `${sepChar}.gsd${sepChar}`;
|
|
76
|
+
const markerIdx = path.indexOf(gsdMarker);
|
|
77
|
+
const candidate = markerIdx !== -1
|
|
78
|
+
? path.slice(0, markerIdx)
|
|
79
|
+
: path.slice(0, segment.gsdIdx);
|
|
80
|
+
|
|
81
|
+
const gsdHome = normalizeWorktreePathForCompare(process.env.GSD_HOME || join(homedir(), ".gsd"));
|
|
82
|
+
const candidateGsdPath = normalizeWorktreePathForCompare(join(candidate, ".gsd"));
|
|
83
|
+
|
|
84
|
+
if (candidateGsdPath === gsdHome || candidateGsdPath.startsWith(`${gsdHome}/`)) {
|
|
85
|
+
const realRoot = resolveProjectRootFromGitFile(path);
|
|
86
|
+
return realRoot ?? path;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return candidate;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function resolveGitWorkingTreeRoot(path: string): string | null {
|
|
93
|
+
try {
|
|
94
|
+
let dir = existsSync(path) && !statSync(path).isDirectory()
|
|
95
|
+
? resolve(path, "..")
|
|
96
|
+
: path;
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < 30; i++) {
|
|
99
|
+
const gitPath = join(dir, ".git");
|
|
100
|
+
if (existsSync(gitPath)) return dir;
|
|
101
|
+
|
|
102
|
+
const parent = resolve(dir, "..");
|
|
103
|
+
if (parent === dir) break;
|
|
104
|
+
dir = parent;
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
// Non-fatal: callers either keep the original path or fail closed.
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function resolveProjectRootFromGitFile(worktreePath: string): string | null {
|
|
113
|
+
try {
|
|
114
|
+
let dir = worktreePath;
|
|
115
|
+
for (let i = 0; i < 30; i++) {
|
|
116
|
+
const gitPath = join(dir, ".git");
|
|
117
|
+
if (existsSync(gitPath)) {
|
|
118
|
+
const content = readFileSync(gitPath, "utf8").trim();
|
|
119
|
+
if (content.startsWith("gitdir: ")) {
|
|
120
|
+
const gitDir = resolve(dir, content.slice(8));
|
|
121
|
+
const dotGitDir = resolve(gitDir, "..", "..");
|
|
122
|
+
if (dotGitDir.endsWith(".git") || dotGitDir.endsWith(".git/") || dotGitDir.endsWith(".git\\")) {
|
|
123
|
+
return resolve(dotGitDir, "..");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const commonDirPath = join(gitDir, "commondir");
|
|
127
|
+
if (existsSync(commonDirPath)) {
|
|
128
|
+
const commonDir = readFileSync(commonDirPath, "utf8").trim();
|
|
129
|
+
const resolvedCommonDir = resolve(gitDir, commonDir);
|
|
130
|
+
return resolve(resolvedCommonDir, "..");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const parent = resolve(dir, "..");
|
|
137
|
+
if (parent === dir) break;
|
|
138
|
+
dir = parent;
|
|
139
|
+
}
|
|
140
|
+
} catch {
|
|
141
|
+
// Non-fatal: callers either keep the original path or fail closed.
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
@@ -12,12 +12,16 @@
|
|
|
12
12
|
* SLICE_BRANCH_RE) remain for backwards compatibility with legacy branches.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { existsSync, readFileSync,
|
|
16
|
-
import { join, resolve
|
|
17
|
-
import { homedir } from "node:os";
|
|
15
|
+
import { existsSync, readFileSync, utimesSync } from "node:fs";
|
|
16
|
+
import { join, resolve } from "node:path";
|
|
18
17
|
|
|
19
18
|
import { GitServiceImpl, writeIntegrationBranch, type TaskCommitContext } from "./git-service.js";
|
|
20
19
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
20
|
+
import {
|
|
21
|
+
findWorktreeSegment,
|
|
22
|
+
resolveWorktreeProjectRoot,
|
|
23
|
+
} from "./worktree-root.js";
|
|
24
|
+
export { resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
21
25
|
|
|
22
26
|
export { MergeConflictError } from "./git-service.js";
|
|
23
27
|
export type { TaskCommitContext } from "./git-service.js";
|
|
@@ -78,29 +82,6 @@ export function captureIntegrationBranch(basePath: string, milestoneId: string):
|
|
|
78
82
|
|
|
79
83
|
// ─── Pure Utility Functions (unchanged) ────────────────────────────────────
|
|
80
84
|
|
|
81
|
-
/**
|
|
82
|
-
* Find the worktrees segment in a path, supporting both direct
|
|
83
|
-
* (`/.gsd/worktrees/`) and symlink-resolved (`/.gsd/projects/<hash>/worktrees/`)
|
|
84
|
-
* layouts. When `.gsd` is a symlink to `~/.gsd/projects/<hash>`, resolved
|
|
85
|
-
* paths contain the intermediate `projects/<hash>/` segment that the old
|
|
86
|
-
* single-marker check missed.
|
|
87
|
-
*/
|
|
88
|
-
function findWorktreeSegment(normalizedPath: string): { gsdIdx: number; afterWorktrees: number } | null {
|
|
89
|
-
// Direct layout: /.gsd/worktrees/<name>
|
|
90
|
-
const directMarker = "/.gsd/worktrees/";
|
|
91
|
-
const idx = normalizedPath.indexOf(directMarker);
|
|
92
|
-
if (idx !== -1) {
|
|
93
|
-
return { gsdIdx: idx, afterWorktrees: idx + directMarker.length };
|
|
94
|
-
}
|
|
95
|
-
// Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/<name>
|
|
96
|
-
const symlinkRe = /\/\.gsd\/projects\/[a-f0-9]+\/worktrees\//;
|
|
97
|
-
const match = normalizedPath.match(symlinkRe);
|
|
98
|
-
if (match && match.index !== undefined) {
|
|
99
|
-
return { gsdIdx: match.index, afterWorktrees: match.index + match[0].length };
|
|
100
|
-
}
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
85
|
/**
|
|
105
86
|
* Detect the active worktree name from the current working directory.
|
|
106
87
|
* Returns null if not inside a GSD worktree (.gsd/worktrees/<name>/).
|
|
@@ -133,99 +114,7 @@ export function detectWorktreeName(basePath: string): string | null {
|
|
|
133
114
|
* operate against the real project root, not a worktree subdirectory.
|
|
134
115
|
*/
|
|
135
116
|
export function resolveProjectRoot(basePath: string): string {
|
|
136
|
-
|
|
137
|
-
if (process.env.GSD_PROJECT_ROOT) {
|
|
138
|
-
return process.env.GSD_PROJECT_ROOT;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const normalizedPath = basePath.replaceAll("\\", "/");
|
|
142
|
-
const seg = findWorktreeSegment(normalizedPath);
|
|
143
|
-
if (!seg) return basePath;
|
|
144
|
-
|
|
145
|
-
// Candidate root via the string-slice heuristic
|
|
146
|
-
const sepChar = basePath.includes("\\") ? "\\" : "/";
|
|
147
|
-
const gsdMarker = `${sepChar}.gsd${sepChar}`;
|
|
148
|
-
const gsdIdx = basePath.indexOf(gsdMarker);
|
|
149
|
-
const candidate = gsdIdx !== -1
|
|
150
|
-
? basePath.slice(0, gsdIdx)
|
|
151
|
-
: basePath.slice(0, seg.gsdIdx);
|
|
152
|
-
|
|
153
|
-
// Layer 2: Guard against resolving to the user's home directory.
|
|
154
|
-
// When .gsd is a symlink into ~/.gsd/projects/<hash>, the resolved path
|
|
155
|
-
// contains /.gsd/ at the user-level boundary. Slicing there yields ~ — wrong.
|
|
156
|
-
const gsdHome = normalizePathForCompare(process.env.GSD_HOME || join(homedir(), ".gsd"));
|
|
157
|
-
const candidateGsdPath = normalizePathForCompare(join(candidate, ".gsd"));
|
|
158
|
-
|
|
159
|
-
if (candidateGsdPath === gsdHome || candidateGsdPath.startsWith(gsdHome + "/")) {
|
|
160
|
-
// The candidate is the home directory (or within it in a way that .gsd
|
|
161
|
-
// maps to the user-level GSD dir). Try to recover the real project root
|
|
162
|
-
// from the worktree's .git file.
|
|
163
|
-
const realRoot = resolveProjectRootFromGitFile(basePath);
|
|
164
|
-
if (realRoot) return realRoot;
|
|
165
|
-
// If git file resolution failed, return basePath unchanged rather than ~
|
|
166
|
-
return basePath;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return candidate;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Recover the real project root from a worktree's .git file.
|
|
174
|
-
*
|
|
175
|
-
* Each git worktree has a `.git` file (not directory) containing:
|
|
176
|
-
* gitdir: /real/project/.git/worktrees/<name>
|
|
177
|
-
*
|
|
178
|
-
* Walking up from that gitdir gives us `/real/project/.git`, and its
|
|
179
|
-
* parent is the real project root.
|
|
180
|
-
*/
|
|
181
|
-
function resolveProjectRootFromGitFile(worktreePath: string): string | null {
|
|
182
|
-
try {
|
|
183
|
-
// Walk up from the worktree path to find the .git file
|
|
184
|
-
let dir = worktreePath;
|
|
185
|
-
for (let i = 0; i < 30; i++) {
|
|
186
|
-
const gitPath = join(dir, ".git");
|
|
187
|
-
if (existsSync(gitPath)) {
|
|
188
|
-
const content = readFileSync(gitPath, "utf8").trim();
|
|
189
|
-
if (content.startsWith("gitdir: ")) {
|
|
190
|
-
// gitdir points to: <real-project>/.git/worktrees/<name>
|
|
191
|
-
const gitDir = resolve(dir, content.slice(8));
|
|
192
|
-
// Walk up: .git/worktrees/<name> → .git/worktrees → .git → project root
|
|
193
|
-
const dotGitDir = resolve(gitDir, "..", "..");
|
|
194
|
-
// Verify this looks like a .git directory
|
|
195
|
-
if (dotGitDir.endsWith(".git") || dotGitDir.endsWith(".git/") || dotGitDir.endsWith(".git\\")) {
|
|
196
|
-
return resolve(dotGitDir, "..");
|
|
197
|
-
}
|
|
198
|
-
// Alternative: the commondir file inside the worktree gitdir
|
|
199
|
-
// points to the main .git directory
|
|
200
|
-
const commonDirPath = join(gitDir, "commondir");
|
|
201
|
-
if (existsSync(commonDirPath)) {
|
|
202
|
-
const commonDir = readFileSync(commonDirPath, "utf8").trim();
|
|
203
|
-
const resolvedCommonDir = resolve(gitDir, commonDir);
|
|
204
|
-
return resolve(resolvedCommonDir, "..");
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
const parent = resolve(dir, "..");
|
|
210
|
-
if (parent === dir) break;
|
|
211
|
-
dir = parent;
|
|
212
|
-
}
|
|
213
|
-
} catch {
|
|
214
|
-
// Non-fatal — caller will use fallback
|
|
215
|
-
}
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function normalizePathForCompare(path: string): string {
|
|
220
|
-
let normalized: string;
|
|
221
|
-
try {
|
|
222
|
-
normalized = realpathSync(path);
|
|
223
|
-
} catch {
|
|
224
|
-
normalized = resolve(path);
|
|
225
|
-
}
|
|
226
|
-
const slashed = normalized.replaceAll("\\", "/");
|
|
227
|
-
const trimmed = slashed.replace(/\/+$/, "");
|
|
228
|
-
return trimmed || "/";
|
|
117
|
+
return resolveWorktreeProjectRoot(basePath);
|
|
229
118
|
}
|
|
230
119
|
|
|
231
120
|
/**
|
|
@@ -119,17 +119,31 @@ export default function ollama(pi: ExtensionAPI) {
|
|
|
119
119
|
// In headless/auto mode, await the probe so the fallback resolver can
|
|
120
120
|
// see Ollama before the first LLM call (#3531 race condition).
|
|
121
121
|
// In interactive mode, keep it async for fast startup.
|
|
122
|
+
// Surface probe failures under GSD_DEBUG so users can diagnose silent
|
|
123
|
+
// "Ollama is missing from /model" reports without patching dist/. The
|
|
124
|
+
// probe still soft-fails (registration is best-effort) — we just stop
|
|
125
|
+
// dropping the error on the floor. See #4982.
|
|
126
|
+
const debugOllama = (where: string, error: unknown): void => {
|
|
127
|
+
if (process.env.GSD_DEBUG) {
|
|
128
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
129
|
+
process.stderr.write(`[ollama] ${where} probe failed: ${msg}\n`);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
122
133
|
if (!ctx.hasUI) {
|
|
123
134
|
try {
|
|
124
135
|
await probeAndRegister(pi);
|
|
125
|
-
} catch {
|
|
136
|
+
} catch (error) {
|
|
137
|
+
debugOllama("headless", error);
|
|
138
|
+
}
|
|
126
139
|
} else {
|
|
127
140
|
probeAndRegister(pi)
|
|
128
141
|
.then((found) => {
|
|
129
142
|
ctx.ui.setStatus("ollama", found ? "Ollama" : undefined);
|
|
130
143
|
})
|
|
131
|
-
.catch(() => {
|
|
144
|
+
.catch((error) => {
|
|
132
145
|
ctx.ui.setStatus("ollama", undefined);
|
|
146
|
+
debugOllama("interactive", error);
|
|
133
147
|
});
|
|
134
148
|
}
|
|
135
149
|
});
|
|
@@ -56,10 +56,44 @@ const KNOWN_MODELS: Array<[pattern: string, caps: ModelCapability]> = [
|
|
|
56
56
|
["llama2", { contextWindow: 4096, maxTokens: 4096, ollamaOptions: { num_ctx: 4096 } }],
|
|
57
57
|
|
|
58
58
|
// ─── Qwen family ────────────────────────────────────────────────────
|
|
59
|
+
// Long-variant entries MUST appear before the bare `qwen3` base —
|
|
60
|
+
// `baseName.startsWith(pattern)` returns true for `qwen3.5`/`qwen3-coder`/
|
|
61
|
+
// `qwen3-next` against `qwen3`, and the first match wins (#4991).
|
|
62
|
+
// ref: qwen3-next 1M ctx — https://qwen.ai/blog?id=qwen3-next
|
|
63
|
+
["qwen3-next", { contextWindow: 1048576, maxTokens: 32768, ollamaOptions: { num_ctx: 1048576 } }],
|
|
64
|
+
// ref: qwen3-coder 256K ctx — https://qwenlm.github.io/blog/qwen3-coder/
|
|
65
|
+
["qwen3-coder", { contextWindow: 262144, maxTokens: 32768, ollamaOptions: { num_ctx: 262144 } }],
|
|
66
|
+
// ref: qwen3.5 / qwen3.6 1M ctx — Ollama Cloud release notes
|
|
67
|
+
["qwen3.6", { contextWindow: 1048576, maxTokens: 32768, ollamaOptions: { num_ctx: 1048576 } }],
|
|
68
|
+
["qwen3.5", { contextWindow: 1048576, maxTokens: 32768, ollamaOptions: { num_ctx: 1048576 } }],
|
|
59
69
|
["qwen3", { contextWindow: 131072, maxTokens: 32768, ollamaOptions: { num_ctx: 131072 } }],
|
|
60
70
|
["qwen2.5", { contextWindow: 131072, maxTokens: 32768, ollamaOptions: { num_ctx: 131072 } }],
|
|
61
71
|
["qwen2", { contextWindow: 131072, maxTokens: 32768, ollamaOptions: { num_ctx: 131072 } }],
|
|
62
72
|
|
|
73
|
+
// ─── GLM family (Z.ai, Ollama Cloud) ────────────────────────────────
|
|
74
|
+
// ref: glm 4.6 / 5.x 200K ctx — https://docs.z.ai/devpack/using5.1
|
|
75
|
+
// Long-variant entries before bare `glm-5` / `glm-4` would-be bases to
|
|
76
|
+
// avoid prefix shadowing (#4991).
|
|
77
|
+
["glm-5.1", { contextWindow: 204800, maxTokens: 16384, ollamaOptions: { num_ctx: 204800 } }],
|
|
78
|
+
["glm-5", { contextWindow: 204800, maxTokens: 16384, ollamaOptions: { num_ctx: 204800 } }],
|
|
79
|
+
["glm-4.6", { contextWindow: 204800, maxTokens: 16384, ollamaOptions: { num_ctx: 204800 } }],
|
|
80
|
+
["glm-4", { contextWindow: 131072, maxTokens: 16384, ollamaOptions: { num_ctx: 131072 } }],
|
|
81
|
+
|
|
82
|
+
// ─── Kimi K2 (Moonshot, Ollama Cloud) ──────────────────────────────
|
|
83
|
+
// ref: kimi-k2 256K ctx — https://platform.moonshot.ai/docs
|
|
84
|
+
// Same shadowing concern: kimi-k2-thinking and kimi-k2.{5,6} must
|
|
85
|
+
// match before any future bare `kimi-k2` entry (#4991).
|
|
86
|
+
["kimi-k2-thinking", { contextWindow: 262144, maxTokens: 16384, ollamaOptions: { num_ctx: 262144 } }],
|
|
87
|
+
["kimi-k2.6", { contextWindow: 262144, maxTokens: 16384, ollamaOptions: { num_ctx: 262144 } }],
|
|
88
|
+
["kimi-k2.5", { contextWindow: 262144, maxTokens: 16384, ollamaOptions: { num_ctx: 262144 } }],
|
|
89
|
+
["kimi-k2", { contextWindow: 262144, maxTokens: 16384, ollamaOptions: { num_ctx: 262144 } }],
|
|
90
|
+
|
|
91
|
+
// ─── MiniMax M2 (Ollama Cloud) ─────────────────────────────────────
|
|
92
|
+
// ref: minimax-m2 1M ctx — https://www.minimax.io/news/minimax-m2
|
|
93
|
+
["minimax-m2.7", { contextWindow: 1048576, maxTokens: 16384, ollamaOptions: { num_ctx: 1048576 } }],
|
|
94
|
+
["minimax-m2.5", { contextWindow: 1048576, maxTokens: 16384, ollamaOptions: { num_ctx: 1048576 } }],
|
|
95
|
+
["minimax-m2", { contextWindow: 1048576, maxTokens: 16384, ollamaOptions: { num_ctx: 1048576 } }],
|
|
96
|
+
|
|
63
97
|
// ─── Gemma family ───────────────────────────────────────────────────
|
|
64
98
|
["gemma3", { contextWindow: 131072, maxTokens: 16384, ollamaOptions: { num_ctx: 131072 } }],
|
|
65
99
|
["gemma2", { contextWindow: 8192, maxTokens: 8192, ollamaOptions: { num_ctx: 8192 } }],
|