pstack-dsh 0.2.3

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 (172) hide show
  1. package/HARNESS.md +109 -0
  2. package/LICENSE +25 -0
  3. package/README.md +168 -0
  4. package/TEST-PLAN.md +70 -0
  5. package/agents/comment-sicko.md +32 -0
  6. package/agents/poteto-agent.md +9 -0
  7. package/cordis.patch.yml +4 -0
  8. package/cordis.yml +4 -0
  9. package/docs/guide/01-setup.md +41 -0
  10. package/docs/guide/02-poteto-mode.md +98 -0
  11. package/docs/guide/03-understand.md +53 -0
  12. package/docs/guide/04-design.md +81 -0
  13. package/docs/guide/05-build-and-clean.md +75 -0
  14. package/docs/guide/06-verify-and-ship.md +87 -0
  15. package/docs/guide/07-overnight.md +81 -0
  16. package/docs/guide/08-principles.md +71 -0
  17. package/docs/guide/09-make-it-yours.md +67 -0
  18. package/docs/guide/10-recipes-and-pitfalls.md +96 -0
  19. package/docs/guide/README.md +30 -0
  20. package/dshx.yml +9 -0
  21. package/lib/client.js +981 -0
  22. package/lib/client.js.map +1 -0
  23. package/lib/index.d.ts +34 -0
  24. package/lib/index.js +1120 -0
  25. package/package.json +140 -0
  26. package/skills/architect/SKILL.md +83 -0
  27. package/skills/architect/references/design-red-flags.md +33 -0
  28. package/skills/architect/references/rationale-template.md +35 -0
  29. package/skills/architect/references/runner-prompt.md +20 -0
  30. package/skills/arena/SKILL.md +73 -0
  31. package/skills/automate-me/SKILL.md +103 -0
  32. package/skills/blast-radius/SKILL.md +50 -0
  33. package/skills/bro/SKILL.md +7 -0
  34. package/skills/create-verification-skill/SKILL.md +44 -0
  35. package/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
  36. package/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
  37. package/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
  38. package/skills/figure-it-out/SKILL.md +53 -0
  39. package/skills/how/SKILL.md +45 -0
  40. package/skills/how/references/explainer-prompt.md +55 -0
  41. package/skills/how/references/explorer-prompt.md +52 -0
  42. package/skills/interrogate/SKILL.md +99 -0
  43. package/skills/interrogate/references/code-quality-review.md +47 -0
  44. package/skills/interrogate/references/lead-judgment.md +58 -0
  45. package/skills/interrogate/references/reviewer-prompt.md +72 -0
  46. package/skills/interrogate/references/rubric.md +77 -0
  47. package/skills/maintain-verification-skill/SKILL.md +39 -0
  48. package/skills/no-comments/SKILL.md +24 -0
  49. package/skills/poteto-mode/SKILL.md +149 -0
  50. package/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
  51. package/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
  52. package/skills/poteto-mode/playbooks/autopilot-full.md +13 -0
  53. package/skills/poteto-mode/playbooks/autopilot-stack.md +16 -0
  54. package/skills/poteto-mode/playbooks/babysit.md +27 -0
  55. package/skills/poteto-mode/playbooks/bug-fix.md +17 -0
  56. package/skills/poteto-mode/playbooks/eval.md +25 -0
  57. package/skills/poteto-mode/playbooks/feature.md +21 -0
  58. package/skills/poteto-mode/playbooks/hillclimb.md +21 -0
  59. package/skills/poteto-mode/playbooks/investigation.md +14 -0
  60. package/skills/poteto-mode/playbooks/multi-phase-plan.md +156 -0
  61. package/skills/poteto-mode/playbooks/opening-a-pr.md +33 -0
  62. package/skills/poteto-mode/playbooks/orchestrate.md +113 -0
  63. package/skills/poteto-mode/playbooks/pause-safely.md +10 -0
  64. package/skills/poteto-mode/playbooks/perf-issue.md +24 -0
  65. package/skills/poteto-mode/playbooks/prototype.md +14 -0
  66. package/skills/poteto-mode/playbooks/refactoring.md +16 -0
  67. package/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
  68. package/skills/poteto-mode/playbooks/session-pickup.md +11 -0
  69. package/skills/poteto-mode/playbooks/shipping.md +17 -0
  70. package/skills/poteto-mode/playbooks/trace-forensics.md +14 -0
  71. package/skills/poteto-mode/playbooks/visual-parity.md +11 -0
  72. package/skills/poteto-mode/playbooks/worktree-cleanup.md +14 -0
  73. package/skills/poteto-mode/references/bugbot-triage.md +142 -0
  74. package/skills/poteto-mode/scripts/bootstrap.ts +62 -0
  75. package/skills/poteto-mode/scripts/bun.lock +67 -0
  76. package/skills/poteto-mode/scripts/check-plan.mjs +186 -0
  77. package/skills/poteto-mode/scripts/orch/orch.test.ts +634 -0
  78. package/skills/poteto-mode/scripts/orch/orch.ts +578 -0
  79. package/skills/poteto-mode/scripts/orch/store.ts +1607 -0
  80. package/skills/poteto-mode/scripts/package.json +16 -0
  81. package/skills/poteto-mode/scripts/watch-pr/cli.test.ts +224 -0
  82. package/skills/poteto-mode/scripts/watch-pr/cli.ts +223 -0
  83. package/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.ts +118 -0
  84. package/skills/poteto-mode/scripts/watch-pr/github.test.ts +306 -0
  85. package/skills/poteto-mode/scripts/watch-pr/github.ts +699 -0
  86. package/skills/poteto-mode/scripts/watch-pr/policy.test.ts +420 -0
  87. package/skills/poteto-mode/scripts/watch-pr/policy.ts +832 -0
  88. package/skills/poteto-mode/scripts/watch-pr/render.ts +169 -0
  89. package/skills/poteto-mode/scripts/watch-pr/tsconfig.json +13 -0
  90. package/skills/poteto-mode/scripts/watch-pr/types.compile.ts +93 -0
  91. package/skills/poteto-mode/scripts/watch-pr/types.ts +401 -0
  92. package/skills/poteto-mode/scripts/watch-pr/watch-pr +6 -0
  93. package/skills/poteto-mode/scripts/worktree-audit.sh +86 -0
  94. package/skills/principle-attack-the-premise/SKILL.md +22 -0
  95. package/skills/principle-boundary-discipline/SKILL.md +33 -0
  96. package/skills/principle-build-the-lever/SKILL.md +22 -0
  97. package/skills/principle-encode-lessons-in-structure/SKILL.md +30 -0
  98. package/skills/principle-exhaust-the-design-space/SKILL.md +20 -0
  99. package/skills/principle-experience-first/SKILL.md +18 -0
  100. package/skills/principle-fix-root-causes/SKILL.md +22 -0
  101. package/skills/principle-foundational-thinking/SKILL.md +20 -0
  102. package/skills/principle-guard-the-context-window/SKILL.md +16 -0
  103. package/skills/principle-laziness-protocol/SKILL.md +17 -0
  104. package/skills/principle-make-operations-idempotent/SKILL.md +23 -0
  105. package/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +21 -0
  106. package/skills/principle-minimize-reader-load/SKILL.md +22 -0
  107. package/skills/principle-model-the-domain/SKILL.md +25 -0
  108. package/skills/principle-never-block-on-the-human/SKILL.md +21 -0
  109. package/skills/principle-outcome-oriented-execution/SKILL.md +21 -0
  110. package/skills/principle-prove-it-works/SKILL.md +32 -0
  111. package/skills/principle-redesign-from-first-principles/SKILL.md +15 -0
  112. package/skills/principle-separate-before-serializing-shared-state/SKILL.md +15 -0
  113. package/skills/principle-sequence-verifiable-units/SKILL.md +21 -0
  114. package/skills/principle-subtract-before-you-add/SKILL.md +20 -0
  115. package/skills/principle-test-behavior-not-implementation/SKILL.md +24 -0
  116. package/skills/principle-type-system-discipline/SKILL.md +30 -0
  117. package/skills/recall/SKILL.md +35 -0
  118. package/skills/reflect/SKILL.md +65 -0
  119. package/skills/reflect/references/divergent-reviewer.md +43 -0
  120. package/skills/reflect/references/judgment-reviewer.md +42 -0
  121. package/skills/reflect/references/synthesizer.md +56 -0
  122. package/skills/reflect/references/tooling-reviewer.md +55 -0
  123. package/skills/setup-pstack/SKILL.md +32 -0
  124. package/skills/setup-pstack/references/catalog.md +28 -0
  125. package/skills/setup-pstack/references/spawn.md +61 -0
  126. package/skills/show-me-your-work/SKILL.md +82 -0
  127. package/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
  128. package/skills/show-me-your-work/scripts/log.sh +40 -0
  129. package/skills/swarm/SKILL.md +44 -0
  130. package/skills/tdd/SKILL.md +44 -0
  131. package/skills/teach/SKILL.md +21 -0
  132. package/skills/technical-writing/SKILL.md +127 -0
  133. package/skills/typescript-best-practices/SKILL.md +30 -0
  134. package/skills/typescript-best-practices/references/patterns.md +313 -0
  135. package/skills/unslop/SKILL.md +67 -0
  136. package/skills/why/SKILL.md +146 -0
  137. package/skills/why/references/epistemics.md +144 -0
  138. package/skills/why/references/investigator-prompt.md +103 -0
  139. package/skills/why/references/source-playbook.md +17 -0
  140. package/skills/why/references/sources/code-archaeology.md +88 -0
  141. package/skills/why/references/sources/databricks.md +70 -0
  142. package/skills/why/references/sources/datadog.md +99 -0
  143. package/skills/why/references/sources/incident-postmortem.md +15 -0
  144. package/skills/why/references/sources/linear.md +48 -0
  145. package/skills/why/references/sources/notion.md +55 -0
  146. package/skills/why/references/sources/sentry.md +100 -0
  147. package/skills/why/references/sources/slack.md +54 -0
  148. package/skills/why/references/synthesizer-prompt.md +135 -0
  149. package/src/catalog-types.ts +54 -0
  150. package/src/catalog.ts +308 -0
  151. package/src/client/PstackSettings.tsx +519 -0
  152. package/src/client/api.ts +56 -0
  153. package/src/client/index.tsx +38 -0
  154. package/src/client/locales.ts +65 -0
  155. package/src/client/poteto-defaults.ts +37 -0
  156. package/src/frontmatter.ts +73 -0
  157. package/src/home.ts +13 -0
  158. package/src/http-trust.ts +38 -0
  159. package/src/ids.ts +39 -0
  160. package/src/index.ts +85 -0
  161. package/src/overlay-model.ts +139 -0
  162. package/src/overlay.ts +40 -0
  163. package/src/persona.ts +38 -0
  164. package/src/plugin-config.ts +29 -0
  165. package/src/request-overlay.ts +40 -0
  166. package/src/roles.ts +55 -0
  167. package/src/settings-api.ts +48 -0
  168. package/src/settings-draft.ts +144 -0
  169. package/src/settings-routes.ts +77 -0
  170. package/src/skills-provider.ts +96 -0
  171. package/src/spawn.ts +52 -0
  172. package/src/tools.ts +226 -0
package/src/catalog.ts ADDED
@@ -0,0 +1,308 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import { join } from 'node:path'
3
+ import {
4
+ ANTIGRAVITY_AUTH_FILENAME,
5
+ ANTIGRAVITY_PROVIDER,
6
+ DEEPSEEK_API_KEY_ENV,
7
+ DEEPSEEK_PROVIDER,
8
+ OAUTH_AUTH_FILENAME,
9
+ OAUTH_AUTH_LEGACY_FILENAME,
10
+ } from './ids.ts'
11
+ import { resolveDshHome } from './home.ts'
12
+ import {
13
+ OAUTH_ROUTE_BY_STORE_ID,
14
+ storeIdForRoute,
15
+ type CatalogResult,
16
+ type LiveEffort,
17
+ type LiveRoute,
18
+ } from './catalog-types.ts'
19
+ import { readOverlay } from './overlay.ts'
20
+
21
+ export type { CatalogResult, LiveEffort, LiveRoute } from './catalog-types.ts'
22
+
23
+ const API_KEY_REF = /^[A-Za-z_][A-Za-z0-9_]*$/
24
+
25
+ interface LlmLike {
26
+ listProviders(): { id: string; name: string }[]
27
+ listConfigurableProviders?(): { provider: string; displayName: string; settingsNs: string; settingsPath: readonly string[] }[]
28
+ listModels(provider: string): Promise<{ id: string; name: string }[]>
29
+ resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise<{
30
+ id: string
31
+ name: string
32
+ reasoning?: { efforts: LiveEffort[]; defaultEffort?: string }
33
+ }>
34
+ }
35
+
36
+ interface CredentialsLike {
37
+ describe(ref: string): Promise<{ configured: boolean; source?: string }>
38
+ }
39
+
40
+ interface SettingsLike {
41
+ describe(options?: { redactSecrets?: boolean }): unknown[]
42
+ }
43
+
44
+ export interface CatalogHost {
45
+ llm?: LlmLike
46
+ credentials?: CredentialsLike
47
+ settings?: SettingsLike
48
+ dshHome?: string
49
+ env?: NodeJS.ProcessEnv
50
+ nowProviders?: () => string[]
51
+ }
52
+
53
+ function isRecord(value: unknown): value is Record<string, unknown> {
54
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
55
+ }
56
+
57
+ function collectApiKeyEnvRefs(value: unknown, out: Set<string>): void {
58
+ if (Array.isArray(value)) {
59
+ for (const item of value) collectApiKeyEnvRefs(item, out)
60
+ return
61
+ }
62
+ if (!isRecord(value)) return
63
+ for (const [key, child] of Object.entries(value)) {
64
+ if (key === 'apiKeyEnv' && typeof child === 'string' && API_KEY_REF.test(child)) out.add(child)
65
+ else collectApiKeyEnvRefs(child, out)
66
+ }
67
+ }
68
+
69
+ function sliceAtPath(value: unknown, path: readonly string[]): unknown {
70
+ let current = value
71
+ for (const segment of path) {
72
+ if (!isRecord(current)) return undefined
73
+ current = current[segment]
74
+ }
75
+ return current
76
+ }
77
+
78
+ function settingsValue(entry: unknown): unknown {
79
+ if (!isRecord(entry)) return undefined
80
+ return entry.value ?? entry.base ?? entry.user
81
+ }
82
+
83
+ function settingsNs(entry: unknown): string | undefined {
84
+ if (!isRecord(entry)) return undefined
85
+ return typeof entry.ns === 'string' ? entry.ns : undefined
86
+ }
87
+
88
+ async function refConfigured(credentials: CredentialsLike | undefined, env: NodeJS.ProcessEnv, ref: string): Promise<boolean> {
89
+ if (credentials !== undefined) {
90
+ try {
91
+ const info = await credentials.describe(ref)
92
+ return info.configured === true
93
+ } catch {
94
+ return false
95
+ }
96
+ }
97
+ const ambient = env[ref]
98
+ return typeof ambient === 'string' && ambient.trim().length > 0
99
+ }
100
+
101
+ async function readOauthStoreIds(dshHome: string): Promise<{ present: boolean; ids: string[] }> {
102
+ const candidates = [join(dshHome, OAUTH_AUTH_FILENAME), join(dshHome, OAUTH_AUTH_LEGACY_FILENAME)]
103
+ let present = false
104
+ const ids = new Set<string>()
105
+ for (const filename of candidates) {
106
+ try {
107
+ const text = await readFile(filename, 'utf8')
108
+ const parsed: unknown = JSON.parse(text)
109
+ if (!isRecord(parsed) || !isRecord(parsed.credentials)) continue
110
+ present = true
111
+ for (const key of Object.keys(parsed.credentials)) ids.add(key)
112
+ break
113
+ } catch (error) {
114
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue
115
+ present = true
116
+ break
117
+ }
118
+ }
119
+
120
+ try {
121
+ const text = await readFile(join(dshHome, ANTIGRAVITY_AUTH_FILENAME), 'utf8')
122
+ const parsed: unknown = JSON.parse(text)
123
+ if (isRecord(parsed) && isRecord(parsed.credential)) {
124
+ present = true
125
+ const cred = parsed.credential
126
+ if (
127
+ cred.type === 'oauth'
128
+ && typeof cred.projectId === 'string'
129
+ && cred.projectId.trim().length > 0
130
+ && typeof cred.expires === 'number'
131
+ && cred.expires > 0
132
+ ) {
133
+ ids.add('antigravity')
134
+ }
135
+ }
136
+ } catch (error) {
137
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
138
+ present = true
139
+ }
140
+ }
141
+
142
+ return { present, ids: [...ids] }
143
+ }
144
+
145
+ function effortsOf(info: { reasoning?: { efforts: LiveEffort[]; defaultEffort?: string } }): {
146
+ efforts: LiveEffort[]
147
+ defaultEffort?: string
148
+ } {
149
+ const reasoning = info.reasoning
150
+ if (reasoning === undefined || !Array.isArray(reasoning.efforts)) return { efforts: [] }
151
+ return {
152
+ efforts: reasoning.efforts.map(effort => ({
153
+ id: effort.id,
154
+ name: effort.name,
155
+ ...effort.description === undefined ? {} : { description: effort.description },
156
+ })),
157
+ ...reasoning.defaultEffort === undefined ? {} : { defaultEffort: reasoning.defaultEffort },
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Live logged-in routes only. No vendor catalog. No invented slugs.
163
+ */
164
+ export async function buildCatalog(host: CatalogHost, signal?: AbortSignal): Promise<CatalogResult> {
165
+ const dshHome = host.dshHome ?? resolveDshHome(host.env)
166
+ const env = host.env ?? process.env
167
+ const overlay = await readOverlay(dshHome)
168
+ const oauth = await readOauthStoreIds(dshHome)
169
+ const llm = host.llm
170
+ const providers = llm?.listProviders() ?? []
171
+ const registered = new Set(providers.map(provider => provider.id))
172
+ const oauthPluginPresent = [...registered].some(id => id.startsWith('pi-') || id === ANTIGRAVITY_PROVIDER || id.startsWith('agy-'))
173
+ const recommendOauthLogin = oauth.ids.length === 0 && !oauthPluginPresent
174
+
175
+ const refsByProvider = new Map<string, Set<string>>()
176
+ const remember = (provider: string, ref: string) => {
177
+ const set = refsByProvider.get(provider) ?? new Set<string>()
178
+ set.add(ref)
179
+ refsByProvider.set(provider, set)
180
+ }
181
+
182
+ if (host.settings !== undefined) {
183
+ let described: unknown[] = []
184
+ try {
185
+ described = host.settings.describe({ redactSecrets: true })
186
+ } catch {
187
+ described = []
188
+ }
189
+ const configurable = llm?.listConfigurableProviders?.() ?? []
190
+ for (const entry of described) {
191
+ const ns = settingsNs(entry)
192
+ const value = settingsValue(entry)
193
+ for (const row of configurable) {
194
+ if (ns !== undefined && row.settingsNs !== ns) continue
195
+ const slice = row.settingsPath.length === 0 ? value : sliceAtPath(value, row.settingsPath)
196
+ const refs = new Set<string>()
197
+ collectApiKeyEnvRefs(slice ?? value, refs)
198
+ for (const ref of refs) remember(row.provider, ref)
199
+ }
200
+ }
201
+ }
202
+
203
+ for (const provider of providers) {
204
+ if (provider.id === DEEPSEEK_PROVIDER) remember(provider.id, DEEPSEEK_API_KEY_ENV)
205
+ }
206
+
207
+ const routes: LiveRoute[] = []
208
+ const seen = new Set<string>()
209
+
210
+ const push = (route: LiveRoute) => {
211
+ const key = `${route.provider}::${route.model}`
212
+ if (seen.has(key)) return
213
+ seen.add(key)
214
+ routes.push(route)
215
+ }
216
+
217
+ if (llm !== undefined) {
218
+ for (const provider of providers) {
219
+ const storeId = storeIdForRoute(provider.id)
220
+ const oauthSignedIn = storeId !== undefined && oauth.ids.includes(storeId)
221
+ let models: { id: string; name: string }[] = []
222
+ try {
223
+ models = await llm.listModels(provider.id)
224
+ } catch {
225
+ models = []
226
+ }
227
+ if (models.length === 0) continue
228
+
229
+ const refs = [...(refsByProvider.get(provider.id) ?? [])]
230
+ let keyPresent = false
231
+ for (const ref of refs) {
232
+ if (await refConfigured(host.credentials, env, ref)) {
233
+ keyPresent = true
234
+ break
235
+ }
236
+ }
237
+
238
+ const selectable = oauthSignedIn || keyPresent
239
+ const source: LiveRoute['source'] = oauthSignedIn ? 'oauth' : 'api-key'
240
+ if (!selectable) continue
241
+
242
+ for (const model of models) {
243
+ let resolved: { id: string; name: string; reasoning?: { efforts: LiveEffort[]; defaultEffort?: string } }
244
+ try {
245
+ resolved = await llm.resolveModelInfo(provider.id, model.id, signal)
246
+ } catch {
247
+ resolved = { id: model.id, name: model.name }
248
+ }
249
+ const { efforts, defaultEffort } = effortsOf(resolved)
250
+ push({
251
+ provider: provider.id,
252
+ providerName: provider.name,
253
+ model: model.id,
254
+ modelName: resolved.name || model.name,
255
+ selectable: true,
256
+ source,
257
+ ...oauthSignedIn ? { oauthSignedIn: true } : {},
258
+ routeRegistered: true,
259
+ efforts,
260
+ ...defaultEffort === undefined ? {} : { defaultEffort },
261
+ })
262
+ }
263
+ }
264
+ }
265
+
266
+ for (const id of oauth.ids) {
267
+ const route = OAUTH_ROUTE_BY_STORE_ID[id]
268
+ if (route === undefined) continue
269
+ if (registered.has(route)) continue
270
+ const isAntigravity = id === 'antigravity' || route === ANTIGRAVITY_PROVIDER
271
+ push({
272
+ provider: route,
273
+ providerName: isAntigravity ? 'Google Antigravity' : id,
274
+ model: '*',
275
+ modelName: isAntigravity
276
+ ? '(install dsh-antigravity-oauth to load this route)'
277
+ : '(install dsh-oauth-login to load this route)',
278
+ selectable: false,
279
+ source: 'oauth',
280
+ oauthSignedIn: true,
281
+ routeRegistered: false,
282
+ efforts: [],
283
+ hint: isAntigravity
284
+ ? 'Signed in at $DSH_HOME/.dsh-antigravity-oauth.json. Install dsh-antigravity-oauth so the route is live.'
285
+ : 'Signed in at $DSH_HOME/.dsh-oauth-auth.json. Install https://github.com/aa2246740/dsh-oauth-login so the route is live.',
286
+ })
287
+ }
288
+
289
+ const selectableCount = routes.filter(route => route.selectable).length
290
+ return {
291
+ routes,
292
+ selectableCount,
293
+ oauthPluginPresent,
294
+ oauthStorePresent: oauth.present,
295
+ oauthSignedInProviders: oauth.ids,
296
+ overlayPath: overlay.path,
297
+ overlayMissing: overlay.missing,
298
+ inheritParent: true,
299
+ recommendOauthLogin,
300
+ ...selectableCount === 0
301
+ ? {
302
+ emptyReason: recommendOauthLogin
303
+ ? 'No logged-in API key and no dsh-oauth-login or dsh-antigravity-oauth store. Children inherit this conversation. Add a key in DSH, or install/login https://github.com/aa2246740/dsh-oauth-login / dsh-antigravity-oauth.'
304
+ : 'No selectable live route. Children inherit this conversation.',
305
+ }
306
+ : {},
307
+ }
308
+ }