pi-monofold 0.7.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 +24 -1
- package/focus-route-override.ts +44 -0
- package/index.ts +57 -7
- package/package.json +66 -64
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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type MonofoldRouteType, parseDefaultRouteOverride } from "./focus-route-override.js";
|
|
1
2
|
import { parseFocusSkills, resetFocusSkillsWarningState } from "./focus-skills.js";
|
|
2
3
|
import { assertKnownKeys, asStringArray, isRecord, uniqueStrings } from "./validation.js";
|
|
3
4
|
|
|
@@ -10,13 +11,14 @@ export type FocusPreset = {
|
|
|
10
11
|
label: string;
|
|
11
12
|
targets: FocusPresetTarget[];
|
|
12
13
|
focusSkills?: string[];
|
|
14
|
+
defaultRouteOverride?: MonofoldRouteType;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
export type FocusMatchableWorkspace = {
|
|
16
18
|
tags: string[];
|
|
17
19
|
};
|
|
18
20
|
|
|
19
|
-
const FOCUS_PRESET_KEYS = new Set(["id", "label", "targets", "focusSkills"]);
|
|
21
|
+
const FOCUS_PRESET_KEYS = new Set(["id", "label", "targets", "focusSkills", "defaultRouteOverride"]);
|
|
20
22
|
const FOCUS_PRESET_TARGET_KEYS = new Set(["targetTags"]);
|
|
21
23
|
|
|
22
24
|
/** Parses and validates focus preset configuration from YAML/JSON input. */
|
|
@@ -52,6 +54,7 @@ export function parseFocusPresets(value: unknown, label = "focusPresets"): Focus
|
|
|
52
54
|
targets.push({ targetTags });
|
|
53
55
|
}
|
|
54
56
|
const focusSkills = parseFocusSkills(itemLabel, item.focusSkills);
|
|
57
|
+
const defaultRouteOverride = parseDefaultRouteOverride(itemLabel, item.defaultRouteOverride);
|
|
55
58
|
if (seenIds.has(item.id)) throw new Error(`${label} has duplicate preset id: ${item.id}`);
|
|
56
59
|
seenIds.add(item.id);
|
|
57
60
|
presets.push({
|
|
@@ -59,6 +62,7 @@ export function parseFocusPresets(value: unknown, label = "focusPresets"): Focus
|
|
|
59
62
|
label: item.label,
|
|
60
63
|
targets,
|
|
61
64
|
...(focusSkills !== undefined ? { focusSkills } : {}),
|
|
65
|
+
...(defaultRouteOverride !== undefined ? { defaultRouteOverride } : {}),
|
|
62
66
|
});
|
|
63
67
|
}
|
|
64
68
|
return presets;
|
|
@@ -182,6 +186,25 @@ export function cycleActiveFocusPresetForward(focusPresets: FocusPreset[] | unde
|
|
|
182
186
|
return { preset, index: nextIndex, total: presets.length, changed };
|
|
183
187
|
}
|
|
184
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
|
+
|
|
185
208
|
/** Clears the active focus preset for the current process/session. */
|
|
186
209
|
export function clearActiveFocusPresetId(): void {
|
|
187
210
|
activeFocusPresetId = null;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Monofold route types available for routed Markdown writes. */
|
|
2
|
+
export const MONOFOLD_ROUTE_TYPES = [
|
|
3
|
+
"default",
|
|
4
|
+
"prd",
|
|
5
|
+
"design",
|
|
6
|
+
"progress",
|
|
7
|
+
"issue",
|
|
8
|
+
"research",
|
|
9
|
+
"decision",
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export type MonofoldRouteType = (typeof MONOFOLD_ROUTE_TYPES)[number];
|
|
13
|
+
|
|
14
|
+
const ROUTE_TYPE_SET = new Set<string>(MONOFOLD_ROUTE_TYPES);
|
|
15
|
+
|
|
16
|
+
/** Validates a route type string and returns the typed value. */
|
|
17
|
+
export function assertMonofoldRouteType(label: string, value: string): MonofoldRouteType {
|
|
18
|
+
if (!ROUTE_TYPE_SET.has(value)) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`${label} must be one of: ${MONOFOLD_ROUTE_TYPES.join(", ")} (got: ${value})`,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
return value as MonofoldRouteType;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Parses an optional defaultRouteOverride from preset config. */
|
|
27
|
+
export function parseDefaultRouteOverride(itemLabel: string, value: unknown): MonofoldRouteType | undefined {
|
|
28
|
+
if (value === undefined) return undefined;
|
|
29
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
30
|
+
throw new Error(`${itemLabel}.defaultRouteOverride must be a non-empty string`);
|
|
31
|
+
}
|
|
32
|
+
return assertMonofoldRouteType(`${itemLabel}.defaultRouteOverride`, value.trim());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Resolves the effective write route: explicit selection wins over Focus default, then "default". */
|
|
36
|
+
export function resolveWriteRouteType(
|
|
37
|
+
explicitRoute: string | undefined,
|
|
38
|
+
defaultRouteOverride: MonofoldRouteType | undefined,
|
|
39
|
+
): MonofoldRouteType {
|
|
40
|
+
if (explicitRoute !== undefined && explicitRoute !== "") {
|
|
41
|
+
return assertMonofoldRouteType("routeType", explicitRoute);
|
|
42
|
+
}
|
|
43
|
+
return defaultRouteOverride ?? "default";
|
|
44
|
+
}
|
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,
|
|
@@ -20,6 +21,10 @@ import {
|
|
|
20
21
|
setActiveFocusPresetId,
|
|
21
22
|
warnZeroTargetMatchesForPreset,
|
|
22
23
|
} from "./focus-preset.js";
|
|
24
|
+
import {
|
|
25
|
+
resolveWriteRouteType,
|
|
26
|
+
type MonofoldRouteType,
|
|
27
|
+
} from "./focus-route-override.js";
|
|
23
28
|
import {
|
|
24
29
|
applyFocusSkillsToSystemPrompt,
|
|
25
30
|
warnMissingFocusSkills,
|
|
@@ -41,7 +46,7 @@ import { assertKnownKeys, asStringArray, isRecord, uniqueStrings } from "./valid
|
|
|
41
46
|
type CapabilityTag = "read" | "writeDocs" | "editCode" | "runCommands" | "git";
|
|
42
47
|
type LegacyCapabilityTag = CapabilityTag | "gitCommit" | "gitPush";
|
|
43
48
|
type IntentCategory = "Explore" | "Write" | "Config" | "Git";
|
|
44
|
-
type RouteType =
|
|
49
|
+
type RouteType = MonofoldRouteType;
|
|
45
50
|
|
|
46
51
|
type RouteConfig = {
|
|
47
52
|
path: string;
|
|
@@ -177,6 +182,8 @@ const ROUTE_KEYS = new Set(["path", "filenameTemplate", "metadata"]);
|
|
|
177
182
|
const FOCUS_STATUS_ID = "monofold-focus";
|
|
178
183
|
const FOCUS_CYCLE_SHORTCUT = "ctrl+shift+m";
|
|
179
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";
|
|
180
187
|
export const FOCUS_CONTEXT_MAX_FILES = 6;
|
|
181
188
|
export const FOCUS_CONTEXT_MAX_CHARS_PER_FILE = 6_000;
|
|
182
189
|
export const FOCUS_CONTEXT_MAX_TOTAL_CHARS = 12_000;
|
|
@@ -892,7 +899,11 @@ function sendCommandError(pi: ExtensionAPI, command: string, error: unknown, usa
|
|
|
892
899
|
}
|
|
893
900
|
|
|
894
901
|
function formatFocusStatus(position: ActiveFocusPresetPosition): string {
|
|
895
|
-
|
|
902
|
+
const base = `focus: ${position.preset.label} (${position.index + 1}/${position.total}) ${FOCUS_CYCLE_SHORTCUT} / ${FOCUS_CYCLE_BACKWARD_SHORTCUT}`;
|
|
903
|
+
if (position.preset.defaultRouteOverride) {
|
|
904
|
+
return `${base} route:${position.preset.defaultRouteOverride}`;
|
|
905
|
+
}
|
|
906
|
+
return base;
|
|
896
907
|
}
|
|
897
908
|
|
|
898
909
|
function updateFocusStatus(ctx: ExtensionContext | ExtensionCommandContext, loaded: LoadedConfig): void {
|
|
@@ -1026,6 +1037,9 @@ async function buildManifest(loaded: LoadedConfig): Promise<string> {
|
|
|
1026
1037
|
const activeTargetIds = new Set(activeWorkspaces.map(({ workspace }) => workspace.targetId));
|
|
1027
1038
|
if (activeWorkspaces.length > 0) {
|
|
1028
1039
|
lines.push(`Active Focus: ${activePreset.label} (${activePreset.id})`);
|
|
1040
|
+
if (activePreset.defaultRouteOverride) {
|
|
1041
|
+
lines.push(`Default write route override: ${activePreset.defaultRouteOverride} (explicit routeType/--route still wins)`);
|
|
1042
|
+
}
|
|
1029
1043
|
for (const { workspace } of activeWorkspaces) {
|
|
1030
1044
|
lines.push(await buildFullWorkspaceManifestEntry(workspace, " (active)"));
|
|
1031
1045
|
}
|
|
@@ -1046,6 +1060,9 @@ async function buildManifest(loaded: LoadedConfig): Promise<string> {
|
|
|
1046
1060
|
async function buildFocusContextInjection(loaded: LoadedConfig, preset: FocusPreset): Promise<FocusContextInjection> {
|
|
1047
1061
|
const activeWorkspaces = getActiveFocusWorkspaces(loaded, preset);
|
|
1048
1062
|
const lines = ["## Focus Context Injection", "", `Active Focus: ${preset.label} (${preset.id})`];
|
|
1063
|
+
if (preset.defaultRouteOverride) {
|
|
1064
|
+
lines.push(`Default write route override: ${preset.defaultRouteOverride} (explicit routeType/--route still wins)`);
|
|
1065
|
+
}
|
|
1049
1066
|
const notices: string[] = [];
|
|
1050
1067
|
const seenFiles = new Set<string>();
|
|
1051
1068
|
let injectedFileCount = 0;
|
|
@@ -1386,7 +1403,7 @@ ${focusInjection.text}` : ""}
|
|
|
1386
1403
|
label: "Workspace Write",
|
|
1387
1404
|
description: "Write a Markdown document to a routed Workspace destination using routeType, title, body, filename, and metadata.",
|
|
1388
1405
|
parameters: Type.Object({
|
|
1389
|
-
routeType: Type.String({ description: "default, prd, design, progress, issue, research, or decision" }),
|
|
1406
|
+
routeType: Type.Optional(Type.String({ description: "default, prd, design, progress, issue, research, or decision; omitted uses active Focus defaultRouteOverride or default" })),
|
|
1390
1407
|
title: Type.String(),
|
|
1391
1408
|
body: Type.String(),
|
|
1392
1409
|
filename: Type.Optional(Type.String()),
|
|
@@ -1397,9 +1414,9 @@ ${focusInjection.text}` : ""}
|
|
|
1397
1414
|
workspaceName: Type.Optional(Type.String()),
|
|
1398
1415
|
}),
|
|
1399
1416
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
1400
|
-
const routeType = params.routeType as RouteType;
|
|
1401
|
-
if (!ROUTE_TYPES.includes(routeType)) throw new Error(`Unknown routeType: ${params.routeType}`);
|
|
1402
1417
|
const loaded = await loadConfig(ctx.cwd);
|
|
1418
|
+
const activePreset = getActiveFocusPreset(loaded);
|
|
1419
|
+
const routeType = resolveWriteRouteType(params.routeType, activePreset?.defaultRouteOverride);
|
|
1403
1420
|
const workspace = await resolveWorkspace(ctx, loaded, {
|
|
1404
1421
|
targetTags: params.targetTags,
|
|
1405
1422
|
targetName: params.targetName,
|
|
@@ -1613,14 +1630,15 @@ ${focusInjection.text}` : ""}
|
|
|
1613
1630
|
const writeCommand = async (args: string, ctx: ExtensionCommandContext) => {
|
|
1614
1631
|
try {
|
|
1615
1632
|
const parsed = parseCommandArgs(args);
|
|
1616
|
-
const routeType = (stringFlag(parsed.flags, "route", "r") ?? parsed.positional[0] ?? "default") as RouteType;
|
|
1617
|
-
if (!ROUTE_TYPES.includes(routeType)) throw new Error(`Unknown routeType: ${routeType}`);
|
|
1618
1633
|
const title = stringFlag(parsed.flags, "title", "t");
|
|
1619
1634
|
const body = stringFlag(parsed.flags, "body", "b");
|
|
1620
1635
|
if (!title) throw new Error("--title is required");
|
|
1621
1636
|
if (!body) throw new Error("--body is required");
|
|
1622
1637
|
|
|
1623
1638
|
const loaded = await loadConfig(ctx.cwd);
|
|
1639
|
+
const activePreset = getActiveFocusPreset(loaded);
|
|
1640
|
+
const explicitRoute = stringFlag(parsed.flags, "route", "r") ?? parsed.positional[0];
|
|
1641
|
+
const routeType = resolveWriteRouteType(explicitRoute, activePreset?.defaultRouteOverride);
|
|
1624
1642
|
const workspace = await resolveWorkspace(ctx, loaded, commandTarget(parsed.flags, ["writeDocs"]));
|
|
1625
1643
|
const route = workspace.normalizedRoutes[routeType] ?? workspace.normalizedRoutes.default;
|
|
1626
1644
|
if (!route) throw new Error(`Workspace has no route for ${routeType} and no default route`);
|
|
@@ -1887,11 +1905,38 @@ ${focusInjection.text}` : ""}
|
|
|
1887
1905
|
}
|
|
1888
1906
|
};
|
|
1889
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
|
+
|
|
1890
1931
|
pi.registerCommand("monofold:explore", { description: "Explore configured workspaces via natural-language handoff", handler: intentCommand("Explore") });
|
|
1891
1932
|
pi.registerCommand("monofold:write", { description: "Create routed Markdown via natural-language handoff", handler: intentCommand("Write") });
|
|
1892
1933
|
pi.registerCommand("monofold:config", { description: "Change Workspace configuration via natural-language handoff", handler: intentCommand("Config") });
|
|
1893
1934
|
pi.registerCommand("monofold:git", { description: "Run workspace git workflows via natural-language handoff", handler: intentCommand("Git") });
|
|
1894
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
|
+
});
|
|
1895
1940
|
pi.registerCommand("monofold:guide", { description: "Conversational guide for Pi Monofold workflows", handler: guideCommand });
|
|
1896
1941
|
pi.registerCommand("monofold:update", { description: `Migrate and validate ${CONFIG_RELATIVE_PATH}`, handler: updateCommand });
|
|
1897
1942
|
pi.registerCommand("monofold:clear-unknown-path-allows", {
|
|
@@ -1904,6 +1949,11 @@ ${focusInjection.text}` : ""}
|
|
|
1904
1949
|
handler: cycleFocusForward,
|
|
1905
1950
|
});
|
|
1906
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
|
+
|
|
1907
1957
|
|
|
1908
1958
|
pi.registerCommand("monofold:list", { description: "List configured Pi Monofold workspaces (legacy)", handler: listCommand });
|
|
1909
1959
|
|
package/package.json
CHANGED
|
@@ -1,64 +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
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"@
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
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
|
+
}
|