@oh-my-pi/pi-coding-agent 12.9.0 → 12.10.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/CHANGELOG.md +40 -0
- package/package.json +7 -7
- package/src/capability/rule.ts +173 -5
- package/src/cli/args.ts +3 -0
- package/src/cli/update-cli.ts +1 -66
- package/src/commands/launch.ts +3 -0
- package/src/config/model-registry.ts +300 -21
- package/src/config/model-resolver.ts +4 -4
- package/src/config/settings-schema.ts +12 -0
- package/src/discovery/agents.ts +175 -12
- package/src/discovery/builtin.ts +3 -13
- package/src/discovery/cline.ts +4 -45
- package/src/discovery/cursor.ts +2 -29
- package/src/discovery/helpers.ts +38 -0
- package/src/discovery/windsurf.ts +5 -44
- package/src/export/ttsr.ts +324 -54
- package/src/internal-urls/index.ts +4 -2
- package/src/internal-urls/memory-protocol.ts +133 -0
- package/src/internal-urls/router.ts +4 -2
- package/src/internal-urls/skill-protocol.ts +1 -1
- package/src/internal-urls/types.ts +6 -2
- package/src/main.ts +5 -0
- package/src/memories/index.ts +6 -13
- package/src/modes/components/settings-defs.ts +6 -0
- package/src/modes/rpc/rpc-client.ts +16 -0
- package/src/prompts/memories/consolidation.md +1 -1
- package/src/prompts/memories/read_path.md +4 -4
- package/src/prompts/memories/stage_one_input.md +1 -2
- package/src/prompts/tools/bash.md +10 -23
- package/src/prompts/tools/read.md +2 -0
- package/src/sdk.ts +23 -6
- package/src/session/agent-session.ts +252 -44
- package/src/tools/bash-skill-urls.ts +177 -0
- package/src/tools/bash.ts +7 -1
- package/src/tools/read.ts +2 -2
package/src/discovery/cline.ts
CHANGED
|
@@ -10,8 +10,7 @@ import { readDirEntries, readFile } from "../capability/fs";
|
|
|
10
10
|
import type { Rule } from "../capability/rule";
|
|
11
11
|
import { ruleCapability } from "../capability/rule";
|
|
12
12
|
import type { LoadContext, LoadResult } from "../capability/types";
|
|
13
|
-
import {
|
|
14
|
-
import { createSourceMeta, loadFilesFromDir } from "./helpers";
|
|
13
|
+
import { buildRuleFromMarkdown, createSourceMeta, loadFilesFromDir } from "./helpers";
|
|
15
14
|
|
|
16
15
|
const PROVIDER_ID = "cline";
|
|
17
16
|
const DISPLAY_NAME = "Cline";
|
|
@@ -53,29 +52,8 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
53
52
|
// Directory format: load all *.md files
|
|
54
53
|
const result = await loadFilesFromDir(ctx, found.path, PROVIDER_ID, "project", {
|
|
55
54
|
extensions: ["md"],
|
|
56
|
-
transform: (name, content, path, source) =>
|
|
57
|
-
|
|
58
|
-
const ruleName = name.replace(/\.md$/, "");
|
|
59
|
-
|
|
60
|
-
// Parse globs (can be array or single string)
|
|
61
|
-
let globs: string[] | undefined;
|
|
62
|
-
if (Array.isArray(frontmatter.globs)) {
|
|
63
|
-
globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
|
|
64
|
-
} else if (typeof frontmatter.globs === "string") {
|
|
65
|
-
globs = [frontmatter.globs];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
name: ruleName,
|
|
70
|
-
path,
|
|
71
|
-
content: body,
|
|
72
|
-
globs,
|
|
73
|
-
alwaysApply: typeof frontmatter.alwaysApply === "boolean" ? frontmatter.alwaysApply : undefined,
|
|
74
|
-
description: typeof frontmatter.description === "string" ? frontmatter.description : undefined,
|
|
75
|
-
ttsrTrigger: typeof frontmatter.ttsr_trigger === "string" ? frontmatter.ttsr_trigger : undefined,
|
|
76
|
-
_source: source,
|
|
77
|
-
};
|
|
78
|
-
},
|
|
55
|
+
transform: (name, content, path, source) =>
|
|
56
|
+
buildRuleFromMarkdown(name, content, path, source, { stripNamePattern: /\.md$/ }),
|
|
79
57
|
});
|
|
80
58
|
|
|
81
59
|
items.push(...result.items);
|
|
@@ -88,27 +66,8 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
88
66
|
return { items, warnings };
|
|
89
67
|
}
|
|
90
68
|
|
|
91
|
-
const { frontmatter, body } = parseFrontmatter(content, { source: found.path });
|
|
92
69
|
const source = createSourceMeta(PROVIDER_ID, found.path, "project");
|
|
93
|
-
|
|
94
|
-
// Parse globs (can be array or single string)
|
|
95
|
-
let globs: string[] | undefined;
|
|
96
|
-
if (Array.isArray(frontmatter.globs)) {
|
|
97
|
-
globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
|
|
98
|
-
} else if (typeof frontmatter.globs === "string") {
|
|
99
|
-
globs = [frontmatter.globs];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
items.push({
|
|
103
|
-
name: "clinerules",
|
|
104
|
-
path: found.path,
|
|
105
|
-
content: body,
|
|
106
|
-
globs,
|
|
107
|
-
alwaysApply: typeof frontmatter.alwaysApply === "boolean" ? frontmatter.alwaysApply : undefined,
|
|
108
|
-
description: typeof frontmatter.description === "string" ? frontmatter.description : undefined,
|
|
109
|
-
ttsrTrigger: typeof frontmatter.ttsr_trigger === "string" ? frontmatter.ttsr_trigger : undefined,
|
|
110
|
-
_source: source,
|
|
111
|
-
});
|
|
70
|
+
items.push(buildRuleFromMarkdown("clinerules.md", content, found.path, source, { ruleName: "clinerules" }));
|
|
112
71
|
}
|
|
113
72
|
|
|
114
73
|
return { items, warnings };
|
package/src/discovery/cursor.ts
CHANGED
|
@@ -21,8 +21,8 @@ import { ruleCapability } from "../capability/rule";
|
|
|
21
21
|
import type { Settings } from "../capability/settings";
|
|
22
22
|
import { settingsCapability } from "../capability/settings";
|
|
23
23
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
24
|
-
import { parseFrontmatter } from "../utils/frontmatter";
|
|
25
24
|
import {
|
|
25
|
+
buildRuleFromMarkdown,
|
|
26
26
|
createSourceMeta,
|
|
27
27
|
expandEnvVarsDeep,
|
|
28
28
|
getProjectPath,
|
|
@@ -137,34 +137,7 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
function transformMDCRule(name: string, content: string, path: string, source: SourceMeta): Rule {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// Extract frontmatter fields
|
|
143
|
-
const description = typeof frontmatter.description === "string" ? frontmatter.description : undefined;
|
|
144
|
-
const alwaysApply = frontmatter.alwaysApply === true;
|
|
145
|
-
const ttsrTrigger = typeof frontmatter.ttsr_trigger === "string" ? frontmatter.ttsr_trigger : undefined;
|
|
146
|
-
|
|
147
|
-
// Parse globs (can be array or single string)
|
|
148
|
-
let globs: string[] | undefined;
|
|
149
|
-
if (Array.isArray(frontmatter.globs)) {
|
|
150
|
-
globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
|
|
151
|
-
} else if (typeof frontmatter.globs === "string") {
|
|
152
|
-
globs = [frontmatter.globs];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Derive name from filename (strip extension)
|
|
156
|
-
const ruleName = name.replace(/\.(mdc|md)$/, "");
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
name: ruleName,
|
|
160
|
-
path,
|
|
161
|
-
content: body,
|
|
162
|
-
description,
|
|
163
|
-
alwaysApply,
|
|
164
|
-
globs,
|
|
165
|
-
ttsrTrigger,
|
|
166
|
-
_source: source,
|
|
167
|
-
};
|
|
140
|
+
return buildRuleFromMarkdown(name, content, path, source, { stripNamePattern: /\.(mdc|md)$/ });
|
|
168
141
|
}
|
|
169
142
|
|
|
170
143
|
// =============================================================================
|
package/src/discovery/helpers.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
|
7
7
|
import { FileType, glob } from "@oh-my-pi/pi-natives";
|
|
8
8
|
import { CONFIG_DIR_NAME } from "@oh-my-pi/pi-utils/dirs";
|
|
9
9
|
import { readFile } from "../capability/fs";
|
|
10
|
+
import { parseRuleConditionAndScope, type Rule, type RuleFrontmatter } from "../capability/rule";
|
|
10
11
|
import type { Skill, SkillFrontmatter } from "../capability/skill";
|
|
11
12
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
12
13
|
import { parseFrontmatter } from "../utils/frontmatter";
|
|
@@ -163,6 +164,43 @@ export function parseArrayOrCSV(value: unknown): string[] | undefined {
|
|
|
163
164
|
return undefined;
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Build a canonical rule item from a markdown/markdown-frontmatter document.
|
|
169
|
+
*/
|
|
170
|
+
export function buildRuleFromMarkdown(
|
|
171
|
+
name: string,
|
|
172
|
+
content: string,
|
|
173
|
+
filePath: string,
|
|
174
|
+
source: SourceMeta,
|
|
175
|
+
options?: {
|
|
176
|
+
ruleName?: string;
|
|
177
|
+
stripNamePattern?: RegExp;
|
|
178
|
+
},
|
|
179
|
+
): Rule {
|
|
180
|
+
const { frontmatter, body } = parseFrontmatter(content, { source: filePath });
|
|
181
|
+
const { condition, scope } = parseRuleConditionAndScope(frontmatter as RuleFrontmatter);
|
|
182
|
+
|
|
183
|
+
let globs: string[] | undefined;
|
|
184
|
+
if (Array.isArray(frontmatter.globs)) {
|
|
185
|
+
globs = frontmatter.globs.filter((item): item is string => typeof item === "string");
|
|
186
|
+
} else if (typeof frontmatter.globs === "string") {
|
|
187
|
+
globs = [frontmatter.globs];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const resolvedName = options?.ruleName ?? name.replace(options?.stripNamePattern ?? /\.(md|mdc)$/, "");
|
|
191
|
+
return {
|
|
192
|
+
name: resolvedName,
|
|
193
|
+
path: filePath,
|
|
194
|
+
content: body,
|
|
195
|
+
globs,
|
|
196
|
+
alwaysApply: frontmatter.alwaysApply === true,
|
|
197
|
+
description: typeof frontmatter.description === "string" ? frontmatter.description : undefined,
|
|
198
|
+
condition,
|
|
199
|
+
scope,
|
|
200
|
+
_source: source,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
166
204
|
/**
|
|
167
205
|
* Parse model field into a prioritized list.
|
|
168
206
|
*/
|
|
@@ -15,8 +15,8 @@ import { readFile } from "../capability/fs";
|
|
|
15
15
|
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
16
16
|
import { type Rule, ruleCapability } from "../capability/rule";
|
|
17
17
|
import type { LoadContext, LoadResult } from "../capability/types";
|
|
18
|
-
import { parseFrontmatter } from "../utils/frontmatter";
|
|
19
18
|
import {
|
|
19
|
+
buildRuleFromMarkdown,
|
|
20
20
|
createSourceMeta,
|
|
21
21
|
expandEnvVarsDeep,
|
|
22
22
|
getProjectPath,
|
|
@@ -104,26 +104,8 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
104
104
|
if (userPath) {
|
|
105
105
|
const content = await readFile(userPath);
|
|
106
106
|
if (content) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
// Validate and normalize globs
|
|
110
|
-
let globs: string[] | undefined;
|
|
111
|
-
if (Array.isArray(frontmatter.globs)) {
|
|
112
|
-
globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
|
|
113
|
-
} else if (typeof frontmatter.globs === "string") {
|
|
114
|
-
globs = [frontmatter.globs];
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
items.push({
|
|
118
|
-
name: "global_rules",
|
|
119
|
-
path: userPath,
|
|
120
|
-
content: body,
|
|
121
|
-
globs,
|
|
122
|
-
alwaysApply: frontmatter.alwaysApply as boolean | undefined,
|
|
123
|
-
description: frontmatter.description as string | undefined,
|
|
124
|
-
ttsrTrigger: typeof frontmatter.ttsr_trigger === "string" ? frontmatter.ttsr_trigger : undefined,
|
|
125
|
-
_source: createSourceMeta(PROVIDER_ID, userPath, "user"),
|
|
126
|
-
});
|
|
107
|
+
const source = createSourceMeta(PROVIDER_ID, userPath, "user");
|
|
108
|
+
items.push(buildRuleFromMarkdown("global_rules.md", content, userPath, source, { ruleName: "global_rules" }));
|
|
127
109
|
}
|
|
128
110
|
}
|
|
129
111
|
|
|
@@ -132,29 +114,8 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
132
114
|
if (projectRulesDir) {
|
|
133
115
|
const result = await loadFilesFromDir<Rule>(ctx, projectRulesDir, PROVIDER_ID, "project", {
|
|
134
116
|
extensions: ["md"],
|
|
135
|
-
transform: (name, content, path, source) =>
|
|
136
|
-
|
|
137
|
-
const ruleName = name.replace(/\.md$/, "");
|
|
138
|
-
|
|
139
|
-
// Validate and normalize globs
|
|
140
|
-
let globs: string[] | undefined;
|
|
141
|
-
if (Array.isArray(frontmatter.globs)) {
|
|
142
|
-
globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
|
|
143
|
-
} else if (typeof frontmatter.globs === "string") {
|
|
144
|
-
globs = [frontmatter.globs];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
name: ruleName,
|
|
149
|
-
path,
|
|
150
|
-
content: body,
|
|
151
|
-
globs,
|
|
152
|
-
alwaysApply: frontmatter.alwaysApply as boolean | undefined,
|
|
153
|
-
description: frontmatter.description as string | undefined,
|
|
154
|
-
ttsrTrigger: typeof frontmatter.ttsr_trigger === "string" ? frontmatter.ttsr_trigger : undefined,
|
|
155
|
-
_source: source,
|
|
156
|
-
};
|
|
157
|
-
},
|
|
117
|
+
transform: (name, content, path, source) =>
|
|
118
|
+
buildRuleFromMarkdown(name, content, path, source, { stripNamePattern: /\.md$/ }),
|
|
158
119
|
});
|
|
159
120
|
items.push(...result.items);
|
|
160
121
|
if (result.warnings) warnings.push(...result.warnings);
|