vibes-diy 2.6.1 → 2.6.3
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/LICENSE.md +19 -50
- package/README.md +27 -19
- package/cli/cmds/chat-response-render.d.ts +10 -0
- package/cli/cmds/chat-response-render.js +94 -0
- package/cli/cmds/chat-response-render.js.map +1 -0
- package/cli/cmds/chat-response-render.test.d.ts +1 -0
- package/cli/cmds/chat-response-render.test.js +140 -0
- package/cli/cmds/chat-response-render.test.js.map +1 -0
- package/cli/cmds/chats-cmd.d.ts +25 -1
- package/cli/cmds/chats-cmd.js +107 -3
- package/cli/cmds/chats-cmd.js.map +1 -1
- package/cli/cmds/chats-cmd.test.js +23 -0
- package/cli/cmds/chats-cmd.test.js.map +1 -1
- package/cli/cmds/db/subscribe-cmd.js +1 -1
- package/cli/cmds/db/subscribe-cmd.js.map +1 -1
- package/cli/cmds/db/subscribe-cmd.test.js +5 -1
- package/cli/cmds/db/subscribe-cmd.test.js.map +1 -1
- package/cli/cmds/edit-cmd.js +4 -3
- package/cli/cmds/edit-cmd.js.map +1 -1
- package/cli/cmds/generate-cmd.js +7 -4
- package/cli/cmds/generate-cmd.js.map +1 -1
- package/cli/cmds/generate-cmd.test.js +140 -1
- package/cli/cmds/generate-cmd.test.js.map +1 -1
- package/cli/cmds/push-from-dir.d.ts +2 -0
- package/cli/cmds/push-from-dir.js +1 -0
- package/cli/cmds/push-from-dir.js.map +1 -1
- package/cli/cmds/push-from-dir.test.js +22 -0
- package/cli/cmds/push-from-dir.test.js.map +1 -1
- package/cli/cmds/resolved-model.js +6 -1
- package/cli/cmds/resolved-model.js.map +1 -1
- package/cli/cmds/resolved-model.test.js +27 -0
- package/cli/cmds/resolved-model.test.js.map +1 -1
- package/cli/main.js +5 -1
- package/cli/main.js.map +1 -1
- package/package.json +6 -6
package/LICENSE.md
CHANGED
|
@@ -1,32 +1,3 @@
|
|
|
1
|
-
The contents of this repository are Copyright (c) corresponding authors and
|
|
2
|
-
contributors, licensed under the `Permissive License Stack` meaning either of:
|
|
3
|
-
|
|
4
|
-
- Apache-2.0 Software License: https://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
-
([...4tr2kfsq](https://dweb.link/ipfs/bafkreiankqxazcae4onkp436wag2lj3ccso4nawxqkkfckd6cg4tr2kfsq))
|
|
6
|
-
|
|
7
|
-
- MIT Software License: https://opensource.org/licenses/MIT
|
|
8
|
-
([...vljevcba](https://dweb.link/ipfs/bafkreiepofszg4gfe2gzuhojmksgemsub2h4uy2gewdnr35kswvljevcba))
|
|
9
|
-
|
|
10
|
-
You may not use the contents of this repository except in compliance
|
|
11
|
-
with one of the listed Licenses. For an extended clarification of the
|
|
12
|
-
intent behind the choice of Licensing please refer to
|
|
13
|
-
https://protocol.ai/blog/announcing-the-permissive-license-stack/
|
|
14
|
-
|
|
15
|
-
Unless required by applicable law or agreed to in writing, software
|
|
16
|
-
distributed under the terms listed in this notice is distributed on
|
|
17
|
-
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
18
|
-
either express or implied. See each License for the specific language
|
|
19
|
-
governing permissions and limitations under that License.
|
|
20
|
-
|
|
21
|
-
<!--- SPDX-License-Identifier: Apache-2.0 OR MIT -->
|
|
22
|
-
|
|
23
|
-
`SPDX-License-Identifier: Apache-2.0 OR MIT`
|
|
24
|
-
|
|
25
|
-
Verbatim copies of both licenses are included below:
|
|
26
|
-
|
|
27
|
-
<details><summary>Apache-2.0 Software License</summary>
|
|
28
|
-
|
|
29
|
-
```
|
|
30
1
|
Apache License
|
|
31
2
|
Version 2.0, January 2004
|
|
32
3
|
http://www.apache.org/licenses/
|
|
@@ -203,30 +174,28 @@ Verbatim copies of both licenses are included below:
|
|
|
203
174
|
of your accepting any such warranty or additional liability.
|
|
204
175
|
|
|
205
176
|
END OF TERMS AND CONDITIONS
|
|
206
|
-
```
|
|
207
177
|
|
|
208
|
-
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
209
179
|
|
|
210
|
-
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
211
188
|
|
|
212
|
-
|
|
213
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
214
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
215
|
-
in the Software without restriction, including without limitation the rights
|
|
216
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
217
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
218
|
-
furnished to do so, subject to the following conditions:
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
219
190
|
|
|
220
|
-
|
|
221
|
-
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
222
194
|
|
|
223
|
-
|
|
224
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
225
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
226
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
227
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
228
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
229
|
-
THE SOFTWARE.
|
|
230
|
-
```
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
231
196
|
|
|
232
|
-
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,23 +1,38 @@
|
|
|
1
1
|
[](https://discord.gg/vnpWycj4Ta)
|
|
3
3
|
|
|
4
|
-
# ✨
|
|
4
|
+
# ✨ Vibes DIY — make apps with your friends
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Software is getting weird again. Describe what you want and get a real, live app — fun, done, and alive. [Try it now](https://vibes.diy/) or [fork on GitHub](https://github.com/VibesDIY/vibes.diy).
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Make apps with your friends, so easy even AI can do it. Describe your app in plain words, it builds instantly, and you keep changing it just by talking to it. Share the link and your friends join right away — no setup, no "wait, let me send you the invite."
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Why it's different
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
12
|
+
- **Fun** — build for any reason, or no reason at all.
|
|
13
|
+
- **Done** — it's a real app at its own live link, not a prototype. State is saved automatically.
|
|
14
|
+
- **Alive** — keep talking to it and it keeps changing. So can anyone you share it with.
|
|
15
|
+
|
|
16
|
+
Seeing a vibe makes you want to change it. Start from someone else's, tweak it to fit you, share it, and the people you share with remix their own version. You're not a user anymore — you're a maker.
|
|
17
|
+
|
|
18
|
+
## What people make
|
|
19
|
+
|
|
20
|
+
A character bot that answers in your voice. A neighborhood resource tracker you share at the next town meeting. A flashcard app remixed into collaborative trivia your students change live. A workout tracker a whole gym swaps routines on. Every one is the same move: start, tweak, share, remix.
|
|
21
|
+
|
|
22
|
+
## Yours to control
|
|
23
|
+
|
|
24
|
+
Private by default — or open to the world. You choose. Keep an app to the people you invite, or publish it so anyone can use and remix it. You set who can read, write, and open it.
|
|
25
|
+
|
|
26
|
+
> Your app's data lives in a centralized cloud database. "Private" means access-gated from other people — not encrypted, and not hidden from the platform.
|
|
27
|
+
|
|
28
|
+
## Open source
|
|
29
|
+
|
|
30
|
+
The whole platform is open source under Apache 2.0. Read the code, open an issue, send a PR.
|
|
16
31
|
|
|
17
32
|
## Quick Start
|
|
18
33
|
|
|
19
|
-
1. [Try the demo](https://vibes.diy/)
|
|
20
|
-
2. Or
|
|
34
|
+
1. [Try the demo](https://vibes.diy/) — no setup required.
|
|
35
|
+
2. Or run it yourself:
|
|
21
36
|
- Clone the repository
|
|
22
37
|
- Install with `pnpm i`
|
|
23
38
|
- Run `pnpm dev`
|
|
@@ -28,11 +43,4 @@ We are committed to providing a welcoming and inclusive environment for all cont
|
|
|
28
43
|
|
|
29
44
|
Interested in contributing? Check out our [Contributing Guide](CONTRIBUTING.md) to get started.
|
|
30
45
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Every app you create is automatically saved, so you can:
|
|
34
|
-
|
|
35
|
-
- Browse your creations in the sidebar
|
|
36
|
-
- Return to previous work anytime
|
|
37
|
-
- Keep track of your building history
|
|
38
|
-
- Save screenshots of your apps
|
|
46
|
+
Find us on [Discord](https://discord.gg/vnpWycj4Ta), [Substack](https://vibesdiy.substack.com/), [YouTube](https://www.youtube.com/@VibesDIY), and [Bluesky](https://bsky.app/profile/vibes.diy).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Result } from "@adviser/cement";
|
|
2
|
+
import type { PromptAndBlockMsgs, ResChatResponseTurn, SectionEvent } from "@vibes.diy/api-types";
|
|
3
|
+
import { type ResolveSectionStreamResult } from "./resolve-section-stream.js";
|
|
4
|
+
export declare function turnBlocks(turn: ResChatResponseTurn): PromptAndBlockMsgs[];
|
|
5
|
+
export declare function reconstructVerbatim(blocks: readonly PromptAndBlockMsgs[]): string;
|
|
6
|
+
export declare function renderJsonl(blocks: readonly PromptAndBlockMsgs[]): string;
|
|
7
|
+
export declare function extractRawText(blocks: readonly PromptAndBlockMsgs[]): string | undefined;
|
|
8
|
+
export declare function extractUserPrompts(blocks: readonly PromptAndBlockMsgs[]): string[];
|
|
9
|
+
export declare function buildSectionStream(turn: ResChatResponseTurn): ReadableStream<SectionEvent>;
|
|
10
|
+
export declare function resolveTurnFiles(turns: readonly ResChatResponseTurn[], selectedPromptId: string): Promise<Result<ResolveSectionStreamResult>>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Result } from "@adviser/cement";
|
|
2
|
+
import { isCodeBegin, isCodeEnd, isCodeLine, isToplevelLine } from "@vibes.diy/call-ai-v2";
|
|
3
|
+
import { isPromptRaw, isPromptReq } from "@vibes.diy/api-types";
|
|
4
|
+
import { resolveSectionStream } from "./resolve-section-stream.js";
|
|
5
|
+
export function turnBlocks(turn) {
|
|
6
|
+
return turn.sections.flatMap((s) => s.blocks);
|
|
7
|
+
}
|
|
8
|
+
export function reconstructVerbatim(blocks) {
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const b of blocks) {
|
|
11
|
+
if (isToplevelLine(b)) {
|
|
12
|
+
out.push(b.line);
|
|
13
|
+
}
|
|
14
|
+
else if (isCodeBegin(b)) {
|
|
15
|
+
const info = b.path ? `${b.lang} ${b.path}` : b.lang;
|
|
16
|
+
out.push("```" + info);
|
|
17
|
+
}
|
|
18
|
+
else if (isCodeLine(b)) {
|
|
19
|
+
out.push(b.line);
|
|
20
|
+
}
|
|
21
|
+
else if (isCodeEnd(b)) {
|
|
22
|
+
out.push("```");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return out.join("\n");
|
|
26
|
+
}
|
|
27
|
+
export function renderJsonl(blocks) {
|
|
28
|
+
return blocks.map((b) => JSON.stringify(b)).join("\n");
|
|
29
|
+
}
|
|
30
|
+
export function extractRawText(blocks) {
|
|
31
|
+
const parts = blocks.filter(isPromptRaw).map((b) => b.text);
|
|
32
|
+
return parts.length === 0 ? undefined : parts.join("");
|
|
33
|
+
}
|
|
34
|
+
export function extractUserPrompts(blocks) {
|
|
35
|
+
const prompts = [];
|
|
36
|
+
for (const b of blocks) {
|
|
37
|
+
if (!isPromptReq(b))
|
|
38
|
+
continue;
|
|
39
|
+
for (const m of b.request.messages) {
|
|
40
|
+
if (m.role !== "user")
|
|
41
|
+
continue;
|
|
42
|
+
const text = m.content
|
|
43
|
+
.filter((c) => c.type === "text")
|
|
44
|
+
.map((c) => c.text)
|
|
45
|
+
.join("\n");
|
|
46
|
+
if (text !== "")
|
|
47
|
+
prompts.push(text);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return prompts;
|
|
51
|
+
}
|
|
52
|
+
export function buildSectionStream(turn) {
|
|
53
|
+
const events = turn.sections.map((s) => ({
|
|
54
|
+
type: "vibes.diy.section-event",
|
|
55
|
+
chatId: turn.chatId,
|
|
56
|
+
promptId: turn.promptId,
|
|
57
|
+
blockSeq: s.blockSeq,
|
|
58
|
+
timestamp: new Date(0),
|
|
59
|
+
blocks: s.blocks,
|
|
60
|
+
}));
|
|
61
|
+
return new ReadableStream({
|
|
62
|
+
start(controller) {
|
|
63
|
+
for (const e of events)
|
|
64
|
+
controller.enqueue(e);
|
|
65
|
+
controller.close();
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export async function resolveTurnFiles(turns, selectedPromptId) {
|
|
70
|
+
const selected = turns.find((t) => t.promptId === selectedPromptId);
|
|
71
|
+
if (selected === undefined) {
|
|
72
|
+
return Result.Err(new Error(`No turn with promptId ${selectedPromptId}`));
|
|
73
|
+
}
|
|
74
|
+
const chain = turns
|
|
75
|
+
.filter((t) => t.chatId === selected.chatId)
|
|
76
|
+
.slice()
|
|
77
|
+
.sort((a, b) => (a.created < b.created ? -1 : a.created > b.created ? 1 : 0));
|
|
78
|
+
let seed = new Map();
|
|
79
|
+
let last;
|
|
80
|
+
for (const t of chain) {
|
|
81
|
+
const r = await resolveSectionStream({ sectionStream: buildSectionStream(t), streamId: t.promptId, seed });
|
|
82
|
+
if (r.isErr())
|
|
83
|
+
return Result.Err(r.Err());
|
|
84
|
+
last = r.Ok();
|
|
85
|
+
seed = new Map(Object.entries(last.files));
|
|
86
|
+
if (t.promptId === selected.promptId)
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
if (last === undefined) {
|
|
90
|
+
return Result.Ok({ files: {}, errors: [], snapshotCount: 0, applyErrorCount: 0, turnEndSeen: false, promptErrors: [] });
|
|
91
|
+
}
|
|
92
|
+
return Result.Ok(last);
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=chat-response-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-response-render.js","sourceRoot":"","sources":["../../../jsr/cli/cmds/chat-response-render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildSectionStream, extractRawText, extractUserPrompts, reconstructVerbatim, renderJsonl, turnBlocks, } from "./chat-response-render.js";
|
|
3
|
+
import { resolveSectionStream } from "./resolve-section-stream.js";
|
|
4
|
+
const base = (seq) => ({
|
|
5
|
+
blockId: "blk",
|
|
6
|
+
streamId: "stream-1",
|
|
7
|
+
seq,
|
|
8
|
+
blockNr: 0,
|
|
9
|
+
timestamp: new Date(0),
|
|
10
|
+
});
|
|
11
|
+
function toplevelLine(seq, line) {
|
|
12
|
+
return { type: "block.toplevel.line", sectionId: "s", lineNr: seq, line, ...base(seq) };
|
|
13
|
+
}
|
|
14
|
+
function codeBegin(seq, lang, path) {
|
|
15
|
+
return { type: "block.code.begin", sectionId: "s", lang, path, ...base(seq) };
|
|
16
|
+
}
|
|
17
|
+
function codeLine(seq, lang, path, line) {
|
|
18
|
+
return { type: "block.code.line", sectionId: "s", lang, path, lineNr: seq, line, ...base(seq) };
|
|
19
|
+
}
|
|
20
|
+
function codeEnd(seq, lang, path) {
|
|
21
|
+
return {
|
|
22
|
+
type: "block.code.end",
|
|
23
|
+
sectionId: "s",
|
|
24
|
+
lang,
|
|
25
|
+
path,
|
|
26
|
+
stats: { lines: 1, bytes: 1 },
|
|
27
|
+
...base(seq),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
describe("reconstructVerbatim", () => {
|
|
31
|
+
it("renders prose, a fenced code block with its bound path, and close fence", () => {
|
|
32
|
+
const blocks = [
|
|
33
|
+
toplevelLine(0, "Here is the app:"),
|
|
34
|
+
codeBegin(1, "jsx", "App.jsx"),
|
|
35
|
+
codeLine(2, "jsx", "App.jsx", "export default function App() {}"),
|
|
36
|
+
codeEnd(3, "jsx", "App.jsx"),
|
|
37
|
+
];
|
|
38
|
+
expect(reconstructVerbatim(blocks)).toBe(["Here is the app:", "```jsx App.jsx", "export default function App() {}", "```"].join("\n"));
|
|
39
|
+
});
|
|
40
|
+
it("surfaces a path clobber: an orphaned label as prose, then a fence bound to the wrong path", () => {
|
|
41
|
+
const blocks = [
|
|
42
|
+
codeBegin(0, "jsx", "App.jsx"),
|
|
43
|
+
codeLine(1, "jsx", "App.jsx", "const a = 1;"),
|
|
44
|
+
codeEnd(2, "jsx", "App.jsx"),
|
|
45
|
+
toplevelLine(3, "access.js"),
|
|
46
|
+
toplevelLine(4, ""),
|
|
47
|
+
codeBegin(5, "js", "App.jsx"),
|
|
48
|
+
codeLine(6, "js", "App.jsx", "export const x = 1;"),
|
|
49
|
+
codeEnd(7, "js", "App.jsx"),
|
|
50
|
+
];
|
|
51
|
+
const out = reconstructVerbatim(blocks);
|
|
52
|
+
expect(out).toContain("access.js");
|
|
53
|
+
expect(out.match(/```js App\.jsx/g)).toHaveLength(1);
|
|
54
|
+
expect(out.match(/```jsx App\.jsx/g)).toHaveLength(1);
|
|
55
|
+
});
|
|
56
|
+
it("omits the path from the info-string when a fence carries none", () => {
|
|
57
|
+
const blocks = [{ type: "block.code.begin", sectionId: "s", lang: "txt", ...base(0) }];
|
|
58
|
+
expect(reconstructVerbatim(blocks)).toBe("```txt");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe("renderJsonl", () => {
|
|
62
|
+
it("emits one JSON object per line", () => {
|
|
63
|
+
const blocks = [toplevelLine(0, "a"), codeBegin(1, "js", "x.js")];
|
|
64
|
+
const lines = renderJsonl(blocks).split("\n");
|
|
65
|
+
expect(lines).toHaveLength(2);
|
|
66
|
+
expect(JSON.parse(lines[0]).type).toBe("block.toplevel.line");
|
|
67
|
+
expect(JSON.parse(lines[1]).type).toBe("block.code.begin");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe("extractRawText", () => {
|
|
71
|
+
const rawBlock = (text) => ({
|
|
72
|
+
type: "prompt.raw",
|
|
73
|
+
streamId: "stream-1",
|
|
74
|
+
chatId: "c",
|
|
75
|
+
seq: 9,
|
|
76
|
+
timestamp: new Date(0),
|
|
77
|
+
text,
|
|
78
|
+
});
|
|
79
|
+
it("returns the byte-faithful text from a prompt.raw block", () => {
|
|
80
|
+
const blocks = [toplevelLine(0, "App.jsx"), rawBlock("App.jsx\n\n```jsx\nconst a=1;\n```\n")];
|
|
81
|
+
expect(extractRawText(blocks)).toBe("App.jsx\n\n```jsx\nconst a=1;\n```\n");
|
|
82
|
+
});
|
|
83
|
+
it("returns undefined when no prompt.raw block is present (un-backfilled turn)", () => {
|
|
84
|
+
expect(extractRawText([toplevelLine(0, "hi"), codeBegin(1, "jsx", "App.jsx")])).toBeUndefined();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe("extractUserPrompts", () => {
|
|
88
|
+
it("pulls user message text from prompt.req blocks", () => {
|
|
89
|
+
const promptReq = {
|
|
90
|
+
type: "prompt.req",
|
|
91
|
+
streamId: "stream-1",
|
|
92
|
+
chatId: "c",
|
|
93
|
+
seq: 0,
|
|
94
|
+
timestamp: new Date(0),
|
|
95
|
+
request: {
|
|
96
|
+
messages: [
|
|
97
|
+
{ role: "system", content: [{ type: "text", text: "ignore me" }] },
|
|
98
|
+
{ role: "user", content: [{ type: "text", text: "build a todo app" }] },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
expect(extractUserPrompts([promptReq])).toEqual(["build a todo app"]);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe("buildSectionStream + resolveSectionStream", () => {
|
|
106
|
+
it("resolves files from a stored turn via the shared generate/edit resolver", async () => {
|
|
107
|
+
const blocks = [
|
|
108
|
+
{ type: "block.begin", ...base(0) },
|
|
109
|
+
codeBegin(0, "jsx", "App.jsx"),
|
|
110
|
+
codeLine(1, "jsx", "App.jsx", "export default function App() { return null; }"),
|
|
111
|
+
codeEnd(2, "jsx", "App.jsx"),
|
|
112
|
+
{
|
|
113
|
+
type: "block.end",
|
|
114
|
+
stats: {
|
|
115
|
+
toplevel: { lines: 0, bytes: 0 },
|
|
116
|
+
code: { lines: 1, bytes: 1 },
|
|
117
|
+
image: { lines: 0, bytes: 0 },
|
|
118
|
+
total: { lines: 1, bytes: 1 },
|
|
119
|
+
},
|
|
120
|
+
usage: { given: [], calculated: {} },
|
|
121
|
+
...base(3),
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
const turn = {
|
|
125
|
+
chatId: "c",
|
|
126
|
+
promptId: "stream-1",
|
|
127
|
+
created: "2026-01-01T00:00:00Z",
|
|
128
|
+
sections: [{ blockSeq: 0, blocks }],
|
|
129
|
+
};
|
|
130
|
+
expect(turnBlocks(turn)).toHaveLength(blocks.length);
|
|
131
|
+
const rResolved = await resolveSectionStream({
|
|
132
|
+
sectionStream: buildSectionStream(turn),
|
|
133
|
+
streamId: "stream-1",
|
|
134
|
+
});
|
|
135
|
+
expect(rResolved.isOk()).toBe(true);
|
|
136
|
+
const files = rResolved.Ok().files;
|
|
137
|
+
expect(files["App.jsx"]).toContain("export default function App()");
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=chat-response-render.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-response-render.test.js","sourceRoot":"","sources":["../../../jsr/cli/cmds/chat-response-render.test.ts"],"names":[],"mappings":"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"}
|
package/cli/cmds/chats-cmd.d.ts
CHANGED
|
@@ -7,9 +7,21 @@ export declare const ReqChats: import("arktype/internal/variants/object.ts").Obj
|
|
|
7
7
|
ownerHandle: string;
|
|
8
8
|
chatId?: string | undefined;
|
|
9
9
|
apiUrl: string;
|
|
10
|
+
response?: boolean | undefined;
|
|
11
|
+
raw?: boolean | undefined;
|
|
12
|
+
files?: boolean | undefined;
|
|
13
|
+
jsonl?: boolean | undefined;
|
|
14
|
+
user?: boolean | undefined;
|
|
15
|
+
promptId?: string | undefined;
|
|
10
16
|
}, {}>;
|
|
11
17
|
export type ReqChats = typeof ReqChats.infer;
|
|
12
18
|
export declare function isReqChats(obj: unknown): obj is ReqChats;
|
|
19
|
+
export declare const ResChatResponse: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
20
|
+
type: "vibes-diy.cli.res-chat-response";
|
|
21
|
+
output: string;
|
|
22
|
+
}, {}>;
|
|
23
|
+
export type ResChatResponse = typeof ResChatResponse.infer;
|
|
24
|
+
export declare function isResChatResponse(obj: unknown): obj is ResChatResponse;
|
|
13
25
|
export declare const ResChatsList: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
14
26
|
type: "vibes-diy.cli.res-chats-list";
|
|
15
27
|
items: {
|
|
@@ -34,7 +46,7 @@ export declare const ResChatDetail: import("arktype/internal/variants/object.ts"
|
|
|
34
46
|
}, {}>;
|
|
35
47
|
export type ResChatDetail = typeof ResChatDetail.infer;
|
|
36
48
|
export declare function isResChatDetail(obj: unknown): obj is ResChatDetail;
|
|
37
|
-
type ResChats = ResChatsList | ResChatDetail;
|
|
49
|
+
type ResChats = ResChatsList | ResChatDetail | ResChatResponse;
|
|
38
50
|
export declare const chatsEvento: EventoHandler<WrapCmdTSMsg<unknown>, ReqChats, ResChats>;
|
|
39
51
|
export declare function chatsCmd(ctx: CliCtx): Partial<import("cmd-ts/dist/cjs/argparser.js").Register> & {
|
|
40
52
|
parse(context: import("cmd-ts/dist/cjs/argparser.js").ParseContext): Promise<import("cmd-ts/dist/cjs/argparser.js").ParsingResult<{
|
|
@@ -42,6 +54,12 @@ export declare function chatsCmd(ctx: CliCtx): Partial<import("cmd-ts/dist/cjs/a
|
|
|
42
54
|
chatId: string | undefined;
|
|
43
55
|
vibe: string;
|
|
44
56
|
handle: string;
|
|
57
|
+
response: boolean;
|
|
58
|
+
raw: boolean;
|
|
59
|
+
files: boolean;
|
|
60
|
+
jsonl: boolean;
|
|
61
|
+
user: boolean;
|
|
62
|
+
turn: string | undefined;
|
|
45
63
|
apiUrl: string;
|
|
46
64
|
json: boolean;
|
|
47
65
|
text: boolean;
|
|
@@ -51,6 +69,12 @@ export declare function chatsCmd(ctx: CliCtx): Partial<import("cmd-ts/dist/cjs/a
|
|
|
51
69
|
chatId: string | undefined;
|
|
52
70
|
vibe: string;
|
|
53
71
|
handle: string;
|
|
72
|
+
response: boolean;
|
|
73
|
+
raw: boolean;
|
|
74
|
+
files: boolean;
|
|
75
|
+
jsonl: boolean;
|
|
76
|
+
user: boolean;
|
|
77
|
+
turn: string | undefined;
|
|
54
78
|
apiUrl: string;
|
|
55
79
|
json: boolean;
|
|
56
80
|
text: boolean;
|
package/cli/cmds/chats-cmd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { command, option, optional, positional, string } from "cmd-ts";
|
|
1
|
+
import { command, flag, option, optional, positional, string } from "cmd-ts";
|
|
2
2
|
import { Result, Option } from "@adviser/cement";
|
|
3
3
|
import { type } from "arktype";
|
|
4
4
|
import { resListApplicationChatsItem } from "@vibes.diy/api-types";
|
|
@@ -7,16 +7,30 @@ import { sendMsg } from "../cmd-evento.js";
|
|
|
7
7
|
import { resolveHandle } from "../resolve-handle.js";
|
|
8
8
|
import { formatErr } from "./format-err.js";
|
|
9
9
|
import { resolveVibePositionals } from "../parse-vibe.js";
|
|
10
|
+
import { extractRawText, extractUserPrompts, reconstructVerbatim, renderJsonl, resolveTurnFiles, turnBlocks, } from "./chat-response-render.js";
|
|
10
11
|
export const ReqChats = type({
|
|
11
12
|
type: "'vibes-diy.cli.chats'",
|
|
12
13
|
appSlug: "string",
|
|
13
14
|
ownerHandle: "string",
|
|
14
15
|
"chatId?": "string",
|
|
15
16
|
apiUrl: "string",
|
|
17
|
+
"response?": "boolean",
|
|
18
|
+
"raw?": "boolean",
|
|
19
|
+
"files?": "boolean",
|
|
20
|
+
"jsonl?": "boolean",
|
|
21
|
+
"user?": "boolean",
|
|
22
|
+
"promptId?": "string",
|
|
16
23
|
});
|
|
17
24
|
export function isReqChats(obj) {
|
|
18
25
|
return !(ReqChats(obj) instanceof type.errors);
|
|
19
26
|
}
|
|
27
|
+
export const ResChatResponse = type({
|
|
28
|
+
type: "'vibes-diy.cli.res-chat-response'",
|
|
29
|
+
output: "string",
|
|
30
|
+
});
|
|
31
|
+
export function isResChatResponse(obj) {
|
|
32
|
+
return !(ResChatResponse(obj) instanceof type.errors);
|
|
33
|
+
}
|
|
20
34
|
export const ResChatsList = type({
|
|
21
35
|
type: "'vibes-diy.cli.res-chats-list'",
|
|
22
36
|
items: resListApplicationChatsItem.array(),
|
|
@@ -54,6 +68,69 @@ export const chatsEvento = {
|
|
|
54
68
|
const args = ctx.validated;
|
|
55
69
|
const api = ectx.vibesDiyApiFactory(args.apiUrl);
|
|
56
70
|
const ownerHandle = await resolveHandle(api, args.ownerHandle === "" ? undefined : args.ownerHandle);
|
|
71
|
+
const wantResponse = args.response === true || args.raw === true || args.files === true || args.jsonl === true || args.user === true;
|
|
72
|
+
if (wantResponse) {
|
|
73
|
+
if (ownerHandle === undefined) {
|
|
74
|
+
return Result.Err("Could not resolve handle. Pass --handle or run 'vibes-diy login'.");
|
|
75
|
+
}
|
|
76
|
+
const rResp = await api.getChatResponse({
|
|
77
|
+
ownerHandle,
|
|
78
|
+
appSlug: args.appSlug,
|
|
79
|
+
...(args.chatId !== undefined ? { chatId: args.chatId } : {}),
|
|
80
|
+
});
|
|
81
|
+
if (rResp.isErr()) {
|
|
82
|
+
return Result.Err(formatErr(rResp.Err()));
|
|
83
|
+
}
|
|
84
|
+
const turns = rResp.Ok().turns;
|
|
85
|
+
if (turns.length === 0) {
|
|
86
|
+
return sendMsg(ctx, {
|
|
87
|
+
type: "vibes-diy.cli.res-chat-response",
|
|
88
|
+
output: "(no response found for this chat)",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
let turn = turns[0];
|
|
92
|
+
if (args.promptId !== undefined) {
|
|
93
|
+
turn = turns.find((t) => t.promptId === args.promptId);
|
|
94
|
+
if (turn === undefined) {
|
|
95
|
+
return Result.Err(`No turn with promptId ${args.promptId} in this chat.`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (turns.length > 1) {
|
|
99
|
+
ectx.output.stderr(`Showing newest turn ${turn.promptId} (${turns.length} turns total — use --turn <promptId> to pick another).\n`);
|
|
100
|
+
}
|
|
101
|
+
const blocks = turnBlocks(turn);
|
|
102
|
+
let body;
|
|
103
|
+
if (args.raw === true) {
|
|
104
|
+
const raw = extractRawText(blocks);
|
|
105
|
+
body =
|
|
106
|
+
raw ??
|
|
107
|
+
"(no raw capture for this turn — byte-faithful text is only stored for generations after raw capture shipped; try --jsonl or the default block-faithful view)";
|
|
108
|
+
}
|
|
109
|
+
else if (args.jsonl === true) {
|
|
110
|
+
body = renderJsonl(blocks);
|
|
111
|
+
}
|
|
112
|
+
else if (args.files === true) {
|
|
113
|
+
const rResolved = await resolveTurnFiles(turns, turn.promptId);
|
|
114
|
+
if (rResolved.isErr()) {
|
|
115
|
+
return Result.Err(`Failed to resolve stored stream: ${rResolved.Err().message}`);
|
|
116
|
+
}
|
|
117
|
+
body = JSON.stringify(rResolved.Ok().files, null, 2);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
body = reconstructVerbatim(blocks);
|
|
121
|
+
}
|
|
122
|
+
let output = body;
|
|
123
|
+
if (args.user === true) {
|
|
124
|
+
const userBlock = extractUserPrompts(blocks)
|
|
125
|
+
.map((p) => p
|
|
126
|
+
.split("\n")
|
|
127
|
+
.map((l) => `> ${l}`)
|
|
128
|
+
.join("\n"))
|
|
129
|
+
.join("\n>\n");
|
|
130
|
+
output = userBlock === "" ? body : `${userBlock}\n\n${body}`;
|
|
131
|
+
}
|
|
132
|
+
return sendMsg(ctx, { type: "vibes-diy.cli.res-chat-response", output });
|
|
133
|
+
}
|
|
57
134
|
switch (true) {
|
|
58
135
|
case args.chatId !== undefined: {
|
|
59
136
|
if (ownerHandle === undefined) {
|
|
@@ -128,8 +205,34 @@ export function chatsCmd(ctx) {
|
|
|
128
205
|
defaultValue: () => "",
|
|
129
206
|
defaultValueIsSerializable: true,
|
|
130
207
|
}),
|
|
208
|
+
response: flag({
|
|
209
|
+
long: "response",
|
|
210
|
+
short: "r",
|
|
211
|
+
description: "Show the model's reply, block-faithfully reconstructed from stored block events, instead of the user prompt",
|
|
212
|
+
}),
|
|
213
|
+
raw: flag({
|
|
214
|
+
long: "raw",
|
|
215
|
+
description: "With --response: byte-faithful raw model text captured upstream of the parser (preserves consumed labels & blank lines; new generations only)",
|
|
216
|
+
}),
|
|
217
|
+
files: flag({
|
|
218
|
+
long: "files",
|
|
219
|
+
description: "With --response: the resolved path→content map (via the generate/edit resolver)",
|
|
220
|
+
}),
|
|
221
|
+
jsonl: flag({
|
|
222
|
+
long: "jsonl",
|
|
223
|
+
description: "With --response: the raw block events, one JSON object per line",
|
|
224
|
+
}),
|
|
225
|
+
user: flag({
|
|
226
|
+
long: "user",
|
|
227
|
+
description: "With --response: also print the user prompt(s) so the full transcript reads top-down",
|
|
228
|
+
}),
|
|
229
|
+
turn: option({
|
|
230
|
+
long: "turn",
|
|
231
|
+
description: "With --response: select a specific turn by promptId (default: newest)",
|
|
232
|
+
type: optional(string),
|
|
233
|
+
}),
|
|
131
234
|
},
|
|
132
|
-
handler: ctx.cliStream.enqueue(({ handle, chatId, vibe, appSlug, ...rest }) => {
|
|
235
|
+
handler: ctx.cliStream.enqueue(({ handle, chatId, vibe, appSlug, turn, ...rest }) => {
|
|
133
236
|
const resolved = resolveVibePositionals({ vibe, handle, positionals: [appSlug, chatId] });
|
|
134
237
|
const resolvedChatId = resolved.trailing[0];
|
|
135
238
|
const base = {
|
|
@@ -138,7 +241,8 @@ export function chatsCmd(ctx) {
|
|
|
138
241
|
appSlug: resolved.appSlug,
|
|
139
242
|
ownerHandle: resolved.handle,
|
|
140
243
|
};
|
|
141
|
-
|
|
244
|
+
const withChat = resolvedChatId === undefined ? base : { ...base, chatId: resolvedChatId };
|
|
245
|
+
return turn === undefined ? withChat : { ...withChat, promptId: turn };
|
|
142
246
|
}),
|
|
143
247
|
});
|
|
144
248
|
}
|