peertable 0.3.2 → 0.3.3
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.ja.md +3 -1
- package/README.md +2 -2
- package/package.json +1 -1
- package/room/client.mjs +4 -1
- package/skill/SKILL.md +17 -2
- package/skill/scripts/archive-room-log.py +57 -0
- package/skill/scripts/teardown.sh +92 -8
package/README.ja.md
CHANGED
|
@@ -79,7 +79,9 @@ claude --mcp-config .team/mcp.json \
|
|
|
79
79
|
|
|
80
80
|
> 円卓を立てて
|
|
81
81
|
|
|
82
|
-
聞き取り・命名・`.team/` の scaffold(プロジェクト本体を汚さない)・Lattice plan 投入(単独モードなら読み取り専用の `.team/tasks.md` 生成)・メンバー起動・親の着卓まで一続き。
|
|
82
|
+
聞き取り・命名・`.team/` の scaffold(プロジェクト本体を汚さない)・Lattice plan 投入(単独モードなら読み取り専用の `.team/tasks.md` 生成)・メンバー起動・親の着卓まで一続き。
|
|
83
|
+
|
|
84
|
+
**teardown は既定で「解散」**——席を畳んでメンバー登録を外し、`.team/` と `.mcp.json` を撤去する。**部屋と過去ログは残る**(部屋は場所であり、次の卓も同じ部屋で続く。過去ログはその部屋の履歴として繋がる)。工程正本 `.lattice/` も残す。**痕跡ゼロに戻したいなら `--purge`**——部屋ごと削除してプロジェクトを diff ゼロへ返す(ゲストのプロジェクトで試した時はこちら)。
|
|
83
85
|
|
|
84
86
|
## 状態
|
|
85
87
|
|
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ Standalone gives up machine-guaranteed scheduling across tasks — nothing else.
|
|
|
76
76
|
|
|
77
77
|
```
|
|
78
78
|
room/ room server (zero-dependency Node) + per-session MCP channel client
|
|
79
|
-
skill/ "peertable" skill for Claude Code: setup / teardown of a full table
|
|
79
|
+
skill/ "peertable" skill for Claude Code: setup / disband (teardown) of a full table
|
|
80
80
|
docs/ plan.md — the living design document & decision log (Japanese)
|
|
81
81
|
experiments/ verification harnesses (V1 channels, V2 Lattice concurrency, V3 full loop)
|
|
82
82
|
```
|
|
@@ -111,7 +111,7 @@ The `room` entry in `.team/mcp.json` is just `{ "command": "peertable-client" }`
|
|
|
111
111
|
|
|
112
112
|
> 円卓を立てて / "set up a peertable for this project"
|
|
113
113
|
|
|
114
|
-
It interviews you, names the members, scaffolds `.team/` (charter + roles, isolated from your project, `.git/info/exclude`d), seeds the Lattice plan — or writes the read-only `.team/tasks.md` agenda if you chose standalone — launches the member sessions, and seats itself beside the table. `teardown`
|
|
114
|
+
It interviews you, names the members, scaffolds `.team/` (charter + roles, isolated from your project, `.git/info/exclude`d), seeds the Lattice plan — or writes the read-only `.team/tasks.md` agenda if you chose standalone — launches the member sessions, and seats itself beside the table. `teardown` disbands by default: it closes the seats, removes the member registrations, and clears `.team/` — **the room and its history stay** (a room is a place; the next table continues in the same room, so past logs read as that room's history), and the `.lattice/` plan store is kept. Pass `--purge` to delete the room too and restore your project to a zero diff.
|
|
115
115
|
|
|
116
116
|
## Status
|
|
117
117
|
|
package/package.json
CHANGED
package/room/client.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
10
10
|
|
|
11
11
|
// client.mjs 側のハードコード版数。package.json の version と一致していることを
|
|
12
12
|
// diagnostics の version_consistency が見る(2 つの版数源の drift 検出。決定45)
|
|
13
|
-
const MCP_VERSION = '0.3.
|
|
13
|
+
const MCP_VERSION = '0.3.3'
|
|
14
14
|
const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
15
15
|
|
|
16
16
|
const USAGE = `usage:
|
|
@@ -222,6 +222,9 @@ async function runDiagnostics(asJson) {
|
|
|
222
222
|
'scripts/make-plan-input.mjs',
|
|
223
223
|
'scripts/parent-join.sh',
|
|
224
224
|
'scripts/wakeup-bridge.mjs',
|
|
225
|
+
'scripts/seat-status-bridge.mjs',
|
|
226
|
+
// teardown の archive(=解散・既定)が呼ぶ。欠けるとログの写しが取れない
|
|
227
|
+
'scripts/archive-room-log.py',
|
|
225
228
|
'templates/gen-plan.mjs',
|
|
226
229
|
'templates/done.sh',
|
|
227
230
|
'templates/charter.md',
|
package/skill/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: peertable
|
|
3
|
-
description: 任意プロジェクトに Peertable
|
|
3
|
+
description: 任意プロジェクトに Peertable チーム(対等メンバー並列型のマルチエージェント作業システム)を導入・解散する。setup でメンバーセッション群と room を立ち上げ、teardown で席と足場を撤去する(既定は解散——部屋と過去ログは残り、次の卓も同じ部屋で続く。痕跡ゼロにするなら --purge)。「チームで作業して」「円卓を立てて」「peertable setup / teardown」で使う。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Peertable — setup / teardown
|
|
@@ -57,7 +57,22 @@ description: 任意プロジェクトに Peertable チーム(対等メンバ
|
|
|
57
57
|
|
|
58
58
|
## teardown
|
|
59
59
|
|
|
60
|
-
`scripts/teardown.sh <project
|
|
60
|
+
`scripts/teardown.sh <project> [--purge]` が機械部分を**全部**行う(room 名・server URL・作成記録は `.team/setup-state.json` から読むので引数は project だけ。書込トークンは環境変数 `PEERTABLE_POST_TOKEN`)。**席の終了も本 script が行う**——AI が事前に `pty_close` して回る必要はない。
|
|
61
|
+
|
|
62
|
+
**既定は archive(=解散)、`--purge` が痕跡ゼロ**(決定61・オーナー裁定 2026-08-09)。**円卓の解散は「部屋を畳む」ではなく「集まりが散る」**——**部屋は場所であって、次の卓も同じ部屋で続く**。過去ログはその部屋の履歴としてそのまま残り、**部屋は常に一つに見える**。ゲスト project を汚さない不可侵原則は `--purge` が担う。
|
|
63
|
+
|
|
64
|
+
段の順序(**前の段が後の段の前提**):
|
|
65
|
+
1. **room ログの写し**(archive のみ)→ `docs/archive/room-log_<room>_<日時>.md`。**原本は room に残る**ので、これは repo 側の控え(失敗しても撤去は続行する)
|
|
66
|
+
2. **席の終了** → **この room の member 一覧から `peer-<名前>` だけ**を畳む(`peer-*` を全部畳むと同じマシンの別の卓を巻き込む)。他卓の席が残っていれば注記だけ出す
|
|
67
|
+
3. **ブリッジの停止**(起床・稼働状態)→ `.team/` を消す前(pid 記録がその中にある)
|
|
68
|
+
4. **解散**(archive): **履歴へ解散の区切りを1行投稿してから、メンバー登録だけ外す**。**部屋も過去ログも消さない**——区切りが無いと、次の卓の発言が前の卓と地続きに読める/**`--purge`**: room ごと削除(トークンを要する唯一の段)
|
|
69
|
+
5. **外部ペインの復元** → `.team/project.json.bak` が退避先なので `.team/` を消す前
|
|
70
|
+
6. `.team/` 削除 → `.mcp.json` → `.git/info/exclude` の追記行を戻す
|
|
71
|
+
7. **`.lattice/`**: archive では**残す**(`lattice todo status` と `gantt serve` が読む)。`--purge` かつ setup が作ったものなら削除。**残しても git 追跡外なら次の clone に残らない**ので、残すなら commit する(script は注記を出すだけ——他人の repo へ勝手に commit しない)
|
|
72
|
+
|
|
73
|
+
**次の卓を同じ部屋で立てる時は、setup の room 名を前と同じにする**。member は席が戻れば再登録され、履歴は続く。
|
|
74
|
+
|
|
75
|
+
実行後は **`git status`(archive なら `docs/archive/` と `.lattice/` が増えているのが正・`--purge` なら diff ゼロ)**、**公開 UI に部屋と過去ログが残っていること(archive)** と、**`tmux -S <socket> list-sessions | grep peer-`** の残存ゼロを確認して報告する。
|
|
61
76
|
|
|
62
77
|
各段は `[実施] / [スキップ] / [未実施]` を1行ずつ出す。**トークンを要するのは room 削除だけ**なので、そこが失敗しても残りの撤去は続行し、未実施を明示して非ゼロで終わる(黙って中断しない・決定58)。未実施が出ても**撤去そのものは済んでいる**。残りは表示された **[手当] の curl を手で叩く**だけで、`.team/` は既に消えているので **teardown.sh の再実行はできない**(2026-08-08 実測。再実行すると `setup-state.json` が読めず落ちる)。
|
|
63
78
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""room の会話ログを Markdown へ書き出す(teardown の archive モード用)。
|
|
3
|
+
|
|
4
|
+
usage:
|
|
5
|
+
archive-room-log.py <server_url> <room> <out.md> ログを書き出す
|
|
6
|
+
archive-room-log.py --members <server_url> <room> member 名を空白区切りで出す(席を畳む相手)
|
|
7
|
+
|
|
8
|
+
本文は投稿時の Markdown をそのまま置く(引用ブロックで包むと表とコードが崩れる)。
|
|
9
|
+
本文の無い発言(過去に本文なし POST が着地した分)は、欠落と分かる形で残す——
|
|
10
|
+
消すと「そこに発言があった」ことまで消える。
|
|
11
|
+
"""
|
|
12
|
+
import json
|
|
13
|
+
import sys
|
|
14
|
+
import urllib.request
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def fetch(url, path):
|
|
18
|
+
with urllib.request.urlopen(f"{url.rstrip('/')}{path}", timeout=15) as r:
|
|
19
|
+
return json.load(r)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main(argv):
|
|
23
|
+
if argv[:1] == ["--members"]:
|
|
24
|
+
url, room = argv[1], argv[2]
|
|
25
|
+
members = fetch(url, f"/api/{room}/members")["members"]
|
|
26
|
+
print(" ".join(m["name"] for m in members))
|
|
27
|
+
return 0
|
|
28
|
+
|
|
29
|
+
url, room, out = argv[0], argv[1], argv[2]
|
|
30
|
+
messages = fetch(url, f"/api/{room}/messages")["messages"]
|
|
31
|
+
lines = [
|
|
32
|
+
f"# 円卓ログ — room `{room}`(全{len(messages)}発言)",
|
|
33
|
+
"",
|
|
34
|
+
"teardown(archive モード)が書き出した正史。room サーバー側は削除済みなので、"
|
|
35
|
+
"この文書が唯一の記録である。",
|
|
36
|
+
"",
|
|
37
|
+
"---",
|
|
38
|
+
"",
|
|
39
|
+
]
|
|
40
|
+
for m in messages:
|
|
41
|
+
body = m.get("body")
|
|
42
|
+
if body is None:
|
|
43
|
+
body = "(本文欠落——本文なし POST が着地した発言。欠落そのものを記録として残す)"
|
|
44
|
+
lines += [f"## [{m['seq']}] {m['from']} → {m.get('to', 'all')} ・ {m['ts']}", "", body, ""]
|
|
45
|
+
with open(out, "w", encoding="utf-8") as f:
|
|
46
|
+
f.write("\n".join(lines))
|
|
47
|
+
return 0
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
# 生の traceback を出さない。teardown の画面へ出るのは「何が起きたか」の1行であるべきで、
|
|
52
|
+
# stack trace は読む側に原因を伝えない(呼び出し側は非ゼロだけを見る)
|
|
53
|
+
try:
|
|
54
|
+
sys.exit(main(sys.argv[1:]))
|
|
55
|
+
except Exception as exc: # noqa: BLE001 — 入口なので型を絞らない
|
|
56
|
+
print(f"ARCHIVE_ROOM_LOG_FAILED: {type(exc).__name__}: {exc}", file=sys.stderr)
|
|
57
|
+
sys.exit(1)
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# Peertable teardown
|
|
3
|
-
# usage: teardown.sh <project_dir>
|
|
2
|
+
# Peertable teardown の機械部分。席(tmux)も本 script が畳む。
|
|
3
|
+
# usage: teardown.sh <project_dir> [--purge]
|
|
4
|
+
# 既定(archive): room のログを `docs/archive/` へ書き出し、`.lattice/` は残して畳む
|
|
5
|
+
# --purge : 何も残さず全部消す(従来の痕跡ゼロ・ゲスト project 向け)
|
|
4
6
|
# 書込トークンは環境変数 PEERTABLE_POST_TOKEN から取る(`~/.config/peertable.env` は export 付きで定義すること)。
|
|
5
7
|
#
|
|
6
8
|
# 撤去は「何が実施され、何が実施されなかったか」を1行ずつ出す。room 削除だけがトークンを要するので、
|
|
7
9
|
# そこが失敗しても残りの撤去は続行し、未実施を明示して非ゼロで終わる(黙って中断しない・決定58)。
|
|
10
|
+
#
|
|
11
|
+
# **既定が archive なのはオーナー裁定(2026-08-09・決定61)**。痕跡ゼロを既定にしていた時代は、
|
|
12
|
+
# 畳んだ瞬間に room の会話ログ(server 側の正本)と Lattice store が消えていた——**卓の議論と
|
|
13
|
+
# 工程の記録は、卓そのものより寿命が長い**。ゲスト project を汚さない不可侵原則は `--purge` が持つ。
|
|
8
14
|
set -e
|
|
9
15
|
proj="$1"
|
|
16
|
+
mode=archive
|
|
17
|
+
for arg in "${@:2}"; do
|
|
18
|
+
case "$arg" in
|
|
19
|
+
--purge) mode=purge ;;
|
|
20
|
+
--archive) mode=archive ;;
|
|
21
|
+
*) echo "ERROR: 未知の引数: ${arg}(受けるのは --purge / --archive だけ)" >&2; exit 1 ;;
|
|
22
|
+
esac
|
|
23
|
+
done
|
|
10
24
|
state="$proj/.team/setup-state.json"
|
|
11
25
|
room=$(python3 -c "import json;print(json.load(open('$state'))['room'])")
|
|
12
26
|
url=$(python3 -c "import json;print(json.load(open('$state'))['server_url'])")
|
|
@@ -22,6 +36,42 @@ skip() { echo "teardown: [スキップ] $*"; }
|
|
|
22
36
|
miss() { echo "teardown: [未実施] $*" >&2; fail=1; }
|
|
23
37
|
yes_() { [ "$1" = "True" ] || [ "$1" = "true" ]; }
|
|
24
38
|
|
|
39
|
+
echo "teardown: mode=${mode}(archive=ログとstoreを残す/purge=痕跡ゼロ)"
|
|
40
|
+
|
|
41
|
+
# ---- ログの控え(archive だけ)。room 自体は残るので、これは repo 側の写し ----
|
|
42
|
+
# 失敗しても撤去は続ける(room に原本があるため)。--purge の時だけ「消す前の最後の機会」になる
|
|
43
|
+
log_saved=skip
|
|
44
|
+
if [ "$mode" = archive ]; then
|
|
45
|
+
arc="$proj/docs/archive"
|
|
46
|
+
out="$arc/room-log_${room}_$(date +%Y%m%d-%H%M%S).md"
|
|
47
|
+
mkdir -p "$arc"
|
|
48
|
+
if python3 "$(dirname "$0")/archive-room-log.py" "$url" "$room" "$out"; then
|
|
49
|
+
did "room ログの写しを ${out#"$proj/"} へ(原本は room に残る)"
|
|
50
|
+
log_saved=yes
|
|
51
|
+
else
|
|
52
|
+
miss "room ログの写しに失敗($url/api/$room が読めない)— **原本は room に残っている**ので撤去は続行する"
|
|
53
|
+
log_saved=no
|
|
54
|
+
fi
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# ---- 席(tmux)の終了。**`.team/` を消す前**に、この room の member だけを畳む ----
|
|
58
|
+
# `peer-*` を全部畳むと、同じマシンの別の卓を巻き込む(bridge が members 起点にしているのと同じ理由)
|
|
59
|
+
sock="${PEERTABLE_TMUX_SOCKET:-${TMPDIR}claude-tmux-sockets/claude.sock}"
|
|
60
|
+
seats=$(python3 "$(dirname "$0")/archive-room-log.py" --members "$url" "$room" 2>/dev/null || true)
|
|
61
|
+
if [ -z "$seats" ]; then
|
|
62
|
+
miss "席の終了 — member 一覧が取れず、畳む相手を特定できない。手で確認: tmux -S \"$sock\" list-sessions | grep peer-"
|
|
63
|
+
else
|
|
64
|
+
closed=0
|
|
65
|
+
for name in $seats; do
|
|
66
|
+
if tmux -S "$sock" has-session -t "peer-$name" 2>/dev/null; then
|
|
67
|
+
tmux -S "$sock" kill-session -t "peer-$name" && closed=$((closed + 1))
|
|
68
|
+
fi
|
|
69
|
+
done
|
|
70
|
+
if [ "$closed" -gt 0 ]; then did "席の終了(${closed}席)"; else skip "席の終了(生きている席なし)"; fi
|
|
71
|
+
left=$(tmux -S "$sock" list-sessions 2>/dev/null | grep -c '^peer-' || true)
|
|
72
|
+
[ "${left:-0}" -eq 0 ] || echo "teardown: [注記] 他の卓の peer-* が ${left}件 残っている(この卓のものではないので畳まない)"
|
|
73
|
+
fi
|
|
74
|
+
|
|
25
75
|
# Codex 席の起床ブリッジ(決定54)。常駐 process なので、`.team/` を消す前に確実に止める
|
|
26
76
|
if [ -f "$proj/.team/wakeup-bridge.json" ]; then
|
|
27
77
|
# 停止に失敗しても **ここで止まらない**。`set -e` で落ちると、t6 の契約(各段の実施・未実施を
|
|
@@ -54,8 +104,38 @@ fi
|
|
|
54
104
|
ext=$(python3 -c "import json;print(json.load(open('$state')).get('external_pane', False))")
|
|
55
105
|
pj_pre=$(python3 -c "import json;print(json.load(open('$state')).get('project_json_preexisting', False))")
|
|
56
106
|
|
|
57
|
-
#
|
|
58
|
-
|
|
107
|
+
# ---- 解散(archive): **部屋は残し、メンバー登録だけ外す** ----
|
|
108
|
+
# 円卓の解散は「部屋を畳む」ではなく「集まりが散る」。部屋は場所であって、次の campaign も
|
|
109
|
+
# 同じ部屋で続く——**過去ログが同じ部屋の履歴として繋がり、部屋は常に一つに見える**
|
|
110
|
+
# (オーナー裁定 2026-08-09・決定61)。参加者一覧だけ空にして、席が戻れば再登録される
|
|
111
|
+
if [ "$mode" = archive ]; then
|
|
112
|
+
if [ -z "${PEERTABLE_POST_TOKEN:-}" ]; then
|
|
113
|
+
miss "メンバー登録の解除 — TOKEN_MISSING: \`~/.config/peertable.env\` の定義が \`export\` 付きでないと子 process へ渡らない"
|
|
114
|
+
echo "teardown: [手当] 参加者は次で外せる: curl -X DELETE \"$url/api/$room/members/<名前>\" -H \"X-Peertable-Token: \$PEERTABLE_POST_TOKEN\"" >&2
|
|
115
|
+
elif [ -z "$seats" ]; then
|
|
116
|
+
skip "メンバー登録の解除(一覧が取れていない)"
|
|
117
|
+
else
|
|
118
|
+
# 履歴に解散の区切りを残す。**部屋が続く以上、どこで卓が変わったかが読めないと
|
|
119
|
+
# 過去ログが一続きの会話に見えてしまう**(次の campaign の発言と地続きになる)
|
|
120
|
+
body="解散。この卓はここまで。参加者: ${seats}。部屋と過去ログはこのまま残り、次の卓も同じ部屋で続く。"
|
|
121
|
+
python3 -c "
|
|
122
|
+
import json,sys,urllib.request
|
|
123
|
+
req=urllib.request.Request('$url/api/$room/messages', method='POST',
|
|
124
|
+
data=json.dumps({'from':'system','to':'all','body':'''$body'''}).encode(),
|
|
125
|
+
headers={'Content-Type':'application/json','X-Peertable-Token':'$PEERTABLE_POST_TOKEN'})
|
|
126
|
+
urllib.request.urlopen(req, timeout=10).read()
|
|
127
|
+
" 2>/dev/null && did "解散の区切りを履歴へ" || skip "解散の区切り(投稿できず・撤去は続行)"
|
|
128
|
+
n=0
|
|
129
|
+
for name in $seats; do
|
|
130
|
+
c=$(curl -s -o /dev/null -w '%{http_code}' -X DELETE "$url/api/$room/members/$name" -H "X-Peertable-Token: $PEERTABLE_POST_TOKEN" || true)
|
|
131
|
+
[ "$c" = 200 ] && n=$((n + 1))
|
|
132
|
+
done
|
|
133
|
+
did "メンバー登録の解除(${n}名)— **部屋と過去ログは残す**($url/$room)"
|
|
134
|
+
fi
|
|
135
|
+
# room 削除は --purge だけ。トークンを要する唯一の段で、ここだけが外部サービスへの依存境界
|
|
136
|
+
elif [ "$log_saved" = no ]; then
|
|
137
|
+
miss "room 削除 $room — ログを保全できていないので消さない(保全より先に消すと会話は二度と戻らない)"
|
|
138
|
+
elif [ -z "${PEERTABLE_POST_TOKEN:-}" ]; then
|
|
59
139
|
miss "room 削除 $room — TOKEN_MISSING: PEERTABLE_POST_TOKEN が空。\`~/.config/peertable.env\` の定義が \`export\` 付きでないと子 process へ渡らない"
|
|
60
140
|
else
|
|
61
141
|
code=$(curl -s -o /dev/null -w '%{http_code}' -X DELETE "$url/api/$room" -H "X-Peertable-Token: $PEERTABLE_POST_TOKEN" || true)
|
|
@@ -107,11 +187,15 @@ else
|
|
|
107
187
|
skip "exclude の .team/(setup が足していない)"
|
|
108
188
|
fi
|
|
109
189
|
|
|
110
|
-
if [ "$lat_pre" = "
|
|
111
|
-
rm -rf "$proj/.lattice"
|
|
112
|
-
did ".lattice/ 削除(setup が作ったもの)"
|
|
113
|
-
else
|
|
190
|
+
if [ "$lat_pre" = "True" ] || [ "$lat_pre" = "true" ]; then
|
|
114
191
|
skip ".lattice/(setup 以前から存在)"
|
|
192
|
+
elif [ "$mode" = archive ]; then
|
|
193
|
+
# 工程正本を残すのが archive の本体。**残すだけでは git が知らない**ので、追跡へ入れるのは人の判断
|
|
194
|
+
did ".lattice/ を残す(工程正本・\`lattice todo status\` と \`gantt serve\` が読む)"
|
|
195
|
+
echo "teardown: [注記] .lattice/ は git 追跡外のままなら次の clone に残らない。残すなら commit すること"
|
|
196
|
+
else
|
|
197
|
+
rm -rf "$proj/.lattice"
|
|
198
|
+
did ".lattice/ 削除(setup が作ったもの・--purge)"
|
|
115
199
|
fi
|
|
116
200
|
|
|
117
201
|
if [ "$fail" -ne 0 ]; then
|