Skip to content

Releases: KhaytApp/khayt-mac

Khayt for macOS 4.0.0-alpha.9

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 14 Sep 08:56

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Changed

  • The Mac signs in to the cloud itself. settings.cloud.token is a session
    token the server issues at login, sealed against the Keychain of the machine
    that asked for it — so a shop's book carried to a new Mac arrives with a token
    nothing on that Mac can read, every cloud feature goes quiet, and the only
    cure was to open the other app. Book → Sign in to the cloud asks for the
    server, the account, its password and the sync passphrase, and does the rest
    here.

    The passphrase is checked before anything is written: a token saved beside
    a key that does not open leaves a shop connected and unable to read a word of
    its own cloud, which reads as the server having lost it. The new token is
    sealed the way the other app seals it, and settings.cloud is written in the
    same shape, so both apps read each other's sign-in.

    Everything after the token already worked — pulling, unlocking, comparing,
    pushing. This was one missing call, and it was the difference between a Mac
    that keeps a shop's book and one that needs another app to stay reachable.

  • The Mac refreshes the customer's tracking link, so a published job can be
    moved here at all.
    A job published to the portal could not be moved on the
    Mac: the app refuses a move it cannot carry out whole, and the refresh — a
    cloud write — was one it could not make. So a shop that had published
    anything could not run its board on this app, which is the one thing the
    board is for. The link is refreshed from here now, through the same rule the
    other app uses (lib/portal-refresh.js): the same payload, the same guards,
    the same path. A refresh that fails says so rather than leaving a customer
    reading "Printing" about a job that was collected yesterday.

    That was the last entry on the list of things this app sends you elsewhere
    for, apart from SMTP mail.

  • A shop whose portal trial had lapsed was refused moves for a message
    nobody was going to get.
    The rule that decides where a move reaches never
    looked at the trial, while the code that actually publishes returns early
    when it has run out. So the two disagreed: one said the move reached the
    customer's link, the other would have sent nothing — and on the Mac that
    disagreement is a move refused outright. Both halves ask one rule now. (No
    shop is affected today: while the beta is free every trial is active.)

  • The Mac can email the customer, so it stops refusing the move. A job
    whose next stage tells the customer by email could not be moved on the Mac at
    all: the app refuses a move it cannot carry out whole — rightly, because a
    half-made move leaves somebody untold while the book says otherwise — and it
    had no way to send one. It sends through SendGrid and Mailgun now, and
    the message is not a second app's idea of one: the subject, the body and the
    decision to send at all are the rule lib/order-email.js, which the other
    app now asks as well. The key is opened where it is used and never held.

    A shop on its own mail server is still sent to the other app, and that is
    written down rather than discovered: custom is SMTP — a socket, EHLO,
    STARTTLS, a dialogue — and a second implementation of a protocol is how two
    apps come to disagree about whether a customer was told. The refusal names
    it now ("an email through your own mail server (SMTP)") instead of saying
    email is missing, because those are different things to a shop deciding what
    to change.

Fixed

  • No email has left Khayt since 31 August, and nothing said so. Three
    functions — the status notification to a customer, Email on an order or
    quote, and the printer-alert digest — each open with
    const shopName = shopName() || 'Khayt';. shopName is also a global
    function, so the const shadows it and the line reads the binding before it
    exists: ReferenceError, thrown before anything is addressed, every time
    since it appeared in #822. Nobody awaited those calls, so each became an
    unhandled rejection — no toast, no error, no email. A shop that finished a
    job watched it move and had no reason to think the customer had not been
    told. The local is renamed in all three; a test now fails on any const or
    let in renderer/ that shadows the function it calls.

  • An unconfigured mail provider built and addressed an email nobody could
    send.
    With emailConfig.provider set to the empty string — never
    configured, or cleared — the renderer refused only the literal 'none', so
    it assembled the whole message and handed it to a transport that matches no
    provider, which returned a mailto: fallback the caller ignores. Meanwhile
    outboundFor, which decides whether a move reaches outside the shop, said
    the opposite. Both halves now ask one rule, and the answer is the true one:
    nothing is delivered, so nothing is built.

Khayt for macOS 4.0.0-alpha.8

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 13 Sep 20:12

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Changed

  • Take a job from something you already make. A product in the catalogue now
    has New Job from This: its parts, its components, its margin and its name,
    filled in — and then it is an ordinary job sheet, because a customer who wants
    two in a different colour is still ordering the product.

    The job names the product, which is what the catalogue counts to say a
    thing has been made 14 times and earned 6,300. A job typed out by hand that
    happens to match is not counted, and nothing on that screen says so.

    Its components come with it — the magnets, the screws, the box. A job
    without them is under-priced by exactly their cost, every time it is sold.

  • Pricing tiers can be added on the Mac, and picked where they are used.
    A product can carry named margins — Retail 45%, Wholesale 20% — and they are
    offered as chips beside the margin on the job sheet. A margin and not a price,
    so a tier stays right when filament gets dearer.

  • Documents can be attached to a product here. Assembly instructions, a
    safety sheet, a drawing. A copy is taken, so your own file can be moved or
    renamed afterwards. Each one says whether it goes in the customer's box or
    stays on the floor's copy — and they are listed on the job, which is where
    somebody stands when they are about to make the thing.

  • Ask what to charge, beside the figure you already have. The job sheet
    already shows what you usually make on work like this. Ask what to charge
    now sends those comparables — and only those — to be weighed, so an outlier
    or a thin sample can be argued about in a sentence rather than averaged away.

    The reason is always shown. A margin that changed with no sentence beside
    it is a number you cannot argue with when a customer does.

    If the answer is unusable, your own median is what comes back — it was worked
    out on your Mac before anything was sent, so a refusal is not a failure.

  • Finishing a job on the Mac now tells the systems you have connected. A
    shop with webhooks configured could not move a job on the Mac at all: the app
    refused the move rather than make it with a piece missing. It sends them now,
    so that refusal is gone — and both webhook systems are covered, the
    subscription list and the single order webhook, because a shop can have both
    and Khayt sends to both.

    The message goes out after the job is saved and only if it was, and a
    delivery that fails is said out loud rather than swallowed — the whole point
    of refusing these moves before was that a piece of the move would silently not
    happen.

  • (Maintainers) The webhook payload and its envelope are shared rules now.
    Two apps sign the same bytes, so the field names, their ORDER, and the
    { event, payload, timestamp } envelope main.js has posted since webhooks
    shipped are all in lib/webhook-bus.js and used from both sides. A literal in
    one app would have meant deliveries that verify from Khayt and fail from the
    Mac, which is the kind of drift a shop only discovers through a consumer that
    stopped trusting it.

    The signature is the bare hex, not sha256=<hex>. main.js has two webhook
    transports that disagree about this, and the bare one is what every delivery
    actually goes through — so it is the spelling consumers verify.

  • (Maintainers) The Mac can send a webhook, with both layers of the guard.
    The transport, the HMAC signature and the retry policy.

    The URL is typed by the shop, so the guard is the feature. Two layers, and
    neither is enough alone: the name is checked against the shared ranges —
    loopback, RFC1918, link-local, cloud metadata, and the spellings that hide
    them ([::1], ::ffff:127.0.0.1 in both forms, 2130706433) — and then the
    host is resolved and every answer is put through the same rule, because a
    perfectly public name can have an A record pointing at 10.0.0.1. Redirects
    are not followed: a consumer answering 302 to a metadata endpoint would walk
    straight past both.

  • (Maintainers) The host ranges are a shared module now. They were the top
    of lib/host-guard.js, which cannot be shared — it requires Node's dns for
    its second layer. lib/host-ranges.js holds the pure range checks and
    host-guard re-exports them, so there is exactly one copy of rules that are
    almost entirely made of holes somebody already found. Its 19 existing tests
    pass unchanged through the re-export.

  • The Mac can draft a message to a customer. On a job with a customer on it:
    pick what the message is about — a status update, ready for pickup, a quote
    follow-up, a payment reminder, an apology for a delay, or your own note — and
    it writes one.

    It drafts. It does not send. The message comes back in a box you can edit,
    with Copy under it, and you send it through whatever you actually use. A
    message written about somebody's order, in your shop's name, is not something
    to put on the wire before a person has read it.

    This is the one feature that sends another person's data, and what travels is
    exactly what the settings screen says: the customer's name, the order
    reference, project, status and due date, and the amount and outstanding
    balance. Their email address, phone number and address are on the same record
    and are not passed — which is a test, because handing the whole record
    over is the obvious way to write this and the disclosure would quietly stop
    being true.

  • You can ask the Mac about your own book. "How did this month compare with
    last?"
    , "How much is still owed to me?" — in the Book menu, when you have
    switched the assistant on.

    It is given a summary, not your book, and the screen says so before you
    ask anything: totals, counts and what is outstanding. No customer name, email,
    phone number, order reference or project title is in what leaves your Mac —
    and that is a test, not a promise, because it is exactly the sentence that
    would quietly stop being true when the summary gains a field.

    The suggested questions are the ones the summary can actually answer. A blank
    box with a cursor in it is a test a shop can fail.

  • A product made from an unsliced model now has a weight, a time and a
    price.
    Most of a shop's library is models nothing has sliced yet, and those
    files record no weight and no time — so the product arrived with neither,
    which meant no cost and therefore no price at all.

    Khayt measures the mesh and prices it at the rate your own finished jobs
    actually ran at. Where the file cannot answer, the geometry does.

    It says the figures are estimates, and says it two different ways: one
    sentence when the rate came from your own measured jobs and names how many,
    another when there are none yet and it is an assumption. An estimate that
    looks typed is the same mistake as a zero that looks typed.

  • Comparable margins are net of tax — which changes a figure Khayt has been
    showing.
    AI price assist recommends a margin from what a shop has actually
    realized, and it computed those margins against the gross price. For an
    inclusive-VAT shop — Saudi, the Gulf, most of Europe — part of every price was
    the tax authority's and was never revenue, so every comparable overstated.

    A Riyadh shop at 15% was shown a median of 56.5% where it had made 50.0%,
    and pricing to the number it was shown leaves it thinner than it thinks by
    exactly that much. An unregistered shop's figures do not move: its price is
    its revenue.

    (This shipped in the previous release under a product-pricing change, which
    did not describe it. It moves a number a shop may have priced against, so it
    is written down here.)

  • The Mac shows what you usually make, before you pick a margin. On the new
    job sheet: "You usually make 34% on PETG — median of 6 finished jobs.",
    with one click to use it.

    No AI is involved and none is needed. It is arithmetic over your own
    finished jobs, so it works with the assistant switched off, with no key, and
    with nothing sent anywhere. Net of tax, for the reason above.

  • (Maintainers) What still needs the other app is a test, not a claim.
    NeedsTheOtherAppTests holds the list, and it is closed: a screen that sends
    a shop to Khayt without a declared entry fails the suite, an entry for
    something already working fails it too, and the count is a ratchet. Three
    times this session a screen was found telling a shop to go elsewhere for
    something the Mac had done for weeks — each true when written.

  • A product made from a model recorded its quantity in a field nothing
    reads.
    Make a product from this wrote quantity where every consumer
    reads qty — the calculator's per-part cost, the packaging split, the price
    tiers, and the specs a catalogue row shows. So the real field was absent and a
    junk one sat beside it.

    Benign only by accident: the arithmetic falls back to one where qty is
    missing, and the value written was always one. It would have stopped being
    benign the moment anything wrote a different number. Found in a real shop's
    book. The test that covered this path asserted quantity — it agreed with the
    code rather than with the rule, which is why nothing caught it.

  • A product added on the Mac now has a price. It did not. The sheet could
    not hold the product's parts, and a product's price is made entirely of
    them — so one written down here saved at 0.00 with no hours and no grams, and
    had to be finished in the other app before it could be sold.

    Parts are on the sheet now: name, spool, grams, hours, quantity. The cost, the
    price and the totals appear as you build it, so a margin typed above is no
    longer a number chosen blind. A part with no spool chosen says that it costs
    nothing and that savin...

Read more

Khayt for macOS 4.0.0-alpha.7

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 13 Sep 07:49

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Added

  • The assistant has a screen of its own. Khayt's AI features could be
    switched on in the other app and not this one, so a shop on a Mac could be
    told a feature was running and have no way to see — let alone refuse — what
    it sends. Settings → AI assist now carries both halves together: which
    provider you use, and a switch per feature with what each one transmits
    written beside it.

    The two halves ship together deliberately. A provider chooser on its own
    would let you point Khayt at a vendor without being told that drafting a
    customer reply sends their name, their order reference and their outstanding
    balance. A list of switches on its own would name a vendor you had not
    chosen. The one that sends a customer's data is badged as such, and nothing
    on the screen works consent out for itself — it asks the same rule the gate
    asks, so a feature can never read as off while it runs.

    Your key is sealed with the book's own key before it is written, the same way
    a printer's key is, because this file syncs, is backed up and is exported. A
    key that cannot be sealed is refused rather than stored in the clear.

  • A model in your library can become a product. The library knew what
    each model weighs and how long it takes — parsed when you imported it — and
    the catalogue asked you to type both in again. Make a product from this is
    on the Model menu and on a model's right-click menu, and the product arrives
    with its first part already filled: weight and time from what the slicer
    measured, material and layer height from the setup you have had most success
    with.

    It is joined to the model, not just named after it. A part used to carry
    the file's NAME — a filename somebody typed — so nothing else could follow
    it. It carries the model's identity now, which is what makes "for this part,
    at these settings, how far out is my estimate?" answerable later.

    What the file cannot answer for is named on screen rather than left at zero,
    because a zero that looks typed is worse than a blank you were told about.

  • Khayt can show a camera that only speaks RTSP — which includes the Buddy3D
    that sits beside a Prusa CORE One. Give the machine the camera's address as
    rtsp://… and set its type to RTSP; Khayt opens the stream, takes one frame,
    and hangs up, the same way it takes a still from any other camera. The
    camera has to be publishing locally first
    : switch on "RTSP stream on local
    network" in the Prusa app, or the camera answers "no stream" and the tile says
    it is waiting. Mac only for now — the Windows and Linux app has no decoder.

  • A printer that changed address can be found again. A DHCP lease
    expires overnight, the router hands out a different address, and Khayt polls
    a host that answers nothing. It said offline — which is also what it says
    when a printer is switched off, and the two have completely different fixes.

    A machine that has gone quiet now offers Find it on the network. Where the
    printer announces the serial or the hardware address Khayt recorded — neither
    of which moves with a lease — that is identity, and one click points Khayt at
    it. Where the evidence is only that exactly one printer of the right model is
    answering, it says so and asks you to check first, because pointing the app
    at a machine is what it will later send commands through.

    What this was costing. Khayt freezes a job's real filament and duration
    on the edge out of printing, because the printer's counters reset when the
    next job starts. Every print that finished while the address was stale is a
    measurement that no longer exists — found exactly that way when a Snapmaker
    U1 moved from .77 to .56 and the completion history came back empty rather
    than short.

  • What a model would take, before anybody slices it. Khayt could
    measure a mesh from the day it could read one and could never price one — a
    model you had not printed showed a size and a triangle count and no answer to
    the question you actually had. The library inspector now says what it would
    take in filament and in hours.

    It does not ask how fast your printers are, because nobody knows that about
    their own printer.
    The estimator's hardest number had been the same guess
    for everyone since it was written. It turns out not to need guessing: it only
    ever appears multiplied by density, and that product is grams per hour —
    which every job whose real weight and duration were recorded has measured.
    So Khayt learns it from your own work, says how many jobs it learned from,
    and says plainly when it is still using its own default instead.

    It will not learn from a job nobody measured, from one job, or from a figure
    divided across several parts — calibrating an estimator against its own
    estimates teaches it nothing.

    Settings → Preferences carries the four numbers you can answer for: density,
    infill, wall thickness and waste. There is deliberately no field for the
    speed.

  • The Mac app can group several prints that are one object. A figure
    printed as a head, two hands and a body on four evenings is four jobs in the
    book, and "what did that figure cost me" was arithmetic across four rows that
    nobody does. The Electron app has grouped them since its Orders Log learnt to;
    the Mac could not. A kit now sits above the jobs table with its own totals,
    clicking one narrows the book to the jobs that made it, and the selected job
    says which kit it belongs to and what the whole object came to.

    Grouped ACROSS orders rather than merged into one, and that is not tidiness:
    what a print really took is recorded on the ORDER and nowhere else, so folding
    four jobs into one would replace four measured numbers with one — and those
    four are exactly what the estimator learns its rate from.

    Every total says how many jobs are behind it. Adding up what four prints
    took, when one of them was never measured, gives a figure that looks like the
    answer and is the answer for three. So a kit that is not fully measured says
    "3 of 4 measured" in amber, and offers no percentage against the estimate at
    all — an estimate covering four jobs and an actual covering three do not
    divide into anything true.

    Naming is a pick rather than a retype: a name a kit already has IS that kit,
    whatever the capitals, and a name one edit away from an existing one is
    questioned before it becomes a second kit with the takings split between them.
    A kit whose name was deleted keeps its jobs and can be named again.

  • A product can have more than one picture on the Mac, and each says what it
    is.
    The catalogue held one: a shop selling a printed part chose between a
    render, a photo of the real thing, a scale shot and a detail of the finish.
    The product sheet now carries a strip — add several at once, drag the order
    that matters, and label each one.

    The label is the point rather than the count. A customer looking at a listing
    is asking a question the pictures rarely answer — is that a render, or is
    that what arrives?
    — and guessing wrong is a refund. The first picture is the
    one the catalogue, the storefront and the invoice use, which the sheet now
    says in words instead of leaving it to be inferred from a row of thumbnails.

    Nothing touches the pictures folder until Save. A picture picked and then
    cancelled leaves no file behind, and one removed and then cancelled is still
    there.

  • The Mac can connect a storefront. Khayt's cloud serves an import route per
    platform — paste it into Salla, Zid, Shopify or WooCommerce as an order
    webhook and new orders arrive in Order requests — and a feed route that
    publishes the catalogue back. Both links were built and shown only by the
    Electron settings page, so a shop keeping its book on the Mac had the cloud,
    had the shop id, and no way to find out what to paste. There is an
    Integrations pane now, with the storefronts and payment systems for its
    market, and a market picker for a shop that sells into more than one.

    Medusa gets the code as well as the link. It is a self-hosted framework with
    no webhook settings to paste a URL into, so Khayt hands over the subscriber
    file to save in the shop's own project — the link on its own would be a URL
    with nowhere to put it.

    Switching a payment system on in one market cannot switch another market's
    off. The directory shows one market at a time, and a shop selling into two has
    providers configured outside the list on screen; the save merges rather than
    replaces, so the first the shop would have heard of it is an invoice that
    stopped offering a way to pay.

Changed

  • The Mac app wears the new icon's colours. Khayt's accent was the cyan of
    the icon before last, and the app had been sitting beside its own orange-on-
    navy mark looking like a different product. It is now the mark's navy, at the
    lightness a label can actually be read at — 5.60:1 on the lightest surface it
    draws in light appearance, 5.26:1 in dark, measured against the real card and
    ground colours rather than against white.

    The accent is the navy and not the orange, and that is the finding. The
    obvious move on a re-brand is to take the mark's loudest colour. Measured, the
    filament in the new icon is hue 23° and Khayt's "something is being made right
    now" was already hue 19° — four degrees. The new icon did not bring an orange
    to the app; it agreed with the one already in it. Spending that hue on
    selection, links and section rails would have cost the app the one colour that
    means printing, on a dashboard that draws exactly that distinction on a
    single control. So the accent is the mark's other colour, and both halves of
    the icon are now on every screen.

    The informational colour moved with i...

Read more

Khayt for macOS 4.0.0-alpha.6

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 12 Sep 17:03

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Fixed

  • Khayt no longer quits when you Quick Look a second model. Going through
    the library pressing ⌘Y, the app disappeared on the second one — with no
    error, no crash report and nothing to look at afterwards.

    The preview panel's binding was never cleared when a panel was dismissed, so
    the second look handed it one file where another already sat. Every look is a
    fresh one now, and both ways in — ⌘Y and the model's own menu — go through
    the same door, which is what stopped one of them being fixed and the other
    not.

Khayt for macOS 4.0.0-alpha.5

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 12 Sep 15:49

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Changed

  • Khayt has a new icon. A chrome nozzle extruding a single thick loop of
    orange filament in the shape of a khaa, on deep navy — one mark at every size,
    from the 1024px Dock icon down to the 16px favicon, instead of a detailed
    drawing that dissolved into a smudge when it got small. The mark is drawn once
    and all 72 shipped assets are derived from it, so the 32px and the 512px can
    no longer disagree.

    Three things this fixes on the way through. The marketing site's two favicons
    were declared 16 and 32 and were both actually 64. Its apple-touch-icon was
    256 with transparency, which iOS composites onto black. And the AppX badge was
    a colour downscale where Windows wants a monochrome glyph it can tint per
    theme.

  • (Maintainers) The Mac app has a macOS 26 layered icon. It shipped a flat
    legacy .icns, so it got none of Tahoe's Liquid Glass, dark or tinted icon
    treatment. Background and foreground are separate layers now.

    The UI accent has deliberately not moved with it. Every contrast ratio in
    mac/README.md was measured against the old cyan, so re-accenting is a
    measured pass rather than a substitution.

Added

  • Khayt can tell you what is likely to go wrong before you quote.
    Select a model and the inspector says what a slicer would find: how much of
    the surface overhangs past 45° and will need supports, how much is
    near-horizontal underside that sags rather than merely printing rough, and
    whether the walls average thinner than the nozzle can lay down.

    Every line carries the measurement it is based on, so you can disagree with
    it. A shop that supports everything by default can see at a glance which
    line to scroll past, and a part with nothing wrong says so — "nothing to
    flag on this one" is a different answer from not having looked.

    It works on the files you actually own. The other Khayt computes the same
    findings for a quote, but it has to build the whole triangle list to do it
    and gives up past four million facets. Two models in this library are past
    that. The Mac reads the mesh as a stream and keeps ninety-one numbers, so the
    size of the file stops being the question.

    Under Settings → Preferences you can choose when Khayt looks: when you
    ask
    , which is the default, or as each file is imported. Reading a mesh
    is a few seconds on a large model — paying that during an import answers
    instantly forever after, and leaving it until you ask keeps imports fast.
    Either way the answer is kept, so the same model is never read twice, and it
    is thrown away if the file behind it is replaced.

  • Adding a spool can be a lookup instead of typing. Start typing a
    brand or a product — "bambu matte", "esun petg" — and Khayt offers the
    filament and its colours from a bundled catalogue of 1,945 products, filling
    in the name, the colour, its hex and the spool weight.

    It fills in what a manufacturer can know and nothing else. Your cost, what the
    roll weighs today, when you opened it and whether you have dried it are facts
    about the spool in your hand, and nothing here invents them — and editing a
    half-used roll never overwrites what is on it.

    The list ships with the app, so it works with no connection and Khayt does not
    tell anybody what you buy. It says how old it is rather than pretending to be
    current. From the Open Filament Database, MIT-licensed — see
    THIRD-PARTY-NOTICES.md.

  • A job's parts can be corrected. They were read-only: a weight typed
    wrong when the job was taken stayed wrong, and the only way to fix it was to
    open the job in the other Khayt. Double-click a part to change its name,
    filament, weight, hours or quantity.

    The price is not a field you type. A part that weighs 40 g rather than
    30 g costs more to make, so the figures you know are asked for and the price
    follows from the same cost model the calculator uses. Correcting a weight
    corrects the job.

    Where the part came from a model in your library, Fill from file takes the
    weight and time the slicer measured. It shows you both figures first rather
    than overwriting quietly — a part may have been corrected on purpose — and it
    says which fields the file could not answer for instead of leaving zeros that
    look typed.

  • A print made of several files says so. A head, two arms and a torso
    are one thing you print, not four — but the Mac app showed a kit as a single
    entry with the rest of its files invisible. The model's panel now lists every
    file in the print, marks the one the card speaks for, and adds up what the
    whole thing weighs on disk.

    Where a file could not be measured it says so, and the total is left off
    rather than quietly adding up the parts it could measure and presenting that
    as the size of the print.

  • An invoice says whether it has actually been reported to ZATCA.
    Khayt already put the Phase 1 QR on the document. What the Mac app could not
    tell you was whether an invoice you had handed a customer had been reported to
    the tax authority at all — which is the part a Saudi shop can be penalised
    for, and it was invisible on this side. A completed invoice now says
    submitted, not submitted, rejected or errored, with the counter value and, if
    it was refused, the reason it was refused.

    It does not offer to submit. Signing the document needs code that only runs in
    the Electron app, and a button here that could not finish the job would be
    worse than a plain statement. Nothing appears at all on a shop that has not
    switched Phase 2 on, because none of this applies to it.

  • Khayt remembers what a print actually worked at. A file counted how
    many times it printed and how many times it failed, but not with what — so
    reprinting a bracket six months later you knew it had worked once and had no
    idea on which printer, in which material, at which layer height. The model's
    panel now lists the settings it has been printed at, marks the one to reach
    for, and says plainly when nothing has worked yet rather than naming the least
    broken option.

    One bad print does not condemn a setup: filament runs out, a spool tangles,
    somebody knocks the machine. Nine of ten is still a setup to reach for, and
    one of four is not, however recently that one worked. A setup nobody has run
    reads as untried rather than as a score of nought — and your own verdict
    overrides the tally, because "it printed, but I did not like the finish" is a
    judgement no counter can reach.

  • A print that exists at more than one size says so. Big and small
    carry their own weight and time, so the panel shows each with its own figures
    and marks the one the estimate is about. Files that have only ever been one
    thing — nearly all of them — are unchanged.

  • Khayt says what is about to run out that is not filament. Glue, IPA,
    mailing bags, spare nozzles — running out of one of those stops a job exactly
    the way running out of filament does, and only filament reached the Mac app's
    shelf. The inventory screen now leads with what needs ordering, in each item's
    own unit.

    Three different reasons put something on that list and they read differently:
    it has run out, it is below the minimum you set, or nothing is wrong yet and
    the rate you are getting through it says otherwise. The last is the one you
    cannot see by looking at the rack. Where Khayt has no usage figure and you
    have set no minimum, it says the item is low and stops there rather than
    inventing a quantity to put on a supplier's order.

  • Khayt tells you what each printer is due for. A machine card now
    lists the recurring jobs set against that printer — replace the nozzle, clean
    the plate, check the belts — with how far off each one is and a button to mark
    it done. Amber when it is close, red when it is past, and nothing at all on a
    printer nobody has set tasks up for.

    The hours are the hours Khayt has logged, counting finished prints only. A
    cancelled print used some of the machine's life in reality, but the log has no
    honest figure for how many, and counting the whole estimate would bring
    services forward on exactly the printers that fail most.

  • Khayt finds printers on your network. Adding a machine meant knowing
    its address and typing it — and a shop that has just plugged a printer in does
    not know it, so the number gets copied by hand off the printer's own screen
    across the room. Find printers on the machines screen asks the network
    instead, and adding one fills in its address, its connection type and — when
    Khayt recognises the model — its bed, nozzle and running cost.

    The scan is owner-initiated and time-boxed, never on a timer, and macOS asks
    your permission the first time. A printer Khayt can see but cannot yet speak
    to says so rather than being added as though it were ready.

  • (Maintainers) The mDNS codec runs on the Mac now. lib/mdns.js was built
    on Node's Buffer, which JavaScriptCore does not have — so the one piece of
    wire-format code both apps need could be loaded by only one of them, and
    finding a printer on the Mac would have meant a second implementation of DNS
    name compression. Two codecs is two chances to mis-read a packet arriving
    unauthenticated from the workshop network. It is Uint8Array throughout now;
    Buffer is a Uint8Array, so nothing in the Windows and Linux app changed.

  • Khayt can tell a printer what to do. The Mac app could watch seven
    protocols and touch none of them: it knew a print was failing, it knew which
    machine, and stopping it meant walking to the printer or opening the other
    app. Pause, resume and cancel are on the machine card now, while something is
    running. Cancelling asks first — it throws away every hour already in the
    pl...

Read more

Khayt for macOS 4.0.0-alpha.4

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 11 Sep 21:14

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Added

  • Khayt says what to run next. It knew the queue and it knew which printers
    were idle; putting the two together was a person doing it in their head. The
    machines screen now proposes a job for each free printer — urgent first, then
    due date, then longest waiting, and preferring the machine already loaded with
    the right material so there is one fewer spool change.

    It proposes; you press Send. No printer Khayt talks to can clear its own
    plate, so an idle printer is very often an idle printer with yesterday's part
    still on it. A machine is only offered once somebody has said its bed is clear
    since its last print — and a machine waiting on that says so, with the button
    to say it, rather than quietly disappearing from the list.

  • Help, in your own language. Sixteen articles — the book, jobs, the board,
    customers, the library, the catalogue, the shelf, machines, money, reports,
    cloud sync, backups, settings, the keyboard, and what to do when something is
    wrong — in English and Arabic, searchable, from the Help menu or ⌘?. It opens
    in a window of its own so you can read it beside the screen you are asking
    about, and it follows the language Khayt is set to rather than the Mac.

  • A product can be written down here. The catalogue could be read on this
    Mac and not added to. There is an editor now, with one tab per language your
    catalogue carries rather than a fixed English and Arabic. Everything the sheet
    does not show is left exactly as it was: parts, prices per quantity, photos
    and documents.

  • The catalogue can be looked at, not only read. A grid of photographs
    beside the existing table, which stays the default because it is the only view
    that puts margin next to weight.

  • Importing models is on the library, and keeps your folders. An Import
    models
    button, and you can drag files or whole folders straight onto the
    library. The folder a model came from becomes the group it is filed under
    a download of seven models in seven folders arrives as seven groups. Packaging
    folders are seen through: a model at Kings/King Abdulaziz/STL/presupported/
    is filed under King Abdulaziz.

Fixed

  • A printer was credited with colours it does not have. Adding a Prusa CORE
    One gave Khayt a machine it believed could print five colours. Five is what a
    CORE One reaches with an MMU3 bolted on; the one on your bench prints one. The
    same was true of every Bambu without an AMS, every MK4 without an MMU, a K2
    Plus without its CFS and a Kobra 3 without an ACE — and capacity, colour
    warnings and the converter all believed it.

    A machine is now added with the colours it prints as sold. Machines whose
    multi-material is built in — a Snapmaker U1's toolchanger, a J1's IDEX, the
    dual-extruder UltiMakers — are unchanged.

  • Four screens had a search box that did nothing. The calculator, the colour
    studio, the reports and the dashboard are not lists, and the field on them
    could be typed into to no effect — while saying "Job, customer or number". It
    is gone from those. The catalogue, which is a list, now searches by name,
    description, material and group.

Khayt for macOS 4.0.0-alpha.3

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 11 Sep 18:38

Khayt for macOS only. The Windows and Linux app is unaffected and is on its own
version — see VERSIONING.md.

Before you update

If you have 4.0.0-alpha.1 or 4.0.0-alpha.2, download this one by hand.
Those builds cannot launch, which means they cannot check for updates either —
Sparkle runs inside the app, and the app stopped before it started. Nothing will
arrive on its own. Drag the new Khayt into Applications over the old one.

Fixed

  • The Mac app could not launch on any Mac that had not built it. Both
    published alphas were signed, notarised, stapled — and dead on their first
    line:

    Fatal error: could not load resource bundle: from
    /Applications/Khayt.app/KhaytCore_KhaytCore.bundle or
    /Users/runner/work/Khayt/Khayt/mac/KhaytCore/.build/…
    

    Khayt's business rules are JavaScript the app loads from inside its own
    bundle, and it asked SwiftPM's Bundle.module where that was. That is not a
    search: it compiles down to two fixed paths — the app bundle's root, where
    nothing may be put because codesign seals only what is inside Contents/,
    and the absolute path of the build directory on the machine that compiled
    the app
    . On a developer's Mac that directory is right there, so every build
    made here ran perfectly, by reaching outside the app into it. On the release
    runner that path is /Users/runner/work/…, which exists on no shop's Mac.

    The app finds its own resources now, in Contents/Resources, where they have
    always been.

  • An invoice would have printed with no styling at all, and the sample book
    would not have opened — the same cause, one layer quieter. Neither crashes,
    so neither would have been reported as this: a shop would simply have sent a
    customer a document that looked like raw HTML.

Added

  • (Maintainers) Khayt --check-resources, and the release runs it. The
    reason this shipped twice is that nothing in the release ever asked the built
    app a question. Launching it would not have helped — CI is a build machine
    too, so a broken app starts there. The app is asked where it found each of
    its resources, and the answer has to be inside itself. Bundle.module is
    banned in this package's own sources, with a test that says so.

Khayt for macOS 4.0.0-alpha.18

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 16 Sep 19:45

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Added

  • (Mac) A listing can be taken off the catalogue. There was no way to
    delete a product here at all — the words for it had been sitting in the app
    unused. Right-click a product in the grid or the table and it asks, in
    Khayt's own sentence, which names what survives as well as what goes: the
    photo is removed, past invoices are kept. Deleting also unlinks every job
    that named the product and drops it from any quote bundle, because a job
    pointing at a product that is not there is the kind of fault that surfaces
    months later as a screen that cannot draw. All of it comes back with one
    undo, except the pictures, whose bytes are gone — the record is restored
    without them rather than naming files that no longer exist.
  • (Mac) Settings → Online can switch public pricing on, and make the
    printer preset it needs.
    The customer-facing price is built from a saved
    preset — a name and the seven figures a part is costed at — and the shared
    rule refuses outright without one. Until now a preset could only be made in
    the other app's calculator, so the Mac could serve the upload and never
    answer. The pane now carries the whole block (the switch, the preset, the
    material or a flat spool cost, margin, minimum, waste and the per-visitor
    hourly ceiling), says plainly when there is no preset yet, and will make
    one: name it, adjust the seven figures, and it is saved and chosen. A name
    already in use replaces that preset rather than doubling it, which is the
    other app's rule and the same id, so anything pointing at it still does.
  • (Mac) A customer can price their own model on the intake form. With
    public pricing switched on, the form offers an upload: the file is measured
    in memory, priced on the shop's own preset, spool cost, margin and waste
    allowance, and the figure is shown as an indication rather than a quote. A
    sliced file is taken at the slicer's own weight and time; an STL, OBJ or
    3MF is measured by this app's own reader. Nothing is written to disk — the
    model is read and dropped, so there is no stranger's file on the shop's
    machine to keep or explain. When the request is submitted, the price
    attached to it is the one THIS server produced, recalled by reference, so
    a browser cannot post a figure of its own. The rules are the shared ones
    (lib/public-quote.js, lib/gcode-parse.js), which the other app already
    quotes through, so a customer is never shown a different sum from the one
    the shop would reach for the same part.

Fixed

  • A delivered job was missing from what its printer had earned, in both
    apps.
    Khayt wrote delivered before it wrote completed with a
    deliveredAt beside it, and both are still in shops' books — thirteen of
    them in the sample. So "is this job finished" is a two-value test, written
    out by hand in eight modules and got wrong in three places: the machine
    P&L in both apps, and the machine revenue chart. Each filtered completed
    alone, so a shop that marks work delivered saw its printers' earnings
    computed on a subset, with nothing to say so. lib/order-status.js
    which already says in its own header that it exists so the two apps cannot
    disagree about whether a job is finished — now names the test once, and
    the three callers ask it. A test holds the Mac's copy of the list to the
    rule's own, and another checks the charts have not gone back to comparing
    by hand.
  • A multi-colour print weighed nothing, so anything made from it cost
    nothing.
    A one-material slice reports a single filament weight, and that
    is the only figure this read. A toolchanger does not produce one: a U1, an
    XL or an AMS slice writes a weight per filament, which the library keeps
    per colour. So every multi-colour file reported "no weight", and a product
    or job made from one came out costing nothing — a 57 g dragon read as zero.
    On the shop's own library, three of 152 files carried a weight and all
    three carried it this way, so the branch that was read had never once
    matched. The colours are summed now, and labelled as the slicer's own
    arithmetic rather than an estimate, because that is what it is. A file that
    genuinely knows no weight still says so.
  • Public pricing settings were dropped on the way to the book. The shared
    settings save merges the LAN block by naming the fields it knows, and the
    model-pricing block was not among them — so a pane that set a margin and a
    preset would have had both discarded on save, silently. It is merged whole
    now, over what was stored, so a field a newer build wrote survives a save
    by an older pane.
  • (Mac) A resin printer's progress was captioned with a claim about a file
    it does not have.
    The machine card names which signal a percentage came
    from, so that "by layer" and "by file position" can be told apart on a
    Moonraker printer. It was meant to say that only for Moonraker, which is
    the one adapter that chooses between two signals — but lib/sdcp.js sets
    the same field, to time or none, and anything the card did not
    recognise was captioned "by file position". So an Elegoo resin printer
    reporting its own elapsed ticks was described in terms of a file it never
    had. The adapter now decides whether to caption at all, and a signal this
    app has not been taught is left undescribed rather than described wrongly.
  • (Mac) A product made on the Mac was priced on its filament alone. The
    other app's calculator puts a labour rate, prep and post time, power draw,
    electricity, wear and a failure allowance on every part it writes; this
    sheet wrote none of them, and the shared pricing rule injects none on
    purpose. So a product added here cost whatever its filament cost and
    nothing else — on a real portrait, 10.57 where the true cost is 35.91,
    because those seven figures are seven tenths of what it takes to make.
    The part being added now carries the same starting figures the other app's
    form carries, folded away under "Labour, power and wear" so they can be
    changed before the part goes in, and a part already in the list that has
    none of them says so instead of quietly costing less.

Khayt for macOS 4.0.0-alpha.17

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 16 Sep 17:00

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Added

  • (Mac) The shop's due dates as a calendar subscription. With the LAN
    server on, Settings → Online shows the same /calendar.ics link the
    Windows and Linux app offers: one all-day event per open job with a due
    date, tentative until it is printing, for any calendar app on the shop's
    Wi‑Fi. The feed is one shared module now (lib/lan-calendar.js), lifted
    verbatim out of the Node route and held byte-identical to it; the
    subscription token is minted into the book the first time the Mac serves.
  • (Mac) "Where is my order": the customer's tracking page, served by the
    Mac.
    On a job under way or done, the inspector has "Copy tracking link":
    the link points at this Mac, carries the job's own tracking token (minted
    the first time, as the other app mints it) and opens the same page that
    app serves — the stage of the order, its details, the shipping, and once it
    is complete a short survey the customer can answer from the page. The page
    is lifted verbatim out of the Node route into lib/lan-order-page.js, the
    Node server draws from it, and the carriers directory moved from the
    renderer into lib/ so both hosts read the same carrier names and links.

Fixed

  • Time left on a Klipper printer is the figure the machine itself shows.
    Khayt worked the number out from the layer count, and a layer count assumes
    every layer costs the same. Measured on a U1 printing a part whose lower
    half held three quarters of the work: layers said 53% done and Khayt
    extrapolated 7h19m left, while the machine's own screen said under three
    hours. Both numbers were in front of the shop at once. Klipper relays the
    slicer's M73 percentage — the only one of the three signals that is about
    time rather than geometry or file layout — as display_status.progress,
    and Khayt was not asking Moonraker for it at all. It asks now, and prefers
    it, captioned "as the printer shows it" so the two can be checked against
    each other. Layers stay the fallback: a file with no M73 behaves exactly
    as before, including the relief whose byte position read 0.7% at 19% done.

Khayt for macOS 4.0.0-alpha.16

Pre-release

Choose a tag to compare

@Alballaa Alballaa released this 16 Sep 15:20

Khayt for macOS only. The Windows and Linux app is on its own version — see
VERSIONING.md.

Added

  • (Mac) The phone's live queue, served by the Mac. A new Online tab in
    Settings carries the LAN block the Windows and Linux app keeps under
    "Advanced": enable the server, listen on the shop's Wi‑Fi, set the owner
    PIN. Switch it on and a phone on the same network gets the same live queue
    page, status API, queue API and installable home-screen icon that app
    serves — the same bytes, from one shared module (lib/lan-pages.js), behind
    the same PIN and the same lockout rules (lib/lan-auth.js), with the same
    security headers on every response. Saving restarts the server when the
    port or the PIN changed. The intake form, quote approval, the calendar feed
    and the webhooks are still the other app's; they follow.
  • (Mac) The customer intake form, served by the Mac. With the LAN server
    on, /intake on a phone or laptop on the shop's Wi‑Fi is the same request
    form the Windows and Linux app serves — same page, same session cookie,
    same limits on opening and submitting it, same consent record — and a
    submitted request lands on the Waiting screen at once. The form's template
    and the rule that turns a submission into a waiting-list entry are one
    shared module now (lib/lan-intake.js); the Node server draws from it and
    is held byte-identical to its old handlers. Not yet on the Mac: pricing an
    uploaded model on the form (the form does not offer the upload here) and
    the legacy intake PIN route.
  • (Mac) A customer approves a quote from their phone. On a job that is a
    quote, the inspector has "Copy quote link": the link points at this Mac,
    carries the job's own approval token (minted into the job the first time,
    as the Windows and Linux app mints it), and opens the same quote page that
    app serves — the parts, the total in the shop's currency, the expiry, and
    one button. Approving moves the job to pending inside the write on the
    newest book; a quote that expired, or was already approved, gets the same
    answer the other app gives. The page's small companions (not found, bad
    link, expired, cannot approve, approved) are lifted out of the Node routes
    into lib/lan-quote-page.js, verbatim, and the Node server draws from
    them; the rule's clock is injectable so both hosts can be held to it. Not
    yet on the Mac: the order tracking page and the legacy POST /order/:id.
  • (Mac) Rounding and "Your own price" on the product sheet. The two
    controls Khayt's product editor has had all along — round to a step (up,
    down or nearest) and a typed price that wins over everything — with the
    price preview following them as they change. Until now a shop on the Mac
    could see a catalogue price move and had no way to set it back.
  • The shared settings save (lib/settings-edit.js) now takes the LAN block
    from a form and merges it the way the Electron page always did: the fields
    shown over the stored block, a blank PIN keeps the current one, a port that
    is not a port is 3219. The Electron page is unchanged.

Fixed

  • (Mac) Saving a product no longer throws away its cost inputs or its
    price.
    The Mac product sheet rebuilt every part from the five fields it
    shows, so the labour rate, prep and post time, power draw, wear and failure
    rate the other app had priced the part with were dropped on save — a
    portrait that cost 35.91 to make came back costing 10.57, and the product
    re-priced itself from 50 to 13.74. The save also ignored the product's own
    rounding and typed price. Now a part keeps every field the sheet does not
    edit, and the product is priced through the shared rule with its rounding
    and override, so the same product saves to the same price in both apps.
  • (Mac) "New job from this" prices the job at the product's own rates.
    The job's parts were costed from grams and hours alone, so the same
    portrait opened at 15 where the catalogue said 50. A part taken from a
    product now carries the product's rates into the cost, and the job opens at
    the catalogue price.