@nac3/forge-cli 0.2.1-alpha.60 → 1.0.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/README.md +5 -1
- package/dist/agents/bridge.d.ts.map +1 -1
- package/dist/agents/bridge.js +27 -0
- package/dist/agents/bridge.js.map +1 -1
- package/dist/agents/config_resolver.d.ts.map +1 -1
- package/dist/agents/config_resolver.js +15 -15
- package/dist/agents/config_resolver.js.map +1 -1
- package/dist/agents/runner.d.ts +8 -0
- package/dist/agents/runner.d.ts.map +1 -1
- package/dist/agents/runner.js +58 -11
- package/dist/agents/runner.js.map +1 -1
- package/dist/agents/system_prompt.d.ts.map +1 -1
- package/dist/agents/system_prompt.js +2 -1
- package/dist/agents/system_prompt.js.map +1 -1
- package/dist/bin/yf.d.ts.map +1 -1
- package/dist/bin/yf.js +18 -0
- package/dist/bin/yf.js.map +1 -1
- package/dist/chat/claude.d.ts +13 -0
- package/dist/chat/claude.d.ts.map +1 -1
- package/dist/chat/claude.js +45 -10
- package/dist/chat/claude.js.map +1 -1
- package/dist/chat/claude_cli.d.ts +10 -0
- package/dist/chat/claude_cli.d.ts.map +1 -1
- package/dist/chat/claude_cli.js +97 -16
- package/dist/chat/claude_cli.js.map +1 -1
- package/dist/chat/completion_hallucination_detector.d.ts +11 -0
- package/dist/chat/completion_hallucination_detector.d.ts.map +1 -1
- package/dist/chat/completion_hallucination_detector.js +37 -2
- package/dist/chat/completion_hallucination_detector.js.map +1 -1
- package/dist/chat/doctrine_digest.d.ts.map +1 -1
- package/dist/chat/doctrine_digest.js +10 -6
- package/dist/chat/doctrine_digest.js.map +1 -1
- package/dist/chat/panel.d.ts.map +1 -1
- package/dist/chat/panel.js +885 -42
- package/dist/chat/panel.js.map +1 -1
- package/dist/chat/refusal_detector.d.ts.map +1 -1
- package/dist/chat/refusal_detector.js +2 -1
- package/dist/chat/refusal_detector.js.map +1 -1
- package/dist/chat/server.d.ts +1 -0
- package/dist/chat/server.d.ts.map +1 -1
- package/dist/chat/server.js +890 -62
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/session_projects.d.ts +31 -0
- package/dist/chat/session_projects.d.ts.map +1 -0
- package/dist/chat/session_projects.js +36 -0
- package/dist/chat/session_projects.js.map +1 -0
- package/dist/chat/session_store.d.ts +32 -0
- package/dist/chat/session_store.d.ts.map +1 -0
- package/dist/chat/session_store.js +58 -0
- package/dist/chat/session_store.js.map +1 -0
- package/dist/chat/tooling_section.d.ts +11 -0
- package/dist/chat/tooling_section.d.ts.map +1 -0
- package/dist/chat/tooling_section.js +70 -0
- package/dist/chat/tooling_section.js.map +1 -0
- package/dist/chat/tools/app_backend_dispatch.d.ts.map +1 -1
- package/dist/chat/tools/app_backend_dispatch.js +44 -1
- package/dist/chat/tools/app_backend_dispatch.js.map +1 -1
- package/dist/chat/tools/fs_editor.d.ts.map +1 -1
- package/dist/chat/tools/fs_editor.js +53 -3
- package/dist/chat/tools/fs_editor.js.map +1 -1
- package/dist/chat/tools/graph.js +2 -2
- package/dist/chat/tools/graph.js.map +1 -1
- package/dist/chat/tools/keys.d.ts.map +1 -1
- package/dist/chat/tools/keys.js +5 -18
- package/dist/chat/tools/keys.js.map +1 -1
- package/dist/chat/tools/nac3_invoke.d.ts.map +1 -1
- package/dist/chat/tools/nac3_invoke.js +16 -7
- package/dist/chat/tools/nac3_invoke.js.map +1 -1
- package/dist/chat/tools/shell.d.ts +6 -0
- package/dist/chat/tools/shell.d.ts.map +1 -1
- package/dist/chat/tools/shell.js +39 -0
- package/dist/chat/tools/shell.js.map +1 -1
- package/dist/chat/tools/workflow.d.ts +20 -0
- package/dist/chat/tools/workflow.d.ts.map +1 -1
- package/dist/chat/tools/workflow.js +98 -0
- package/dist/chat/tools/workflow.js.map +1 -1
- package/dist/chat/tools.d.ts.map +1 -1
- package/dist/chat/tools.js +79 -1
- package/dist/chat/tools.js.map +1 -1
- package/dist/chat/turn_control.d.ts +42 -0
- package/dist/chat/turn_control.d.ts.map +1 -0
- package/dist/chat/turn_control.js +53 -0
- package/dist/chat/turn_control.js.map +1 -0
- package/dist/commands/brain.js +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +61 -10
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/graph.js +9 -9
- package/dist/commands/graph.js.map +1 -1
- package/dist/commands/keys_setup.d.ts +10 -28
- package/dist/commands/keys_setup.d.ts.map +1 -1
- package/dist/commands/keys_setup.js +54 -228
- package/dist/commands/keys_setup.js.map +1 -1
- package/dist/commands/license.d.ts.map +1 -1
- package/dist/commands/license.js +52 -28
- package/dist/commands/license.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +62 -6
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/mobile.d.ts +1 -1
- package/dist/commands/mobile.d.ts.map +1 -1
- package/dist/commands/mobile.js +32 -28
- package/dist/commands/mobile.js.map +1 -1
- package/dist/commands/onboard.d.ts +19 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +126 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/commands/pending.d.ts.map +1 -1
- package/dist/commands/pending.js +25 -1
- package/dist/commands/pending.js.map +1 -1
- package/dist/commands/projects.js +25 -1
- package/dist/commands/projects.js.map +1 -1
- package/dist/commands/review-screens.js +28 -1
- package/dist/commands/review-screens.js.map +1 -1
- package/dist/commands/workflow.d.ts +18 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +253 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/core/brain_config.d.ts +2 -0
- package/dist/core/brain_config.d.ts.map +1 -1
- package/dist/core/brain_config.js +18 -3
- package/dist/core/brain_config.js.map +1 -1
- package/dist/core/cf_tunnel.d.ts.map +1 -1
- package/dist/core/cf_tunnel.js +8 -2
- package/dist/core/cf_tunnel.js.map +1 -1
- package/dist/core/cost_router.d.ts.map +1 -1
- package/dist/core/cost_router.js +11 -2
- package/dist/core/cost_router.js.map +1 -1
- package/dist/core/desktop_open.d.ts +16 -0
- package/dist/core/desktop_open.d.ts.map +1 -0
- package/dist/core/desktop_open.js +114 -0
- package/dist/core/desktop_open.js.map +1 -0
- package/dist/core/keys_envelope.d.ts.map +1 -1
- package/dist/core/keys_envelope.js +5 -1
- package/dist/core/keys_envelope.js.map +1 -1
- package/dist/core/limits_config.d.ts +5 -0
- package/dist/core/limits_config.d.ts.map +1 -1
- package/dist/core/limits_config.js +5 -0
- package/dist/core/limits_config.js.map +1 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +3 -0
- package/dist/core/logger.js.map +1 -1
- package/dist/core/pairing.d.ts +6 -0
- package/dist/core/pairing.d.ts.map +1 -1
- package/dist/core/pairing.js +41 -2
- package/dist/core/pairing.js.map +1 -1
- package/dist/core/provider_keys.d.ts.map +1 -1
- package/dist/core/provider_keys.js +25 -12
- package/dist/core/provider_keys.js.map +1 -1
- package/dist/core/provider_models.js +1 -1
- package/dist/deploy/cloudflare.d.ts.map +1 -1
- package/dist/deploy/cloudflare.js +13 -2
- package/dist/deploy/cloudflare.js.map +1 -1
- package/dist/design/yujin_design_resolver.d.ts +16 -0
- package/dist/design/yujin_design_resolver.d.ts.map +1 -1
- package/dist/design/yujin_design_resolver.js +103 -20
- package/dist/design/yujin_design_resolver.js.map +1 -1
- package/dist/docs/doctrine/default-design-system.md +32 -0
- package/dist/docs/doctrine/office-tools.md +20 -0
- package/dist/docs/doctrine/verb-composition.md +16 -0
- package/dist/docs/doctrine/workflow-kinds.md +39 -22
- package/dist/docs/doctrine/workflow.md +12 -4
- package/dist/license/auto_sync.d.ts +22 -0
- package/dist/license/auto_sync.d.ts.map +1 -0
- package/dist/license/auto_sync.js +91 -0
- package/dist/license/auto_sync.js.map +1 -0
- package/dist/license/handle_key.d.ts +32 -0
- package/dist/license/handle_key.d.ts.map +1 -0
- package/dist/license/handle_key.js +56 -0
- package/dist/license/handle_key.js.map +1 -0
- package/dist/license/hito4_client.d.ts.map +1 -1
- package/dist/license/hito4_client.js +63 -25
- package/dist/license/hito4_client.js.map +1 -1
- package/dist/llm/gemini_client.d.ts.map +1 -1
- package/dist/llm/gemini_client.js +5 -2
- package/dist/llm/gemini_client.js.map +1 -1
- package/dist/llm/managed_client.d.ts.map +1 -1
- package/dist/llm/managed_client.js +14 -9
- package/dist/llm/managed_client.js.map +1 -1
- package/dist/mcp/plan_bridges.d.ts +17 -0
- package/dist/mcp/plan_bridges.d.ts.map +1 -0
- package/dist/mcp/plan_bridges.js +119 -0
- package/dist/mcp/plan_bridges.js.map +1 -0
- package/dist/migrate/ai-apply.d.ts.map +1 -1
- package/dist/migrate/ai-apply.js +25 -2
- package/dist/migrate/ai-apply.js.map +1 -1
- package/dist/nac3/internal_manifest.d.ts.map +1 -1
- package/dist/nac3/internal_manifest.js +200 -10
- package/dist/nac3/internal_manifest.js.map +1 -1
- package/dist/nac3/verb_tier_map.d.ts.map +1 -1
- package/dist/nac3/verb_tier_map.js +3 -0
- package/dist/nac3/verb_tier_map.js.map +1 -1
- package/dist/onboarding/concierge_client.d.ts +34 -0
- package/dist/onboarding/concierge_client.d.ts.map +1 -0
- package/dist/onboarding/concierge_client.js +80 -0
- package/dist/onboarding/concierge_client.js.map +1 -0
- package/dist/onboarding/next_step.d.ts +32 -0
- package/dist/onboarding/next_step.d.ts.map +1 -0
- package/dist/onboarding/next_step.js +60 -0
- package/dist/onboarding/next_step.js.map +1 -0
- package/dist/pending/store.d.ts +7 -0
- package/dist/pending/store.d.ts.map +1 -1
- package/dist/pending/store.js +19 -0
- package/dist/pending/store.js.map +1 -1
- package/dist/pending/types.d.ts +20 -0
- package/dist/pending/types.d.ts.map +1 -1
- package/dist/pending/types.js.map +1 -1
- package/dist/reader/parsers/epub.d.ts.map +1 -1
- package/dist/reader/parsers/epub.js +6 -1
- package/dist/reader/parsers/epub.js.map +1 -1
- package/dist/relay/board_snapshot.d.ts +69 -0
- package/dist/relay/board_snapshot.d.ts.map +1 -0
- package/dist/relay/board_snapshot.js +149 -0
- package/dist/relay/board_snapshot.js.map +1 -0
- package/dist/relay/command_consumer.d.ts +91 -0
- package/dist/relay/command_consumer.d.ts.map +1 -0
- package/dist/relay/command_consumer.js +129 -0
- package/dist/relay/command_consumer.js.map +1 -0
- package/dist/relay/mock_relay.d.ts +34 -0
- package/dist/relay/mock_relay.d.ts.map +1 -0
- package/dist/relay/mock_relay.js +93 -0
- package/dist/relay/mock_relay.js.map +1 -0
- package/dist/relay/relay_client.d.ts +28 -0
- package/dist/relay/relay_client.d.ts.map +1 -0
- package/dist/relay/relay_client.js +80 -0
- package/dist/relay/relay_client.js.map +1 -0
- package/dist/relay/relay_publisher.d.ts +59 -0
- package/dist/relay/relay_publisher.d.ts.map +1 -0
- package/dist/relay/relay_publisher.js +101 -0
- package/dist/relay/relay_publisher.js.map +1 -0
- package/dist/relay/types.d.ts +54 -0
- package/dist/relay/types.d.ts.map +1 -0
- package/dist/relay/types.js +8 -0
- package/dist/relay/types.js.map +1 -0
- package/dist/semantic_graph/ast_extract.d.ts +5 -0
- package/dist/semantic_graph/ast_extract.d.ts.map +1 -1
- package/dist/semantic_graph/ast_extract.js +46 -0
- package/dist/semantic_graph/ast_extract.js.map +1 -1
- package/dist/semantic_graph/derive.d.ts +12 -0
- package/dist/semantic_graph/derive.d.ts.map +1 -1
- package/dist/semantic_graph/derive.js +325 -6
- package/dist/semantic_graph/derive.js.map +1 -1
- package/dist/semantic_graph/store.d.ts +9 -0
- package/dist/semantic_graph/store.d.ts.map +1 -1
- package/dist/semantic_graph/store.js +23 -1
- package/dist/semantic_graph/store.js.map +1 -1
- package/dist/semantic_graph/types.d.ts +1 -1
- package/dist/semantic_graph/types.d.ts.map +1 -1
- package/dist/support/github_dispatcher.d.ts.map +1 -1
- package/dist/support/github_dispatcher.js +30 -2
- package/dist/support/github_dispatcher.js.map +1 -1
- package/dist/tasks/supervisor.d.ts +88 -0
- package/dist/tasks/supervisor.d.ts.map +1 -0
- package/dist/tasks/supervisor.js +308 -0
- package/dist/tasks/supervisor.js.map +1 -0
- package/dist/tasks/task_type.d.ts +11 -0
- package/dist/tasks/task_type.d.ts.map +1 -0
- package/dist/tasks/task_type.js +21 -0
- package/dist/tasks/task_type.js.map +1 -0
- package/dist/vault/store.d.ts.map +1 -1
- package/dist/vault/store.js +6 -1
- package/dist/vault/store.js.map +1 -1
- package/dist/version.d.ts +3 -5
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +3 -5
- package/dist/version.js.map +1 -1
- package/dist/voice/providers/google.d.ts.map +1 -1
- package/dist/voice/providers/google.js +6 -4
- package/dist/voice/providers/google.js.map +1 -1
- package/dist/workflow/config.d.ts +43 -0
- package/dist/workflow/config.d.ts.map +1 -0
- package/dist/workflow/config.js +199 -0
- package/dist/workflow/config.js.map +1 -0
- package/dist/workflow/instances.d.ts +40 -0
- package/dist/workflow/instances.d.ts.map +1 -0
- package/dist/workflow/instances.js +122 -0
- package/dist/workflow/instances.js.map +1 -0
- package/dist/workflow/multi_view.d.ts +27 -0
- package/dist/workflow/multi_view.d.ts.map +1 -0
- package/dist/workflow/multi_view.js +76 -0
- package/dist/workflow/multi_view.js.map +1 -0
- package/dist/workflow/orchestrator.d.ts +111 -0
- package/dist/workflow/orchestrator.d.ts.map +1 -0
- package/dist/workflow/orchestrator.js +241 -0
- package/dist/workflow/orchestrator.js.map +1 -0
- package/docs/doctrine/default-design-system.md +32 -0
- package/docs/doctrine/office-tools.md +20 -0
- package/docs/doctrine/verb-composition.md +16 -0
- package/docs/doctrine/workflow-kinds.md +39 -22
- package/docs/doctrine/workflow.md +12 -4
- package/package.json +2 -1
- package/src/i18n/catalogs/ar.json +223 -210
- package/src/i18n/catalogs/de.json +223 -210
- package/src/i18n/catalogs/en.json +223 -210
- package/src/i18n/catalogs/es.json +223 -210
- package/src/i18n/catalogs/fr.json +223 -210
- package/src/i18n/catalogs/hi.json +223 -210
- package/src/i18n/catalogs/it.json +223 -210
- package/src/i18n/catalogs/ja.json +223 -210
- package/src/i18n/catalogs/pt.json +223 -210
- package/src/i18n/catalogs/zh.json +223 -210
|
@@ -100,3 +100,23 @@ similar. The verbs are cross-platform; no shell needed.
|
|
|
100
100
|
the doc is long.
|
|
101
101
|
- Pair `office.*.write` with R8 modal (policy=approval-required;
|
|
102
102
|
user confirms before disk write).
|
|
103
|
+
|
|
104
|
+
## Opening vs reading (desktop.open vs office.*.read)
|
|
105
|
+
|
|
106
|
+
There are TWO different intents -- pick by what the user wants:
|
|
107
|
+
|
|
108
|
+
- **OPEN / SHOW it to the user** ("abri la planilla", "open this Excel",
|
|
109
|
+
"show me the doc") -> `desktop.open({target})`. It launches the file
|
|
110
|
+
in its native app (.xlsx -> Excel, .docx -> Word, .pdf -> the viewer)
|
|
111
|
+
or, for a Google Sheets/Docs URL or a `.gsheet`/`.gdoc` shortcut, in
|
|
112
|
+
the browser. This is the right move when the human wants to SEE it.
|
|
113
|
+
|
|
114
|
+
- **READ / COMPUTE over the data** ("what's the total", "extract the
|
|
115
|
+
rows", "summarize the doc") -> `office.excel.read` / `office.word.read`
|
|
116
|
+
/ `office.pdf.read`. These return structured data for YOU to reason
|
|
117
|
+
over.
|
|
118
|
+
|
|
119
|
+
NEVER open a binary office file as a pizarron editor tab
|
|
120
|
+
(`forge_open_file_for_editor` / fs.read-file): the bytes render as
|
|
121
|
+
noise and FREEZE the panel (PND-102). The open-file verb now refuses
|
|
122
|
+
office/binary extensions and points here.
|
|
@@ -59,6 +59,22 @@ In those cases, invoke `yujin.shell.exec` directly. The classifier
|
|
|
59
59
|
will gate destructive / network / elevation commands behind the
|
|
60
60
|
approval modal; safe ones auto-approve.
|
|
61
61
|
|
|
62
|
+
## Long-running commands -> yujin.task.run (MANDATORY)
|
|
63
|
+
|
|
64
|
+
`yujin.shell.exec` runs SYNCHRONOUSLY: it blocks the turn and the
|
|
65
|
+
child process is killed when the turn ends. So a command that does NOT
|
|
66
|
+
terminate on its own -- a dev server, a watcher, `tail -f`, a tunnel
|
|
67
|
+
(`npm/pnpm run dev|start|serve|watch`, `expo start`, `vite`,
|
|
68
|
+
`next dev`, `nodemon`, `wrangler dev`, `docker compose up`,
|
|
69
|
+
`cloudflared tunnel`, ...) -- MUST be launched with `yujin.task.run`,
|
|
70
|
+
which runs it detached so it SURVIVES the turn. Follow it with
|
|
71
|
+
`yujin.task.status` / `yujin.task.list`; the user stops or deletes it
|
|
72
|
+
from the Tareas tab in the pizarron.
|
|
73
|
+
|
|
74
|
+
shell.exec ENFORCES this: it refuses such commands and points you to
|
|
75
|
+
`yujin.task.run` (error `long_running_must_use_task`). Only pass
|
|
76
|
+
`allow_long_running:true` in the rare case you truly need it in-turn.
|
|
77
|
+
|
|
62
78
|
## When to fetch this doctrine
|
|
63
79
|
|
|
64
80
|
Fetch when:
|
|
@@ -21,32 +21,49 @@ changed. No doc drift.
|
|
|
21
21
|
|
|
22
22
|
## How Forge decides + acts
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
The orchestration is DETERMINISTIC code (`src/workflow/orchestrator.ts`),
|
|
25
|
+
not LLM judgement. You drive it through verbs:
|
|
26
|
+
|
|
27
|
+
1. **Open a workflow with `yujin.workflow.start({request})`.** It
|
|
28
|
+
classifies the kind (regex over the request + whether the project
|
|
29
|
+
has code -- `src/workflow/select.ts`). When the result is
|
|
30
|
+
`needs_confirm:true`, ASK the user "greenfield, correctivo o
|
|
31
|
+
evolutivo?" and call again with `{kind}`. Do NOT silently assume.
|
|
32
|
+
`start` then creates the instance (WFL-NNN) + **spawns one pending
|
|
33
|
+
per canonical task, in mandatory order**. Several workflows can
|
|
34
|
+
coexist (keyed by name) -- a fix and a feature run side by side.
|
|
35
|
+
2. **Stages are NOT pendings; tasks are.** Work the task pendings in
|
|
36
|
+
order. The `yf pending close` gate REFUSES to close a task while an
|
|
37
|
+
earlier-order task is still open (override: `--force-order`). When
|
|
38
|
+
every task closes, the workflow **auto-closes** -- you do not close
|
|
39
|
+
it by hand.
|
|
40
|
+
3. **Add tasks at discretion.** If the user OR you decide a
|
|
41
|
+
corrective/evolutive task is needed mid-workflow, add it with
|
|
42
|
+
`yujin.workflow.add-task({code, title})` -- it appends at the end of
|
|
43
|
+
the order (flagged `ad_hoc`).
|
|
44
|
+
4. **Edit the phases/tasks on request.** `yujin.workflow.configure({patch})`
|
|
45
|
+
rewrites the project's editable definitions
|
|
46
|
+
(`.forge/workflow-config.json`); the code default stays recoverable
|
|
47
|
+
(`yf workflow config --reset`).
|
|
48
|
+
5. **Log the evolution.** As you cross stage/step boundaries, call
|
|
49
|
+
`yujin.workflow.log-step(...)` -- it writes `docs/WORKFLOW_LOG.md` +
|
|
50
|
+
`workflow.evolution[]` so the project records its own workflow
|
|
51
|
+
history. Greenfield detail = the 18-step flow (`workflow`,
|
|
52
|
+
`workflow-phases`); never force it on a live project.
|
|
38
53
|
|
|
39
54
|
## Relation to the request lifecycle
|
|
40
55
|
|
|
41
56
|
The pending request-lifecycle (add -> note -> close with history) is
|
|
42
|
-
the MICRO level (per
|
|
43
|
-
project, with stages). They
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
the corrective stages.
|
|
57
|
+
the MICRO level (per task). The workflow is the MACRO level (per
|
|
58
|
+
project, with stages). They are now the SAME store: a workflow task IS
|
|
59
|
+
a pending item (with a `workflow` link). The instance names the stages;
|
|
60
|
+
its tasks are pendings closed in mandatory order.
|
|
47
61
|
|
|
48
62
|
## Canonical steps source
|
|
49
63
|
|
|
50
|
-
The canonical step definitions
|
|
51
|
-
|
|
52
|
-
|
|
64
|
+
The canonical step definitions live in `src/workflow/definitions.ts`
|
|
65
|
+
(the immutable DEFAULT + disaster-recovery source). A project may
|
|
66
|
+
override them in `.forge/workflow-config.json` (edited via
|
|
67
|
+
`yujin.workflow.configure`); a `.default.json` snapshot keeps the
|
|
68
|
+
default recoverable. The worker-canonical layer plugs in later, same
|
|
69
|
+
pattern as doctrines + lessons.
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
# Workflow doctrine -- 6 phases / 18 steps
|
|
1
|
+
# Workflow doctrine -- 6 phases / 18 steps (GREENFIELD)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
SCOPE: this 6-phase / 18-step methodology is the GREENFIELD workflow --
|
|
4
|
+
building a new app from zero. A LIVE project uses the compact
|
|
5
|
+
corrective / evolutive flow instead (see `workflow-kinds`). Never force
|
|
6
|
+
these 18 steps on an existing project. Open any workflow with
|
|
7
|
+
`yujin.workflow.start` (it classifies the kind + spawns the task
|
|
8
|
+
pendings in order); this doc is the detail for the greenfield case.
|
|
9
|
+
|
|
10
|
+
Yujin Forge guides greenfield delivery through 6 phases / 18 steps
|
|
11
|
+
(PRODUCT_WORKFLOW.md). The LLM picks the right phase based on what the
|
|
12
|
+
user is asking; if the user jumps mid-phase the LLM respects that but
|
|
13
|
+
flags the risk.
|
|
6
14
|
|
|
7
15
|
PHASE I -- INTAKE (steps 1-3.5)
|
|
8
16
|
1. Complexity triage Simple / Medium / Full tier
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface EnsureLicenseOptions {
|
|
2
|
+
/** Force a sync regardless of the throttle window. */
|
|
3
|
+
force?: boolean;
|
|
4
|
+
/** Network timeout. Default 2500ms. */
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
/** Sink for the transition note. Default: console.error (stderr, so
|
|
7
|
+
* it never pollutes a command's stdout / JSON output). */
|
|
8
|
+
notify?: (line: string) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Refresh the local license cache if it is stale. Resolves to the new
|
|
12
|
+
* plan string when a sync ran, or null when it was skipped/failed. Never
|
|
13
|
+
* throws.
|
|
14
|
+
*/
|
|
15
|
+
export declare function ensureLicenseFresh(opts?: EnsureLicenseOptions): Promise<string | null>;
|
|
16
|
+
/** Resolve the top-level command name for a (possibly nested) leaf. */
|
|
17
|
+
export declare function topLevelName(actionCommand: {
|
|
18
|
+
name(): string;
|
|
19
|
+
parent?: unknown;
|
|
20
|
+
} | null): string;
|
|
21
|
+
export declare function shouldAutoSync(topName: string): boolean;
|
|
22
|
+
//# sourceMappingURL=auto_sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto_sync.d.ts","sourceRoot":"","sources":["../../src/license/auto_sync.ts"],"names":[],"mappings":"AAwCA,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;+DAC2D;IAC3D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4BhG;AAWD,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,aAAa,EAAE;IAAE,IAAI,IAAI,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,GAAG,MAAM,CAS/F;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-sync the Polar license, silently, so the user NEVER runs
|
|
3
|
+
* `yf license sync` by hand.
|
|
4
|
+
*
|
|
5
|
+
* Wired as a global Commander `preAction` hook (src/bin/yf.ts): before
|
|
6
|
+
* any command runs, we opportunistically pull the canonical license row
|
|
7
|
+
* from HITO 4 and refresh ~/.yujin-forge/license.json. This closes the
|
|
8
|
+
* gap where a user paid on Polar but the local cache still said "none"
|
|
9
|
+
* until they manually synced.
|
|
10
|
+
*
|
|
11
|
+
* Design rules (zero friction, never get in the way):
|
|
12
|
+
* - Best-effort: every error is swallowed. Offline / no handle / no
|
|
13
|
+
* server -> the command proceeds with the cached license.
|
|
14
|
+
* - Time-boxed: a slow/unreachable server can never hang the CLI.
|
|
15
|
+
* - Throttled: we do not hit the network on every keystroke. When the
|
|
16
|
+
* plan is already active we refresh at most hourly; when it is not
|
|
17
|
+
* active yet (just paid, waiting on the webhook) we retry quickly so
|
|
18
|
+
* the paid status is picked up within ~90s of the next command.
|
|
19
|
+
* - Silent on no-op; a one-line note only when the plan actually
|
|
20
|
+
* transitions (e.g. none -> paid) so the user sees the win.
|
|
21
|
+
*
|
|
22
|
+
* ASCII-only.
|
|
23
|
+
*/
|
|
24
|
+
import { readLicense as readPolarLicense, isActive as isPolarActive } from '../core/polar.js';
|
|
25
|
+
import { syncLicense } from './sync.js';
|
|
26
|
+
const FRESH_ACTIVE_MS = 60 * 60 * 1000; /* active plan: refresh hourly */
|
|
27
|
+
const FRESH_INACTIVE_MS = 90 * 1000; /* not active yet: retry fast */
|
|
28
|
+
const DEFAULT_TIMEOUT_MS = 2500;
|
|
29
|
+
function withTimeout(p, ms) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const t = setTimeout(() => reject(new Error('auto-sync timeout')), ms);
|
|
32
|
+
p.then((v) => { clearTimeout(t); resolve(v); }, (e) => { clearTimeout(t); reject(e); });
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Refresh the local license cache if it is stale. Resolves to the new
|
|
37
|
+
* plan string when a sync ran, or null when it was skipped/failed. Never
|
|
38
|
+
* throws.
|
|
39
|
+
*/
|
|
40
|
+
export async function ensureLicenseFresh(opts = {}) {
|
|
41
|
+
try {
|
|
42
|
+
const local = await readPolarLicense();
|
|
43
|
+
/* No handle -> we literally cannot ask the server who this is.
|
|
44
|
+
* The activate flow captures it; until then, nothing to do. */
|
|
45
|
+
if (!local.user_handle)
|
|
46
|
+
return null;
|
|
47
|
+
if (!opts.force) {
|
|
48
|
+
const active = isPolarActive(local);
|
|
49
|
+
const window = active ? FRESH_ACTIVE_MS : FRESH_INACTIVE_MS;
|
|
50
|
+
const lastV = local.last_validated_at ? Date.parse(local.last_validated_at) : 0;
|
|
51
|
+
if (lastV && Number.isFinite(lastV) && (Date.now() - lastV) < window) {
|
|
52
|
+
return null; /* still fresh enough */
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const before = local.plan;
|
|
56
|
+
const report = await withTimeout(syncLicense(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
57
|
+
if (!report.ok)
|
|
58
|
+
return null;
|
|
59
|
+
if (report.local_plan_after && report.local_plan_after !== before) {
|
|
60
|
+
const notify = opts.notify ?? ((l) => process.stderr.write(l + '\n'));
|
|
61
|
+
notify('Forge: license updated (' + before + ' -> ' + report.local_plan_after + ').');
|
|
62
|
+
}
|
|
63
|
+
return report.local_plan_after ?? null;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null; /* offline / not configured / timeout -- proceed quietly */
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Top-level command names that must NOT trigger auto-sync (they either
|
|
70
|
+
* manage the license themselves -> recursion, or are pure offline
|
|
71
|
+
* utilities where a network probe is unwanted). */
|
|
72
|
+
const SKIP_AUTOSYNC = new Set([
|
|
73
|
+
'license', /* activate/status/sync/cancel manage the cache directly */
|
|
74
|
+
'help',
|
|
75
|
+
'completion',
|
|
76
|
+
]);
|
|
77
|
+
/** Resolve the top-level command name for a (possibly nested) leaf. */
|
|
78
|
+
export function topLevelName(actionCommand) {
|
|
79
|
+
let cur = actionCommand;
|
|
80
|
+
let last = cur;
|
|
81
|
+
/* Walk up until the parent is the root program (parent has no parent). */
|
|
82
|
+
while (cur && cur.parent) {
|
|
83
|
+
last = cur;
|
|
84
|
+
cur = cur.parent ?? null;
|
|
85
|
+
}
|
|
86
|
+
return last ? last.name() : '';
|
|
87
|
+
}
|
|
88
|
+
export function shouldAutoSync(topName) {
|
|
89
|
+
return !SKIP_AUTOSYNC.has(topName);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=auto_sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto_sync.js","sourceRoot":"","sources":["../../src/license/auto_sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** MUST match the worker + mobile constants exactly. */
|
|
2
|
+
export declare const HANDLE_KEY_SALT = "yf-relay-handle-key:v1";
|
|
3
|
+
export declare const HANDLE_KEY_INFO_PREFIX = "yf-handle:";
|
|
4
|
+
/** Vault slot for the derived per-handle key (v2). */
|
|
5
|
+
export declare const HANDLE_KEY_SLOT = "yf_handle_key";
|
|
6
|
+
/** Vault slot for the legacy global root secret (v1). */
|
|
7
|
+
export declare const ROOT_KEY_SLOT = "yf_server_api_key";
|
|
8
|
+
/** Derive the per-handle signing key (hex) from the global root secret
|
|
9
|
+
* and the user handle. node:crypto HKDF-SHA256 -- identical to the
|
|
10
|
+
* worker (WebCrypto) + mobile (@noble) derivations. */
|
|
11
|
+
export declare function deriveHandleKey(root: string, handle: string): string;
|
|
12
|
+
/** A vault-like handle (the real Vault or a test fake). set/remove are
|
|
13
|
+
* optional so a read-only fake never breaks signing. */
|
|
14
|
+
export interface SigningVaultLike {
|
|
15
|
+
has(slot: string): boolean;
|
|
16
|
+
get(slot: string): string;
|
|
17
|
+
set?(slot: string, value: string): Promise<void>;
|
|
18
|
+
remove?(slot: string): Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
/** Resolve the per-handle signing secret. Prefers the migrated
|
|
21
|
+
* `yf_handle_key`; otherwise derives it from the legacy root and
|
|
22
|
+
* persists it (best-effort). Returns null when neither slot exists.
|
|
23
|
+
* Single source of truth for every desktop signing site, so dropping
|
|
24
|
+
* the root later is safe everywhere. */
|
|
25
|
+
export declare function resolveSigningSecret(vault: SigningVaultLike, handle: string): Promise<{
|
|
26
|
+
secret: string;
|
|
27
|
+
derivedFromRoot: boolean;
|
|
28
|
+
} | null>;
|
|
29
|
+
/** Drop the legacy root once the per-handle key is persisted -- after
|
|
30
|
+
* this the device can no longer sign for any other handle. Best-effort. */
|
|
31
|
+
export declare function dropLegacyRoot(vault: SigningVaultLike): Promise<void>;
|
|
32
|
+
//# sourceMappingURL=handle_key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle_key.d.ts","sourceRoot":"","sources":["../../src/license/handle_key.ts"],"names":[],"mappings":"AAcA,wDAAwD;AACxD,eAAO,MAAM,eAAe,2BAA2B,CAAC;AACxD,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,sDAAsD;AACtD,eAAO,MAAM,eAAe,kBAAkB,CAAC;AAC/C,yDAAyD;AACzD,eAAO,MAAM,aAAa,sBAAsB,CAAC;AAEjD;;wDAEwD;AACxD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAUpE;AAED;yDACyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACzC;AAED;;;;yCAIyC;AACzC,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GACtC,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC,CAQ9D;AAED;4EAC4E;AAC5E,wBAAsB,cAAc,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3E"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-handle signing key derivation -- CLI side (PND-047 / sec 7.1).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors packages/hito4-server/src/handle_key.ts (the worker) and
|
|
5
|
+
* nac3-rn/src/brain_client.ts (the phone): HKDF-SHA256(root, salt, info)
|
|
6
|
+
* with byte-identical constants so all three derive the SAME per-handle
|
|
7
|
+
* key. The CLI then signs bearers with this derived key instead of the
|
|
8
|
+
* raw root, so a tenant only ever holds the key for ITS handle and
|
|
9
|
+
* cannot impersonate another (HKDF is one-way). See the interop test.
|
|
10
|
+
*
|
|
11
|
+
* ASCII-only.
|
|
12
|
+
*/
|
|
13
|
+
import { hkdfSync } from 'node:crypto';
|
|
14
|
+
/** MUST match the worker + mobile constants exactly. */
|
|
15
|
+
export const HANDLE_KEY_SALT = 'yf-relay-handle-key:v1';
|
|
16
|
+
export const HANDLE_KEY_INFO_PREFIX = 'yf-handle:';
|
|
17
|
+
/** Vault slot for the derived per-handle key (v2). */
|
|
18
|
+
export const HANDLE_KEY_SLOT = 'yf_handle_key';
|
|
19
|
+
/** Vault slot for the legacy global root secret (v1). */
|
|
20
|
+
export const ROOT_KEY_SLOT = 'yf_server_api_key';
|
|
21
|
+
/** Derive the per-handle signing key (hex) from the global root secret
|
|
22
|
+
* and the user handle. node:crypto HKDF-SHA256 -- identical to the
|
|
23
|
+
* worker (WebCrypto) + mobile (@noble) derivations. */
|
|
24
|
+
export function deriveHandleKey(root, handle) {
|
|
25
|
+
const enc = new TextEncoder();
|
|
26
|
+
const out = hkdfSync('sha256', enc.encode(root), enc.encode(HANDLE_KEY_SALT), enc.encode(HANDLE_KEY_INFO_PREFIX + handle.toLowerCase()), 32);
|
|
27
|
+
return Buffer.from(new Uint8Array(out)).toString('hex');
|
|
28
|
+
}
|
|
29
|
+
/** Resolve the per-handle signing secret. Prefers the migrated
|
|
30
|
+
* `yf_handle_key`; otherwise derives it from the legacy root and
|
|
31
|
+
* persists it (best-effort). Returns null when neither slot exists.
|
|
32
|
+
* Single source of truth for every desktop signing site, so dropping
|
|
33
|
+
* the root later is safe everywhere. */
|
|
34
|
+
export async function resolveSigningSecret(vault, handle) {
|
|
35
|
+
if (vault.has(HANDLE_KEY_SLOT))
|
|
36
|
+
return { secret: vault.get(HANDLE_KEY_SLOT), derivedFromRoot: false };
|
|
37
|
+
if (vault.has(ROOT_KEY_SLOT)) {
|
|
38
|
+
const secret = deriveHandleKey(vault.get(ROOT_KEY_SLOT), handle);
|
|
39
|
+
try {
|
|
40
|
+
await vault.set?.(HANDLE_KEY_SLOT, secret);
|
|
41
|
+
}
|
|
42
|
+
catch { /* read-only fake */ }
|
|
43
|
+
return { secret, derivedFromRoot: true };
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/** Drop the legacy root once the per-handle key is persisted -- after
|
|
48
|
+
* this the device can no longer sign for any other handle. Best-effort. */
|
|
49
|
+
export async function dropLegacyRoot(vault) {
|
|
50
|
+
try {
|
|
51
|
+
if (vault.has(HANDLE_KEY_SLOT) && vault.has(ROOT_KEY_SLOT))
|
|
52
|
+
await vault.remove?.(ROOT_KEY_SLOT);
|
|
53
|
+
}
|
|
54
|
+
catch { /* best-effort -- a later call retries */ }
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=handle_key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle_key.js","sourceRoot":"","sources":["../../src/license/handle_key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,wDAAwD;AACxD,MAAM,CAAC,MAAM,eAAe,GAAG,wBAAwB,CAAC;AACxD,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;AAEnD,sDAAsD;AACtD,MAAM,CAAC,MAAM,eAAe,GAAG,eAAe,CAAC;AAC/C,yDAAyD;AACzD,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAEjD;;wDAEwD;AACxD,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAAc;IAC1D,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,QAAQ,CAClB,QAAQ,EACR,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAChB,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,EAC3B,GAAG,CAAC,MAAM,CAAC,sBAAsB,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,EACzD,EAAE,CACH,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAWD;;;;yCAIyC;AACzC,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAuB,EAAE,MAAc;IAEvC,IAAI,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;IACtG,IAAI,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;QACjE,IAAI,CAAC;YAAC,MAAM,KAAK,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC;QAClF,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;4EAC4E;AAC5E,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAuB;IAC1D,IAAI,CAAC;QACH,IAAI,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;YAAE,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,CAAC;IAClG,CAAC;IAAC,MAAM,CAAC,CAAC,yCAAyC,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hito4_client.d.ts","sourceRoot":"","sources":["../../src/license/hito4_client.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"hito4_client.d.ts","sourceRoot":"","sources":["../../src/license/hito4_client.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAO1C,OAAO,KAAK,EAAyB,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGrF,eAAO,MAAM,cAAc,QAA8E,CAAC;AAiC1G,UAAU,aAAa;IACrB,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;gDAEgD;AAChD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAoBlE;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACnC;qDACiD;IACjD,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAsDD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAE,MAAmB,GAAG,MAAM,CAG1F;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;;;;;8CAM8C;AAC9C,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE,eAAoB,GACvD,OAAO,CAAC,cAAc,CAAC,CAsBzB;AA+BD;;;qEAGqE;AACrE,wBAAsB,aAAa,CACjC,IAAI,GAAE,eAAe,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9C,OAAO,CAAC,cAAc,CAAC,CAkBzB;AAED;qDACqD;AACrD,wBAAsB,kBAAkB,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAe5F"}
|
|
@@ -24,10 +24,25 @@ import path from 'node:path';
|
|
|
24
24
|
import os from 'node:os';
|
|
25
25
|
import { Vault } from '../vault/store.js';
|
|
26
26
|
import { configDir } from './index.js';
|
|
27
|
+
import { HANDLE_KEY_SLOT, ROOT_KEY_SLOT, resolveSigningSecret, dropLegacyRoot, } from './handle_key.js';
|
|
27
28
|
import { readLicense } from '../core/polar.js';
|
|
28
29
|
import { renderForgeError, E_WORKER_UNREACHABLE } from '../core/error_catalog.js';
|
|
29
30
|
export const HITO4_BASE_URL = process.env.YF_HITO4_BASE_URL ?? 'https://yujin-hito4.yujinapp.workers.dev';
|
|
30
|
-
|
|
31
|
+
/* PND-051 (sec 7.8) -- the worker carries BYOK key material + bearer
|
|
32
|
+
* tokens. If an operator overrides the base URL to plain http (or any
|
|
33
|
+
* non-https, non-loopback scheme) the traffic is interceptable; warn
|
|
34
|
+
* loudly once at module load. Loopback http is allowed for local dev. */
|
|
35
|
+
(() => {
|
|
36
|
+
try {
|
|
37
|
+
const u = new URL(HITO4_BASE_URL);
|
|
38
|
+
const isLoopback = u.hostname === '127.0.0.1' || u.hostname === 'localhost' || u.hostname === '::1';
|
|
39
|
+
if (u.protocol !== 'https:' && !isLoopback) {
|
|
40
|
+
console.warn('[hito4] WARNING: YF_HITO4_BASE_URL is not https (' + u.protocol + '//' + u.hostname
|
|
41
|
+
+ '). BYOK keys + bearer tokens would travel in clear. Use https.');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch { /* malformed override -- callers fail later with a clear error */ }
|
|
45
|
+
})();
|
|
31
46
|
/** Read the local plaintext provider keys cache. The mobile
|
|
32
47
|
* equivalent is the `useProviderKeys` hook. Returns null if
|
|
33
48
|
* the file does not exist yet (user has not run keys setup). */
|
|
@@ -47,29 +62,32 @@ async function readLocalProviderKeys() {
|
|
|
47
62
|
* the current request. Mirrors the mobile-side logic that
|
|
48
63
|
* reads from the encrypted keys-sync cache. */
|
|
49
64
|
export async function resolveBrainHeaders() {
|
|
65
|
+
/* PND-051 -- the SECRET key value now comes from the encrypted Vault
|
|
66
|
+
* (src/core/provider_keys.ts), NOT the plaintext provider_keys.json.
|
|
67
|
+
* The file keeps only the NON-secret metadata (which provider is
|
|
68
|
+
* preferred + the model alias). */
|
|
50
69
|
const cache = await readLocalProviderKeys();
|
|
51
|
-
|
|
52
|
-
return { provider: null, apiKey: null, modelAlias: null };
|
|
53
|
-
const provider = (cache.brain_provider_preference ?? null);
|
|
70
|
+
const provider = (cache?.brain_provider_preference ?? null);
|
|
54
71
|
if (!provider)
|
|
55
72
|
return { provider: null, apiKey: null, modelAlias: null };
|
|
56
|
-
|
|
73
|
+
const { getKey } = await import('../core/provider_keys.js');
|
|
74
|
+
let apiKey = null;
|
|
57
75
|
let modelAlias;
|
|
58
76
|
if (provider === 'anthropic') {
|
|
59
|
-
apiKey =
|
|
60
|
-
modelAlias = cache
|
|
77
|
+
apiKey = await getKey('anthropic_api_key');
|
|
78
|
+
modelAlias = cache?.anthropic_model_preference;
|
|
61
79
|
}
|
|
62
80
|
else if (provider === 'openai') {
|
|
63
|
-
apiKey =
|
|
64
|
-
modelAlias = cache
|
|
81
|
+
apiKey = await getKey('openai_api_key');
|
|
82
|
+
modelAlias = cache?.openai_brain_model_preference;
|
|
65
83
|
}
|
|
66
84
|
else if (provider === 'google') {
|
|
67
|
-
apiKey =
|
|
68
|
-
modelAlias = cache
|
|
85
|
+
apiKey = await getKey('google_ai_key');
|
|
86
|
+
modelAlias = cache?.google_brain_model_preference;
|
|
69
87
|
}
|
|
70
88
|
else if (provider === 'deepseek') {
|
|
71
|
-
apiKey =
|
|
72
|
-
modelAlias = cache
|
|
89
|
+
apiKey = await getKey('deepseek_api_key');
|
|
90
|
+
modelAlias = cache?.deepseek_model_preference;
|
|
73
91
|
}
|
|
74
92
|
return {
|
|
75
93
|
provider,
|
|
@@ -80,15 +98,29 @@ export async function resolveBrainHeaders() {
|
|
|
80
98
|
function hmacHex(secret, msg) {
|
|
81
99
|
return createHmac('sha256', secret).update(msg).digest('hex');
|
|
82
100
|
}
|
|
83
|
-
|
|
101
|
+
/** PND-047 -- resolve the per-handle signing key. Prefers the migrated
|
|
102
|
+
* `yf_handle_key` slot; otherwise derives it from the legacy root
|
|
103
|
+
* (`yf_server_api_key`) and persists it, but KEEPS the root until a
|
|
104
|
+
* successful v2 call confirms the worker accepts the new key (so a
|
|
105
|
+
* client updated before the worker is never locked out). */
|
|
106
|
+
async function getSigningContext(deps, handle) {
|
|
84
107
|
const opener = deps.vaultOpener ?? (() => Vault.open({ configDir: configDir() }));
|
|
85
|
-
const vault = await opener();
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
108
|
+
const vault = (await opener());
|
|
109
|
+
const resolved = await resolveSigningSecret(vault, handle);
|
|
110
|
+
if (!resolved) {
|
|
111
|
+
throw new Error('HITO 4 client: vault has neither "' + HANDLE_KEY_SLOT + '" nor "' + ROOT_KEY_SLOT + '". '
|
|
112
|
+
+ 'Run `yf vault set ' + ROOT_KEY_SLOT + '` with the value provided '
|
|
89
113
|
+ 'at signup (or your tenant admin).');
|
|
90
114
|
}
|
|
91
|
-
return vault.
|
|
115
|
+
return { vault, secret: resolved.secret, derivedFromRoot: resolved.derivedFromRoot };
|
|
116
|
+
}
|
|
117
|
+
/** Drop the legacy root once the per-handle key has been used in a
|
|
118
|
+
* successful call -- after this the client can no longer sign for any
|
|
119
|
+
* other handle (cross-tenant impersonation closed on this device). */
|
|
120
|
+
async function finalizeHandleKeyMigration(ctx) {
|
|
121
|
+
if (!ctx.derivedFromRoot)
|
|
122
|
+
return;
|
|
123
|
+
await dropLegacyRoot(ctx.vault);
|
|
92
124
|
}
|
|
93
125
|
async function getHandle(deps) {
|
|
94
126
|
if (deps.handleProvider)
|
|
@@ -113,9 +145,9 @@ export function signBearer(secret, handle, ts = Date.now()) {
|
|
|
113
145
|
* worker never persists nor logs the key. */
|
|
114
146
|
export async function callFlow(flow, input, deps = {}) {
|
|
115
147
|
const base = deps.baseUrl ?? HITO4_BASE_URL;
|
|
116
|
-
const secret = await getSecret(deps);
|
|
117
148
|
const handle = await getHandle(deps);
|
|
118
|
-
const
|
|
149
|
+
const ctx = await getSigningContext(deps, handle);
|
|
150
|
+
const bearer = signBearer(ctx.secret, handle);
|
|
119
151
|
const fetchImpl = deps.fetchImpl ?? ((u, init) => globalThis.fetch(u, init));
|
|
120
152
|
const brain = await resolveBrainHeaders();
|
|
121
153
|
const url = base.replace(/\/+$/, '') + '/v1/flows/' + encodeURIComponent(flow);
|
|
@@ -131,6 +163,8 @@ export async function callFlow(flow, input, deps = {}) {
|
|
|
131
163
|
if (brain.modelAlias)
|
|
132
164
|
headers['x-yf-brain-model'] = brain.modelAlias;
|
|
133
165
|
const r = await safeWorkerFetch(fetchImpl, url, { method: 'POST', headers, body: JSON.stringify(input ?? null) });
|
|
166
|
+
if (r.ok)
|
|
167
|
+
await finalizeHandleKeyMigration(ctx);
|
|
134
168
|
let body = {};
|
|
135
169
|
try {
|
|
136
170
|
body = await r.json();
|
|
@@ -168,9 +202,9 @@ async function safeWorkerFetch(fetchImpl, url, init) {
|
|
|
168
202
|
* `month` arg is YYYY-MM; defaults to current month server-side. */
|
|
169
203
|
export async function readCostMeter(deps = {}) {
|
|
170
204
|
const base = deps.baseUrl ?? HITO4_BASE_URL;
|
|
171
|
-
const secret = await getSecret(deps);
|
|
172
205
|
const handle = await getHandle(deps);
|
|
173
|
-
const
|
|
206
|
+
const ctx = await getSigningContext(deps, handle);
|
|
207
|
+
const bearer = signBearer(ctx.secret, handle);
|
|
174
208
|
const fetchImpl = deps.fetchImpl ?? ((u, init) => globalThis.fetch(u, init));
|
|
175
209
|
const qs = deps.month && /^\d{4}-\d{2}$/.test(deps.month)
|
|
176
210
|
? '?month=' + encodeURIComponent(deps.month)
|
|
@@ -180,6 +214,8 @@ export async function readCostMeter(deps = {}) {
|
|
|
180
214
|
method: 'GET',
|
|
181
215
|
headers: { 'Authorization': 'Bearer ' + bearer },
|
|
182
216
|
});
|
|
217
|
+
if (r.ok)
|
|
218
|
+
await finalizeHandleKeyMigration(ctx);
|
|
183
219
|
let body = {};
|
|
184
220
|
try {
|
|
185
221
|
body = await r.json();
|
|
@@ -193,15 +229,17 @@ export async function readCostMeter(deps = {}) {
|
|
|
193
229
|
* Polar cache is then refreshed with the result. */
|
|
194
230
|
export async function fetchServerLicense(deps = {}) {
|
|
195
231
|
const base = deps.baseUrl ?? HITO4_BASE_URL;
|
|
196
|
-
const secret = await getSecret(deps);
|
|
197
232
|
const handle = await getHandle(deps);
|
|
198
|
-
const
|
|
233
|
+
const ctx = await getSigningContext(deps, handle);
|
|
234
|
+
const bearer = signBearer(ctx.secret, handle);
|
|
199
235
|
const fetchImpl = deps.fetchImpl ?? ((u, init) => globalThis.fetch(u, init));
|
|
200
236
|
const url = base.replace(/\/+$/, '') + '/v1/license/' + encodeURIComponent(handle);
|
|
201
237
|
const r = await safeWorkerFetch(fetchImpl, url, {
|
|
202
238
|
method: 'GET',
|
|
203
239
|
headers: { 'Authorization': 'Bearer ' + bearer },
|
|
204
240
|
});
|
|
241
|
+
if (r.ok)
|
|
242
|
+
await finalizeHandleKeyMigration(ctx);
|
|
205
243
|
let body = {};
|
|
206
244
|
try {
|
|
207
245
|
body = await r.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hito4_client.js","sourceRoot":"","sources":["../../src/license/hito4_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAElF,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"hito4_client.js","sourceRoot":"","sources":["../../src/license/hito4_client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini_client.d.ts","sourceRoot":"","sources":["../../src/llm/gemini_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAMvD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAClE,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AA6BD,qBAAa,cAAe,SAAQ,KAAK;IACvC,MAAM,EAAE,MAAM,CAAC;gBACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAK5C;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,YAAY,CAAS;gBAEjB,IAAI,EAAE,mBAAmB;IAS/B,IAAI,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"gemini_client.d.ts","sourceRoot":"","sources":["../../src/llm/gemini_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAMvD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAClE,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AA6BD,qBAAa,cAAe,SAAQ,KAAK;IACvC,MAAM,EAAE,MAAM,CAAC;gBACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAK5C;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,YAAY,CAAS;gBAEjB,IAAI,EAAE,mBAAmB;IAS/B,IAAI,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAoLhE"}
|
|
@@ -68,10 +68,13 @@ export class GeminiClient {
|
|
|
68
68
|
body.tools = [{ functionDeclarations }];
|
|
69
69
|
body.toolConfig = { functionCallingConfig: { mode: 'AUTO' } };
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
/* PND-051 (sec 4.6) -- pass the API key in the x-goog-api-key
|
|
72
|
+
* header, not the query string. Query strings land in access
|
|
73
|
+
* logs, proxy logs and Referer headers; the header does not. */
|
|
74
|
+
const url = GEMINI_BASE + encodeURIComponent(model) + ':generateContent';
|
|
72
75
|
const res = await this.fetchImpl(url, {
|
|
73
76
|
method: 'POST',
|
|
74
|
-
headers: { 'content-type': 'application/json' },
|
|
77
|
+
headers: { 'content-type': 'application/json', 'x-goog-api-key': this.apiKey },
|
|
75
78
|
body: JSON.stringify(body),
|
|
76
79
|
});
|
|
77
80
|
const json = await res.json();
|