pi-monofold 0.8.0 → 0.9.0
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 +3 -2
- package/focus-preset.ts +19 -0
- package/index.ts +36 -1
- package/package.json +66 -65
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ pi -e npm:pi-monofold
|
|
|
86
86
|
1. Install the extension (see [Install](#install)).
|
|
87
87
|
2. In your control repository, create `.pi/monofold.yaml` with at least one workspace entry (or run `/monofold:init`).
|
|
88
88
|
3. Start Pi in the control repository and run `/monofold:explore show the project workspaces`.
|
|
89
|
-
4. Use `/monofold:focus
|
|
89
|
+
4. Use `/monofold:focus`, `ctrl+shift+m`, or `shift+ctrl+f` to switch focus presets when `focusPresets` are configured.
|
|
90
90
|
5. Use `/monofold:write` for routed Markdown outputs and `/monofold:git` for guarded git workflows.
|
|
91
91
|
|
|
92
92
|
Example command flows: [docs/examples.md](./docs/examples.md).
|
|
@@ -100,11 +100,12 @@ Example command flows: [docs/examples.md](./docs/examples.md).
|
|
|
100
100
|
| `/monofold:config` | Add or change workspaces and project workspaces |
|
|
101
101
|
| `/monofold:git` | Run guarded git status, commit, push, or commit+push |
|
|
102
102
|
| `/monofold:focus` | Select the active focus preset from a TUI list |
|
|
103
|
+
| `/monofold:focus-prev` | Cycle Active Focus backward through `focusPresets` YAML order |
|
|
103
104
|
| `/monofold:guide` | Interactive guide for common flows |
|
|
104
105
|
| `/monofold:init` | Create or update `.pi/monofold.yaml` |
|
|
105
106
|
| `/monofold:update` | Migrate legacy config and optionally request config edits |
|
|
106
107
|
|
|
107
|
-
Default focus
|
|
108
|
+
Default focus shortcuts: `ctrl+shift+m` cycles Active Focus forward and `shift+ctrl+f` cycles backward through `focusPresets` YAML order. Both wrap at the start/end of the list.
|
|
108
109
|
|
|
109
110
|
When Active Focus is set, Pi Monofold injects the active preset's `contextFiles` into each agent turn under **Focus Context Injection** and recomposes the manifest so active Workspace Targets are shown first while non-active targets are collapsed to one-line summaries. Tag-based target inference in `monofold_read`, `monofold_write`, and `monofold_git` also prefers Workspace Targets that belong to the active preset when a tag query would otherwise match multiple candidates; explicit `targetId` / workspace name selectors and uniquely matching targets are unchanged. If multiple in-focus targets still tie, the existing workspace selection flow applies. The MVP uses provisional context-injection caps that are intentionally temporary and exposed as constants for future tuning:
|
|
110
111
|
|
package/focus-preset.ts
CHANGED
|
@@ -186,6 +186,25 @@ export function cycleActiveFocusPresetForward(focusPresets: FocusPreset[] | unde
|
|
|
186
186
|
return { preset, index: nextIndex, total: presets.length, changed };
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
/** Cycles the active focus preset backward in YAML order. */
|
|
190
|
+
export function cycleActiveFocusPresetBackward(focusPresets: FocusPreset[] | undefined): FocusCycleResult | null {
|
|
191
|
+
const presets = focusPresets ?? [];
|
|
192
|
+
if (presets.length === 0) {
|
|
193
|
+
clearActiveFocusPresetId();
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
ensureActiveFocusInitialized(presets);
|
|
198
|
+
const currentId = getActiveFocusPresetId();
|
|
199
|
+
const currentIndex = currentId ? presets.findIndex((preset) => preset.id === currentId) : -1;
|
|
200
|
+
const nextIndex =
|
|
201
|
+
currentIndex < 0 ? presets.length - 1 : (currentIndex - 1 + presets.length) % presets.length;
|
|
202
|
+
const preset = presets[nextIndex]!;
|
|
203
|
+
const changed = presets.length > 1 && preset.id !== currentId;
|
|
204
|
+
setActiveFocusPresetId(preset.id, presets);
|
|
205
|
+
return { preset, index: nextIndex, total: presets.length, changed };
|
|
206
|
+
}
|
|
207
|
+
|
|
189
208
|
/** Clears the active focus preset for the current process/session. */
|
|
190
209
|
export function clearActiveFocusPresetId(): void {
|
|
191
210
|
activeFocusPresetId = null;
|
package/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import YAML from "yaml";
|
|
7
7
|
import {
|
|
8
8
|
type ActiveFocusPresetPosition,
|
|
9
|
+
cycleActiveFocusPresetBackward,
|
|
9
10
|
cycleActiveFocusPresetForward,
|
|
10
11
|
type FocusPreset,
|
|
11
12
|
ensureActiveFocusInitialized,
|
|
@@ -181,6 +182,8 @@ const ROUTE_KEYS = new Set(["path", "filenameTemplate", "metadata"]);
|
|
|
181
182
|
const FOCUS_STATUS_ID = "monofold-focus";
|
|
182
183
|
const FOCUS_CYCLE_SHORTCUT = "ctrl+shift+m";
|
|
183
184
|
const FOCUS_CYCLE_ACTION_ID = "app.monofold.focus.cycleForward";
|
|
185
|
+
const FOCUS_CYCLE_BACKWARD_SHORTCUT = "shift+ctrl+f";
|
|
186
|
+
const FOCUS_CYCLE_BACKWARD_ACTION_ID = "app.monofold.focus.cycleBackward";
|
|
184
187
|
export const FOCUS_CONTEXT_MAX_FILES = 6;
|
|
185
188
|
export const FOCUS_CONTEXT_MAX_CHARS_PER_FILE = 6_000;
|
|
186
189
|
export const FOCUS_CONTEXT_MAX_TOTAL_CHARS = 12_000;
|
|
@@ -896,7 +899,7 @@ function sendCommandError(pi: ExtensionAPI, command: string, error: unknown, usa
|
|
|
896
899
|
}
|
|
897
900
|
|
|
898
901
|
function formatFocusStatus(position: ActiveFocusPresetPosition): string {
|
|
899
|
-
const base = `focus: ${position.preset.label} (${position.index + 1}/${position.total}) ${FOCUS_CYCLE_SHORTCUT}`;
|
|
902
|
+
const base = `focus: ${position.preset.label} (${position.index + 1}/${position.total}) ${FOCUS_CYCLE_SHORTCUT} / ${FOCUS_CYCLE_BACKWARD_SHORTCUT}`;
|
|
900
903
|
if (position.preset.defaultRouteOverride) {
|
|
901
904
|
return `${base} route:${position.preset.defaultRouteOverride}`;
|
|
902
905
|
}
|
|
@@ -1902,11 +1905,38 @@ ${focusInjection.text}` : ""}
|
|
|
1902
1905
|
}
|
|
1903
1906
|
};
|
|
1904
1907
|
|
|
1908
|
+
const cycleFocusBackward = async (ctx: ExtensionContext) => {
|
|
1909
|
+
try {
|
|
1910
|
+
const loaded = await loadConfig(ctx.cwd);
|
|
1911
|
+
const focusPresets = loaded.raw.focusPresets ?? [];
|
|
1912
|
+
if (focusPresets.length === 0) {
|
|
1913
|
+
notifyNoFocusPresets(ctx);
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
const result = cycleActiveFocusPresetBackward(focusPresets);
|
|
1917
|
+
if (!result) return;
|
|
1918
|
+
updateFocusStatus(ctx, loaded);
|
|
1919
|
+
warnZeroTargetMatchesForPreset(result.preset, loaded.workspaces, (message) => ctx.ui.notify(message, "warning"));
|
|
1920
|
+
if (focusPresets.length === 1) {
|
|
1921
|
+
ctx.ui.notify(`Active Focus unchanged: ${result.preset.label} (1/1)`, "info");
|
|
1922
|
+
return;
|
|
1923
|
+
}
|
|
1924
|
+
ctx.ui.notify(`Active Focus: ${result.preset.label} (${result.index + 1}/${result.total})`, "info");
|
|
1925
|
+
} catch (error) {
|
|
1926
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1927
|
+
ctx.ui.notify(`Monofold focus cycle failed: ${message}`, "error");
|
|
1928
|
+
}
|
|
1929
|
+
};
|
|
1930
|
+
|
|
1905
1931
|
pi.registerCommand("monofold:explore", { description: "Explore configured workspaces via natural-language handoff", handler: intentCommand("Explore") });
|
|
1906
1932
|
pi.registerCommand("monofold:write", { description: "Create routed Markdown via natural-language handoff", handler: intentCommand("Write") });
|
|
1907
1933
|
pi.registerCommand("monofold:config", { description: "Change Workspace configuration via natural-language handoff", handler: intentCommand("Config") });
|
|
1908
1934
|
pi.registerCommand("monofold:git", { description: "Run workspace git workflows via natural-language handoff", handler: intentCommand("Git") });
|
|
1909
1935
|
pi.registerCommand("monofold:focus", { description: "Select the active Monofold focus preset from a TUI list", handler: focusCommand });
|
|
1936
|
+
pi.registerCommand("monofold:focus-prev", {
|
|
1937
|
+
description: "Cycle the active Monofold focus preset backward through focusPresets YAML order",
|
|
1938
|
+
handler: (_args, ctx) => cycleFocusBackward(ctx),
|
|
1939
|
+
});
|
|
1910
1940
|
pi.registerCommand("monofold:guide", { description: "Conversational guide for Pi Monofold workflows", handler: guideCommand });
|
|
1911
1941
|
pi.registerCommand("monofold:update", { description: `Migrate and validate ${CONFIG_RELATIVE_PATH}`, handler: updateCommand });
|
|
1912
1942
|
pi.registerCommand("monofold:clear-unknown-path-allows", {
|
|
@@ -1919,6 +1949,11 @@ ${focusInjection.text}` : ""}
|
|
|
1919
1949
|
handler: cycleFocusForward,
|
|
1920
1950
|
});
|
|
1921
1951
|
|
|
1952
|
+
pi.registerShortcut(FOCUS_CYCLE_BACKWARD_SHORTCUT, {
|
|
1953
|
+
description: `${FOCUS_CYCLE_BACKWARD_ACTION_ID}: cycle active Monofold focus preset backward`,
|
|
1954
|
+
handler: cycleFocusBackward,
|
|
1955
|
+
});
|
|
1956
|
+
|
|
1922
1957
|
|
|
1923
1958
|
pi.registerCommand("monofold:list", { description: "List configured Pi Monofold workspaces (legacy)", handler: listCommand });
|
|
1924
1959
|
|
package/package.json
CHANGED
|
@@ -1,65 +1,66 @@
|
|
|
1
|
-
{
|
|
2
|
-
"scripts": {
|
|
3
|
-
"typecheck": "tsc --noEmit",
|
|
4
|
-
"test": "node --import tsx --test tests/**/*.test.ts",
|
|
5
|
-
"check": "npm run typecheck && npm test && npm pack --dry-run"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"@earendil-works/pi-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"focus-
|
|
29
|
-
"focus-
|
|
30
|
-
"
|
|
31
|
-
"read-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"@earendil-works/pi-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"pi-
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"typecheck": "tsc --noEmit",
|
|
4
|
+
"test": "node --import tsx --test tests/**/*.test.ts",
|
|
5
|
+
"check": "npm run typecheck && npm test && npm pack --dry-run",
|
|
6
|
+
"version:check": "node scripts/check-version-bump.mjs"
|
|
7
|
+
},
|
|
8
|
+
"peerDependencies": {
|
|
9
|
+
"typebox": "*",
|
|
10
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
11
|
+
"@earendil-works/pi-ai": "*"
|
|
12
|
+
},
|
|
13
|
+
"description": "Pi extension that folds multiple repositories and folders into a guarded virtual monorepo for AI agents.",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"version": "0.9.0",
|
|
16
|
+
"pi": {
|
|
17
|
+
"extensions": [
|
|
18
|
+
"./index.ts"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"index.ts",
|
|
25
|
+
"path-normalize.ts",
|
|
26
|
+
"unknown-path-allows.ts",
|
|
27
|
+
"file-read-preview.ts",
|
|
28
|
+
"focus-preset.ts",
|
|
29
|
+
"focus-route-override.ts",
|
|
30
|
+
"focus-skills.ts",
|
|
31
|
+
"monofold-read-ops.ts",
|
|
32
|
+
"read-caps.ts",
|
|
33
|
+
"validation.ts"
|
|
34
|
+
],
|
|
35
|
+
"name": "pi-monofold",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"typescript": "^6.0.3",
|
|
38
|
+
"typebox": "^1.1.38",
|
|
39
|
+
"@types/node": "^25.9.1",
|
|
40
|
+
"tsx": "^4.20.5",
|
|
41
|
+
"@earendil-works/pi-coding-agent": "^0.75.4",
|
|
42
|
+
"@earendil-works/pi-ai": "^0.75.4"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"yaml": "^2.8.1"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"pi-package",
|
|
49
|
+
"pi-extension",
|
|
50
|
+
"ai-coding",
|
|
51
|
+
"virtual-monorepo",
|
|
52
|
+
"multi-repo"
|
|
53
|
+
],
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "git+https://github.com/eiei114/pi-monofold.git"
|
|
57
|
+
},
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://github.com/eiei114/pi-monofold/issues"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://github.com/eiei114/pi-monofold#readme",
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public"
|
|
64
|
+
},
|
|
65
|
+
"license": "MIT"
|
|
66
|
+
}
|