Commit Graph
37 Commits
Author SHA1 Message Date
james.maesandClaude Fable 5.1 bef8762aa0 release: run the TUI's Bun tests and type check before a release
The TUI is neither published nor bundled into the qqq binaries yet, but
it builds on the same kernel, so a release that breaks it should stop.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:41:12 -05:00
james.maesandClaude Fable 5.1 7893dd465e Merge feat/m1-kernel-cli (4728702) into feat/m5-cli-release
Brings in the TUI package and the hardening review (createProgram in
program.ts, qqq doctor, the golden-output suite). Resolutions: main.ts
from the base; program.ts prints versionText(), whose second line now
starts with "UI API client <version>" as the golden test expects and
adds the supported server range; the CLI package keeps the release
metadata with the base's exports and its new conformance dependency,
and conformance goes to 1.6.0-rc.2 because the CLI now ships against it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:40:33 -05:00
james.maesandClaude Opus 5.5 47287020b4 Merge feat/m1-kernel-cli (165c002) into feat/m1-hardening
Brings in the TUI stream (program.ts with createProgram and runCli, the io
object, qqq ui, session/login, local-state, filter completion, the result
cursor, the file navigator and env/doctor). Resolutions:

- main.ts is the base's thin entry; it still awaits the 0.1 credentials import.
- program.ts carries the option fixes (--version only, --server without -s)
  and registers qqq doctor.
- One set of ui helpers: the TUI's. readUiSettings/writeUiSettings are gone;
  qqq config set|get download-dir, upload-dir and download-mode use
  readFilePreferences/writeFilePreferences (ui.files), and the new
  qqq config set|get theme uses readTheme/writeTheme. readConfig keeps the
  corrupt-file refusal and unknown sections; the profiles test covers files,
  theme and an unknown section together.
- qqq doctor's terminal rows come from checkEnvironment, with formatReport
  under the table; --fix asks before each applyLiveFix and calls
  appendTmuxConf only after a y typed at a terminal.
- runCli and the prompts coexist (stdin is not a terminal in runCli, so
  prompts refuse; direct stdout writes are captured), tested in a child process.
- @qrun-io/qqq-ui-api-conformance is a dependency of the CLI package.
- The parity matrix is regenerated; docs/review-2026-10-31.md records each
  merge decision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 18:37:51 -05:00
james.maesandClaude Opus 5.5 4af42bb51f docs: review of the merged CLI and kernel; TRY-IT checked against the sample server
docs/review-2026-10-31.md lists each finding of the fresh-eyes review, its
severity and the fix (or why it was left). TRY-IT.md was run block by block
against the sample server and corrected: placeholders written as commands,
missing upload files, record ids the shared data no longer matches; it now
documents the option names shared by every noun, the footer, the exit codes
for a no, Ctrl-C and gateways, the download directory and qqq doctor. The
parity matrix notes REC-022 (BLOB upload and download) as verified and the
REVEAL masking in lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 18:32:58 -05:00
james.maesandClaude Fable 5.1 19569d8273 packaging: curl installer, Homebrew formula and Scoop manifest drafts
scripts/install.sh picks the binary for the machine (musl on Alpine,
native arm64 under Rosetta), verifies it against the release's
SHA256SUMS and installs to ~/.local/bin. qqq.rb and qqq.json follow the
qctl tap and bucket shapes; scripts/update-packaging.mjs fills their
version and checksums from the uploaded release so nobody pastes sums
by hand. The formula writes its own #compdef zsh file because the
output of qqq completion zsh is an eval script, not an fpath file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:31:41 -05:00
james.maesandClaude Fable 5.1 99befbb2ef Merge feat/m1-kernel-cli (f364a3c) into feat/m3-tui
Parity matrix regenerated with both the CLI and the TUI statuses.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:29:18 -05:00
james.maesandClaude Fable 5.1 dc6513bc8f docs: qqq ui README, TRY-IT TUI section, TUI parity column, server findings 21-22
packages/tui/README.md: running it, keys, screens, the : commands, the local
settings, the keys terminals and tmux may take (with the alternate_on
rebinding), tests and the code layout. TRY-IT.md replaces the spike section
with the qqq ui section. scripts/parity-matrix.py gets a TUI status table
and a TUI summary; feature-matrix.md regenerated (TUI: 118 pass, 25
partial). Server findings: recordSearch advertised with no provider, and
the untyped multiStatistics group (statisticList).

Also: -o -field in : commands and qqq ui routes, ASCII title separators,
short F-key labels at 80 columns.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:28:40 -05:00
james.maesandClaude Fable 5.1 2bc76f6dc4 release: scripts/release.mjs checks a release and prints the commands
Clean tree, free tags, npm ci, the orb's generate-drift, build and test
steps, lint, npm pack dry runs and the binaries; then it prints the
signed tag, npm publish and gh release commands. It never tags,
pushes or publishes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:28:04 -05:00
james.maesandClaude Fable 5.1 e1135b958f build: single-file qqq binaries with bun build --compile
scripts/build-binaries.mjs (npm run binaries) writes
dist/qqq-<os>-<arch>[.exe] for macOS arm64 and x64, Linux x64 and arm64
(glibc), Windows x64 and, with --musl, Linux musl, plus SHA256SUMS. It
refuses to build when the compiled-in operations index no longer
matches the OpenAPI document or the CLI version constant disagrees with
package.json, stamps the commit and target into qqq --version, and
smoke-runs the host binary. x64 targets use the baseline runtime so they
run on pre-AVX2 CPUs and under Rosetta or QEMU.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:28:04 -05:00
james.maesandClaude Fable 5.1 e488df6d70 lint: fail when release versions disagree
Checks the CLI's compiled-in version against its package.json, the
client's UI_API_VERSION against the document's info.version, and every
workspace dependency against the workspace version, so a coordinated
bump cannot leave one behind.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:28:04 -05:00
james.maesandClaude Fable 5.1 0588e902fe release: 1.0.0-rc.1 metadata for the CLI, core and client packages
CLI and core go to 1.0.0-rc.1 and the client to 1.8.0-rc.2, with the
workspace dependencies pinned to them. Every published package now has
repository, homepage, bugs, engines (Node 20+), publishConfig, explicit
exports and a files list that leaves out compiled tests and source
maps. The repository LICENSE is copied in on prepack because npm only
packs a LICENSE from the package root. core had no publishConfig, so a
publish would have gone to the public registry; it now targets GitHub
Packages like the others. The CLI and client packages get the README
their files lists already named.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:28:04 -05:00
james.maesandClaude Fable 5.1 913e2a22ce tui: in-memory renderer tests, tmux smoke script, dashboard headings; core: multiStatistics
bun test in packages/tui (npm run test:tui at the root): the whole TUI
against a fake server in the test renderer: Esc from record 4 lands on row
4 and after stepping to record 7 lands on row 7; server paging, sort and a
:filter; a contingent form where State waits for Country and narrows;
the process wizard through an asynchronous job to its summary; F10 asks.
Plus unit tests for column layout, the line editor under a key burst,
command-line splitting and theme tokens.

packages/tui/scripts/smoke.sh drives the real TUI in tmux against the
sample server through fourteen screens and keeps the captures.

The kernel's multiStatistics reading accepts statisticList, the spelling
the sample server sends. Lint covers packages/tui.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:22:51 -05:00
james.maesandClaude Fable 5.1 f364a3c8de Merge feat/m1-kernel-cli (ee855eb) into feat/m1-process-components
Brings in the extensions, related-records and query-gaps streams. The parity
matrix is regenerated from the merged STATUS table; process downloads already
use the shared safeFileName/saveDownload helpers from the base.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:06:15 -05:00
james.maesandClaude Fable 5.1 2bf68e9667 client+cli+dev-idp: OAuth2 browser sign-in with PKCE, provider logout, revoked sign-ins
qqq login --browser signs in with the authorization code and S256 PKCE on a
loopback redirect (RFC 8252): a one-shot listener on 127.0.0.1 takes the
callback, the state is checked, and the code is exchanged at the provider with
the verifier (no nonce, as UI-API-CLIENTS.md section 7 asks). --port,
--redirect-host and --no-open cover exact registered URIs and headless hosts.
A denied request, a forged state or a refused exchange exits 3 and saves
nothing; the new token is checked against the server before it is kept.

qqq logout --provider-logout revokes the refresh token (RFC 7009) and opens
the provider end-session URL with the ID token, which refreshes now keep. A
refresh the provider refuses becomes UNAUTHENTICATED (exit 3, sign in again).

qqq-dev-idp gains the authorize endpoint (Approve/Deny page or auto-approve,
loopback redirects and S256 only), the authorization_code grant, ID tokens,
revocation and end-session. The device flow was run end to end for the first
time against a sample on OAUTH2 (8078) and worked unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:02:40 -05:00
james.maesandClaude Fable 5.1 ee855eb146 Merge feat/m1-kernel-cli (extensions) into feat/m1-query-record-gaps
My server findings move to 19 and 20 after the merged 18.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:01:43 -05:00
james.maesandClaude Fable 5.1 3c75c22d41 Merge feat/m1-kernel-cli into feat/m1-query-record-gaps
Conflicts resolved by keeping both sides: table get keeps the record view
(sections, links, reveal, help) and gains --join and --variant; create and
update keep uploads and parents and send the variant; filters keep the
DATE_TIME to UTC conversion and accept joined names; export keeps safe
file names. My server findings are renumbered 18 and 19 after the merged
13 to 17. Joined DATE_TIME values are now shown in the local zone too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 18:01:06 -05:00
james.maesandClaude Fable 5.1 6f822f3baa Merge feat/m1-kernel-cli (dd33657) into feat/m1-extensions
Conflicts: core index exports (records, render/files and extensions all kept), CLI context
(imports from both sides; UnsafeFileNameError exits 2 and ExtensionNotInstalledError exits 5),
server-findings (the presence finding is now #18, after related records' #16 and #17). The parity
matrix regenerates unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:58:25 -05:00
james.maesandClaude Fable 5.1 275abe90ca docs: parity rows and TRY-IT line for audits
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:58:06 -05:00
james.maesandClaude Fable 5.1 9cc07008fb docs: parity rows and TRY-IT lines for saved views
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:57:08 -05:00
james.maesandClaude Fable 5.1 dd33657f4f Merge feat/m1-kernel-cli (e058942) into feat/m1-related-records
Brings in the DATE_TIME work (local-zone display and input, --utc, process input exit codes).
The record view now formats DATE_TIME through displayDateTime (the viewer's zone, --utc for
the raw instant, server-zoned text kept), and so do the child lists of table get
--associations and table children; create/update keep the base's conversion through the
form session, including the --parent and --upload paths. process.ts keeps the base's value
formatting with the unified safeFileName/saveDownload. Exports, TRY-IT sections and parity
STATUS merged; this branch's findings renumbered to 16 and 17; matrix regenerated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:57:07 -05:00
james.maesandClaude Fable 5.1 23d625ef9a Merge feat/m1-kernel-cli (e058942) into feat/m1-extensions
Conflicts: core index exports (both kept), CLI context imports (both), main.ts registrations
(extensions and help), server-findings (the presence finding renumbered to #16 after #11-#15).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:56:53 -05:00
james.maesandClaude Fable 5.1 e058942257 core+cli: DATE_TIME typed and shown in the local zone, sent as UTC instants
forms/datetime converts typed wall-clock times (2026-10-31T14:30) to UTC in
the TZ zone with Intl offsets: a time in a spring-forward gap moves forward,
a repeated fall-back time means its first occurrence, and an unchanged
wall-clock time keeps the original instant with its precision. Instants are
shown as 2026-10-31 14:30:00 CDT; display values the server formats in a
declared zone are kept; --utc shows raw instants.

The form session converts DATE_TIME on set (table create, update, copy and
process values), DATE_TIME validation now requires a date and time, --where
and --group criteria on DATE_TIME fields are converted (a date alone is local
midnight), and table get/query and process screens format in the zone.
Tests cover Chicago, London, Sydney and Kolkata DST edges; verified live on
fieldLab (create, get, --utc, TZ=Asia/Tokyo, filters, update across the gap,
fieldLab.bulkEdit values).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:54:29 -05:00
james.maesandClaude Fable 5.1 416790169d Merge feat/m1-kernel-cli (ffedcbb) into feat/m1-related-records
Conflicts resolved: core index keeps every export; table get keeps --key (Go To) and gains
the record view, --associations, --links, --follow, --reveal, --help-content; table export
keeps the new formats, --search and stdout with the kernel's safe default name; README module
table and TRY-IT keep both; server findings keep 11-14 from the base and renumber this
branch's to 15 and 16; parity STATUS merged row by row and the matrix regenerated. The record
view's help helpers are renamed helpEntryText and tableViewHelp, since the base's help and
process screen modules export helpText and tableHelp.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:54:17 -05:00
james.maesandClaude Fable 5.1 8dbd434d8f docs: parity rows and TRY-IT lines for column statistics
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:53:12 -05:00
james.maesandClaude Fable 5.1 e3703a34a1 docs: parity rows, TRY-IT lines and server findings for joins and variants
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:51:25 -05:00
james.maesandClaude Fable 5.1 093b5377fe docs: related records and record view in TRY-IT, parity and findings
TRY-IT gains the related-record and record-view commands as verified against the sample.
Parity: REL-001..005 and 009, REC-028 pass live; REL-006..008, REC-002, REC-029..041 are
partial because the sample declares no such metadata (kernel unit tests cover them).
Findings: downloadRecordFieldFile 500s on a BLOB without adornments, and the sample lacks the
adornment, help and composite-association metadata needed to check those rows live.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:51:00 -05:00
james.maesandClaude Fable 5.1 0ef9bfb364 Merge feat/m1-kernel-cli into feat/m1-process-components
Keeps both export sets in the kernel index, renumbers the process findings to
13 and 14 after the query-gaps findings, and regenerates the parity matrix from
the merged STATUS table.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:49:50 -05:00
james.maesandClaude Fable 5.1 e4916c2971 core+cli: every process step component, review prompt, cancel, back, min/max records
The kernel gains a screen model (process/screen): each step's components in
declared order become neutral blocks both heads render - HELP_TEXT and HTML as
text, VIEW_FORM pairs on every step, RECORD_LIST paged through GET .../records,
the validation review with its preview and summary, PROCESS_SUMMARY_RESULTS
lines, DOWNLOAD_FORM references (GET /download), WIDGET through the widget
render model, and step help content.

The runner presents each screen, asks the provider on every input step
(validation review included), restarts at backStep with isStepBack=true when
the provider returns BACK, cancels on an abort signal with POST .../cancel,
and checks min/max input records before init. A step whose components are
only a VIEW_FORM no longer counts its formFields as inputs.

qqq process run prints intermediate screens to stderr and the last as its
output, asks validate-or-skip and Submit? on a terminal, saves downloads to
--out-dir, and turns Ctrl-C into a server cancel (exit 130). Verified live on
sleepInteractive, greetInteractive, clonePeople, simpleThrow, placeAddressPick
and person.bulkEdit's review screen; findings 11 and 12 recorded.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:47:38 -05:00
james.maesandClaude Fable 5.1 c31a426ea8 docs: parity rows, TRY-IT lines and server findings for query and record gaps (batch 1)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:46:29 -05:00
james.maesandClaude Fable 5.1 2a2325bc6f client: merge every extension document and tag each operation with its extension
The client document is now the sample server's live document (core plus esb, UI API 1.8.0) merged
with the extension documents of every qbit checked out beside this repository: health (qqq), alerts,
assistant, collaboration, data-analysis, db-performance, edi, qa-capture, quick-search,
release-notes, secured-data and sql-workbench. 202 operations, 136 of them from extensions.

- scripts/merge-spec.mjs records each extension's path prefix and operationIds in
  info.x-qqq-extensions, and accepts an extension the core input already carries when its
  operations are identical (the live document's esb), instead of failing on the duplicate.
- scripts/merge-extensions.mjs (npm run spec:merge-extensions) finds the documents, merges them and
  writes openapi/extension-sources.json with each document's version, branch and commit.
- scripts/gen-operations.mjs adds `extension` to OperationInfo (from x-qqq-extensions, else the
  /qbit/{name} or established prefix) and exports DOCUMENT_EXTENSIONS.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:43:58 -05:00
james.maesandClaude Fable 5.1 7f1ad5e120 ci: prepublishOnly and lint scripts the qqq-orb node profile runs
The orb's node_install_dependencies runs npm run prepublishOnly (now the workspace build) and
node_run_tests runs npm test then npm run lint. lint checks license headers and that no
package imports another package's src. Also records finding 10: the sample app has no
uploaded-file archive table, so bulk load cannot be exercised against it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:31:32 -05:00
james.maesandClaude Fable 5.1 455e62ff2f docs: terminal-clients parity matrix generated from the Next UI acceptance matrix
docs/parity/feature-matrix.md keeps the 401 Next UI row ids and adds a CLI and a TUI column
(pass, todo, partial, n/a with reasons), computed by scripts/parity-matrix.py from the copied
Next matrix (docs/parity/next-feature-matrix.md) and the status table in the script. First fill
of the CLI column after the M1 work so far.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:28:49 -05:00
james.maesandClaude Fable 5.1 8ed694cd2f cli: noun-verb grammar on the kernel, output formats, JMESPath, CRUD, api escape hatch
qqq <noun> <verb> for table (list, describe, query, count, get, create, update, delete, export),
process (list, describe, run) and job (list, get, logs, cancel, retry), with the 0.1 flat
commands kept as hidden aliases. Global --output json|table|text|csv|yaml, --json, --query
(JMESPath), --fields, --yes and --trace work before or after the subcommand. Filters take
--where, --group (AND/OR with parentheses), --or, --order, --filter-json, --print-filter and
--count; queries page with --limit, --skip and --all. qqq api <operationId> calls any
operation from the generated index (--path, --param, --body-json, --form, --bytes, --out).
Exit codes: 2 usage and bad filters, 3 auth, 4 unreachable or rate limited, 5 not found,
6 validation, 70 server error. The realtime stream can carry a session cookie for tail.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 17:03:18 -05:00
james.maesandClaude Fable 5.1 ff27af2f9e cli: session sign-in for MOCK and anonymous servers, sent as a cookie; qqq launcher
The client gains getAuthenticationMetaData, createSession (reads the HttpOnly sessionUUID
cookie) and a sessionCookie option; UI_API_VERSION is 1.8.0. qqq login branches on the
server's authentication type and stores a server session for MOCK and FULLY_ANONYMOUS; the
device flow stays for OAUTH2 and AUTH_0. The session goes as a cookie because a bearer
session cannot continue asynchronous process steps on the 4.1.0-SNAPSHOT sample server.
scripts/dev/qqq.sh runs the CLI from source so every commit is testable without a build.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 16:21:02 -05:00
james.maesandClaude Fable 5.1 45db6bbc7e spike(m0): show the running build in the launcher and status line
So the person testing always knows which commit the shell is, and whether it carries
uncommitted changes. TRY-IT.md explains that there is no install step.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 16:17:03 -05:00
james.maesandClaude Fable 5.1 c11495643e spike(m0): OpenTUI feasibility spike with results, dev launchers and TRY-IT guide
Throwaway OpenTUI (React) spike on Bun: 10k x 40 grid, every-field-type form, and a real
UI API process run with an async job against the qqq sample server. Records the go
decision, the measured latencies, binary sizes, and two server findings (bearer session
cannot continue an async process step under MOCK auth; url-encoded process values are
silently ignored). Adds scripts/dev launchers so the client can be tried after every step.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 15:48:34 -05:00
james.maesandClaude Opus 5.5 ea79ddeb78 feat: reference CLI, generated UI API client, conformance suite and dev IdP
- @qrun-io/qqq-ui-api-client: typed client generated (openapi-typescript +
  openapi-fetch) from the merged UI API document; device-flow sign-in, refresh,
  UiApiError (BasicErrorResponseV1), SSE reader
- @qrun-io/qqq-cli: qqq login/whoami/apps/tables/query/get/run/jobs/tail,
  only through /qqq/v1 with Authorization: Bearer
- @qrun-io/qqq-ui-api-conformance: black-box suite + qqq-dev-idp
- scripts/merge-spec.mjs, Prism mock, CI and GitHub Packages publish workflows

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:47:12 -05:00