howone 0.2.3 → 0.2.5

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 (23) hide show
  1. package/package.json +1 -1
  2. package/templates/vite/.howone/skills/howone/01-architect/01-app-generation.md +8 -7
  3. package/templates/vite/.howone/skills/howone/01-architect/02-manifest-codegen.md +121 -436
  4. package/templates/vite/.howone/skills/howone/03-ai-capabilities/04-workflow-operations.md +13 -4
  5. package/templates/vite/.howone/skills/howone/04-app-sdk/01-client-setup.md +94 -261
  6. package/templates/vite/.howone/skills/howone/04-app-sdk/02-entity-operations.md +85 -465
  7. package/templates/vite/.howone/skills/howone/04-app-sdk/03-auth.md +11 -7
  8. package/templates/vite/.howone/skills/howone/04-app-sdk/04-react-integration.md +84 -137
  9. package/templates/vite/.howone/skills/howone/04-app-sdk/05-file-upload.md +66 -273
  10. package/templates/vite/.howone/skills/howone/04-app-sdk/06-raw-http.md +72 -249
  11. package/templates/vite/.howone/skills/howone/04-app-sdk/07-ai-action-calls.md +135 -499
  12. package/templates/vite/.howone/skills/howone/04-app-sdk/08-ai-manifest-handoff.md +49 -196
  13. package/templates/vite/.howone/skills/howone/04-app-sdk/09-extension-boundaries.md +4 -4
  14. package/templates/vite/.howone/skills/howone/04-app-sdk/10-workflow-execute-sse.md +94 -61
  15. package/templates/vite/.howone/skills/howone/04-app-sdk/11-entity-data-access-patterns.md +4 -3
  16. package/templates/vite/.howone/skills/howone/SKILL.md +48 -8
  17. package/templates/vite/.howone/skills/howone/references/common-errors.md +27 -0
  18. package/templates/vite/.howone/skills/howone/references/version-evidence.md +47 -0
  19. package/templates/vite/.howone/skills/howone/scripts/verify-project.mjs +151 -0
  20. package/templates/vite/package.json +1 -1
  21. package/templates/vite/src/App.tsx +9 -5
  22. package/templates/vite/src/lib/sdk.ts +7 -5
  23. package/templates/vite/bun.lock +0 -1478
@@ -0,0 +1,27 @@
1
+ # Common SDK Errors
2
+
3
+ Use this reference when typecheck, build, authentication, entity access, upload, or AI execution
4
+ fails.
5
+
6
+ | Symptom | Cause | Fix |
7
+ |---|---|---|
8
+ | `AI_WORKFLOW_CONFIGURATION_ERROR` | Missing or non-UUID `workflowId` | Re-read `.howone/ai/manifest.json`; pass its exact workflow config UUID. There is no action-name fallback. |
9
+ | `AI_SCHEMA_CONFIGURATION_ERROR` | JSON Schema passed to `defineAiAction` | Convert manifest JSON Schema to a Zod schema. |
10
+ | `AI_SCHEMA_VALIDATION_ERROR` on output | Workflow `finalResult` disagrees with manifest output schema | Fix the workflow or contract. Do not add `.passthrough()` or make required fields optional. |
11
+ | `WorkflowExecutionError` | `run_error` or `credit_insufficient` terminal event | Inspect `error.outcome`, `error.result.errors`, and `error.runId`; show app-owned UI or retry only when appropriate. |
12
+ | `aiUrl` / `aiBaseUrl` is not accepted | EAX routing is environment-owned | Remove the URL override and set `env` to `local`, `dev`, or `prod`. |
13
+ | Request hits `/api/api/...` | Raw path included `/api` even though the base already ends in `/api` | Use a path such as `/custom/stats`, not `/api/custom/stats`. |
14
+ | `response.data` is undefined | `howone.raw.*` already returns response data | Use `const data = await howone.raw.get<T>(...)`. |
15
+ | Provider renders blank forever in a public app | Provider guard conflicts with client auth or no client was passed | Pass `<HowOneProvider client={howone}>`; its guard defaults to `howone.auth.guard`. |
16
+ | `useHowoneContext must be used within HowOneProvider` | Hook called outside the Provider | Keep one root Provider and move the hook below it. |
17
+ | `ElementSelectorProvider` import fails from `/react` | Devtools moved to a separate entry | Import it from `@howone/sdk/devtools`. |
18
+ | Entity method is absent at typecheck/runtime | Manifest access forbids that capability and contract wrappers pruned it | Use the allowed namespace/operation or change and re-sync the platform contract. Do not cast the method back. |
19
+ | Public query rejects a filter/sort/scope | Query violates `access.public` | Put filters under `where`; use only `allowedFilters`, `allowedSorts`, and every `requiredScopes` field. |
20
+ | Nested JSON keys unexpectedly changed | `caseDepth: 'deep'` was enabled | Prefer the default `caseDepth: 'top-level'` for business JSON. |
21
+ | `HowOneProtocolError` key collision | snake_case and camelCase keys normalize to the same key | Fix the backend response contract; the SDK refuses silent overwrite. |
22
+ | Upload has no progress updates | Transport did not provide total bytes | Keep a loading state; `onProgress` fires only when total size is available. |
23
+ | Batch upload loops/fails immediately | `concurrent` is not a positive integer | Use `concurrent: 1` or higher. |
24
+ | Core import pulls React or React is missing | Framework code imported from the wrong entry | Use `@howone/sdk` for core, `@howone/sdk/react` for React, and `@howone/sdk/devtools` for selector tooling. |
25
+
26
+ After a fix, run the project verifier, typecheck, and production build. A successful build alone does
27
+ not prove that workflow IDs or manifest access rules are correct.
@@ -0,0 +1,47 @@
1
+ # SDK Version Evidence
2
+
3
+ Use this reference before writing or repairing `@howone/sdk` bindings. HowOne app contracts and
4
+ SDK APIs change independently; verify both.
5
+
6
+ ## Evidence Order
7
+
8
+ 1. Read `.howone/database/manifest.json` and `.howone/ai/manifest.json` for project-specific names,
9
+ fields, access rules, schemas, and workflow UUIDs.
10
+ 2. Read the app `package.json` for the requested `@howone/sdk` version.
11
+ 3. Read `node_modules/@howone/sdk/package.json` for the version actually installed.
12
+ 4. Inspect the installed version's public typings:
13
+ - `node_modules/@howone/sdk/dist/index.d.ts`
14
+ - `node_modules/@howone/sdk/dist/react.d.ts`
15
+ - `node_modules/@howone/sdk/dist/devtools.d.ts`
16
+ 5. Use this Skill for the workflow and code-generation recipe.
17
+ 6. Use official remote documentation only as supplemental evidence. Never let latest remote docs
18
+ override installed typings for an older app.
19
+
20
+ If steps 2 and 3 disagree, run the project's package manager install before coding. Do not repair
21
+ types by casting around a stale installation.
22
+
23
+ ## Deterministic Check
24
+
25
+ From the app root, run:
26
+
27
+ ```bash
28
+ node .howone/skills/howone/scripts/verify-project.mjs
29
+ ```
30
+
31
+ Fix every reported error before final validation. Warnings identify missing evidence or code that
32
+ still relies on compatibility behavior.
33
+
34
+ ## Lookup Patterns
35
+
36
+ Use `rg` against installed declarations instead of relying on remembered signatures:
37
+
38
+ ```bash
39
+ rg -n "CreateClientOptions|HowOneClientRuntime" node_modules/@howone/sdk/dist/index.d.ts
40
+ rg -n "defineAiAction|AiActionClient|WorkflowExecutionError" node_modules/@howone/sdk/dist/index.d.ts
41
+ rg -n "EntityClient|withEntityContract|withPublicEntities" node_modules/@howone/sdk/dist/index.d.ts
42
+ rg -n "HowOneProviderProps" node_modules/@howone/sdk/dist/react.d.ts
43
+ rg -n "ElementSelectorProviderProps" node_modules/@howone/sdk/dist/devtools.d.ts
44
+ ```
45
+
46
+ When declarations and this Skill disagree, use the installed declarations for signatures and this
47
+ Skill for platform ordering. Report the mismatch instead of silently inventing an adapter.
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'node:fs'
4
+ import path from 'node:path'
5
+
6
+ const appRoot = path.resolve(process.argv[2] || process.cwd())
7
+ const errors = []
8
+ const warnings = []
9
+ const facts = []
10
+
11
+ function relative(filePath) {
12
+ return path.relative(appRoot, filePath) || '.'
13
+ }
14
+
15
+ function readText(filePath) {
16
+ return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : null
17
+ }
18
+
19
+ function readJson(filePath, required = false) {
20
+ const source = readText(filePath)
21
+ if (source === null) {
22
+ if (required) errors.push(`Missing ${relative(filePath)}`)
23
+ return null
24
+ }
25
+ try {
26
+ return JSON.parse(source)
27
+ } catch (error) {
28
+ errors.push(`Invalid JSON in ${relative(filePath)}: ${error.message}`)
29
+ return null
30
+ }
31
+ }
32
+
33
+ function dependencySpec(pkg, name) {
34
+ return (
35
+ pkg?.dependencies?.[name] ??
36
+ pkg?.devDependencies?.[name] ??
37
+ pkg?.peerDependencies?.[name] ??
38
+ null
39
+ )
40
+ }
41
+
42
+ function collectWorkflowIds(value, output = []) {
43
+ if (Array.isArray(value)) {
44
+ for (const entry of value) collectWorkflowIds(entry, output)
45
+ return output
46
+ }
47
+ if (!value || typeof value !== 'object') return output
48
+ for (const [key, entry] of Object.entries(value)) {
49
+ if (key === 'workflowId' && typeof entry === 'string') output.push(entry)
50
+ collectWorkflowIds(entry, output)
51
+ }
52
+ return output
53
+ }
54
+
55
+ const packagePath = path.join(appRoot, 'package.json')
56
+ const pkg = readJson(packagePath, true)
57
+ const requested = dependencySpec(pkg, '@howone/sdk')
58
+ if (!requested) errors.push('package.json does not declare @howone/sdk')
59
+ else facts.push(`requested @howone/sdk: ${requested}`)
60
+
61
+ const installedPackagePath = path.join(appRoot, 'node_modules/@howone/sdk/package.json')
62
+ const installed = readJson(installedPackagePath)
63
+ if (!installed) {
64
+ errors.push('node_modules/@howone/sdk is missing; run the project package manager install')
65
+ } else {
66
+ facts.push(`installed @howone/sdk: ${installed.version}`)
67
+ const normalizedRequest = String(requested || '').replace(/^[~^]/, '')
68
+ if (/^\d/.test(normalizedRequest) && normalizedRequest !== installed.version) {
69
+ errors.push(`SDK version mismatch: package.json requests ${requested}, installed ${installed.version}`)
70
+ }
71
+ for (const declaration of ['index.d.ts', 'react.d.ts', 'devtools.d.ts']) {
72
+ const declarationPath = path.join(appRoot, 'node_modules/@howone/sdk/dist', declaration)
73
+ if (!fs.existsSync(declarationPath)) {
74
+ errors.push(`Installed SDK is missing dist/${declaration}`)
75
+ }
76
+ }
77
+ }
78
+
79
+ const databaseManifestPath = path.join(appRoot, '.howone/database/manifest.json')
80
+ const aiManifestPath = path.join(appRoot, '.howone/ai/manifest.json')
81
+ const databaseManifest = readJson(databaseManifestPath)
82
+ const aiManifest = readJson(aiManifestPath)
83
+ if (databaseManifest) facts.push(`database manifest: ${relative(databaseManifestPath)}`)
84
+ else warnings.push('No synced database manifest found')
85
+ if (aiManifest) {
86
+ facts.push(`AI manifest: ${relative(aiManifestPath)}`)
87
+ const workflowIds = collectWorkflowIds(aiManifest)
88
+ const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
89
+ for (const workflowId of workflowIds) {
90
+ if (!uuid.test(workflowId)) errors.push(`AI manifest contains invalid workflowId: ${workflowId}`)
91
+ }
92
+ if (workflowIds.length === 0) warnings.push('AI manifest contains no workflowId values')
93
+ } else {
94
+ warnings.push('No synced AI manifest found')
95
+ }
96
+
97
+ const sdkSourcePath = path.join(appRoot, 'src/lib/sdk.ts')
98
+ const sdkSource = readText(sdkSourcePath)
99
+ if (sdkSource === null) {
100
+ warnings.push('src/lib/sdk.ts is missing')
101
+ } else {
102
+ facts.push(`SDK binding: ${relative(sdkSourcePath)}`)
103
+ if (/\b(?:aiUrl|aiBaseUrl)\s*:/.test(sdkSource)) {
104
+ errors.push('src/lib/sdk.ts overrides the EAX URL; use createClient env only')
105
+ }
106
+ if (/\bmode\s*:\s*['"](?:auto|standalone|embedded)['"]/.test(sdkSource)) {
107
+ errors.push('src/lib/sdk.ts uses the removed createClient mode option')
108
+ }
109
+ }
110
+
111
+ const sourceRoot = path.join(appRoot, 'src')
112
+ if (fs.existsSync(sourceRoot)) {
113
+ const sourceFiles = []
114
+ const visit = (directory) => {
115
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
116
+ const entryPath = path.join(directory, entry.name)
117
+ if (entry.isDirectory()) visit(entryPath)
118
+ else if (/\.[cm]?[jt]sx?$/.test(entry.name)) sourceFiles.push(entryPath)
119
+ }
120
+ }
121
+ visit(sourceRoot)
122
+
123
+ for (const filePath of sourceFiles) {
124
+ const source = readText(filePath) || ''
125
+ if (
126
+ /import\s*\{[^}]*\bElementSelectorProvider\b[^}]*\}\s*from\s*['"]@howone\/sdk\/react['"]/.test(
127
+ source,
128
+ )
129
+ ) {
130
+ errors.push(`${relative(filePath)} imports ElementSelectorProvider from /react; use /devtools`)
131
+ }
132
+ if (/\burl\s*:\s*[`'"]\/api\//.test(source)) {
133
+ warnings.push(`${relative(filePath)} contains a raw /api/... path; the SDK REST base already includes /api`)
134
+ }
135
+ if (/<HowOneProvider\b(?![^>]*\bclient=)[^>]*>/.test(source)) {
136
+ errors.push(`${relative(filePath)} renders HowOneProvider without client={howone}`)
137
+ }
138
+ }
139
+ }
140
+
141
+ console.log(`HowOne project verification: ${appRoot}`)
142
+ for (const fact of facts) console.log(` ok: ${fact}`)
143
+ for (const warning of [...new Set(warnings)]) console.warn(` warning: ${warning}`)
144
+ for (const error of [...new Set(errors)]) console.error(` error: ${error}`)
145
+
146
+ if (errors.length > 0) {
147
+ console.error(`Verification failed with ${new Set(errors).size} error(s).`)
148
+ process.exit(1)
149
+ }
150
+
151
+ console.log('Verification passed.')
@@ -14,7 +14,7 @@
14
14
  "dependencies": {
15
15
  "@base-ui/react": "^1.4.1",
16
16
  "@fontsource-variable/inter": "^5.2.8",
17
- "@howone/sdk": "2.0.0-beta.31",
17
+ "@howone/sdk": "2.0.0-beta.32",
18
18
  "@tailwindcss/vite": "^4.2.1",
19
19
  "class-variance-authority": "^0.7.1",
20
20
  "clsx": "^2.1.1",
@@ -1,12 +1,16 @@
1
+ import howone from '@/lib/sdk'
2
+ import { ElementSelectorProvider } from '@howone/sdk/devtools'
1
3
  import { HowOneProvider } from '@howone/sdk/react'
2
4
 
3
5
  function App() {
4
6
  return (
5
- <HowOneProvider brand="visible">
6
- <div className="App">
7
- <h1>Hello HowOne</h1>
8
- </div>
9
- </HowOneProvider>
7
+ <ElementSelectorProvider>
8
+ <HowOneProvider client={howone} brand="visible">
9
+ <div className="App">
10
+ <h1>Hello HowOne</h1>
11
+ </div>
12
+ </HowOneProvider>
13
+ </ElementSelectorProvider>
10
14
  )
11
15
  }
12
16
 
@@ -12,17 +12,19 @@ const client = createClient({
12
12
  })
13
13
 
14
14
  export const entities = defineEntities({
15
- // Add generated entity bindings here, for example:
16
- // Todo: client.entity<Todo, TodoCreate, TodoUpdate>("Todo"),
15
+ // Generate bindings from .howone/database/manifest.json.
16
+ // Wrap each client.entity(...) with withEntityContract(..., entityDefinition).
17
+ // Generate manifest-approved public bindings separately with
18
+ // definePublicEntities + withPublicEntityContract + withPublicEntities.
17
19
  })
18
20
 
19
21
  export const ai = defineAiActions({
20
- // Add generated AI action bindings here, for example:
21
- // import { z } from "zod" and define Zod schemas before using defineAiAction.
22
+ // Generate bindings from .howone/ai/manifest.json.
23
+ // Import z from "zod" and convert manifest JSON Schema before using defineAiAction.
22
24
  // Do not paste JSON Schema objects from .howone/ai/manifest.json here directly.
23
25
  // With outputSchema configured, howone.ai.<action>.run() returns the validated finalResult payload.
24
26
  // generateImage: defineAiAction("generateImage", {
25
- // workflowId: "<workflow-config-id>", // config_id for this capability
27
+ // workflowId: "<exact-manifest-uuid>", // required; there is no action-name fallback
26
28
  // inputSchema: generateImageInputSchema,
27
29
  // outputSchema: generateImageOutputSchema,
28
30
  // }),