sfora-cli 0.10.0 → 0.12.0
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/README.md +174 -0
- package/dist/SforaFs.js +8 -6
- package/dist/api-client.d.ts +344 -4
- package/dist/api-client.js +289 -21
- package/dist/block-commands.d.ts +84 -0
- package/dist/block-commands.js +155 -0
- package/dist/chat.d.ts +89 -0
- package/dist/chat.js +189 -0
- package/dist/cli-args.d.ts +32 -0
- package/dist/cli-args.js +88 -0
- package/dist/cli.js +530 -88
- package/dist/format/blockSplice.d.ts +135 -0
- package/dist/format/blockSplice.js +330 -0
- package/dist/format/blocks/dropClosure.d.ts +10 -1
- package/dist/format/blocks/dropClosure.js +11 -1
- package/dist/format/callout.d.ts +69 -7
- package/dist/format/callout.js +112 -15
- package/dist/format/checklist.js +11 -4
- package/dist/format/formatAxes.d.ts +228 -0
- package/dist/format/formatAxes.js +454 -0
- package/dist/format/index.d.ts +1 -0
- package/dist/format/index.js +4 -0
- package/dist/format/lineGeometry.d.ts +34 -4
- package/dist/format/lineGeometry.js +140 -40
- package/dist/format/lint/appliesTo.d.ts +92 -0
- package/dist/format/lint/appliesTo.js +369 -0
- package/dist/format/lint/config.d.ts +106 -0
- package/dist/format/lint/config.js +205 -0
- package/dist/format/lint/fixAll.d.ts +62 -0
- package/dist/format/lint/fixAll.js +107 -0
- package/dist/format/lint/frontmatterSchema.d.ts +181 -0
- package/dist/format/lint/frontmatterSchema.js +660 -0
- package/dist/format/lint/index.d.ts +34 -5
- package/dist/format/lint/index.js +34 -5
- package/dist/format/lint/lintSource.d.ts +27 -7
- package/dist/format/lint/lintSource.js +67 -33
- package/dist/format/lint/rules/frontmatter-schema.d.ts +2 -0
- package/dist/format/lint/rules/frontmatter-schema.js +92 -0
- package/dist/format/lint/rules/index.d.ts +2 -1
- package/dist/format/lint/rules/index.js +7 -1
- package/dist/format/lint/rules/malformed-callout.js +25 -16
- package/dist/format/lint/rules/malformed-checklist.js +8 -3
- package/dist/format/lint/rules/malformed-frontmatter.js +6 -1
- package/dist/format/lint/severity.d.ts +15 -0
- package/dist/format/lint/severity.js +50 -0
- package/dist/format/lint/textEdits.d.ts +86 -0
- package/dist/format/lint/textEdits.js +162 -0
- package/dist/format/lint/types.d.ts +44 -8
- package/dist/format/markdown/slug.d.ts +28 -0
- package/dist/format/markdown/slug.js +63 -0
- package/dist/format/plaintext.js +13 -3
- package/dist/format/sheetCellSpans.d.ts +95 -0
- package/dist/format/sheetCellSpans.js +223 -0
- package/dist/format/sheetSelection.d.ts +136 -0
- package/dist/format/sheetSelection.js +282 -0
- package/dist/format/textStats.d.ts +23 -0
- package/dist/format/textStats.js +80 -0
- package/dist/format/wikiLinks.d.ts +60 -1
- package/dist/format/wikiLinks.js +195 -9
- package/dist/index.d.ts +26 -1
- package/dist/index.js +20 -3
- package/dist/opener.d.ts +23 -0
- package/dist/opener.js +26 -0
- package/dist/render.d.ts +162 -0
- package/dist/render.js +280 -0
- package/dist/shell-commands.d.ts +34 -0
- package/dist/shell-commands.js +108 -0
- package/dist/watch.d.ts +79 -0
- package/dist/watch.js +113 -0
- package/dist/web-url.d.ts +39 -0
- package/dist/web-url.js +63 -0
- package/package.json +1 -1
package/dist/chat.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sfora rooms` / `sfora join` / `sfora chat` — the room in the terminal.
|
|
3
|
+
*
|
|
4
|
+
* Humans and agents are the same member model in the same rooms, and this is
|
|
5
|
+
* how either sits in the conversation from a terminal. Everything
|
|
6
|
+
* decision-shaped lives here as pure functions (name resolution, message
|
|
7
|
+
* formatting, the tail loop) so it can be tested with canned data; `cli.ts`
|
|
8
|
+
* owns the process — readline, signals, the real streams.
|
|
9
|
+
*
|
|
10
|
+
* The live tail rides `/v1/events`, the same long-poll `sfora watch` uses: the
|
|
11
|
+
* feed carries a `message` event for every room the caller is in (never their
|
|
12
|
+
* own posts), so a new message is a wake, not a poll schedule. The event's
|
|
13
|
+
* preview is clipped server-side at 280 chars, so the loop treats it as a
|
|
14
|
+
* DOORBELL only — on any message event for this room it refetches the recent
|
|
15
|
+
* page and prints what it has not printed yet, deduped by message id. That is
|
|
16
|
+
* also what makes the caller's own sends (echoed by the send itself) never
|
|
17
|
+
* print twice.
|
|
18
|
+
*/
|
|
19
|
+
import type { AgentEventsPage, ChatMessage, Room } from "./api-client.js";
|
|
20
|
+
/** How `sfora rooms` and `sfora join` spell a room name as an argument. */
|
|
21
|
+
export declare function roomSlug(name: string): string;
|
|
22
|
+
export type RoomMatch = {
|
|
23
|
+
kind: "match";
|
|
24
|
+
room: Room;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "ambiguous";
|
|
27
|
+
candidates: Room[];
|
|
28
|
+
} | {
|
|
29
|
+
kind: "none";
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The room a reference names: exact name or slug first (case-insensitive),
|
|
33
|
+
* then an unambiguous prefix of either. Ambiguity is reported, not guessed —
|
|
34
|
+
* sending a message into the wrong room is the failure this exists to prevent.
|
|
35
|
+
* A joined room beats an unjoined one on an otherwise-tied exact match.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveRoomRef(rooms: Room[], ref: string): RoomMatch;
|
|
38
|
+
/** House rule: a displayed name leads with a capital, wherever it renders. */
|
|
39
|
+
export declare function capitalizeName(name: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* A chat timestamp, relative — a room is read as a conversation, and "3m ago"
|
|
42
|
+
* is how a conversation tells time. Beyond a week the date says it better.
|
|
43
|
+
*/
|
|
44
|
+
export declare function relativeTime(ts: number, now: number): string;
|
|
45
|
+
/**
|
|
46
|
+
* A message body for a terminal: markdown, lightly dressed. Headings read
|
|
47
|
+
* bold, fence delimiters and blockquote markers go dim; everything else is
|
|
48
|
+
* printed as the author wrote it — the CLI prints what the server sends, and
|
|
49
|
+
* markdown is already a terminal-legible format.
|
|
50
|
+
*/
|
|
51
|
+
export declare function renderChatBody(markdown: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* One message: `Author 3m ago`, then the body indented under it. The author
|
|
54
|
+
* is bold because it is the line's anchor; the time is dim because it is
|
|
55
|
+
* context, not content.
|
|
56
|
+
*/
|
|
57
|
+
export declare function renderChatMessage(msg: ChatMessage, now: number): string;
|
|
58
|
+
/** `sfora rooms` — one row per room; unjoined rows carry their join hint. */
|
|
59
|
+
export declare function renderRoomList(rooms: Room[]): string;
|
|
60
|
+
/** Everything the tail loop needs from the outside world. */
|
|
61
|
+
export interface ChatTailDeps {
|
|
62
|
+
/** One `/v1/events` long-poll. Rejects on a drop — the loop backs off. */
|
|
63
|
+
poll(since: number): Promise<AgentEventsPage>;
|
|
64
|
+
/** The room's recent page, any order — refetched when the doorbell rings. */
|
|
65
|
+
fetchRecent(): Promise<ChatMessage[]>;
|
|
66
|
+
/** Print one message the reader has not seen. */
|
|
67
|
+
print(message: ChatMessage): void;
|
|
68
|
+
/** A warning, never mixed into the transcript. */
|
|
69
|
+
warn(text: string): void;
|
|
70
|
+
sleep(ms: number): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
export interface ChatTailOptions {
|
|
73
|
+
roomId: string;
|
|
74
|
+
/** Message ids already on screen — history, and the caller's own sends. */
|
|
75
|
+
seen: Set<string>;
|
|
76
|
+
/** Events cursor to start from (the CLI starts at "now"). */
|
|
77
|
+
since: number;
|
|
78
|
+
stopped?: () => boolean;
|
|
79
|
+
backoffMs?: number;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Poll until stopped, printing new messages in this room as they arrive.
|
|
83
|
+
*
|
|
84
|
+
* The same three rules `watchLoop` holds, held here for the same reasons: the
|
|
85
|
+
* cursor survives reconnects and only moves forward, drops back off (doubling
|
|
86
|
+
* to {@link MAX_BACKOFF_MS}) and recover fast, and nothing prints twice — the
|
|
87
|
+
* `seen` set is the single ledger, shared with the prompt's own sends.
|
|
88
|
+
*/
|
|
89
|
+
export declare function chatTailLoop(deps: ChatTailDeps, options: ChatTailOptions): Promise<number>;
|
package/dist/chat.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sfora rooms` / `sfora join` / `sfora chat` — the room in the terminal.
|
|
3
|
+
*
|
|
4
|
+
* Humans and agents are the same member model in the same rooms, and this is
|
|
5
|
+
* how either sits in the conversation from a terminal. Everything
|
|
6
|
+
* decision-shaped lives here as pure functions (name resolution, message
|
|
7
|
+
* formatting, the tail loop) so it can be tested with canned data; `cli.ts`
|
|
8
|
+
* owns the process — readline, signals, the real streams.
|
|
9
|
+
*
|
|
10
|
+
* The live tail rides `/v1/events`, the same long-poll `sfora watch` uses: the
|
|
11
|
+
* feed carries a `message` event for every room the caller is in (never their
|
|
12
|
+
* own posts), so a new message is a wake, not a poll schedule. The event's
|
|
13
|
+
* preview is clipped server-side at 280 chars, so the loop treats it as a
|
|
14
|
+
* DOORBELL only — on any message event for this room it refetches the recent
|
|
15
|
+
* page and prints what it has not printed yet, deduped by message id. That is
|
|
16
|
+
* also what makes the caller's own sends (echoed by the send itself) never
|
|
17
|
+
* print twice.
|
|
18
|
+
*/
|
|
19
|
+
import { colors } from "./render.js";
|
|
20
|
+
import { MAX_BACKOFF_MS } from "./watch.js";
|
|
21
|
+
const dim = (text) => `${colors.dim}${text}${colors.reset}`;
|
|
22
|
+
// ─── Room resolution ─────────────────────────────────────────────────
|
|
23
|
+
/** How `sfora rooms` and `sfora join` spell a room name as an argument. */
|
|
24
|
+
export function roomSlug(name) {
|
|
25
|
+
return name
|
|
26
|
+
.toLowerCase()
|
|
27
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
28
|
+
.replace(/^-|-$/g, "");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The room a reference names: exact name or slug first (case-insensitive),
|
|
32
|
+
* then an unambiguous prefix of either. Ambiguity is reported, not guessed —
|
|
33
|
+
* sending a message into the wrong room is the failure this exists to prevent.
|
|
34
|
+
* A joined room beats an unjoined one on an otherwise-tied exact match.
|
|
35
|
+
*/
|
|
36
|
+
export function resolveRoomRef(rooms, ref) {
|
|
37
|
+
const want = ref.trim().toLowerCase().replace(/^#/, "");
|
|
38
|
+
if (!want)
|
|
39
|
+
return { kind: "none" };
|
|
40
|
+
const bySlug = roomSlug(want);
|
|
41
|
+
const exact = rooms.filter((r) => r.name.toLowerCase() === want || roomSlug(r.name) === bySlug);
|
|
42
|
+
if (exact.length === 1)
|
|
43
|
+
return { kind: "match", room: exact[0] };
|
|
44
|
+
if (exact.length > 1) {
|
|
45
|
+
const joined = exact.filter((r) => r.joined);
|
|
46
|
+
if (joined.length === 1)
|
|
47
|
+
return { kind: "match", room: joined[0] };
|
|
48
|
+
return { kind: "ambiguous", candidates: exact };
|
|
49
|
+
}
|
|
50
|
+
const prefix = rooms.filter((r) => r.name.toLowerCase().startsWith(want) ||
|
|
51
|
+
roomSlug(r.name).startsWith(bySlug));
|
|
52
|
+
if (prefix.length === 1)
|
|
53
|
+
return { kind: "match", room: prefix[0] };
|
|
54
|
+
if (prefix.length > 1)
|
|
55
|
+
return { kind: "ambiguous", candidates: prefix };
|
|
56
|
+
return { kind: "none" };
|
|
57
|
+
}
|
|
58
|
+
// ─── Message formatting ──────────────────────────────────────────────
|
|
59
|
+
/** House rule: a displayed name leads with a capital, wherever it renders. */
|
|
60
|
+
export function capitalizeName(name) {
|
|
61
|
+
return name ? name.charAt(0).toUpperCase() + name.slice(1) : name;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A chat timestamp, relative — a room is read as a conversation, and "3m ago"
|
|
65
|
+
* is how a conversation tells time. Beyond a week the date says it better.
|
|
66
|
+
*/
|
|
67
|
+
export function relativeTime(ts, now) {
|
|
68
|
+
const diff = Math.max(0, now - ts);
|
|
69
|
+
const minutes = Math.floor(diff / 60_000);
|
|
70
|
+
if (minutes < 1)
|
|
71
|
+
return "just now";
|
|
72
|
+
if (minutes < 60)
|
|
73
|
+
return `${minutes}m ago`;
|
|
74
|
+
const hours = Math.floor(minutes / 60);
|
|
75
|
+
if (hours < 24)
|
|
76
|
+
return `${hours}h ago`;
|
|
77
|
+
const days = Math.floor(hours / 24);
|
|
78
|
+
if (days < 7)
|
|
79
|
+
return `${days}d ago`;
|
|
80
|
+
// The reader's LOCAL date — toISOString would name yesterday for an
|
|
81
|
+
// evening timestamp anywhere east of UTC.
|
|
82
|
+
const d = new Date(ts);
|
|
83
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
84
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* A message body for a terminal: markdown, lightly dressed. Headings read
|
|
88
|
+
* bold, fence delimiters and blockquote markers go dim; everything else is
|
|
89
|
+
* printed as the author wrote it — the CLI prints what the server sends, and
|
|
90
|
+
* markdown is already a terminal-legible format.
|
|
91
|
+
*/
|
|
92
|
+
export function renderChatBody(markdown) {
|
|
93
|
+
let inFence = false;
|
|
94
|
+
return markdown
|
|
95
|
+
.replace(/\s+$/, "")
|
|
96
|
+
.split("\n")
|
|
97
|
+
.map((line) => {
|
|
98
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
99
|
+
inFence = !inFence;
|
|
100
|
+
return ` ${dim(line)}`;
|
|
101
|
+
}
|
|
102
|
+
if (inFence)
|
|
103
|
+
return ` ${line}`;
|
|
104
|
+
if (/^#{1,6}\s/.test(line)) {
|
|
105
|
+
return ` ${colors.bold}${line}${colors.reset}`;
|
|
106
|
+
}
|
|
107
|
+
if (/^\s*>/.test(line))
|
|
108
|
+
return ` ${dim(line)}`;
|
|
109
|
+
return ` ${line}`;
|
|
110
|
+
})
|
|
111
|
+
.join("\n");
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* One message: `Author 3m ago`, then the body indented under it. The author
|
|
115
|
+
* is bold because it is the line's anchor; the time is dim because it is
|
|
116
|
+
* context, not content.
|
|
117
|
+
*/
|
|
118
|
+
export function renderChatMessage(msg, now) {
|
|
119
|
+
const author = capitalizeName(msg.author?.name ?? "Unknown");
|
|
120
|
+
const header = `${colors.bold}${author}${colors.reset} ${dim(relativeTime(msg._creationTime, now))}`;
|
|
121
|
+
return `${header}\n${renderChatBody(msg.body)}`;
|
|
122
|
+
}
|
|
123
|
+
/** `sfora rooms` — one row per room; unjoined rows carry their join hint. */
|
|
124
|
+
export function renderRoomList(rooms) {
|
|
125
|
+
if (rooms.length === 0)
|
|
126
|
+
return dim("(no rooms)");
|
|
127
|
+
const width = Math.max(...rooms.map((r) => r.name.length));
|
|
128
|
+
return rooms
|
|
129
|
+
.map((room) => {
|
|
130
|
+
const marker = room.joined
|
|
131
|
+
? `${colors.green}●${colors.reset}`
|
|
132
|
+
: dim("○");
|
|
133
|
+
const meta = room.joined
|
|
134
|
+
? dim(room.type)
|
|
135
|
+
: dim(`${room.type} · not joined — sfora join ${roomSlug(room.name)}`);
|
|
136
|
+
return ` ${marker} ${room.name.padEnd(width)} ${meta}`;
|
|
137
|
+
})
|
|
138
|
+
.join("\n");
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Poll until stopped, printing new messages in this room as they arrive.
|
|
142
|
+
*
|
|
143
|
+
* The same three rules `watchLoop` holds, held here for the same reasons: the
|
|
144
|
+
* cursor survives reconnects and only moves forward, drops back off (doubling
|
|
145
|
+
* to {@link MAX_BACKOFF_MS}) and recover fast, and nothing prints twice — the
|
|
146
|
+
* `seen` set is the single ledger, shared with the prompt's own sends.
|
|
147
|
+
*/
|
|
148
|
+
export async function chatTailLoop(deps, options) {
|
|
149
|
+
const stopped = options.stopped ?? (() => false);
|
|
150
|
+
const firstBackoff = options.backoffMs ?? 1_000;
|
|
151
|
+
let cursor = options.since;
|
|
152
|
+
let backoff = firstBackoff;
|
|
153
|
+
while (!stopped()) {
|
|
154
|
+
let page;
|
|
155
|
+
try {
|
|
156
|
+
page = await deps.poll(cursor);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (stopped())
|
|
160
|
+
break;
|
|
161
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
162
|
+
deps.warn(`reconnecting in ${Math.round(backoff / 1000)}s — ${message}`);
|
|
163
|
+
await deps.sleep(backoff);
|
|
164
|
+
backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
backoff = firstBackoff;
|
|
168
|
+
const rang = page.events.some((e) => e.type === "message" && e.roomId === options.roomId);
|
|
169
|
+
if (rang) {
|
|
170
|
+
try {
|
|
171
|
+
const recent = await deps.fetchRecent();
|
|
172
|
+
const fresh = recent
|
|
173
|
+
.filter((m) => !options.seen.has(m._id))
|
|
174
|
+
.sort((a, b) => a._creationTime - b._creationTime);
|
|
175
|
+
for (const msg of fresh) {
|
|
176
|
+
options.seen.add(msg._id);
|
|
177
|
+
deps.print(msg);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
182
|
+
deps.warn(`could not fetch new messages — ${message}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Never backwards: an empty page holds the cursor where it was.
|
|
186
|
+
cursor = Math.max(cursor, page.cursor);
|
|
187
|
+
}
|
|
188
|
+
return cursor;
|
|
189
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI's argument grammar, as a pure function.
|
|
3
|
+
*
|
|
4
|
+
* Lifted out of `cli.ts` so it can be tested: importing `cli.ts` runs
|
|
5
|
+
* `main()`, which is exactly what a test must not do. Nothing here reads the
|
|
6
|
+
* process — argv in, a parsed shape out.
|
|
7
|
+
*/
|
|
8
|
+
export interface CliArgs {
|
|
9
|
+
command?: string;
|
|
10
|
+
rest: string[];
|
|
11
|
+
org?: string;
|
|
12
|
+
cwd: string;
|
|
13
|
+
mcp: boolean;
|
|
14
|
+
help: boolean;
|
|
15
|
+
url?: string;
|
|
16
|
+
key?: string;
|
|
17
|
+
bot?: string;
|
|
18
|
+
as?: string;
|
|
19
|
+
web?: string;
|
|
20
|
+
project?: string;
|
|
21
|
+
column?: string;
|
|
22
|
+
draft: boolean;
|
|
23
|
+
json: boolean;
|
|
24
|
+
local: boolean;
|
|
25
|
+
cloud: boolean;
|
|
26
|
+
block?: string;
|
|
27
|
+
self: boolean;
|
|
28
|
+
wait?: number;
|
|
29
|
+
message?: string;
|
|
30
|
+
limit?: number;
|
|
31
|
+
}
|
|
32
|
+
export declare function parseArgs(argv: string[]): CliArgs;
|
package/dist/cli-args.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI's argument grammar, as a pure function.
|
|
3
|
+
*
|
|
4
|
+
* Lifted out of `cli.ts` so it can be tested: importing `cli.ts` runs
|
|
5
|
+
* `main()`, which is exactly what a test must not do. Nothing here reads the
|
|
6
|
+
* process — argv in, a parsed shape out.
|
|
7
|
+
*/
|
|
8
|
+
export function parseArgs(argv) {
|
|
9
|
+
const args = { rest: [], cwd: "/", mcp: false, help: false, draft: false, json: false, local: false, cloud: false, self: false };
|
|
10
|
+
for (let i = 0; i < argv.length; i++) {
|
|
11
|
+
const a = argv[i];
|
|
12
|
+
if (a === "--mcp")
|
|
13
|
+
args.mcp = true;
|
|
14
|
+
else if (a === "--help" || a === "-h")
|
|
15
|
+
args.help = true;
|
|
16
|
+
else if (a === "--org")
|
|
17
|
+
args.org = argv[++i];
|
|
18
|
+
else if (a.startsWith("--org="))
|
|
19
|
+
args.org = a.slice("--org=".length);
|
|
20
|
+
else if (a === "--cwd")
|
|
21
|
+
args.cwd = argv[++i] ?? "/";
|
|
22
|
+
else if (a.startsWith("--cwd="))
|
|
23
|
+
args.cwd = a.slice("--cwd=".length);
|
|
24
|
+
else if (a === "--url")
|
|
25
|
+
args.url = argv[++i];
|
|
26
|
+
else if (a.startsWith("--url="))
|
|
27
|
+
args.url = a.slice("--url=".length);
|
|
28
|
+
else if (a === "--key")
|
|
29
|
+
args.key = argv[++i];
|
|
30
|
+
else if (a.startsWith("--key="))
|
|
31
|
+
args.key = a.slice("--key=".length);
|
|
32
|
+
else if (a === "--bot" || a === "--agent")
|
|
33
|
+
args.bot = argv[++i];
|
|
34
|
+
else if (a.startsWith("--bot="))
|
|
35
|
+
args.bot = a.slice("--bot=".length);
|
|
36
|
+
else if (a.startsWith("--agent="))
|
|
37
|
+
args.bot = a.slice("--agent=".length);
|
|
38
|
+
else if (a === "--as")
|
|
39
|
+
args.as = argv[++i];
|
|
40
|
+
else if (a.startsWith("--as="))
|
|
41
|
+
args.as = a.slice("--as=".length);
|
|
42
|
+
else if (a === "--web")
|
|
43
|
+
args.web = argv[++i];
|
|
44
|
+
else if (a.startsWith("--web="))
|
|
45
|
+
args.web = a.slice("--web=".length);
|
|
46
|
+
else if (a === "--project")
|
|
47
|
+
args.project = argv[++i];
|
|
48
|
+
else if (a.startsWith("--project="))
|
|
49
|
+
args.project = a.slice("--project=".length);
|
|
50
|
+
else if (a === "--column")
|
|
51
|
+
args.column = argv[++i];
|
|
52
|
+
else if (a.startsWith("--column="))
|
|
53
|
+
args.column = a.slice("--column=".length);
|
|
54
|
+
else if (a === "--draft")
|
|
55
|
+
args.draft = true;
|
|
56
|
+
else if (a === "--json")
|
|
57
|
+
args.json = true;
|
|
58
|
+
else if (a === "--local")
|
|
59
|
+
args.local = true;
|
|
60
|
+
else if (a === "--cloud")
|
|
61
|
+
args.cloud = true;
|
|
62
|
+
else if (a === "--block")
|
|
63
|
+
args.block = argv[++i];
|
|
64
|
+
else if (a.startsWith("--block="))
|
|
65
|
+
args.block = a.slice("--block=".length);
|
|
66
|
+
else if (a === "--self")
|
|
67
|
+
args.self = true;
|
|
68
|
+
else if (a === "--wait")
|
|
69
|
+
args.wait = Number.parseInt(argv[++i] ?? "", 10);
|
|
70
|
+
else if (a.startsWith("--wait="))
|
|
71
|
+
args.wait = Number.parseInt(a.slice("--wait=".length), 10);
|
|
72
|
+
else if (a === "-m" || a === "--message")
|
|
73
|
+
args.message = argv[++i];
|
|
74
|
+
else if (a.startsWith("--message="))
|
|
75
|
+
args.message = a.slice("--message=".length);
|
|
76
|
+
else if (a === "-n" || a === "--limit")
|
|
77
|
+
args.limit = Number.parseInt(argv[++i] ?? "", 10);
|
|
78
|
+
else if (a.startsWith("--limit="))
|
|
79
|
+
args.limit = Number.parseInt(a.slice("--limit=".length), 10);
|
|
80
|
+
else if (!a.startsWith("-")) {
|
|
81
|
+
if (!args.command)
|
|
82
|
+
args.command = a;
|
|
83
|
+
else
|
|
84
|
+
args.rest.push(a);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return args;
|
|
88
|
+
}
|