Commit Graph

16 Commits

Author SHA1 Message Date
d09d360530 feat(cli): HITL compact block, resume status framing, spinner fix
- renderHitlBlock: compact inline Actions/Inputs, no blank lines,
  rename Prompt→Message, indent multi-line form_content by 4 spaces
- resumeApp: write ✓ form submitted / workflow execution resumed / ✓ workflow finished
  to stderr in text mode only; JSON/non-text formats are unaffected
- StreamingStructuredStrategy: call spinner.stop() before exit(0) in
  HITL catch to prevent spinner bleed onto pause block output
2026-05-19 00:48:43 -07:00
8a4c87234f chore: switched to shared contract (#36380) 2026-05-19 15:19:41 +08:00
31ea69be66 feat(cli): add release pipeline (#36365) 2026-05-19 14:51:28 +08:00
6de46024a3 fix(cli): CJK table alignment, workflow plain-text output, HITL label rename
- formatTable: use displayWidth() for CJK/fullwidth chars instead of
  String.length, so double-wide characters don't misalign columns
- workflowTextHandler: print value directly when outputs has exactly one
  string key; fall back to JSON for multi-key or non-string outputs
- hitl-render: rename 'Prompt:' label to 'Message:' — less ambiguous
  than 'prompt' in an LLM context
2026-05-18 23:03:07 -07:00
0d5173f73f fix(cli): client-side --mode enum validation, EPIPE guard, stderr redirects
- Reject invalid --mode values before HTTP (e.g. "chatbot" → clear error)
- Add options field to FlagDefinition + validateFlagOptions in parseArgv
- EPIPE exit-0 guard in run.ts catch block
- tree:gen/tree:check diagnostic output redirected to stderr
- Tailwind class sort in web/app/device/components/code-input.tsx
2026-05-18 21:54:49 -07:00
d5dee5326e feat(cli): align HITL pause envelope, split resume into top-level command, JSON purity
- Match server SSE envelope: HitlPausePayload now mirrors {event, task_id,
  workflow_run_id, data:{...}}; renamed user_actions → actions.
- New shared hitl-render.ts: text-mode block, JSON-mode pretty pure JSON
  (no ANSI), colored stderr hint. Exit 0 on pause (no longer a process error).
- Move RunAppResume → top-level ResumeApp at commands/resume/app/; rewire
  imports + regen tree.generated.ts. User-facing strings updated to
  `difyctl resume app`.
- Spinner gated on text mode: structured strategy passes
  enabled = isText && !livePrint so -o json/yaml never spin.
- Hint emits external-channel note when form_token is null (email-only
  delivery to OPENAPI/SERVICE_API surface returns no resume token).
- ColorScheme extended with dim/cyan/green/yellow/magenta methods.
- dify-mock fixture + tests updated to envelope shape; HITL pause test
  split into text + json variants.
2026-05-18 19:25:13 -07:00
badfd7689a feat(cli): build-time command-tree codegen + hidden/deprecated framework flags
Replaces the hand-written src/commands/tree.ts with a build-time-generated
artifact derived from src/commands/**/index.ts. tree.ts becomes a one-line
re-export of tree.generated.ts. Determinism: lexicographic sort, LF pinned
via .gitattributes, atomic write (tmp + rename), CI-gated by `pnpm tree:check`.

Codegen script (cli/scripts/generate-command-tree.ts) walks the commands
tree, derives canonical PascalCase identifiers (with reserved-word + hyphen
handling), and emits a static ESM module with sorted default imports and a
nested literal of shape CommandTree. Shared exclusion predicate
(isExcludedCommandPath) consumed by both codegen and coverage.test.ts so
underscore-prefixed segments stay non-commands.

Wired pre* lifecycle hooks (prebuild/predev/pretest) and ci composite
gating `tree:check` first. Pack now emits .js outputs (fixedExtension:false)
to drop .mjs; bin/run.js stays on .js. Vitest test.include extended to
cover scripts/.

Framework additions bundled in:
- static hidden = true       omits command from printTopLevelHelp listing
                              (still resolves and runs when invoked)
- static deprecated = '...'  prints "deprecated: <msg>" to stderr before
                              constructing the command

Verified: pnpm ci green (tree:check ok, tsc clean, lint clean, 702 tests
pass, build complete). Smoke: node bin/run.js version + auth login --help,
add-a-command flow, loose-file error case all behave as expected.
2026-05-18 18:25:57 -07:00
0ff00e742f fix(cli): restore BaseError catch routing post-oclif removal
PR #36328 (remove oclif) dropped the DifyCommand.catch() override that
routed BaseError through formatErrorForCli with semantic exit codes.
The replacement catch in framework/run.ts wrote raw err.message and
always exited 1, losing the code prefix, hint, http_status line, JSON
envelope path, and Auth/Usage/VersionCompat exit codes.

framework/run.ts:
- Add sniffOutputFormat(argv) helper: detects --output / -o (= and space
  forms), stops at --, first-occurrence-wins. Schema-free so it survives
  command-construction failures and pre-parse throws.
- Rewrite catch block: branch BaseError -> Error -> non-Error. BaseError
  branch routes through formatErrorForCli({ format: sniffOutputFormat(argv) })
  and exits via err.exit(). Explicit return after each process.exit
  defends against stubbed exits in tests.

run/app/sse-collector.ts:
- decodeStreamError now unwraps openapi-v1 InvokeError envelopes
  ({error_type, args, message}) buried inside env.message. Prefers
  args.description, falls back to inner.message, then raw on shape
  mismatch.

framework/command.ts:
- Sort named imports (fix pre-existing lint error).

Tests (run.test.ts new, sse-collector.test.ts extended):
- 10 sniffOutputFormat cases.
- 12 run() catch-routing cases: BaseError human/JSON, Usage/Server5xx
  exit codes, withRequest method+url in human and JSON, generic Error,
  non-Error throw, success path, constructor-time BaseError, --
  separator.
- 5 decodeStreamError unwrap cases.

Full suite: 675/675. type-check + lint clean. No subclass changes.
2026-05-18 16:34:32 -07:00
a89b43bccc simplify type signature 2026-05-18 20:30:57 +08:00
8918142ce1 refactor: remove oclif (#36328) 2026-05-18 19:07:23 +08:00
2fd7b82970 feat(cli,api): startSpinner export, local install scripts, OPENAPI enum mapping
- spinner.ts: extract startSpinner() returning ActiveSpinner handle for non-blocking use
- scripts/: add install-local.sh / uninstall-local.sh + pnpm install:local / uninstall:local
- api enums: add OPENAPI to InvokeFrom source mapping in both enum definitions
2026-05-17 20:10:01 -07:00
1cc7953f79 feat(cli): add --think flag to strip or show model thinking blocks
By default <think>...</think> blocks emitted by thinking-capable models
are silently stripped from the answer before printing. With --think,
thinking blocks are routed to stderr (with tags preserved) and the
clean answer goes to stdout.

- src/io/think-filter.ts: ThinkChunkFilter (stateful streaming filter
  that handles partial tags split across chunk boundaries), stripThinkBlocks
  and extractThinkBlocks for bulk non-stream processing; \r\n-aware
- stream-handlers.ts: ChatStreamPrinter and CompletionStreamPrinter use
  ThinkChunkFilter; streamPrinterFor(mode, think=false) backward-compat
- streaming-structured.ts: post-collect strip/extract on resp.answer
- streaming-text.ts + print-flags.ts: ctx.think threaded through
- run.ts, resume/run.ts, _strategies/index.ts: think field in types
- run/app/index.ts, resume/index.ts: --think oclif flag, default false
2026-05-17 19:18:34 -07:00
31cf656b35 feat(cli): app run overhaul — always stream, --inputs JSON, HITL pause/resume, Ctrl+C stop
- Remove blocking mode; all apps stream SSE, --stream controls live vs collect output
- Replace --input k=v with --inputs '{json}' (single object, mutually exclusive with --inputs-file)
- Add --workflow-id, --file flags
- HITL: human_input_required → pause JSON to stdout + hint to stderr + exit 2
- Ctrl+C: captures task_id from SSE, calls stop-task, exits 1
- New difyctl run app resume subcommand: POST form, reconnect SSE, stream to completion
- resume: --action (auto-select), --with-history (include_state_snapshot), --stream flags
- Delete BlockingStrategy; simplify pickStrategy(isText, livePrint)
- Add HitlPauseError, SILENT_EVENTS handling in sse-collector and stream-handlers
- Update dify-mock: always SSE, hitl-pause/hitl-resume scenarios, stop/form/events handlers
- Update agent guide: --inputs JSON syntax, HITL pause/resume instructions
2026-05-15 02:53:19 -07:00
1a83dfaf1f refactor: use BaseModel in openapi group. Generate ts code from swagger (#36076)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-13 12:56:42 +08:00
b21d0ae32d fix(cli): call this.parse in arg-less commands to silence oclif UnparsedCommand warning
oclif v4 warns "did not parse its arguments" for any command class whose
run() never calls this.parse(ClassName), independent of whether the
command declares args/flags. Add the call in the five arg-less commands.
2026-05-11 19:01:14 -07:00
6779366dca feat(api,web,cli): difyctl v1.0 — OAuth device flow, /openapi/v1 auth pipeline, CLI client 2026-05-11 18:40:39 -07:00