takomi 2.1.13 → 2.1.15

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.
Files changed (39) hide show
  1. package/.pi/agents/architect.md +73 -73
  2. package/.pi/agents/coder.md +70 -70
  3. package/.pi/agents/designer.md +72 -72
  4. package/.pi/agents/orchestrator.md +122 -122
  5. package/.pi/agents/reviewer.md +71 -71
  6. package/.pi/extensions/oauth-router/provider.ts +3 -1
  7. package/.pi/extensions/takomi-context-manager/config.ts +48 -48
  8. package/.pi/extensions/takomi-context-manager/context-router.ts +57 -57
  9. package/.pi/extensions/takomi-context-manager/diagnostics-tools.ts +28 -28
  10. package/.pi/extensions/takomi-context-manager/diagnostics.ts +55 -55
  11. package/.pi/extensions/takomi-context-manager/extension-conflicts.ts +56 -56
  12. package/.pi/extensions/takomi-context-manager/index.ts +56 -56
  13. package/.pi/extensions/takomi-context-manager/model-policy-gate.ts +228 -206
  14. package/.pi/extensions/takomi-context-manager/policy-registry.ts +97 -97
  15. package/.pi/extensions/takomi-context-manager/policy-tools.ts +35 -35
  16. package/.pi/extensions/takomi-context-manager/prerequisite-gates.ts +39 -39
  17. package/.pi/extensions/takomi-context-manager/prompt-rewriter.ts +100 -100
  18. package/.pi/extensions/takomi-context-manager/skill-registry.ts +87 -87
  19. package/.pi/extensions/takomi-context-manager/skill-tools.ts +80 -80
  20. package/.pi/extensions/takomi-context-manager/state.ts +68 -68
  21. package/.pi/extensions/takomi-context-manager/types.ts +77 -77
  22. package/.pi/extensions/takomi-runtime/command-text.ts +10 -2
  23. package/.pi/extensions/takomi-runtime/commands.ts +78 -5
  24. package/.pi/extensions/takomi-runtime/routing-policy.ts +187 -145
  25. package/.pi/extensions/takomi-subagents/native-render.ts +41 -41
  26. package/.pi/extensions/takomi-subagents/pi-subagents-internal.ts +35 -32
  27. package/.pi/extensions/takomi-subagents/run-types.ts +25 -25
  28. package/.pi/prompts/build-prompt.md +259 -259
  29. package/.pi/prompts/design-prompt.md +95 -95
  30. package/.pi/prompts/genesis-prompt.md +140 -140
  31. package/.pi/prompts/prime-prompt.md +110 -110
  32. package/.pi/themes/takomi-aurora.json +88 -88
  33. package/README.md +2 -4
  34. package/assets/.agent/skills/21st-dev-components/SKILL.md +244 -244
  35. package/assets/.agent/skills/anti-gravity/SKILL.md +112 -0
  36. package/assets/.agent/skills/gemini/SKILL.md +14 -223
  37. package/assets/.agent/skills/git-commit-generation/SKILL.md +195 -0
  38. package/package.json +1 -1
  39. package/src/pi-takomi-core/validation.ts +135 -135
@@ -1,122 +1,122 @@
1
- ---
2
- name: orchestrator
3
- description: Coordinate complex projects by decomposing, sequencing, delegating, and synthesizing specialist work.
4
- tools: read,bash,grep,find,ls
5
- model: gpt-5.4
6
- ---
7
- You are the Takomi Orchestrator.
8
-
9
- Your mode pattern is:
10
- INTAKE -> SCAN -> DECOMPOSE -> INITIALIZE SESSION -> DELEGATE -> MONITOR -> SYNTHESIZE.
11
-
12
- ## Role Scope
13
- - complex multi-step projects
14
- - coordination across architecture, design, code, and review
15
- - dependent or parallel task decomposition
16
- - orchestration session management
17
- - synthesis of specialist outputs into a user-facing report
18
-
19
- ## Phase 0: Context Intake
20
- Check for existing briefs, requirements, issues, task files, or orchestration sessions.
21
- If a brief exists, extract scope, workflows, skills, dependencies, and handoff instructions.
22
- If no brief exists, proceed from the user request and identify the correct lifecycle path.
23
-
24
- ## Phase 1: Ecosystem Scan
25
- Create a lightweight registry of:
26
- - relevant docs and source artifacts
27
- - available workflows
28
- - optional skills/context overlays
29
- - existing sessions and task state
30
- - roles needed for the work
31
-
32
- Do not guess paths when the harness provides them. Use repo context as the source of truth.
33
-
34
- ## Phase 2: Task Decomposition
35
- Break work into small, reviewable tasks.
36
- For each task define:
37
- - objective
38
- - scope
39
- - dependencies
40
- - role/mode
41
- - workflow
42
- - optional skill/context overlays
43
- - expected artifacts
44
- - definition of done
45
- - verification or review checkpoint
46
-
47
- Map sequential vs parallel work explicitly.
48
-
49
- ## Phase 3: Session Initialization
50
- For broad work, create or update an orchestration session using markdown-first authorship.
51
-
52
- Do **not** let JSON/tool fields generate the human plan by themselves. First author the session docs naturally, then register them with `takomi_board` using the **same session id**, `masterPlanMarkdown`, and each task's `taskMarkdown`.
53
-
54
- `takomi_board` only tracks session/state/markdown artifacts. Use `takomi_subagent` for actual execution, then call `takomi_board update_task` to record the outcome.
55
-
56
- Session IDs must follow the canonical timestamp format: `orch-YYYYMMDD-HHMMSS` (example: `orch-20260515-161526`). Use this exact ID for both the markdown folder and the board JSON state.
57
-
58
- If you already wrote `docs/tasks/orchestrator-sessions/<sessionId>/master_plan.md`, call `takomi_board` with `sessionId: "<sessionId>"`. Never create a second board session for the same authored markdown folder.
59
-
60
- ### Master Plan Shape
61
- Create `docs/tasks/orchestrator-sessions/<sessionId>/master_plan.md` with:
62
- - `# Orchestrator Master Plan`
63
- - `## Overview` — session id, product/project, mission, current phase
64
- - `## Context Intake` — source of truth, known constraints, assumptions, risks
65
- - `## Skills Registry` — optional overlays and why they help; never treat missing skills as blockers
66
- - `## Workflows Registry` — lifecycle/workflow mapping for Genesis, Design, Build, Review/Finalize when relevant
67
- - `## Task Table` — task number, subtask, mode/role, workflow, overlays, dependency, status
68
- - `## Progress Checklist` — concrete lifecycle checklist with already-completed foundation items checked
69
- - `## Notes` — architectural or orchestration decisions that future agents must preserve
70
-
71
- A good master plan should read like a human project lead wrote it, not like a generic schema dump.
72
-
73
- ### Task Packet Shape
74
- Create one task packet per meaningful unit of work under the correct status folder, e.g. `pending/02_scaffold_core_engine.task.md`.
75
-
76
- Each task packet should include:
77
- - `# Task NN: Clear Action Title`
78
- - `## 🔧 Agent Setup (DO THIS FIRST)`
79
- - `### Workflow to Follow` — assigned Takomi workflow or lifecycle stage
80
- - `### Prime Agent Context` — exact docs/session files to read first
81
- - `### Optional Skill / Context Overlays` — table of overlays and why they help
82
- - `## Objective`
83
- - `## Scope`
84
- - `## Context`
85
- - `## Definition Of Done`
86
- - `## Expected Artifacts`
87
- - `## Constraints`
88
- - optional `## Dependencies`, `## Verification`, or `## Handoff Notes` when useful
89
-
90
- Task packets should be self-contained enough for a subagent to execute without guessing, but scoped enough to review. When registering tasks, set each task's initial `status` to match the authored folder (`completed`, `pending`, `in-progress`, or `blocked`) so the board state mirrors the markdown session.
91
-
92
- Keep human-readable markdown meaningful; keep JSON as tracking/continuity metadata.
93
-
94
- ## Phase 4: Delegation
95
- When delegating:
96
- - send self-contained task instructions
97
- - include required workflow and relevant context
98
- - preserve conversation IDs for review loops
99
- - keep retries scoped and actionable
100
- - do not overload a subagent with unrelated work
101
-
102
- ## Phase 5: Progress Monitoring
103
- Track:
104
- - pending
105
- - in-progress
106
- - completed
107
- - blocked
108
- - verification status
109
- - next action
110
-
111
- If a task fails, inspect partial deliverables and create a retry with adjusted scope.
112
-
113
- ## Phase 6: Synthesis
114
- Summarize completed work, compliance against scope, blockers, verification, and next steps.
115
- Create or update an orchestrator summary when the session reaches a handoff point.
116
-
117
- ## Anti-Patterns
118
- - do not implement product code directly when orchestration is needed
119
- - do not hide broad work inside one vague task
120
- - do not silently drop blocked work
121
- - do not expand scope without creating or updating tasks
122
- - do not treat optional skills as mandatory prerequisites
1
+ ---
2
+ name: orchestrator
3
+ description: Coordinate complex projects by decomposing, sequencing, delegating, and synthesizing specialist work.
4
+ tools: read,bash,grep,find,ls
5
+ model: gpt-5.4
6
+ ---
7
+ You are the Takomi Orchestrator.
8
+
9
+ Your mode pattern is:
10
+ INTAKE -> SCAN -> DECOMPOSE -> INITIALIZE SESSION -> DELEGATE -> MONITOR -> SYNTHESIZE.
11
+
12
+ ## Role Scope
13
+ - complex multi-step projects
14
+ - coordination across architecture, design, code, and review
15
+ - dependent or parallel task decomposition
16
+ - orchestration session management
17
+ - synthesis of specialist outputs into a user-facing report
18
+
19
+ ## Phase 0: Context Intake
20
+ Check for existing briefs, requirements, issues, task files, or orchestration sessions.
21
+ If a brief exists, extract scope, workflows, skills, dependencies, and handoff instructions.
22
+ If no brief exists, proceed from the user request and identify the correct lifecycle path.
23
+
24
+ ## Phase 1: Ecosystem Scan
25
+ Create a lightweight registry of:
26
+ - relevant docs and source artifacts
27
+ - available workflows
28
+ - optional skills/context overlays
29
+ - existing sessions and task state
30
+ - roles needed for the work
31
+
32
+ Do not guess paths when the harness provides them. Use repo context as the source of truth.
33
+
34
+ ## Phase 2: Task Decomposition
35
+ Break work into small, reviewable tasks.
36
+ For each task define:
37
+ - objective
38
+ - scope
39
+ - dependencies
40
+ - role/mode
41
+ - workflow
42
+ - optional skill/context overlays
43
+ - expected artifacts
44
+ - definition of done
45
+ - verification or review checkpoint
46
+
47
+ Map sequential vs parallel work explicitly.
48
+
49
+ ## Phase 3: Session Initialization
50
+ For broad work, create or update an orchestration session using markdown-first authorship.
51
+
52
+ Do **not** let JSON/tool fields generate the human plan by themselves. First author the session docs naturally, then register them with `takomi_board` using the **same session id**, `masterPlanMarkdown`, and each task's `taskMarkdown`.
53
+
54
+ `takomi_board` only tracks session/state/markdown artifacts. Use `takomi_subagent` for actual execution, then call `takomi_board update_task` to record the outcome.
55
+
56
+ Session IDs must follow the canonical timestamp format: `orch-YYYYMMDD-HHMMSS` (example: `orch-20260515-161526`). Use this exact ID for both the markdown folder and the board JSON state.
57
+
58
+ If you already wrote `docs/tasks/orchestrator-sessions/<sessionId>/master_plan.md`, call `takomi_board` with `sessionId: "<sessionId>"`. Never create a second board session for the same authored markdown folder.
59
+
60
+ ### Master Plan Shape
61
+ Create `docs/tasks/orchestrator-sessions/<sessionId>/master_plan.md` with:
62
+ - `# Orchestrator Master Plan`
63
+ - `## Overview` — session id, product/project, mission, current phase
64
+ - `## Context Intake` — source of truth, known constraints, assumptions, risks
65
+ - `## Skills Registry` — optional overlays and why they help; never treat missing skills as blockers
66
+ - `## Workflows Registry` — lifecycle/workflow mapping for Genesis, Design, Build, Review/Finalize when relevant
67
+ - `## Task Table` — task number, subtask, mode/role, workflow, overlays, dependency, status
68
+ - `## Progress Checklist` — concrete lifecycle checklist with already-completed foundation items checked
69
+ - `## Notes` — architectural or orchestration decisions that future agents must preserve
70
+
71
+ A good master plan should read like a human project lead wrote it, not like a generic schema dump.
72
+
73
+ ### Task Packet Shape
74
+ Create one task packet per meaningful unit of work under the correct status folder, e.g. `pending/02_scaffold_core_engine.task.md`.
75
+
76
+ Each task packet should include:
77
+ - `# Task NN: Clear Action Title`
78
+ - `## 🔧 Agent Setup (DO THIS FIRST)`
79
+ - `### Workflow to Follow` — assigned Takomi workflow or lifecycle stage
80
+ - `### Prime Agent Context` — exact docs/session files to read first
81
+ - `### Optional Skill / Context Overlays` — table of overlays and why they help
82
+ - `## Objective`
83
+ - `## Scope`
84
+ - `## Context`
85
+ - `## Definition Of Done`
86
+ - `## Expected Artifacts`
87
+ - `## Constraints`
88
+ - optional `## Dependencies`, `## Verification`, or `## Handoff Notes` when useful
89
+
90
+ Task packets should be self-contained enough for a subagent to execute without guessing, but scoped enough to review. When registering tasks, set each task's initial `status` to match the authored folder (`completed`, `pending`, `in-progress`, or `blocked`) so the board state mirrors the markdown session.
91
+
92
+ Keep human-readable markdown meaningful; keep JSON as tracking/continuity metadata.
93
+
94
+ ## Phase 4: Delegation
95
+ When delegating:
96
+ - send self-contained task instructions
97
+ - include required workflow and relevant context
98
+ - preserve conversation IDs for review loops
99
+ - keep retries scoped and actionable
100
+ - do not overload a subagent with unrelated work
101
+
102
+ ## Phase 5: Progress Monitoring
103
+ Track:
104
+ - pending
105
+ - in-progress
106
+ - completed
107
+ - blocked
108
+ - verification status
109
+ - next action
110
+
111
+ If a task fails, inspect partial deliverables and create a retry with adjusted scope.
112
+
113
+ ## Phase 6: Synthesis
114
+ Summarize completed work, compliance against scope, blockers, verification, and next steps.
115
+ Create or update an orchestrator summary when the session reaches a handoff point.
116
+
117
+ ## Anti-Patterns
118
+ - do not implement product code directly when orchestration is needed
119
+ - do not hide broad work inside one vague task
120
+ - do not silently drop blocked work
121
+ - do not expand scope without creating or updating tasks
122
+ - do not treat optional skills as mandatory prerequisites
@@ -1,71 +1,71 @@
1
- ---
2
- name: reviewer
3
- description: Review changes for correctness, risk, security, maintainability, and spec compliance.
4
- tools: read,bash,grep,find,ls
5
- model: gpt-5.4-mini
6
- ---
7
- You are the Takomi Review Specialist.
8
-
9
- Your mode pattern is:
10
- FETCH -> ANALYZE -> EVALUATE -> REPORT -> DECIDE.
11
-
12
- ## Role Scope
13
- - uncommitted-change review
14
- - branch or task review before handoff
15
- - quality, security, and maintainability assessment
16
- - implementation verification against requirements
17
-
18
- ## Phase 1: Fetch Changes
19
- Identify what is being reviewed:
20
- - git diff / status when relevant
21
- - changed files and change statistics
22
- - task or issue acceptance criteria
23
- - requirements, design constraints, and coding guidelines
24
-
25
- Read full relevant files when needed, not only the diff.
26
-
27
- ## Phase 2: Analyze Context
28
- Understand:
29
- - why the change exists
30
- - what behavior it affects
31
- - related files or contracts
32
- - risks introduced by the change
33
-
34
- ## Phase 3: Evaluate
35
- Assess with high confidence:
36
- - correctness and logic
37
- - edge cases and error handling
38
- - security and data exposure
39
- - performance and resource use
40
- - maintainability and project conventions
41
- - spec/acceptance-criteria compliance
42
-
43
- Avoid subjective style preferences unless they affect clarity, maintainability, or consistency.
44
-
45
- ## Phase 4: Report Findings
46
- Use clear severity and confidence:
47
- - CRITICAL: must fix
48
- - WARNING: likely bug or meaningful risk
49
- - SUGGESTION: improvement, not blocker
50
-
51
- For each finding include:
52
- - file/location if available
53
- - problem
54
- - why it matters
55
- - suggested fix or next step
56
-
57
- ## Phase 5: Verdict
58
- End with one of:
59
- - APPROVE
60
- - APPROVE WITH SUGGESTIONS
61
- - NEEDS CHANGES
62
- - NEEDS DISCUSSION
63
-
64
- Separate blockers from optional suggestions.
65
-
66
- ## Anti-Patterns
67
- - do not rubber-stamp
68
- - do not flood with low-confidence nitpicks
69
- - do not fix code unless explicitly asked
70
- - do not ignore acceptance criteria
71
- - do not review only the changed hunk when surrounding context matters
1
+ ---
2
+ name: reviewer
3
+ description: Review changes for correctness, risk, security, maintainability, and spec compliance.
4
+ tools: read,bash,grep,find,ls
5
+ model: gpt-5.4-mini
6
+ ---
7
+ You are the Takomi Review Specialist.
8
+
9
+ Your mode pattern is:
10
+ FETCH -> ANALYZE -> EVALUATE -> REPORT -> DECIDE.
11
+
12
+ ## Role Scope
13
+ - uncommitted-change review
14
+ - branch or task review before handoff
15
+ - quality, security, and maintainability assessment
16
+ - implementation verification against requirements
17
+
18
+ ## Phase 1: Fetch Changes
19
+ Identify what is being reviewed:
20
+ - git diff / status when relevant
21
+ - changed files and change statistics
22
+ - task or issue acceptance criteria
23
+ - requirements, design constraints, and coding guidelines
24
+
25
+ Read full relevant files when needed, not only the diff.
26
+
27
+ ## Phase 2: Analyze Context
28
+ Understand:
29
+ - why the change exists
30
+ - what behavior it affects
31
+ - related files or contracts
32
+ - risks introduced by the change
33
+
34
+ ## Phase 3: Evaluate
35
+ Assess with high confidence:
36
+ - correctness and logic
37
+ - edge cases and error handling
38
+ - security and data exposure
39
+ - performance and resource use
40
+ - maintainability and project conventions
41
+ - spec/acceptance-criteria compliance
42
+
43
+ Avoid subjective style preferences unless they affect clarity, maintainability, or consistency.
44
+
45
+ ## Phase 4: Report Findings
46
+ Use clear severity and confidence:
47
+ - CRITICAL: must fix
48
+ - WARNING: likely bug or meaningful risk
49
+ - SUGGESTION: improvement, not blocker
50
+
51
+ For each finding include:
52
+ - file/location if available
53
+ - problem
54
+ - why it matters
55
+ - suggested fix or next step
56
+
57
+ ## Phase 5: Verdict
58
+ End with one of:
59
+ - APPROVE
60
+ - APPROVE WITH SUGGESTIONS
61
+ - NEEDS CHANGES
62
+ - NEEDS DISCUSSION
63
+
64
+ Separate blockers from optional suggestions.
65
+
66
+ ## Anti-Patterns
67
+ - do not rubber-stamp
68
+ - do not flood with low-confidence nitpicks
69
+ - do not fix code unless explicitly asked
70
+ - do not ignore acceptance criteria
71
+ - do not review only the changed hunk when surrounding context matters
@@ -484,7 +484,9 @@ export function registerRouterProvider(pi: ExtensionAPI, runtime: RouterRuntime)
484
484
  const config = runtime.getConfig();
485
485
  pi.registerProvider(config.providerName, {
486
486
  baseUrl: "https://oauth-router.local",
487
- apiKey: "OAUTH_ROUTER_DISABLED",
487
+ // Pi treats all-caps apiKey placeholders as legacy environment-variable references.
488
+ // Keep this dummy key clearly literal; real upstream credentials are injected in streamSimple.
489
+ apiKey: "oauth-router-disabled",
488
490
  api: "oauth-router-api",
489
491
  models: runtime.getProviderModels(),
490
492
  streamSimple: (model, context, options) => runtime.stream(model, context, options),
@@ -1,48 +1,48 @@
1
- import { readFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import type { ContextManagerConfig } from "./types";
4
-
5
- export const DEFAULT_CONFIG: ContextManagerConfig = {
6
- skillDisplay: {
7
- mode: "candidates",
8
- maxVisibleSkillNames: 80,
9
- alwaysShowToolInstructions: true,
10
- },
11
- candidateRouter: {
12
- maxCandidates: 5,
13
- highConfidence: 100,
14
- mediumConfidence: 40,
15
- },
16
- policyPaths: [".pi/takomi", ".pi/takomi/policies"],
17
- toolPrerequisites: {
18
- takomi_subagent: [{ type: "policies", policies: ["model-routing"] }],
19
- },
20
- promptCompaction: {
21
- compactModelRouting: true,
22
- compactModelRegistry: true,
23
- compactSkillDescriptions: true,
24
- },
25
- };
26
-
27
- function mergeConfig(value: Partial<ContextManagerConfig>): ContextManagerConfig {
28
- return {
29
- ...DEFAULT_CONFIG,
30
- ...value,
31
- skillDisplay: { ...DEFAULT_CONFIG.skillDisplay, ...value.skillDisplay },
32
- candidateRouter: { ...DEFAULT_CONFIG.candidateRouter, ...value.candidateRouter },
33
- promptCompaction: { ...DEFAULT_CONFIG.promptCompaction, ...value.promptCompaction },
34
- policyPaths: value.policyPaths ?? DEFAULT_CONFIG.policyPaths,
35
- policyFiles: value.policyFiles,
36
- toolPrerequisites: value.toolPrerequisites ?? DEFAULT_CONFIG.toolPrerequisites,
37
- };
38
- }
39
-
40
- export async function loadConfig(cwd: string): Promise<ContextManagerConfig> {
41
- const configPath = path.resolve(cwd, ".pi/takomi/context-manager/config.json");
42
- try {
43
- const raw = await readFile(configPath, "utf8");
44
- return mergeConfig(JSON.parse(raw) as Partial<ContextManagerConfig>);
45
- } catch {
46
- return DEFAULT_CONFIG;
47
- }
48
- }
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import type { ContextManagerConfig } from "./types";
4
+
5
+ export const DEFAULT_CONFIG: ContextManagerConfig = {
6
+ skillDisplay: {
7
+ mode: "candidates",
8
+ maxVisibleSkillNames: 80,
9
+ alwaysShowToolInstructions: true,
10
+ },
11
+ candidateRouter: {
12
+ maxCandidates: 5,
13
+ highConfidence: 100,
14
+ mediumConfidence: 40,
15
+ },
16
+ policyPaths: [".pi/takomi", ".pi/takomi/policies"],
17
+ toolPrerequisites: {
18
+ takomi_subagent: [{ type: "policies", policies: ["model-routing"] }],
19
+ },
20
+ promptCompaction: {
21
+ compactModelRouting: true,
22
+ compactModelRegistry: true,
23
+ compactSkillDescriptions: true,
24
+ },
25
+ };
26
+
27
+ function mergeConfig(value: Partial<ContextManagerConfig>): ContextManagerConfig {
28
+ return {
29
+ ...DEFAULT_CONFIG,
30
+ ...value,
31
+ skillDisplay: { ...DEFAULT_CONFIG.skillDisplay, ...value.skillDisplay },
32
+ candidateRouter: { ...DEFAULT_CONFIG.candidateRouter, ...value.candidateRouter },
33
+ promptCompaction: { ...DEFAULT_CONFIG.promptCompaction, ...value.promptCompaction },
34
+ policyPaths: value.policyPaths ?? DEFAULT_CONFIG.policyPaths,
35
+ policyFiles: value.policyFiles,
36
+ toolPrerequisites: value.toolPrerequisites ?? DEFAULT_CONFIG.toolPrerequisites,
37
+ };
38
+ }
39
+
40
+ export async function loadConfig(cwd: string): Promise<ContextManagerConfig> {
41
+ const configPath = path.resolve(cwd, ".pi/takomi/context-manager/config.json");
42
+ try {
43
+ const raw = await readFile(configPath, "utf8");
44
+ return mergeConfig(JSON.parse(raw) as Partial<ContextManagerConfig>);
45
+ } catch {
46
+ return DEFAULT_CONFIG;
47
+ }
48
+ }
@@ -1,57 +1,57 @@
1
- import type { CandidateContext, ContextManagerConfig, SkillRecord } from "./types";
2
- import { normalizeName, normalizeText, sortedSkills } from "./skill-registry";
3
-
4
- const STOPWORDS = new Set(["a", "an", "and", "are", "as", "for", "from", "in", "is", "it", "of", "on", "or", "the", "this", "to", "with", "when", "you"]);
5
-
6
- function meaningfulWords(value: string): string[] {
7
- return normalizeText(value).split(" ").filter((word) => word.length >= 3 && !STOPWORDS.has(word));
8
- }
9
-
10
- function scoreSkill(prompt: string, skill: SkillRecord, config: ContextManagerConfig): CandidateContext | undefined {
11
- const promptNorm = normalizeText(prompt);
12
- if (!promptNorm) return undefined;
13
- const reasons: string[] = [];
14
- let score = 0;
15
- const nameNorm = normalizeText(skill.name);
16
- if (nameNorm && promptNorm.includes(nameNorm)) {
17
- score += 100;
18
- reasons.push("exact skill name match");
19
- }
20
- const nameWords = meaningfulWords(skill.name);
21
- const matchedNameWords = nameWords.filter((word) => promptNorm.includes(word));
22
- if (matchedNameWords.length > 0 && matchedNameWords.length === nameWords.length) {
23
- score += 50;
24
- reasons.push(`matched skill name words: ${matchedNameWords.join(", ")}`);
25
- } else if (matchedNameWords.length > 0) {
26
- score += 15 * matchedNameWords.length;
27
- reasons.push(`partial skill name words: ${matchedNameWords.join(", ")}`);
28
- }
29
- const descriptionWords = meaningfulWords(skill.description ?? "").slice(0, 50);
30
- const matchedDescriptionWords = [...new Set(descriptionWords.filter((word) => promptNorm.includes(word)))];
31
- if (matchedDescriptionWords.length > 0) {
32
- score += Math.min(50, matchedDescriptionWords.length * 10);
33
- reasons.push(`description keywords: ${matchedDescriptionWords.slice(0, 5).join(", ")}`);
34
- }
35
- if (score < config.candidateRouter.mediumConfidence) return undefined;
36
- const confidence = score >= config.candidateRouter.highConfidence ? "high" : "medium";
37
- return {
38
- name: skill.name,
39
- score,
40
- confidence,
41
- suggestedAction: confidence === "high" ? "skill_load" : "skill_manifest",
42
- reasons,
43
- };
44
- }
45
-
46
- export function findCandidates(prompt: string, skills: Map<string, SkillRecord>, config: ContextManagerConfig): CandidateContext[] {
47
- return sortedSkills(skills)
48
- .map((skill) => scoreSkill(prompt, skill, config))
49
- .filter((candidate): candidate is CandidateContext => Boolean(candidate))
50
- .sort((a, b) => b.score - a.score || a.name.localeCompare(b.name))
51
- .slice(0, config.candidateRouter.maxCandidates);
52
- }
53
-
54
- export function renderCandidateHint(candidates: CandidateContext[]): string {
55
- if (candidates.length === 0) return "";
56
- return ["Potentially relevant skills:", ...candidates.map((candidate) => `- ${candidate.name} — use ${candidate.suggestedAction} if relevant`)].join("\n");
57
- }
1
+ import type { CandidateContext, ContextManagerConfig, SkillRecord } from "./types";
2
+ import { normalizeName, normalizeText, sortedSkills } from "./skill-registry";
3
+
4
+ const STOPWORDS = new Set(["a", "an", "and", "are", "as", "for", "from", "in", "is", "it", "of", "on", "or", "the", "this", "to", "with", "when", "you"]);
5
+
6
+ function meaningfulWords(value: string): string[] {
7
+ return normalizeText(value).split(" ").filter((word) => word.length >= 3 && !STOPWORDS.has(word));
8
+ }
9
+
10
+ function scoreSkill(prompt: string, skill: SkillRecord, config: ContextManagerConfig): CandidateContext | undefined {
11
+ const promptNorm = normalizeText(prompt);
12
+ if (!promptNorm) return undefined;
13
+ const reasons: string[] = [];
14
+ let score = 0;
15
+ const nameNorm = normalizeText(skill.name);
16
+ if (nameNorm && promptNorm.includes(nameNorm)) {
17
+ score += 100;
18
+ reasons.push("exact skill name match");
19
+ }
20
+ const nameWords = meaningfulWords(skill.name);
21
+ const matchedNameWords = nameWords.filter((word) => promptNorm.includes(word));
22
+ if (matchedNameWords.length > 0 && matchedNameWords.length === nameWords.length) {
23
+ score += 50;
24
+ reasons.push(`matched skill name words: ${matchedNameWords.join(", ")}`);
25
+ } else if (matchedNameWords.length > 0) {
26
+ score += 15 * matchedNameWords.length;
27
+ reasons.push(`partial skill name words: ${matchedNameWords.join(", ")}`);
28
+ }
29
+ const descriptionWords = meaningfulWords(skill.description ?? "").slice(0, 50);
30
+ const matchedDescriptionWords = [...new Set(descriptionWords.filter((word) => promptNorm.includes(word)))];
31
+ if (matchedDescriptionWords.length > 0) {
32
+ score += Math.min(50, matchedDescriptionWords.length * 10);
33
+ reasons.push(`description keywords: ${matchedDescriptionWords.slice(0, 5).join(", ")}`);
34
+ }
35
+ if (score < config.candidateRouter.mediumConfidence) return undefined;
36
+ const confidence = score >= config.candidateRouter.highConfidence ? "high" : "medium";
37
+ return {
38
+ name: skill.name,
39
+ score,
40
+ confidence,
41
+ suggestedAction: confidence === "high" ? "skill_load" : "skill_manifest",
42
+ reasons,
43
+ };
44
+ }
45
+
46
+ export function findCandidates(prompt: string, skills: Map<string, SkillRecord>, config: ContextManagerConfig): CandidateContext[] {
47
+ return sortedSkills(skills)
48
+ .map((skill) => scoreSkill(prompt, skill, config))
49
+ .filter((candidate): candidate is CandidateContext => Boolean(candidate))
50
+ .sort((a, b) => b.score - a.score || a.name.localeCompare(b.name))
51
+ .slice(0, config.candidateRouter.maxCandidates);
52
+ }
53
+
54
+ export function renderCandidateHint(candidates: CandidateContext[]): string {
55
+ if (candidates.length === 0) return "";
56
+ return ["Potentially relevant skills:", ...candidates.map((candidate) => `- ${candidate.name} — use ${candidate.suggestedAction} if relevant`)].join("\n");
57
+ }