pi-ui-extend 1.0.42 → 1.0.45

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 (233) hide show
  1. package/README.md +41 -12
  2. package/dist/app/app.d.ts +10 -0
  3. package/dist/app/app.js +132 -8
  4. package/dist/app/cli/install.js +2 -2
  5. package/dist/app/commands/command-controller.d.ts +4 -0
  6. package/dist/app/commands/command-controller.js +11 -0
  7. package/dist/app/commands/command-git-actions.d.ts +25 -0
  8. package/dist/app/commands/command-git-actions.js +381 -0
  9. package/dist/app/commands/command-host.d.ts +3 -0
  10. package/dist/app/commands/command-host.js +5 -2
  11. package/dist/app/commands/command-model-actions.d.ts +1 -0
  12. package/dist/app/commands/command-model-actions.js +51 -34
  13. package/dist/app/commands/command-navigation-actions.d.ts +1 -0
  14. package/dist/app/commands/command-navigation-actions.js +16 -3
  15. package/dist/app/commands/command-registry.d.ts +2 -0
  16. package/dist/app/commands/command-registry.js +14 -0
  17. package/dist/app/commands/reload-context-inventory.js +12 -1
  18. package/dist/app/input/autocomplete-controller.js +61 -34
  19. package/dist/app/input/input-action-controller.d.ts +2 -0
  20. package/dist/app/input/input-action-controller.js +8 -1
  21. package/dist/app/input/input-controller.d.ts +2 -1
  22. package/dist/app/input/input-controller.js +7 -2
  23. package/dist/app/input/prompt-enhancer-controller.js +53 -35
  24. package/dist/app/input/voice-controller.d.ts +41 -45
  25. package/dist/app/input/voice-controller.js +351 -419
  26. package/dist/app/model/model-usage-controller.js +17 -7
  27. package/dist/app/model/model-usage-status.d.ts +4 -1
  28. package/dist/app/model/model-usage-status.js +270 -46
  29. package/dist/app/popup/menu-items-controller.d.ts +13 -3
  30. package/dist/app/popup/menu-items-controller.js +37 -21
  31. package/dist/app/popup/popup-action-controller.d.ts +12 -2
  32. package/dist/app/popup/popup-action-controller.js +77 -24
  33. package/dist/app/popup/popup-menu-controller.d.ts +36 -14
  34. package/dist/app/popup/popup-menu-controller.js +239 -69
  35. package/dist/app/rendering/dcp-stats.d.ts +9 -4
  36. package/dist/app/rendering/dcp-stats.js +40 -425
  37. package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
  38. package/dist/app/rendering/popup-menu-renderer.js +42 -37
  39. package/dist/app/rendering/render-controller.js +23 -2
  40. package/dist/app/rendering/status-line-renderer.d.ts +5 -0
  41. package/dist/app/rendering/status-line-renderer.js +41 -5
  42. package/dist/app/rendering/tab-line-renderer.js +26 -20
  43. package/dist/app/runtime.d.ts +12 -1
  44. package/dist/app/runtime.js +120 -12
  45. package/dist/app/screen/mouse-controller.d.ts +2 -0
  46. package/dist/app/screen/mouse-controller.js +17 -7
  47. package/dist/app/screen/status-controller.d.ts +4 -0
  48. package/dist/app/screen/status-controller.js +5 -0
  49. package/dist/app/session/lazy-session-manager.js +34 -0
  50. package/dist/app/session/session-event-controller.d.ts +1 -0
  51. package/dist/app/session/session-event-controller.js +10 -1
  52. package/dist/app/session/session-history.d.ts +1 -0
  53. package/dist/app/session/session-history.js +12 -1
  54. package/dist/app/session/session-lifecycle-controller.d.ts +6 -1
  55. package/dist/app/session/session-lifecycle-controller.js +10 -1
  56. package/dist/app/session/tabs-controller.d.ts +25 -1
  57. package/dist/app/session/tabs-controller.js +442 -153
  58. package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
  59. package/dist/app/subagents/subagents-widget-controller.js +6 -0
  60. package/dist/app/types.d.ts +11 -1
  61. package/dist/app/workspace/workspace-actions-controller.js +10 -2
  62. package/dist/app/workspace/workspace-undo.d.ts +1 -0
  63. package/dist/app/workspace/workspace-undo.js +1 -0
  64. package/dist/bundled-extensions/question/index.js +9 -1
  65. package/dist/bundled-extensions/question/remote.d.ts +4 -0
  66. package/dist/bundled-extensions/question/remote.js +33 -0
  67. package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
  68. package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
  69. package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
  70. package/dist/bundled-extensions/telegram-connector/config.js +87 -0
  71. package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
  72. package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
  73. package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
  74. package/dist/bundled-extensions/telegram-connector/index.js +195 -0
  75. package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
  76. package/dist/bundled-extensions/terminal-bell/index.js +0 -76
  77. package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
  78. package/dist/bundled-extensions/workspace-undo/index.js +191 -0
  79. package/dist/config.d.ts +21 -2
  80. package/dist/config.js +159 -32
  81. package/dist/default-pix-config.js +20 -10
  82. package/dist/schemas/pi-tools-suite-schema.d.ts +8 -4
  83. package/dist/schemas/pi-tools-suite-schema.js +11 -5
  84. package/dist/schemas/pix-schema.d.ts +12 -2
  85. package/dist/schemas/pix-schema.js +37 -9
  86. package/dist/schemas/tasks-schema.js +1 -1
  87. package/docs/concurrency.md +3 -1
  88. package/docs/desktop-mvp.md +10 -5
  89. package/docs/desktop-task-manager.md +81 -28
  90. package/docs/release.md +30 -6
  91. package/external/pi-tools-suite/README.md +165 -39
  92. package/external/pi-tools-suite/docs/session-recovery.md +7 -0
  93. package/external/pi-tools-suite/docs/subagent-model-pools.md +12 -5
  94. package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
  95. package/external/pi-tools-suite/package.json +6 -1
  96. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
  97. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
  98. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
  99. package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
  100. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
  101. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
  102. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
  103. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
  104. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
  105. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
  106. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
  107. package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
  108. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
  109. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
  110. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
  111. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
  112. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
  113. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
  114. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
  115. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
  116. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
  117. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
  118. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
  119. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
  120. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
  121. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
  122. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
  123. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
  124. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
  125. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
  126. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
  127. package/external/pi-tools-suite/src/async-subagents/commands.ts +1 -1
  128. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
  129. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +0 -2
  130. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
  131. package/external/pi-tools-suite/src/async-subagents/core/config.ts +40 -17
  132. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
  133. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
  134. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +7 -4
  135. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +34 -24
  136. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
  137. package/external/pi-tools-suite/src/async-subagents/lib.ts +9 -1
  138. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +0 -1
  139. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +2 -2
  140. package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
  141. package/external/pi-tools-suite/src/config.ts +14 -0
  142. package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
  143. package/external/pi-tools-suite/src/context-gateway/config.ts +66 -1
  144. package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
  145. package/external/pi-tools-suite/src/context-gateway/enforcement.ts +123 -3
  146. package/external/pi-tools-suite/src/context-gateway/index.ts +137 -4
  147. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +5 -5
  148. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +2 -2
  149. package/external/pi-tools-suite/src/context-gateway/types.ts +8 -1
  150. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
  151. package/external/pi-tools-suite/src/dcp/auto-compress.ts +41 -14
  152. package/external/pi-tools-suite/src/dcp/commands.ts +14 -156
  153. package/external/pi-tools-suite/src/dcp/compress-tool.ts +8 -2
  154. package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
  155. package/external/pi-tools-suite/src/dcp/config.ts +58 -4
  156. package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
  157. package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
  158. package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
  159. package/external/pi-tools-suite/src/dcp/index.ts +338 -66
  160. package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
  161. package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
  162. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +92 -2
  163. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
  164. package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
  165. package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
  166. package/external/pi-tools-suite/src/dcp/state.ts +9 -0
  167. package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
  168. package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
  169. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +68 -16
  170. package/external/pi-tools-suite/src/lib/project.ts +36 -1
  171. package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
  172. package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
  173. package/external/pi-tools-suite/src/resource-registry/index.ts +282 -21
  174. package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
  175. package/external/pi-tools-suite/src/todo/index.ts +21 -0
  176. package/external/pi-tools-suite/src/todo/todo.ts +19 -1
  177. package/external/pi-tools-suite/src/tool-descriptions.ts +44 -15
  178. package/package.json +7 -8
  179. package/schemas/pi-tools-suite.json +44 -12
  180. package/schemas/pix.json +109 -15
  181. package/schemas/tasks.json +1 -2
  182. package/skills/simplify/SKILL.md +33 -5
  183. package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -196
  184. package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
  185. package/skills/playwright-cli/SKILL.md +0 -420
  186. package/skills/playwright-cli/references/element-attributes.md +0 -23
  187. package/skills/playwright-cli/references/playwright-tests.md +0 -50
  188. package/skills/playwright-cli/references/request-mocking.md +0 -87
  189. package/skills/playwright-cli/references/running-code.md +0 -241
  190. package/skills/playwright-cli/references/session-management.md +0 -273
  191. package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
  192. package/skills/playwright-cli/references/storage-state.md +0 -290
  193. package/skills/playwright-cli/references/test-generation.md +0 -142
  194. package/skills/playwright-cli/references/tracing.md +0 -154
  195. package/skills/playwright-cli/references/video-recording.md +0 -147
  196. package/skills/spec-wiki/SKILL.md +0 -55
  197. package/skills/spec-wiki/evals/evals.json +0 -132
  198. package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +0 -14
  199. package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +0 -4
  200. package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +0 -9
  201. package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +0 -17
  202. package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +0 -12
  203. package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +0 -11
  204. package/skills/spec-wiki/evals/files/focused/src/session.ts +0 -5
  205. package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +0 -17
  206. package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +0 -2
  207. package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +0 -3
  208. package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +0 -18
  209. package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +0 -5
  210. package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +0 -24
  211. package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +0 -7
  212. package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +0 -7
  213. package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +0 -17
  214. package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +0 -3
  215. package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +0 -3
  216. package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +0 -4
  217. package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +0 -9
  218. package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +0 -15
  219. package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +0 -6
  220. package/skills/spec-wiki/evals/maintenance_regression.py +0 -311
  221. package/skills/spec-wiki/evals/retrieval-eval.md +0 -37
  222. package/skills/spec-wiki/evals/retrieval-evals.json +0 -37
  223. package/skills/spec-wiki/evals/trigger-evals.json +0 -94
  224. package/skills/spec-wiki/references/bootstrap.md +0 -100
  225. package/skills/spec-wiki/references/focused-spec.md +0 -117
  226. package/skills/spec-wiki/references/index-schema.md +0 -330
  227. package/skills/spec-wiki/references/maintenance.md +0 -134
  228. package/skills/spec-wiki/references/query.md +0 -74
  229. package/skills/spec-wiki/scripts/spec_wiki.py +0 -2076
  230. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
  231. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
  232. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
  233. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
@@ -1,17 +0,0 @@
1
- # Payment capture requirements
2
-
3
- ## Behavior
4
-
5
- - A capture request with the same idempotency key must not charge twice.
6
- - A successful capture returns the existing capture result when the same key is
7
- replayed.
8
- - A different amount with a reused idempotency key is rejected.
9
-
10
- ## Related files
11
-
12
- - `src/payments.ts`
13
- - `tests/payments.test.ts`
14
-
15
- ## Verification
16
-
17
- Cover first capture, exact replay, and conflicting replay.
@@ -1,12 +0,0 @@
1
- const captures = new Map<string, { amount: number; id: string }>();
2
-
3
- export function capture(key: string, amount: number): { amount: number; id: string } {
4
- const existing = captures.get(key);
5
- if (existing) {
6
- if (existing.amount !== amount) throw new Error("idempotency conflict");
7
- return existing;
8
- }
9
- const result = { amount, id: `capture-${captures.size + 1}` };
10
- captures.set(key, result);
11
- return result;
12
- }
@@ -1,11 +0,0 @@
1
- // @ts-nocheck
2
- import assert from "node:assert/strict";
3
- import { test } from "node:test";
4
-
5
- import { capture } from "../src/payments.js";
6
-
7
- test("idempotent replay returns the same capture", () => {
8
- const first = capture("key-1", 100);
9
- assert.deepEqual(capture("key-1", 100), first);
10
- assert.throws(() => capture("key-1", 200), /idempotency conflict/);
11
- });
@@ -1,5 +0,0 @@
1
- export type TokenLoader = () => Promise<string>;
2
-
3
- export async function refreshSession(loadToken: TokenLoader): Promise<string> {
4
- return loadToken();
5
- }
@@ -1,17 +0,0 @@
1
- // @ts-nocheck
2
- import assert from "node:assert/strict";
3
- import { test } from "node:test";
4
-
5
- import { refreshSession } from "../src/session.js";
6
-
7
- test("refreshSession performs one token-load attempt", async () => {
8
- let attempts = 0;
9
- await assert.rejects(
10
- refreshSession(async () => {
11
- attempts += 1;
12
- throw new Error("transient");
13
- }),
14
- /transient/,
15
- );
16
- assert.equal(attempts, 1);
17
- });
@@ -1,2 +0,0 @@
1
- Duplicate capture requests with the same idempotency key return the original result.
2
- This rule describes current production behavior for capture requests.
@@ -1,3 +0,0 @@
1
- export function capture(idempotencyKey: string, previous?: string): string {
2
- return previous ?? `capture:${idempotencyKey}`;
3
- }
@@ -1,18 +0,0 @@
1
- # Background job cancellation contract
2
-
3
- ## Type
4
-
5
- As-is
6
-
7
- ## Lifecycle
8
-
9
- Active
10
-
11
- ## Behavior
12
-
13
- Cancelling a running job is idempotent. Running jobs become cancelled; already
14
- terminal jobs remain terminal.
15
-
16
- ## Related files
17
-
18
- - `src/job.ts`
@@ -1,5 +0,0 @@
1
- export type JobState = "running" | "done" | "failed" | "cancelled";
2
-
3
- export function cancelJob(state: JobState): JobState {
4
- return state === "running" ? "cancelled" : state;
5
- }
@@ -1,24 +0,0 @@
1
- # Session refresh contract
2
-
3
- ## Type
4
-
5
- As-is
6
-
7
- ## Lifecycle
8
-
9
- Active
10
-
11
- ## Behavior
12
-
13
- Interactive and background session refresh retry a transient token-acquisition
14
- failure exactly once. A second token-acquisition failure propagates to the
15
- caller. Successful acquisition is not retried.
16
-
17
- ## Related files
18
-
19
- - `src/session.ts`
20
-
21
- ## Verification
22
-
23
- - Interactive refresh covers success, retry-success, and second-failure paths.
24
- - Every additional refresh entrypoint must preserve the same retry contract.
@@ -1,7 +0,0 @@
1
- export async function refreshInBackground(loadToken: () => Promise<string>): Promise<string> {
2
- try {
3
- return await loadToken();
4
- } catch {
5
- return await loadToken();
6
- }
7
- }
@@ -1,7 +0,0 @@
1
- export async function refreshSession(loadToken: () => Promise<string>): Promise<string> {
2
- try {
3
- return await loadToken();
4
- } catch {
5
- return await loadToken();
6
- }
7
- }
@@ -1,17 +0,0 @@
1
- # Authentication contract
2
-
3
- ## Type
4
-
5
- As-is
6
-
7
- ## Lifecycle
8
-
9
- Active
10
-
11
- ## Behavior
12
-
13
- Authentication accepts a valid token and rejects an empty token.
14
-
15
- ## Related files
16
-
17
- - `src/auth.ts`
@@ -1,3 +0,0 @@
1
- export function formatTelemetryName(name: string): string {
2
- return name.trim().toLowerCase();
3
- }
@@ -1,3 +0,0 @@
1
- export function authenticate(token: string): boolean {
2
- return token.length > 0;
3
- }
@@ -1,4 +0,0 @@
1
- # How to run jobs locally
2
-
3
- Start the worker, enqueue a sample job, and tail the development log. This is a
4
- usage guide and does not define cancellation semantics.
@@ -1,9 +0,0 @@
1
- # Job specifications overview
2
-
3
- The primary job behavior documents are linked below.
4
-
5
- - [Cancellation contract](../features/jobs/cancellation-contract.md) — jobs can
6
- be stopped safely.
7
- - [Retry spec](../features/jobs/retry-spec.md) — retry timing and limits.
8
-
9
- This page is a catalog, not a behavioral source of truth.
@@ -1,15 +0,0 @@
1
- # Background job cancellation contract
2
-
3
- ## Behavior
4
-
5
- - Cancellation requests are idempotent.
6
- - A running job transitions to `cancelled` when cancellation is accepted.
7
- - Jobs already in `completed`, `failed`, or `cancelled` remain in that terminal
8
- state when cancellation is requested again.
9
- - Cancellation does not imply that already-committed external side effects are
10
- rolled back.
11
-
12
- ## Verification
13
-
14
- Tests should cover repeated cancellation, running-to-cancelled transition, and
15
- all terminal states.
@@ -1,6 +0,0 @@
1
- # Background job retry behavior
2
-
3
- ## Behavior
4
-
5
- Failed jobs retry at most three times with exponential backoff. Cancellation is
6
- outside this document's scope.
@@ -1,311 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Deterministic regression checks for Spec Wiki maintenance primitives."""
3
-
4
- from __future__ import annotations
5
-
6
- import json
7
- import subprocess
8
- import tempfile
9
- from pathlib import Path
10
-
11
-
12
- CLI = Path(__file__).resolve().parents[1] / "scripts" / "spec_wiki.py"
13
-
14
-
15
- def run(cwd: Path, *args: str) -> str:
16
- proc = subprocess.run(
17
- ["python3", str(CLI), "--root", str(cwd), *args],
18
- cwd=cwd,
19
- text=True,
20
- stdout=subprocess.PIPE,
21
- stderr=subprocess.PIPE,
22
- check=False,
23
- )
24
- if proc.returncode != 0:
25
- raise AssertionError(f"command failed {args}:\nstdout={proc.stdout}\nstderr={proc.stderr}")
26
- return proc.stdout
27
-
28
-
29
- def run_json(cwd: Path, *args: str) -> dict:
30
- return json.loads(run(cwd, *args, "--json"))
31
-
32
-
33
- def git(cwd: Path, *args: str) -> None:
34
- subprocess.run(["git", *args], cwd=cwd, check=True, stdout=subprocess.DEVNULL)
35
-
36
-
37
- def write(root: Path, rel: str, text: str) -> None:
38
- path = root / rel
39
- path.parent.mkdir(parents=True, exist_ok=True)
40
- path.write_text(text, encoding="utf-8")
41
-
42
-
43
- def init_repo(root: Path) -> None:
44
- git(root, "init", "-q")
45
- git(root, "config", "user.email", "spec-wiki-eval@example.com")
46
- git(root, "config", "user.name", "Spec Wiki Eval")
47
-
48
-
49
- def commit_all(root: Path, message: str = "baseline") -> None:
50
- git(root, "add", ".")
51
- git(root, "commit", "-qm", message)
52
-
53
-
54
- def test_relation_map_invalidates_verification(tmp: Path) -> None:
55
- root = tmp / "relations"
56
- root.mkdir()
57
- init_repo(root)
58
- write(root, "src/a.ts", "export const a = 1\n")
59
- write(root, "src/b.ts", "export const b = 2\n")
60
- write(
61
- root,
62
- "docs/contract.md",
63
- """# Contract
64
-
65
- ## Type
66
- As-is
67
-
68
- ## Lifecycle
69
- Active
70
-
71
- ## Behavior
72
- A is part of the current contract.
73
-
74
- ## Related files
75
- - `src/a.ts`
76
- """,
77
- )
78
- commit_all(root)
79
- run(
80
- root,
81
- "record",
82
- "--path",
83
- "docs/contract.md",
84
- "--classification",
85
- "spec",
86
- "--type",
87
- "as-is",
88
- "--lifecycle",
89
- "active",
90
- "--confidence",
91
- "high",
92
- "--summary",
93
- "Contract for A.",
94
- )
95
- run(root, "verify", "--path", "docs/contract.md")
96
- audit = run_json(root, "audit")
97
- assert audit["freshCount"] == 1
98
-
99
- run(root, "relate", "--path", "docs/contract.md", "--add-code", "src/b.ts")
100
- audit = run_json(root, "audit")
101
- assert audit["freshCount"] == 0
102
- status = next(item for item in audit["statuses"] if item["path"] == "docs/contract.md")
103
- assert status["status"] == "inputs-changed"
104
- assert "relations:changed" in status["reasons"]
105
-
106
- run(root, "verify", "--path", "docs/contract.md")
107
- assert run_json(root, "audit")["freshCount"] == 1
108
- run(root, "relate", "--path", "docs/contract.md", "--remove-code", "src/b.ts")
109
- status = next(item for item in run_json(root, "audit")["statuses"] if item["path"] == "docs/contract.md")
110
- assert status["status"] == "inputs-changed"
111
- assert status["reasons"] == ["relations:changed"]
112
-
113
-
114
- def test_impact_detects_coverage_gaps_and_moves(tmp: Path) -> None:
115
- root = tmp / "impact"
116
- root.mkdir()
117
- init_repo(root)
118
- write(root, "src/session.ts", "export function session() { return 'ok' }\n")
119
- write(
120
- root,
121
- "docs/session-contract.md",
122
- """# Session contract
123
-
124
- ## Type
125
- As-is
126
-
127
- ## Lifecycle
128
- Active
129
-
130
- ## Behavior
131
- Session loading returns the current session.
132
-
133
- ## Related files
134
- - `src/session.ts`
135
- """,
136
- )
137
- commit_all(root)
138
- run(
139
- root,
140
- "record",
141
- "--path",
142
- "docs/session-contract.md",
143
- "--classification",
144
- "spec",
145
- "--type",
146
- "as-is",
147
- "--lifecycle",
148
- "active",
149
- "--confidence",
150
- "high",
151
- "--summary",
152
- "Session loading contract.",
153
- )
154
- run(root, "verify", "--path", "docs/session-contract.md")
155
-
156
- git(root, "mv", "docs/session-contract.md", "docs/session-lifecycle.md")
157
- with (root / "docs/session-lifecycle.md").open("a", encoding="utf-8") as handle:
158
- handle.write("\nMoved without changing the behavioral contract.\n")
159
- write(root, "src/refresh-worker.ts", "export const retryOnce = true\n")
160
- write(root, "notes.txt", "deliberately low signal document\n")
161
-
162
- impact = run_json(root, "impact")
163
- assert ".spec-wiki/state.json" not in impact["changedPaths"]
164
- assert any(
165
- item.get("status") == "R"
166
- and item.get("oldPath") == "docs/session-contract.md"
167
- and item.get("path") == "docs/session-lifecycle.md"
168
- for item in impact["changes"]
169
- )
170
- assert "src/refresh-worker.ts" in impact["uncoveredPaths"]
171
- changed_docs = {item["path"]: item for item in impact["changedDocuments"]}
172
- assert changed_docs["docs/session-lifecycle.md"]["requiresClassification"] is True
173
- assert changed_docs["notes.txt"]["score"] == 0
174
- assert "docs/session-contract.md" in impact["missingTrackedSpecs"]
175
- assert impact["semanticSweepRequired"] is True
176
-
177
-
178
- def test_deep_audit_finds_low_signal_committed_docs(tmp: Path) -> None:
179
- root = tmp / "deep"
180
- root.mkdir()
181
- init_repo(root)
182
- write(
183
- root,
184
- "notes/capture.txt",
185
- "Duplicate capture requests with the same key return the original result.\n",
186
- )
187
- write(root, "skills/example/evals/fixture.md", "# Contract\n\n## Behavior\nFixture only.\n")
188
- commit_all(root)
189
-
190
- normal = run_json(root, "discover", "--limit", "100")
191
- assert "notes/capture.txt" not in {item["path"] for item in normal["candidates"]}
192
- deep = run_json(root, "discover", "--all-unclassified", "--limit", "100")
193
- paths = {item["path"] for item in deep["candidates"]}
194
- assert "notes/capture.txt" in paths
195
- assert "skills/example/evals/fixture.md" not in paths
196
-
197
-
198
- def test_relate_restores_source_explicit_relation(tmp: Path) -> None:
199
- root = tmp / "supersession"
200
- root.mkdir()
201
- init_repo(root)
202
- write(root, "docs/b.md", "# B\n")
203
- write(
204
- root,
205
- "docs/a.md",
206
- """# A contract
207
-
208
- ## Type
209
- As-is
210
-
211
- ## Lifecycle
212
- Active
213
-
214
- ## Behavior
215
- A references B.
216
-
217
- [B](./b.md)
218
- """,
219
- )
220
- commit_all(root)
221
- run(
222
- root,
223
- "record",
224
- "--path",
225
- "docs/a.md",
226
- "--classification",
227
- "spec",
228
- "--type",
229
- "as-is",
230
- "--lifecycle",
231
- "active",
232
- "--confidence",
233
- "high",
234
- "--summary",
235
- "A contract.",
236
- )
237
- run(root, "verify", "--path", "docs/a.md")
238
- run(root, "relate", "--path", "docs/a.md", "--add-supersedes", "docs/b.md")
239
- state = json.loads((root / ".spec-wiki/state.json").read_text(encoding="utf-8"))
240
- relations = state["entries"]["docs/a.md"]["relations"]["specs"]
241
- assert any(
242
- item.get("path") == "docs/b.md"
243
- and item.get("source") == "explicit"
244
- and item.get("kind") == "related"
245
- for item in relations
246
- )
247
- assert any(item.get("path") == "docs/b.md" and item.get("kind") == "supersedes" for item in relations)
248
- run(root, "relate", "--path", "docs/a.md", "--remove-supersedes", "docs/b.md")
249
- state = json.loads((root / ".spec-wiki/state.json").read_text(encoding="utf-8"))
250
- relations = state["entries"]["docs/a.md"]["relations"]["specs"]
251
- assert any(
252
- item.get("path") == "docs/b.md"
253
- and item.get("source") == "explicit"
254
- and item.get("kind") == "related"
255
- for item in relations
256
- )
257
- assert not any(item.get("kind") == "supersedes" for item in relations)
258
-
259
-
260
- def test_changed_non_primary_requires_reclassification(tmp: Path) -> None:
261
- root = tmp / "reclassification"
262
- root.mkdir()
263
- init_repo(root)
264
- write(root, "docs/info.md", "# Operator notes\n\nRun the service with --help.\n")
265
- commit_all(root)
266
- run(
267
- root,
268
- "record",
269
- "--path",
270
- "docs/info.md",
271
- "--classification",
272
- "guide",
273
- "--summary",
274
- "Operator notes.",
275
- )
276
- write(
277
- root,
278
- "docs/info.md",
279
- """# Request contract
280
-
281
- ## Type
282
- As-is
283
-
284
- ## Lifecycle
285
- Active
286
-
287
- ## Behavior
288
- Duplicate requests return the original result.
289
- """,
290
- )
291
- impact = run_json(root, "impact", "docs/info.md")
292
- changed = next(item for item in impact["changedDocuments"] if item["path"] == "docs/info.md")
293
- assert changed["knownClassification"] == "guide"
294
- assert changed["requiresClassification"] is False
295
- assert changed["requiresReclassification"] is True
296
- assert impact["semanticSweepRequired"] is True
297
-
298
-
299
- def main() -> None:
300
- with tempfile.TemporaryDirectory(prefix="spec-wiki-maint-") as directory:
301
- tmp = Path(directory)
302
- test_relation_map_invalidates_verification(tmp)
303
- test_impact_detects_coverage_gaps_and_moves(tmp)
304
- test_deep_audit_finds_low_signal_committed_docs(tmp)
305
- test_relate_restores_source_explicit_relation(tmp)
306
- test_changed_non_primary_requires_reclassification(tmp)
307
- print("maintenance regression: 5/5 passed")
308
-
309
-
310
- if __name__ == "__main__":
311
- main()
@@ -1,37 +0,0 @@
1
- # Retrieval regression protocol
2
-
3
- Use `retrieval-evals.json` to check the query router after search/index changes.
4
- The cases are intentionally mixed: direct keywords, natural paraphrases,
5
- Russian requests, synonyms, exact code paths, and symbols.
6
-
7
- ## Guard against answer leakage
8
-
9
- The retrieval agent must receive only each case `id` and `query`. Do not expose
10
- `expectedAny` until after it returns candidate paths.
11
-
12
- ## Stage 1: deterministic candidate generation
13
-
14
- Run `spec_wiki.py search` against the current `.spec-wiki/state.json` and record
15
- top-1/top-3/top-5 plus `confidence` / `catalogFallbackRecommended`. This stage is
16
- expected to be imperfect for semantic paraphrases; its job is cheap candidate
17
- generation and reliable low-confidence detection.
18
-
19
- ## Stage 2: full skill workflow
20
-
21
- Have a fresh agent read only `SKILL.md` and `references/query.md`, then for each
22
- query:
23
-
24
- 1. create the in-model retrieval bundle;
25
- 2. call relation-aware `search` with `--also` aliases;
26
- 3. semantically rerank compact result metadata;
27
- 4. when fallback is recommended or intent coverage is visibly incomplete, use
28
- only `.spec-wiki/index.md` as the semantic catalog fallback;
29
- 5. return up to three primary spec paths without opening the primary specs.
30
-
31
- Compare those paths with `expectedAny` only after the run. A case passes top-k
32
- when any expected path appears in the first k selections.
33
-
34
- Current target for this repository: at least 95% top-1 and 100% top-3/recall.
35
- Do not tune expected paths after seeing a run merely to improve the score; change
36
- an expectation only when independent review shows that more than one primary
37
- spec is genuinely defensible.
@@ -1,37 +0,0 @@
1
- {
2
- "version": 1,
3
- "description": "Live retrieval regression cases for the host repository. Expected paths are chosen before running the search; use expectedAny when more than one primary spec is defensible.",
4
- "cases": [
5
- {"id":"kw-dcp","category":"keyword","query":"dcp persistence recovery","expectedAny":["specs/dcp.md"]},
6
- {"id":"kw-desktop-markdown","category":"keyword","query":"desktop markdown mermaid file preview","expectedAny":["specs/desktop-markdown-rendering.md"]},
7
- {"id":"kw-project-agents","category":"keyword","query":"project local agents .pi/agents","expectedAny":["specs/project-agents-dir.md"]},
8
- {"id":"kw-question-tab","category":"keyword","query":"question inactive tab","expectedAny":["specs/question-inactive-tab.md"]},
9
- {"id":"kw-retry-toast","category":"keyword","query":"retry toast action","expectedAny":["specs/retry-toast-action.md"]},
10
- {"id":"kw-openai-usage","category":"keyword","query":"openai codex token refresh usage","expectedAny":["specs/openai-codex-usage-refresh.md"]},
11
-
12
- {"id":"para-recovery","category":"paraphrase","query":"recover old conversation after compaction","expectedAny":["external/pi-tools-suite/docs/session-recovery.md"]},
13
- {"id":"para-browser-qa","category":"paraphrase","query":"browser qa credentials origin isolation redaction","expectedAny":["external/pi-tools-suite/docs/browser-qa-subagent.md"]},
14
- {"id":"para-concurrency","category":"paraphrase","query":"async callback updates the wrong session tab","expectedAny":["docs/concurrency.md"]},
15
- {"id":"para-cache","category":"paraphrase","query":"keep tool output stable for prompt caching","expectedAny":["specs/dcp-provider-cache-stability.md"]},
16
- {"id":"para-window","category":"paraphrase","query":"window opens offscreen after monitor change","expectedAny":["specs/desktop-window-state.md"]},
17
- {"id":"para-copy","category":"paraphrase","query":"copy last assistant response slash command","expectedAny":["specs/desktop-slash-commands.md"]},
18
- {"id":"para-task-jsonc","category":"paraphrase","query":"task storage comments jsonc","expectedAny":["docs/desktop-task-manager.md"]},
19
- {"id":"para-wrapped-link","category":"paraphrase","query":"click file uri in wrapped markdown","expectedAny":["specs/clickable-markdown-links.md"]},
20
- {"id":"para-zed","category":"paraphrase","query":"open source file in zed at line","expectedAny":["specs/file-link-opening.md"]},
21
-
22
- {"id":"ru-recovery","category":"russian","query":"как восстанавливается история после сжатия контекста","expectedAny":["external/pi-tools-suite/docs/session-recovery.md"]},
23
- {"id":"ru-zed","category":"russian","query":"как открыть ссылку на файл в zed","expectedAny":["specs/file-link-opening.md"]},
24
- {"id":"ru-question-tab","category":"russian","query":"что происходит с вопросом в неактивной вкладке","expectedAny":["specs/question-inactive-tab.md"]},
25
- {"id":"ru-tasks","category":"russian","query":"где хранятся задачи проекта и поддерживаются ли комментарии","expectedAny":["docs/desktop-task-manager.md"]},
26
- {"id":"ru-provider-seen","category":"russian","query":"почему старый tool result нельзя удалять до отправки провайдеру","expectedAny":["specs/dcp-provider-cache-stability.md"]},
27
-
28
- {"id":"syn-auth","category":"synonym","query":"oauth account rotation when quota exhausted","expectedAny":["specs/antigravity-auth.md"]},
29
- {"id":"syn-background-agent","category":"synonym","query":"cancel a running background agent","expectedAny":["specs/async-subagents.md"]},
30
-
31
- {"id":"path-openai","category":"path","query":"src/app/model/model-usage-status.ts","expectedAny":["specs/openai-codex-usage-refresh.md"]},
32
- {"id":"path-dcp-journal","category":"path","query":"external/pi-tools-suite/src/dcp/journal.ts","expectedAny":["specs/dcp.md","specs/dcp-reliability-mechanisms.md","specs/dcp-provider-cache-stability.md"]},
33
-
34
- {"id":"symbol-sidebar","category":"symbol","query":"WorkspaceSidebar.svelte tasks","expectedAny":["docs/desktop-task-manager.md"]},
35
- {"id":"symbol-question-bridge","category":"symbol","query":"ui-request-bridge question","expectedAny":["specs/desktop-question-tool.md"]}
36
- ]
37
- }