forgeos 0.1.0-alpha.21 → 0.1.0-alpha.23

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 (51) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +30 -2
  3. package/adapters/java/target/forge-java-adapter-0.1.0-alpha.11.jar +0 -0
  4. package/adapters/java-spring-boot-starter/target/forge-java-spring-boot-starter-0.1.0-alpha.11.jar +0 -0
  5. package/docs/cair-protocol.md +103 -0
  6. package/docs/changelog.md +30 -0
  7. package/examples/java-billing/target/java-billing-0.1.0-alpha.11-all.jar +0 -0
  8. package/examples/java-billing/target/java-billing-0.1.0-alpha.11.jar +0 -0
  9. package/package.json +2 -1
  10. package/src/forge/_generated/releaseManifest.json +1 -1
  11. package/src/forge/_generated/releaseManifest.ts +3 -3
  12. package/src/forge/agent-adapters/types.ts +3 -0
  13. package/src/forge/agent-memory/bridge.ts +28 -0
  14. package/src/forge/agent-memory/context-pack.ts +134 -8
  15. package/src/forge/agent-memory/types.ts +10 -1
  16. package/src/forge/cli/commands.ts +47 -0
  17. package/src/forge/cli/main.ts +4 -0
  18. package/src/forge/cli/new.ts +3 -1
  19. package/src/forge/cli/parse.ts +64 -11
  20. package/src/forge/cli/studio.ts +54 -0
  21. package/src/forge/cli/verify.ts +2 -0
  22. package/src/forge/compiler/frontend-graph/build.ts +58 -2
  23. package/src/forge/delta/explain.ts +113 -1
  24. package/src/forge/delta/index.ts +12 -0
  25. package/src/forge/delta/recorder.ts +60 -0
  26. package/src/forge/delta/status.ts +639 -2
  27. package/src/forge/delta/store.ts +281 -5
  28. package/src/forge/delta/timeline.ts +75 -1
  29. package/src/forge/version.ts +1 -1
  30. package/templates/nuxt-web/.vscode/settings.json +14 -0
  31. package/templates/nuxt-web/README.md +30 -0
  32. package/templates/nuxt-web/forge.config.ts +3 -0
  33. package/templates/nuxt-web/package.json +33 -0
  34. package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -0
  35. package/templates/nuxt-web/src/commands/createNote.ts +26 -0
  36. package/templates/nuxt-web/src/forge/schema.ts +12 -0
  37. package/templates/nuxt-web/src/policies.ts +6 -0
  38. package/templates/nuxt-web/src/queries/listNotes.ts +8 -0
  39. package/templates/nuxt-web/src/queries/liveNotes.ts +8 -0
  40. package/templates/nuxt-web/tsconfig.json +17 -0
  41. package/templates/nuxt-web/web/app.vue +67 -0
  42. package/templates/nuxt-web/web/components/LiveNotes.vue +89 -0
  43. package/templates/nuxt-web/web/components/NoteComposer.vue +100 -0
  44. package/templates/nuxt-web/web/composables/forge.ts +13 -0
  45. package/templates/nuxt-web/web/composables/useNotes.ts +24 -0
  46. package/templates/nuxt-web/web/nuxt.config.ts +11 -0
  47. package/templates/nuxt-web/web/package.json +17 -0
  48. package/templates/nuxt-web/web/plugins/forge.client.ts +10 -0
  49. package/templates/nuxt-web/web/plugins/forge.server.ts +10 -0
  50. package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -0
  51. package/templates/nuxt-web/web/tsconfig.json +3 -0
@@ -0,0 +1,8 @@
1
+ import { can, liveQuery } from "forge/server";
2
+
3
+ export const liveNotes = liveQuery({
4
+ auth: can("notes.read"),
5
+ handler: async (ctx) => {
6
+ return ctx.db.notes.all();
7
+ },
8
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "strict": true,
7
+ "noEmit": true,
8
+ "skipLibCheck": true,
9
+ "allowImportingTsExtensions": true,
10
+ "types": [
11
+ "node"
12
+ ]
13
+ },
14
+ "include": [
15
+ "src/**/*.ts"
16
+ ]
17
+ }
@@ -0,0 +1,67 @@
1
+ <script setup lang="ts">
2
+ import LiveNotes from "./components/LiveNotes.vue";
3
+ import NoteComposer from "./components/NoteComposer.vue";
4
+ </script>
5
+
6
+ <template>
7
+ <main class="shell">
8
+ <section class="header">
9
+ <p class="eyebrow">ForgeOS nuxt-web</p>
10
+ <h1>Notes</h1>
11
+ </section>
12
+
13
+ <NoteComposer />
14
+ <LiveNotes />
15
+ </main>
16
+ </template>
17
+
18
+ <style>
19
+ :root {
20
+ color: #17211d;
21
+ background: #f7f6f0;
22
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ }
28
+
29
+ body {
30
+ margin: 0;
31
+ }
32
+
33
+ button,
34
+ input,
35
+ textarea {
36
+ font: inherit;
37
+ }
38
+
39
+ .shell {
40
+ width: min(780px, calc(100vw - 32px));
41
+ margin: 0 auto;
42
+ padding: 48px 0;
43
+ }
44
+
45
+ .header {
46
+ margin-bottom: 24px;
47
+ }
48
+
49
+ .eyebrow {
50
+ margin: 0 0 6px;
51
+ color: #58655f;
52
+ font-size: 0.82rem;
53
+ font-weight: 700;
54
+ text-transform: uppercase;
55
+ }
56
+
57
+ h1,
58
+ h2,
59
+ p {
60
+ margin-top: 0;
61
+ }
62
+
63
+ h1 {
64
+ margin-bottom: 0;
65
+ font-size: 2.4rem;
66
+ }
67
+ </style>
@@ -0,0 +1,89 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+ import { useNotes } from "../composables/useNotes";
4
+
5
+ const { notes } = useNotes();
6
+ const noteCount = computed(() => notes.data.value?.length ?? 0);
7
+ </script>
8
+
9
+ <template>
10
+ <section class="notes">
11
+ <div class="section-heading">
12
+ <h2>Live notes</h2>
13
+ <span>{{ noteCount }}</span>
14
+ </div>
15
+ <p v-if="notes.loading.value" class="muted">Loading notes...</p>
16
+ <p v-else-if="notes.error.value" class="error">
17
+ {{ notes.error.value.message }}
18
+ </p>
19
+ <p v-else-if="noteCount === 0" class="muted">No notes yet.</p>
20
+ <ul v-else>
21
+ <li v-for="note in notes.data.value" :key="note.id">
22
+ <strong>{{ note.title }}</strong>
23
+ <p v-if="note.body">{{ note.body }}</p>
24
+ </li>
25
+ </ul>
26
+ </section>
27
+ </template>
28
+
29
+ <style scoped>
30
+ .notes {
31
+ border: 1px solid #d9ddd0;
32
+ border-radius: 8px;
33
+ background: #ffffff;
34
+ padding: 18px;
35
+ }
36
+
37
+ .section-heading {
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: space-between;
41
+ gap: 12px;
42
+ margin-bottom: 12px;
43
+ }
44
+
45
+ .section-heading h2 {
46
+ margin: 0;
47
+ font-size: 1.1rem;
48
+ }
49
+
50
+ .section-heading span {
51
+ display: inline-grid;
52
+ min-width: 28px;
53
+ height: 28px;
54
+ place-items: center;
55
+ border-radius: 999px;
56
+ color: #1f6f54;
57
+ background: #e4f2ec;
58
+ font-weight: 800;
59
+ }
60
+
61
+ ul {
62
+ display: grid;
63
+ gap: 10px;
64
+ margin: 0;
65
+ padding: 0;
66
+ list-style: none;
67
+ }
68
+
69
+ li {
70
+ border: 1px solid #edf0e7;
71
+ border-radius: 6px;
72
+ padding: 12px;
73
+ }
74
+
75
+ li p {
76
+ margin: 6px 0 0;
77
+ color: #53605a;
78
+ }
79
+
80
+ .muted {
81
+ margin: 0;
82
+ color: #6a756f;
83
+ }
84
+
85
+ .error {
86
+ margin: 0;
87
+ color: #a02d2d;
88
+ }
89
+ </style>
@@ -0,0 +1,100 @@
1
+ <script setup lang="ts">
2
+ import { ref } from "vue";
3
+ import { useNotes } from "../composables/useNotes";
4
+
5
+ const title = ref("");
6
+ const body = ref("");
7
+ const { createNote } = useNotes({
8
+ onCreated: () => {
9
+ title.value = "";
10
+ body.value = "";
11
+ },
12
+ });
13
+
14
+ async function submit() {
15
+ const trimmedTitle = title.value.trim();
16
+ if (!trimmedTitle || createNote.loading.value) {
17
+ return;
18
+ }
19
+
20
+ await createNote.run({
21
+ title: trimmedTitle,
22
+ body: body.value.trim(),
23
+ });
24
+ }
25
+ </script>
26
+
27
+ <template>
28
+ <form class="composer" @submit.prevent="submit">
29
+ <label>
30
+ <span>Title</span>
31
+ <input v-model="title" placeholder="Ship the full-stack loop" />
32
+ </label>
33
+ <label>
34
+ <span>Body</span>
35
+ <textarea v-model="body" placeholder="Optional note" />
36
+ </label>
37
+ <button :disabled="createNote.loading.value || !title.trim()" type="submit">
38
+ {{ createNote.loading.value ? "Creating..." : "Create note" }}
39
+ </button>
40
+ <p v-if="createNote.error.value" class="error">
41
+ {{ createNote.error.value.message }}
42
+ </p>
43
+ </form>
44
+ </template>
45
+
46
+ <style scoped>
47
+ .composer {
48
+ display: grid;
49
+ gap: 14px;
50
+ margin-bottom: 18px;
51
+ border: 1px solid #d9ddd0;
52
+ border-radius: 8px;
53
+ background: #ffffff;
54
+ padding: 18px;
55
+ }
56
+
57
+ label {
58
+ display: grid;
59
+ gap: 6px;
60
+ color: #39423e;
61
+ font-size: 0.92rem;
62
+ font-weight: 700;
63
+ }
64
+
65
+ input,
66
+ textarea {
67
+ width: 100%;
68
+ border: 1px solid #cfd5c6;
69
+ border-radius: 6px;
70
+ padding: 10px 12px;
71
+ color: #17211d;
72
+ background: #fbfcf8;
73
+ }
74
+
75
+ textarea {
76
+ min-height: 96px;
77
+ resize: vertical;
78
+ }
79
+
80
+ button {
81
+ justify-self: start;
82
+ min-height: 40px;
83
+ border: 0;
84
+ border-radius: 6px;
85
+ padding: 0 14px;
86
+ color: #ffffff;
87
+ background: #1f6f54;
88
+ font-weight: 800;
89
+ }
90
+
91
+ button:disabled {
92
+ cursor: not-allowed;
93
+ opacity: 0.6;
94
+ }
95
+
96
+ .error {
97
+ margin: 0;
98
+ color: #a02d2d;
99
+ }
100
+ </style>
@@ -0,0 +1,13 @@
1
+ export const forgeUrl = "http://127.0.0.1:3765";
2
+
3
+ export { api } from "../../src/forge/_generated/api";
4
+ export { createForgeClient, ForgeError } from "../../src/forge/_generated/client";
5
+ export {
6
+ ForgeVuePlugin,
7
+ provideForge,
8
+ useForgeAuth,
9
+ useForgeClient,
10
+ useForgeCommand,
11
+ useForgeLiveQuery,
12
+ useForgeQuery,
13
+ } from "../../src/forge/_generated/vue";
@@ -0,0 +1,24 @@
1
+ import { api, useForgeCommand, useForgeLiveQuery } from "./forge";
2
+
3
+ export type Note = {
4
+ id: string;
5
+ title: string;
6
+ body?: string;
7
+ status?: string;
8
+ createdAt?: string;
9
+ };
10
+
11
+ export function useNotes(options: { onCreated?: (note: Note) => void } = {}) {
12
+ const notes = useForgeLiveQuery<Note[]>(api.liveQueries.liveNotes, {});
13
+ const createNote = useForgeCommand<{ title: string; body?: string }, Note>(
14
+ api.commands.createNote,
15
+ {
16
+ onSuccess: (note) => options.onCreated?.(note),
17
+ },
18
+ );
19
+
20
+ return {
21
+ notes,
22
+ createNote,
23
+ };
24
+ }
@@ -0,0 +1,11 @@
1
+ export default defineNuxtConfig({
2
+ compatibilityDate: "2026-06-24",
3
+ runtimeConfig: {
4
+ public: {
5
+ forgeUrl: process.env.NUXT_PUBLIC_FORGE_URL ?? "http://127.0.0.1:3765",
6
+ },
7
+ },
8
+ typescript: {
9
+ strict: true,
10
+ },
11
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "__FORGE_APP_NAME__-web",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "nuxt dev --host 127.0.0.1",
7
+ "build": "nuxt build",
8
+ "typecheck": "nuxt typecheck"
9
+ },
10
+ "dependencies": {
11
+ "nuxt": "^4.0.0",
12
+ "vue": "^3.5.38"
13
+ },
14
+ "devDependencies": {
15
+ "typescript": "^5.7.3"
16
+ }
17
+ }
@@ -0,0 +1,10 @@
1
+ import { ForgeVuePlugin } from "../composables/forge";
2
+
3
+ export default defineNuxtPlugin((nuxtApp) => {
4
+ const config = useRuntimeConfig();
5
+
6
+ nuxtApp.vueApp.use(ForgeVuePlugin, {
7
+ url: String(config.public.forgeUrl),
8
+ devAuth: true,
9
+ });
10
+ });
@@ -0,0 +1,10 @@
1
+ import { ForgeVuePlugin } from "../composables/forge";
2
+
3
+ export default defineNuxtPlugin((nuxtApp) => {
4
+ const config = useRuntimeConfig();
5
+
6
+ nuxtApp.vueApp.use(ForgeVuePlugin, {
7
+ url: String(config.public.forgeUrl),
8
+ devAuth: true,
9
+ });
10
+ });
@@ -0,0 +1,7 @@
1
+ export default defineEventHandler(() => {
2
+ const config = useRuntimeConfig();
3
+
4
+ return {
5
+ forgeUrl: config.public.forgeUrl,
6
+ };
7
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "./.nuxt/tsconfig.json"
3
+ }