@geoly-ai/social-hub-cli 0.3.4 → 0.3.6
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/CHANGELOG.md +16 -0
- package/dist/cmd-manifest.json +22 -2
- package/dist/cmd-manifest.test.js +28 -0
- package/dist/cmd-manifest.test.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -1
- package/dist/permissions-gates-notify.d.ts +26 -0
- package/dist/permissions-gates-notify.d.ts.map +1 -0
- package/dist/permissions-gates-notify.js +118 -0
- package/dist/permissions-gates-notify.js.map +1 -0
- package/dist/permissions-gates-notify.test.d.ts +2 -0
- package/dist/permissions-gates-notify.test.d.ts.map +1 -0
- package/dist/permissions-gates-notify.test.js +107 -0
- package/dist/permissions-gates-notify.test.js.map +1 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +2 -0
- package/dist/permissions.js.map +1 -1
- package/dist/postinstall.js +1 -1
- package/dist/postinstall.js.map +1 -1
- package/dist/register-extensions.d.ts.map +1 -1
- package/dist/register-extensions.js +5 -9
- package/dist/register-extensions.js.map +1 -1
- package/dist/register-notify.d.ts +172 -0
- package/dist/register-notify.d.ts.map +1 -0
- package/dist/register-notify.js +1148 -0
- package/dist/register-notify.js.map +1 -0
- package/dist/register-notify.test.d.ts +2 -0
- package/dist/register-notify.test.d.ts.map +1 -0
- package/dist/register-notify.test.js +309 -0
- package/dist/register-notify.test.js.map +1 -0
- package/dist/skill-update-check.d.ts +15 -0
- package/dist/skill-update-check.d.ts.map +1 -1
- package/dist/skill-update-check.js +22 -3
- package/dist/skill-update-check.js.map +1 -1
- package/dist/skill-update-check.test.js +19 -6
- package/dist/skill-update-check.test.js.map +1 -1
- package/package.json +3 -3
- package/skills/README.md +10 -7
- package/skills/manifest.json +6 -1
- package/skills/social-hub-cli/SKILL.md +3 -2
- package/skills/social-hub-notifications/SKILL.md +351 -0
- package/skills/social-hub-posts/SKILL.md +36 -0
- package/skills/social-hub-shared/SKILL.md +9 -9
- package/dist/register-subreddit-post-style.d.ts +0 -8
- package/dist/register-subreddit-post-style.d.ts.map +0 -1
- package/dist/register-subreddit-post-style.js +0 -161
- package/dist/register-subreddit-post-style.js.map +0 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type NotificationPullReceiptDto, type NotificationPullResponseDto, type NotificationSubscriptionDto, type SocialHubClient } from "@geoly-ai/social-hub-sdk";
|
|
3
|
+
/**
|
|
4
|
+
* `social-hub notify …` —— 事件订阅通知的消费面(设计见
|
|
5
|
+
* `docs/notification-event-subscription-design.md`,契约见
|
|
6
|
+
* `packages/contracts/src/notifications.ts`)。
|
|
7
|
+
*
|
|
8
|
+
* 使用场景:用户自己机器上的 agent 从 Hub 拉「帖子发布后 2h/6h/24h/2d/7d」这类节点事件,
|
|
9
|
+
* 拿到后自己去开浏览器截图、发飞书群。**Hub 只通知,完全不管执行**。因此本命令组的设计
|
|
10
|
+
* 目标是「AI agent 的工具调用」:机器友好 + 崩溃可恢复。
|
|
11
|
+
*
|
|
12
|
+
* ## 五条不可协商的形态约束
|
|
13
|
+
*
|
|
14
|
+
* 1. **默认 `--limit 1`**(不是 20)。没有 delivery 表,ack 是**连续 watermark** 而不是
|
|
15
|
+
* 单条确认:`cursorSeq = N` 表示该订阅所有匹配事件中 `seq ≤ N` 的**均已完成**。
|
|
16
|
+
* 一次拉 20 条、第 5 条失败,后面 15 条就再也无法安全 ack。
|
|
17
|
+
* 2. **`--follow` 的背压固定为 maxUnacked=1**:输出一条后轮询自己的 subscription,
|
|
18
|
+
* 等 `cursorSeq >= pendingSeq` 才拉下一条。`--follow` 是便利模式,**不是新的消费协议**。
|
|
19
|
+
* 3. **不提供 `--auto-ack`**。CLI 写完 stdout 不代表下游 agent 已经截完图、发完飞书;
|
|
20
|
+
* 此时崩溃事件就丢了。ack 必须由真正完成副作用的一方显式发起。
|
|
21
|
+
* 4. **只原样输出,绝不「补齐」缺失字段**。envelope 带四层版本 + `includedFields`,
|
|
22
|
+
* 形状随配置变化是设计不是 bug。
|
|
23
|
+
* 5. **`seq` 全程字符串**(bigint)。任何 `Number(seq)` 都是精度炸弹;比较走
|
|
24
|
+
* {@link compareNotificationSeqStrings}(BigInt)。
|
|
25
|
+
*
|
|
26
|
+
* ## 退出码矩阵(脚本/supervisor 据此分流)
|
|
27
|
+
*
|
|
28
|
+
* | 码 | 含义 |
|
|
29
|
+
* | -- | ---- |
|
|
30
|
+
* | 0 | 成功(含「无消息」、`--follow` 被 SIGINT/SIGTERM 正常中断) |
|
|
31
|
+
* | 1 | 参数 / 鉴权 / 权限 / 协议错误,或服务端**非重试**错误(含 pull 的 410 stale) |
|
|
32
|
+
* | 2 | 可重试的网络 / 服务不可用;或 `--fail-if-empty` 且无消息 |
|
|
33
|
+
* | 3 | ack 的 cursor / receipt 冲突(409 CAS 冲突、410 游标过期) |
|
|
34
|
+
* | 4 | **保留**:未来批量操作部分成功。Phase 1 不产生该退出码 |
|
|
35
|
+
*/
|
|
36
|
+
export declare const NOTIFY_EXIT: {
|
|
37
|
+
readonly OK: 0;
|
|
38
|
+
/** 参数/鉴权/权限/协议或服务端非重试错误。 */
|
|
39
|
+
readonly FATAL: 1;
|
|
40
|
+
/** 可重试的网络/服务不可用,或 --fail-if-empty 且无消息。 */
|
|
41
|
+
readonly RETRYABLE: 2;
|
|
42
|
+
/** ack 的 cursor/receipt 冲突(409/410)。 */
|
|
43
|
+
readonly CURSOR_CONFLICT: 3;
|
|
44
|
+
/** 保留:批量操作部分成功(Phase 1 不产生)。 */
|
|
45
|
+
readonly PARTIAL: 4;
|
|
46
|
+
};
|
|
47
|
+
export type NotifyExitCode = (typeof NOTIFY_EXIT)[keyof typeof NOTIFY_EXIT];
|
|
48
|
+
/**
|
|
49
|
+
* 可重试的 HTTP 状态:超时/过早/限流/服务端故障。
|
|
50
|
+
* 4xx 里只有 408 / 425 / 429 是「等一会儿再来」,其余都是调用方自己的问题。
|
|
51
|
+
*/
|
|
52
|
+
export declare function isRetryableStatus(status: number): boolean;
|
|
53
|
+
/** 传输层失败(DNS / 连接拒绝 / socket 断开 / TLS)——一律当可重试。 */
|
|
54
|
+
export declare function isNetworkError(e: unknown): boolean;
|
|
55
|
+
export type NotifyPhase = "pull" | "ack" | "admin";
|
|
56
|
+
export type NotifyErrorClassification = {
|
|
57
|
+
exitCode: NotifyExitCode;
|
|
58
|
+
/** true = `--follow` 应退避重试而不是退出。 */
|
|
59
|
+
retryable: boolean;
|
|
60
|
+
status?: number;
|
|
61
|
+
code?: string;
|
|
62
|
+
message: string;
|
|
63
|
+
details?: unknown;
|
|
64
|
+
retryAfterSeconds?: number;
|
|
65
|
+
/** 给 agent 的下一步动作提示(stderr 上打印)。 */
|
|
66
|
+
hint?: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* 把任意错误映射成退出码。
|
|
70
|
+
*
|
|
71
|
+
* 关键取舍:
|
|
72
|
+
* - **pull 的 410(`SUBSCRIPTION_CURSOR_EXPIRED`)判 1 而不是 2**。它需要人工确认后
|
|
73
|
+
* `notify subscriptions reset`;若判成「可重试」,supervisor 会对同一个 stale 订阅
|
|
74
|
+
* 无限重启。
|
|
75
|
+
* - **ack 的 409 与 410 都判 3**,方便调用方统一进入「游标恢复分支」;具体动作靠
|
|
76
|
+
* stderr 里的 `code` 区分(409 → 重读订阅/重新 pull 拿新 receipt;410 → 人工 reset)。
|
|
77
|
+
* - **`PULL_RECEIPT_INVALID` 判 1**:签名/epoch/filterVersion 已变,重试同一 receipt
|
|
78
|
+
* 永远不会成功,必须重新 pull。
|
|
79
|
+
*/
|
|
80
|
+
export declare function classifyNotifyError(e: unknown, phase: NotifyPhase): NotifyErrorClassification;
|
|
81
|
+
/**
|
|
82
|
+
* receipt sidecar 的形状。
|
|
83
|
+
*
|
|
84
|
+
* **为什么必须有它**:JSON Lines 模式下 stdout 只能出 envelope,而 envelope 里**没有**
|
|
85
|
+
* receipt;ack 又要求回传**整个 receipt 对象**(不只是 signature)。没有 sidecar,
|
|
86
|
+
* `--format jsonl` 拉到的事件就是永远无法 ack 的死事件。
|
|
87
|
+
*/
|
|
88
|
+
export type NotifyReceiptSidecar = {
|
|
89
|
+
subscriptionId: string;
|
|
90
|
+
/** ack 时的 `expectedCursorSeq`(= receipt.fromCursorSeq)。 */
|
|
91
|
+
cursorSeq: string;
|
|
92
|
+
/** ack 时的 `throughSeq`(= 本批最后一条事件的 seq)。 */
|
|
93
|
+
throughSeq: string;
|
|
94
|
+
/** 本批事件的 eventId(便于 agent 对账;不参与 ack 校验)。 */
|
|
95
|
+
eventIds: string[];
|
|
96
|
+
receipt: NotificationPullReceiptDto;
|
|
97
|
+
};
|
|
98
|
+
export declare function buildReceiptSidecar(res: NotificationPullResponseDto): NotifyReceiptSidecar | null;
|
|
99
|
+
/**
|
|
100
|
+
* 原子落盘:先写临时文件再 rename,避免 agent 读到半截 JSON。
|
|
101
|
+
* 权限 0600 —— receipt 是签名凭据,虽有 TTL 但不该对同机其它用户可读。
|
|
102
|
+
*/
|
|
103
|
+
export declare function writeReceiptSidecarAtomically(path: string, sidecar: NotifyReceiptSidecar): void;
|
|
104
|
+
/** 指数退避 + ±20% 抖动,封顶 maxMs。 */
|
|
105
|
+
export declare function nextBackoffMs(attempt: number, baseMs: number, maxMs: number, rand?: () => number): number;
|
|
106
|
+
/**
|
|
107
|
+
* `--subscription` 收 name 或 uuid。
|
|
108
|
+
*
|
|
109
|
+
* SDK 侧**只认 uuid**(pull/ack 是消费热路径,不该藏一次隐式 list);name 解析是 CLI
|
|
110
|
+
* 的便利层,且 `--follow` 只在启动时解析一次。
|
|
111
|
+
*/
|
|
112
|
+
export declare function resolveSubscription(client: SocialHubClient, teamId: string, ref: string,
|
|
113
|
+
/** `--follow` 启动期解析也必须能被 Ctrl-C 打断,否则要一直等到网络超时。 */
|
|
114
|
+
signal?: AbortSignal): Promise<NotificationSubscriptionDto>;
|
|
115
|
+
export type CursorWaitDecision = {
|
|
116
|
+
kind: "advanced";
|
|
117
|
+
} | {
|
|
118
|
+
kind: "wait";
|
|
119
|
+
} | {
|
|
120
|
+
kind: "abort";
|
|
121
|
+
reason: string;
|
|
122
|
+
hint: string;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* `--follow` 每轮 GET subscription 后的判定。
|
|
126
|
+
*
|
|
127
|
+
* 只比 cursor 是不够的 —— 下列情形会让「等 cursor 推进」永久挂死,必须当场退出:
|
|
128
|
+
* - `paused` / `stale` / `deleted`:这些状态下 ack 根本不会成功;
|
|
129
|
+
* - `receiptEpoch` / `filterVersion` 变了而 cursor 还没越过 pendingSeq:
|
|
130
|
+
* 在途 receipt 已作废(reset / 改 filter / 权限变化),这条事件再也 ack 不上去。
|
|
131
|
+
*
|
|
132
|
+
* cursor 已越过 pendingSeq 视为**已被别处推进**,直接继续下一轮,**不重复输出**该事件。
|
|
133
|
+
*/
|
|
134
|
+
export declare function evaluateCursorWait(args: {
|
|
135
|
+
subscription: NotificationSubscriptionDto;
|
|
136
|
+
pendingSeq: string;
|
|
137
|
+
receiptEpoch: number;
|
|
138
|
+
filterVersion: number;
|
|
139
|
+
}): CursorWaitDecision;
|
|
140
|
+
/** 逗号分隔列表 → 去重 + ASCII 升序(契约要求 sourceIds / 字段路径升序去重)。 */
|
|
141
|
+
export declare function parseSortedList(raw: string | undefined): string[] | undefined;
|
|
142
|
+
export declare function registerNotifyCommands(program: Command): void;
|
|
143
|
+
/** 组装 create 请求体:`-j/--json` 整体覆盖,否则由扁平参数拼(并做升序去重规范化)。 */
|
|
144
|
+
export declare function buildCreateSubscriptionBody(opts: {
|
|
145
|
+
name?: string;
|
|
146
|
+
source?: string[];
|
|
147
|
+
start?: string;
|
|
148
|
+
requireFields?: string;
|
|
149
|
+
filterBrand?: string;
|
|
150
|
+
filterAccount?: string;
|
|
151
|
+
filterSubreddit?: string;
|
|
152
|
+
json?: string;
|
|
153
|
+
jsonFile?: string;
|
|
154
|
+
}): {
|
|
155
|
+
name: string;
|
|
156
|
+
sourceIds: string[];
|
|
157
|
+
filters?: Record<string, string[]>;
|
|
158
|
+
requiredFields?: string[];
|
|
159
|
+
startPosition?: "now" | "earliest";
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* `--receipt` / `--receipt-file` 收两种形状:
|
|
163
|
+
* - sidecar(`{subscriptionId, cursorSeq, throughSeq, receipt}`,`notify pull --receipt-file` 产出)
|
|
164
|
+
* - 裸 receipt(`{subscriptionId, fromCursorSeq, …, signature}`)
|
|
165
|
+
* 两者都接受,agent 不必自己拆包。
|
|
166
|
+
*/
|
|
167
|
+
export declare function extractAckInput(raw: unknown): {
|
|
168
|
+
receipt: NotificationPullReceiptDto;
|
|
169
|
+
cursorSeq?: string;
|
|
170
|
+
throughSeq?: string;
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=register-notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-notify.d.ts","sourceRoot":"","sources":["../src/register-notify.ts"],"names":[],"mappings":"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"}
|