Skip to content

Releases: intelligo-dev/intelligo

v1.3.0-next.1

v1.3.0-next.1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 22 Oct 17:01
e801599
  • Upgrade: recommended — the chat transport no longer reads client-sent history on a new conversation's first turn
  • Breaking: the admin plugin's user writes answer 404 over HTTP, and the chat item's saveMessageAsArtifact takes { conversationId, messageId, title? } (steps under Upgrading)
  • Migrations: none

Added

  • ### Security is a changelog category. From 1.2.5, each of its entries
    links the GitHub security advisory published for it, and from 1.3.0 a
    section that has one says Upgrade: required;
    scripts/release-notes.mjs refuses a release whose section does not.
  • The admin-console registry item: the platform operator's console under
    /admin, installed as source the application owns
    (intelligo sync admin-console). An overview (the product's own panels
    first, then the last 24 hours and integration health), a searchable,
    paged user directory with a record panel, a workspace's support page
    (plan, credit, members, payments, executions, and grant-plan, add-credit
    and impersonate actions that each need a reason), revenue and costs (the
    billing settings, the payment ledger and the usage ledger, paged), and
    operations (failed jobs, unsettled executions and the audit trail, with
    actors and resources by name). A platform admin only; anyone else gets
    the app's 404. Every string is in the admin-console message namespace,
    and dates and money are written by next-intl's formatter in the
    reader's time zone.
  • Its seams: lib/admin-nav.ts (the sidebar, titleKeys resolved like
    lib/settings-nav.ts) and lib/admin-config.tsx (brandKey,
    backHref, overviewPanels, workspacePanels(workspaceId),
    auditFilterPlaceholderKey).
  • Its components serve a product's own console pages too:
    components/admin/page-title.tsx (title, description, crumbs,
    actions), panel.tsx (Panel, Stat, Status, PaymentStatus),
    action-form.tsx, data-list.tsx (a URL-state list over data-table
    and record-panel, with bulk actions and UrlTabs), properties.tsx
    (property-list without the server and browser formatting a value two
    ways), settled.tsx, and lib/admin-page.ts / lib/admin-list.ts /
    lib/admin-format.ts.
  • @intelligo-dev/admin: isPlatformAdmin(), the admin check without an
    audit row; listUserSummaries({ query, limit, offset }),
    getWorkspace(id), listWorkspaceMembers(id),
    listPayments({ workspaceId, status, limit, offset }),
    getSignupsByDay({ days, timeZone }), resolveDisplayNames(),
    countAuditEvents() and countUsageRecords(); listUsageRecords takes
    an offset.
  • @intelligo-dev/audit: queryAuditEvents takes an offset, and
    countAuditEvents counts the same filters.
  • From this release on, every GitHub release carries a CycloneDX 1.6
    SBOM per published package (intelligo-dev-<package>-<version>.cdx.json):
    its runtime dependencies as the release's lockfile resolved them, each
    with its registry hash, and the package's tarball hash in hex — the
    sha512 npm serves as integrity. Earlier releases carry none.
  • From this release on, every GitHub release carries each package's SLSA
    provenance as npm serves it: the Sigstore bundle
    (intelligo-dev-<package>-<version>.sigstore.json) and the attested
    statements (intelligo-dev-<version>.intoto.jsonl).
  • A next channel: the next minor ships as X.Y.0-next.N, and
    npx @intelligo-dev/cli@next create scaffolds it with its own pages
    from /r/<version>/ (the scaffold template is 1.23.0). A maintainer's
    node scripts/npm-maintain.mjs keeps next at or above latest and
    removes the retired beta tag; the release run says when next is
    behind.

Changed

  • Calling checkQuota, or checking out a credit bundle with
    credits/priceUsd, logs a one-time DeprecationWarning
    (INTELLIGO_DEP0001 to INTELLIGO_DEP0003) naming the replacement.
  • The admin plugin's user writes — create-user, update-user,
    set-role, set-user-password, ban-user, unban-user,
    remove-user, revoke-user-session(s) — answer 404 over HTTP, like
    impersonation and the user listings already did. They leave no audit
    row, and the platform role holds no permission for them; closing them
    keeps a role that gains one from opening them to the browser.
    Server-side calls through auth.api are unaffected.
  • @intelligo-dev/auth sets the rate limits of its credential
    endpoints itself rather than inheriting Better-Auth's: 3 attempts per
    10 seconds at signing in, signing up and changing a password or email,
    3 reset or verification emails per minute, and 100 requests per 10
    seconds elsewhere. The numbers are unchanged; on the paths
    AUTH_RATE_LIMIT_RULES names, a dependency update can no longer move
    them, and any other path keeps Better-Auth's built-in rule. They, the
    session lifetime and the impersonation length are named constants in
    request-hardening.ts.
  • @intelligo-dev/billing's admission rule and settlement's pool split
    are pure internal modules, with no change in behaviour or API.
  • applyRate's documentation states its rounding bound in the
    deployment's own currency: under usdRateMicros / 1e6 + 1 micros
    over the exact charge, which is two micros only in a USD deployment.
  • .env.example (app-scaffold 1.23.0) and the Environment page list
    STORAGE_*, read once a storage adapter is bound, and
    ACCOUNT_DELETION_GRACE_DAYS, and say production refuses to start
    without an email provider. The docs guard now finds a variable read
    from an injected env as well as from process.env.
  • The deploy guide says production refuses to start without an email
    provider unless EMAIL_PROVIDER=console, and lists the warnings
    assertEnv() logs, separating those logged only in production from
    those logged in every environment.
  • The billing README (and /docs/packages/billing) describes registering
    a local payment provider once, with what its currency does.
  • The docs have a Security section, opening at /docs/security with what
    the framework enforces and what stays the application's.
  • A production checklist at /docs/security/production-checklist: the
    environment, proxies, rate limits, platform admins, the maintenance
    cron, Stripe, the AI surface, the edge and database, and what to watch.
  • Threat models at /docs/security/: threat-model-auth,
    threat-model-billing, threat-model-chat, threat-model-executions,
    threat-model-storage (file storage and chat uploads) and
    threat-model-admin (the admin console and support impersonation).
  • intelligo.dev and /r serve the release npm tags latest; a
    prerelease keeps its own copy at /r/<version>/, frozen once npm has
    it, and its publish does not redeploy the site.
  • Every fixed vulnerability gets a published GitHub security advisory,
    with its affected and patched versions, a CVSS score and a CVE where
    one is assigned, so Dependabot and npm audit report it to projects on
    an affected version. SECURITY.md says so and links the published
    advisories; its fix goes under ### Security, linking the advisory,
    and npm marks the affected versions deprecated.
    docs/incident-response.md writes the advisory in the private report
    and publishes it once the fixed version is on npm.
  • RELEASES.md: what a patch, minor and major may change, what counts as
    public API, which packages are stable and which experimental, the
    release cadence, the support window and the deprecation rule.
    SECURITY.md says how fast a report is acknowledged, triaged and fixed
    by severity, that disclosure is coordinated within 90 days, the safe
    harbour for good-faith research, a scope that includes the registry
    items, the CLI scaffold and what client data may reach server state,
    and a supported-versions table that an architecture test holds to the
    released minor.
  • docs/incident-response.md: the maintainers' runbook for a report or an
    incident — roles, severity and timelines, containing a compromised npm
    account, trusted publisher or Cloudflare token and a leaked
    BETTER_AUTH_SECRET, how the fix release is cut, and how users are told.
  • GOVERNANCE.md: roles, review rules, and how a contributor becomes a
    maintainer.
  • CONTRIBUTING.md is written for people: where to start, the boundary
    rule, setup, the steps of a change and what review checks. It no
    longer sends a newcomer to AGENTS.md first. SUPPORT.md drops the
    beta wording.
  • CONTRIBUTING.md and the pull request template say what an
    AI-assisted change passes and which lines a person reads.
  • .github/CODEOWNERS marks the high-risk source paths, and a test keeps
    every pattern there matching a tracked file.
  • The review-window status holds a pull request that touches a
    high-risk path, or is labelled security, for 24 hours. Its workflow
    stays inactive until the repository variable REVIEW_WINDOW_CLIENT_ID
    is set.
  • The new-issue chooser links the Show and tell discussions, for a
    product or demo built on Intelligo.
  • node scripts/npm-maintain.mjs deprecates, per package, the versions a
    published security advisory affects (vulnerable.fixedIn in
    scripts/npm-deprecations.json), so installing one warns and points at
    the advisories; nothing is deprecated for a package until npm has its
    fixed version.
  • CI fails when a workflow uses an action by tag instead of commit SHA,
    grants a write scope at the top level, leaves the token in a checkout,
    hands a checkout, an env var or a step the triggering event's head
    (a workflow_run, a pull request's head, head_ref) or triggers on
    pull_request_target; CI's checkouts no longer keep the token.
  • OpenSSF Scorecard runs weekly and on every push to main; its results are
    public at scorecard.dev and in the repository's code-scanning alerts.
  • The README shows the OpenSSF Scorecard score.
  • A dependency-audit workflow, separate from the CI run the release waits
    on, fails...
Read more

v1.2.4

Choose a tag to compare

@github-actions github-actions released this 20 Oct 16:40

Fixed

  • property-list rendered an element that a server component passed as
    a value — a link, a badge — as React's internal fields laid out like a
    record. Such an element reaches the client as a lazy reference, and
    PropertyValue now renders it as itself.

v1.2.3

Choose a tag to compare

@github-actions github-actions released this 20 Oct 14:59

Added

  • Three registry primitives for a product's console, installed with
    shadcn add @intelligo/<name>:
    • data-table: a list the server pages, sorts and filters — rows with
      a pinned header and keyboard steps (↑ ↓, Enter, Space), a toolbar
      with search, facet filters and a column and density menu, removable
      filter chips and pagination. It is controlled: every change is a
      callback, so the product decides how list state reaches the server
      (usually the URL).
    • record-panel: one record opened in a sheet beside its list, with
      previous and next (the arrow keys, or J and K), a link to its full
      page, actions and a pinned footer.
    • property-list: a record's fields as label and value. Dates,
      numbers, lists and nested records are formatted for a reader rather
      than shown as JSON, and empty fields fold behind a toggle.
  • Their copy comes in through a labels prop with English defaults, as
    the other primitives take theirs.

v1.2.2

Choose a tag to compare

@github-actions github-actions released this 18 Oct 14:52

1.2.1 was set on main but never published: its release commit failed CI
on formatting. 1.2.2 is that release.

Added

  • setConversationSharing("public" | "workspace" | "off") in
    @intelligo-dev/core chooses who a share link opens for. public
    (the default) is unchanged; workspace opens a link only for members
    of the conversation's workspace; off hides the share dialog and
    refuses to share (sharing_off). The public read honours it on the
    server.
  • Invitations carry a product's own fields: inviteMember takes
    productFields, accepting the invitation copies them to the new
    membership, and memberProductFields reads them back.
  • isImpersonating(session) in @intelligo-dev/auth.
  • The chat config takes linkHosts, and Markdown takes
    linkPrefixes: a product that names them links only to those hosts,
    and other links show as text. MarkdownLink is the confirming link a
    components.a override falls back to.
  • DOCUMENT_LIMITS bounds a saved document's id, title, content and
    kept versions.

Changed

  • Production refuses to start without an email provider: set
    RESEND_API_KEY or LOOPS_API_KEY, or choose EMAIL_PROVIDER=console
    explicitly.
  • A chat opened with ?query= puts the text in the composer instead of
    sending it. A same-origin handoff still sends.
  • For a persisted conversation, the model reads the stored transcript:
    an earlier message the client sends is replaced by the stored message
    with the same id and role. persist: false, or a product's own
    persist, keeps the old path.
  • hasFeature answers false with degraded: true while the feature
    flags cannot be read, instead of falling back to the plan matrix.
  • Platform admins list users, read a user, list a user's sessions and
    start or stop impersonating only through the admin console's server
    calls, not the raw auth endpoints.
  • Checkout, local payment and credit purchases refuse while an admin is
    acting as the user (errors.impersonating).
  • Reply links open only http(s), mailto: and tel: addresses.
  • An HTML document preview runs under a content security policy that
    reaches no server, and only code documents are previewed as HTML.

Fixed

  • Tokens prepareMessages spent are charged when admission then
    refuses the turn.
  • A saved document links only the actor's own conversations, and old
    versions beyond the limit are pruned. Too long or foreign input shows
    actions.invalidArtifact.
  • The prompt sanitizer strips role prefixes, chat-template tokens,
    [INST] and prompt tags in any language.
  • Links next to citations still confirm before opening.

Upgrading

Run intelligo migrate before deploying:
0009_invitation_product_fields adds a nullable product_fields jsonb
column to invitation and member. Nothing is rewritten.

Set RESEND_API_KEY, LOOPS_API_KEY or EMAIL_PROVIDER=console in
production, or the app does not start.

Run intelligo sync for every item (chat, chat-share, dashboard,
pricing, payment-poll, ai-markdown, document-viewer and
artifacts changed). Add the chat keys actions.invalidArtifact,
actions.sharingOff and share.descriptionWorkspace, and the pricing
and payment-poll key errors.impersonating, to any locale you own.

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 08 Oct 03:55
e6d7d12

Added

  • Account deletion with a grace period. Deleting an account schedules it
    for 30 days (ACCOUNT_DELETION_GRACE_DAYS); signing in during that
    time leads to a "Restore your account" screen, and afterwards
    purgeDeletedAccounts, called from the maintenance route, removes the
    user's private conversations, facts, memories and profile snapshots
    while usage, billing and execution rows stay with the user cleared.
    Deletion is refused while the user is the only owner of a workspace
    other people belong to; workspaces only they belong to are deleted
    with the account and their subscriptions ended.
  • Audit trails can be pseudonymized: eraseUserFromMemoryAudit and
    eraseActorFromAuditEvents clear what the trails hold about a person
    (ids, recorded values, the actor's email) and keep what happened. The
    append-only triggers allow exactly that change.
  • consumeFeatureQuota in @intelligo-dev/billing checks a feature
    quota and counts the use in one statement, so concurrent requests
    cannot exceed the limit.
  • Credit purchases are reversed when refunded or disputed:
    charge.refunded and charge.dispute.created take the refunded or
    disputed share back from the balance, never below zero, as a credit
    usage row and a billing.credit_reversed audit event.
  • runInBackground and setBackgroundTaskRunner, with
    nextBackgroundTasks from @intelligo-dev/next: work the framework
    starts without awaiting (auth emails, a new workspace's bootstrap,
    notification emails) keeps running after the response on a serverless
    host.
  • The chat upload route takes upload.rateLimit, maxUnclaimedBytes
    and admitUpload, and honours the chat feature gate. The chat route
    takes maxBodyBytes.
  • run.progress({ usage }) records a running execution's usage so far,
    and reconcile() charges an abandoned run that recorded usage instead
    of releasing its hold.
  • pruneNotifications removes old read notifications;
    pruneJobs(before, { failedBefore }) also deletes failed jobs.
  • summarizeExecutions and summarizeExecutionsByDay take an optional
    userId.
  • intelligo.dev/r keeps every release's items at
    /r/<version>/<item>.json, and the site sends a content security
    policy, refuses framing and serves the registry as JSON to any origin.

Changed

  • intelligo.dev/r serves the items of the latest release on npm instead
    of main.
  • The usage page follows the caller's role: owners and admins see the
    workspace's usage, spend, quota and trial credit; members see only the
    runs they started.
  • Older reply versions are read-only: the composer, edit and regenerate
    return on the latest version, which is the one stored.
  • @intelligo-dev/auth and @intelligo-dev/billing declare react as
    a peer dependency, since they send email rendered with React.
  • The workspace limit counts the workspaces a user owns, not the ones
    they were invited into. Workspace names cannot contain links, and
    invitations are rate-limited per sender and per workspace.
  • The release workflow publishes from a job that runs no install, build
    or test and holds only npm's OIDC identity, in dependency order;
    tagging and the GitHub release run in a job that holds only the write
    token, and point at the release commit. A hand-pushed v* tag
    publishes only when it points at the release commit on main.

Fixed

  • A tool-approval continuation resumes the assistant message the model
    wrote. The handler takes the stored message and copies only the
    client's answers onto it: an approval or denial for a call awaiting
    one, under that call's approval id and with the input the model
    proposed, or the output of a tool the client runs. Any other change,
    a call the model never made, or a message stored under another role
    refuses the turn, and the finished reply is persisted from the stored
    message rather than the client's copy. A call that already ran or was
    denied can no longer be approved again.
  • A user message carries text, files and data-* parts only. A file
    part's providerReference and providerMetadata are dropped, so the
    model reads the file whose URL was checked; an assistant message's
    file must carry its bytes as a data URL. An elided file is restored
    only from a stored message of the same role, and only when the
    attachment policy still accepts it.
  • upsertMessages in @intelligo-dev/core/conversations no longer
    rewrites a stored message under a different role.
  • Usage and money counters no longer overflow: a month's token count and
    Stripe, local-payment and credit-pack amounts are 64-bit.
  • Deleting a user or a workspace no longer fails because of the memory
    audit, and deleting a fact no longer keeps its content there.
    Notifications are deleted with their user or workspace.
  • customer.subscription.updated writes the subscription's current
    state, read back from Stripe, so an older update retried after a newer
    one no longer restores the earlier plan. A local payment refuses to
    sell a plan to a workspace a live Stripe subscription bills
    (subscription_active), a days grant after a canceled subscription
    starts from now, and two subscription checkouts started together no
    longer both open a session. Deleting a workspace cancels its
    subscription only once the workspace is gone.
  • hasFeature no longer caches an answer decided while the database
    could not be read, and its cache drops expired entries.
    getBillingSettings throws instead of answering with USD defaults
    when the row has never been read. Settlement treats a usage row in
    another currency as an exhausted allowance. The first quota row for a
    user is created once; recordFeatureUsage works on Postgres again.
  • A trial's warning and remaining share follow its money grant; trial
    reminders are sent at most 50 per run and retried when the email was
    not sent; a usage or trial notice that could not be delivered is
    retried by the next check. The rate-limit and reservation cleanups
    delete in batches.
  • A chat file part is estimated by what the model reads, not its base64,
    so an inline image no longer inflates the admission hold, empties the
    window or inflates a stopped reply's charge. The default window keeps
    the user message an over-budget continued assistant message answers. A
    step the provider fails partway through is charged from what ran.
    streamTurn receives stored files as the model sees them.
  • The chat route authenticates before reading the body. A first turn
    refused at admission leaves no empty conversation (turn.conversation
    is null on a first turn, as documented). The share page leaves out a
    failed call's raw input and provider metadata, and no longer carries
    the conversation id. With persist: false, uploads are no longer
    swept as unclaimed. sendWithoutEarlierFiles keeps the bytes of a
    message no reply answered.
  • Editing a message drops it and everything after it on the server,
    including the first message of a conversation or of the loaded page.
    Reopened chat panels and widgets continue from what is stored.
    chat-eve stores a stopped turn's cursor, settles steps finished before
    a failure, closes eve's stream after each turn and reads "Don't allow"
    as a denial. A malformed percent escape in a source URL no longer
    breaks rendering; an attachment can be sent on its own; the dashboard
    prompt no longer travels in the URL.
  • mastra settles against the admitted model; a differing reported id
    is kept as metadata.reportedModel.
  • A job claimed in a batch runs once, and a failed status write no
    longer re-runs a handler or stops the batch.
  • Requests to the bucket and the email providers time out. An upload
    whose row cannot be written removes its object, and a key the bucket
    keeps refusing no longer holds back other deletions. Request headers
    stay with their own call when two request contexts start at once
    outside Next.
  • A shared conversation stops being public when its author leaves the
    workspace or deletes their account. Admins cannot remove themselves
    from a workspace; they leave it.
  • intelligo sync keeps the app's seams and messages when an install is
    interrupted (under .intelligo/sync-restore/), backs up shadcn's own
    files an install replaced, and runs on Windows from a path with a
    space; intelligo remove and intelligo add --force back up what
    they replace. intelligo migrate takes an advisory lock; migrate --check reports an adopted pre-1.0 database as up_to_date or
    pending. intelligo doctor accepts every client-safe framework
    module.
  • getIntegrationHealth refuses a caller who is not a platform admin.
  • Signup's verification link lands on /verify-email; a failed fact
    deletion comes back into the privacy list with the error; plan prices
    show their cents; the pricing, checkout, artifacts and invitation
    error boundaries render RouteError; a timed-out QR payment checks
    the same invoice again; the login page confirms a password reset and
    billing settings confirm a credit purchase; the trial banner survives
    storage that throws.
  • Accessibility: settings tabs are single links, the onboarding card
    group has a name, paywalled content is inert, a press-and-hold button
    confirms on a screen reader's click, and Spinner takes a translated
    label and is otherwise decorative.

Upgrading

Run intelligo migrate before deploying:
0008_wide_counters_kept_ledgers widens four counters to bigint, keeps
memory-audit and usage rows when a user or workspace is deleted, adds
foreign keys on notifications and eight indexes. Nothing is renamed or
removed; widening a column rewrites its table under a lock, so run it in
a quiet window.

Bind setBackgroundTaskRunner(nextBackgroundTasks) in
lib/intelligo.ts (app-scaffold 1.22.0 does). Call
purgeDeletedAccounts and pruneNotifications from the maintenance
route, as the reference app does. Enable charge.refunded and
`...

Read more

v1.1.2

Choose a tag to compare

@github-actions github-actions released this 07 Oct 04:04
cae0695

Added

  • definePlans and forPlans in @intelligo-dev/billing/plans make a
    catalogue's slugs a type: a plan's slug must equal its key, and a
    feature matrix or per-plan map that names a plan the catalogue lacks
    (chat: ["free", "por"]) fails to compile instead of denying the
    feature at runtime. The scaffold's lib/plans.ts uses them.

  • Each config seam declares where it runs (boundaries in the
    registry's requires.json): client when the browser bundles it,
    server otherwise, derived from the items' imports by an architecture
    test. intelligo doctor warns when a client seam imports server code
    (server-only, a server @intelligo-dev/* module, a Node built-in) or
    reads a non-public environment variable, and the config-seams page says
    which seams the browser bundles.

  • intelligo --version, intelligo <command> --help for one command's
    usage, and documented exit codes: 0 done, 1 a check found problems or
    the command failed, 2 the command was used wrongly (an unknown command
    or a missing argument now exits 2).

  • intelligo doctor asks the database when DATABASE_URL is set (and
    --offline is not): whether the framework's and the app's migrations
    are applied, whether pgvector is available, and whether the billing
    row's currency is the one lib/billing-config.ts formats. It accepts
    AUTH_SECRET as the app does (with a note to rename it), warns about a
    Resend key without EMAIL_FROM and, in production, a non-https URL or a
    test Stripe key. Its migrations line now says what it checks: the
    framework chain's integrity, not the database.

  • --json on doctor, upgrade --check and sync --check, for CI.

  • intelligo upgrade --diff <path> shows how the app's copy differs from
    the current template, and upgrade --accept <path> keeps the app's copy
    and stops reporting it as a conflict until the template changes again.

  • intelligo sync records each seam's shipped default, and sync --check
    reports seam-changed when a release changes it (the app's copy is still
    kept); sync --diff <path> shows the change. Files an earlier release
    shipped and none of the app's items do now are reported orphaned.

  • intelligo remove <item> deletes the files only that item ships and
    forgets it, keeping its seams; it refuses an item another needs.

  • intelligo sync --force copies the files it replaces to
    .intelligo/backup/<time>/ first.

  • executionRefusalResponse(run) in @intelligo-dev/next/route: the chat
    route's answer to a refused execution for any route — 503
    MODEL_UNAVAILABLE or BILLING_NOT_CONFIGURED, 402 QUOTA_EXCEEDED.
    The scaffold's assistant route uses it with withWorkspace (template
    1.20.0).

  • assertEnv({ extra }) and validateEnv({ extra }) check a product's own
    variables beside the framework's; the thrown error names the missing
    variables, and validateEnv warns about a pair set by half (OAuth id
    without secret, a Stripe key without its webhook secret, a storage
    bucket without credentials).

  • LOG_LEVEL sets how much the server logs.

  • clearUpgradeMessages and clearActionLabels, for tests.

Fixed

  • A conversation with an inline image no longer sends the image again
    with every later message. useChat sends the whole transcript each
    turn, so a 3 MB image added about 4 MB of base64 to every request
    after it, past a serverless body limit for the rest of the chat. The
    chat item's transport uses sendWithoutEarlierFiles from
    @intelligo-dev/chat/client, which replaces earlier messages' inline
    bytes with a placeholder, and the handler puts the stored file back
    (or drops the part when that message was never stored).

  • A conversation opens on its latest 100 messages, with "Show earlier
    messages" for the rest (loadEarlierMessages), instead of reading its
    whole transcript on every load. An approval continuation reads the one
    message it checks. @intelligo-dev/core/conversations adds
    getRecentMessages (a page, oldest first, with hasEarlier),
    getMessage and getMessagesByIds. A turn on a reopened long
    conversation shows the model what the thread holds, windowed as
    before; turn.history() still reads everything.

  • Registry items name a version range for every npm dependency. The
    build pins each one to the range the registry is developed and tested
    against (its own package.json), so an item installs the major it was
    written for rather than whatever is newest that day; @intelligo-dev/*
    stays unversioned, since intelligo create installed it and sync
    refuses another release's pages.

  • intelligo sync delivers reworded registry copy. Message files kept
    the app's value for every key, so a changed sentence or argument never
    arrived and nothing said so. A sync now records a short hash of each
    message it shipped (registry.messages in the manifest): a value the
    app never changed takes the new text, and a key the registry dropped
    goes unless the app reworded it. sync --check reports
    messages-changed for the app's own wording of a key whose registry
    text changed, and fails with messages-arguments when that wording
    uses an ICU argument the registry's text no longer passes. The first
    sync after upgrading records the hashes and changes nothing.

  • The scaffold registers per-plan chat request limits (RATE_LIMITS in
    lib/plans.ts, 10 a minute on free and 60 on pro). It registered
    none, so every plan got the conservative default of 10.

  • A key a new release adds arrives in English only, and an app whose
    default locale is not English threw on it until translated: the
    scaffold's i18n/request.ts falls back from the locale to the default
    locale to English (app-scaffold template 1.21.0).

  • The pricing and billing-settings pages read actionRoles from their
    config seams with in, so an app whose lib/plan-card-config.tsx or
    lib/credit-bundle-config.tsx predates the field — intelligo sync
    keeps seams as they are — compiles again. Since 1.1.0 it failed to
    type-check.

  • A chat turn holds what it can spend. Admission held one model call
    against a fixed 16K-token prompt, while a turn with tools may call the
    model once per step and a long conversation sends more than 16K; the
    shortfall was forgiven at settlement. executions.begin takes a
    workload (inputTokens, steps), estimateWorstCaseCharge scales by
    it, and the chat handler passes the prepared prompt's estimate and, for
    an agent with tools, maxSteps.

  • A chat turn that errors after its first steps is charged for them. The
    stream error released the hold, so every step the provider had already
    billed was free; the finished steps (and a step the provider had begun
    to answer) are now settled.

  • Tokens a tool spent on another model are recorded however low the
    balance has run: executions.begin({ alreadySpent: true }) skips
    admission for work that already happened, and the chat handler uses it
    for that usage, which a refusal used to drop.

  • A product's deriveTitle runs once the turn is admitted, so a refused
    turn no longer pays a model to name its conversation.

  • Two plan grants to one workspace at the same moment — two local
    invoices settled together — both count: grants take turns on a
    per-workspace lock, so the second adds its days to the first's end
    instead of both starting from the same one.

  • A job whose handler kills its worker every time stops being reclaimed
    once it has used its attempts, and is recorded failed. drain takes
    deadlineMs: jobs it claimed but had no time to start go back with the
    attempt unspent, reported as deferred.

  • An execution that receives usage after it was failed — abandoned by the
    stale sweep while it still ran — logs it and records an
    execution.usage_after_failure audit event instead of dropping it
    without a trace.

  • A local invoice its provider's callback names is asked about again
    even when it was recorded failed, and granted if it was paid after all
    (settleLocalInvoice({ recheckFailed })).

  • Uploaded files are deleted. Nothing called listOrphanAttachments, and
    a deleted workspace or user took its attachment rows with it and left
    the objects in the bucket. The database now queues an object's key
    whenever its row is deleted (storage_deletions), and
    sweepAttachments({ storage, olderThan }) from
    @intelligo-dev/core/attachments deletes uploads no conversation
    claimed, then the queued objects; a key leaves the queue only once
    storage has deleted it. The maintenance route runs it when a storage
    adapter is bound (maintenance template 1.3.0).

  • Looking up a request's usage by workspace and request id uses an
    index (usage_records_workspace_request_idx) instead of scanning the
    workspace's records.

Security

  • The platform-admin role keeps only what the console uses of
    Better-Auth's admin plugin — finding users and impersonating one — and
    /admin/impersonate-user is closed over HTTP
    (SERVICE_ONLY_ADMIN_PATHS): setting roles, passwords and emails,
    banning, deleting and raw impersonation went around the reason and the
    audit event.
  • An impersonation's reason is recorded on its admin.impersonation.started
    event, and one that the session then refused leaves an
    admin.impersonation.refused event instead of a start that never
    happened (requireAdminOrRefuse takes metadata).
  • A promotion from PLATFORM_ADMIN_EMAILS is audited
    (admin.platform_admin.granted, via the allowlist), and
    intelligo admin revoke <email> takes the role away, ends the user's
    sessions and audits it, warning when the allowlist would promote the
    address again. requirePlatformAdmin returns promoted.
  • @intelligo-dev/admin's cross-tenant read models check that a platform
    admin is asking, so a page that forgot requireAdmin refuses instead of
    listing every tenant. Calling them outside a request (a script) reads the
    tables...
Read more

v1.1.1

Choose a tag to compare

@github-actions github-actions released this 07 Oct 00:46
0722c21

Fixed

  • The logger writes an Error passed in its data as its type, message,
    stack, code and cause chain. It wrote {}, so a logged failure such
    as the scaffold's seeding error carried no detail.
  • settlePendingLocalInvoices picks its invoices at random rather than
    oldest first, so an invoice that fails to settle on every run (an
    amount the provider disputes, a grant that throws) no longer holds back
    every invoice behind it, and starts no settle after deadlineMs
    (default 45 s), reporting the rest as deferred.
  • The payment-poll item's callback route answers { ok } only. It
    returned the settle summary, with each failure's message, to an
    unauthenticated caller.
  • The scaffold's assistant route answered every request with 429: its
    stand-in model example/echo-1 had no registered price, so admission
    refused it as unknown_model. The scaffold registers the stand-in at
    no cost, and the route answers a refusal only the deployment can fix
    with 503 and one the workspace can fix by paying with 402, and lets a
    failure other than a refused guard through instead of answering 401.
  • The stub chat model refuses to reply in a production build, so a
    deployment that never bound a real model in lib/chat-model.ts fails
    loudly instead of billing its users for an echo.
    INTELLIGO_ALLOW_STUB_MODEL=1, or allowInProduction in code, lets a
    deployment meant to run on it do so.
  • Stripe amounts for ISK, UGX and MNT. Stripe takes these in hundredths
    although none are in use, and they were sent as whole units — a charge
    at a hundredth of its price, or refused under Stripe's minimum. Credit
    checkout now converts through the new toStripeMinor, and amounts read
    back from Stripe (the payment-failed email, the admin revenue totals)
    through fromStripeMinor, both in @intelligo-dev/core/money. toMinor
    keeps the whole units local payment rails take.
  • A Stripe subscription that ended stays ended. A payment failure that
    arrives after customer.subscription.deleted no longer marks it
    past_due (which kept the paid plan), and the deletion drops the row's
    Stripe id. A plan granted to a workspace whose Stripe subscription
    ended — a local payment, grantPlan — now gets its period and lapses,
    instead of being taken for one Stripe still bills.
  • Quota admission no longer needs a second database connection inside its
    transaction. A billing settings cache miss read the settings through the
    shared pool while the transaction held its connection, so a pool full of
    admissions waited on each other forever. The settings are read first.
  • The database pool waits at most 15 seconds for a connection, so an
    exhausted pool fails requests instead of hanging the process, and logs
    an idle connection the server dropped instead of letting the unhandled
    error end the process. DATABASE_POOL_MAX sizes it (default 10).
  • A chat turn stopped mid-reply is charged for the step that was running.
    The finished steps were the only usage settled, so a reply stopped
    before its first step finished — every one-step turn — settled at
    zero while the provider billed it. The step in flight is now estimated
    from its prompt and what it had streamed.

Security

  • Better-Auth's organization endpoints that the team and workspace
    services wrap (create, update, delete, invite, accept, reject, cancel,
    remove, update role, leave) answer 404 over HTTP. Called directly they
    skipped the plan's member and workspace limits and the
    beforeDeleteWorkspace hook that cancels the subscription. The
    services, and set-active from the workspace switcher, are unaffected.
    A product that called these through authClient.organization calls the
    services instead.
  • A password reset ends every session that was open before it
    (revokeSessionsOnPasswordReset).
  • AUTH_IP_HEADERS and AUTH_TRUSTED_PROXIES tell the auth rate limiter
    where the client address is: without them, an app behind more than one
    proxy resolved no address and put every client in one bucket.
  • The scaffold's next.config.mjs sends frame-ancestors 'none',
    X-Frame-Options, X-Content-Type-Options, Referrer-Policy and
    Strict-Transport-Security on every response. An existing app adds the
    headers() block to its own config (intelligo upgrade --check shows
    the template changed).

Changed

  • A workspace that is its owner's only one cannot be deleted, and no one
    can leave their only workspace (last_workspace from the workspace and
    team services, with messages in workspace-settings and
    team-settings). With none left, the next page created a new personal
    workspace, and with it a new start for whatever the product grants one.

Upgrading

Run intelligo sync team-settings workspace-settings app-shell payment-poll chat for the new error messages, the callback route and the seam notes. Copy
the headers() block from the scaffold's next.config.mjs into your own.
A production deployment that runs on the stub chat model sets
INTELLIGO_ALLOW_STUB_MODEL=1; one behind more than one proxy sets
AUTH_IP_HEADERS / AUTH_TRUSTED_PROXIES. Code that called Better-Auth's
organization endpoints from the browser (authClient.organization.*,
other than setActive) calls the team and workspace services instead.

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 16:04
e60e48c

Added

  • actionRoles on the pricing item's lib/plan-card-config.tsx and the
    billing-settings item's lib/credit-bundle-config.tsx: the workspace
    roles shown a plan's or a bundle's other ways to pay (default
    ["owner"]). Bind it to paymentPollConfig.payerRoles so the pages
    offer the QR payment to the roles its server action accepts.
  • PaymentProvider.callbackResponse({ settled }): the answer a provider
    expects to its callback. The payment-poll item's callback route returns
    it when the provider has one, and its JSON summary otherwise.

Changed

  • PricingContent, PlanCard and CreditBundles take the caller's role
    instead of a canCheckout flag. Card checkout stays owner-only; an
    admin or member sees the bundles on billing settings when
    actionRoles includes their role.
  • A local invoice is recorded before its provider is asked. openLocalInvoice
    writes the payments row as opening, hands its id to
    createPayment as the new paymentId parameter, and fills in the
    provider's invoice_id and expires_at from the answer; a provider that
    refuses leaves the row failed. A provider can use paymentId as its
    merchant-side invoice number or in its callback URL, and
    invoiceIdFromCallback may return either id.
  • An invoice's expiry is kept and acted on. settleLocalInvoice cancels an
    invoice the provider still reports unpaid LOCAL_INVOICE_EXPIRY_GRACE_MS
    (15 minutes) after its expiresAt and marks it failed, and
    settlePendingLocalInvoices keeps settling an invoice with a recorded
    expiry until then rather than only for a day after it was opened.
  • A local invoice keeps what it was sold for. openLocalInvoice takes the
    offer's grant and stores it in the new payments.grant_terms, and
    settleLocalInvoice applies that grant rather than asking fulfil,
    which now decides only for an invoice opened without one. An offer
    changed or removed after the invoice was opened no longer changes or
    blocks what a paid invoice grants. The payment-poll item's
    startLocalPayment passes the grant.
  • Payment.invoiceId (the payments row type) is string | null: a row
    is opening, with no invoice id yet, while its provider is asked. Code
    that reads payments directly checks for it.
  • Migrations 0005_local_invoice_expiry (payments.invoice_id nullable,
    payments.expires_at added) and 0006_local_invoice_grant
    (payments.grant_terms added). Nothing is renamed or removed, so
    intelligo migrate can run ahead of the deploy.

Upgrading

Run intelligo migrate, then intelligo sync pricing billing-settings payment-poll to take the new pages and route; bind actionRoles in
lib/plan-card-config.tsx and lib/credit-bundle-config.tsx if a role
other than the owner pays locally.

v1.0.1

Choose a tag to compare

@github-actions github-actions released this 06 Oct 14:55
58e570a

Fixed

  • The auth-login item's returnPath validates the post-sign-in
    destination more strictly and returns the path resolved against the
    site. Re-sync auth-login.
  • In the chat's inline attachment mode a file part must be a data:
    URL; any other URL is refused as attachmentRejected. stored mode
    is unchanged.

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 27 Sep 14:35
99560de

Added

  • intelligo admin grant <email>: makes a signed-up user a platform admin
    by writing users.role, and records an admin.platform_admin.granted
    audit event in the same transaction. With NODE_ENV=production it
    refuses unless --force is passed. PLATFORM_ADMIN_EMAILS counts only
    a verified address, which a development setup without an email provider
    never has.
  • A granted plan can end. grantPlan({ …, endsAt }) or { …, days }
    records the grant's period (days counts from the end of a running
    grant of the same plan, so renewals stack), and a local payment's plan
    grant takes days too: { plan: slug, days: 30 }. Without either, a
    grant has no end, as before, and clears an end an earlier grant left.
    GrantPlanResult carries endsAt. On a workspace Stripe bills, the
    plan moves and the period stays Stripe's.
  • processExpiredPlanGrants() in @intelligo-dev/billing returns every
    lapsed grant to the free plan, audited as billing.plan_grant.expired,
    and the maintenance template (1.2.0) runs it after trial expiry.
    A one-time QR payment therefore no longer grants its plan forever.
  • Local invoices settle without the buyer's tab. settlePendingLocalInvoices
    in @intelligo-dev/billing settles every unfulfilled invoice opened in
    the last day, or the one a provider's callback names, each against the
    workspace that recorded it and by asking the provider — a callback's
    body is never taken as payment. PaymentProvider gains an optional
    invoiceIdFromCallback(request); the mock reads ?invoice=. The
    payment-poll item ships app/api/payments/local/settle/route.ts
    (schedule it with CRON_SECRET, beside maintenance) and
    app/api/webhooks/local-payment/route.ts (the provider's callback URL),
    both granting through the new lib/local-payment-grant.ts, which the
    poll action now uses too.
  • withCronSecret(handler) in @intelligo-dev/next/route: 401 without
    Authorization: Bearer $CRON_SECRET, 403 to everyone while the secret
    is unset or shorter than 32 characters.
  • @intelligo-dev/core/storage/s3: a StorageAdapter for any
    S3-compatible bucket — AWS S3, Cloudflare R2, MinIO. createS3Storage
    takes the bucket, region, keys and an optional endpoint and
    pathStyle, and signs with Signature Version 4 over fetch and Web
    Crypto, so it adds no dependency; s3StorageFromEnv() builds
    one from STORAGE_BUCKET, STORAGE_ACCESS_KEY_ID,
    STORAGE_SECRET_ACCESS_KEY, STORAGE_REGION and STORAGE_ENDPOINT, or
    returns null without a bucket. The storage port's example no longer
    names an adapter that did not exist.

Changed

  • The scaffold's i18n/request.ts lays a locale's messages over the
    default locale's: a namespace or key a locale has not translated yet
    renders in the default language instead of throwing, so a locale can
    be translated a namespace at a time. intelligo sync --check still
    reports what is behind. app-scaffold 1.16.0.
  • intelligo migrate --check also checks the app's own chain: the
    migrations drizzle-kit generate wrote to ./drizzle against what
    drizzle-kit migrate recorded in drizzle.__app_migrations. A pending
    or unknown app migration exits 1, so the scaffold's db:check deploy
    gate no longer passes with the app's schema behind. --json carries it
    as app (null when the app owns no chain); state still describes
    the framework's chain and exitCode covers both.
  • Outside production, the console email provider logs the links a message
    carries (verificationUrl, resetUrl, …) beside its recipient and
    subject, so an address can be verified and a password reset without an
    email provider.

Fixed

  • @intelligo-dev/core's db maps a column declared without a name to
    snake_case, as the scaffold's drizzle.config.ts does: a consumer table
    written workspaceId: text() is queried as workspace_id, the column
    drizzle-kit generated. The framework's own columns are all named, so
    their SQL is unchanged.
  • The chat item's lib/chat-server-config.ts shows Mastra's
    handleChatStream with version: "v7", the stream AI SDK 7 reads.
  • The usage item's chart renders the same scale on server and client.
    UsagePage formats the axis labels in compact notation and passes them
    down (UsageChart takes max and scaleLabels), as the trial banner
    does: Node's and a browser's ICU spell compact numbers differently for
    many locales, which React reported as a hydration mismatch. An
    architecture test now refuses compact notation in any client component
    an item ships.
  • intelligo create inside a pnpm workspace no longer gives the app a
    package name another package has: create apps/app --name Acme in a
    workspace whose root is acme names the app @acme/app (the root's
    scope or name, then the directory). The page title and billing product
    still come from --name. The package name is its own template variable,
    __PACKAGE_NAME__ (app-scaffold 1.17.0); an app recorded before it
    reads as named __APP_NAME__, so its package.json stays current.
  • intelligo doctor warns when the app's package name is also another
    workspace package's — pnpm --filter and workspace:* resolve only one.