@jinion/core 0.3.0 → 0.5.0
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/dist/agent/agent.d.ts +5 -1
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +3 -2
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/claude/approvals.d.ts +2 -1
- package/dist/agent/claude/approvals.d.ts.map +1 -1
- package/dist/agent/claude/approvals.js +2 -2
- package/dist/agent/claude/approvals.js.map +1 -1
- package/dist/agent/claude/backend.d.ts +4 -0
- package/dist/agent/claude/backend.d.ts.map +1 -1
- package/dist/agent/claude/backend.js +1 -1
- package/dist/agent/claude/backend.js.map +1 -1
- package/dist/agent/claude/events.js +1 -1
- package/dist/agent/claude/events.js.map +1 -1
- package/dist/agent/claude/guard.d.ts.map +1 -1
- package/dist/agent/claude/guard.js +2 -1
- package/dist/agent/claude/guard.js.map +1 -1
- package/dist/agent/claude/jinion-tools.d.ts +9 -1
- package/dist/agent/claude/jinion-tools.d.ts.map +1 -1
- package/dist/agent/claude/jinion-tools.js +14 -2
- package/dist/agent/claude/jinion-tools.js.map +1 -1
- package/dist/agent/claude/mcp.d.ts.map +1 -1
- package/dist/agent/claude/mcp.js +21 -1
- package/dist/agent/claude/mcp.js.map +1 -1
- package/dist/agent/claude/options.d.ts +9 -1
- package/dist/agent/claude/options.d.ts.map +1 -1
- package/dist/agent/claude/options.js +7 -3
- package/dist/agent/claude/options.js.map +1 -1
- package/dist/agent/claude/paths.d.ts +0 -3
- package/dist/agent/claude/paths.d.ts.map +1 -1
- package/dist/agent/claude/paths.js +1 -7
- package/dist/agent/claude/paths.js.map +1 -1
- package/dist/agent/claude/permissions.js +1 -1
- package/dist/agent/claude/permissions.js.map +1 -1
- package/dist/agent/claude/policy.d.ts +1 -1
- package/dist/agent/claude/policy.d.ts.map +1 -1
- package/dist/agent/claude/policy.js +1 -0
- package/dist/agent/claude/policy.js.map +1 -1
- package/dist/agent/claude/prompt.d.ts +2 -1
- package/dist/agent/claude/prompt.d.ts.map +1 -1
- package/dist/agent/claude/prompt.js +10 -5
- package/dist/agent/claude/prompt.js.map +1 -1
- package/dist/agent/claude/review.d.ts +4 -1
- package/dist/agent/claude/review.d.ts.map +1 -1
- package/dist/agent/claude/review.js +5 -2
- package/dist/agent/claude/review.js.map +1 -1
- package/dist/agent/claude/session.d.ts +8 -1
- package/dist/agent/claude/session.d.ts.map +1 -1
- package/dist/agent/claude/session.js +7 -1
- package/dist/agent/claude/session.js.map +1 -1
- package/dist/agent/claude/tool-calls.d.ts.map +1 -1
- package/dist/agent/claude/tool-calls.js +11 -2
- package/dist/agent/claude/tool-calls.js.map +1 -1
- package/dist/agent/codex/approvals.d.ts +1 -1
- package/dist/agent/codex/approvals.d.ts.map +1 -1
- package/dist/agent/codex/approvals.js +1 -1
- package/dist/agent/codex/approvals.js.map +1 -1
- package/dist/agent/codex/backend.d.ts +4 -0
- package/dist/agent/codex/backend.d.ts.map +1 -1
- package/dist/agent/codex/backend.js +1 -1
- package/dist/agent/codex/backend.js.map +1 -1
- package/dist/agent/codex/events.d.ts.map +1 -1
- package/dist/agent/codex/events.js +15 -1
- package/dist/agent/codex/events.js.map +1 -1
- package/dist/agent/codex/jinion-tools.d.ts +38 -4
- package/dist/agent/codex/jinion-tools.d.ts.map +1 -1
- package/dist/agent/codex/jinion-tools.js +57 -10
- package/dist/agent/codex/jinion-tools.js.map +1 -1
- package/dist/agent/codex/mcp.d.ts.map +1 -1
- package/dist/agent/codex/mcp.js +4 -0
- package/dist/agent/codex/mcp.js.map +1 -1
- package/dist/agent/codex/modes.d.ts +2 -2
- package/dist/agent/codex/modes.d.ts.map +1 -1
- package/dist/agent/codex/modes.js +4 -3
- package/dist/agent/codex/modes.js.map +1 -1
- package/dist/agent/codex/rewind.js +1 -47
- package/dist/agent/codex/rewind.js.map +1 -1
- package/dist/agent/codex/session.d.ts +10 -3
- package/dist/agent/codex/session.d.ts.map +1 -1
- package/dist/agent/codex/session.js +21 -7
- package/dist/agent/codex/session.js.map +1 -1
- package/dist/agent/demo/mcp.d.ts +2 -0
- package/dist/agent/demo/mcp.d.ts.map +1 -1
- package/dist/agent/demo/mcp.js +14 -0
- package/dist/agent/demo/mcp.js.map +1 -1
- package/dist/agent/demo/script.d.ts +8 -2
- package/dist/agent/demo/script.d.ts.map +1 -1
- package/dist/agent/demo/tasks.d.ts +4 -1
- package/dist/agent/demo/tasks.d.ts.map +1 -1
- package/dist/agent/events.d.ts +4 -0
- package/dist/agent/events.d.ts.map +1 -1
- package/dist/agent/events.js +2 -0
- package/dist/agent/events.js.map +1 -1
- package/dist/agent/mcp.d.ts +5 -0
- package/dist/agent/mcp.d.ts.map +1 -1
- package/dist/agent/mcp.js +2 -0
- package/dist/agent/mcp.js.map +1 -1
- package/dist/agent/modes.d.ts +15 -1
- package/dist/agent/modes.d.ts.map +1 -1
- package/dist/agent/modes.js +16 -1
- package/dist/agent/modes.js.map +1 -1
- package/dist/agent/patches.d.ts +5 -0
- package/dist/agent/patches.d.ts.map +1 -1
- package/dist/agent/patches.js +49 -0
- package/dist/agent/patches.js.map +1 -1
- package/dist/agent/review-tools.d.ts +15 -0
- package/dist/agent/review-tools.d.ts.map +1 -0
- package/dist/agent/review-tools.js +13 -0
- package/dist/agent/review-tools.js.map +1 -0
- package/dist/agent/review.d.ts +18 -6
- package/dist/agent/review.d.ts.map +1 -1
- package/dist/agent/review.js +52 -17
- package/dist/agent/review.js.map +1 -1
- package/dist/api/client.d.ts +19 -5
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +14 -3
- package/dist/api/client.js.map +1 -1
- package/dist/api/connection.d.ts +7 -2
- package/dist/api/connection.d.ts.map +1 -1
- package/dist/api/connection.js +6 -0
- package/dist/api/connection.js.map +1 -1
- package/dist/api/fields.d.ts +9 -7
- package/dist/api/fields.d.ts.map +1 -1
- package/dist/api/fields.js +3 -2
- package/dist/api/fields.js.map +1 -1
- package/dist/api/json-schema.d.ts +604 -95
- package/dist/api/json-schema.d.ts.map +1 -1
- package/dist/api/json-schema.js +2 -1
- package/dist/api/json-schema.js.map +1 -1
- package/dist/api/methods/accounts.d.ts.map +1 -1
- package/dist/api/methods/accounts.js +1 -2
- package/dist/api/methods/accounts.js.map +1 -1
- package/dist/api/methods/app.d.ts.map +1 -1
- package/dist/api/methods/app.js +9 -5
- package/dist/api/methods/app.js.map +1 -1
- package/dist/api/methods/files.d.ts +3 -1
- package/dist/api/methods/files.d.ts.map +1 -1
- package/dist/api/methods/files.js +75 -2
- package/dist/api/methods/files.js.map +1 -1
- package/dist/api/methods/git.d.ts.map +1 -1
- package/dist/api/methods/git.js +54 -6
- package/dist/api/methods/git.js.map +1 -1
- package/dist/api/methods/lsp.d.ts +7 -0
- package/dist/api/methods/lsp.d.ts.map +1 -0
- package/dist/api/methods/lsp.js +68 -0
- package/dist/api/methods/lsp.js.map +1 -0
- package/dist/api/methods/preview.d.ts +4 -1
- package/dist/api/methods/preview.d.ts.map +1 -1
- package/dist/api/methods/preview.js +19 -3
- package/dist/api/methods/preview.js.map +1 -1
- package/dist/api/methods/terminals.d.ts.map +1 -1
- package/dist/api/methods/terminals.js +7 -1
- package/dist/api/methods/terminals.js.map +1 -1
- package/dist/api/protocol.d.ts +774 -13
- package/dist/api/protocol.d.ts.map +1 -1
- package/dist/api/protocol.js +126 -8
- package/dist/api/protocol.js.map +1 -1
- package/dist/api/schemas.d.ts +15 -2
- package/dist/api/schemas.d.ts.map +1 -1
- package/dist/api/schemas.js +4 -0
- package/dist/api/schemas.js.map +1 -1
- package/dist/api/screen.d.ts +2 -0
- package/dist/api/screen.d.ts.map +1 -1
- package/dist/api/screen.js +3 -0
- package/dist/api/screen.js.map +1 -1
- package/dist/api/server.d.ts +2 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +13 -0
- package/dist/api/server.js.map +1 -1
- package/dist/commands/agent.js +3 -3
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/builtin.d.ts.map +1 -1
- package/dist/commands/builtin.js +2 -0
- package/dist/commands/builtin.js.map +1 -1
- package/dist/commands/conversation.d.ts.map +1 -1
- package/dist/commands/conversation.js +2 -0
- package/dist/commands/conversation.js.map +1 -1
- package/dist/commands/feedback.d.ts.map +1 -1
- package/dist/commands/feedback.js +1 -0
- package/dist/commands/feedback.js.map +1 -1
- package/dist/commands/notifications.d.ts.map +1 -1
- package/dist/commands/notifications.js +5 -3
- package/dist/commands/notifications.js.map +1 -1
- package/dist/commands/registry.d.ts +3 -0
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +14 -0
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/skill.d.ts +5 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +30 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/views.d.ts.map +1 -1
- package/dist/commands/views.js +5 -1
- package/dist/commands/views.js.map +1 -1
- package/dist/controllers/accounts.d.ts +5 -2
- package/dist/controllers/accounts.d.ts.map +1 -1
- package/dist/controllers/accounts.js +11 -8
- package/dist/controllers/accounts.js.map +1 -1
- package/dist/controllers/context.d.ts +2 -0
- package/dist/controllers/context.d.ts.map +1 -1
- package/dist/controllers/context.js.map +1 -1
- package/dist/controllers/feedback.d.ts +1 -1
- package/dist/controllers/feedback.d.ts.map +1 -1
- package/dist/controllers/feedback.js +4 -1
- package/dist/controllers/feedback.js.map +1 -1
- package/dist/controllers/input.d.ts.map +1 -1
- package/dist/controllers/input.js +2 -0
- package/dist/controllers/input.js.map +1 -1
- package/dist/controllers/jinion.d.ts +7 -0
- package/dist/controllers/jinion.d.ts.map +1 -1
- package/dist/controllers/jinion.js +7 -0
- package/dist/controllers/jinion.js.map +1 -1
- package/dist/controllers/mcp.d.ts +7 -2
- package/dist/controllers/mcp.d.ts.map +1 -1
- package/dist/controllers/mcp.js +23 -7
- package/dist/controllers/mcp.js.map +1 -1
- package/dist/controllers/mode.d.ts +8 -4
- package/dist/controllers/mode.d.ts.map +1 -1
- package/dist/controllers/mode.js +30 -4
- package/dist/controllers/mode.js.map +1 -1
- package/dist/controllers/session.d.ts.map +1 -1
- package/dist/controllers/session.js +5 -1
- package/dist/controllers/session.js.map +1 -1
- package/dist/controllers/turns.d.ts +1 -0
- package/dist/controllers/turns.d.ts.map +1 -1
- package/dist/controllers/turns.js +9 -2
- package/dist/controllers/turns.js.map +1 -1
- package/dist/conversation/activity.d.ts +5 -0
- package/dist/conversation/activity.d.ts.map +1 -0
- package/dist/conversation/activity.js +41 -0
- package/dist/conversation/activity.js.map +1 -0
- package/dist/conversation/apply-event.d.ts.map +1 -1
- package/dist/conversation/apply-event.js +2 -1
- package/dist/conversation/apply-event.js.map +1 -1
- package/dist/conversation/dialogs.d.ts +1 -0
- package/dist/conversation/dialogs.d.ts.map +1 -1
- package/dist/conversation/edits.d.ts +5 -0
- package/dist/conversation/edits.d.ts.map +1 -1
- package/dist/conversation/edits.js +10 -0
- package/dist/conversation/edits.js.map +1 -1
- package/dist/conversation/reducer.d.ts +12 -0
- package/dist/conversation/reducer.d.ts.map +1 -1
- package/dist/design/guides.d.ts +78 -5
- package/dist/design/guides.d.ts.map +1 -1
- package/dist/design/guides.js +78 -5
- package/dist/design/guides.js.map +1 -1
- package/dist/design/prompt.d.ts +1 -1
- package/dist/design/prompt.d.ts.map +1 -1
- package/dist/design/prompt.js +2 -2
- package/dist/design/prompt.js.map +1 -1
- package/dist/design/tools.d.ts +2 -0
- package/dist/design/tools.d.ts.map +1 -1
- package/dist/design/tools.js +6 -2
- package/dist/design/tools.js.map +1 -1
- package/dist/directions/directions.d.ts +42 -0
- package/dist/directions/directions.d.ts.map +1 -0
- package/dist/directions/directions.js +120 -0
- package/dist/directions/directions.js.map +1 -0
- package/dist/directions/store.d.ts +34 -0
- package/dist/directions/store.d.ts.map +1 -0
- package/dist/directions/store.js +61 -0
- package/dist/directions/store.js.map +1 -0
- package/dist/directions/tools.d.ts +29 -0
- package/dist/directions/tools.d.ts.map +1 -0
- package/dist/directions/tools.js +57 -0
- package/dist/directions/tools.js.map +1 -0
- package/dist/directions/viewer.d.ts +6 -0
- package/dist/directions/viewer.d.ts.map +1 -0
- package/dist/directions/viewer.js +266 -0
- package/dist/directions/viewer.js.map +1 -0
- package/dist/files/names.d.ts +6 -0
- package/dist/files/names.d.ts.map +1 -0
- package/dist/files/names.js +18 -0
- package/dist/files/names.js.map +1 -0
- package/dist/files/operations.d.ts +54 -0
- package/dist/files/operations.d.ts.map +1 -0
- package/dist/files/operations.js +173 -0
- package/dist/files/operations.js.map +1 -0
- package/dist/files/search.d.ts +11 -0
- package/dist/files/search.d.ts.map +1 -0
- package/dist/files/search.js +112 -0
- package/dist/files/search.js.map +1 -0
- package/dist/files/trash.d.ts +11 -0
- package/dist/files/trash.d.ts.map +1 -0
- package/dist/files/trash.js +64 -0
- package/dist/files/trash.js.map +1 -0
- package/dist/files/types.d.ts +112 -0
- package/dist/files/types.d.ts.map +1 -0
- package/dist/files/types.js +47 -0
- package/dist/files/types.js.map +1 -0
- package/dist/files/watch.d.ts +26 -0
- package/dist/files/watch.d.ts.map +1 -0
- package/dist/files/watch.js +107 -0
- package/dist/files/watch.js.map +1 -0
- package/dist/git/blame.d.ts +10 -0
- package/dist/git/blame.d.ts.map +1 -0
- package/dist/git/blame.js +91 -0
- package/dist/git/blame.js.map +1 -0
- package/dist/git/repos.d.ts +5 -0
- package/dist/git/repos.d.ts.map +1 -1
- package/dist/git/repos.js +13 -0
- package/dist/git/repos.js.map +1 -1
- package/dist/git/staging.d.ts +10 -1
- package/dist/git/staging.d.ts.map +1 -1
- package/dist/git/staging.js +21 -0
- package/dist/git/staging.js.map +1 -1
- package/dist/git/types.d.ts +48 -0
- package/dist/git/types.d.ts.map +1 -1
- package/dist/git/types.js +25 -0
- package/dist/git/types.js.map +1 -1
- package/dist/host.d.ts +2 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +8 -1
- package/dist/host.js.map +1 -1
- package/dist/lib/glob.d.ts +6 -0
- package/dist/lib/glob.d.ts.map +1 -0
- package/dist/lib/glob.js +49 -0
- package/dist/lib/glob.js.map +1 -0
- package/dist/lib/paths.d.ts +3 -0
- package/dist/lib/paths.d.ts.map +1 -1
- package/dist/lib/paths.js +9 -1
- package/dist/lib/paths.js.map +1 -1
- package/dist/look/tools.d.ts +7 -1
- package/dist/look/tools.d.ts.map +1 -1
- package/dist/look/tools.js +19 -4
- package/dist/look/tools.js.map +1 -1
- package/dist/lsp/code-intelligence.d.ts +87 -0
- package/dist/lsp/code-intelligence.d.ts.map +1 -0
- package/dist/lsp/code-intelligence.js +343 -0
- package/dist/lsp/code-intelligence.js.map +1 -0
- package/dist/lsp/edits.d.ts +4 -0
- package/dist/lsp/edits.d.ts.map +1 -0
- package/dist/lsp/edits.js +14 -0
- package/dist/lsp/edits.js.map +1 -0
- package/dist/lsp/project-check.d.ts +8 -0
- package/dist/lsp/project-check.d.ts.map +1 -0
- package/dist/lsp/project-check.js +71 -0
- package/dist/lsp/project-check.js.map +1 -0
- package/dist/lsp/results.d.ts +95 -0
- package/dist/lsp/results.d.ts.map +1 -0
- package/dist/lsp/results.js +116 -0
- package/dist/lsp/results.js.map +1 -0
- package/dist/lsp/server.d.ts +22 -0
- package/dist/lsp/server.d.ts.map +1 -0
- package/dist/lsp/server.js +123 -0
- package/dist/lsp/server.js.map +1 -0
- package/dist/lsp/servers.d.ts +21 -0
- package/dist/lsp/servers.d.ts.map +1 -0
- package/dist/lsp/servers.js +57 -0
- package/dist/lsp/servers.js.map +1 -0
- package/dist/lsp/transport.d.ts +9 -0
- package/dist/lsp/transport.d.ts.map +1 -0
- package/dist/lsp/transport.js +64 -0
- package/dist/lsp/transport.js.map +1 -0
- package/dist/lsp/types.d.ts +262 -0
- package/dist/lsp/types.d.ts.map +1 -0
- package/dist/lsp/types.js +64 -0
- package/dist/lsp/types.js.map +1 -0
- package/dist/map/prompt.d.ts.map +1 -1
- package/dist/map/prompt.js +2 -1
- package/dist/map/prompt.js.map +1 -1
- package/dist/map/review.d.ts +29 -9
- package/dist/map/review.d.ts.map +1 -1
- package/dist/map/review.js +105 -25
- package/dist/map/review.js.map +1 -1
- package/dist/mcp/login.d.ts +2 -0
- package/dist/mcp/login.d.ts.map +1 -1
- package/dist/mcp/login.js +5 -0
- package/dist/mcp/login.js.map +1 -1
- package/dist/preview/pages.d.ts +17 -0
- package/dist/preview/pages.d.ts.map +1 -0
- package/dist/preview/pages.js +92 -0
- package/dist/preview/pages.js.map +1 -0
- package/dist/preview/previews.d.ts +22 -0
- package/dist/preview/previews.d.ts.map +1 -0
- package/dist/preview/previews.js +28 -0
- package/dist/preview/previews.js.map +1 -0
- package/dist/preview/prompt.d.ts +3 -0
- package/dist/preview/prompt.d.ts.map +1 -0
- package/dist/preview/prompt.js +5 -0
- package/dist/preview/prompt.js.map +1 -0
- package/dist/preview/tools.d.ts +21 -0
- package/dist/preview/tools.d.ts.map +1 -0
- package/dist/preview/tools.js +34 -0
- package/dist/preview/tools.js.map +1 -0
- package/dist/preview/types.d.ts +7 -0
- package/dist/preview/types.d.ts.map +1 -1
- package/dist/preview/types.js +2 -0
- package/dist/preview/types.js.map +1 -1
- package/dist/prompt/files.d.ts +4 -1
- package/dist/prompt/files.d.ts.map +1 -1
- package/dist/prompt/files.js +23 -8
- package/dist/prompt/files.js.map +1 -1
- package/dist/settings/user.d.ts +2 -0
- package/dist/settings/user.d.ts.map +1 -1
- package/dist/settings/user.js.map +1 -1
- package/dist/skills/tools.d.ts +26 -0
- package/dist/skills/tools.d.ts.map +1 -0
- package/dist/skills/tools.js +34 -0
- package/dist/skills/tools.js.map +1 -0
- package/dist/state/agent.d.ts +2 -2
- package/dist/state/session.d.ts +9 -5
- package/dist/state/session.d.ts.map +1 -1
- package/dist/state/session.js +1 -0
- package/dist/state/session.js.map +1 -1
- package/package.json +3 -1
- package/schema/api.json +3017 -45
- package/vendor/darwin-arm64/build.json +62 -0
- package/vendor/darwin-arm64/ffmpeg +0 -0
- package/vendor/darwin-arm64/ffprobe +0 -0
- package/vendor/darwin-arm64/licenses/README.md +13 -0
- package/vendor/darwin-arm64/licenses/ffmpeg-LGPL-2.1.txt +502 -0
- package/vendor/darwin-arm64/licenses/whisper.cpp-MIT.txt +21 -0
- package/vendor/darwin-arm64/voices.bin +0 -0
- package/vendor/darwin-arm64/whisper-cli +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { createServer } from 'node:http';
|
|
3
|
+
import { basename } from 'node:path';
|
|
4
|
+
import { DirectionsStore } from './store.js';
|
|
5
|
+
import { viewerPage } from './viewer.js';
|
|
6
|
+
const MAX_PICK_BYTES = 4 * 1024;
|
|
7
|
+
/** The viewer as a Preview beside the thread shows it, which has no room for the rounds. */
|
|
8
|
+
export const SIDEBAR_CLOSED = '#sidebar-closed';
|
|
9
|
+
/**
|
|
10
|
+
* Jinion's own place to show directions, the same for every project and client: the rounds kept under the project's
|
|
11
|
+
* folder in `~/.jinion`, served to a viewer on 127.0.0.1 behind a token. Nothing listens before a round is shown.
|
|
12
|
+
*/
|
|
13
|
+
export class Directions {
|
|
14
|
+
cwd;
|
|
15
|
+
store;
|
|
16
|
+
token = randomBytes(16).toString('hex');
|
|
17
|
+
/** The conversation each round was shown in, while it is open; a pick on any other is only kept. */
|
|
18
|
+
listeners = new Map();
|
|
19
|
+
server;
|
|
20
|
+
port;
|
|
21
|
+
constructor(cwd) {
|
|
22
|
+
this.cwd = cwd;
|
|
23
|
+
this.store = new DirectionsStore(cwd);
|
|
24
|
+
}
|
|
25
|
+
async show(offered, onPick) {
|
|
26
|
+
const round = this.store.add(offered);
|
|
27
|
+
this.listeners.set(round.id, onPick);
|
|
28
|
+
const viewer = await this.address();
|
|
29
|
+
return {
|
|
30
|
+
round,
|
|
31
|
+
address: `${viewer}?round=${round.id}`,
|
|
32
|
+
/** Each direction's page alone, for the agent to look at. */
|
|
33
|
+
pages: round.directions.map((_, index) => `${viewer}rounds/${round.id}/${index + 1}`),
|
|
34
|
+
/** Each direction in the viewer without its sidebar, as a Preview shows the round. */
|
|
35
|
+
shown: round.directions.map((_, index) => `${viewer}?round=${round.id}&direction=${index + 1}${SIDEBAR_CLOSED}`),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** The viewer, at the newest round. */
|
|
39
|
+
async address() {
|
|
40
|
+
this.port ??= this.listen();
|
|
41
|
+
return `http://127.0.0.1:${await this.port}/${this.token}/`;
|
|
42
|
+
}
|
|
43
|
+
pick(id, direction) {
|
|
44
|
+
const round = this.store.pick(id, direction);
|
|
45
|
+
if (!round)
|
|
46
|
+
return undefined;
|
|
47
|
+
const listener = this.listeners.get(id);
|
|
48
|
+
listener?.({ round, direction });
|
|
49
|
+
return { round, sent: listener !== undefined };
|
|
50
|
+
}
|
|
51
|
+
close() {
|
|
52
|
+
this.server?.close();
|
|
53
|
+
this.server = undefined;
|
|
54
|
+
this.port = undefined;
|
|
55
|
+
}
|
|
56
|
+
listen() {
|
|
57
|
+
const server = createServer((request, response) => this.receive(request, response));
|
|
58
|
+
this.server = server;
|
|
59
|
+
// The app quits whether or not a browser still holds a connection open.
|
|
60
|
+
server.unref();
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
server.once('error', reject);
|
|
63
|
+
server.listen(0, '127.0.0.1', () => resolve(server.address().port));
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
receive(request, response) {
|
|
67
|
+
const { pathname } = new URL(request.url ?? '/', 'http://127.0.0.1');
|
|
68
|
+
const [token, ...rest] = pathname.split('/').slice(1);
|
|
69
|
+
const path = rest.join('/');
|
|
70
|
+
response.setHeader('Cache-Control', 'no-store');
|
|
71
|
+
if (token !== this.token)
|
|
72
|
+
return void response.writeHead(404).end();
|
|
73
|
+
if (request.method === 'GET' && path === '')
|
|
74
|
+
return send(response, 'text/html', viewerPage(basename(this.cwd)));
|
|
75
|
+
if (request.method === 'GET' && path === 'rounds')
|
|
76
|
+
return send(response, 'application/json', JSON.stringify(this.store.list()));
|
|
77
|
+
const page = /^rounds\/([^/]+)\/(\d+)$/.exec(path);
|
|
78
|
+
if (request.method === 'GET' && page) {
|
|
79
|
+
const html = this.store.page(page[1], Number(page[2]) - 1);
|
|
80
|
+
if (html === undefined)
|
|
81
|
+
return void response.writeHead(404).end();
|
|
82
|
+
// A page of its own origin, so what the agent wrote can't reach the viewer, its token or the picks.
|
|
83
|
+
response.setHeader('Content-Security-Policy', 'sandbox allow-scripts allow-forms allow-popups');
|
|
84
|
+
return send(response, 'text/html', html);
|
|
85
|
+
}
|
|
86
|
+
const pick = /^rounds\/([^/]+)\/pick$/.exec(path);
|
|
87
|
+
if (request.method === 'POST' && pick)
|
|
88
|
+
return this.receivePick(request, response, pick[1]);
|
|
89
|
+
response.writeHead(404).end();
|
|
90
|
+
}
|
|
91
|
+
receivePick(request, response, id) {
|
|
92
|
+
const chunks = [];
|
|
93
|
+
let size = 0;
|
|
94
|
+
request.on('data', (chunk) => {
|
|
95
|
+
size += chunk.length;
|
|
96
|
+
if (size <= MAX_PICK_BYTES)
|
|
97
|
+
chunks.push(chunk);
|
|
98
|
+
});
|
|
99
|
+
request.on('end', () => {
|
|
100
|
+
const direction = size <= MAX_PICK_BYTES ? directionOf(Buffer.concat(chunks).toString('utf8')) : undefined;
|
|
101
|
+
const answer = direction === undefined ? undefined : this.pick(id, direction);
|
|
102
|
+
if (!answer)
|
|
103
|
+
return void response.writeHead(400).end();
|
|
104
|
+
send(response, 'application/json', JSON.stringify(answer));
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function send(response, type, body) {
|
|
109
|
+
response.writeHead(200, { 'Content-Type': `${type}; charset=utf-8` }).end(body);
|
|
110
|
+
}
|
|
111
|
+
function directionOf(body) {
|
|
112
|
+
try {
|
|
113
|
+
const { direction } = JSON.parse(body);
|
|
114
|
+
return typeof direction === 'string' ? direction : undefined;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=directions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directions.js","sourceRoot":"","sources":["../../src/directions/directions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface Direction {
|
|
2
|
+
name: string;
|
|
3
|
+
idea: string;
|
|
4
|
+
}
|
|
5
|
+
/** A round as the agent hands it over: each direction with its page. */
|
|
6
|
+
export interface Offered {
|
|
7
|
+
title: string;
|
|
8
|
+
directions: (Direction & {
|
|
9
|
+
html: string;
|
|
10
|
+
})[];
|
|
11
|
+
}
|
|
12
|
+
export interface Round {
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
/** When it was shown, in milliseconds. */
|
|
16
|
+
at: number;
|
|
17
|
+
directions: Direction[];
|
|
18
|
+
picked?: string;
|
|
19
|
+
}
|
|
20
|
+
/** The project's rounds of directions, a folder each, out of the project and of git. */
|
|
21
|
+
export declare class DirectionsStore {
|
|
22
|
+
private readonly cwd;
|
|
23
|
+
constructor(cwd: string);
|
|
24
|
+
get dir(): string;
|
|
25
|
+
add({ title, directions }: Offered): Round;
|
|
26
|
+
/** The newest first. */
|
|
27
|
+
list(): Round[];
|
|
28
|
+
get(id: string): Round | undefined;
|
|
29
|
+
/** The page of a round's direction, by its place in the round. */
|
|
30
|
+
page(id: string, index: number): string | undefined;
|
|
31
|
+
pick(id: string, name: string): Round | undefined;
|
|
32
|
+
private save;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/directions/store.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wEAAwE;AACxE,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,CAAC,SAAS,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wFAAwF;AACxF,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,GAAG;IAAhC,YAA6B,GAAG,EAAE,MAAM,EAAI;IAE5C,IAAI,GAAG,WAEN;IAED,GAAG,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,OAAO,GAAG,KAAK,CASzC;IAED,wBAAwB;IACxB,IAAI,IAAI,KAAK,EAAE,CAMd;IAED,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAMjC;IAED,kEAAkE;IAClE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,sBAK7B;IAED,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAShD;IAED,OAAO,CAAC,IAAI;CAGb"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { projectDir } from '../lib/paths.js';
|
|
5
|
+
/** The project's rounds of directions, a folder each, out of the project and of git. */
|
|
6
|
+
export class DirectionsStore {
|
|
7
|
+
cwd;
|
|
8
|
+
constructor(cwd) {
|
|
9
|
+
this.cwd = cwd;
|
|
10
|
+
}
|
|
11
|
+
get dir() {
|
|
12
|
+
return join(projectDir(this.cwd), 'directions');
|
|
13
|
+
}
|
|
14
|
+
add({ title, directions }) {
|
|
15
|
+
const round = { id: randomUUID().slice(0, 8), title, at: Date.now(), directions: directions.map(({ name, idea }) => ({ name, idea })) };
|
|
16
|
+
const folder = join(this.dir, round.id);
|
|
17
|
+
mkdirSync(folder, { recursive: true });
|
|
18
|
+
for (const [index, { html }] of directions.entries())
|
|
19
|
+
writeFileSync(join(folder, pageName(index)), html);
|
|
20
|
+
this.save(round);
|
|
21
|
+
return round;
|
|
22
|
+
}
|
|
23
|
+
/** The newest first. */
|
|
24
|
+
list() {
|
|
25
|
+
if (!existsSync(this.dir))
|
|
26
|
+
return [];
|
|
27
|
+
return readdirSync(this.dir)
|
|
28
|
+
.flatMap((id) => this.get(id) ?? [])
|
|
29
|
+
.sort((a, b) => b.at - a.at);
|
|
30
|
+
}
|
|
31
|
+
get(id) {
|
|
32
|
+
if (!ROUND_ID.test(id))
|
|
33
|
+
return undefined;
|
|
34
|
+
const file = join(this.dir, id, 'round.json');
|
|
35
|
+
return existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : undefined;
|
|
36
|
+
}
|
|
37
|
+
/** The page of a round's direction, by its place in the round. */
|
|
38
|
+
page(id, index) {
|
|
39
|
+
const round = this.get(id);
|
|
40
|
+
if (!round || !Number.isInteger(index) || index < 0 || index >= round.directions.length)
|
|
41
|
+
return undefined;
|
|
42
|
+
return readFileSync(join(this.dir, id, pageName(index)), 'utf8');
|
|
43
|
+
}
|
|
44
|
+
pick(id, name) {
|
|
45
|
+
const round = this.get(id);
|
|
46
|
+
if (!round?.directions.some((direction) => direction.name === name))
|
|
47
|
+
return undefined;
|
|
48
|
+
const picked = { ...round, picked: name };
|
|
49
|
+
this.save(picked);
|
|
50
|
+
return picked;
|
|
51
|
+
}
|
|
52
|
+
save(round) {
|
|
53
|
+
writeFileSync(join(this.dir, round.id, 'round.json'), `${JSON.stringify(round, null, 2)}\n`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Ids come back in addresses, so only one of ours ever names a folder.
|
|
57
|
+
const ROUND_ID = /^[0-9a-f]{8}$/;
|
|
58
|
+
function pageName(index) {
|
|
59
|
+
return `${index + 1}.html`;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/directions/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ToolCall } from '../agent/tools.js';
|
|
3
|
+
import type { Previews } from '../preview/previews.js';
|
|
4
|
+
import { type Directions, type Picked } from './directions.js';
|
|
5
|
+
/** A tool the agent shows directions with; each backend offers it its own way. */
|
|
6
|
+
export interface DirectionsTool<S extends z.ZodRawShape = z.ZodRawShape> {
|
|
7
|
+
description: string;
|
|
8
|
+
input: S;
|
|
9
|
+
run(input: z.infer<z.ZodObject<S>>): Promise<string>;
|
|
10
|
+
}
|
|
11
|
+
/** `onPick` is told of a pick on a round this conversation showed; `previews` opens the round beside the thread where the app has a Preview. */
|
|
12
|
+
export declare function directionsTools(directions: Directions, onPick: (picked: Picked) => void, previews?: Previews): {
|
|
13
|
+
show_directions: DirectionsTool<{
|
|
14
|
+
title: z.ZodString;
|
|
15
|
+
directions: z.ZodArray<z.ZodObject<{
|
|
16
|
+
name: z.ZodString;
|
|
17
|
+
idea: z.ZodString;
|
|
18
|
+
html: z.ZodString;
|
|
19
|
+
}, z.core.$strip>>;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
export type DirectionsTools = ReturnType<typeof directionsTools>;
|
|
23
|
+
export type DirectionsAction = keyof DirectionsTools;
|
|
24
|
+
export declare const DIRECTIONS_ACTIONS: Set<string>;
|
|
25
|
+
/** A call of the tool as the conversation shows it, worded alike whichever backend made it. */
|
|
26
|
+
export declare function directionsCall(input: unknown): ToolCall;
|
|
27
|
+
/** What the user's pick says to the agent, as their own message. */
|
|
28
|
+
export declare function pickMessage({ round, direction }: Picked): string;
|
|
29
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/directions/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,MAAM,EAAkB,MAAM,iBAAiB,CAAC;AAE/E,kFAAkF;AAClF,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,CAAC,CAAC;IACT,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AAMD,gJAAgJ;AAChJ,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,EAAE,QAAQ,CAAC,EAAE,QAAQ;IAEzG,eAAe;;;;;;;;EA4ClB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAEjE,MAAM,MAAM,gBAAgB,GAAG,MAAM,eAAe,CAAC;AAErD,eAAO,MAAM,kBAAkB,aAAoE,CAAC;AAEpG,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAIvD;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,UAEvD"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { errorMessage } from '../lib/errors.js';
|
|
3
|
+
import { SIDEBAR_CLOSED } from './directions.js';
|
|
4
|
+
const MAX_PAGE_BYTES = 2 * 1024 * 1024;
|
|
5
|
+
const define = (tool) => tool;
|
|
6
|
+
/** `onPick` is told of a pick on a round this conversation showed; `previews` opens the round beside the thread where the app has a Preview. */
|
|
7
|
+
export function directionsTools(directions, onPick, previews) {
|
|
8
|
+
return {
|
|
9
|
+
show_directions: define({
|
|
10
|
+
description: "Shows the user a round of directions to pick from, in Jinion's own viewer outside the project: each direction's name, its idea in a sentence and its page. Use it whenever you offer directions, rather than describing them in words or writing their pages into the project. Nothing is written in the project and nothing is asked. The user's pick comes back as their next message.",
|
|
11
|
+
input: {
|
|
12
|
+
title: z.string().describe('What the round decides, in a few words, such as "The today screen".'),
|
|
13
|
+
directions: z
|
|
14
|
+
.array(z.object({
|
|
15
|
+
name: z.string().describe('A word or two the user can call it by.'),
|
|
16
|
+
idea: z.string().describe('What it stands for and what it gives up, in a sentence.'),
|
|
17
|
+
html: z
|
|
18
|
+
.string()
|
|
19
|
+
.describe("Its page: one whole HTML document, its CSS and any script inline, pictures as data: URLs or from the web. Nothing from the project's files or its dev server, which the viewer can't reach."),
|
|
20
|
+
}))
|
|
21
|
+
.min(2)
|
|
22
|
+
.max(4),
|
|
23
|
+
},
|
|
24
|
+
run: async ({ title, directions: offered }) => {
|
|
25
|
+
const names = offered.map(({ name }) => name.trim());
|
|
26
|
+
if (new Set(names).size < names.length)
|
|
27
|
+
return 'Two directions have the same name. Give each its own, so the user can tell them apart.';
|
|
28
|
+
const large = offered.find(({ html }) => Buffer.byteLength(html) > MAX_PAGE_BYTES);
|
|
29
|
+
if (large)
|
|
30
|
+
return `The page of ${large.name} is over 2 MB. Leave large pictures out, or take them from the web.`;
|
|
31
|
+
const { address, pages, shown } = await directions.show({ title, directions: offered.map((direction, index) => ({ ...direction, name: names[index] })) }, onPick);
|
|
32
|
+
const preview = previews?.client;
|
|
33
|
+
const opened = preview && !(await preview.open(`${address}${SIDEBAR_CLOSED}`).catch((error) => ({ error: errorMessage(error) }))).error;
|
|
34
|
+
return [
|
|
35
|
+
opened
|
|
36
|
+
? 'The directions are open in the Preview beside the conversation, where the user sees them now.'
|
|
37
|
+
: `The directions are shown. Give the user this address to open in their browser: ${address}`,
|
|
38
|
+
'They pick there, and the pick comes back as their next message; they may also answer in words. Until they pick, build none of the directions in the project.',
|
|
39
|
+
'Before you tell them, look at each page with `look`; if one needs fixing, show the round again:',
|
|
40
|
+
// In the Preview each is looked at in the viewer, so the round stays where the user sees it.
|
|
41
|
+
...(opened ? shown : pages).map((page, index) => `- ${names[index]}: ${page}`),
|
|
42
|
+
].join('\n');
|
|
43
|
+
},
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export const DIRECTIONS_ACTIONS = new Set(['show_directions']);
|
|
48
|
+
/** A call of the tool as the conversation shows it, worded alike whichever backend made it. */
|
|
49
|
+
export function directionsCall(input) {
|
|
50
|
+
const { title } = (input ?? {});
|
|
51
|
+
return { name: 'other', input: { title: 'Show directions', detail: String(title ?? '') } };
|
|
52
|
+
}
|
|
53
|
+
/** What the user's pick says to the agent, as their own message. */
|
|
54
|
+
export function pickMessage({ round, direction }) {
|
|
55
|
+
return `I pick ${direction}, of the directions for ${round.title}.`;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/directions/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The viewer the core serves, as drawn in @jinion/ui's playground (`pages/directions`): one page that reads the rounds
|
|
3
|
+
* from beside it. The core draws no React, so it is written out here, with @jinion/ui's tokens by the same names.
|
|
4
|
+
*/
|
|
5
|
+
export declare function viewerPage(project: string): string;
|
|
6
|
+
//# sourceMappingURL=viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../src/directions/viewer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,UAezC"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The viewer the core serves, as drawn in @jinion/ui's playground (`pages/directions`): one page that reads the rounds
|
|
3
|
+
* from beside it. The core draws no React, so it is written out here, with @jinion/ui's tokens by the same names.
|
|
4
|
+
*/
|
|
5
|
+
export function viewerPage(project) {
|
|
6
|
+
return `<!doctype html>
|
|
7
|
+
<html lang="en">
|
|
8
|
+
<head>
|
|
9
|
+
<meta charset="utf-8">
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
11
|
+
<title>Directions</title>
|
|
12
|
+
<style>${STYLE}</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<nav id="rounds"><h1><span class="strong">Directions</span><span class="faint">${escapeHtml(project)}</span></h1></nav>
|
|
16
|
+
<main><div class="sheet" id="sheet"></div></main>
|
|
17
|
+
<script>${SCRIPT}</script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>`;
|
|
20
|
+
}
|
|
21
|
+
function escapeHtml(text) {
|
|
22
|
+
return text.replace(/[&<>"']/g, (character) => `&#${character.charCodeAt(0)};`);
|
|
23
|
+
}
|
|
24
|
+
const STYLE = `
|
|
25
|
+
:root {
|
|
26
|
+
--background: #ffffff;
|
|
27
|
+
--raised: #f4f5f8;
|
|
28
|
+
--floating: #ffffff;
|
|
29
|
+
--ink: #12162a;
|
|
30
|
+
--muted: #5c6275;
|
|
31
|
+
--faint: #989dae;
|
|
32
|
+
--edge: rgb(18 22 42 / 0.1);
|
|
33
|
+
--shade: rgb(18 22 42 / 0.045);
|
|
34
|
+
--selected: rgb(18 22 42 / 0.07);
|
|
35
|
+
--primary: #181e33;
|
|
36
|
+
--on-primary: #ffffff;
|
|
37
|
+
--float-shadow: 0 6px 24px -8px rgb(0 0 0 / 0.14), 0 0 0 0.5px rgb(0 0 0 / 0.1);
|
|
38
|
+
--sheet-shadow: 0 0 0 1px rgb(0 0 0 / 0.05), 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
39
|
+
--font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
|
|
40
|
+
--font-mono: "JetBrains Mono", ui-monospace, Menlo, monospace;
|
|
41
|
+
color-scheme: light;
|
|
42
|
+
}
|
|
43
|
+
* { box-sizing: border-box; }
|
|
44
|
+
html, body { height: 100%; margin: 0; }
|
|
45
|
+
body { display: flex; background: var(--raised); color: var(--ink); font: 13px/20px var(--font-sans); -webkit-font-smoothing: antialiased; }
|
|
46
|
+
button { font: inherit; color: inherit; border: 0; background: none; padding: 0; cursor: default; text-align: left; transition: background-color 100ms ease-out, color 100ms ease-out; }
|
|
47
|
+
button:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
|
|
48
|
+
.strong { font-weight: 600; }
|
|
49
|
+
.faint { color: var(--faint); }
|
|
50
|
+
.small { font-size: 12px; line-height: 16px; }
|
|
51
|
+
.truncate { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
52
|
+
nav { display: flex; flex-direction: column; gap: 1px; width: 224px; flex-shrink: 0; padding: 12px; overflow-y: auto; }
|
|
53
|
+
nav h1 { display: flex; align-items: baseline; gap: 8px; margin: 0; padding: 4px 10px 12px; font-size: inherit; font-weight: 400; min-width: 0; }
|
|
54
|
+
.round { display: flex; flex-direction: column; min-width: 0; border-radius: 8px; padding: 6px 10px; color: var(--muted); }
|
|
55
|
+
.round:hover { color: var(--ink); }
|
|
56
|
+
.round[aria-current="true"] { background: var(--shade); color: var(--ink); }
|
|
57
|
+
main { flex: 1; min-width: 0; padding: 12px 12px 12px 0; }
|
|
58
|
+
.sidebar-closed nav { display: none; }
|
|
59
|
+
.sidebar-closed main { padding-left: 12px; }
|
|
60
|
+
.sheet { position: relative; height: 100%; overflow: hidden; border-radius: 12px; background: var(--background); box-shadow: var(--sheet-shadow); }
|
|
61
|
+
iframe { display: block; width: 100%; height: 100%; border: 0; }
|
|
62
|
+
.dock { position: absolute; inset: auto 16px 16px; display: flex; justify-content: center; pointer-events: none; }
|
|
63
|
+
.switcher { display: flex; align-items: center; gap: 4px; max-width: 100%; min-width: 0; padding: 4px; border-radius: 16px; background: var(--floating); box-shadow: var(--float-shadow); pointer-events: auto; user-select: none; }
|
|
64
|
+
.options { display: flex; gap: 4px; min-width: 0; overflow-x: auto; }
|
|
65
|
+
.option { display: flex; flex-direction: column; gap: 2px; width: 208px; min-width: 144px; flex-shrink: 1; border-radius: 12px; padding: 8px 12px; }
|
|
66
|
+
.option:hover { background: var(--shade); }
|
|
67
|
+
.option[aria-pressed="true"] { background: var(--selected); }
|
|
68
|
+
.option-head { display: flex; align-items: center; gap: 6px; }
|
|
69
|
+
.option-name { font-weight: 500; color: var(--ink); }
|
|
70
|
+
.option-number { margin-left: auto; font: 12px/20px var(--font-mono); color: var(--faint); }
|
|
71
|
+
.idea { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; font-size: 12px; line-height: 16px; color: var(--muted); }
|
|
72
|
+
.check { width: 14px; height: 14px; flex-shrink: 0; color: var(--muted); }
|
|
73
|
+
.act { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; padding: 0 8px; }
|
|
74
|
+
.button { display: inline-flex; align-items: center; gap: 8px; height: 32px; padding: 0 12px; border-radius: 8px; font-weight: 500; white-space: nowrap; }
|
|
75
|
+
.button .check { width: 16px; height: 16px; color: inherit; }
|
|
76
|
+
.primary { background: var(--primary); color: var(--on-primary); }
|
|
77
|
+
.primary:hover { background: color-mix(in srgb, var(--primary) 90%, transparent); }
|
|
78
|
+
.outline { background: var(--background); box-shadow: 0 0 0 1px var(--edge), 0 1px 2px 0 rgb(0 0 0 / 0.05); }
|
|
79
|
+
.button:disabled { opacity: 0.4; }
|
|
80
|
+
.said { max-width: 208px; text-align: right; }
|
|
81
|
+
.empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; height: 100%; padding: 0 24px; text-align: center; }
|
|
82
|
+
.empty p { margin: 0; }
|
|
83
|
+
.empty .title { font-weight: 500; }
|
|
84
|
+
.empty .text { max-width: 320px; color: var(--muted); text-wrap: pretty; }
|
|
85
|
+
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
|
|
86
|
+
`;
|
|
87
|
+
const SCRIPT = `
|
|
88
|
+
const CHECK = '<svg class="check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>';
|
|
89
|
+
const nav = document.getElementById('rounds');
|
|
90
|
+
const sheet = document.getElementById('sheet');
|
|
91
|
+
let rounds = [];
|
|
92
|
+
let loaded = false;
|
|
93
|
+
const params = new URLSearchParams(location.search);
|
|
94
|
+
let roundId = params.get('round');
|
|
95
|
+
// The direction the address asks for, by its number in the round, as the agent opens each one to look at it.
|
|
96
|
+
const asked = Number(params.get('direction') ?? 1) - 1;
|
|
97
|
+
let shown = 0;
|
|
98
|
+
let said = '';
|
|
99
|
+
|
|
100
|
+
function element(tag, className, text) {
|
|
101
|
+
const made = document.createElement(tag);
|
|
102
|
+
if (className) made.className = className;
|
|
103
|
+
if (text !== undefined) made.textContent = text;
|
|
104
|
+
return made;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function current() {
|
|
108
|
+
return rounds.find((round) => round.id === roundId);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function when(at) {
|
|
112
|
+
const date = new Date(at);
|
|
113
|
+
const time = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
114
|
+
const days = Math.round((new Date().setHours(0, 0, 0, 0) - new Date(at).setHours(0, 0, 0, 0)) / 86400000);
|
|
115
|
+
if (days === 0) return 'Today, ' + time;
|
|
116
|
+
if (days === 1) return 'Yesterday, ' + time;
|
|
117
|
+
return date.toLocaleDateString([], { day: 'numeric', month: 'long' });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function open(id, index = 0) {
|
|
121
|
+
roundId = id;
|
|
122
|
+
show(index);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function show(index) {
|
|
126
|
+
const round = current();
|
|
127
|
+
shown = round && index >= 0 && index < round.directions.length ? index : 0;
|
|
128
|
+
said = '';
|
|
129
|
+
const url = new URL(location.href);
|
|
130
|
+
if (roundId) url.searchParams.set('round', roundId);
|
|
131
|
+
url.searchParams.set('direction', String(shown + 1));
|
|
132
|
+
history.replaceState(null, '', url);
|
|
133
|
+
render();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function renderRounds() {
|
|
137
|
+
nav.querySelectorAll('.round').forEach((row) => row.remove());
|
|
138
|
+
for (const round of rounds) {
|
|
139
|
+
const row = element('button', 'round');
|
|
140
|
+
row.type = 'button';
|
|
141
|
+
row.setAttribute('aria-current', String(round.id === roundId));
|
|
142
|
+
row.append(element('span', 'truncate', round.title));
|
|
143
|
+
const status = round.picked ? 'Picked ' + round.picked : round.directions.length + ' to pick from';
|
|
144
|
+
row.append(element('span', 'truncate small faint', status + ' · ' + when(round.at)));
|
|
145
|
+
row.onclick = () => open(round.id);
|
|
146
|
+
nav.append(row);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function renderSheet() {
|
|
151
|
+
const round = current();
|
|
152
|
+
if (!round) {
|
|
153
|
+
sheet.replaceChildren(empty());
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
document.title = round.title + ' · Directions';
|
|
157
|
+
const direction = round.directions[shown];
|
|
158
|
+
const src = 'rounds/' + round.id + '/' + (shown + 1);
|
|
159
|
+
let frame = sheet.querySelector('iframe');
|
|
160
|
+
if (!frame) frame = element('iframe');
|
|
161
|
+
if (frame.getAttribute('src') !== src) {
|
|
162
|
+
frame.setAttribute('src', src);
|
|
163
|
+
frame.title = direction.name;
|
|
164
|
+
}
|
|
165
|
+
// The page holds no secret of the viewer's, and runs on an origin of its own besides.
|
|
166
|
+
frame.setAttribute('sandbox', 'allow-scripts allow-forms allow-popups');
|
|
167
|
+
sheet.replaceChildren(frame, dock(round));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function dock(round) {
|
|
171
|
+
const options = element('div', 'options');
|
|
172
|
+
round.directions.forEach((direction, index) => {
|
|
173
|
+
const option = element('button', 'option');
|
|
174
|
+
option.type = 'button';
|
|
175
|
+
option.title = direction.idea;
|
|
176
|
+
option.setAttribute('aria-pressed', String(index === shown));
|
|
177
|
+
const head = element('span', 'option-head');
|
|
178
|
+
head.append(element('span', 'option-name', direction.name));
|
|
179
|
+
if (direction.name === round.picked) head.insertAdjacentHTML('beforeend', CHECK);
|
|
180
|
+
head.append(element('span', 'option-number', String(index + 1)));
|
|
181
|
+
option.append(head, element('span', 'idea', direction.idea));
|
|
182
|
+
option.onclick = () => show(index);
|
|
183
|
+
options.append(option);
|
|
184
|
+
});
|
|
185
|
+
const act = element('div', 'act');
|
|
186
|
+
const name = round.directions[shown].name;
|
|
187
|
+
const button = element('button', 'button');
|
|
188
|
+
button.type = 'button';
|
|
189
|
+
if (name === round.picked) {
|
|
190
|
+
button.className = 'button outline';
|
|
191
|
+
button.disabled = true;
|
|
192
|
+
button.innerHTML = CHECK;
|
|
193
|
+
button.append('Picked');
|
|
194
|
+
} else {
|
|
195
|
+
button.className = 'button primary';
|
|
196
|
+
button.textContent = round.picked ? 'Pick ' + name + ' instead' : 'Pick ' + name;
|
|
197
|
+
button.onclick = () => pick(round, name);
|
|
198
|
+
}
|
|
199
|
+
act.append(button);
|
|
200
|
+
if (said) act.append(element('span', 'said small faint', said));
|
|
201
|
+
const switcher = element('div', 'switcher');
|
|
202
|
+
switcher.append(options, act);
|
|
203
|
+
const wrapper = element('div', 'dock');
|
|
204
|
+
wrapper.append(switcher);
|
|
205
|
+
return wrapper;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function empty(title = 'No directions yet', text = 'When Jinion offers you directions for this project, each round shows here to compare and pick from.') {
|
|
209
|
+
const box = element('div', 'empty');
|
|
210
|
+
box.append(element('p', 'title', title), element('p', 'text', text));
|
|
211
|
+
return box;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function pick(round, name) {
|
|
215
|
+
try {
|
|
216
|
+
const response = await fetch('rounds/' + round.id + '/pick', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ direction: name }) });
|
|
217
|
+
if (!response.ok) throw new Error(String(response.status));
|
|
218
|
+
const answer = await response.json();
|
|
219
|
+
rounds = rounds.map((each) => (each.id === answer.round.id ? answer.round : each));
|
|
220
|
+
said = answer.sent ? '' : "Saved. Its conversation isn't open, so tell Jinion there.";
|
|
221
|
+
} catch {
|
|
222
|
+
said = "Jinion couldn't be reached. Is it still running?";
|
|
223
|
+
}
|
|
224
|
+
render();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function render() {
|
|
228
|
+
document.body.classList.toggle('sidebar-closed', location.hash === '#sidebar-closed');
|
|
229
|
+
renderRounds();
|
|
230
|
+
renderSheet();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function load() {
|
|
234
|
+
try {
|
|
235
|
+
const known = new Set(rounds.map((round) => round.id));
|
|
236
|
+
const response = await fetch('rounds');
|
|
237
|
+
if (!response.ok) throw new Error(String(response.status));
|
|
238
|
+
const fresh = await response.json();
|
|
239
|
+
const first = !loaded;
|
|
240
|
+
loaded = true;
|
|
241
|
+
rounds = fresh;
|
|
242
|
+
const added = fresh.find((round) => !known.has(round.id));
|
|
243
|
+
// A round shown while the viewer is open comes up by itself.
|
|
244
|
+
if (!first && added) return open(added.id);
|
|
245
|
+
if (!current()) roundId = rounds[0] ? rounds[0].id : null;
|
|
246
|
+
if (first) return roundId ? open(roundId, asked) : render();
|
|
247
|
+
renderRounds();
|
|
248
|
+
} catch {
|
|
249
|
+
if (rounds.length === 0) sheet.replaceChildren(empty("Jinion isn't running", 'The directions show while Jinion runs. Start it again, then reload this page.'));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
addEventListener('hashchange', render);
|
|
254
|
+
addEventListener('keydown', (event) => {
|
|
255
|
+
const round = current();
|
|
256
|
+
if (!round || event.metaKey || event.ctrlKey || event.altKey) return;
|
|
257
|
+
const count = round.directions.length;
|
|
258
|
+
const number = Number(event.key);
|
|
259
|
+
if (event.key === 'ArrowRight') show((shown + 1) % count);
|
|
260
|
+
else if (event.key === 'ArrowLeft') show((shown - 1 + count) % count);
|
|
261
|
+
else if (number >= 1 && number <= count) show(number - 1);
|
|
262
|
+
});
|
|
263
|
+
load();
|
|
264
|
+
setInterval(load, 2000);
|
|
265
|
+
`;
|
|
266
|
+
//# sourceMappingURL=viewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer.js","sourceRoot":"","sources":["../../src/directions/viewer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO;;;;;;SAMA,KAAK;;;iFAGmE,UAAU,CAAC,OAAO,CAAC;;UAE1F,MAAM;;QAER,CAAC;AACT,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Db,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkLd,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first name free in `folder`, as the Finder names a copy: with a word, `box copy.tsx`, then `box copy 2.tsx`;
|
|
3
|
+
* without one, `box.tsx` itself, then `box 2.tsx`.
|
|
4
|
+
*/
|
|
5
|
+
export declare function freeName(folder: string, name: string, word: string): Promise<string>;
|
|
6
|
+
//# sourceMappingURL=names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../src/files/names.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,mBAexE"}
|