kanbo-cli 0.1.3 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,75 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Krowli
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Required Notice: Copyright (c) 2026 Krowli (https://github.com/Krowli/kanbo)
2
+
3
+ # PolyForm Noncommercial License 1.0.0
4
+
5
+ <https://polyformproject.org/licenses/noncommercial/1.0.0>
6
+
7
+ ## Acceptance
8
+
9
+ In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
10
+
11
+ ## Copyright License
12
+
13
+ The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
14
+
15
+ ## Distribution License
16
+
17
+ The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
18
+
19
+ ## Notices
20
+
21
+ You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
22
+
23
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
24
+
25
+ ## Changes and New Works License
26
+
27
+ The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
28
+
29
+ ## Patent License
30
+
31
+ The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
32
+
33
+ ## Noncommercial Purposes
34
+
35
+ Any noncommercial purpose is a permitted purpose.
36
+
37
+ ## Personal Uses
38
+
39
+ Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
40
+
41
+ ## Noncommercial Organizations
42
+
43
+ Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
44
+
45
+ ## Fair Use
46
+
47
+ You may have "fair use" rights for the software under the law. These terms do not limit them.
48
+
49
+ ## No Other Rights
50
+
51
+ These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
52
+
53
+ ## Patent Defense
54
+
55
+ If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
56
+
57
+ ## Violations
58
+
59
+ The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
60
+
61
+ ## No Liability
62
+
63
+ ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
64
+
65
+ ## Definitions
66
+
67
+ The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
68
+
69
+ **You** refers to the individual or entity agreeing to these terms.
70
+
71
+ **Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
72
+
73
+ **Your licenses** are all the licenses granted to you for the software under these terms.
74
+
75
+ **Use** means anything you do with the software requiring one of your licenses.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/Krowli/kanbo/actions/workflows/ci.yml/badge.svg)](https://github.com/Krowli/kanbo/actions/workflows/ci.yml)
4
4
  [![npm version](https://img.shields.io/npm/v/kanbo-cli.svg)](https://www.npmjs.com/package/kanbo-cli)
5
- [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
+ [![License: PolyForm Noncommercial](https://img.shields.io/badge/license-PolyForm%20Noncommercial-orange.svg)](LICENSE)
6
6
  [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24.11-brightgreen.svg)](docs/installation.md)
7
7
 
8
8
  **A Kanban board your AI agents drive, and you watch.** kanbo is a board that lives next to your code — a SQLite file in the project, or a shared Postgres/Supabase database — with a command line and an MCP server made for coding agents. Agents take cards, move them, write a one-line status at every step, split work into subtasks and link their pull requests; when they need you, they hand the card over and stop. Only a person approves or sends a card back, and kanbo enforces that rather than asking nicely. You follow along in a terminal or on a small board page in your browser.
@@ -77,4 +77,6 @@ Every entry point — the CLI, the MCP server, the HTTP server — calls the sam
77
77
 
78
78
  ## License
79
79
 
80
- [MIT](LICENSE)
80
+ [PolyForm Noncommercial 1.0.0](LICENSE) — free for personal, research, educational and other noncommercial use. Commercial use — selling it, or building it into a paid product or service — needs a separate license: write to lionmause999@gmail.com.
81
+
82
+ Versions up to and including 0.2.0 were released under MIT and stay under MIT.
package/dist/cli.cjs CHANGED
@@ -3084,7 +3084,7 @@ var import_picocolors = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin((
3084
3084
  * `package.version`. A build carries it as a literal; running from source
3085
3085
  * (tests, `tsx`) reads the package's own `package.json` instead.
3086
3086
  */
3087
- const KANBO_PACKAGE_VERSION = "0.1.3";
3087
+ const KANBO_PACKAGE_VERSION = "0.2.1";
3088
3088
  /**
3089
3089
  * Every exit code this tool promises, and what it means — the capabilities
3090
3090
  * manifest's `exitCodes` reads this rather than naming the codes again. `0` and
@@ -10789,15 +10789,12 @@ async function approve(store, issueId, input, actor, scope) {
10789
10789
  * leaves even says "returned by you".
10790
10790
  */
10791
10791
  async function returnCard(store, issueId, input, actor, scope) {
10792
- if (actor.kind !== "user") throw new BoardError("board_return_requires_user", {
10793
- issueId,
10794
- actorKind: actor.kind
10795
- });
10796
10792
  return await runBoardWrite(store, async ({ tx }) => {
10793
+ await ensureDefaultColumns(tx, (await requireCard$1(tx, issueId)).workspaceId, { tx });
10794
+ const target = await assertReturnable(tx, issueId, input, actor);
10797
10795
  const card = await requireCard$1(tx, issueId);
10798
- const columns = await ensureDefaultColumns(tx, card.workspaceId, { tx });
10799
10796
  const updates = {
10800
- statusId: (input.toStatusName ? await requireColumn(tx, card.workspaceId, input.toStatusName) : previousColumn(columns, card)).id,
10797
+ statusId: target.id,
10801
10798
  waitingFor: null,
10802
10799
  updatedAt: currentUnixSeconds()
10803
10800
  };
@@ -10818,6 +10815,27 @@ async function returnCard(store, issueId, input, actor, scope) {
10818
10815
  };
10819
10816
  }, scope);
10820
10817
  }
10818
+ /**
10819
+ * Every reason `returnCard` would refuse, asked on reads alone, and the column
10820
+ * the card would go back to when none applies.
10821
+ *
10822
+ * `returnCard` asks exactly this inside its write. A caller that has to undo
10823
+ * something of its own before the return — stop listening for the approval the
10824
+ * card is waiting on, say — asks it first, so a return the board refuses leaves
10825
+ * that untouched. The refusals are the same `BoardError` codes: an actor who is
10826
+ * not a person (`board_return_requires_user`), a card that is not there
10827
+ * (`issue_not_found`), a named column the workspace does not hold
10828
+ * (`issue_status_not_found`), and a card already in the first column with no
10829
+ * column named (`board_return_no_previous_column`).
10830
+ */
10831
+ async function assertReturnable(store, issueId, input, actor) {
10832
+ if (actor.kind !== "user") throw new BoardError("board_return_requires_user", {
10833
+ issueId,
10834
+ actorKind: actor.kind
10835
+ });
10836
+ const card = await requireCard$1(store, issueId);
10837
+ return input.toStatusName ? await requireColumn(store, card.workspaceId, input.toStatusName) : previousColumn(await listColumns(store, card.workspaceId), card);
10838
+ }
10821
10839
  /** Write a comment on the card, as the actor unless the caller names another author. */
10822
10840
  async function addComment(store, input, actor, scope) {
10823
10841
  return await runBoardWrite(store, async ({ tx }) => {
@@ -11695,6 +11713,7 @@ function createBoardOps(store) {
11695
11713
  waitApproval: async (issueId, input, actor, scope) => await waitApproval(store, issueId, input, actor, scope),
11696
11714
  approve: async (issueId, input, actor, scope) => await approve(store, issueId, input, actor, scope),
11697
11715
  returnCard: async (issueId, input, actor, scope) => await returnCard(store, issueId, input, actor, scope),
11716
+ assertReturnable: async (issueId, input, actor) => await assertReturnable(store, issueId, input, actor),
11698
11717
  readApproval: async (issueId) => await readApproval(store, issueId),
11699
11718
  linkPullRequest: async (issueId, urlOrRef, actor, scope) => await linkPullRequest(store, issueId, urlOrRef, actor, scope),
11700
11719
  unlinkPullRequest: async (issueId, linkId, actor, scope) => await unlinkPullRequest(store, issueId, linkId, actor, scope),
@@ -43395,21 +43414,6 @@ function sendBoardPage(response, pathname, assets) {
43395
43414
  * reason turned around: the answer will be yes once the card meets them, and
43396
43415
  * `details.unmet` says what is missing.
43397
43416
  *
43398
- * The five failures about where a board is kept read the same rule. A database
43399
- * that holds no board this build can speak for is 409 — the setting is there,
43400
- * the board behind it is not yet, and `board-storage prepare` is what settles
43401
- * that — and one nobody could reach at all is 503, because nothing about the
43402
- * request was wrong. A workspace naming no board at all is 404: the caller
43403
- * asked about a setting that is not there. A board still holding cards when
43404
- * somebody asks to point the workspace elsewhere is 409, because the answer
43405
- * would have been yes on an empty board and `board-storage migrate` is what
43406
- * makes it one. An operation naming cards from two different boards is 400: no
43407
- * transaction reaches both, so the caller asked for something that cannot be
43408
- * done. A copy that would land on a card number or a column name the target
43409
- * already holds under a different id is 409 for the same reason the others
43410
- * are: the answer would have been yes on a target that did not hold that
43411
- * board, and `details.conflicts` names every value that clashed.
43412
- *
43413
43417
  * A failure may also be renamed here: the package names its codes after the
43414
43418
  * board, while every error the `/issues` routes answer with is named after the
43415
43419
  * issue, and a client matching on `issue_*` should not have to learn a second
@@ -43431,10 +43435,6 @@ const BOARD_ERROR_RESPONSES = {
43431
43435
  message: "The card does not meet what that column asks for yet",
43432
43436
  code: "issue_column_rules_unmet"
43433
43437
  },
43434
- board_copy_conflict: {
43435
- status: 409,
43436
- message: "That board already holds cards or columns of this workspace under the same numbers or names; nothing was copied"
43437
- },
43438
43438
  board_entry_rule_invalid: {
43439
43439
  status: 400,
43440
43440
  message: "Unknown column entry rule"
@@ -43443,10 +43443,6 @@ const BOARD_ERROR_RESPONSES = {
43443
43443
  status: 400,
43444
43444
  message: "Execution mode cannot change once the card has been launched"
43445
43445
  },
43446
- board_mixed_workspaces: {
43447
- status: 400,
43448
- message: "Those cards are not all on the same board"
43449
- },
43450
43446
  board_pull_request_invalid: {
43451
43447
  status: 400,
43452
43448
  message: "Not a GitHub pull request: give its URL or owner/repo#number"
@@ -43506,22 +43502,6 @@ const BOARD_ERROR_RESPONSES = {
43506
43502
  status: 400,
43507
43503
  message: "A sprint cannot start after it is due"
43508
43504
  },
43509
- board_storage_not_configured: {
43510
- status: 404,
43511
- message: "This workspace names no board storage"
43512
- },
43513
- board_storage_not_empty: {
43514
- status: 409,
43515
- message: "That board still holds cards of this workspace; move them with migrate before changing where the board is kept"
43516
- },
43517
- board_storage_not_prepared: {
43518
- status: 409,
43519
- message: "That board has not been prepared yet"
43520
- },
43521
- board_storage_unavailable: {
43522
- status: 503,
43523
- message: "That board could not be reached"
43524
- },
43525
43505
  issue_comment_delete_requires_user: {
43526
43506
  status: 403,
43527
43507
  message: "Only a person can delete a comment the board wrote"