@happyvertical/smrt-app-shell 0.0.0-stage → 0.60.16

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 (56) hide show
  1. package/AGENTS.md +99 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +173 -2
  5. package/agents/engine.md +85 -0
  6. package/dist/engine/app-runtime.d.ts +138 -0
  7. package/dist/engine/app-runtime.js +545 -0
  8. package/dist/engine/app-worker.d.ts +1 -0
  9. package/dist/engine/app-worker.js +62 -0
  10. package/dist/engine/commands.d.ts +94 -0
  11. package/dist/engine/commands.js +30 -0
  12. package/dist/engine/definition.d.ts +192 -0
  13. package/dist/engine/definition.js +497 -0
  14. package/dist/engine/errors.d.ts +23 -0
  15. package/dist/engine/errors.js +35 -0
  16. package/dist/engine/host.d.ts +153 -0
  17. package/dist/engine/host.js +791 -0
  18. package/dist/engine/index.d.ts +6 -0
  19. package/dist/engine/index.js +7 -0
  20. package/dist/engine/sandbox.d.ts +60 -0
  21. package/dist/engine/sandbox.js +260 -0
  22. package/dist/engine/snapshots.d.ts +7 -0
  23. package/dist/engine/snapshots.js +54 -0
  24. package/dist/engine/store.d.ts +39 -0
  25. package/dist/engine/store.js +32 -0
  26. package/dist/engine/worker-handle.d.ts +29 -0
  27. package/dist/engine/worker-handle.js +89 -0
  28. package/dist/engine/worker-protocol.d.ts +22 -0
  29. package/dist/engine/worker-protocol.js +20 -0
  30. package/dist/lib/objects/App.d.ts +60 -0
  31. package/dist/lib/objects/App.js +273 -0
  32. package/dist/lib/objects/AppVersion.d.ts +22 -0
  33. package/dist/lib/objects/AppVersion.js +62 -0
  34. package/dist/lib/objects/Approval.d.ts +39 -0
  35. package/dist/lib/objects/Approval.js +101 -0
  36. package/dist/lib/objects/AssistantMessage.d.ts +24 -0
  37. package/dist/lib/objects/AssistantMessage.js +63 -0
  38. package/dist/lib/objects/AssistantThread.d.ts +16 -0
  39. package/dist/lib/objects/AssistantThread.js +44 -0
  40. package/dist/lib/objects/index.d.ts +5 -0
  41. package/dist/lib/objects/index.js +5 -0
  42. package/dist/lib/server/approvals.d.ts +69 -0
  43. package/dist/lib/server/approvals.js +239 -0
  44. package/dist/lib/server/builder.d.ts +16 -0
  45. package/dist/lib/server/builder.js +71 -0
  46. package/dist/lib/server/events.d.ts +16 -0
  47. package/dist/lib/server/events.js +14 -0
  48. package/dist/lib/server/host.d.ts +22 -0
  49. package/dist/lib/server/host.js +96 -0
  50. package/dist/lib/server/owner.d.ts +33 -0
  51. package/dist/lib/server/owner.js +92 -0
  52. package/dist/lib/server/version-store.d.ts +20 -0
  53. package/dist/lib/server/version-store.js +115 -0
  54. package/dist/manifest.json +1680 -0
  55. package/dist/smrt-knowledge.okf.md +95 -0
  56. package/package.json +80 -3
@@ -0,0 +1,94 @@
1
+ import type { AppDefinition, FieldDef, MethodDef } from './definition.ts';
2
+ export type Command = {
3
+ type: 'defineModel';
4
+ name: string;
5
+ label?: string;
6
+ fields?: Record<string, FieldDef>;
7
+ } | {
8
+ type: 'addField';
9
+ model: string;
10
+ field: string;
11
+ definition: FieldDef;
12
+ } | {
13
+ type: 'hideField';
14
+ model: string;
15
+ field: string;
16
+ } | {
17
+ type: 'renameField';
18
+ model: string;
19
+ from: string;
20
+ to: string;
21
+ } | {
22
+ type: 'removeField';
23
+ model: string;
24
+ field: string;
25
+ } | {
26
+ type: 'changeFieldType';
27
+ model: string;
28
+ field: string;
29
+ to: FieldDef;
30
+ } | {
31
+ type: 'removeModel';
32
+ model: string;
33
+ } | {
34
+ type: 'addMethod';
35
+ model: string;
36
+ name: string;
37
+ method: MethodDef;
38
+ } | {
39
+ type: 'enableRecipe';
40
+ recipe: string;
41
+ }
42
+ /**
43
+ * Undo the current version. `version` (optional) pins which version the
44
+ * caller means; the host refuses if the app has moved on since.
45
+ */
46
+ | {
47
+ type: 'undo';
48
+ version?: number;
49
+ } | {
50
+ type: 'cleanUp';
51
+ keep: number;
52
+ } | {
53
+ type: 'exportTemplate';
54
+ includeRecords?: boolean;
55
+ } | {
56
+ type: 'importTemplate';
57
+ data: Template;
58
+ };
59
+ export type CommandType = Command['type'];
60
+ export interface Plan {
61
+ summary: string;
62
+ risky: boolean;
63
+ /** Counts of values to archive, values that will not convert, rows in a removed model. */
64
+ preview?: Record<string, unknown>;
65
+ /** Methods whose code mentions a renamed field; their code is not rewritten. */
66
+ affectedMethods?: string[];
67
+ }
68
+ export interface ExecuteOptions {
69
+ author: string;
70
+ approved?: boolean;
71
+ }
72
+ /** A template: the definition (and optionally the records) of an app. */
73
+ export interface Template {
74
+ format: 1;
75
+ exportedAt?: string;
76
+ definition: AppDefinition;
77
+ records?: Record<string, Record<string, unknown>[]>;
78
+ }
79
+ /**
80
+ * Commands that must be approved. `importTemplate` is risky only when the
81
+ * template carries method code (see {@link isRiskyCommand}); `undo` is risky
82
+ * only when the stored version being undone has a `convertColumn` step, which
83
+ * the host decides from the stored version (never from the caller), so it is
84
+ * not in this set.
85
+ */
86
+ export declare const RISKY_COMMANDS: ReadonlySet<CommandType>;
87
+ /** A migration step whose down path overwrites newer data with archived originals. */
88
+ export declare function overwritesOnUndo(step: {
89
+ op: string;
90
+ }): boolean;
91
+ /** Static risk of a command. `undo` is decided by the host from the stored version. */
92
+ export declare function isRiskyCommand(cmd: Command): boolean;
93
+ /** Generated app tools that delete records need approval. */
94
+ export declare function isRiskyTool(name: string): boolean;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Commands that must be approved. `importTemplate` is risky only when the
3
+ * template carries method code (see {@link isRiskyCommand}); `undo` is risky
4
+ * only when the stored version being undone has a `convertColumn` step, which
5
+ * the host decides from the stored version (never from the caller), so it is
6
+ * not in this set.
7
+ */
8
+ export const RISKY_COMMANDS = new Set([
9
+ 'addMethod',
10
+ 'removeField',
11
+ 'removeModel',
12
+ 'changeFieldType',
13
+ 'cleanUp',
14
+ ]);
15
+ /** A migration step whose down path overwrites newer data with archived originals. */
16
+ export function overwritesOnUndo(step) {
17
+ return step.op === 'convertColumn';
18
+ }
19
+ /** Static risk of a command. `undo` is decided by the host from the stored version. */
20
+ export function isRiskyCommand(cmd) {
21
+ if (RISKY_COMMANDS.has(cmd.type))
22
+ return true;
23
+ if (cmd.type === 'importTemplate')
24
+ return Object.values(cmd.data?.definition?.models ?? {}).some((m) => Object.keys(m?.methods ?? {}).length > 0);
25
+ return false;
26
+ }
27
+ /** Generated app tools that delete records need approval. */
28
+ export function isRiskyTool(name) {
29
+ return /_delete$/.test(name);
30
+ }
@@ -0,0 +1,192 @@
1
+ import type { RuntimeFieldType, RuntimeModelDefinition } from '@happyvertical/smrt-core';
2
+ export declare const USER_PKG = "@local/app";
3
+ export declare const FORMAT = 1;
4
+ export type FieldType = 'text' | 'number' | 'integer' | 'boolean' | 'date' | 'money' | 'choice' | 'reference' | 'json';
5
+ export interface FieldDef {
6
+ type: FieldType;
7
+ label?: string;
8
+ required?: boolean;
9
+ choices?: string[];
10
+ /** For `reference`: the name of another model of the app. */
11
+ ref?: string;
12
+ hidden?: boolean;
13
+ }
14
+ export interface MethodParamDef {
15
+ type: FieldType;
16
+ required?: boolean;
17
+ }
18
+ export interface MethodDef {
19
+ description: string;
20
+ params?: Record<string, MethodParamDef>;
21
+ /**
22
+ * JavaScript body of `function ({ record, params, data, app })`. Return a
23
+ * result; call `app.create/update/delete` to propose writes.
24
+ */
25
+ code: string;
26
+ }
27
+ export interface ModelDef {
28
+ label?: string;
29
+ /**
30
+ * Qualified name of a shipped model this app model extends (the app-subclass
31
+ * rule: `Profile` extends `@happyvertical/smrt-profiles:Profile`). The
32
+ * model's fields become nullable columns on the parent's table.
33
+ */
34
+ extends?: string;
35
+ fields: Record<string, FieldDef>;
36
+ methods?: Record<string, MethodDef>;
37
+ }
38
+ export interface AppDefinition {
39
+ format: 1;
40
+ name: string;
41
+ /** Shipped SMRT packages turned on. Only `profiles` for now. */
42
+ recipes: string[];
43
+ models: Record<string, ModelDef>;
44
+ }
45
+ export declare const EMPTY_APP: AppDefinition;
46
+ export interface RecipeModel {
47
+ /** Qualified name of the shipped parent class. */
48
+ parent: string;
49
+ /** The parent's (shared, STI) table. */
50
+ table: string;
51
+ /**
52
+ * Class name the app subclass is registered under. It cannot be `Profile`
53
+ * yet: a second class named `Profile` makes the real package's own
54
+ * `Person`/`Organization` subclasses lose their STI base in the registry
55
+ * (see AGENTS.md, "Known core gap"). Flip this to the model name when core
56
+ * resolves a parent by qualified name.
57
+ */
58
+ className: string;
59
+ /** Fields the parent already has, in app terms. */
60
+ builtIn: Record<string, FieldDef>;
61
+ }
62
+ export interface Recipe {
63
+ /** Shipped classes whose tables are created first. */
64
+ tables: string[];
65
+ models: Record<string, RecipeModel>;
66
+ }
67
+ export declare const RECIPES: Record<string, Recipe>;
68
+ /** The recipe model an app model extends, if it does. */
69
+ export declare function recipeModelFor(model: string, md: ModelDef | undefined): RecipeModel | undefined;
70
+ export declare const MAX_CODE_LENGTH = 20000;
71
+ export declare const MAX_MODELS = 100;
72
+ export declare const MAX_FIELDS = 200;
73
+ export declare const MAX_METHODS = 50;
74
+ export declare const MAX_PARAMS = 20;
75
+ export declare const MAX_CHOICES = 200;
76
+ export declare const FIELD_TYPES: readonly FieldType[];
77
+ /** The regular expression field and method names must match (camelCase). */
78
+ export declare const FIELD_NAME_PATTERN: string;
79
+ /** A legal camelCase spelling of a rejected name, e.g. `due_date` -> `dueDate`. */
80
+ export declare function suggestFieldName(name: string): string | undefined;
81
+ export declare const snake: (s: string) => string;
82
+ export declare function isValidModelName(s: string): boolean;
83
+ export declare function isValidFieldName(s: string): boolean;
84
+ export declare function tableFor(model: string, md?: ModelDef): string;
85
+ /** Class name a model is registered under (generated tools use it). */
86
+ export declare function classNameFor(model: string, md?: ModelDef): string;
87
+ /** Route segment of the generated REST collection. */
88
+ export declare function routeFor(model: string, md?: ModelDef): string;
89
+ /**
90
+ * Whether a REST request may be served: only `/api/<route>` and
91
+ * `/api/<route>/<id or action>` of the app's own models. Core's generated
92
+ * handler also serves reserved endpoints (`sync/apply`, whose `delete` op
93
+ * deletes records, `_changes`, `_events`, ...) and any shipped class it can
94
+ * find in its registry; none of those belong to the app.
95
+ */
96
+ export declare function restRouteAllowed(def: AppDefinition, rawUrl: string): boolean;
97
+ /** Names of the generated tools: `<class>_list`, ... and one per method. */
98
+ export declare function toolNamesFor(model: string, md: ModelDef): string[];
99
+ /** Shipped (built-in) fields of an app model. */
100
+ export declare function builtInFields(model: string, md: ModelDef | undefined): Record<string, FieldDef>;
101
+ export declare function visible(fields: Record<string, FieldDef>): {
102
+ [k: string]: FieldDef;
103
+ };
104
+ export declare const sqlType: (t: FieldType) => string;
105
+ export declare const runtimeType: (t: FieldType) => RuntimeFieldType;
106
+ /** Storage family of a declared SQLite column type, to compare columns. */
107
+ export declare function storageFamily(declared: string): string;
108
+ /** Check a whole definition. Returns problems; empty means valid. */
109
+ export declare function validate(def: unknown): string[];
110
+ /** Changes that cannot be applied by only adding things. */
111
+ export declare function refuseChanges(prev: AppDefinition, next: AppDefinition, converting?: Set<string>): string[];
112
+ /** What the app looks like to the assistant and the page. */
113
+ export declare function describeApp(def: AppDefinition, version: number): {
114
+ name: string;
115
+ version: number;
116
+ recipes: string[];
117
+ models: Record<string, DescribedModel>;
118
+ };
119
+ export interface DescribedModel {
120
+ kind: 'app' | 'shipped-subclass';
121
+ label: string;
122
+ table: string;
123
+ className: string;
124
+ extends: string | null;
125
+ fields: Record<string, FieldDef>;
126
+ ownFields: string[];
127
+ methods: Record<string, {
128
+ description: string;
129
+ params: Record<string, MethodParamDef>;
130
+ }>;
131
+ }
132
+ /** A model as core's `registerRuntimeModel` wants it (hidden fields left out). */
133
+ export declare function toRuntimeModel(model: string, md: ModelDef): RuntimeModelDefinition;
134
+ /**
135
+ * One database step of a definition change that is not purely additive. Each
136
+ * has an inverse, which undo runs. Additive changes (new tables and columns)
137
+ * need no step: the app runtime adds what the definition lacks.
138
+ */
139
+ export type Step = {
140
+ op: 'renameColumn';
141
+ table: string;
142
+ from: string;
143
+ to: string;
144
+ }
145
+ /** Values are archived first, so undo can put them back. */
146
+ | {
147
+ op: 'dropColumn';
148
+ table: string;
149
+ key: string;
150
+ column: string;
151
+ type: FieldType;
152
+ }
153
+ /** Original values are archived; rows that do not convert become null. */
154
+ | {
155
+ op: 'convertColumn';
156
+ table: string;
157
+ key: string;
158
+ column: string;
159
+ from: FieldDef;
160
+ to: FieldDef;
161
+ }
162
+ /** The table is renamed out of the way, not dropped. */
163
+ | {
164
+ op: 'archiveTable';
165
+ table: string;
166
+ archivedAs: string;
167
+ };
168
+ export interface Migration {
169
+ steps: Step[];
170
+ /** 'up' applies steps; 'down' undoes them in reverse order. */
171
+ direction: 'up' | 'down';
172
+ /** The version whose steps these are (archives are keyed by it). */
173
+ version: number;
174
+ }
175
+ /** Convert one stored value to a field type. */
176
+ export declare function convertValue(v: unknown, to: FieldDef): {
177
+ ok: boolean;
178
+ value: unknown;
179
+ };
180
+ export type Coerced = {
181
+ ok: true;
182
+ value: unknown;
183
+ } | {
184
+ ok: false;
185
+ error: string;
186
+ };
187
+ /**
188
+ * Check a value against a field and convert it for storage. Shared by record
189
+ * writes and by the writes a method proposes, so both are held to one rule.
190
+ * References are only checked for shape here; the runtime checks the target.
191
+ */
192
+ export declare function coerceValue(fd: FieldDef, v: unknown): Coerced;