create-lykomi-app 0.10.1 → 0.11.1

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": "create-lykomi-app",
3
- "version": "0.10.1",
3
+ "version": "0.11.1",
4
4
  "license": "MIT",
5
5
  "description": "Scaffold a new LYKOMI app — AG-UI protocol + Microsoft Agent Framework + Azure Foundry, ready to run.",
6
6
  "keywords": [
@@ -5,7 +5,7 @@
5
5
  "extends": "default",
6
6
  "filesDir": "files",
7
7
  "extraDependencies": {
8
- "@lykomi/web-graph": "0.3.18"
8
+ "@lykomi/web-graph": "0.3.20"
9
9
  },
10
10
  "extraScripts": {
11
11
  "graph:up": "docker compose up -d",
@@ -51,16 +51,18 @@ then open chat and ask “Make this idea more specific”. The context indicator
51
51
  **Your idea**; the AG-UI request includes its field path, current value and selected
52
52
  text. The active window also supplies the named form fields and edit mode.
53
53
 
54
- `src/pages/use-draft-context.ts` uses the public `useAppStore.setContextItem` and
55
- `usePageTools` APIs. Its `page_update_draft_field` tool validates the field and
54
+ `Field` and `ReadOnlyField` automatically supply the selected field context through
55
+ `@lykomi/web-ui`. No per-field focus handlers or context hook are required.
56
+ `src/pages/use-draft-tools.ts` uses `usePageTools` for the app-owned edits. Its `page_update_draft_field` tool validates the field and
56
57
  checks that its current value still matches the value the agent read. Updates
57
58
  appear in the same inputs you edit manually. **Save draft** accepts the changes
58
59
  in memory; **Cancel** restores the previous values. Closing the draft or switching
59
60
  to another window removes its field context and tools. Moving into chat keeps them.
60
61
 
61
- The leaf `Input`, `Textarea` and `Field` components do not automatically send values
62
- to a model. Your app explicitly chooses the fields to expose. Keep sensitive fields
63
- out of context, and connect your own authenticated persistence before saving remotely.
62
+ Wrap native inputs in `Field` to get automatic field context. Use
63
+ `agentContext={false}` on `Field` or `ReadOnlyField` for sensitive values;
64
+ password inputs are always excluded. Your app owns validation and persistence.
65
+ Connect an authenticated storage service before saving remotely.
64
66
 
65
67
  ## Coding With AI Agents
66
68
 
@@ -26,11 +26,11 @@
26
26
  "@assistant-ui/react": "^0.15.1",
27
27
  "@azure/msal-browser": "^5.6.3",
28
28
  "@azure/msal-react": "^5.2.1",
29
- "@lykomi/agent": "0.50.0",
30
- "@lykomi/web-primitives": "0.50.0",
31
- "@lykomi/web-shell": "0.50.0",
32
- "@lykomi/web-ui": "0.50.0",
33
- "@lykomi/web-voice": "0.1.34",
29
+ "@lykomi/agent": "0.52.0",
30
+ "@lykomi/web-primitives": "0.52.0",
31
+ "@lykomi/web-shell": "0.52.0",
32
+ "@lykomi/web-ui": "0.52.0",
33
+ "@lykomi/web-voice": "0.1.36",
34
34
  "@radix-ui/react-tabs": "^1.1.22",
35
35
  "@tanstack/react-query": "^5.99.0",
36
36
  "lucide-react": "^0.553.0",
@@ -21,15 +21,9 @@ export function DraftForm({ tab }: { tab: GuideWindow }) {
21
21
  saved: undefined,
22
22
  editing: false,
23
23
  dirty: false,
24
- field: undefined,
25
24
  });
26
25
  requestAnimationFrame(() => editButton.current?.focus());
27
26
  };
28
- const track = (key: "name" | "text", input: HTMLInputElement | HTMLTextAreaElement) => {
29
- const field = { key, start: input.selectionStart ?? 0, end: input.selectionEnd ?? 0 };
30
- const current = guideWindows.get().tabs.find((entry) => entry.id === tab.id)?.field;
31
- if (JSON.stringify(current) !== JSON.stringify(field)) guideWindows.update(tab.id, { field });
32
- };
33
27
  return (
34
28
  <FormLayout
35
29
  className="mt-4"
@@ -89,15 +83,13 @@ export function DraftForm({ tab }: { tab: GuideWindow }) {
89
83
  >
90
84
  {tab.editing ? (
91
85
  <Control
86
+ name={key}
92
87
  id={`starter-draft-${key}`}
93
88
  value={tab[key] ?? ""}
94
89
  className={valueClass}
95
90
  maxLength={2000}
96
- onFocus={(event) => track(key, event.currentTarget)}
97
- onSelect={(event) => track(key, event.currentTarget)}
98
91
  onChange={(event) => {
99
92
  guideWindows.update(tab.id, { [key]: event.target.value, dirty: true });
100
- track(key, event.currentTarget);
101
93
  }}
102
94
  />
103
95
  ) : (
@@ -9,11 +9,11 @@ import {
9
9
  DropdownMenuItem,
10
10
  } from "@lykomi/web-ui";
11
11
  import { DraftForm } from "./draft-form.tsx";
12
- import { useDraftContext } from "./use-draft-context.ts";
12
+ import { useDraftTools } from "./use-draft-tools.ts";
13
13
  import { guideWindows, openGuideWindow } from "./guide-windows.ts";
14
14
 
15
15
  export function GuidePage() {
16
- useDraftContext();
16
+ useDraftTools();
17
17
  return (
18
18
  <WindowWorkbench
19
19
  controller={guideWindows}
@@ -6,7 +6,6 @@ export interface GuideWindow extends WorkbenchWindow {
6
6
  name?: string;
7
7
  editing?: boolean;
8
8
  saved?: { name: string; text: string };
9
- field?: { key: "name" | "text"; start: number; end: number };
10
9
  }
11
10
 
12
11
  // App-owned data; the UI framework owns selection, pinning, ordering and layouts.
@@ -1,52 +1,11 @@
1
- import { useEffect } from "react";
2
- import { useAppStore, usePageTools } from "@lykomi/web-ui";
1
+ import { usePageTools } from "@lykomi/web-ui";
3
2
  import { useWindows } from "@lykomi/web-ui/windows";
4
3
  import { guideWindows } from "./guide-windows.ts";
5
4
 
6
- /** Only the active window contributes a field; moving into chat retains it. */
7
- export function useDraftContext() {
5
+ /** App-owned draft updates. Field focus/value/selection context comes from the framework. */
6
+ export function useDraftTools() {
8
7
  const { tabs, active } = useWindows(guideWindows);
9
8
  const tab = tabs.find((entry) => entry.id === active);
10
- useEffect(() => {
11
- const field = tab?.kind === "draft" && tab.editing ? tab.field : undefined;
12
- const value = field ? (tab?.[field.key] ?? "") : "";
13
- const label = field?.key === "name" ? "App name" : "Your idea";
14
- useAppStore.getState().setContextItem(
15
- "starter:active-field",
16
- field
17
- ? {
18
- type: "ref",
19
- label,
20
- sourcePage: "/guide",
21
- persistence: "ephemeral",
22
- payload: {
23
- kind: "ref",
24
- refType: "form-field",
25
- refId: `draft:${field.key}`,
26
- target: {
27
- kind: "field",
28
- path: field.key,
29
- label,
30
- containerId: "draft",
31
- containerLabel: "Working draft",
32
- currentValue: value,
33
- },
34
- meta: {
35
- fieldFocus: "active",
36
- fieldLabel: label,
37
- caret: {
38
- start: field.start,
39
- end: field.end,
40
- selectedText: value.slice(field.start, field.end),
41
- },
42
- },
43
- },
44
- }
45
- : null,
46
- );
47
- return () => useAppStore.getState().setContextItem("starter:active-field", null);
48
- }, [tab]);
49
-
50
9
  usePageTools(
51
10
  tab?.kind === "draft" && tab.editing
52
11
  ? [
@@ -85,7 +44,6 @@ export function useDraftContext() {
85
44
  guideWindows.update(current.id, {
86
45
  [args.field]: args.value,
87
46
  dirty: true,
88
- field: { key: args.field, start: 0, end: 0 },
89
47
  });
90
48
  return JSON.stringify({
91
49
  status: "updated",