open-index/open-npm huggingface dataset:
npm package: @mjamsek/ngx-keycloak-service
Description: Library for integration with Keycloak authorization server
Author: Miha Jamšek
Latest version: 0.0.1

# @mjamsek/ngx-keycloak-service
![Build Status](https://jenkins.mjamsek.com/buildStatus/icon?job=ngx-keycloak-service-lib)
> Library for integrating Keycloak IAM service with Angular application

## Introduction

## Documentation

### Installation

To install library simply execute command:

```bash
npm install --save @mjamsek/ngx-keycloak-service
```

### Usage

#### Initialization

Library's initialization method must be called at application startup, preferably, before any other code.

Two recommended ways:

* Register Angular application initializer (recommended - the Angular way)
* In `main.ts` file to wrap around Angular's bootstrap function

##### Application initializer

First, we will need to write factory function, which will call initialization method. For this we can create new file called `factories.ts` and put this code in it:

```typescript
import {KeycloakService} from "@mjamsek/ngx-keycloak-service";

export function AppAuthFactory() {
    return async () => {
        await KeycloakService.initialize({
            url: "http://keycloak.domain.com/auth",
            realm: "realm-name",
            clientId: "client-id",
            allowAnonymousAccess: true,
            roleClients: ["client-id"],
            forbiddenPage: {
                external: false,
                url: "/403"
            }
        });
    };
}
```

Next we need to let Angular know, to use this factory when initializing application. We can do this in `app.module.ts`:

```typescript
import {APP_INITIALIZER, NgModule} from "@angular/core";
import {AppAuthFactory} from "./factories";

@NgModule({
    declarations: [],
    imports: [],
    providers: [
        {provide: APP_INITIALIZER, useFactory: AppAuthFactory, multi: true}
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }
```

##### Wrapping method

In file `main.ts`, bootstrap Angular method with own:

```typescript
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";
import { KeycloakService } from "@mjamsek/ngx-keycloak-service";

if (environment.production) {
    enableProdMode();
}
KeycloakService.initialize({jsonPath: "assets/keycloak.json"}).then(() => {
    platformBrowserDynamic().bootstrapModule(AppModule)
        .catch(err => console.error(err));
});
```
npm package: @mjamsek/rxjs-utils
Description: Utility library providing RxJS operators.
Author: Miha Jamšek
Latest version: 0.0.7

# RxJS Utils
[![npm (scoped)](https://img.shields.io/npm/v/@mjamsek/rxjs-utils)](https://www.npmjs.com/package/@mjamsek/rxjs-utils)
[![GitHub license](https://img.shields.io/github/license/Jamsek-m/prog-lib-rxjs)](https://github.com/Jamsek-m/prog-lib-rxjs/blob/master/LICENSE)
> Utility library providing RxJS operators.

## Installation

Run command: `npm install --save @mjamsek/rxjs-utils`

## Documentation

### Type assertions

#### Assert type

`assertType<T>()` asserts observable is of type `T`. Usage:

```typescript
observable$.pipe(
    assertType<string>(),
);
```

#### Assert void

`assertVoid()` asserts observable is of type `void`. Usage:

```typescript
observable$.pipe(
    assertVoid(),
);
```

#### Assert non null

`nonNull()` asserts observable value is not null. Usage: 

```typescript
observable$.pipe(
    nonNull(),
);
```

#### Type filter

`ofTypeOnly<T>()` runs a type guard check on observable to filter values that are not of type `T`. Usage:

```typescript
function isString(x: unknown): x is string {
    return typeof x === "string";
}

observable$.pipe(
    ofTypeOnly<string>(isString),
);
```

You can also create reusable filters, by using `createTypeFilter` function:

```typescript
const enforceString = createTypeFilter(isString);

observable$.pipe(
    enforceString(),
);
```
 
#### Enforce type

`enforceType<T>()` runs a type guard check on observable to enforce it is of type `T`. Usage:

```typescript
function isString(x: unknown): x is string {
    return typeof x === "string";
}

observable$.pipe(
    enforceType<string>(isString),
);
```

You can also create reusable enforcers, by using `createTypeEnforcer` function:

```typescript
const enforceString = createTypeEnforcer(isString);

observable$.pipe(
    enforceString(),
);
```

## Bugs & Features

Any issues, requests for a new feature, etc. can be filled using [GitHub Issues](https://github.com/Jamsek-m/prog-lib-rxjs/issues).

## License

MIT
npm package: @mjand66/openclaw-dingtalk
Description: DingTalk (钉钉) channel plugin for OpenClaw
Author: mjand66
Latest version: 3.2.3

# DingTalk Channel for OpenClaw

钉钉企业内部机器人 Channel 插件，使用 Stream 模式（无需公网 IP）。

npm 包：[`@mjand66/openclaw-dingtalk`](https://www.npmjs.com/package/@mjand66/openclaw-dingtalk)

---

## 核心改进：AI 任务实时进度推送

> 本仓库 fork 自 [soimy/openclaw-channel-dingtalk](https://github.com/soimy/openclaw-channel-dingtalk)，最核心的改进是将钉钉机器人的回复模式从**任务完成后统一返回**升级为**实时推送执行进度**。

### 原有问题

上游版本中，当 AI 执行复杂任务（如调用多个工具、搜索、读写文件等）时，钉钉用户需要等待所有步骤全部完成后，才能收到一条最终回复。在耗时较长的任务（30 秒～几分钟）场景下，用户完全不知道 AI 在做什么，群聊中尤为明显。

### 本 fork 的方案

**订阅 OpenClaw 全局 Agent 事件总线**，在任务执行过程中实时向钉钉推送进度消息：

```
用户: 帮我分析最近一周的销售数据并生成报告

机器人: 思考中...
机器人: 🔧 正在执行：read_file
机器人: 🔧 正在执行：search_database
机器人: 🔧 正在执行：generate_chart
机器人: [最终完整报告]         ← 任务完成后统一回复
```

实现细节：
- 收到用户消息后立即发送"思考中..."提示
- 监听 `tool:start` 事件，每次工具调用开始时推送 `🔧 正在执行：<工具名>` 通知
- 每 30 秒发送一次心跳，防止长任务期间用户误以为机器人已挂起
- 任务结束后自动清理事件订阅

### 同步修复：并发会话 runId 串扰

多用户同时向机器人发消息时，上游代码存在竞态条件——多个并发 handler 会争抢同一个 `lifecycle.start` 事件的 `runId`，导致进度通知发送到错误的会话。本 fork 通过模块级 `claimedRunIds` Set 保证每个 Agent 运行的生命周期事件只被一个 handler 独占认领。

---

## 安装

```bash
openclaw plugins install @mjand66/openclaw-dingtalk
```

或从源码安装：

```bash
git clone https://github.com/MyQiongbao/openclaw-channel-dingtalk.git
openclaw plugins install ./openclaw-channel-dingtalk
```

## 配置

在钉钉开放平台创建企业内部应用机器人，获取 Client ID 和 Client Secret，填入 `openclaw.json`：

```json
{
  "channels": {
    "dingtalk": {
      "clientId": "YOUR_CLIENT_ID",
      "clientSecret": "YOUR_CLIENT_SECRET"
    }
  }
}
```

| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| `clientId` | string | — | 钉钉应用 Client ID（必填） |
| `clientSecret` | string | — | 钉钉应用 Client Secret（必填） |
| `cardMode` | boolean | `false` | 启用互动卡片模式（流式输出） |
| `thinkingMessage` | string | `"思考中..."` | 任务开始时的提示文本 |
| `logLevel` | string | `"info"` | 日志级别：`debug` / `info` / `warn` / `error` |

## 其他功能

- **Stream 模式** — WebSocket 长连接，无需公网 IP 或 Webhook
- **私聊 & 群聊** — 支持直接对话和群内 @机器人
- **多种消息类型** — 文本、图片、语音（自动识别）、视频、文件、钉钉文档/钉盘文件卡片
- **引用消息** — 支持大多数引用场景，`钉钉文档/钉盘文件卡片` 群聊引用暂不支持
- **Markdown 回复** — 自动将 Markdown 表格转为可读文本格式
- **互动卡片** — 支持流式更新

> 实时进度通知仅在 `cardMode: false`（默认）时生效。启用卡片模式后，AI 输出会直接流式更新到卡片中。

## 常见问题

**机器人无响应** → 检查 `clientId` / `clientSecret` 是否正确，确认开放平台已开启 Stream 模式，查看日志：`tail -f ~/.openclaw/logs/gateway.log`

**群聊 @机器人 无响应** → 确认应用已添加到该群并授权消息权限

## 许可证

MIT © [mjand66](https://github.com/MyQiongbao)