howone 0.1.8 → 0.1.9

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "howone",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "description": "HowOne command line tools for creating app templates.",
6
6
  "type": "module",
@@ -29,4 +29,4 @@ Use this skill when writing app code that consumes `@howone/sdk`. The goal is st
29
29
 
30
30
  ## References
31
31
 
32
- Read `references/usage-patterns.md` when implementing or reviewing actual code.
32
+ Read `references/usage-patterns.md` before writing any code. It is the complete API reference for `@howone/sdk` and `@howone/sdk/react` — all type signatures, method names, import paths, and call patterns are already there.
@@ -1,5 +1,192 @@
1
1
  # HowOne SDK Usage Patterns
2
2
 
3
+ Complete API reference for `@howone/sdk` and `@howone/sdk/react`. Covers all type signatures, method names, import paths, and usage patterns needed to wire up entities, AI actions, and React components in a HowOne app.
4
+
5
+ ## Complete Import Reference
6
+
7
+ ```ts
8
+ // @howone/sdk — all public exports
9
+ import {
10
+ createClient,
11
+ defineAiAction,
12
+ defineAiActions,
13
+ defineEntities,
14
+ withAiActions,
15
+ withEntities,
16
+ type CreateClientOptions,
17
+ type EntityRecord,
18
+ type EntityClient,
19
+ type EntityBindings,
20
+ type QueryOptions,
21
+ type QueryResult,
22
+ type PageInfo,
23
+ type DeleteResult,
24
+ type AiClient,
25
+ type AiActionDefinition,
26
+ type AiActionClient,
27
+ type AiActionConfig,
28
+ type AiResult, // = ExecutionResult
29
+ type AiSession, // { result: Promise<AiResult>, cancel(): void, signal: AbortSignal }
30
+ type AiEvent, // SSE event payload
31
+ type AiOptions,
32
+ type UserProfile,
33
+ AiSchemaValidationError,
34
+ } from '@howone/sdk'
35
+
36
+ // @howone/sdk/react — React components and hooks
37
+ import {
38
+ HowOneProvider,
39
+ useHowoneContext,
40
+ FloatingButton,
41
+ Loading,
42
+ LoadingSpinner,
43
+ type HowOneProviderProps,
44
+ type HowOneAuthMode,
45
+ type HowOneThemeMode,
46
+ type HowOneBrandMode,
47
+ } from '@howone/sdk/react'
48
+
49
+ import { z } from 'zod'
50
+ ```
51
+
52
+ ---
53
+
54
+ ## createClient — signature & return shape
55
+
56
+ ```ts
57
+ const client = createClient({
58
+ projectId: import.meta.env.VITE_HOWONE_PROJECT_ID, // required in Vite apps
59
+ env: import.meta.env.VITE_HOWONE_ENV, // 'local' | 'dev' | 'prod'
60
+ // Optional advanced options (rarely needed):
61
+ // apiUrl, aiUrl, caseStyle ('camel'|'snake'), auth: { mode, getToken }
62
+ })
63
+
64
+ // client shape:
65
+ client.entity<TRecord, TCreate, TUpdate>(entityName: string): EntityClient<...>
66
+ client.entities: Record<string, EntityClient>
67
+ client.ai: AiClient // low-level; prefer withAiActions bindings
68
+ client.me(): Promise<UserProfile | null>
69
+ client.requireMe(): Promise<UserProfile>
70
+ client.auth.setToken(t: string | null): void
71
+ client.auth.getToken(): string | null
72
+ client.auth.isAuthenticated(): boolean
73
+ client.auth.login(redirect?: string): void
74
+ client.auth.logout(): void
75
+ client.upload.file(file, options?): Promise<{ url, thumbnailUrl?, id?, size?, mimeType? }>
76
+ client.upload.image(file): Promise<{ url }>
77
+ client.upload.batch({ files, concurrent?, onProgress?, onFileComplete? }): Promise<BatchUploadResponse>
78
+ ```
79
+
80
+ ---
81
+
82
+ ## EntityClient — complete method signatures
83
+
84
+ ```ts
85
+ type EntityClient<TRecord, TCreate, TUpdate> = {
86
+ name: string
87
+ // Basic CRUD
88
+ list(options?: { page?, limit?, sort?, order?, ...filters }): Promise<TRecord[]>
89
+ get(id: string): Promise<TRecord | null>
90
+ getOrThrow(id: string): Promise<TRecord>
91
+ create(data: TCreate): Promise<TRecord>
92
+ update(id: string, data: TUpdate): Promise<TRecord>
93
+ delete(id: string): Promise<{ deleted: boolean; id: string; message? }>
94
+ // Advanced query with filters/pagination
95
+ query(options?: QueryOptions<TRecord>): Promise<QueryResult<TRecord>>
96
+ query.mine(options?: QueryOptions<TRecord>): Promise<QueryResult<TRecord>>
97
+ bulkCreate(records: TCreate[], options?: { sample?: boolean }): Promise<TRecord[]>
98
+ aggregate(pipeline: unknown[]): Promise<unknown[]>
99
+ }
100
+
101
+ // QueryOptions
102
+ type QueryOptions<TRecord> = {
103
+ where?: { [K in keyof TRecord]?: TRecord[K] | FieldOperator }
104
+ // FieldOperator: { eq, ne, gt, gte, lt, lte, contains, like, startsWith, endsWith, in, notIn }
105
+ search?: string
106
+ page?: { number?: number; size?: number }
107
+ orderBy?: Partial<Record<keyof TRecord | string, 'asc' | 'desc'>>
108
+ }
109
+
110
+ // QueryResult
111
+ type QueryResult<T> = {
112
+ items: T[]
113
+ page: { number, size, total, totalPages, hasNext, hasPrev }
114
+ }
115
+
116
+ // EntityRecord base
117
+ type EntityRecord = {
118
+ id: string
119
+ createdDate?: string
120
+ updatedDate?: string
121
+ createdById?: string
122
+ isSample?: boolean
123
+ [key: string]: unknown
124
+ }
125
+ ```
126
+
127
+ ---
128
+
129
+ ## AI Action — complete signatures
130
+
131
+ ```ts
132
+ // Define a typed action
133
+ defineAiAction(id: string, config?: {
134
+ inputSchema?: z.ZodType<TInput>
135
+ outputSchema?: z.ZodType<TOutput>
136
+ mode?: 'run' | 'stream' | 'events'
137
+ }): AiActionDefinition<TInput, TOutput>
138
+
139
+ // Group actions
140
+ defineAiActions({ [name]: AiActionDefinition, ... }): actions
141
+
142
+ // Bind to client
143
+ withAiActions(client, actions): client & { ai: { [name]: AiActionClient } }
144
+
145
+ // AiActionClient methods
146
+ howone.ai.<actionName>.run(inputs?, options?): Promise<TOutput>
147
+ howone.ai.<actionName>.stream(inputs?, options?): AiSession
148
+ howone.ai.<actionName>.events(inputs?, options?): AsyncIterable<AiEvent>
149
+
150
+ // AiSession
151
+ type AiSession = {
152
+ result: Promise<AiResult>
153
+ cancel(): void
154
+ signal: AbortSignal
155
+ }
156
+
157
+ // Reserved names — do NOT use as action names: run, stream, events
158
+ ```
159
+
160
+ ---
161
+
162
+ ## React: HowOneProvider & hooks
163
+
164
+ `@howone/sdk/react` exports exactly: `HowOneProvider`, `useHowoneContext`, `FloatingButton`, `Loading`, `LoadingSpinner`.
165
+
166
+ **There are no `useEntity`, `useQuery`, `useAi`, or other data-fetching hooks.** Entity and AI calls are plain async functions — call them directly in components with `useEffect`/`useState` or any data-fetching library (SWR, React Query, etc.).
167
+
168
+ ```tsx
169
+ // Wrap app root — handles auth, theme, toasts, floating button
170
+ <HowOneProvider
171
+ projectId={...} // optional if client is already configured
172
+ auth="optional" // 'required' | 'optional' | 'none'
173
+ brand="visible" // 'visible' | 'hidden'
174
+ theme="inherit" // 'dark' | 'light' | 'system' | 'inherit'
175
+ showBrandButton={true}
176
+ >
177
+ <App />
178
+ </HowOneProvider>
179
+
180
+ // Auth context hook — the only hook in the package
181
+ const { user, token, isAuthenticated, logout } = useHowoneContext()
182
+ // user shape: { id, email, name, avatar } | null
183
+
184
+ // Loading components
185
+ <Loading size="md" tone="brand" label="..." description="..." fullScreen />
186
+ <LoadingSpinner size="sm" tone="neutral" />
187
+ // size: 'sm' | 'md' | 'lg' tone: 'brand' | 'neutral' | 'inverse'
188
+ ```
189
+
3
190
  ## App SDK Entry
4
191
 
5
192
  Preferred Vite app entry shape:
@@ -120,20 +307,19 @@ for await (const event of howone.ai.generateStory.events(input)) {
120
307
  }
121
308
  ```
122
309
 
123
- ## AI Output Validation Caveat
310
+ ## AI Output Validation
124
311
 
125
- Check `packages/sdk/src/services/ai.ts` before relying on output validation. The desired behavior is for `defineAiAction(...).run()` to validate and return the workflow final result, not the whole SSE execution envelope.
312
+ `run()` validates input with `inputSchema`, calls the workflow, then validates the **raw `ExecutionResult`** (the full SSE envelope) with `outputSchema`. It does **not** automatically unwrap `result.finalResult`.
126
313
 
127
- Desired implementation shape:
314
+ If you want to type the final result only, either:
315
+ 1. Define `outputSchema` to match the full `ExecutionResult` shape, or
316
+ 2. Omit `outputSchema` and unwrap manually:
128
317
 
129
318
  ```ts
130
- const result = await base.run(definition.id, validInputs, options)
131
- const output = result?.finalResult ?? result
132
- return parseAiValue(definition.id, 'output', output, definition.outputSchema)
319
+ const result = await howone.ai.generateStory.run(input) // returns AiResult
320
+ const finalResult = result.finalResult as GenerateStoryOutput
133
321
  ```
134
322
 
135
- If the SDK still validates the whole `ExecutionResult`, either fix the SDK first or avoid generating final-result `outputSchema` in app code that will immediately run.
136
-
137
323
  ## AI Result Persistence
138
324
 
139
325
  For AI-generated data that should be saved:
@@ -6,6 +6,39 @@ Read this file once when entering the project.
6
6
  Follow it during implementation.
7
7
  Do not repeatedly reread it unless it changes or the current task requires checking project rules again.
8
8
 
9
+ ## Multi-turn Policy
10
+
11
+ After reading this file, maintain a concise project policy summary for the active workspace session.
12
+ Use that summary across turns instead of rereading this file or relying on old chat history.
13
+
14
+ The project policy summary should stay short and include only durable rules:
15
+
16
+ - package manager and common commands
17
+ - trusted libraries and framework assumptions
18
+ - context-loading rules
19
+ - validation rules
20
+ - project-specific constraints
21
+
22
+ Do not store transient command output, temporary reasoning, full file contents, or step-by-step logs in the project policy.
23
+
24
+ Maintain a separate short task state summary while implementing a user request:
25
+
26
+ - current goal
27
+ - current phase: explore, implement, validate, fix, or done
28
+ - files already read
29
+ - files changed
30
+ - last validation command and result
31
+ - known blockers or open questions
32
+
33
+ Use task state to avoid repeating exploration or rereading unchanged files. Reset or replace it when the user starts a new unrelated task.
34
+
35
+ Do not reread this file unless:
36
+
37
+ - this file changed
38
+ - the project policy summary is unavailable
39
+ - the task enters a nested project with its own `AGENTS.md`
40
+ - validation errors suggest a project rule was missed
41
+
9
42
  ## Library Trust Policy
10
43
 
11
44
  For common public libraries already known to modern coding models, prefer model knowledge and package metadata over reading local source files.
@@ -43,4 +76,22 @@ Only read local component or library-style source files when:
43
76
  - the project has custom wrappers, custom variants, or unusual exports
44
77
  - the user explicitly asks to follow local component conventions
45
78
 
46
- Prefer failure-driven inspection over speculative context loading.
79
+ Prefer failure-driven inspection over speculative context loading.
80
+
81
+ ## Context Budget Policy
82
+
83
+ Start with the smallest useful context:
84
+
85
+ 1. Identify the app root and relevant scripts.
86
+ 2. Read the smallest file that directly controls the requested behavior.
87
+ 3. Prefer package metadata, config files, and public API usage before local library internals.
88
+ 4. Expand to additional files only when implementation, validation, or ambiguity requires it.
89
+
90
+ Avoid broad project scans unless the user asks for a repository-wide change or the relevant files are genuinely unknown.
91
+
92
+ ## Validation Policy
93
+
94
+ After meaningful code changes, run the narrowest relevant validation command available in this project.
95
+ Prefer build or typecheck before deeper investigation into library internals.
96
+
97
+ If validation fails, inspect the smallest file or error location needed to fix the failure.
@@ -35,7 +35,9 @@
35
35
  "tailwind-merge": "^3.5.0",
36
36
  "tailwindcss": "^4.2.1",
37
37
  "tw-animate-css": "^1.4.0",
38
- "vaul": "^1.1.2"
38
+ "vaul": "^1.1.2",
39
+ "zod": "^4.3.6",
40
+ "framer-motion": "^12.38.0"
39
41
  },
40
42
  "devDependencies": {
41
43
  "@eslint/js": "^9.39.4",