dsh-plugin-prompt-tool 1.0.0 → 2.0.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.
Files changed (95) hide show
  1. package/README.md +38 -29
  2. package/engine/actions/append-context.mjs +49 -0
  3. package/engine/actions/assembly.mjs +150 -0
  4. package/engine/actions/catalog.mjs +92 -0
  5. package/engine/actions/content.mjs +205 -0
  6. package/engine/actions/decision.mjs +54 -0
  7. package/engine/actions/examples.mjs +11 -0
  8. package/engine/actions/guard.mjs +80 -0
  9. package/engine/actions/inbox-prepend.mjs +37 -0
  10. package/engine/actions/index.mjs +100 -0
  11. package/engine/actions/inject-text.mjs +22 -0
  12. package/engine/actions/pre-step-filter.mjs +55 -0
  13. package/engine/actions/registration.mjs +168 -0
  14. package/engine/actions/request-params.mjs +32 -0
  15. package/engine/actions/sdk-strip.mjs +30 -0
  16. package/engine/actions/shared.mjs +71 -0
  17. package/engine/actions.mjs +2 -931
  18. package/engine/branch.mjs +44 -0
  19. package/engine/compaction-epoch.mjs +31 -13
  20. package/engine/compositions/source/local/dev-tool-search.yml +11 -0
  21. package/engine/compositions/source/local/instruction-hint.yml +22 -1
  22. package/engine/compositions/source/local/rule-engine.yml +6 -0
  23. package/engine/condition.mjs +16 -3
  24. package/engine/conditions/anchor.mjs +32 -0
  25. package/engine/conditions/availability.mjs +47 -0
  26. package/engine/conditions/composite.mjs +83 -0
  27. package/engine/conditions/count.mjs +140 -0
  28. package/engine/conditions/evaluation.mjs +41 -0
  29. package/engine/conditions/examples.mjs +11 -0
  30. package/engine/conditions/index.mjs +85 -0
  31. package/engine/conditions/names.mjs +21 -0
  32. package/engine/conditions/phase.mjs +54 -0
  33. package/engine/conditions/preset.mjs +94 -0
  34. package/engine/conditions/scope.mjs +18 -0
  35. package/engine/conditions/session.mjs +22 -0
  36. package/engine/conditions/source.mjs +63 -0
  37. package/engine/conditions/subject.mjs +121 -0
  38. package/engine/conditions/text.mjs +44 -0
  39. package/engine/conditions/values.mjs +32 -0
  40. package/engine/dev-tool-search.mjs +213 -0
  41. package/engine/executor.mjs +55 -6
  42. package/engine/fillers.mjs +23 -16
  43. package/engine/instruction-hint.mjs +34 -22
  44. package/engine/layers.mjs +135 -49
  45. package/engine/order.mjs +4 -1
  46. package/engine/predicates.mjs +2 -753
  47. package/engine/rule-engine.mjs +40 -0
  48. package/engine/rule-runtime.mjs +110 -0
  49. package/engine/rule-spec.mjs +187 -0
  50. package/engine/schema.mjs +16 -5
  51. package/engine/shared.mjs +1 -1
  52. package/engine/strategies.mjs +2 -235
  53. package/engine/subagent-tool-policy-core.mjs +7 -7
  54. package/engine/subagent-tool-policy.mjs +20 -10
  55. package/engine/tool-config-engine.mjs +53 -32
  56. package/engine/trigger-editor-meta.mjs +2 -21
  57. package/engine/trigger-spec.mjs +49 -133
  58. package/lib/client.js +10446 -10820
  59. package/lib/client.js.map +1 -1
  60. package/lib/index.d.mts +82 -139
  61. package/lib/index.mjs +826 -1087
  62. package/lib/migrate-rules.d.mts +1 -0
  63. package/lib/migrate-rules.mjs +39 -0
  64. package/lib/module-package-CHPFweqK.mjs +2 -0
  65. package/lib/module-package-Cnd1_mwx.mjs +2872 -0
  66. package/lib/{paths-BgL42sSM.d.mts → paths-CyP0IkaM.d.mts} +223 -108
  67. package/lib/preset-transfer.d.mts +2 -2
  68. package/lib/preset-transfer.mjs +3 -2
  69. package/lib/{module-package-Cm3fHHlp.mjs → rules-migration-DJ6vASB5.mjs} +13696 -15557
  70. package/modules/ponytail/module.yml +381 -147
  71. package/modules/skill-surface/module.yml +74 -0
  72. package/modules/tool-surface/module.yml +67 -0
  73. package/package.json +5 -1
  74. package/templates/10-pre-step.yml +26 -22
  75. package/templates/14-first-turn-anchor.yml +25 -21
  76. package/templates/15-guide-auto.yml +34 -19
  77. package/templates/16-custom-fallback.yml +27 -15
  78. package/templates/18-placeholder-env-facts.yml +23 -14
  79. package/templates/20-system-section.yml +16 -10
  80. package/templates/30-runtime-context.yml +13 -7
  81. package/templates/40-agent-request.yml +11 -8
  82. package/templates/50-llm-stream.yml +14 -6
  83. package/templates/60-tool-pipeline.yml +15 -9
  84. package/templates/65-turn-stop.yml +19 -12
  85. package/templates/66-subagent-start.yml +12 -7
  86. package/templates/70-subagent-maintenance.yml +35 -29
  87. package/templates/75-subagent-end.yml +10 -5
  88. package/templates/80-tool-surface.yml +66 -0
  89. package/templates/policies/legacy-defaults.yml +34 -0
  90. package/engine/compositions/source/local/prompt-config-engine.yml +0 -7
  91. package/engine/prompt-config-engine.mjs +0 -104
  92. package/modules/ponytail/configs/0000-ponytail-rules.yml +0 -102
  93. package/modules/ponytail/configs/0010-ponytail-level-full.yml +0 -19
  94. package/modules/ponytail/configs/0020-ponytail-level-lite.yml +0 -19
  95. package/modules/ponytail/configs/0030-ponytail-level-ultra.yml +0 -19
@@ -0,0 +1,66 @@
1
+ # 模板:工具面收窄(核心文件与任务集)+ 按需解锁
2
+ #
3
+ # 为什么:工具面实测 **156 个工具、描述合计 46894 字符(≈12K token)**,每个请求都付。
4
+ # 收窄到核心集后只剩约 10 个工具,其余按需解锁。
5
+ #
6
+ # 与 test/engine/declarations/tool-bootstrap.yml 的关键差别:那份原型**只在受控相位收窄**
7
+ # (`promoted: false`),晋升后原样放开;本模板**覆盖全部相位**——晋升后放开等于白省,
8
+ # 而工具描述是每请求的固定开销。若要旧语义,给 `phase` 加 `promoted: false` 并把
9
+ # `compacted` 拆成两条即可。
10
+ #
11
+ # 配套两件(缺一不可):
12
+ # 1. `dev_tool_search` 工具(组合源 engine/compositions/source/local/dev-tool-search.yml)
13
+ # ——唯一发现入口,模型靠它搜索并解锁。
14
+ # 2. `allowFrom`(engine/actions/assembly.mjs)——从历史 `tool/call` 参数回收解锁名单。
15
+ # 只挂插件不配 allowFrom 的话,解锁是**一次性的**(当次请求用完即被裁)。
16
+ #
17
+ # 工具名必须与**实际装配名**一致。本项目 harness 是 `pwsh`(不是 `bash`)、
18
+ # `edit` + `write`(不是 `str_replace_editor`)。写错名字有两个后果,都很隐蔽:
19
+ # - 写进 allow 的名字不存在 → `requireMatch` 触发 fail-open,**静默暴露完整目录**;
20
+ # - 该在的没写进去 → 该工具被裁掉,模型只能用别的方式硬凑。
21
+ #
22
+ # `requireMatch: true` 是刻意的:任一 allow 工具缺失(或模型解锁了一个不存在的名字)
23
+ # 就放弃裁剪、暴露完整目录。宁可多给上下文,也不静默裁成空目录——收窄错了会让当前
24
+ # 工作流调不到工具,那是比多花 token 严重得多的故障。
25
+ #
26
+ # **本模板走规则路径,不能声明 `waterfallPosition`**(那是声明 `triggers` 路径的字段,
27
+ # `compileRules` 会以 unknown fields 拒绝)。`assembly` 的改写发生在通道下游结算之后,
28
+ # 与相邻动作的先后由规则顺序与模块顺序决定。若确实需要 `outermost`(`prepend: true`,
29
+ # 保证本动作在普通注册之外先看到装配),改用声明路径(同 test/engine/declarations/
30
+ # tool-bootstrap.yml 的格式)而不是本模板。
31
+ id: tool-surface-resident
32
+ name: 工具面收窄(核心文件与任务集)
33
+ enabled: true
34
+ if:
35
+ # 覆盖全部相位。为什么不能只写 `phase: { promoteOn, includeSubagents }`:
36
+ # `promoted` 的缺省是 **true**(= 只匹配已晋升),不是「任意」;而 `compacted` 未声明才是
37
+ # 「不判该维度」(engine/conditions/phase.mjs:27-48)。更麻烦的是 `promoted: 'ignore'`
38
+ # 要求同时声明 `compacted`,而 `compacted` 只接受布尔值——**没有任何单节点组合能表达
39
+ # 「两个相位都命中」**,必须用 `any` 拼两支(phase.mjs:30-35 的注释正是在讲这个表达力边界)。
40
+ # 支 1 `promoted: true` → 已晋升(不论压缩与否)
41
+ # 支 2 `{compacted: true, promoted: false}` → 压缩后未晋升(受控相位的压缩回退)
42
+ # 未晋升且未压缩的**首轮不收窄**:与「首轮保全文」同一取舍——先让模型看到完整目录,
43
+ # 再随相位推进收窄。收窄的价值在于工具描述是**每请求固定开销**(实测 46894 字符),
44
+ # 而长会话必然进入上面两支,所以省下的正是大头。
45
+ any:
46
+ - phase: { promoteOn: either, includeSubagents: true, promoted: true }
47
+ - phase: { promoteOn: either, includeSubagents: true, compacted: true, promoted: false }
48
+ then:
49
+ - id: narrow-tools
50
+ kind: assembly
51
+ target:
52
+ tools:
53
+ allow:
54
+ - pwsh
55
+ - read
56
+ - write
57
+ - edit
58
+ - glob
59
+ - grep
60
+ - todo_write
61
+ - skill_search
62
+ - skill_load
63
+ - dev_tool_search
64
+ # 解锁项从 dev_tool_search 的持久调用参数回收({ tool, key } 精确匹配)。
65
+ allowFrom: { tool: dev_tool_search, key: toolNames }
66
+ requireMatch: true
@@ -0,0 +1,34 @@
1
+ #旧业务默认的精确数据快照,仅供模板生成和显式离线迁移读取。引擎运行时不得读取此文件。
2
+
3
+ version: 1
4
+ fillers:
5
+ envFacts:
6
+ text: |-
7
+ Environment facts:
8
+ {{ENV_FACTS}}
9
+ skillCatalog:
10
+ text: |-
11
+ Available skills ({{SKILL_COUNT}}):
12
+ {{SKILLS_TEXT}}
13
+ params:
14
+ limit: 20
15
+ fields: name,description
16
+ whenToUseLabel: 适用:
17
+ unnamedLabel: (unnamed)
18
+ instructionHint:
19
+ projectTemplate: "Reference documents exist: {{FILES}} (project root: {{ROOT}})."
20
+ globalTemplate: "A user reference document exists: {{FILES}}."
21
+ suffixTemplate: They are reference documents about the user's environment and
22
+ workspace conventions, not task instructions. Reading the relevant file
23
+ before workspace tasks is recommended, but consult them only when you need
24
+ those details; the task itself never depends on them.
25
+ messageTemplate: |-
26
+ <system-reminder>
27
+ Reference documents exist: {{FILES}}. {{SUFFIX}}
28
+ </system-reminder>
29
+ promotionGate:
30
+ reasoningPattern: \bwe\b
31
+ reasoningNegativePattern: \blet me\b
32
+ reasoningFlags: gi
33
+ customFallback:
34
+ fallbackAfter: 1
@@ -1,7 +0,0 @@
1
- # module: prompt-config-engine
2
- # source: engine/compositions/source/local/prompt-config-engine.yml (本地附加,非官方模块)
3
-
4
- - id: prompt-config-engine
5
- name: ./engine/prompt-config-engine.mjs
6
- config:
7
- configsDir: ../configs
@@ -1,104 +0,0 @@
1
- /**
2
- * prompt-config-engine — prompt-tool 的唯一提示词注入执行器(装配入口)。
3
- *
4
- * 本文件只做装配:
5
- * - schema.mjs 提示词配置加载/归一化/权威校验
6
- * - strategies.mjs 内置策略绑定 + 模板专属策略懒加载(strategyDir)
7
- * - fillers.mjs placeholder 动态填充器(instruction-hint / env-facts / skill-catalog)
8
- * - instruction-hint.mjs 通用指令文件提示实现(策略与 context-gate 共用)
9
- * - layers.mjs 非 pre-step 五个官方层级接线
10
- * - executor.mjs pre-step 消息批执行器(过滤/去重/合并/落位)
11
- *
12
- * agent.cordis.yml 引擎行:
13
- * - id: prompt-config-engine
14
- * name: ./engine/prompt-config-engine.mjs
15
- * config:
16
- * configsDir: ../prompt-configs # 提示词配置模块目录(相对本文件)
17
- * strategyDir: ../strategies # 模板专属策略目录(可选,相对本文件)
18
- *
19
- * 铁律:任一提示词配置失败只跳过该提示词配置并 warnOnce;配置错误挂载时 fail loud。
20
- */
21
-
22
- import { readFileSync } from 'node:fs'
23
- import { basename } from 'node:path'
24
- import { fileURLToPath } from 'node:url'
25
- import { createPromptConfigs, loadPromptConfigFiles, parsePromptConfigYaml } from './schema.mjs'
26
- import { applyPromptConfigs } from './executor.mjs'
27
- import { defineConfig, passthrough } from './fields.mjs'
28
-
29
- /** Cordis plugin name used by loader diagnostics. */
30
- export const name = 'prompt-config-engine'
31
-
32
- /**
33
- * 等待全部可注入层级的宿主服务。preset 行在 agent 组合内解析这些服务
34
- * (persona 依赖 systemPrompt,工具行依赖 tools,agent loop 依赖 llm)。
35
- */
36
- export const inject = ['systemPrompt', 'tools', 'llm']
37
-
38
- export { parsePromptConfigYaml, loadPromptConfigFiles, createPromptConfigs, applyPromptConfigs }
39
-
40
- /** 物化清单里是否仍挂着官方指令加载行(负责人冲突事实)。 */
41
- const OFFICIAL_INSTRUCTIONS_ROW = /dsh-agent-instructions|(^|\s)id:\s*agent-instructions\b/m
42
-
43
- /**
44
- * 本 mount 的装配事实:来源 id(协调器注册键,取预设目录名)+ 是否仍挂着官方
45
- * 指令行。协调器据此拒绝在官方负责人仍在时同时注入插件指令文件正文。
46
- * 引擎直接以源码方式被引用(无物化组合文件)时按未知处理,不声明冲突。
47
- */
48
- function compositionFacts(dirUrl) {
49
- try {
50
- const dir = new URL('..', dirUrl)
51
- return {
52
- sourceId: `preset:${basename(fileURLToPath(dir))}`,
53
- officialInstructions: OFFICIAL_INSTRUCTIONS_ROW.test(readFileSync(new URL('../agent.cordis.yml', dirUrl), 'utf8')),
54
- }
55
- } catch {
56
- return { sourceId: undefined, officialInstructions: false }
57
- }
58
- }
59
-
60
- /**
61
- * 引擎插件入口:config.configsDir 为提示词配置模块目录(相对本文件的 URL),
62
- * config.strategyDir 为模板专属策略目录(可选)。引擎扫描目录内每个
63
- * *.yml / *.yaml / *.json 并装配为提示词配置。
64
- */
65
- /**
66
- * 配置契约:白名单由字段声明派生(此前没有白名单,未知键被静默忽略)。
67
- * 三个键都刻意用 passthrough 保住既有语义——迁移前它们对**非字符串或空串**是静默取默认值
68
- * (`typeof x === 'string' && x.length > 0 ? x : 默认`),换成 text() 会把静默降级变成挂载期
69
- * 报错,那是 B2 未授权的行为变更。归一化结果与迁移前逐字段一致,唯一新增的是「未知键报错」。
70
- *
71
- * `presetRoot` 是可选的预设根基准(绝对 file URL):引擎由插件包提供、不再位于
72
- * `<预设根>/.engine/` 时,`templateFile` 的越界校验无法再从引擎位置推导,改由装配期注入。
73
- */
74
- export const configContract = defineConfig({
75
- configsDir: passthrough((value) => (typeof value === 'string' && value.length > 0 ? value : './prompt-configs')),
76
- strategyDir: passthrough((value) => (typeof value === 'string' && value.length > 0 ? value : undefined)),
77
- presetRoot: passthrough((value) => (typeof value === 'string' && value.length > 0 ? value : undefined)),
78
- })
79
-
80
- export function apply(ctx, config) {
81
- const { configsDir: dirName, strategyDir: rawStrategyDir, presetRoot: rawPresetRoot } = configContract.parse(config, name)
82
- const dirUrl = new URL(dirName.endsWith('/') ? dirName : `${dirName}/`, import.meta.url)
83
- // strategyDir 在入口统一解析成绝对 URL:bindResolver 用 `new URL(x.mjs, strategyDir)`
84
- // 懒加载,相对写法的 base 不是合法绝对 URL(ERR_INVALID_URL),会让整行挂载失败。
85
- const strategyDir = rawStrategyDir === undefined
86
- ? undefined
87
- : new URL(rawStrategyDir.endsWith('/') ? rawStrategyDir : `${rawStrategyDir}/`, import.meta.url).href
88
- // 预设根基准(可选):装配期注入绝对 file URL;缺省时由 schema 按「引擎上一级目录」推导。
89
- const templatePresetRoot = rawPresetRoot === undefined
90
- ? undefined
91
- : new URL(rawPresetRoot.endsWith('/') ? rawPresetRoot : `${rawPresetRoot}/`)
92
- const facts = compositionFacts(dirUrl)
93
- applyPromptConfigs(ctx, createPromptConfigs(loadPromptConfigFiles(dirUrl), {
94
- strategyDir,
95
- // 注入预设根时(引擎由插件包提供):相对 templateFile 仍按**历史引擎位置**
96
- // `<预设根>/.engine/` 解析,用户预设与提示词配置零改写;越界校验基准则是预设根本身。
97
- ...(templatePresetRoot === undefined
98
- ? {}
99
- : { templateBaseUrl: new URL('.engine/prompt-config-engine.mjs', templatePresetRoot), templatePresetRoot }),
100
- }), {
101
- prepend: true,
102
- ...facts,
103
- })
104
- }
@@ -1,102 +0,0 @@
1
- id: ponytail-rules
2
- name: Ponytail 规则(公共部分,常驻)
3
- layer: system-section
4
- order: 190
5
- enabled: true
6
- strategy: static
7
- text: |-
8
- # Ponytail
9
-
10
- You are a lazy senior developer. Lazy means efficient, not careless. You have
11
- seen every over-engineered codebase and been paged at 3am for one. The best
12
- code is the code never written.
13
-
14
- ## Persistence
15
-
16
- ACTIVE EVERY RESPONSE. No drift back to over-building. Still active if
17
- unsure. Default: **full**.
18
-
19
- The active level is controlled by the preset's Ponytail configuration
20
- and persists until that configuration is changed.
21
-
22
- ## The ladder
23
-
24
- Stop at the first rung that holds:
25
-
26
- 1. **Does this need to exist at all?** Speculative need = skip it, say so in one line. (YAGNI)
27
- 2. **Already in this codebase?** A helper, util, type, or pattern that already lives here → reuse it. Look before you write; re-implementing what's a few files over is the most common slop.
28
- 3. **Stdlib does it?** Use it.
29
- 4. **Native platform feature covers it?** `<input type="date">` over a picker lib, CSS over JS, DB constraint over app code.
30
- 5. **Already-installed dependency solves it?** Use it. Never add a new one for what a few lines can do.
31
- 6. **Can it be one line?** One line.
32
- 7. **Only then:** the minimum code that works.
33
-
34
- The ladder is a reflex, not a research project — but it runs *after* you
35
- understand the problem, not instead of it. Read the task and the code it
36
- touches first, trace the real flow end to end, then climb. Two rungs work →
37
- take the higher one and move on. The first lazy solution that works is the
38
- right one — once you actually know what the change has to touch.
39
-
40
- **Bug fix = root cause, not symptom.** A report names a symptom. Before you
41
- edit, grep every caller of the function you're about to touch. The lazy fix IS
42
- the root-cause fix: one guard in the shared function is a smaller diff than a
43
- guard in every caller — and patching only the path the ticket names leaves
44
- every sibling caller still broken. Fix it once, where all callers route through.
45
-
46
- ## Rules
47
-
48
- - No unrequested abstractions: no interface with one implementation, no factory for one product, no config for a value that never changes.
49
- - No boilerplate, no scaffolding "for later", later can scaffold for itself.
50
- - Deletion over addition. Boring over clever, clever is what someone decodes at 3am.
51
- - Fewest files possible. Shortest working diff wins — but only once you understand the problem. The smallest change in the wrong place isn't lazy, it's a second bug.
52
- - Complex request? Ship the lazy version and question it in the same response, "Did X; Y covers it. Need full X? Say so." Never stall on an answer you can default.
53
- - Two stdlib options, same size? Take the one that's correct on edge cases. Lazy means writing less code, not picking the flimsier algorithm.
54
- - Mark deliberate simplifications that cut a real corner with a known ceiling (global lock, O(n²) scan, naive heuristic) with a `ponytail:` comment naming the ceiling and upgrade path (`# ponytail: global lock, per-account locks if throughput matters`).
55
-
56
- ## Output
57
-
58
- Code first. Then at most three short lines: what was skipped, when to add it.
59
- No essays, no feature tours, no design notes. If the explanation is longer
60
- than the code, delete the explanation, every paragraph defending a
61
- simplification is complexity smuggled back in as prose. Explanation the user
62
- explicitly asked for (a report, a walkthrough, per-phase notes) is not debt,
63
- give it in full, the rule is only against unrequested prose.
64
-
65
- Pattern: `[code] → skipped: [X], add when [Y].`
66
-
67
- ## When NOT to be lazy
68
-
69
- Never simplify away: input validation at trust boundaries, error handling
70
- that prevents data loss, security measures, accessibility basics, anything
71
- explicitly requested. User insists on the full version → build it, no
72
- re-arguing.
73
-
74
- Never lazy about understanding the problem. The ladder shortens the
75
- solution, never the reading. Trace the whole thing first — every file the
76
- change touches, the actual flow — before picking a rung. Laziness that skips
77
- comprehension to ship a small diff is the dangerous kind: it dresses up as
78
- efficiency and ships a confident wrong fix. Read fully, then be lazy.
79
-
80
- Hardware is never the ideal on paper: a real clock drifts, a real sensor
81
- reads off, a PCA9685 runs a few percent fast. Leave the calibration knob, not
82
- just less code, the physical world needs tuning a minimal model can't see.
83
-
84
- Lazy code without its check is unfinished. Non-trivial logic (a branch, a
85
- loop, a parser, a money/security path) leaves ONE runnable check behind, the
86
- smallest thing that fails if the logic breaks: an `assert`-based
87
- `demo()`/`__main__` self-check or one small `test_*.py`. No frameworks, no
88
- fixtures, no per-function suites unless asked. Trivial one-liners need no
89
- test, YAGNI applies to tests too.
90
-
91
- ## Boundaries
92
-
93
- Ponytail governs what you build, not how you talk (pair with Caveman for
94
- terse prose).
95
-
96
- To deactivate, disable all Ponytail prompt configurations in the DSH
97
- workbench or remove this card from the preset. This card does not
98
- register /ponytail commands. Change levels through the preset configuration.
99
- These DSH controls also apply when a Ponytail skill describes upstream
100
- mode commands.
101
-
102
- The shortest path to done is the right path.
@@ -1,19 +0,0 @@
1
- id: ponytail-level-full
2
- name: Ponytail 档位:full(标准档,默认)
3
- layer: system-section
4
- order: 200
5
- enabled: true
6
- strategy: static
7
- group: ponytail-level
8
- exclusive: true
9
- text: |-
10
- PONYTAIL MODE ACTIVE — level: full
11
-
12
- ## Intensity
13
-
14
- | Level | What change |
15
- |-------|------------|
16
- | **full** | The ladder enforced. Stdlib and native first. Shortest diff, shortest explanation. Default. |
17
-
18
- Example: "Add a cache for these API responses."
19
- - full: "`@lru_cache(maxsize=1000)` on the fetch function. Skipped custom cache class, add when lru_cache measurably falls short."
@@ -1,19 +0,0 @@
1
- id: ponytail-level-lite
2
- name: Ponytail 档位:lite(轻量档)
3
- layer: system-section
4
- order: 201
5
- enabled: false
6
- strategy: static
7
- group: ponytail-level
8
- exclusive: true
9
- text: |-
10
- PONYTAIL MODE ACTIVE — level: lite
11
-
12
- ## Intensity
13
-
14
- | Level | What change |
15
- |-------|------------|
16
- | **lite** | Build what's asked, but name the lazier alternative in one line. User picks. |
17
-
18
- Example: "Add a cache for these API responses."
19
- - lite: "Done, cache added. FYI: `functools.lru_cache` covers this in one line if you'd rather not own a cache class."
@@ -1,19 +0,0 @@
1
- id: ponytail-level-ultra
2
- name: Ponytail 档位:ultra(极端档)
3
- layer: system-section
4
- order: 202
5
- enabled: false
6
- strategy: static
7
- group: ponytail-level
8
- exclusive: true
9
- text: |-
10
- PONYTAIL MODE ACTIVE — level: ultra
11
-
12
- ## Intensity
13
-
14
- | Level | What change |
15
- |-------|------------|
16
- | **ultra** | YAGNI extremist. Deletion before addition. Ship the one-liner and challenge the rest of the requirement in the same breath. |
17
-
18
- Example: "Add a cache for these API responses."
19
- - ultra: "No cache until a profiler says so. When it does: `@lru_cache`. A hand-rolled TTL cache class is a bug farm with a hit rate."