@flowmind/cli 0.3.6 → 0.3.7
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/dist/index.js +51 -15
- package/package.json +8 -1
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ var ERROR_CODES = {
|
|
|
23
23
|
INVALID_API_RESPONSE: "INVALID_API_RESPONSE",
|
|
24
24
|
MAX_ACTIVE_JOBS_REACHED: "MAX_ACTIVE_JOBS_REACHED",
|
|
25
25
|
NOT_FOUND: "NOT_FOUND",
|
|
26
|
+
PLAN_LIMIT_REACHED: "PLAN_LIMIT_REACHED",
|
|
26
27
|
QUOTA_EXCEEDED: "QUOTA_EXCEEDED",
|
|
27
28
|
RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED",
|
|
28
29
|
SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE",
|
|
@@ -455,10 +456,10 @@ async function writeIgnore(start, reason) {
|
|
|
455
456
|
}
|
|
456
457
|
|
|
457
458
|
// ../../packages/contracts/src/generated/revision.ts
|
|
458
|
-
var contractRevision = "
|
|
459
|
+
var contractRevision = "bbd616246f8533ef25c4f4889cea85dde03967c231740071c89597c025853d6b";
|
|
459
460
|
|
|
460
461
|
// ../../packages/contracts/src/generated/validators/apiError.js
|
|
461
|
-
var m = { additionalProperties: false, properties: { data: { enum: [null], nullable: true, type: "object" }, details: {}, error: { enum: ["BAD_REQUEST", "PUBLICATION_REVISION_CONFLICT", "PUBLICATION_STALE_ENTRIES", "SHARE_STALE_ENTRIES", "SLUG_TAKEN", "CONFLICT", "EXPIRED", "FORBIDDEN", "HUMAN_SESSION_REQUIRED", "INTERNAL_ERROR", "INVALID_API_RESPONSE", "MAX_ACTIVE_JOBS_REACHED", "NOT_FOUND", "QUOTA_EXCEEDED", "RATE_LIMIT_EXCEEDED", "SERVICE_UNAVAILABLE", "UNDECLARED_API_OPERATION", "UNAUTHENTICATED", "VALIDATION_FAILED"], type: "string" }, message: { type: "string" }, requestId: { minLength: 1, type: "string" }, status: { maximum: 599, minimum: 400, type: "integer" }, success: { enum: [false], type: "boolean" } }, required: ["success", "status", "message", "data", "requestId", "error", "details"], type: "object" };
|
|
462
|
+
var m = { additionalProperties: false, properties: { data: { enum: [null], nullable: true, type: "object" }, details: {}, error: { enum: ["BAD_REQUEST", "PUBLICATION_REVISION_CONFLICT", "PUBLICATION_STALE_ENTRIES", "SHARE_STALE_ENTRIES", "SLUG_TAKEN", "CONFLICT", "EXPIRED", "FORBIDDEN", "HUMAN_SESSION_REQUIRED", "INTERNAL_ERROR", "INVALID_API_RESPONSE", "MAX_ACTIVE_JOBS_REACHED", "NOT_FOUND", "PLAN_LIMIT_REACHED", "QUOTA_EXCEEDED", "RATE_LIMIT_EXCEEDED", "SERVICE_UNAVAILABLE", "UNDECLARED_API_OPERATION", "UNAUTHENTICATED", "VALIDATION_FAILED"], type: "string" }, message: { type: "string" }, requestId: { minLength: 1, type: "string" }, status: { maximum: 599, minimum: 400, type: "integer" }, success: { enum: [false], type: "boolean" } }, required: ["success", "status", "message", "data", "requestId", "error", "details"], type: "object" };
|
|
462
463
|
function t2(r2, { instancePath: i4 = "", parentData: E, parentDataProperty: d5, rootData: f2 = r2 } = {}) {
|
|
463
464
|
let p7 = null, s6 = 0;
|
|
464
465
|
if (s6 === 0) if (r2 && typeof r2 == "object" && !Array.isArray(r2)) {
|
|
@@ -481,7 +482,7 @@ function t2(r2, { instancePath: i4 = "", parentData: E, parentDataProperty: d5,
|
|
|
481
482
|
if (r2.error !== void 0) {
|
|
482
483
|
let e4 = r2.error, o10 = s6;
|
|
483
484
|
if (typeof e4 != "string") return t2.errors = [{ instancePath: i4 + "/error", schemaPath: "#/properties/error/type", keyword: "type", params: { type: "string" }, message: "must be string" }], false;
|
|
484
|
-
if (!(e4 === "BAD_REQUEST" || e4 === "PUBLICATION_REVISION_CONFLICT" || e4 === "PUBLICATION_STALE_ENTRIES" || e4 === "SHARE_STALE_ENTRIES" || e4 === "SLUG_TAKEN" || e4 === "CONFLICT" || e4 === "EXPIRED" || e4 === "FORBIDDEN" || e4 === "HUMAN_SESSION_REQUIRED" || e4 === "INTERNAL_ERROR" || e4 === "INVALID_API_RESPONSE" || e4 === "MAX_ACTIVE_JOBS_REACHED" || e4 === "NOT_FOUND" || e4 === "QUOTA_EXCEEDED" || e4 === "RATE_LIMIT_EXCEEDED" || e4 === "SERVICE_UNAVAILABLE" || e4 === "UNDECLARED_API_OPERATION" || e4 === "UNAUTHENTICATED" || e4 === "VALIDATION_FAILED")) return t2.errors = [{ instancePath: i4 + "/error", schemaPath: "#/properties/error/enum", keyword: "enum", params: { allowedValues: m.properties.error.enum }, message: "must be equal to one of the allowed values" }], false;
|
|
485
|
+
if (!(e4 === "BAD_REQUEST" || e4 === "PUBLICATION_REVISION_CONFLICT" || e4 === "PUBLICATION_STALE_ENTRIES" || e4 === "SHARE_STALE_ENTRIES" || e4 === "SLUG_TAKEN" || e4 === "CONFLICT" || e4 === "EXPIRED" || e4 === "FORBIDDEN" || e4 === "HUMAN_SESSION_REQUIRED" || e4 === "INTERNAL_ERROR" || e4 === "INVALID_API_RESPONSE" || e4 === "MAX_ACTIVE_JOBS_REACHED" || e4 === "NOT_FOUND" || e4 === "PLAN_LIMIT_REACHED" || e4 === "QUOTA_EXCEEDED" || e4 === "RATE_LIMIT_EXCEEDED" || e4 === "SERVICE_UNAVAILABLE" || e4 === "UNDECLARED_API_OPERATION" || e4 === "UNAUTHENTICATED" || e4 === "VALIDATION_FAILED")) return t2.errors = [{ instancePath: i4 + "/error", schemaPath: "#/properties/error/enum", keyword: "enum", params: { allowedValues: m.properties.error.enum }, message: "must be equal to one of the allowed values" }], false;
|
|
485
486
|
var a4 = o10 === s6;
|
|
486
487
|
} else var a4 = true;
|
|
487
488
|
if (a4) {
|
|
@@ -621,7 +622,7 @@ var U = c((r2) => {
|
|
|
621
622
|
// ../../packages/contracts/src/generated/validators/shared/774NGUAG.js
|
|
622
623
|
var t3 = U().fullFormats.date;
|
|
623
624
|
|
|
624
|
-
// ../../packages/contracts/src/generated/validators/shared/
|
|
625
|
+
// ../../packages/contracts/src/generated/validators/shared/53EW46KW.js
|
|
625
626
|
function s(e4, { instancePath: a4 = "", parentData: n7, parentDataProperty: u4, rootData: l4 = e4 } = {}) {
|
|
626
627
|
let m5 = null, r2 = 0;
|
|
627
628
|
if (r2 === 0) if (e4 && typeof e4 == "object" && !Array.isArray(e4)) {
|
|
@@ -2794,9 +2795,23 @@ var ApiRejectionError = class extends BridgeError {
|
|
|
2794
2795
|
return this.#rejectionMessage;
|
|
2795
2796
|
}
|
|
2796
2797
|
};
|
|
2798
|
+
var PlanLimitError = class extends BridgeError {
|
|
2799
|
+
constructor(error, details) {
|
|
2800
|
+
super(error.code, error.context);
|
|
2801
|
+
this.details = details;
|
|
2802
|
+
}
|
|
2803
|
+
};
|
|
2804
|
+
var readPlanLimitDetails = (details) => {
|
|
2805
|
+
const value = details;
|
|
2806
|
+
if (typeof value !== "object" || value === null || typeof value.limitKey !== "string" || !Number.isInteger(value.limit) || !Number.isInteger(value.used) || !(value.resetAt === null || typeof value.resetAt === "string")) {
|
|
2807
|
+
throw new Error("Flowmind sent a plan limit error without its details");
|
|
2808
|
+
}
|
|
2809
|
+
return { limitKey: value.limitKey, limit: value.limit, used: value.used, resetAt: value.resetAt };
|
|
2810
|
+
};
|
|
2797
2811
|
async function apiRequest(endpoint, args, options = {}) {
|
|
2798
2812
|
const apiKey = options.authOptional ? void 0 : requireApiKey();
|
|
2799
2813
|
let rejectionResponse;
|
|
2814
|
+
let planLimitResponse;
|
|
2800
2815
|
try {
|
|
2801
2816
|
return await requestEndpoint(toleratingAdditions(endpoint), API_URL, args, {
|
|
2802
2817
|
headers: {
|
|
@@ -2804,17 +2819,21 @@ async function apiRequest(endpoint, args, options = {}) {
|
|
|
2804
2819
|
...options.headers
|
|
2805
2820
|
},
|
|
2806
2821
|
...options.signal ? { signal: options.signal } : {},
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
}
|
|
2813
|
-
return response;
|
|
2822
|
+
fetch: async (input2, init) => {
|
|
2823
|
+
const response = await fetch(input2, init);
|
|
2824
|
+
if (response.status === 402) planLimitResponse = response.clone();
|
|
2825
|
+
if (options.preserveRejectionMessage && response.status >= 400 && response.status < 500 && response.status !== 408) {
|
|
2826
|
+
rejectionResponse = response.clone();
|
|
2814
2827
|
}
|
|
2815
|
-
|
|
2828
|
+
return response;
|
|
2829
|
+
}
|
|
2816
2830
|
});
|
|
2817
2831
|
} catch (error) {
|
|
2832
|
+
if (error instanceof BridgeError && error.context.kind === "api" && error.code === "PLAN_LIMIT_REACHED" && planLimitResponse) {
|
|
2833
|
+
const envelope = await planLimitResponse.json();
|
|
2834
|
+
assertApiEnvelope(envelope);
|
|
2835
|
+
throw new PlanLimitError(error, readPlanLimitDetails(envelope.details));
|
|
2836
|
+
}
|
|
2818
2837
|
if (error instanceof BridgeError && error.context.kind === "api" && rejectionResponse) {
|
|
2819
2838
|
const envelope = await rejectionResponse.json();
|
|
2820
2839
|
assertApiEnvelope(envelope);
|
|
@@ -3498,8 +3517,25 @@ async function resolveSession(explicit, cwd, now = /* @__PURE__ */ new Date()) {
|
|
|
3498
3517
|
}
|
|
3499
3518
|
|
|
3500
3519
|
// src/command-error.ts
|
|
3520
|
+
var LIMIT_WORDS = {
|
|
3521
|
+
"projects.active": (limit) => `${limit} active projects`,
|
|
3522
|
+
"logs.personal.month": (limit) => `${limit} personal logs this month`,
|
|
3523
|
+
"logs.agent.month": (limit) => `${limit} agent logs this month`
|
|
3524
|
+
};
|
|
3525
|
+
var describePlanLimit = ({ limit, limitKey, resetAt }) => {
|
|
3526
|
+
const what = (LIMIT_WORDS[limitKey] ?? ((count) => `${count} of ${limitKey}`))(limit);
|
|
3527
|
+
const frees = resetAt === null ? "Archiving a finished project frees a slot (archiving is final), or upgrade to Pro." : `It resets on ${new Date(resetAt).toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric", timeZone: "UTC" })}, or upgrade to Pro.`;
|
|
3528
|
+
return `Your plan allows ${what}. ${frees} Everything you already logged stays. Upgrade in the Flowmind web app under Settings > Plan.`;
|
|
3529
|
+
};
|
|
3501
3530
|
var printCommandError = (action, error, json = false, extra) => {
|
|
3502
3531
|
let diagnostic;
|
|
3532
|
+
if (error instanceof PlanLimitError) {
|
|
3533
|
+
const message = describePlanLimit(error.details);
|
|
3534
|
+
console.error(json ? JSON.stringify({ error: message, code: error.code, ...error.details, ...extra }) : `${message}${extra ? `
|
|
3535
|
+
${extra.message}` : ""}`);
|
|
3536
|
+
process.exitCode = 1;
|
|
3537
|
+
return;
|
|
3538
|
+
}
|
|
3503
3539
|
if (error instanceof BridgeError) {
|
|
3504
3540
|
const context2 = error.context;
|
|
3505
3541
|
const schema = `${context2.schemaId ?? "unavailable"}${context2.schemaPath ?? ""}`;
|
|
@@ -5053,7 +5089,7 @@ ${box}
|
|
|
5053
5089
|
}
|
|
5054
5090
|
});
|
|
5055
5091
|
|
|
5056
|
-
// ../../packages/contracts/src/generated/validators/shared/
|
|
5092
|
+
// ../../packages/contracts/src/generated/validators/shared/2AOOQGDJ.js
|
|
5057
5093
|
var b2 = { description: "A project", properties: { archivedAt: { format: "date-time", nullable: true, type: "string" }, category: { type: "string" }, color: { type: "string" }, completedAt: { format: "date-time", nullable: true, type: "string" }, createdAt: { format: "date-time", type: "string" }, description: { nullable: true, type: "string" }, details: { description: "Private details for lastOutcome, or an empty array when no outcome exists.", items: { type: "string" }, type: "array" }, estimatedHours: { nullable: true, type: "integer" }, icon: { type: "string" }, id: { format: "uuid", type: "string" }, lastActiveDay: { format: "date", nullable: true, type: "string" }, lastOutcome: { nullable: true, type: "string" }, launchDescription: { nullable: true, type: "string" }, launchUrl: { nullable: true, type: "string" }, launchedAt: { format: "date-time", nullable: true, type: "string" }, name: { type: "string" }, nextStep: { anyOf: [{ $ref: "urn:flowmind:schema:ProjectNextStep" }, { enum: [null], nullable: true, type: "object" }] }, updatedAt: { format: "date-time", type: "string" } }, required: ["id", "name", "description", "color", "icon", "category", "estimatedHours", "launchedAt", "completedAt", "launchDescription", "launchUrl", "createdAt", "updatedAt", "archivedAt", "nextStep", "lastOutcome", "details", "lastActiveDay"], type: "object" };
|
|
5058
5094
|
function n6(r2, { instancePath: i4 = "", parentData: k3, parentDataProperty: _, rootData: w3 = r2 } = {}) {
|
|
5059
5095
|
let l4 = null, e4 = 0;
|
|
@@ -6224,7 +6260,7 @@ import { Command as Command10 } from "commander";
|
|
|
6224
6260
|
// ../../packages/contracts/src/generated/validators/shared/VVGMHJLN.js
|
|
6225
6261
|
var e3 = new RegExp("^[a-f0-9]{64}$", "u");
|
|
6226
6262
|
|
|
6227
|
-
// ../../packages/contracts/src/generated/validators/shared/
|
|
6263
|
+
// ../../packages/contracts/src/generated/validators/shared/LVEL2FHK.js
|
|
6228
6264
|
var K2 = new RegExp("^[a-z0-9]+(-[a-z0-9]+)*$", "u");
|
|
6229
6265
|
var w2 = { additionalProperties: false, properties: { candidates: { items: { additionalProperties: false, properties: { agentLabel: { nullable: true, type: "string" }, artifactUrl: { nullable: true, type: "string" }, captureSource: { type: "string" }, details: { items: { type: "string" }, type: "array" }, digest: { pattern: "^[a-f0-9]{64}$", type: "string" }, durationSeconds: { minimum: 0, type: "integer" }, entryId: { format: "uuid", type: "string" }, fieldVersion: { minimum: 0, type: "integer" }, localDay: { pattern: "^\\d{4}-\\d{2}-\\d{2}$", type: "string" }, loggedLate: { type: "boolean" }, outcome: { type: "string" }, provenance: { enum: ["personal", "agent"], type: "string" }, selection: { additionalProperties: false, nullable: true, properties: { artifactKind: { enum: ["code", "design", "document", "demo", "other", null], nullable: true, type: "string" }, selectedAt: { format: "date-time", type: "string" } }, required: ["artifactKind", "selectedAt"], type: "object" }, state: { enum: ["public", "changed", "new", "private"], type: "string" }, suggestedArtifactKind: { enum: ["code", "design", "document", "demo", "other", null], nullable: true, type: "string" } }, required: ["entryId", "localDay", "outcome", "details", "artifactUrl", "durationSeconds", "provenance", "captureSource", "loggedLate", "digest", "fieldVersion", "agentLabel", "suggestedArtifactKind", "state", "selection"], type: "object" }, type: "array" }, candidatesTruncated: { type: "boolean" }, counts: { additionalProperties: false, properties: { changed: { minimum: 0, type: "integer" }, eligible: { minimum: 0, type: "integer" }, new: { minimum: 0, type: "integer" }, public: { minimum: 0, type: "integer" } }, required: ["public", "changed", "new", "eligible"], type: "object" }, project: { additionalProperties: false, properties: { archived: { type: "boolean" }, color: { type: "string" }, id: { format: "uuid", type: "string" }, name: { type: "string" } }, required: ["id", "name", "color", "archived"], type: "object" }, publication: { additionalProperties: false, nullable: true, properties: { hiddenByModeration: { type: "boolean" }, id: { format: "uuid", type: "string" }, links: { additionalProperties: false, properties: { badgeMarkdown: { type: "string" }, card: { type: "string" }, feed: { type: "string" }, page: { type: "string" } }, required: ["page", "card", "feed", "badgeMarkdown"], type: "object" }, publicSummary: { nullable: true, type: "string" }, publicTitle: { type: "string" }, publishedAt: { format: "date-time", nullable: true, type: "string" }, reviewedAt: { format: "date-time", type: "string" }, slug: { maxLength: 60, minLength: 3, pattern: "^[a-z0-9]+(-[a-z0-9]+)*$", type: "string" }, status: { enum: ["published", "unpublished"], type: "string" }, updatedAt: { format: "date-time", type: "string" } }, required: ["id", "slug", "publicTitle", "publicSummary", "status", "hiddenByModeration", "publishedAt", "reviewedAt", "updatedAt", "links"], type: "object" }, revision: { minimum: 0, type: "integer" }, suggestedSlug: { maxLength: 60, minLength: 3, pattern: "^[a-z0-9]+(-[a-z0-9]+)*$", type: "string" }, suggestedTitle: { type: "string" }, username: { type: "string" } }, required: ["project", "username", "revision", "suggestedSlug", "suggestedTitle", "publication", "counts", "candidates", "candidatesTruncated"], type: "object" };
|
|
6230
6266
|
function s5(l4, { instancePath: i4 = "", parentData: x4, parentDataProperty: I2, rootData: B = l4 } = {}) {
|
|
@@ -6793,7 +6829,7 @@ var shipLogCommand = new Command10("ship-log").description("Read a project ship
|
|
|
6793
6829
|
|
|
6794
6830
|
// src/index.ts
|
|
6795
6831
|
var program = new Command11();
|
|
6796
|
-
program.name("flowmind").description("Flowmind CLI (also installed as fm)").version("0.3.
|
|
6832
|
+
program.name("flowmind").description("Flowmind CLI (also installed as fm)").version("0.3.7").enablePositionalOptions();
|
|
6797
6833
|
program.addCommand(agentCommand);
|
|
6798
6834
|
program.addCommand(authCommand);
|
|
6799
6835
|
program.addCommand(logCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowmind/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Flowmind CLI: log what you and your coding agents ship, with the outcome and the link that proves it. Works with Codex and Claude Code.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -37,8 +37,15 @@
|
|
|
37
37
|
"flowmind": "dist/index.js"
|
|
38
38
|
},
|
|
39
39
|
"type": "module",
|
|
40
|
+
"imports": {
|
|
41
|
+
"#contracts": {
|
|
42
|
+
"types": "./src/contracts.ts",
|
|
43
|
+
"default": "./dist/contracts.js"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
40
46
|
"scripts": {
|
|
41
47
|
"build": "tsc --noEmit && node build.mjs",
|
|
48
|
+
"typecheck:tests": "tsc -p tsconfig.tests.json",
|
|
42
49
|
"prepack": "npm run build",
|
|
43
50
|
"test": "pnpm run build && node --test test/*.test.mjs && tsx --test src/*.test.ts && node test/pack-install.mjs",
|
|
44
51
|
"dev": "npm run build && node dist/index.js"
|